From 4ea73fc8c5e2c29f35b6a1b66fd845ffdb32929d Mon Sep 17 00:00:00 2001
From: Christophe Geuzaine <cgeuzaine@ulg.ac.be>
Date: Mon, 19 Dec 2011 10:15:42 +0000
Subject: [PATCH] moving to netgen svn

---
 contrib/Netgen/libsrc/Makefile.am             |    5 +
 contrib/Netgen/libsrc/csg/Makefile.am         |   26 +
 contrib/Netgen/libsrc/csg/algprim.cpp         | 1727 +++++
 contrib/Netgen/libsrc/csg/algprim.hpp         |  446 ++
 contrib/Netgen/libsrc/csg/brick.cpp           |  526 ++
 contrib/Netgen/libsrc/csg/brick.hpp           |  126 +
 contrib/Netgen/libsrc/csg/bspline2d.cpp       |  242 +
 contrib/Netgen/libsrc/csg/csg.hpp             |   44 +
 contrib/Netgen/libsrc/csg/csgeom.cpp          | 1500 +++++
 contrib/Netgen/libsrc/csg/csgeom.hpp          |  327 +
 contrib/Netgen/libsrc/csg/csgparser.cpp       | 1390 ++++
 contrib/Netgen/libsrc/csg/csgparser.hpp       |  101 +
 contrib/Netgen/libsrc/csg/csgpkg.cpp          |  700 ++
 contrib/Netgen/libsrc/csg/curve2d.cpp         |   78 +
 contrib/Netgen/libsrc/csg/curve2d.hpp         |   67 +
 contrib/Netgen/libsrc/csg/edgeflw.cpp         | 1850 ++++++
 contrib/Netgen/libsrc/csg/edgeflw.hpp         |  110 +
 contrib/Netgen/libsrc/csg/explicitcurve2d.cpp |  160 +
 contrib/Netgen/libsrc/csg/explicitcurve2d.hpp |  113 +
 contrib/Netgen/libsrc/csg/extrusion.cpp       |  876 +++
 contrib/Netgen/libsrc/csg/extrusion.hpp       |  155 +
 contrib/Netgen/libsrc/csg/gencyl.cpp          |  179 +
 contrib/Netgen/libsrc/csg/gencyl.hpp          |   70 +
 contrib/Netgen/libsrc/csg/genmesh.cpp         |  849 +++
 contrib/Netgen/libsrc/csg/geoml.hpp           |   16 +
 contrib/Netgen/libsrc/csg/identify.cpp        | 1662 +++++
 contrib/Netgen/libsrc/csg/identify.hpp        |  210 +
 contrib/Netgen/libsrc/csg/manifold.cpp        |   14 +
 contrib/Netgen/libsrc/csg/manifold.hpp        |   29 +
 contrib/Netgen/libsrc/csg/meshsurf.cpp        |  211 +
 contrib/Netgen/libsrc/csg/meshsurf.hpp        |   97 +
 contrib/Netgen/libsrc/csg/polyhedra.cpp       |  738 +++
 contrib/Netgen/libsrc/csg/polyhedra.hpp       |  104 +
 contrib/Netgen/libsrc/csg/revolution.cpp      |  900 +++
 contrib/Netgen/libsrc/csg/revolution.hpp      |  153 +
 contrib/Netgen/libsrc/csg/singularref.cpp     |  217 +
 contrib/Netgen/libsrc/csg/singularref.hpp     |   84 +
 contrib/Netgen/libsrc/csg/solid.cpp           | 1732 +++++
 contrib/Netgen/libsrc/csg/solid.hpp           |  246 +
 contrib/Netgen/libsrc/csg/specpoin.cpp        | 2099 ++++++
 contrib/Netgen/libsrc/csg/specpoin.hpp        |  191 +
 contrib/Netgen/libsrc/csg/spline3d.cpp        |  355 ++
 contrib/Netgen/libsrc/csg/spline3d.hpp        |   99 +
 contrib/Netgen/libsrc/csg/surface.cpp         |  568 ++
 contrib/Netgen/libsrc/csg/surface.hpp         |  374 ++
 contrib/Netgen/libsrc/csg/triapprox.cpp       |   59 +
 contrib/Netgen/libsrc/csg/triapprox.hpp       |   63 +
 contrib/Netgen/libsrc/csg/vscsg.cpp           |  559 ++
 contrib/Netgen/libsrc/csg/vscsg.hpp           |   34 +
 contrib/Netgen/libsrc/general/Makefile.am     |   14 +
 contrib/Netgen/libsrc/general/array.cpp       |   75 +
 contrib/Netgen/libsrc/general/array.hpp       |  661 ++
 contrib/Netgen/libsrc/general/autodiff.hpp    |  351 +
 contrib/Netgen/libsrc/general/autoptr.hpp     |   36 +
 contrib/Netgen/libsrc/general/bitarray.cpp    |  132 +
 contrib/Netgen/libsrc/general/bitarray.hpp    |  227 +
 contrib/Netgen/libsrc/general/dynamicmem.cpp  |  201 +
 contrib/Netgen/libsrc/general/dynamicmem.hpp  |   98 +
 contrib/Netgen/libsrc/general/flags.cpp       |  330 +
 contrib/Netgen/libsrc/general/flags.hpp       |   88 +
 contrib/Netgen/libsrc/general/hashtabl.cpp    |  326 +
 contrib/Netgen/libsrc/general/hashtabl.hpp    | 1362 ++++
 .../Netgen/libsrc/general/mpi_interface.hpp   |  300 +
 contrib/Netgen/libsrc/general/myadt.hpp       |   48 +
 contrib/Netgen/libsrc/general/mystring.cpp    |  426 ++
 contrib/Netgen/libsrc/general/mystring.hpp    |  220 +
 contrib/Netgen/libsrc/general/netgenout.hpp   |  187 +
 contrib/Netgen/libsrc/general/ngexception.cpp |   33 +
 contrib/Netgen/libsrc/general/ngexception.hpp |   33 +
 contrib/Netgen/libsrc/general/optmem.cpp      |   63 +
 contrib/Netgen/libsrc/general/optmem.hpp      |   62 +
 contrib/Netgen/libsrc/general/parthreads.cpp  |   40 +
 contrib/Netgen/libsrc/general/parthreads.hpp  |  192 +
 contrib/Netgen/libsrc/general/profiler.cpp    |  118 +
 contrib/Netgen/libsrc/general/profiler.hpp    |   66 +
 contrib/Netgen/libsrc/general/seti.cpp        |   70 +
 contrib/Netgen/libsrc/general/seti.hpp        |   50 +
 contrib/Netgen/libsrc/general/sort.cpp        |   75 +
 contrib/Netgen/libsrc/general/sort.hpp        |   46 +
 contrib/Netgen/libsrc/general/spbita2d.cpp    |  172 +
 contrib/Netgen/libsrc/general/spbita2d.hpp    |   59 +
 contrib/Netgen/libsrc/general/stack.hpp       |  114 +
 contrib/Netgen/libsrc/general/symbolta.cpp    |   52 +
 contrib/Netgen/libsrc/general/symbolta.hpp    |  161 +
 contrib/Netgen/libsrc/general/table.cpp       |  214 +
 contrib/Netgen/libsrc/general/table.hpp       |  239 +
 contrib/Netgen/libsrc/general/template.hpp    |  460 ++
 contrib/Netgen/libsrc/geom2d/Makefile.am      |   14 +
 contrib/Netgen/libsrc/geom2d/genmesh2d.cpp    |  542 ++
 contrib/Netgen/libsrc/geom2d/geom2dmesh.cpp   |   82 +
 contrib/Netgen/libsrc/geom2d/geom2dmesh.hpp   |   52 +
 contrib/Netgen/libsrc/geom2d/geom2dpkg.cpp    |   72 +
 contrib/Netgen/libsrc/geom2d/geometry2d.cpp   |  938 +++
 contrib/Netgen/libsrc/geom2d/geometry2d.hpp   |  184 +
 contrib/Netgen/libsrc/geom2d/spline2d.hpp     |  234 +
 .../Netgen/libsrc/geom2d/splinegeometry2.hpp  |  103 +
 contrib/Netgen/libsrc/geom2d/vsgeom2d.cpp     |  110 +
 contrib/Netgen/libsrc/geom2d/vsgeom2d.hpp     |   28 +
 contrib/Netgen/libsrc/gprim/Makefile.am       |    7 +
 contrib/Netgen/libsrc/gprim/adtree.cpp        | 2165 +++++++
 contrib/Netgen/libsrc/gprim/adtree.hpp        |  486 ++
 contrib/Netgen/libsrc/gprim/geom2d.cpp        |  489 ++
 contrib/Netgen/libsrc/gprim/geom2d.hpp        |  886 +++
 contrib/Netgen/libsrc/gprim/geom3d.cpp        |  731 +++
 contrib/Netgen/libsrc/gprim/geom3d.hpp        |  746 +++
 contrib/Netgen/libsrc/gprim/geomfuncs.cpp     |  111 +
 contrib/Netgen/libsrc/gprim/geomfuncs.hpp     |  170 +
 contrib/Netgen/libsrc/gprim/geomobjects.hpp   |  370 ++
 contrib/Netgen/libsrc/gprim/geomobjects2.hpp  |  366 ++
 contrib/Netgen/libsrc/gprim/geomops.hpp       |  394 ++
 contrib/Netgen/libsrc/gprim/geomops2.hpp      |  428 ++
 contrib/Netgen/libsrc/gprim/geomtest3d.cpp    | 1150 ++++
 contrib/Netgen/libsrc/gprim/geomtest3d.hpp    |   87 +
 contrib/Netgen/libsrc/gprim/gprim.hpp         |   33 +
 contrib/Netgen/libsrc/gprim/spline.cpp        |  497 ++
 contrib/Netgen/libsrc/gprim/spline.hpp        |  647 ++
 .../Netgen/libsrc/gprim/splinegeometry.cpp    |  134 +
 .../Netgen/libsrc/gprim/splinegeometry.hpp    |   68 +
 contrib/Netgen/libsrc/gprim/transform3d.cpp   |  165 +
 contrib/Netgen/libsrc/gprim/transform3d.hpp   |  193 +
 contrib/Netgen/libsrc/include/Makefile.am     |    8 +
 contrib/Netgen/libsrc/include/acisgeom.hpp    |    3 +
 contrib/Netgen/libsrc/include/csg.hpp         |    1 +
 contrib/Netgen/libsrc/include/geometry2d.hpp  |    1 +
 contrib/Netgen/libsrc/include/gprim.hpp       |    1 +
 contrib/Netgen/libsrc/include/incvis.hpp      |   39 +
 contrib/Netgen/libsrc/include/linalg.hpp      |    1 +
 contrib/Netgen/libsrc/include/meshing.hpp     |    1 +
 contrib/Netgen/libsrc/include/myadt.hpp       |    1 +
 contrib/Netgen/libsrc/include/mydefs.hpp      |   49 +
 contrib/Netgen/libsrc/include/mystdlib.h      |   88 +
 contrib/Netgen/libsrc/include/nginterface.h   |  510 ++
 .../Netgen/libsrc/include/nginterface_v2.hpp  |  175 +
 contrib/Netgen/libsrc/include/occgeom.hpp     |    1 +
 contrib/Netgen/libsrc/include/opti.hpp        |    1 +
 contrib/Netgen/libsrc/include/parallel.hpp    |    1 +
 .../libsrc/include/parallelinterface.hpp      |   49 +
 contrib/Netgen/libsrc/include/stlgeom.hpp     |    1 +
 contrib/Netgen/libsrc/include/visual.hpp      |    1 +
 contrib/Netgen/libsrc/interface/Makefile.am   |   12 +
 .../Netgen/libsrc/interface/nginterface.cpp   | 2448 +++++++
 .../libsrc/interface/nginterface_v2.cpp       |  221 +
 .../Netgen/libsrc/interface/read_fnf_mesh.cpp |  451 ++
 .../Netgen/libsrc/interface/readtetmesh.cpp   |  797 +++
 contrib/Netgen/libsrc/interface/readuser.cpp  |  422 ++
 .../libsrc/interface/writeOpenFOAM15x.cpp     |  768 +++
 .../Netgen/libsrc/interface/writeabaqus.cpp   |  237 +
 .../Netgen/libsrc/interface/writediffpack.cpp |  296 +
 .../Netgen/libsrc/interface/writedolfin.cpp   |   69 +
 .../Netgen/libsrc/interface/writeelmer.cpp    |  132 +
 contrib/Netgen/libsrc/interface/writefeap.cpp |  220 +
 .../Netgen/libsrc/interface/writefluent.cpp   |  193 +
 contrib/Netgen/libsrc/interface/writegmsh.cpp |  200 +
 .../Netgen/libsrc/interface/writegmsh2.cpp    |  261 +
 contrib/Netgen/libsrc/interface/writejcm.cpp  |  430 ++
 .../Netgen/libsrc/interface/writepermas.cpp   |  208 +
 .../Netgen/libsrc/interface/writetecplot.cpp  |  127 +
 contrib/Netgen/libsrc/interface/writetet.cpp  | 1096 ++++
 .../Netgen/libsrc/interface/writetochnog.cpp  |  108 +
 contrib/Netgen/libsrc/interface/writeuser.cpp | 1026 +++
 contrib/Netgen/libsrc/interface/writeuser.hpp |  165 +
 .../Netgen/libsrc/interface/wuchemnitz.cpp    |  317 +
 contrib/Netgen/libsrc/linalg/Makefile.am      |    9 +
 contrib/Netgen/libsrc/linalg/bfgs.cpp         |  407 ++
 contrib/Netgen/libsrc/linalg/densemat.cpp     | 1384 ++++
 contrib/Netgen/libsrc/linalg/densemat.hpp     |  277 +
 contrib/Netgen/libsrc/linalg/linalg.hpp       |   32 +
 contrib/Netgen/libsrc/linalg/linopt.cpp       |   73 +
 contrib/Netgen/libsrc/linalg/linsearch.cpp    |  349 +
 contrib/Netgen/libsrc/linalg/opti.hpp         |  142 +
 contrib/Netgen/libsrc/linalg/polynomial.cpp   |  198 +
 contrib/Netgen/libsrc/linalg/polynomial.hpp   |   45 +
 contrib/Netgen/libsrc/linalg/vector.hpp       |  161 +
 contrib/Netgen/libsrc/meshing/Makefile.am     |   31 +
 contrib/Netgen/libsrc/meshing/adfront2.cpp    |  508 ++
 contrib/Netgen/libsrc/meshing/adfront2.hpp    |  282 +
 contrib/Netgen/libsrc/meshing/adfront3.cpp    |  868 +++
 contrib/Netgen/libsrc/meshing/adfront3.hpp    |  320 +
 contrib/Netgen/libsrc/meshing/basegeom.cpp    |   66 +
 contrib/Netgen/libsrc/meshing/basegeom.hpp    |   50 +
 contrib/Netgen/libsrc/meshing/bcfunctions.cpp |  468 ++
 contrib/Netgen/libsrc/meshing/bcfunctions.hpp |   53 +
 contrib/Netgen/libsrc/meshing/bisect.cpp      | 4071 ++++++++++++
 contrib/Netgen/libsrc/meshing/bisect.hpp      |  102 +
 .../Netgen/libsrc/meshing/boundarylayer.cpp   |  610 ++
 .../Netgen/libsrc/meshing/boundarylayer.hpp   |   13 +
 .../Netgen/libsrc/meshing/classifyhpel.hpp    | 1728 +++++
 contrib/Netgen/libsrc/meshing/clusters.cpp    |  267 +
 contrib/Netgen/libsrc/meshing/clusters.hpp    |   42 +
 contrib/Netgen/libsrc/meshing/curvedelems.cpp | 3581 +++++++++++
 contrib/Netgen/libsrc/meshing/curvedelems.hpp |  223 +
 contrib/Netgen/libsrc/meshing/delaunay.cpp    | 1676 +++++
 contrib/Netgen/libsrc/meshing/delaunay2d.cpp  |  174 +
 contrib/Netgen/libsrc/meshing/findip.hpp      |  192 +
 contrib/Netgen/libsrc/meshing/findip2.hpp     |   95 +
 contrib/Netgen/libsrc/meshing/geomsearch.cpp  |  263 +
 contrib/Netgen/libsrc/meshing/geomsearch.hpp  |  117 +
 contrib/Netgen/libsrc/meshing/global.cpp      |   59 +
 contrib/Netgen/libsrc/meshing/global.hpp      |   54 +
 contrib/Netgen/libsrc/meshing/hpref_hex.hpp   |  236 +
 contrib/Netgen/libsrc/meshing/hpref_prism.hpp | 3405 ++++++++++
 .../Netgen/libsrc/meshing/hpref_pyramid.hpp   |  118 +
 contrib/Netgen/libsrc/meshing/hpref_quad.hpp  | 2082 ++++++
 contrib/Netgen/libsrc/meshing/hpref_segm.hpp  |  122 +
 contrib/Netgen/libsrc/meshing/hpref_tet.hpp   | 3128 +++++++++
 contrib/Netgen/libsrc/meshing/hpref_trig.hpp  |  776 +++
 .../Netgen/libsrc/meshing/hprefinement.cpp    | 1969 ++++++
 .../Netgen/libsrc/meshing/hprefinement.hpp    |  319 +
 contrib/Netgen/libsrc/meshing/improve2.cpp    |  854 +++
 contrib/Netgen/libsrc/meshing/improve2.hpp    |  102 +
 contrib/Netgen/libsrc/meshing/improve2gen.cpp |  455 ++
 contrib/Netgen/libsrc/meshing/improve3.cpp    | 2779 ++++++++
 contrib/Netgen/libsrc/meshing/improve3.hpp    |  125 +
 contrib/Netgen/libsrc/meshing/localh.cpp      |  708 +++
 contrib/Netgen/libsrc/meshing/localh.hpp      |  187 +
 contrib/Netgen/libsrc/meshing/meshclass.cpp   | 5648 +++++++++++++++++
 contrib/Netgen/libsrc/meshing/meshclass.hpp   |  770 +++
 contrib/Netgen/libsrc/meshing/meshfunc.cpp    |  717 +++
 contrib/Netgen/libsrc/meshing/meshfunc.hpp    |   41 +
 contrib/Netgen/libsrc/meshing/meshfunc2d.cpp  |   61 +
 contrib/Netgen/libsrc/meshing/meshing.hpp     |   71 +
 contrib/Netgen/libsrc/meshing/meshing2.cpp    | 1957 ++++++
 contrib/Netgen/libsrc/meshing/meshing2.hpp    |  164 +
 contrib/Netgen/libsrc/meshing/meshing3.cpp    | 1264 ++++
 contrib/Netgen/libsrc/meshing/meshing3.hpp    |  130 +
 contrib/Netgen/libsrc/meshing/meshtool.cpp    | 1015 +++
 contrib/Netgen/libsrc/meshing/meshtool.hpp    |   81 +
 contrib/Netgen/libsrc/meshing/meshtype.cpp    | 2680 ++++++++
 contrib/Netgen/libsrc/meshing/meshtype.hpp    | 1306 ++++
 contrib/Netgen/libsrc/meshing/msghandler.cpp  |  227 +
 contrib/Netgen/libsrc/meshing/msghandler.hpp  |   57 +
 contrib/Netgen/libsrc/meshing/netrule2.cpp    |  222 +
 contrib/Netgen/libsrc/meshing/netrule3.cpp    | 1138 ++++
 .../Netgen/libsrc/meshing/parallelmesh.cpp    | 1173 ++++
 contrib/Netgen/libsrc/meshing/paralleltop.cpp |  896 +++
 contrib/Netgen/libsrc/meshing/paralleltop.hpp |  156 +
 contrib/Netgen/libsrc/meshing/parser2.cpp     |  605 ++
 contrib/Netgen/libsrc/meshing/parser3.cpp     | 1019 +++
 contrib/Netgen/libsrc/meshing/prism2rls.cpp   |  457 ++
 contrib/Netgen/libsrc/meshing/prism2rls_2.cpp |  446 ++
 contrib/Netgen/libsrc/meshing/pyramid2rls.cpp |  309 +
 contrib/Netgen/libsrc/meshing/pyramidrls.cpp  |  263 +
 contrib/Netgen/libsrc/meshing/quadrls.cpp     |  887 +++
 contrib/Netgen/libsrc/meshing/refine.cpp      |  757 +++
 contrib/Netgen/libsrc/meshing/ruler2.cpp      |  719 +++
 contrib/Netgen/libsrc/meshing/ruler2.hpp      |  169 +
 contrib/Netgen/libsrc/meshing/ruler3.cpp      | 1136 ++++
 contrib/Netgen/libsrc/meshing/ruler3.hpp      |  210 +
 contrib/Netgen/libsrc/meshing/secondorder.cpp |  490 ++
 .../Netgen/libsrc/meshing/smoothing2.5.cpp    |  265 +
 contrib/Netgen/libsrc/meshing/smoothing2.cpp  |  903 +++
 contrib/Netgen/libsrc/meshing/smoothing3.cpp  | 1838 ++++++
 contrib/Netgen/libsrc/meshing/specials.cpp    |  193 +
 contrib/Netgen/libsrc/meshing/specials.hpp    |   16 +
 contrib/Netgen/libsrc/meshing/tetrarls.cpp    | 1466 +++++
 contrib/Netgen/libsrc/meshing/topology.cpp    | 1726 +++++
 contrib/Netgen/libsrc/meshing/topology.hpp    |  683 ++
 contrib/Netgen/libsrc/meshing/triarls.cpp     |  468 ++
 contrib/Netgen/libsrc/meshing/validate.cpp    |  591 ++
 contrib/Netgen/libsrc/meshing/validate.hpp    |   21 +
 contrib/Netgen/libsrc/meshing/zrefine.cpp     |  740 +++
 contrib/Netgen/libsrc/occ/Makefile.am         |   28 +
 .../Netgen/libsrc/occ/Partition_Inter2d.cxx   |  678 ++
 .../Netgen/libsrc/occ/Partition_Inter2d.hxx   |  110 +
 .../Netgen/libsrc/occ/Partition_Inter2d.ixx   |   32 +
 .../Netgen/libsrc/occ/Partition_Inter2d.jxx   |   50 +
 .../Netgen/libsrc/occ/Partition_Inter3d.cxx   |  947 +++
 .../Netgen/libsrc/occ/Partition_Inter3d.hxx   |  143 +
 .../Netgen/libsrc/occ/Partition_Inter3d.ixx   |   31 +
 .../Netgen/libsrc/occ/Partition_Inter3d.jxx   |   53 +
 contrib/Netgen/libsrc/occ/Partition_Loop.cxx  |  473 ++
 contrib/Netgen/libsrc/occ/Partition_Loop.hxx  |  118 +
 contrib/Netgen/libsrc/occ/Partition_Loop.ixx  |   31 +
 contrib/Netgen/libsrc/occ/Partition_Loop.jxx  |   41 +
 .../Netgen/libsrc/occ/Partition_Loop2d.cxx    | 1145 ++++
 .../Netgen/libsrc/occ/Partition_Loop2d.hxx    |  106 +
 .../Netgen/libsrc/occ/Partition_Loop2d.ixx    |   14 +
 .../Netgen/libsrc/occ/Partition_Loop2d.jxx    |   24 +
 .../Netgen/libsrc/occ/Partition_Loop3d.cxx    |  356 ++
 .../Netgen/libsrc/occ/Partition_Loop3d.hxx    |  102 +
 .../Netgen/libsrc/occ/Partition_Loop3d.ixx    |   14 +
 .../Netgen/libsrc/occ/Partition_Loop3d.jxx    |   30 +
 .../Netgen/libsrc/occ/Partition_Spliter.cxx   | 2168 +++++++
 .../Netgen/libsrc/occ/Partition_Spliter.hxx   |  150 +
 .../Netgen/libsrc/occ/Partition_Spliter.ixx   |   31 +
 .../Netgen/libsrc/occ/Partition_Spliter.jxx   |   41 +
 contrib/Netgen/libsrc/occ/occconstruction.cpp |  157 +
 contrib/Netgen/libsrc/occ/occgenmesh.cpp      | 1460 +++++
 contrib/Netgen/libsrc/occ/occgeom.cpp         | 1608 +++++
 contrib/Netgen/libsrc/occ/occgeom.hpp         |  451 ++
 contrib/Netgen/libsrc/occ/occmeshsurf.cpp     |  735 +++
 contrib/Netgen/libsrc/occ/occmeshsurf.hpp     |  203 +
 contrib/Netgen/libsrc/occ/occpkg.cpp          | 1020 +++
 contrib/Netgen/libsrc/occ/utilities.h         |  112 +
 contrib/Netgen/libsrc/occ/vsocc.cpp           |  764 +++
 contrib/Netgen/libsrc/occ/vsocc.hpp           |   33 +
 contrib/Netgen/libsrc/stlgeom/Makefile.am     |   15 +
 .../Netgen/libsrc/stlgeom/meshstlsurface.cpp  | 1133 ++++
 .../Netgen/libsrc/stlgeom/meshstlsurface.hpp  |  121 +
 contrib/Netgen/libsrc/stlgeom/stlgeom.cpp     | 3506 ++++++++++
 contrib/Netgen/libsrc/stlgeom/stlgeom.hpp     |  459 ++
 .../Netgen/libsrc/stlgeom/stlgeomchart.cpp    |  798 +++
 contrib/Netgen/libsrc/stlgeom/stlgeommesh.cpp | 1590 +++++
 contrib/Netgen/libsrc/stlgeom/stlline.cpp     |  780 +++
 contrib/Netgen/libsrc/stlgeom/stlline.hpp     |  188 +
 contrib/Netgen/libsrc/stlgeom/stlpkg.cpp      |  622 ++
 contrib/Netgen/libsrc/stlgeom/stltool.cpp     | 1287 ++++
 contrib/Netgen/libsrc/stlgeom/stltool.hpp     |  271 +
 contrib/Netgen/libsrc/stlgeom/stltopology.cpp | 1067 ++++
 contrib/Netgen/libsrc/stlgeom/stltopology.hpp |  362 ++
 contrib/Netgen/libsrc/stlgeom/vsstl.cpp       | 1212 ++++
 contrib/Netgen/libsrc/stlgeom/vsstl.hpp       |   53 +
 .../Netgen/libsrc/visualization/Makefile.am   |   11 +
 .../libsrc/visualization/importsolution.cpp   |  129 +
 .../Netgen/libsrc/visualization/meshdoc.cpp   |  614 ++
 .../Netgen/libsrc/visualization/meshdoc.hpp   |   37 +
 .../Netgen/libsrc/visualization/mvdraw.cpp    |  806 +++
 .../Netgen/libsrc/visualization/mvdraw.hpp    |  245 +
 .../Netgen/libsrc/visualization/soldata.hpp   |  111 +
 .../libsrc/visualization/stlmeshing.cpp       | 1076 ++++
 .../Netgen/libsrc/visualization/vispar.hpp    |  106 +
 .../Netgen/libsrc/visualization/visual.hpp    |   35 +
 contrib/Netgen/libsrc/visualization/vscsg.cpp |  272 +
 .../libsrc/visualization/vsfieldlines.cpp     |  729 +++
 .../Netgen/libsrc/visualization/vsmesh.cpp    | 3445 ++++++++++
 contrib/Netgen/libsrc/visualization/vsocc.cpp |  762 +++
 .../libsrc/visualization/vssolution.cpp       | 4537 +++++++++++++
 .../libsrc/visualization/vssolution.hpp       |  430 ++
 328 files changed, 166474 insertions(+)
 create mode 100644 contrib/Netgen/libsrc/Makefile.am
 create mode 100644 contrib/Netgen/libsrc/csg/Makefile.am
 create mode 100644 contrib/Netgen/libsrc/csg/algprim.cpp
 create mode 100644 contrib/Netgen/libsrc/csg/algprim.hpp
 create mode 100644 contrib/Netgen/libsrc/csg/brick.cpp
 create mode 100644 contrib/Netgen/libsrc/csg/brick.hpp
 create mode 100644 contrib/Netgen/libsrc/csg/bspline2d.cpp
 create mode 100644 contrib/Netgen/libsrc/csg/csg.hpp
 create mode 100644 contrib/Netgen/libsrc/csg/csgeom.cpp
 create mode 100644 contrib/Netgen/libsrc/csg/csgeom.hpp
 create mode 100644 contrib/Netgen/libsrc/csg/csgparser.cpp
 create mode 100644 contrib/Netgen/libsrc/csg/csgparser.hpp
 create mode 100644 contrib/Netgen/libsrc/csg/csgpkg.cpp
 create mode 100644 contrib/Netgen/libsrc/csg/curve2d.cpp
 create mode 100644 contrib/Netgen/libsrc/csg/curve2d.hpp
 create mode 100644 contrib/Netgen/libsrc/csg/edgeflw.cpp
 create mode 100644 contrib/Netgen/libsrc/csg/edgeflw.hpp
 create mode 100644 contrib/Netgen/libsrc/csg/explicitcurve2d.cpp
 create mode 100644 contrib/Netgen/libsrc/csg/explicitcurve2d.hpp
 create mode 100644 contrib/Netgen/libsrc/csg/extrusion.cpp
 create mode 100644 contrib/Netgen/libsrc/csg/extrusion.hpp
 create mode 100644 contrib/Netgen/libsrc/csg/gencyl.cpp
 create mode 100644 contrib/Netgen/libsrc/csg/gencyl.hpp
 create mode 100644 contrib/Netgen/libsrc/csg/genmesh.cpp
 create mode 100644 contrib/Netgen/libsrc/csg/geoml.hpp
 create mode 100644 contrib/Netgen/libsrc/csg/identify.cpp
 create mode 100644 contrib/Netgen/libsrc/csg/identify.hpp
 create mode 100644 contrib/Netgen/libsrc/csg/manifold.cpp
 create mode 100644 contrib/Netgen/libsrc/csg/manifold.hpp
 create mode 100644 contrib/Netgen/libsrc/csg/meshsurf.cpp
 create mode 100644 contrib/Netgen/libsrc/csg/meshsurf.hpp
 create mode 100644 contrib/Netgen/libsrc/csg/polyhedra.cpp
 create mode 100644 contrib/Netgen/libsrc/csg/polyhedra.hpp
 create mode 100644 contrib/Netgen/libsrc/csg/revolution.cpp
 create mode 100644 contrib/Netgen/libsrc/csg/revolution.hpp
 create mode 100644 contrib/Netgen/libsrc/csg/singularref.cpp
 create mode 100644 contrib/Netgen/libsrc/csg/singularref.hpp
 create mode 100644 contrib/Netgen/libsrc/csg/solid.cpp
 create mode 100644 contrib/Netgen/libsrc/csg/solid.hpp
 create mode 100644 contrib/Netgen/libsrc/csg/specpoin.cpp
 create mode 100644 contrib/Netgen/libsrc/csg/specpoin.hpp
 create mode 100644 contrib/Netgen/libsrc/csg/spline3d.cpp
 create mode 100644 contrib/Netgen/libsrc/csg/spline3d.hpp
 create mode 100644 contrib/Netgen/libsrc/csg/surface.cpp
 create mode 100644 contrib/Netgen/libsrc/csg/surface.hpp
 create mode 100644 contrib/Netgen/libsrc/csg/triapprox.cpp
 create mode 100644 contrib/Netgen/libsrc/csg/triapprox.hpp
 create mode 100644 contrib/Netgen/libsrc/csg/vscsg.cpp
 create mode 100644 contrib/Netgen/libsrc/csg/vscsg.hpp
 create mode 100644 contrib/Netgen/libsrc/general/Makefile.am
 create mode 100644 contrib/Netgen/libsrc/general/array.cpp
 create mode 100644 contrib/Netgen/libsrc/general/array.hpp
 create mode 100644 contrib/Netgen/libsrc/general/autodiff.hpp
 create mode 100644 contrib/Netgen/libsrc/general/autoptr.hpp
 create mode 100644 contrib/Netgen/libsrc/general/bitarray.cpp
 create mode 100644 contrib/Netgen/libsrc/general/bitarray.hpp
 create mode 100644 contrib/Netgen/libsrc/general/dynamicmem.cpp
 create mode 100644 contrib/Netgen/libsrc/general/dynamicmem.hpp
 create mode 100644 contrib/Netgen/libsrc/general/flags.cpp
 create mode 100644 contrib/Netgen/libsrc/general/flags.hpp
 create mode 100644 contrib/Netgen/libsrc/general/hashtabl.cpp
 create mode 100644 contrib/Netgen/libsrc/general/hashtabl.hpp
 create mode 100644 contrib/Netgen/libsrc/general/mpi_interface.hpp
 create mode 100644 contrib/Netgen/libsrc/general/myadt.hpp
 create mode 100644 contrib/Netgen/libsrc/general/mystring.cpp
 create mode 100644 contrib/Netgen/libsrc/general/mystring.hpp
 create mode 100644 contrib/Netgen/libsrc/general/netgenout.hpp
 create mode 100644 contrib/Netgen/libsrc/general/ngexception.cpp
 create mode 100644 contrib/Netgen/libsrc/general/ngexception.hpp
 create mode 100644 contrib/Netgen/libsrc/general/optmem.cpp
 create mode 100644 contrib/Netgen/libsrc/general/optmem.hpp
 create mode 100644 contrib/Netgen/libsrc/general/parthreads.cpp
 create mode 100644 contrib/Netgen/libsrc/general/parthreads.hpp
 create mode 100644 contrib/Netgen/libsrc/general/profiler.cpp
 create mode 100644 contrib/Netgen/libsrc/general/profiler.hpp
 create mode 100644 contrib/Netgen/libsrc/general/seti.cpp
 create mode 100644 contrib/Netgen/libsrc/general/seti.hpp
 create mode 100644 contrib/Netgen/libsrc/general/sort.cpp
 create mode 100644 contrib/Netgen/libsrc/general/sort.hpp
 create mode 100644 contrib/Netgen/libsrc/general/spbita2d.cpp
 create mode 100644 contrib/Netgen/libsrc/general/spbita2d.hpp
 create mode 100644 contrib/Netgen/libsrc/general/stack.hpp
 create mode 100644 contrib/Netgen/libsrc/general/symbolta.cpp
 create mode 100644 contrib/Netgen/libsrc/general/symbolta.hpp
 create mode 100644 contrib/Netgen/libsrc/general/table.cpp
 create mode 100644 contrib/Netgen/libsrc/general/table.hpp
 create mode 100644 contrib/Netgen/libsrc/general/template.hpp
 create mode 100644 contrib/Netgen/libsrc/geom2d/Makefile.am
 create mode 100644 contrib/Netgen/libsrc/geom2d/genmesh2d.cpp
 create mode 100644 contrib/Netgen/libsrc/geom2d/geom2dmesh.cpp
 create mode 100644 contrib/Netgen/libsrc/geom2d/geom2dmesh.hpp
 create mode 100644 contrib/Netgen/libsrc/geom2d/geom2dpkg.cpp
 create mode 100644 contrib/Netgen/libsrc/geom2d/geometry2d.cpp
 create mode 100644 contrib/Netgen/libsrc/geom2d/geometry2d.hpp
 create mode 100644 contrib/Netgen/libsrc/geom2d/spline2d.hpp
 create mode 100644 contrib/Netgen/libsrc/geom2d/splinegeometry2.hpp
 create mode 100644 contrib/Netgen/libsrc/geom2d/vsgeom2d.cpp
 create mode 100644 contrib/Netgen/libsrc/geom2d/vsgeom2d.hpp
 create mode 100644 contrib/Netgen/libsrc/gprim/Makefile.am
 create mode 100644 contrib/Netgen/libsrc/gprim/adtree.cpp
 create mode 100644 contrib/Netgen/libsrc/gprim/adtree.hpp
 create mode 100644 contrib/Netgen/libsrc/gprim/geom2d.cpp
 create mode 100644 contrib/Netgen/libsrc/gprim/geom2d.hpp
 create mode 100644 contrib/Netgen/libsrc/gprim/geom3d.cpp
 create mode 100644 contrib/Netgen/libsrc/gprim/geom3d.hpp
 create mode 100644 contrib/Netgen/libsrc/gprim/geomfuncs.cpp
 create mode 100644 contrib/Netgen/libsrc/gprim/geomfuncs.hpp
 create mode 100644 contrib/Netgen/libsrc/gprim/geomobjects.hpp
 create mode 100644 contrib/Netgen/libsrc/gprim/geomobjects2.hpp
 create mode 100644 contrib/Netgen/libsrc/gprim/geomops.hpp
 create mode 100644 contrib/Netgen/libsrc/gprim/geomops2.hpp
 create mode 100644 contrib/Netgen/libsrc/gprim/geomtest3d.cpp
 create mode 100644 contrib/Netgen/libsrc/gprim/geomtest3d.hpp
 create mode 100644 contrib/Netgen/libsrc/gprim/gprim.hpp
 create mode 100644 contrib/Netgen/libsrc/gprim/spline.cpp
 create mode 100644 contrib/Netgen/libsrc/gprim/spline.hpp
 create mode 100644 contrib/Netgen/libsrc/gprim/splinegeometry.cpp
 create mode 100644 contrib/Netgen/libsrc/gprim/splinegeometry.hpp
 create mode 100644 contrib/Netgen/libsrc/gprim/transform3d.cpp
 create mode 100644 contrib/Netgen/libsrc/gprim/transform3d.hpp
 create mode 100644 contrib/Netgen/libsrc/include/Makefile.am
 create mode 100644 contrib/Netgen/libsrc/include/acisgeom.hpp
 create mode 100644 contrib/Netgen/libsrc/include/csg.hpp
 create mode 100644 contrib/Netgen/libsrc/include/geometry2d.hpp
 create mode 100644 contrib/Netgen/libsrc/include/gprim.hpp
 create mode 100644 contrib/Netgen/libsrc/include/incvis.hpp
 create mode 100644 contrib/Netgen/libsrc/include/linalg.hpp
 create mode 100644 contrib/Netgen/libsrc/include/meshing.hpp
 create mode 100644 contrib/Netgen/libsrc/include/myadt.hpp
 create mode 100644 contrib/Netgen/libsrc/include/mydefs.hpp
 create mode 100644 contrib/Netgen/libsrc/include/mystdlib.h
 create mode 100644 contrib/Netgen/libsrc/include/nginterface.h
 create mode 100644 contrib/Netgen/libsrc/include/nginterface_v2.hpp
 create mode 100644 contrib/Netgen/libsrc/include/occgeom.hpp
 create mode 100644 contrib/Netgen/libsrc/include/opti.hpp
 create mode 100644 contrib/Netgen/libsrc/include/parallel.hpp
 create mode 100644 contrib/Netgen/libsrc/include/parallelinterface.hpp
 create mode 100644 contrib/Netgen/libsrc/include/stlgeom.hpp
 create mode 100644 contrib/Netgen/libsrc/include/visual.hpp
 create mode 100644 contrib/Netgen/libsrc/interface/Makefile.am
 create mode 100644 contrib/Netgen/libsrc/interface/nginterface.cpp
 create mode 100644 contrib/Netgen/libsrc/interface/nginterface_v2.cpp
 create mode 100644 contrib/Netgen/libsrc/interface/read_fnf_mesh.cpp
 create mode 100644 contrib/Netgen/libsrc/interface/readtetmesh.cpp
 create mode 100644 contrib/Netgen/libsrc/interface/readuser.cpp
 create mode 100644 contrib/Netgen/libsrc/interface/writeOpenFOAM15x.cpp
 create mode 100644 contrib/Netgen/libsrc/interface/writeabaqus.cpp
 create mode 100644 contrib/Netgen/libsrc/interface/writediffpack.cpp
 create mode 100644 contrib/Netgen/libsrc/interface/writedolfin.cpp
 create mode 100644 contrib/Netgen/libsrc/interface/writeelmer.cpp
 create mode 100644 contrib/Netgen/libsrc/interface/writefeap.cpp
 create mode 100644 contrib/Netgen/libsrc/interface/writefluent.cpp
 create mode 100644 contrib/Netgen/libsrc/interface/writegmsh.cpp
 create mode 100644 contrib/Netgen/libsrc/interface/writegmsh2.cpp
 create mode 100644 contrib/Netgen/libsrc/interface/writejcm.cpp
 create mode 100644 contrib/Netgen/libsrc/interface/writepermas.cpp
 create mode 100644 contrib/Netgen/libsrc/interface/writetecplot.cpp
 create mode 100644 contrib/Netgen/libsrc/interface/writetet.cpp
 create mode 100644 contrib/Netgen/libsrc/interface/writetochnog.cpp
 create mode 100644 contrib/Netgen/libsrc/interface/writeuser.cpp
 create mode 100644 contrib/Netgen/libsrc/interface/writeuser.hpp
 create mode 100644 contrib/Netgen/libsrc/interface/wuchemnitz.cpp
 create mode 100644 contrib/Netgen/libsrc/linalg/Makefile.am
 create mode 100644 contrib/Netgen/libsrc/linalg/bfgs.cpp
 create mode 100644 contrib/Netgen/libsrc/linalg/densemat.cpp
 create mode 100644 contrib/Netgen/libsrc/linalg/densemat.hpp
 create mode 100644 contrib/Netgen/libsrc/linalg/linalg.hpp
 create mode 100644 contrib/Netgen/libsrc/linalg/linopt.cpp
 create mode 100644 contrib/Netgen/libsrc/linalg/linsearch.cpp
 create mode 100644 contrib/Netgen/libsrc/linalg/opti.hpp
 create mode 100644 contrib/Netgen/libsrc/linalg/polynomial.cpp
 create mode 100644 contrib/Netgen/libsrc/linalg/polynomial.hpp
 create mode 100644 contrib/Netgen/libsrc/linalg/vector.hpp
 create mode 100644 contrib/Netgen/libsrc/meshing/Makefile.am
 create mode 100644 contrib/Netgen/libsrc/meshing/adfront2.cpp
 create mode 100644 contrib/Netgen/libsrc/meshing/adfront2.hpp
 create mode 100644 contrib/Netgen/libsrc/meshing/adfront3.cpp
 create mode 100644 contrib/Netgen/libsrc/meshing/adfront3.hpp
 create mode 100644 contrib/Netgen/libsrc/meshing/basegeom.cpp
 create mode 100644 contrib/Netgen/libsrc/meshing/basegeom.hpp
 create mode 100644 contrib/Netgen/libsrc/meshing/bcfunctions.cpp
 create mode 100644 contrib/Netgen/libsrc/meshing/bcfunctions.hpp
 create mode 100644 contrib/Netgen/libsrc/meshing/bisect.cpp
 create mode 100644 contrib/Netgen/libsrc/meshing/bisect.hpp
 create mode 100644 contrib/Netgen/libsrc/meshing/boundarylayer.cpp
 create mode 100644 contrib/Netgen/libsrc/meshing/boundarylayer.hpp
 create mode 100644 contrib/Netgen/libsrc/meshing/classifyhpel.hpp
 create mode 100644 contrib/Netgen/libsrc/meshing/clusters.cpp
 create mode 100644 contrib/Netgen/libsrc/meshing/clusters.hpp
 create mode 100644 contrib/Netgen/libsrc/meshing/curvedelems.cpp
 create mode 100644 contrib/Netgen/libsrc/meshing/curvedelems.hpp
 create mode 100644 contrib/Netgen/libsrc/meshing/delaunay.cpp
 create mode 100644 contrib/Netgen/libsrc/meshing/delaunay2d.cpp
 create mode 100644 contrib/Netgen/libsrc/meshing/findip.hpp
 create mode 100644 contrib/Netgen/libsrc/meshing/findip2.hpp
 create mode 100644 contrib/Netgen/libsrc/meshing/geomsearch.cpp
 create mode 100644 contrib/Netgen/libsrc/meshing/geomsearch.hpp
 create mode 100644 contrib/Netgen/libsrc/meshing/global.cpp
 create mode 100644 contrib/Netgen/libsrc/meshing/global.hpp
 create mode 100644 contrib/Netgen/libsrc/meshing/hpref_hex.hpp
 create mode 100644 contrib/Netgen/libsrc/meshing/hpref_prism.hpp
 create mode 100644 contrib/Netgen/libsrc/meshing/hpref_pyramid.hpp
 create mode 100644 contrib/Netgen/libsrc/meshing/hpref_quad.hpp
 create mode 100644 contrib/Netgen/libsrc/meshing/hpref_segm.hpp
 create mode 100644 contrib/Netgen/libsrc/meshing/hpref_tet.hpp
 create mode 100644 contrib/Netgen/libsrc/meshing/hpref_trig.hpp
 create mode 100644 contrib/Netgen/libsrc/meshing/hprefinement.cpp
 create mode 100644 contrib/Netgen/libsrc/meshing/hprefinement.hpp
 create mode 100644 contrib/Netgen/libsrc/meshing/improve2.cpp
 create mode 100644 contrib/Netgen/libsrc/meshing/improve2.hpp
 create mode 100644 contrib/Netgen/libsrc/meshing/improve2gen.cpp
 create mode 100644 contrib/Netgen/libsrc/meshing/improve3.cpp
 create mode 100644 contrib/Netgen/libsrc/meshing/improve3.hpp
 create mode 100644 contrib/Netgen/libsrc/meshing/localh.cpp
 create mode 100644 contrib/Netgen/libsrc/meshing/localh.hpp
 create mode 100644 contrib/Netgen/libsrc/meshing/meshclass.cpp
 create mode 100644 contrib/Netgen/libsrc/meshing/meshclass.hpp
 create mode 100644 contrib/Netgen/libsrc/meshing/meshfunc.cpp
 create mode 100644 contrib/Netgen/libsrc/meshing/meshfunc.hpp
 create mode 100644 contrib/Netgen/libsrc/meshing/meshfunc2d.cpp
 create mode 100644 contrib/Netgen/libsrc/meshing/meshing.hpp
 create mode 100644 contrib/Netgen/libsrc/meshing/meshing2.cpp
 create mode 100644 contrib/Netgen/libsrc/meshing/meshing2.hpp
 create mode 100644 contrib/Netgen/libsrc/meshing/meshing3.cpp
 create mode 100644 contrib/Netgen/libsrc/meshing/meshing3.hpp
 create mode 100644 contrib/Netgen/libsrc/meshing/meshtool.cpp
 create mode 100644 contrib/Netgen/libsrc/meshing/meshtool.hpp
 create mode 100644 contrib/Netgen/libsrc/meshing/meshtype.cpp
 create mode 100644 contrib/Netgen/libsrc/meshing/meshtype.hpp
 create mode 100644 contrib/Netgen/libsrc/meshing/msghandler.cpp
 create mode 100644 contrib/Netgen/libsrc/meshing/msghandler.hpp
 create mode 100644 contrib/Netgen/libsrc/meshing/netrule2.cpp
 create mode 100644 contrib/Netgen/libsrc/meshing/netrule3.cpp
 create mode 100644 contrib/Netgen/libsrc/meshing/parallelmesh.cpp
 create mode 100644 contrib/Netgen/libsrc/meshing/paralleltop.cpp
 create mode 100644 contrib/Netgen/libsrc/meshing/paralleltop.hpp
 create mode 100644 contrib/Netgen/libsrc/meshing/parser2.cpp
 create mode 100644 contrib/Netgen/libsrc/meshing/parser3.cpp
 create mode 100644 contrib/Netgen/libsrc/meshing/prism2rls.cpp
 create mode 100644 contrib/Netgen/libsrc/meshing/prism2rls_2.cpp
 create mode 100644 contrib/Netgen/libsrc/meshing/pyramid2rls.cpp
 create mode 100644 contrib/Netgen/libsrc/meshing/pyramidrls.cpp
 create mode 100644 contrib/Netgen/libsrc/meshing/quadrls.cpp
 create mode 100644 contrib/Netgen/libsrc/meshing/refine.cpp
 create mode 100644 contrib/Netgen/libsrc/meshing/ruler2.cpp
 create mode 100644 contrib/Netgen/libsrc/meshing/ruler2.hpp
 create mode 100644 contrib/Netgen/libsrc/meshing/ruler3.cpp
 create mode 100644 contrib/Netgen/libsrc/meshing/ruler3.hpp
 create mode 100644 contrib/Netgen/libsrc/meshing/secondorder.cpp
 create mode 100644 contrib/Netgen/libsrc/meshing/smoothing2.5.cpp
 create mode 100644 contrib/Netgen/libsrc/meshing/smoothing2.cpp
 create mode 100644 contrib/Netgen/libsrc/meshing/smoothing3.cpp
 create mode 100644 contrib/Netgen/libsrc/meshing/specials.cpp
 create mode 100644 contrib/Netgen/libsrc/meshing/specials.hpp
 create mode 100644 contrib/Netgen/libsrc/meshing/tetrarls.cpp
 create mode 100644 contrib/Netgen/libsrc/meshing/topology.cpp
 create mode 100644 contrib/Netgen/libsrc/meshing/topology.hpp
 create mode 100644 contrib/Netgen/libsrc/meshing/triarls.cpp
 create mode 100644 contrib/Netgen/libsrc/meshing/validate.cpp
 create mode 100644 contrib/Netgen/libsrc/meshing/validate.hpp
 create mode 100644 contrib/Netgen/libsrc/meshing/zrefine.cpp
 create mode 100644 contrib/Netgen/libsrc/occ/Makefile.am
 create mode 100644 contrib/Netgen/libsrc/occ/Partition_Inter2d.cxx
 create mode 100644 contrib/Netgen/libsrc/occ/Partition_Inter2d.hxx
 create mode 100644 contrib/Netgen/libsrc/occ/Partition_Inter2d.ixx
 create mode 100644 contrib/Netgen/libsrc/occ/Partition_Inter2d.jxx
 create mode 100644 contrib/Netgen/libsrc/occ/Partition_Inter3d.cxx
 create mode 100644 contrib/Netgen/libsrc/occ/Partition_Inter3d.hxx
 create mode 100644 contrib/Netgen/libsrc/occ/Partition_Inter3d.ixx
 create mode 100644 contrib/Netgen/libsrc/occ/Partition_Inter3d.jxx
 create mode 100644 contrib/Netgen/libsrc/occ/Partition_Loop.cxx
 create mode 100644 contrib/Netgen/libsrc/occ/Partition_Loop.hxx
 create mode 100644 contrib/Netgen/libsrc/occ/Partition_Loop.ixx
 create mode 100644 contrib/Netgen/libsrc/occ/Partition_Loop.jxx
 create mode 100644 contrib/Netgen/libsrc/occ/Partition_Loop2d.cxx
 create mode 100644 contrib/Netgen/libsrc/occ/Partition_Loop2d.hxx
 create mode 100644 contrib/Netgen/libsrc/occ/Partition_Loop2d.ixx
 create mode 100644 contrib/Netgen/libsrc/occ/Partition_Loop2d.jxx
 create mode 100644 contrib/Netgen/libsrc/occ/Partition_Loop3d.cxx
 create mode 100644 contrib/Netgen/libsrc/occ/Partition_Loop3d.hxx
 create mode 100644 contrib/Netgen/libsrc/occ/Partition_Loop3d.ixx
 create mode 100644 contrib/Netgen/libsrc/occ/Partition_Loop3d.jxx
 create mode 100644 contrib/Netgen/libsrc/occ/Partition_Spliter.cxx
 create mode 100644 contrib/Netgen/libsrc/occ/Partition_Spliter.hxx
 create mode 100644 contrib/Netgen/libsrc/occ/Partition_Spliter.ixx
 create mode 100644 contrib/Netgen/libsrc/occ/Partition_Spliter.jxx
 create mode 100644 contrib/Netgen/libsrc/occ/occconstruction.cpp
 create mode 100644 contrib/Netgen/libsrc/occ/occgenmesh.cpp
 create mode 100644 contrib/Netgen/libsrc/occ/occgeom.cpp
 create mode 100644 contrib/Netgen/libsrc/occ/occgeom.hpp
 create mode 100644 contrib/Netgen/libsrc/occ/occmeshsurf.cpp
 create mode 100644 contrib/Netgen/libsrc/occ/occmeshsurf.hpp
 create mode 100644 contrib/Netgen/libsrc/occ/occpkg.cpp
 create mode 100644 contrib/Netgen/libsrc/occ/utilities.h
 create mode 100644 contrib/Netgen/libsrc/occ/vsocc.cpp
 create mode 100644 contrib/Netgen/libsrc/occ/vsocc.hpp
 create mode 100644 contrib/Netgen/libsrc/stlgeom/Makefile.am
 create mode 100644 contrib/Netgen/libsrc/stlgeom/meshstlsurface.cpp
 create mode 100644 contrib/Netgen/libsrc/stlgeom/meshstlsurface.hpp
 create mode 100644 contrib/Netgen/libsrc/stlgeom/stlgeom.cpp
 create mode 100644 contrib/Netgen/libsrc/stlgeom/stlgeom.hpp
 create mode 100644 contrib/Netgen/libsrc/stlgeom/stlgeomchart.cpp
 create mode 100644 contrib/Netgen/libsrc/stlgeom/stlgeommesh.cpp
 create mode 100644 contrib/Netgen/libsrc/stlgeom/stlline.cpp
 create mode 100644 contrib/Netgen/libsrc/stlgeom/stlline.hpp
 create mode 100644 contrib/Netgen/libsrc/stlgeom/stlpkg.cpp
 create mode 100644 contrib/Netgen/libsrc/stlgeom/stltool.cpp
 create mode 100644 contrib/Netgen/libsrc/stlgeom/stltool.hpp
 create mode 100644 contrib/Netgen/libsrc/stlgeom/stltopology.cpp
 create mode 100644 contrib/Netgen/libsrc/stlgeom/stltopology.hpp
 create mode 100644 contrib/Netgen/libsrc/stlgeom/vsstl.cpp
 create mode 100644 contrib/Netgen/libsrc/stlgeom/vsstl.hpp
 create mode 100644 contrib/Netgen/libsrc/visualization/Makefile.am
 create mode 100644 contrib/Netgen/libsrc/visualization/importsolution.cpp
 create mode 100644 contrib/Netgen/libsrc/visualization/meshdoc.cpp
 create mode 100644 contrib/Netgen/libsrc/visualization/meshdoc.hpp
 create mode 100644 contrib/Netgen/libsrc/visualization/mvdraw.cpp
 create mode 100644 contrib/Netgen/libsrc/visualization/mvdraw.hpp
 create mode 100644 contrib/Netgen/libsrc/visualization/soldata.hpp
 create mode 100644 contrib/Netgen/libsrc/visualization/stlmeshing.cpp
 create mode 100644 contrib/Netgen/libsrc/visualization/vispar.hpp
 create mode 100644 contrib/Netgen/libsrc/visualization/visual.hpp
 create mode 100644 contrib/Netgen/libsrc/visualization/vscsg.cpp
 create mode 100644 contrib/Netgen/libsrc/visualization/vsfieldlines.cpp
 create mode 100644 contrib/Netgen/libsrc/visualization/vsmesh.cpp
 create mode 100644 contrib/Netgen/libsrc/visualization/vsocc.cpp
 create mode 100644 contrib/Netgen/libsrc/visualization/vssolution.cpp
 create mode 100644 contrib/Netgen/libsrc/visualization/vssolution.hpp

diff --git a/contrib/Netgen/libsrc/Makefile.am b/contrib/Netgen/libsrc/Makefile.am
new file mode 100644
index 0000000000..8337b4b7f7
--- /dev/null
+++ b/contrib/Netgen/libsrc/Makefile.am
@@ -0,0 +1,5 @@
+AM_CPPFLAGS = 
+
+METASOURCES = AUTO
+
+SUBDIRS = general gprim  linalg include meshing  interface csg geom2d occ stlgeom visualization
diff --git a/contrib/Netgen/libsrc/csg/Makefile.am b/contrib/Netgen/libsrc/csg/Makefile.am
new file mode 100644
index 0000000000..acf35b00d9
--- /dev/null
+++ b/contrib/Netgen/libsrc/csg/Makefile.am
@@ -0,0 +1,26 @@
+noinst_HEADERS = algprim.hpp csgparser.hpp extrusion.hpp manifold.hpp \
+singularref.hpp surface.hpp brick.hpp curve2d.hpp gencyl.hpp	      \
+meshsurf.hpp solid.hpp triapprox.hpp csgeom.hpp edgeflw.hpp geoml.hpp \
+polyhedra.hpp specpoin.hpp csg.hpp explicitcurve2d.hpp identify.hpp   \
+revolution.hpp spline3d.hpp vscsg.hpp
+
+
+AM_CPPFLAGS = -I$(top_srcdir)/libsrc/include  $(TCL_INCLUDES)
+METASOURCES = AUTO
+
+lib_LTLIBRARIES = libcsg.la  libcsgvis.la 
+
+
+libcsg_la_SOURCES = algprim.cpp brick.cpp   \
+bspline2d.cpp csgeom.cpp csgparser.cpp curve2d.cpp edgeflw.cpp	       \
+explicitcurve2d.cpp extrusion.cpp gencyl.cpp genmesh.cpp identify.cpp  \
+manifold.cpp meshsurf.cpp polyhedra.cpp revolution.cpp singularref.cpp \
+solid.cpp specpoin.cpp spline3d.cpp surface.cpp triapprox.cpp
+
+
+libcsgvis_la_SOURCES = vscsg.cpp csgpkg.cpp
+
+
+libcsgvis_la_LIBADD = libcsg.la
+#   $(top_builddir)/libsrc/geom2d/libgeom2d.la 
+
diff --git a/contrib/Netgen/libsrc/csg/algprim.cpp b/contrib/Netgen/libsrc/csg/algprim.cpp
new file mode 100644
index 0000000000..09bad01327
--- /dev/null
+++ b/contrib/Netgen/libsrc/csg/algprim.cpp
@@ -0,0 +1,1727 @@
+#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;
+  }
+
+
+  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)
+  {
+    eps_base = 1e-8;
+
+    p = ap;
+    n = an;
+    CalcData();
+  }
+
+  void Plane :: CalcData()
+  {
+    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;
+
+    CalcData();
+  }
+
+
+
+  void Plane :: GetPrimitiveData (const 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);
+
+    CalcData();
+  }
+
+  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
+  {
+    const Plane * ps2 = dynamic_cast<const Plane*>(&s2);
+
+    if(ps2)
+      {
+        Point<3> pp2 = ps2->GetSurfacePoint();
+        Vec<3> n2 = s2.GetNormalVector(pp2);
+
+        if(fabs(n*n2) < 1.-eps_base)
+          return 0;
+
+        if (fabs (s2.CalcFunctionValue(p)) > eps) return 0;
+      }
+    else
+      {
+        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;
+    n1 = GetNormalVector (p);
+    n2 = s2.GetNormalVector (p);
+    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
+  {
+    p3d = p1 + (h * pplane(0)) * ex + (h * pplane(1)) * ey;
+  }
+
+
+  void Plane :: Project (Point<3> & p3d) const
+  {
+    double val = Plane::CalcFunctionValue (p3d);
+    p3d -= val * n;
+  }
+
+  INSOLID_TYPE Plane :: BoxInSolid (const BoxSphere<3> & box) const
+  {
+    int i;
+    double val;
+    Point<3> pp;
+
+    val = Plane::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++)
+          {
+            pp = box.GetPointNr (i);
+            val = Plane::CalcFunctionValue (pp);
+            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++)
+          {
+            pp = box.GetPointNr (i);
+            val = Plane::CalcFunctionValue (pp);
+            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;
+    invr = 1.0/r;
+
+    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 (const 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);
+
+    invr = 1.0/r;
+    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;
+  }
+
+
+  double Sphere :: CalcFunctionValue (const Point<3> & point) const
+  {
+    return 0.5* (invr * Abs2 (point-c) - r);
+  }
+
+
+  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 n = int(facets) + 1;  
+
+    for (int j = 0; j <= n; j++)
+      for (int i = 0; i <= n; i++)
+        {
+          double lg = 2 * M_PI * double (i) / n;
+          double 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 (int j = 0; j < n; j++)
+      for (int 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;
+
+    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 < 1e-32) lv1 = 1;
+    double lv2 = v2.Length2 ();
+    if (lv2 < 1e-32) lv2 = 1;
+    double lv3 = v3.Length2 ();
+    if (lv3 < 1e-32) 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);
+  }
+
+  double Ellipsoid :: MaxCurvature () const
+  {
+    const double a2 = v1.Length2();
+    const double b2 = v2.Length2();
+    const double c2 = v3.Length2();
+
+    return max3 ( sqrt(a2)/min2(b2,c2), sqrt(b2)/min2(a2,c2), sqrt(c2)/min2(a2,b2) );
+  }
+
+  Point<3> Ellipsoid :: GetSurfacePoint () const
+  {
+    return a + v1;
+  }
+
+
+
+  void Ellipsoid :: GetTriangleApproximation 
+  (TriangleApproximation & tas, 
+   const Box<3> & /* boundingbox */, double facets) const
+  {
+    int n = int(facets) + 1;  
+
+    for (int j = 0; j <= n; j++)
+      for (int i = 0; i <= n; i++)
+        {
+          double lg = 2 * M_PI * double (i) / n;
+          double 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 (int j = 0; j < n; j++)
+      for (int 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 (Array<double> & coeffs)
+  {
+    SetPrimitiveData(coeffs);
+  }
+
+  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 (const 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);
+  }
+
+
+  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 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 (int j = 0; j <= n; j++)
+      for (int i = 0; i <= n; i++)
+        {
+          double lg = 2 * M_PI * double (i) / n;
+          double bg = double(j) / n;
+
+          Point<3> p = a + (bg * lvab) 
+            + ((r * cos(lg)) * n1) 
+            + ((r * sin(lg)) * n2);
+
+          tas.AddPoint (p);
+        }
+
+    for (int j = 0; j < n; j++)
+      for (int 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;
+    if(avl.Length2() > avs.Length2())
+      {
+        vl = avl;
+        vs = avs;
+      }
+    else
+      {
+        vl = avs;
+        vs = avl;
+      }
+
+    CalcData();
+  }
+
+  EllipticCylinder :: EllipticCylinder (Array<double> & coeffs)
+  {
+    SetPrimitiveData(coeffs);
+  }
+
+
+
+  void EllipticCylinder :: GetPrimitiveData (const char *& classname, Array<double> & coeffs) const
+  {
+    classname = "ellipticcylinder";
+    coeffs.SetSize (9);
+    coeffs[0] = a(0);
+    coeffs[1] = a(1);
+    coeffs[2] = a(2);
+    coeffs[3] = vl(0);
+    coeffs[4] = vl(1);
+    coeffs[5] = vl(2);
+    coeffs[6] = vs(0);
+    coeffs[7] = vs(1);
+    coeffs[8] = vs(2);
+  }
+
+  void EllipticCylinder :: SetPrimitiveData (Array<double> & coeffs)
+  {
+    a(0) = coeffs[0];
+    a(1) = coeffs[1];
+    a(2) = coeffs[2];
+    vl(0) = coeffs[3];
+    vl(1) = coeffs[4];
+    vl(2) = coeffs[5];
+    vs(0) = coeffs[6];
+    vs(1) = coeffs[7];
+    vs(2) = coeffs[8];
+
+    CalcData();
+  }
+
+
+
+  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 < 1e-32) lvl = 1;
+    double lvs = vs.Length2 ();
+    if (lvs < 1e-32) 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 = pow(va * hvl,2) + pow(va * hvs,2) - 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/min(vs.Length2 (),vl.Length2());
+  }
+
+  double EllipticCylinder :: MaxCurvature () const
+  {
+    double aa = vs.Length();
+    double bb = vl.Length();
+
+    return max2(bb/(aa*aa),aa/(bb*bb));
+  }
+
+  double EllipticCylinder :: MaxCurvatureLoc (const Point<3> & /* c */, 
+                                              double /* rad */) const
+  {
+    // saubere Loesung wird noch notwendig !!!
+    double aa = vs.Length();
+    double bb = vl.Length();
+    return max2(bb/(aa*aa),aa/(bb*bb));
+  }
+
+
+
+  Point<3> EllipticCylinder :: GetSurfacePoint () const
+  {
+    return a + vl;
+  }
+
+
+
+  void EllipticCylinder :: GetTriangleApproximation 
+  (TriangleApproximation & tas, 
+   const Box<3> & /* boundingbox */, double facets) const
+  {
+    int n = int(facets) + 1;  
+
+    Vec<3> axis = Cross (vl, vs);
+
+    for (int j = 0; j <= n; j++)
+      for (int i = 0; i <= n; i++)
+        {
+          double lg = 2 * M_PI * double (i) / n;
+          double bg = double(j) / n;
+
+          Point<3> p = a + (bg * axis)
+            + cos(lg) * vl + sin(lg) * vs;
+
+          tas.AddPoint (p);
+        }
+
+    for (int j = 0; j < n; j++)
+      for (int 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 (const 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^2k
+
+    cosphi = vabl / sqrt (vabl*vabl+sqr(ra-rb));
+
+    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;
+
+
+    double maxr = max2(ra,rb);
+    cxx /= maxr; cyy /= maxr; czz /= maxr;
+    cxy /= maxr; cxz /= maxr; cyz /= maxr;
+    cx /= maxr; cy /= maxr; cz /= maxr;
+    c1 /= maxr;
+
+
+    // (*testout) << "t0vec = " << t0vec << " t0 = " << t0 << endl;
+    // (*testout) << "t1vec = " << t1vec << " t1 = " << t1 << endl;
+    // PrintCoeff (*testout);
+  }
+
+
+  INSOLID_TYPE Cone :: BoxInSolid (const BoxSphere<3> & box) const
+  {
+    Vec<3> cv(box.Center());
+
+    double rzp = cv * t1vec + t1;
+    double dist = sqrt (CalcFunctionValue(box.Center()) *max2(ra,rb) + rzp * rzp) - rzp;
+
+    dist *= cosphi;
+    INSOLID_TYPE res = DOES_INTERSECT;
+
+    if (dist - box.Diam() > 0) res = IS_OUTSIDE;
+    if (dist + box.Diam() < 0) res = IS_INSIDE;
+
+    return res;
+  }
+
+
+  double Cone :: HesseNorm () const
+  {
+    // cout << "2/minr = " << 2/minr << ",  cxx .. = " << cxx << ", " << cyy << ", " << czz << endl;
+    return 2 / minr;
+  }
+
+
+  double Cone ::  LocH (const Point<3> & p, double /* x */, 
+                        double /* c */, double hmax) const
+  {
+    //double bloch = Surface::LocH (p, x, c, hmax);
+    Vec<3> g;
+    CalcGradient (p, g);
+
+    double lam = Abs(g);
+    double meancurv = 
+      -( 2  * g(0)*g(1)*cxy - 2 * czz * (g(0)*g(0)+g(1)*g(1))
+         +2 * g(1)*g(2)*cyz - 2 * cxx * (g(1)*g(1)+g(2)*g(2))
+         +2 * g(0)*g(2)*cxz - 2 * cyy * (g(0)*g(0)+g(2)*g(2))) / (3*lam*lam*lam);
+
+    // cout << "type = " << typeid(*this).name() << ", baseh = " << bloch << ", meancurv = " << meancurv << endl;
+    // return bloch;
+  
+    meancurv = fabs (meancurv);
+    if (meancurv < 1e-20) meancurv = 1e-20;
+
+    // cout << "c = " << c << ", safety = " << mparam.curvaturesafety << endl;
+    double hcurv = 1.0/(4*meancurv*mparam.curvaturesafety);
+
+    return min2 (hmax, hcurv);
+  }
+
+
+  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));
+        }
+  }
+
+
+
+
+
+
+
+
+
+  /// Torus 
+  /// Lorenzo Codecasa (codecasa@elet.polimi.it)
+  /// April 27th, 2005 
+  ///
+  Torus :: Torus (const Point<3> & ac, const Vec<3> & an, double aR, double ar)
+  {
+    c = ac;
+    n = an;
+    n.Normalize();
+    R = aR;
+    r = ar;
+  }
+
+  void Torus :: GetPrimitiveData (const char *& classname, Array<double> & coeffs) const
+  {
+    classname = "torus";
+    coeffs.SetSize (8);
+    coeffs.Elem(1) = c(0);
+    coeffs.Elem(2) = c(1);
+    coeffs.Elem(3) = c(2);
+    coeffs.Elem(4) = n(0);
+    coeffs.Elem(5) = n(1);
+    coeffs.Elem(6) = n(2);
+    coeffs.Elem(7) = R;
+    coeffs.Elem(8) = r;
+  }
+
+  void Torus :: SetPrimitiveData (Array<double> & coeffs)
+  {
+    c(0) = coeffs.Elem(1);
+    c(1) = coeffs.Elem(2);
+    c(2) = coeffs.Elem(3);
+    n(0) = coeffs.Elem(4);
+    n(1) = coeffs.Elem(5);
+    n(2) = coeffs.Elem(6);
+    R = coeffs.Elem(7);
+    r = coeffs.Elem(8);
+  }
+
+  Primitive * Torus :: CreateDefault ()
+  {
+    return new Torus (Point<3> (0,0,0), Vec<3> (0,0,1), 2, 1);
+  }
+
+  Primitive * Torus :: Copy () const
+  {
+    return new Torus (c, n, R, r);
+  }
+
+  void Torus :: Transform (Transformation<3> & trans)
+  {
+    Point<3> hc;
+    trans.Transform (c, hc);
+    c = hc;
+  
+    Vec<3> hn;
+    trans.Transform (n, hn);
+    n = hn;
+  }
+
+  int Torus :: IsIdentic (const Surface & s2, int & inv, double eps) const
+  {
+    const Torus * torus2 = dynamic_cast<const Torus*>  (&s2);
+
+    if (!torus2) return 0;
+
+    if (fabs (torus2->R - R) > eps) return 0;
+  
+    if (fabs (torus2->r - r) > eps) return 0;
+
+    Vec<3> v2 = torus2->n - n;
+    if ( v2 * v2 > eps ) return 0;
+  
+    v2 = torus2->c - c;
+    if ( v2 * v2 > eps ) return 0;
+
+    inv = 0;
+    return 1;
+  }
+
+  double Torus :: CalcFunctionValue (const Point<3> & point) const
+  {
+    /*
+    // original version
+    Vec<3> v1 = point - c;
+    double a1 = Abs2 (v1);         // v1(0) * v1(0) + v1(1) * v1(1) + v1(2) * v1(2);
+    double a2 = n * v1;            // n(0) * v1(0) + n(1) * v1(1) + n(2) * v1(2);
+    double a3 = a1 + R * R - r * r;
+    double a4 = Abs2 (n);          // n(0) * n(0) + n(1) * n(1) + n(2) * n(2);
+
+    return ( a3 * a3 -4 * R * R * ( a1 - a2 * a2 / a4 ) ) / ( R * R * R );
+    */
+
+    
+    // JS, April 2011
+    Vec<3> v1 = point-c;
+    double abs2 = Abs2(v1);
+    double tau = v1 * n;
+    double rho = sqrt (abs2 - tau*tau);
+    return sqr (R - rho) + tau*tau - r*r;
+
+    // double val2 = sqr (tau*tau + sqr (R - rho) -r*r) / (R*R*R);
+  }
+
+  void Torus :: CalcGradient (const Point<3> & point, Vec<3> & grad) const
+  {
+    /*
+    Vec<3> v1 = point - c;
+    double a1 = v1(0) * v1(0) + v1(1) * v1(1) + v1(2) * v1(2);
+    double a2 = n(0) * v1(0) + n(1) * v1(1) + n(2) * v1(2);
+    double a3 = a1 - R * R - r * r;
+    double a4 = n(0) * n(0) + n(1) * n(1) + n(2) * n(2);
+    grad(0) = ( 4 * a3 * v1(0) + 8 * R * R * a2 / a4 * n(0) ) / ( R * R * R );
+    grad(1) = ( 4 * a3 * v1(1) + 8 * R * R * a2 / a4 * n(1) ) / ( R * R * R );
+    grad(2) = ( 4 * a3 * v1(2) + 8 * R * R * a2 / a4 * n(2) ) / ( R * R * R );
+    */
+
+    Vec<3> v1 = point-c;
+    double abs2 = Abs2(v1);
+    double tau = v1 * n;
+    double rho = sqrt (abs2 - tau*tau);
+    double func = sqr (R - rho) + tau*tau - r*r;
+
+    Vec<3> gradabs2 = 2 * v1;
+    Vec<3> gradtau = n;
+    Vec<3> gradrho = 0.5 / rho * (gradabs2 - 2 * tau * gradtau);
+    grad = -2 * (R - rho) * gradrho  + 2 * tau * gradtau;
+  }
+
+  void Torus :: CalcHesse (const Point<3> & point, Mat<3> & hesse) const
+  {
+    Surface::CalcHesse (point, hesse);
+    return;
+
+    Vec<3> v1 = point - c;
+    double a1 = v1(0) * v1(0) + v1(1) * v1(1) + v1(2) * v1(2);
+    double a3 = a1 - R * R - r * r;
+    double a4 = n(0) * n(0) + n(1) * n(1) + n(2) * n(2);
+    hesse(0,0) = ( 4 * a3 + 8 * (v1(0) * v1(0) + (R * n(0)) * (R * n(0)) / a4 ) ) / ( R * R * R );
+    hesse(1,1) = ( 4 * a3 + 8 * (v1(1) * v1(1) + (R * n(1)) * (R * n(1)) / a4 ) ) / ( R * R * R );
+    hesse(2,2) = ( 4 * a3 + 8 * (v1(2) * v1(2) + (R * n(2)) * (R * n(2)) / a4 ) ) / ( R * R * R );
+    hesse(0,1) = hesse(1,0) = 8 * (v1(0) * v1(1) + (R * n(0)) * (R * n(1)) / a4 ) / ( R * R * R );
+    hesse(1,2) = hesse(2,1) = 8 * (v1(1) * v1(2) + (R * n(1)) * (R * n(2)) / a4) / ( R * R * R );
+    hesse(0,2) = hesse(2,0) = 8 * (v1(0) * v1(2) + (R * n(0)) * (R * n(2)) / a4) / ( R * R * R );
+  }
+
+  double Torus :: HesseNorm () const
+  {	
+    return 4/(r*r);
+    // return  ( 2 / r + 2 / ( R - r ) );
+  }
+
+  Point<3> Torus :: GetSurfacePoint () const
+  {
+    Vec<3> vn = n.GetNormal();
+    return c + ( R + r ) * vn.Normalize();
+  }
+
+  /// void Torus :: DefineTangentialPlane (const Point<3> & ap1, const Point<3> & ap2)
+  /// {
+  /// }
+
+  /// void Torus :: ToPlane (const Point<3> & p, 
+  ///			  Point<2> & pplane, 
+  ///			  double h, int & zone) const
+  /// {
+  /// }
+
+  /// void Torus :: FromPlane (const Point<2> & pplane, Point<3> & p, double h) const
+  /// {
+  /// }
+
+  /// void Torus :: Project (Point<3> & p) const
+  /// {
+  /// }
+
+  INSOLID_TYPE Torus :: BoxInSolid (const BoxSphere<3> & box) const
+  {
+    Vec<3> v1 = box.Center() - c;
+    double a1 = Abs2(v1);        // v1(0) * v1(0) + v1(1) * v1(1) + v1(2) * v1(2);
+    double a2 = n * v1;          // n(0) * v1(0) + n(1) * v1(1) + n(2) * v1(2);
+    double a4 = Abs2(n);         // n(0) * n(0) + n(1) * n(1) + n(2) * n(2);
+ 
+    double dist = sqrt( a1 + R * R - 2 * R * sqrt( a1 - a2 * a2 / a4) );
+
+    if (dist - box.Diam()/2 > r) return IS_OUTSIDE;
+    if (dist + box.Diam()/2 < r) return IS_INSIDE;
+    return DOES_INTERSECT;
+  }
+
+  void Torus :: GetTriangleApproximation (TriangleApproximation & tas, 
+                                          const Box<3> & /* boundingbox */, double facets) const
+  {
+    int N = int(facets) + 1;  
+
+    Vec<3> lvab = n ;
+    lvab.Normalize();
+  
+    Vec<3> n1 = lvab.GetNormal();
+    n1.Normalize();
+  
+    Vec<3> n2 = Cross(lvab, n1);
+    n2.Normalize();
+  
+    for (int j = 0; j <= N; j++)
+      for (int i = 0; i <= N; i++)
+	{
+          double lg = 2 * M_PI * double (i) / N;
+          double bg = 2 * M_PI * double(j) / N;
+	
+          Point<3> p = c + ( R + r * cos(lg) ) * ( cos(bg) * n1 + sin(bg) * n2 ) + r * sin(lg) * n;
+          tas.AddPoint (p);
+	}
+	
+    for (int j = 0; j < N; j++)
+      for (int 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));
+	}
+  } 
+  
+  void Torus :: Read (istream & ist)
+  {
+    ist >> c(0) >> c(1) >> c(2) >> n(0) >> n(1) >> n(2) >> R >> r;
+  }
+
+  void Torus :: Print (ostream & ost) const
+  {
+    ost << c(0) << "  " << c(1) << "  " << c(2) << "  "
+        << n(0) << "  " << n(1) << "  " << n(2) << "  "
+        << R    << "  " << r    << endl;
+  }
+
+
+
+}
diff --git a/contrib/Netgen/libsrc/csg/algprim.hpp b/contrib/Netgen/libsrc/csg/algprim.hpp
new file mode 100644
index 0000000000..82cd58e788
--- /dev/null
+++ b/contrib/Netgen/libsrc/csg/algprim.hpp
@@ -0,0 +1,446 @@
+#ifndef FILE_ALGPRIM
+#define FILE_ALGPRIM
+
+
+/**************************************************************************/
+/* File:   algprim.hpp                                                    */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   1. Dez. 95                                                     */
+/**************************************************************************/
+
+namespace netgen
+{
+
+  /*
+
+  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;
+
+    double eps_base;
+
+  public:
+    ///
+    Plane (const Point<3> & ap, Vec<3> an);
+
+    virtual void GetPrimitiveData (const 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;
+
+    ///
+    inline virtual double CalcFunctionValue (const Point<3> & p3d) const
+    {return cx * p3d(0) + cy * p3d(1) + cz * p3d(2) + c1;}
+    ///
+    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;
+  protected:
+    void CalcData();
+  };
+
+  // typedef Plane Plane;
+
+
+  ///
+  class Sphere : public QuadraticSurface
+  {
+    ///
+    Point<3> c;
+    ///
+    double r, invr;
+  public:
+    ///
+    Sphere (const Point<3> & ac, double ar);
+
+    virtual void GetPrimitiveData (const 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 double CalcFunctionValue (const Point<3> & point) const;
+
+
+    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);
+    Cylinder (Array<double> & coeffs);
+
+    virtual void GetPrimitiveData (const 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);
+    EllipticCylinder (Array<double> & coeffs);
+
+
+    // static Primitive * CreateDefault ();
+    virtual void GetPrimitiveData (const 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;
+
+  
+    virtual double MaxCurvature () const;
+
+    virtual double MaxCurvatureLoc (const Point<3> & /* c */ , 
+				    double /* rad */) 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 double MaxCurvature () 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;
+    double cosphi;
+  public:
+    ///
+    Cone (const Point<3> & aa, const Point<3> & ab, double ara, double arb);
+    ///
+    static Primitive * CreateDefault ();
+    virtual void GetPrimitiveData (const 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 double LocH (const Point<3> & p, double x, 
+			 double c, double hmax) const;
+
+    ///
+    virtual Point<3> GetSurfacePoint () const;
+
+    virtual void GetTriangleApproximation (TriangleApproximation & tas, 
+					   const Box<3> & bbox, 
+					   double facets) const;
+
+  private:
+    void CalcData();
+  };
+
+
+
+
+
+
+
+
+  /** Torus 
+  /// Lorenzo Codecasa (codecasa@elet.polimi.it)
+  /// April 27th, 2005 
+  */
+  class Torus : public OneSurfacePrimitive
+  { 
+    /// center of the torus
+    Point<3> c;
+    /// vector normal to the symmetry plane of the torus
+    Vec<3> n;
+    /// Large radius of the torus
+    double R;
+    /// Small radius of the torus
+    double r;
+  
+  public:
+    /// OK
+    Torus (const Point<3> & ac, const Vec<3> & an, double aR, double ar);
+    /// OK
+    const Point<3> & Center () const { return c; }
+    /// OK
+    const Vec<3> & NormalToPlane () const { return n; }
+    /// OK
+    double LargeRadius () const { return R; }
+    /// OK
+    double SmallRadius () const { return r; }
+    /// OK
+    virtual double CalcFunctionValue (const Point<3> & point) const;
+    /// OK
+    virtual void CalcGradient (const Point<3> & point, Vec<3> & grad) const;
+    /// OK
+    virtual void CalcHesse (const Point<3> & point, Mat<3> & hesse) const;
+    /// OK
+    virtual double HesseNorm () const;
+    /// OK
+    virtual Point<3> GetSurfacePoint () const;
+    /// OK
+    virtual void GetPrimitiveData (const char *& classname, 
+				   Array<double> & coeffs) const;
+    /// OK			 
+    virtual void SetPrimitiveData (Array<double> & coeffs);
+    /// OK
+    static Primitive * CreateDefault ();
+    /// OK
+    virtual Primitive * Copy () const;
+    /// OK
+    virtual void Transform (Transformation<3> & trans);
+    /// OK
+    virtual int IsIdentic (const Surface & s2, int & inv, double eps) const;
+    /// OK
+    /// virtual void DefineTangentialPlane (const Point<3> & ap1, 
+    //				      const Point<3> & ap2);
+    /// OK
+    /// virtual void ToPlane (const Point<3> & p3d, 
+    ///			Point<2> & pplane, 
+    ///			double h, int & zone) const;
+    /// OK
+    /// virtual void FromPlane (const Point<2> & pplane, 
+    //			  Point<3> & p, double h) const;
+    /// OK
+    /// virtual void Project (Point<3> & p) const;
+    /// OK
+    virtual INSOLID_TYPE BoxInSolid (const BoxSphere<3> & box) const;
+    /// OK
+    virtual void GetTriangleApproximation (TriangleApproximation & tas, 
+					   const Box<3> & bbox, 
+					   double facets) const;
+    /// OK		 
+    virtual void Print (ostream & ist) const;
+    /// OK
+    virtual void Read (istream & ist);
+  };
+
+  /// ...end
+
+
+}
+
+
+
+
+
+#endif
diff --git a/contrib/Netgen/libsrc/csg/brick.cpp b/contrib/Netgen/libsrc/csg/brick.cpp
new file mode 100644
index 0000000000..54c23b1740
--- /dev/null
+++ b/contrib/Netgen/libsrc/csg/brick.cpp
@@ -0,0 +1,526 @@
+#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;
+      n2 = s2.GetNormalVector(p1);
+      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));
+}
+
+
+
+Primitive * Brick :: Copy () const
+{
+  return new Brick (p1, p2, p3, p4);
+}
+
+void  Brick :: Transform (Transformation<3> & trans)
+{
+  trans.Transform (p1);
+  trans.Transform (p2);
+  trans.Transform (p3);
+  trans.Transform (p4);
+
+  CalcData();
+}
+
+
+
+
+
+
+
+
+
+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;
+
+  Point<3> p[8];
+  for (int j = 0; j < 8; j++)
+    p[j] = box.GetPointNr(j);
+
+  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]->Plane::CalcFunctionValue (p[j]);
+
+	  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] -> Plane::CalcFunctionValue (p);
+  for (int i = 1; i < 6; i++)
+    {
+      double val = faces[i] -> Plane::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 result = IS_INSIDE;
+  for (int i = 0; i < faces.Size(); i++)
+    {
+      INSOLID_TYPE hres = faces[i]->VecInSolid(p, v, eps);
+      if (hres == IS_OUTSIDE || result == IS_OUTSIDE) result = IS_OUTSIDE;
+      else if (hres == DOES_INTERSECT || result == DOES_INTERSECT) result = DOES_INTERSECT;
+      else result = IS_INSIDE;
+    }
+  return result;
+
+  /*
+  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);
+  */
+}
+
+
+
+
+
+INSOLID_TYPE Brick :: VecInSolid2 (const Point<3> & p,
+				    const Vec<3> & v1,
+				    const Vec<3> & v2,
+				    double eps) const
+{
+  INSOLID_TYPE result = IS_INSIDE;
+  for (int i = 0; i < faces.Size(); i++)
+    {
+      INSOLID_TYPE hres = faces[i]->VecInSolid2(p, v1, v2, eps);
+      if (hres == IS_OUTSIDE || result == IS_OUTSIDE) result = IS_OUTSIDE;
+      else if (hres == DOES_INTERSECT || result == DOES_INTERSECT) result = DOES_INTERSECT;
+      else result = IS_INSIDE;
+    }
+  return result;
+}
+
+INSOLID_TYPE Brick :: VecInSolid3 (const Point<3> & p,
+				    const Vec<3> & v1,
+				    const Vec<3> & v2,
+				    double eps) const
+{
+  INSOLID_TYPE result = IS_INSIDE;
+  for (int i = 0; i < faces.Size(); i++)
+    {
+      INSOLID_TYPE hres = faces[i]->VecInSolid3(p, v1, v2, eps);
+      if (hres == IS_OUTSIDE || result == IS_OUTSIDE) result = IS_OUTSIDE;
+      else if (hres == DOES_INTERSECT || result == DOES_INTERSECT) result = DOES_INTERSECT;
+      else result = IS_INSIDE;
+    }
+  return result;
+}
+
+INSOLID_TYPE Brick :: VecInSolid4 (const Point<3> & p,
+				    const Vec<3> & v,
+				    const Vec<3> & v2,
+				    const Vec<3> & m,
+				    double eps) const
+{
+  INSOLID_TYPE result = IS_INSIDE;
+  for (int i = 0; i < faces.Size(); i++)
+    {
+      INSOLID_TYPE hres = faces[i]->VecInSolid4(p, v, v2, m, eps);
+      if (hres == IS_OUTSIDE || result == IS_OUTSIDE) result = IS_OUTSIDE;
+      else if (hres == DOES_INTERSECT || result == DOES_INTERSECT) result = DOES_INTERSECT;
+      else result = IS_INSIDE;
+    }
+  return result;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+void Brick :: 
+GetPrimitiveData (const 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> lp1 = pi[lface[i][0]-1];
+      const Point<3> lp2 = pi[lface[i][1]-1];
+      const Point<3> lp3 = pi[lface[i][2]-1];
+
+      Vec<3> n = Cross ((lp2-lp1), (lp3-lp1));
+      n.Normalize();
+      
+      for (j = 0; j < 3; j++)
+	{
+	  data[j] = lp1(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;
+  Point<3> p[8];
+  for(int j=0;j<8;j++)
+    p[j]=box.GetPointNr(j);
+
+  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]->Plane::CalcFunctionValue (p[j]);
+	  if (val > 0)  hasout = 1;
+	  else if (val < 0)  hasin = 1;
+	  if (hasout && hasin) break;
+	}
+      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/contrib/Netgen/libsrc/csg/brick.hpp b/contrib/Netgen/libsrc/csg/brick.hpp
new file mode 100644
index 0000000000..25b003e0e8
--- /dev/null
+++ b/contrib/Netgen/libsrc/csg/brick.hpp
@@ -0,0 +1,126 @@
+#ifndef FILE_BRICK
+#define FILE_BRICK
+
+
+/**************************************************************************/
+/* File:   brick.hpp                                                      */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   11. Mar. 98                                                    */
+/**************************************************************************/
+
+namespace netgen
+{
+
+
+  /*
+
+  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;
+    Array<Plane*> faces;
+
+  public:
+    Brick (Point<3> ap1, Point<3> ap2, Point<3> ap3, Point<3> ap4);
+    virtual ~Brick ();
+    static Primitive * CreateDefault ();
+
+    virtual Primitive * Copy () const;
+    virtual void Transform (Transformation<3> & trans);
+
+
+    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 INSOLID_TYPE VecInSolid2 (const Point<3> & p,
+				      const Vec<3> & v1,
+				      const Vec<3> & v2,
+				      double eps) const;
+
+    virtual INSOLID_TYPE VecInSolid3 (const Point<3> & p,
+				      const Vec<3> & v1,
+				      const Vec<3> & v2,
+				      double eps) const;
+
+    virtual INSOLID_TYPE VecInSolid4 (const Point<3> & p,
+				      const Vec<3> & v,
+				      const Vec<3> & v2,
+				      const Vec<3> & m,
+				      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 (const 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/contrib/Netgen/libsrc/csg/bspline2d.cpp b/contrib/Netgen/libsrc/csg/bspline2d.cpp
new file mode 100644
index 0000000000..93b5e89621
--- /dev/null
+++ b/contrib/Netgen/libsrc/csg/bspline2d.cpp
@@ -0,0 +1,242 @@
+#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;
+
+  return scal >= 0;
+}
+  
+double BSplineCurve2d :: ProjectParam (const Point<2> & p) const
+{
+  double t, dt, mindist, mint = 0.0;
+  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 ddb1, ddb2, ddb3, ddb4;
+  Vec<2> hv;
+  
+  n = int(t);   
+  //  double 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/contrib/Netgen/libsrc/csg/csg.hpp b/contrib/Netgen/libsrc/csg/csg.hpp
new file mode 100644
index 0000000000..8ddf8d5087
--- /dev/null
+++ b/contrib/Netgen/libsrc/csg/csg.hpp
@@ -0,0 +1,44 @@
+#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>
+
+// #include <geometry2d.hpp>
+#include "../gprim/spline.hpp"
+#include "../gprim/splinegeometry.hpp"
+
+
+
+#include "surface.hpp"
+#include "solid.hpp"
+#include "identify.hpp"
+#include "singularref.hpp"
+#include "csgeom.hpp"
+#include "csgparser.hpp"
+
+
+#include "triapprox.hpp"
+#include "algprim.hpp"
+#include "brick.hpp"
+#include "spline3d.hpp"
+#include "manifold.hpp"
+#include "curve2d.hpp"
+#include "explicitcurve2d.hpp"
+#include "gencyl.hpp"
+#include "polyhedra.hpp"
+#include "extrusion.hpp"
+#include "revolution.hpp"
+#include "specpoin.hpp"
+#include "edgeflw.hpp"
+#include "meshsurf.hpp"
+
+
+#endif
diff --git a/contrib/Netgen/libsrc/csg/csgeom.cpp b/contrib/Netgen/libsrc/csg/csgeom.cpp
new file mode 100644
index 0000000000..ec8125da63
--- /dev/null
+++ b/contrib/Netgen/libsrc/csg/csgeom.cpp
@@ -0,0 +1,1500 @@
+#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);
+
+    bcname = "default";
+  }
+
+  void TopLevelObject :: GetData (ostream & ost)
+  {
+    ost << red << " " << green << " " << blue << " " 
+	<< transp << " " << visible << " ";
+  }
+
+  void TopLevelObject :: SetData (istream & ist)
+  {
+    ist >> red >> green >> blue >> transp >> visible;
+  }
+
+
+ 
+  Box<3> CSGeometry::default_boundingbox (Point<3> (-1000, -1000, -1000),
+					  Point<3> ( 1000,  1000,  1000));
+
+
+  CSGeometry :: CSGeometry ()
+    : boundingbox (default_boundingbox),
+      identicsurfaces (100), ideps(1e-9), filename("")
+  {
+    ;
+  }
+
+  CSGeometry :: CSGeometry (const string & afilename)
+    : boundingbox (default_boundingbox),
+      identicsurfaces (100), ideps(1e-9), filename(afilename)
+  {
+    changeval++;
+  }
+
+  CSGeometry :: ~CSGeometry ()
+  {
+    Clean();
+  }
+
+
+  void CSGeometry :: Clean ()
+  {
+    Array< Solid* > to_delete;
+    
+    for (int i = 0; i < solids.Size(); i++)
+      if(!to_delete.Contains(solids[i]->S1()))
+	to_delete.Append(solids[i]->S1());
+    for (int i = 0; i < solids.Size(); i++)
+      if(!to_delete.Contains(solids[i]))
+	to_delete.Append(solids[i]);
+    for(int i = 0; i < to_delete.Size(); i++)
+      delete to_delete[i];    
+    
+    /*
+    for (int i = 0; i < solids.Size(); i++)
+      delete solids[i]->S1();
+    for (int i = 0; i < solids.Size(); i++)
+      delete solids[i];
+    */
+
+    solids.DeleteAll ();
+
+    for (int i = 0; i < splinecurves2d.Size(); i++)
+      delete splinecurves2d[i];
+    splinecurves2d.DeleteAll();
+    
+    /*
+    for (int i = 0; i < surfaces.Size(); i++)
+      delete surfaces[i];
+    surfaces.DeleteAll ();
+    */
+    for(int i = 0; i<delete_them.Size(); i++)
+      delete delete_them[i];
+    delete_them.DeleteAll();
+    surfaces.DeleteAll();
+  
+    for (int i = 0; i < toplevelobjects.Size(); i++)
+      delete toplevelobjects[i];
+    toplevelobjects.DeleteAll ();
+    for (int i = 0; i < triapprox.Size(); i++)
+      delete triapprox[i];
+    triapprox.DeleteAll();
+
+    for(int i = 0; i < identifications.Size(); i++)
+      delete identifications[i];
+    identifications.DeleteAll();
+
+    for (int i = 0; i < singfaces.Size(); i++)
+      delete singfaces[i];
+    singfaces.DeleteAll();
+    for (int i = 0; i < singedges.Size(); i++)
+      delete singedges[i];
+    singedges.DeleteAll();
+    for (int i = 0; i < singpoints.Size(); i++)
+      delete singpoints[i];
+    singpoints.DeleteAll();
+
+    changeval++;
+  }
+
+
+  extern int CSGGenerateMesh (CSGeometry & geom, 
+			      Mesh *& mesh, MeshingParameters & mparam,
+			      int perfstepsstart, int perfstepsend);
+
+
+  int CSGeometry :: GenerateMesh (Mesh*& mesh, MeshingParameters & mparam,
+				 int perfstepsstart, int perfstepsend)
+  {
+    return CSGGenerateMesh (*this, mesh, mparam, perfstepsstart, perfstepsend);
+  }
+
+
+  const Refinement & CSGeometry :: GetRefinement () const
+  {
+    // cout << "get CSGeometry - Refinement" << endl;
+    // should become class variables
+    RefinementSurfaces * ref = new RefinementSurfaces(*this);
+    ref -> Set2dOptimizer(new MeshOptimize2dSurfaces(*this));
+    return *ref;
+  }
+
+  class WritePrimitivesIt : public SolidIterator
+  {
+    ostream & ost;
+  public:
+    WritePrimitivesIt (ostream & aost) : ost(aost) { ; }
+    virtual ~WritePrimitivesIt () { ; }
+
+    virtual void Do (Solid * sol);
+  };
+
+  void WritePrimitivesIt :: Do (Solid * sol) 
+  {
+    Primitive * prim = sol->GetPrimitive();
+    if (prim)
+      {
+	const 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 (string filename) const
+  {
+    fstream ost (filename.c_str());
+    Save (ost);
+  }
+  
+  void CSGeometry :: Save (ostream & ost) const
+  {
+    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);
+
+    for (int i = 0; i < solids.Size(); i++)
+      {
+	if (!solids[i]->GetPrimitive())
+	  {
+	    ost << "solid " << solids.GetName(i) << " ";
+	    solids[i] -> GetSolidData (ost);
+	    ost << endl;
+	  }
+      }
+
+    for (int 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 (int 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 :: SaveSurfaces (ostream & out) const
+  {
+    if(singfaces.Size() > 0 || singedges.Size() > 0 || singpoints.Size() > 0)
+      {
+	PrintMessage(3,"Singular faces/edges/points => no csg-information in .vol file");
+	return;
+      }
+
+
+    
+    Array<double> coeffs;
+    const char * classname;
+
+    out << "csgsurfaces " << GetNSurf() << "\n";
+    for(int i=0; i<GetNSurf(); i++)
+      {
+	const OneSurfacePrimitive * sp = dynamic_cast< const OneSurfacePrimitive * > (GetSurface(i));
+	const ExtrusionFace * ef = dynamic_cast< const ExtrusionFace * > (GetSurface(i));
+	const RevolutionFace * rf = dynamic_cast< const RevolutionFace * > (GetSurface(i));
+	const DummySurface * dummyf = dynamic_cast< const DummySurface * > (GetSurface(i));
+
+
+	if(sp)
+	  {
+	    sp->GetPrimitiveData(classname,coeffs);
+	
+	    out << classname << " ";
+	  }
+	else if(ef)
+	  {
+	    out << "extrusionface ";
+	    ef->GetRawData(coeffs);
+	  }
+	else if(rf)
+	  {
+	    out << "revolutionface ";
+	    rf->GetRawData(coeffs);
+	  }
+	else if(dummyf)
+	  {
+	    out << "dummy ";
+            coeffs.SetSize(0);
+	  }
+	else
+	  throw NgException ("Cannot write csg surface. Please, contact developers!");
+      
+	
+	out << coeffs.Size() << "\n";
+	for(int j=0; j<coeffs.Size(); j++)
+	  out << coeffs[j] << " ";
+	    
+	out << "\n";
+      }
+  }
+
+  void CSGeometry :: LoadSurfaces (istream & in)
+  {
+    Array<double> coeffs;
+    string classname;
+    int nsurfaces,size;
+
+    in >> classname;
+    
+    if(classname == "csgsurfaces")
+      in >> nsurfaces;
+    else
+      nsurfaces = atoi(classname.c_str());
+    
+    Point<3> dummypoint(0,0,0);
+    Vec<3> dummyvec(0,0,0);
+    double dummydouble(0.1);
+
+    for(int i=0; i<nsurfaces; i++)
+      {
+	in >> classname;
+	in >> size;
+
+	coeffs.SetSize(size);
+
+	for(int j=0; j<size; j++)
+	  in >> coeffs[j];
+
+	if(classname == "plane")
+	  {
+	    Plane * plane = new Plane(dummypoint,dummyvec);
+	    plane->SetPrimitiveData(coeffs);
+
+	    AddSurface(plane);
+	    delete_them.Append(plane);
+	  }
+
+	else if(classname == "sphere")
+	  {
+	    Sphere * sphere = new Sphere(dummypoint,dummydouble);
+	    sphere->SetPrimitiveData(coeffs);
+
+	    AddSurface(sphere);
+	    delete_them.Append(sphere);
+	  }
+
+	else if(classname == "cylinder")
+	  {
+	    Cylinder * cylinder = new Cylinder(coeffs);
+
+	    AddSurface(cylinder);
+	    delete_them.Append(cylinder);
+	  }
+
+	else if(classname == "ellipticcylinder")
+	  {
+	    EllipticCylinder * cylinder = new EllipticCylinder(coeffs);
+	    AddSurface(cylinder);
+	    delete_them.Append(cylinder);
+	  }
+
+
+	else if(classname == "torus")
+	  {
+	    Torus * torus = new Torus(dummypoint,dummyvec,dummydouble, dummydouble);
+	    torus->SetPrimitiveData(coeffs);
+	    AddSurface(torus);
+	    delete_them.Append(torus);
+	  }
+
+
+	else if(classname == "cone")
+	  {
+	    Cone * cone = new Cone(dummypoint,dummypoint,dummydouble,dummydouble);
+	    cone->SetPrimitiveData(coeffs);
+
+	    AddSurface(cone);
+	    delete_them.Append(cone);
+	  }
+
+	else if(classname == "extrusionface")
+	  {
+	    ExtrusionFace * ef =
+	      new ExtrusionFace(coeffs);
+
+	    AddSurface(ef);
+	    delete_them.Append(ef);
+	  }
+
+	else if(classname == "revolutionface")
+	  {
+	    RevolutionFace * rf =
+	      new RevolutionFace(coeffs);
+
+	    AddSurface(rf);
+	    delete_them.Append(rf);
+	  }
+
+	else if(classname == "dummy")
+	  {
+	    Surface * surf = new DummySurface();
+            
+	    AddSurface(surf);
+	    delete_them.Append(surf);
+	  }
+
+      }    
+  }
+    
+
+  void CSGeometry :: SaveToMeshFile (ostream & ost) const
+  {
+    SaveSurfaces (ost);
+  }
+
+
+
+
+  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)
+  { 
+    (*testout) << "Adding surface " << name << endl;
+    surfaces.Set (name, surf); 
+    surf->SetName (name);
+    changeval++; 
+  }
+
+  void CSGeometry :: AddSurfaces (Primitive * prim)
+  {
+    for (int i = 0; i < prim->GetNSurfaces(); i++)
+      {
+	AddSurface (&prim->GetSurface(i));
+	prim->SetSurfaceId (i, GetNSurf()-1);
+	surf2prim.Append (prim);
+      }
+  }
+
+  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
+      throw NgException ("CSGeometry::GetSurface out of range");
+  }
+  */
+
+
+
+
+  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;
+  }
+
+
+
+
+  void CSGeometry :: SetSplineCurve (const char * name, SplineGeometry<2> * spl)
+  {
+    splinecurves2d.Set(name,spl);
+  }
+  void CSGeometry :: SetSplineCurve (const char * name, SplineGeometry<3> * spl)
+  {
+    splinecurves3d.Set(name,spl);
+  }
+
+
+  const SplineGeometry<2> * CSGeometry :: GetSplineCurve2d (const string & name) const
+  {
+    if (splinecurves2d.Used(name.c_str()))
+      return splinecurves2d.Get(name.c_str());
+    else
+      return NULL;
+  }
+  const SplineGeometry<3> * CSGeometry :: GetSplineCurve3d (const string & name) const
+  {
+    if (splinecurves3d.Used(name.c_str()))
+      return splinecurves3d.Get(name.c_str());
+    else
+      return NULL;
+  }
+
+
+
+    /*
+  class RemoveDummyIterator : public SolidIterator
+  {
+  public:
+  
+    RemoveDummyIterator() { ; }
+    virtual ~RemoveDummyIterator() { ; }
+    virtual void Do(Solid * sol);
+  };
+
+  void RemoveDummyIterator :: Do(Solid * sol)
+  {
+    cerr << "remove dummy iterator is obsolete" << endl;
+
+    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;
+  }
+
+  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.StringFlagDefined ("bcname") )
+      {
+	solid->GetSurfaceIndices (surfind);
+	string bcn = flags.GetStringFlag("bcname", "default");
+	for (i = 0; i < surfind.Size(); i++)
+	  {
+	    if(surfaces[surfind[i]]->GetBCName() == "default")
+	      surfaces[surfind[i]]->SetBCName(bcn);
+	  }
+      }
+
+    if (flags.StringListFlagDefined ("bcname"))
+      {
+	const Array<char*> & bcname = flags.GetStringListFlag("bcname");
+
+	Polyhedra * polyh;
+	if(solid->S1())
+	  polyh = dynamic_cast<Polyhedra *>(solid->S1()->GetPrimitive());
+	else
+	  polyh = dynamic_cast<Polyhedra *>(solid->GetPrimitive());
+
+	if(polyh)
+	  {
+	    Array < Array<int> * > polysurfs;
+	    polyh->GetPolySurfs(polysurfs);
+	    if(bcname.Size() != polysurfs.Size())
+	      cerr << "WARNING: solid \"" << solidname << "\" has " << polysurfs.Size()
+		   << " surfaces and should get " << bcname.Size() << " bc-names!" << endl;
+	    
+	    for ( i = 0; i < min2(polysurfs.Size(),bcname.Size()); i++)
+	      {
+		for (int j = 0; j < polysurfs[i]->Size(); j++)
+		  {
+		    if(surfaces[(*polysurfs[i])[j]]->GetBCName() == "default")
+		      surfaces[(*polysurfs[i])[j]]->SetBCName(bcname[i]);
+		  }
+		delete polysurfs[i];
+	      }
+	  }
+	else
+	  {
+	    solid->GetSurfaceIndices (surfind);
+	    if(bcname.Size() != surfind.Size())
+	      cerr << "WARNING: solid \"" << solidname << "\" has " << surfind.Size()
+		   << " surfaces and should get " << bcname.Size() << " bc-names!" << endl;
+	    
+	    for (i = 0; i < min2(surfind.Size(),bcname.Size()); i++)
+	      {
+		if(surfaces[surfind[i]]->GetBCName() == "default")
+		  surfaces[surfind[i]]->SetBCName(bcname[i]);
+	      }
+	  }
+      }
+
+    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);
+	  }
+      }
+   
+    if (flags.NumListFlagDefined ("bc"))
+      {
+	const Array<double> & bcnum = flags.GetNumListFlag("bc");
+
+	Polyhedra * polyh;
+	if(solid->S1())
+	  polyh = dynamic_cast<Polyhedra *>(solid->S1()->GetPrimitive());
+	else
+	  polyh = dynamic_cast<Polyhedra *>(solid->GetPrimitive());
+
+	if(polyh)
+	  {
+	    Array < Array<int> * > polysurfs;
+	    polyh->GetPolySurfs(polysurfs);
+	    if(bcnum.Size() != polysurfs.Size())
+	      cerr << "WARNING: solid \"" << solidname << "\" has " << polysurfs.Size()
+		   << " surfaces and should get " << bcnum.Size() << " bc-numbers!" << endl;
+	    
+	    for ( i = 0; i < min2(polysurfs.Size(),bcnum.Size()); i++)
+	      {
+		for (int j = 0; j < polysurfs[i]->Size(); j++)
+		  {
+		    if ( surfaces[(*polysurfs[i])[j]]->GetBCProperty() == -1 )
+		      surfaces[(*polysurfs[i])[j]]->SetBCProperty(int(bcnum[i]));
+		  }
+		delete polysurfs[i];
+	      }
+	  }
+	else
+	  {
+	    solid->GetSurfaceIndices (surfind);
+	    if(bcnum.Size() != surfind.Size())
+	      cerr << "WARNING: solid \"" << solidname << "\" has " << surfind.Size()
+		   << " surfaces and should get " << bcnum.Size() << " bc-numbers!" << endl;
+	    
+	    for (i = 0; i < min2(surfind.Size(),bcnum.Size()); i++)
+	      {
+		if (surfaces[surfind[i]]->GetBCProperty() == -1)
+		  surfaces[surfind[i]]->SetBCProperty(int(bcnum[i]));
+	      }
+	  }
+      }
+
+  }
+
+  void CSGeometry :: FindIdenticSurfaces (double eps)
+  {
+    int inv;
+    int nsurf = GetNSurf();
+
+    isidenticto.SetSize(nsurf);
+    for (int i = 0; i < nsurf; i++)
+      isidenticto[i] = i;
+  
+    //(*testout) << "jetzt!" << endl;
+    for (int i = 0; i < nsurf; i++)
+      for (int j = i+1; j < nsurf; j++)
+	{
+	  //(*testout) << "surf" << i << " surf" << j << endl;
+	  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 (int i = 0; i < isidenticto.Size(); i++)
+      (*testout) << i << " -> " << isidenticto[i] << endl;
+
+    /*    
+    for (int i = 0; i < nsurf; i++)
+      GetSurface(i)->Print (*testout);
+    */
+  }
+  
+
+  
+  void CSGeometry ::
+  GetSurfaceIndices (const Solid * sol, 
+		     const BoxSphere<3> & box, 
+		     Array<int> & locsurf) const
+  {
+    ReducePrimitiveIterator rpi(box);
+    UnReducePrimitiveIterator urpi;
+
+    ((Solid*)sol) -> IterateSolid (rpi);
+    sol -> GetSurfaceIndices (locsurf);
+    ((Solid*)sol) -> IterateSolid (urpi);
+
+    for (int i = locsurf.Size()-1; i >= 0; i--)
+      {
+	bool indep = 1;
+	for (int j = 0; j < i; j++)
+	  if (locsurf[i] == locsurf[j])
+	    {
+	      indep = 0;
+	      break;
+	    }
+
+	if (!indep) locsurf.Delete(i);
+      }
+  }
+
+
+
+  
+  void CSGeometry ::
+  GetIndependentSurfaceIndices (const Solid * sol, 
+				const BoxSphere<3> & box, 
+				Array<int> & locsurf) const
+  {
+    ReducePrimitiveIterator rpi(box);
+    UnReducePrimitiveIterator urpi;
+
+    ((Solid*)sol) -> IterateSolid (rpi);
+    sol -> GetSurfaceIndices (locsurf);
+    ((Solid*)sol) -> IterateSolid (urpi);
+
+    for (int i = 0; i < locsurf.Size(); i++)
+      locsurf[i] = isidenticto[locsurf[i]];
+
+    for (int i = locsurf.Size()-1; i >= 0; i--)
+      {
+	bool indep = 1;
+	for (int j = 0; j < i; j++)
+	  if (locsurf[i] == locsurf[j])
+	    {
+	      indep = 0;
+	      break;
+	    }
+
+	if (!indep) locsurf.Delete(i);
+      }
+
+
+    /*
+    // delete identified
+    for (int i = locsurf.Size()-1; i >= 0; i--)
+      {
+	bool indep = 1;
+	for (int j = 0; j < i; j++)
+	  {
+	    if (identicsurfaces.Used (INDEX_2::Sort (locsurf[i], locsurf[j])) !=
+		(isidenticto[locsurf[i]] == isidenticto[locsurf[j]]))
+	      {
+		cerr << "different result" << endl;
+		exit(1);
+	      }
+
+	    if (isidenticto[locsurf[i]] == isidenticto[locsurf[j]])
+	      {
+		indep = 0;
+		break;
+	      }
+	  }
+	if (!indep)
+	  locsurf.Delete(i);
+      }
+
+    for (int 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
+  {
+    cout << "very dangerous" << endl;
+    Point<3> p2 = p + 1e-2 * v;
+    BoxSphere<3> box (p2, p2);
+    box.Increase (1e-3);
+    box.CalcDiamCenter();
+    GetIndependentSurfaceIndices (sol, box, locsurf);
+  }
+
+
+  void CSGeometry ::
+  GetIndependentSurfaceIndices (Array<int> & locsurf) const
+  {
+    for (int i = 0; i < locsurf.Size(); i++)
+      locsurf[i] = isidenticto[locsurf[i]];
+
+    for (int i = locsurf.Size()-1; i >= 0; i--)
+      {
+	bool indep = 1;
+	for (int j = 0; j < i; j++)
+	  if (locsurf[i] == locsurf[j])
+	    {
+	      indep = 0;
+	      break;
+	    }
+
+	if (!indep) locsurf.Delete(i);
+      }
+  }
+
+
+
+
+
+
+
+
+
+  void CSGeometry :: 
+  CalcTriangleApproximation(double detail, double facets)
+  {
+    PrintMessage (1, "Calc Triangle Approximation");
+
+    try
+      {
+    //    FindIdenticSurfaces (1e-6);
+  
+    int ntlo = GetNTopLevelObjects();
+
+    for (int i = 0; i < triapprox.Size(); i++)
+      delete triapprox[i];
+    triapprox.SetSize (ntlo);
+
+    Array<int> surfind;
+    IndexSet iset(GetNSurf());
+
+    for (int i = 0; i < ntlo; i++)
+      {
+	Solid * sol;
+	Surface * surf;
+	GetTopLevelObject (i, sol, surf);
+
+	sol -> CalcSurfaceInverse ();
+
+	TriangleApproximation * tams = new TriangleApproximation();
+	triapprox[i] = tams;
+
+	// sol -> GetSurfaceIndices (surfind);
+	for (int j = 0; j < GetNSurf(); j++)
+	  // for (int jj = 0; jj < surfind.Size(); jj++)
+	  {
+	    // int j = surfind[jj];
+
+	    PrintMessageCR (3, "Surface ", j, "/", GetNSurf());
+	    // PrintMessageCR (3, "Surface ", j, "/", surfind.Size());
+
+	    if (surf && surf != GetSurface(j))
+	      continue;
+
+	    TriangleApproximation tas;
+	    GetSurface (j) -> GetTriangleApproximation (tas, boundingbox, facets);
+
+	    int oldnp = tams -> GetNP();
+
+	    if (!tas.GetNP())
+	      continue;
+
+	    for (int k = 0; k < tas.GetNP(); k++)
+	      {
+		tams -> AddPoint (tas.GetPoint(k));
+                Vec<3> n = GetSurface(j) -> GetNormalVector (tas.GetPoint(k)); 
+		n.Normalize();
+		if (GetSurface(j)->Inverse()) n *= -1;
+		tams -> AddNormal (n);
+	      }
+	  
+	    BoxSphere<3> surfbox;
+
+	    if (tas.GetNP())
+	      surfbox.Set (tas.GetPoint(0));
+	    for (int 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 (int 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, iset, 1);
+
+		    delete locsol;
+		  }
+	      }
+	  }
+
+	tams->RemoveUnusedPoints ();
+	PrintMessage (2, "Object ", i, " has ", tams->GetNT(), " triangles");
+      }
+      }
+    catch (exception)
+      {
+	cerr << "*************************************************************" << endl
+	     << "****   out of memory problem in CSG visualization        ****" << endl
+	     << "****   Restart netgen, and disable                       ****" << endl
+	     << "****   'Draw Geometry' in Geometry -> CSG Options        ****" << endl
+	     << "****   before loading the geometry                       ****" << endl
+	     << "****   meshing will still work !                         ****" << endl
+	     << "*************************************************************" << endl;
+	exit(1);
+      }
+    Change();
+  }
+
+
+
+  void CSGeometry ::
+  RefineTriangleApprox (Solid * locsol, 
+			int surfind,
+			const BoxSphere<3> & box, 
+			double detail,
+			const TATriangle & tria, 
+			TriangleApproximation & tams,
+			IndexSet & iset,
+                        int level)
+  {
+    // if (level > 10) return;
+
+    //tams.AddTriangle (tria);
+    //(*testout) << "tria " << tams.GetPoint(tria[0]) << " - " << tams.GetPoint(tria[1]) << " - " << tams.GetPoint(tria[2]) 
+    //       << " ( " << tria[0] << " " << tria[1] << " " << tria[2] << ")" <<endl;
+    //return;
+
+    int pinds[6];
+    ArrayMem<int,500> surfused(GetNSurf());
+  
+    ReducePrimitiveIterator rpi(box);
+    UnReducePrimitiveIterator urpi;
+
+    locsol -> IterateSolid (rpi);
+    //  locsol -> GetSurfaceIndices (lsurfi);
+
+
+    //    IndexSet iset(GetNSurf());
+    locsol -> GetSurfaceIndices (iset);
+    const Array<int> & lsurfi = iset.GetArray();
+
+    locsol -> IterateSolid (urpi);
+
+    int surfii = -1;
+    for (int i = 0; i < lsurfi.Size(); i++)
+      if (lsurfi[i] == surfind)
+	{
+	  surfii = i;
+	  break;
+	}
+
+    if (surfii == -1)
+      return;
+
+    int cntindep = 0;
+
+    for (int i = 0; i < lsurfi.Size(); i++)
+      {
+	int linkto = isidenticto[lsurfi[i]];
+	surfused[linkto] = 0;
+      }
+
+    for (int 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)
+      {
+	tams.AddTriangle (tria);
+	//(*testout) << "pos1 " << tams.GetPoint(tria[0]) << " - " << tams.GetPoint(tria[1]) << " - " << tams.GetPoint(tria[2]) << endl;
+	return;
+      }
+
+    if (cntindep == 2)
+      {
+	// just 2 surfaces:
+	// if smooth, project inner points to edge and finish
+
+	int otherind = -1;
+
+	for (int 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 ();
+
+	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 (int 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);
+		
+		//
+		/*
+		static int nos=0;
+		if(!onsurface[j])
+		  {
+		    nos++;
+		    cout << "NOT ON SURFACE!! "<< nos << endl;
+		  }
+		*/
+	      }
+	  
+	    for (int 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;
+
+		    double l2(100),l1(100);
+		    if ( fabs (f1-f2) > 1e-20 )
+		      {
+			l2 = -f1/(f2-f1);
+			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;
+
+// 		    if(fabs(pn(0)) > 4 || fabs(pn(1)) > 4 || fabs(pn(2)) > 4)
+// 		      {
+// 			cout << "p1 " << p1 << " p2 " << p2 
+// 			     << " f1 " << f1 << " f2 " << f2
+// 			     << " l1 " << l1 << " l2 " << l2 
+// 			     << " pn " << pn << endl;
+
+// 		      }
+
+		    
+		    //GetSurface (surfind)->Project (pn);
+		    
+		    pnums[lpin] = tams.AddPoint (pn);
+
+		    GetSurface (surfind)->Project (pn);
+		    
+		    Vec<3> n;
+		    n = GetSurface (surfind)->GetNormalVector (pn);
+		    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 (int j = 0; j < 3; j++)
+	      if (onsurface[j])
+		nvis++;
+
+	    for (int 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]);
+		//(*testout) << "pos2 " << tams.GetPoint(ntria[0]) << " - " << tams.GetPoint(ntria[1]) << " - " << tams.GetPoint(ntria[2]) << endl
+		//	   << "( " << ntria[0] << " - " << ntria[1] << " - " << ntria[2] << ")" << endl;
+		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)
+      {
+	//cout << "returning" << endl;
+	return;
+      }
+
+    for (int i = 0; i < 3; i++)
+      pinds[i] = tria[i];
+  
+    static int between[3][3] =
+      { { 0, 1, 5 },
+	{ 0, 2, 4 },
+	{ 1, 2, 3 } };
+  
+    for (int 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);
+
+	n = GetSurface(surfind)->GetNormalVector (newp);
+      
+	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 (int 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-8);
+	nbox.CalcDiamCenter();
+
+	Solid * nsol = locsol -> GetReducedSolid (nbox);
+
+	if (nsol)
+	  {
+	    RefineTriangleApprox (nsol, surfind, nbox, 
+				  detail, ntri, tams, iset, level+1);
+	  
+	    delete nsol;
+	  }
+      }
+  }
+
+
+
+
+  class ClearVisitedIt : public SolidIterator
+  {
+  public:
+    ClearVisitedIt () { ; }
+    virtual ~ClearVisitedIt () { ; }
+
+    virtual void Do (Solid * sol)
+    { 
+      sol -> visited = 0;
+    }
+  };
+
+
+  void CSGeometry :: 
+  IterateAllSolids (SolidIterator & it, bool only_once) const
+  {
+    if (only_once)
+      {
+	ClearVisitedIt clit;
+	for (int i = 0; i < solids.Size(); i++)
+	  solids[i] -> IterateSolid (clit, 0);
+      }
+
+    for (int i = 0; i < solids.Size(); i++)
+      solids[i] -> IterateSolid (it, only_once);
+  }
+
+
+  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/contrib/Netgen/libsrc/csg/csgeom.hpp b/contrib/Netgen/libsrc/csg/csgeom.hpp
new file mode 100644
index 0000000000..64badd492c
--- /dev/null
+++ b/contrib/Netgen/libsrc/csg/csgeom.hpp
@@ -0,0 +1,327 @@
+#ifndef FILE_CSGEOM
+#define FILE_CSGEOM
+
+/**************************************************************************/
+/* File:   csgeom.hh                                                      */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   27. Nov. 97                                                    */
+/**************************************************************************/
+
+namespace netgen
+{
+
+  /**
+     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
+    string bcname;
+
+  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; }
+
+    void SetBCName (string abc) { bcname = abc; }
+    const string GetBCName () const { return bcname; }
+  };
+
+
+
+
+
+  /**
+     CSGeometry has the whole geometric information
+  */
+  class CSGeometry : public NetgenGeometry
+  {
+  private:
+    /// all surfaces
+    SYMBOLTABLE<Surface*> surfaces;
+
+  public:
+    /// primitive of surface
+    Array<const Primitive*> surf2prim;
+
+  private:
+    Array<Surface*> delete_them;
+
+    /// all named solids
+    SYMBOLTABLE<Solid*> solids;
+
+    /// all 2d splinecurves
+    SYMBOLTABLE< SplineGeometry<2>* > splinecurves2d;
+    /// all 3d splinecurves
+    SYMBOLTABLE< SplineGeometry<3>* > splinecurves3d;
+
+    /// all top level objects: solids and surfaces
+    Array<TopLevelObject*> toplevelobjects;
+
+    /// additional points specified by user
+    Array<Point<3> > userpoints;
+    Array<double> userpoints_ref_factor;
+
+    mutable Array<Point<3> > identpoints;
+
+    /// triangular approximation of top level objects
+    Array<TriangleApproximation*> triapprox;
+
+    /// increment, if geometry is changed
+    static int changeval;
+  
+    /// bounding box of geometry
+    Box<3> boundingbox;
+
+    /// bounding box, if not set by input file
+    static Box<3> default_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, ...)
+
+    double ideps;
+
+    /// filename of inputfile
+    string filename;
+
+  public:
+    CSGeometry ();
+    CSGeometry (const string & afilename);
+    virtual ~CSGeometry ();
+
+    void Clean ();
+
+    virtual void Save (string filename) const;
+    void Save (ostream & ost) const;
+    void Load (istream & ist);
+
+    void SaveSurfaces (ostream & out) const;
+    void LoadSurfaces (istream & in);
+
+    virtual void SaveToMeshFile (ostream & ost) const;
+
+    int GetChangeVal() { return changeval; }
+    void Change() { changeval++; }
+
+    void AddSurface (Surface * surf);
+    void AddSurface (char * name, Surface * surf);
+    void AddSurfaces (Primitive * prim);
+
+    int GetNSurf () const { return surfaces.Size(); }
+    const Surface * GetSurface (const char * name) const;
+    const Surface * GetSurface (int i) const
+    { return surfaces[i]; }
+
+    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) const { return solids[i]; }
+    const SYMBOLTABLE<Solid*> & GetSolids () const { return solids; }
+
+
+    void SetSplineCurve (const char * name, SplineGeometry<2> * spl);
+    void SetSplineCurve (const char * name, SplineGeometry<3> * spl);
+    const SplineGeometry<2> * GetSplineCurve2d (const string & name) const;
+    const SplineGeometry<3> * GetSplineCurve3d (const string & name) const;
+    
+
+    void SetFlags (const char * solidname, const Flags & flags);
+
+
+    int GetNTopLevelObjects () const
+    { return toplevelobjects.Size(); }
+    int SetTopLevelObject (Solid * sol, Surface * surf = NULL);
+    void GetTopLevelObject (int nr, Solid *& sol, Surface *& surf)
+    {
+      sol = toplevelobjects[nr]->GetSolid();
+      surf = toplevelobjects[nr]->GetSurface();
+    }
+    void GetTopLevelObject (int nr, const Solid *& sol, const Surface *& surf) const
+    {
+      sol = toplevelobjects[nr]->GetSolid();
+      surf = toplevelobjects[nr]->GetSurface();
+    }
+
+    TopLevelObject * GetTopLevelObject (const Solid * sol, const Surface * surf = NULL);
+    TopLevelObject * GetTopLevelObject (int nr) const
+    { 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, double ref_factor = 0)
+    { userpoints.Append (p); userpoints_ref_factor.Append (ref_factor); }
+    int GetNUserPoints () const
+    { return userpoints.Size(); }
+    const Point<3> & GetUserPoint (int nr) const
+    { return userpoints[nr]; }
+    double GetUserPointRefFactor (int nr) const
+    { return userpoints_ref_factor[nr]; }
+  
+    void AddIdentPoint (const Point<3> & p) const
+    { identpoints.Append(p);}
+    int GetNIdentPoints (void) const
+    { return identpoints.Size();}
+    const Point<3> & GetIdentPoint(int nr) const
+    { return identpoints[nr]; }
+    void DeleteIdentPoints(void) const
+    { identpoints.DeleteAll();}
+
+
+    // quick implementations:
+    Array<SingularFace*> singfaces;
+    Array<SingularEdge*> singedges;
+    Array<SingularPoint*> singpoints;
+    Array<Identification*> identifications;
+
+    int GetNIdentifications (void) const { return identifications.Size(); }
+    void AddIdentification (Identification * ident);
+
+
+    ///
+    void CalcTriangleApproximation(double detail, double facets);
+
+    ///
+    void FindIdenticSurfaces (double eps);
+    ///
+    void GetSurfaceIndices (const Solid * sol, 
+			    const BoxSphere<3> & box, 
+			    Array<int> & locsurf) const;
+    ///
+    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;
+    ///
+    void GetIndependentSurfaceIndices (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, bool only_once = false) const;
+
+    void RefineTriangleApprox (Solid * locsol, 
+			       int surfind,
+			       const BoxSphere<3> & box, 
+			       double detail,
+			       const TATriangle & tria, 
+			       TriangleApproximation & tams,
+			       IndexSet & iset,
+			       int level);
+
+    const Box<3> & BoundingBox () const { return boundingbox; }
+
+    void SetBoundingBox (const Box<3> & abox)
+    {
+      boundingbox = abox;
+    }
+
+
+    static void SetDefaultBoundingBox (const Box<3> & abox)
+    {
+      default_boundingbox = abox;
+    }
+
+    double MaxSize () const;
+
+    void SetIdEps(double eps){ideps = eps;}
+    double GetIdEps(void) const {return ideps;}
+
+    class BCModification {
+    public:
+      int si;
+      int tlonr;
+      int bcnr;
+      string * bcname;
+    };
+
+    Array<BCModification> bcmodifications;
+
+    virtual int GenerateMesh (Mesh*& mesh, MeshingParameters & mparam, 
+			      int perfstepsstart, int perfstepsend);
+
+    virtual const Refinement & GetRefinement () const; 
+  };
+
+
+  
+
+
+}
+
+#endif
+
diff --git a/contrib/Netgen/libsrc/csg/csgparser.cpp b/contrib/Netgen/libsrc/csg/csgparser.cpp
new file mode 100644
index 0000000000..c2728bcdf3
--- /dev/null
+++ b/contrib/Netgen/libsrc/csg/csgparser.cpp
@@ -0,0 +1,1390 @@
+#include <mystdlib.h>
+#include <myadt.hpp>
+
+#include <linalg.hpp>
+#include <csg.hpp>
+
+
+namespace netgen
+{
+  static kwstruct defkw[] =
+    {
+      { TOK_RECO,    "algebraic3d" },
+      { TOK_SOLID,   "solid" },
+      { TOK_TLO,     "tlo" },
+      { TOK_CURVE2D, "curve2d" },
+      { TOK_CURVE3D, "curve3d" },
+      { TOK_BOUNDINGBOX, "boundingbox" },
+      { TOK_OR,      "or" },
+      { TOK_AND,     "and" },
+      { TOK_NOT,     "not" },
+      { TOK_SINGULAR, "singular" },
+      { TOK_EDGE,     "edge" },
+      { TOK_FACE,     "face" },
+      { TOK_POINT,    "point" },
+      { TOK_IDENTIFY, "identify" },
+      { TOK_CLOSESURFACES, "closesurfaces" },
+      { TOK_CLOSEEDGES, "closeedges" },
+      { TOK_PERIODIC,  "periodic" },
+      { TOK_BOUNDARYCONDITION, "boundarycondition" },
+      { TOK_BOUNDARYCONDITIONNAME, "boundaryconditionname" },
+      { TOK_DEFINE, "define" },
+      { TOK_CONSTANT, "constant" },
+      { TOKEN_TYPE(0), 0 }
+    };
+
+  static primstruct defprim[] =
+    {
+      { TOK_PLANE,     "plane" },
+      { TOK_SPHERE,    "sphere" },
+      { TOK_CYLINDER,  "cylinder" },
+      { TOK_CONE,      "cone" },
+      { TOK_ELLIPTICCYLINDER, "ellipticcylinder" },
+      { TOK_ELLIPSOID, "ellipsoid" },
+      { TOK_ORTHOBRICK, "orthobrick" },
+      { TOK_POLYHEDRON, "polyhedron" },
+      { TOK_TORUS,      "torus" },
+
+      { TOK_TUBE,      "tube" },
+      { TOK_GENCYL,    "gencyl" },
+      { TOK_EXTRUSION,  "extrusion" },
+      { TOK_REVOLUTION, "revolution" },
+
+      { TOK_TRANSLATE, "translate" },
+      { TOK_MULTITRANSLATE, "multitranslate" },
+      { TOK_ROTATE,   "rotate" },
+      { TOK_MULTIROTATE, "multirotate" },
+      { PRIMITIVE_TYPE(0), 0 }
+    };
+
+  static CSGeometry * geom;
+
+
+  CSGScanner :: CSGScanner (istream & ascanin)
+  {
+    scanin = &ascanin;
+    token = TOK_END;
+    num_value = 0;
+    linenum = 1;
+  }
+
+
+  void CSGScanner :: ReadNext ()
+  {
+    char ch;
+  
+
+    // scan whitespaces
+    do
+      { 
+	scanin->get(ch);
+
+	//if (ch == '\n') 
+	//  linenum++;
+
+	// end of file reached
+	if (scanin->eof())
+	  {
+	    token = TOK_END;
+	    return;
+	  }
+	if (ch == '\n') 
+	  linenum++;
+
+
+	// 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) || ch == '_')
+		{
+		  string_value += ch;
+		  scanin->get(ch);
+		}
+	      scanin->putback (ch);
+	    }
+
+	  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)
+  {
+    if (scan.GetToken() != TOKEN_TYPE(ch)) 
+      scan.Error (string ("token '") + string(1, ch) + 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;
+  }
+
+  Vec<3> ParseVector (CSGScanner & scan)
+  {
+    Vec<3> v;
+    v(0) = ParseNumber (scan);
+    ParseChar (scan, ',');
+    v(1) = ParseNumber (scan);
+    ParseChar (scan, ',');
+    v(2) = ParseNumber (scan);
+    return v;
+  }
+
+
+  CSGScanner & operator>> (CSGScanner & scan, char ch)
+  {
+    if (scan.GetToken() != TOKEN_TYPE(ch)) 
+      scan.Error (string ("token '") + string(1, ch) + string("' expected"));
+    scan.ReadNext();
+    return scan;
+  }
+
+  CSGScanner & operator>> (CSGScanner & scan, double & d)
+  {
+    d = ParseNumber (scan);
+    return scan;
+  }
+
+  CSGScanner & operator>> (CSGScanner & scan, int & i)
+  {
+    i = int (ParseNumber (scan));
+    return scan;
+  }
+
+  CSGScanner & operator>> (CSGScanner & scan, Point<3> & p)
+  {
+    scan >> p(0) >> ',' >> p(1) >> ',' >> p(2);
+    return scan;
+  }
+
+  CSGScanner & operator>> (CSGScanner & scan, Vec<3> & v)
+  {
+    scan >> v(0) >> ',' >> v(1) >> ',' >> v(2);
+    return scan;
+  }
+
+
+  Solid * ParseSolid (CSGScanner & scan);
+  Solid * ParseTerm (CSGScanner & scan);
+  Solid * ParsePrimary (CSGScanner & scan);
+ 
+
+  Solid * ParsePrimary (CSGScanner & scan)
+  {
+    if (scan.GetToken() == TOK_PRIMITIVE)
+      {
+	switch (scan.GetPrimitiveToken())
+	  {
+	  case TOK_PLANE:
+	    {
+	      Point<3> p;
+	      Vec<3> v;
+	      
+	      scan.ReadNext();
+	      scan >> '(' >> p >> ';' >> v >> ')';
+
+	      OneSurfacePrimitive * surf = new Plane ( p, v );
+	      geom->AddSurfaces (surf);
+	      return new Solid (surf);
+	    }
+
+	  case TOK_CYLINDER:
+	    {
+	      Point<3> pa, pb;
+	      double r;
+	      
+	      scan.ReadNext();
+	      scan >> '(' >> pa >> ';' >> pb >> ';' >> r >> ')';
+
+	      OneSurfacePrimitive * surf = new Cylinder ( pa, pb, r );
+	      geom->AddSurfaces (surf);
+	      return new Solid (surf);
+	    }
+
+	  case TOK_ELLIPTICCYLINDER:
+	    {
+	      Point<3> pa;
+	      Vec<3> vl, vs;
+	      
+	      scan.ReadNext();
+	      scan >> '(' >> pa >> ';' >> vl >> ';' >> vs >> ')';
+
+	      OneSurfacePrimitive * surf = new EllipticCylinder ( pa, vl, vs);
+	      geom->AddSurfaces (surf);
+	      return new Solid (surf);
+	    }
+
+
+	  case TOK_ELLIPSOID:
+	    {
+	      Point<3> pa;
+	      Vec<3> v1, v2, v3;
+	      
+	      scan.ReadNext();
+	      scan >> '(' >> pa >> ';' >> v1 >> ';' >> v2 >> ';' >> v3 >> ')';
+
+	      OneSurfacePrimitive * surf = new Ellipsoid ( pa, v1, v2, v3);
+	      geom->AddSurfaces (surf);
+	      return new Solid (surf);
+	    }
+
+
+	  case TOK_CONE:
+	    {
+	      Point<3> pa, pb;
+	      double ra, rb;
+	      
+	      scan.ReadNext();
+	      scan >> '(' >> pa >> ';' >> ra >> ';' >> pb >> ';' >> rb >> ')';
+
+	      OneSurfacePrimitive * surf = new Cone ( pa, pb, ra, rb );
+	      geom->AddSurfaces (surf);
+	      return new Solid (surf);
+	    }
+
+
+
+	  case TOK_SPHERE:
+	    {
+	      Point<3> p;
+	      double r;
+	      
+	      scan.ReadNext();
+	      scan >> '(' >> p >> ';' >> r >> ')';
+
+	      OneSurfacePrimitive * surf = new Sphere ( p, r );
+	      geom->AddSurfaces (surf);
+	      return new Solid (surf);
+	    }
+
+	  case TOK_ORTHOBRICK:
+	    {
+	      Point<3> pa, pb;
+	      
+	      scan.ReadNext();
+	      scan >> '(' >> pa >> ';' >> pb >> ')';
+	      
+
+	      Primitive * nprim = new OrthoBrick (pa, pb);
+	      geom->AddSurfaces (nprim);
+	      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 = Point<3> (ParseVector (scan));
+		  ParseChar (scan, ';');
+
+		  polyhedron->AddPoint(p);
+
+		  if (scan.GetToken() == ';')
+		    {
+		      scan.ReadNext();
+		      break;
+		    }
+		}
+
+	      // scanning the faces
+	      int inputface = 0;
+	      while (1)
+		{
+		  Array<int> pnums,cleaned_pnums;
+		  for(int i=0; i<3; i++)
+		    {
+		      pnums.Append((int) (ParseNumber (scan)));
+		      if(i<2) 
+			ParseChar (scan, ',');
+		    }
+
+		  if (scan.GetToken() == TOK_COMMA)
+		    {
+		      ParseChar (scan, ',');
+		      pnums.Append((int) (ParseNumber (scan)));	
+		    }
+
+		  for(int i=0; i<pnums.Size(); i++)
+		    if(!cleaned_pnums.Contains(pnums[i]))
+		      cleaned_pnums.Append(pnums[i]);
+
+		  if(cleaned_pnums.Size() == 3)
+		    {
+		      polyhedron->AddFace(cleaned_pnums[0]-1,
+					  cleaned_pnums[1]-1,
+					  cleaned_pnums[2]-1,
+					  inputface);
+		    }
+		  else if(cleaned_pnums.Size() == 4)
+		    {
+		      polyhedron->AddFace(cleaned_pnums[0]-1,
+					  cleaned_pnums[1]-1,
+					  cleaned_pnums[2]-1,
+					  inputface);
+		      polyhedron->AddFace(cleaned_pnums[0]-1,
+					  cleaned_pnums[2]-1,
+					  cleaned_pnums[3]-1,
+					  inputface);
+		    }
+		  else
+		    {
+		      ostringstream msg;
+		      msg << "Something wrong with polyhedron face:";
+		      for(int i=0; i<pnums.Size(); i++)
+			msg << " " << pnums[i];
+		      throw NgException(msg.str());
+		    }
+		  
+		      
+
+		  if (scan.GetToken() == ')')
+		    {
+		      scan.ReadNext();
+		      break;
+		    }
+		  scan.ReadNext();
+		  inputface++;
+		}
+
+	      geom->AddSurfaces (polyhedron);
+	      return new Solid (polyhedron);
+	    }
+
+
+	  case TOK_REVOLUTION:
+	    {
+	      Point<3> p0,p1;
+
+	      scan.ReadNext();
+	      scan >> '(' >> p0 >> ';' >> p1 >> ';';
+
+	      string spline = scan.GetStringValue();
+	      
+	      scan.ReadNext();
+	      scan >> ')';
+	      
+	      if(!geom->GetSplineCurve2d(spline))
+		{
+		  scan.Error ( string("2D Spline curve not found: ") + spline );
+		  break;
+		}
+
+	      Primitive * nprim = new Revolution(p0,p1,
+						 *(geom->GetSplineCurve2d(spline)));
+
+	      geom->AddSurfaces (nprim);
+	      return new Solid(nprim);
+	    }
+
+
+	  case TOK_EXTRUSION: 
+	    {   
+	      scan.ReadNext();
+	      scan >> '(';
+	      string epath = scan.GetStringValue();
+	      scan.ReadNext();
+	      scan >> ';';
+	      string profile = scan.GetStringValue();
+
+	      
+	      scan.ReadNext();
+	      Vec<3> z_dir;
+	      scan >> ';' >> z_dir(0) >> ',' >> z_dir(1) >> ',' >> z_dir(2) >> ')';
+	      
+	      if(!geom->GetSplineCurve2d(profile))
+		{
+		  scan.Error ( string("2D Spline curve not found: ") + profile );
+		  break;
+		}
+	      if(!geom->GetSplineCurve3d(epath))
+		{
+		  scan.Error ( string("2D Spline curve not found: ") + epath );
+		  break;
+		}
+	      
+	      Primitive * nprim = new Extrusion(*(geom->GetSplineCurve3d(epath)),
+						*(geom->GetSplineCurve2d(profile)),
+						z_dir);
+	      geom->AddSurfaces (nprim);
+	      return new Solid(nprim);
+	    }
+
+
+	  /// Torus 
+    	  /// Lorenzo Codecasa (codecasa@elet.polimi.it)
+    	  /// April 27th, 2005 
+	  ///
+	  /// begin...
+	  case TOK_TORUS:
+	    {     
+	      Point<3> pc; 
+	      Vec<3> vn;
+	      double R, r;
+	      
+	      scan.ReadNext();
+	      scan >> '(' >> pc >> ';' >> vn >> ';' >> R >> ';' >> r >> ')';
+
+	      OneSurfacePrimitive * surf = new Torus ( pc, vn, R, r );
+	      geom->AddSurfaces (surf);
+	      return new Solid (surf);
+	    }
+	  /// ..end
+
+
+
+
+	  case TOK_TRANSLATE: 
+	    {
+	      Vec<3> v;
+	      scan.ReadNext();
+
+	      ParseChar (scan, '(');
+	      v = ParseVector (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_ROTATE: 
+	    {
+	      Point<3> c;
+	      Vec<3> v;
+	      scan.ReadNext();
+
+	      scan >> '(' >> c >> ';' >> v >> ';';
+
+	      Solid * sol1 = ParseSolid (scan);
+
+	      ParseChar (scan, ')');
+
+	      Solid * nsol = sol1 -> Copy(*geom);
+	      Transformation<3> trans(c,v(0),v(1),v(2));
+	      nsol -> Transform (trans);
+	      return nsol;
+	    }
+
+
+	  case TOK_MULTITRANSLATE: 
+	    {
+	      Vec<3> v;
+	      int n;
+	      
+	      scan.ReadNext();
+
+	      scan >> '(' >> v >> ';' >> n >> ';';
+
+	      Solid * sol1 = ParseSolid (scan);
+	      
+	      scan >> ')';
+	      
+	      Solid * hsol = sol1;
+	      for (int 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;
+	    }
+
+
+	  case TOK_MULTIROTATE: 
+	    {
+	      Point<3> c;
+	      Vec<3> v;
+	      int n;
+	      
+	      scan.ReadNext();
+
+	      scan >> '(' >> c >> ';' >> v >> ';' >> n >> ';';
+	      Solid * sol1 = ParseSolid (scan);
+	      scan >> ')';
+
+	      Transformation<3> trans(c, v(0), v(1), v(2));
+	      Transformation<3> multi(Vec<3>(0,0,0));
+	      Transformation<3> ht;
+
+	      Solid * hsol = sol1;
+	      for (int i = 1; i <= n; i++)
+		{
+		  Solid * nsol = sol1 -> Copy(*geom);
+
+		  nsol -> Transform (multi);
+		  hsol = new Solid (Solid::UNION, hsol, nsol); 
+
+		  ht=multi;
+		  multi.Combine (trans, ht);
+		}
+	      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;
+  }
+
+
+  template <int D>
+  void LoadSpline (SplineGeometry<D> & spline, CSGScanner & scan)
+  {
+    double hd;
+    Point<D> x;
+    int nump, numseg;
+    
+    //scan.ReadNext();
+    scan >> nump >> ';';
+    
+    hd = 1;
+    spline.geompoints.SetSize(nump);
+    for(int i = 0; i<nump; i++)
+      {
+	if(D==2)
+	  scan >> x(0) >> ',' >> x(1) >> ';';
+	else if(D==3)
+	  scan >> x(0) >> ',' >> x(1) >> ',' >> x(2) >> ';';
+	
+	spline.geompoints[i] = GeomPoint<D>(x,hd);
+      }
+    
+    scan >> numseg;// >> ';';
+
+    spline.splines.SetSize(numseg);
+
+  int pnums,pnum1,pnum2,pnum3;
+    
+
+  for(int i = 0; i<numseg; i++)
+    {
+      scan >> ';' >> pnums >> ',';
+      if (pnums == 2)
+	{
+	  scan >> pnum1 >> ',' >> pnum2;// >> ';';
+	  spline.splines[i] = new LineSeg<D>(spline.geompoints[pnum1-1],
+					     spline.geompoints[pnum2-1]);
+	}
+      else if (pnums == 3)
+	{
+	  scan >> pnum1 >> ',' >> pnum2 >> ',' 
+	       >> pnum3;// >> ';';
+	  spline.splines[i] = new SplineSeg3<D>(spline.geompoints[pnum1-1],
+						spline.geompoints[pnum2-1],
+						spline.geompoints[pnum3-1]);
+	}
+      else if (pnums == 4)
+	{
+	  scan >> pnum1 >> ',' >> pnum2 >> ',' 
+	       >> pnum3;// >> ';';
+	  spline.splines[i] = new CircleSeg<D>(spline.geompoints[pnum1-1],
+					       spline.geompoints[pnum2-1],
+					       spline.geompoints[pnum3-1]);
+	}
+    }
+  }
+
+
+
+
+  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();
+
+		if(scan.GetToken() == '-' || scan.GetToken() == TOK_NUM)
+		  {
+		    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
+		  { // string list
+		    Array<char*> vals;
+		    string val = scan.GetStringValue();
+		    vals.Append(new char[val.size()+1]);
+		    strcpy(vals.Last(),val.c_str());
+		    scan.ReadNext();
+
+		    while (scan.GetToken() == ',')
+		      {
+			scan.ReadNext();
+			val = scan.GetStringValue();
+			vals.Append(new char[val.size()+1]);
+			strcpy(vals.Last(),val.c_str());
+			scan.ReadNext();
+		      }
+		    ParseChar (scan, ']');
+		    flags.SetFlag (name.c_str(), vals);
+		    for(int i=0; i<vals.Size(); i++)
+		      delete [] vals[i];
+		  }
+	      }
+	    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, ';');
+		    if (!geom->GetSolid (name))
+		      scan.Error ("Top-Level-Object "+name+" not defined");
+
+		    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)));
+		    if ( flags.StringFlagDefined("bcname") )
+		      tlo->SetBCName ( flags.GetStringFlag ("bcname", "default") );
+		  }
+	      }
+	    
+	    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);
+
+		      const TopLevelObject * domain = 0;
+		      if (flags.StringFlagDefined ("tlo"))
+			{
+			  domain = 
+			    geom->GetTopLevelObject (geom->GetSolid(flags.GetStringFlag ("tlo","")));
+			  if (!domain) 
+			    scan.Error ("identification needs undefined tlo");
+			}
+
+		      geom->AddIdentification 
+			(new CloseSurfaceIdentification 
+			 (geom->GetNIdentifications()+1, *geom, 
+			  geom->GetSurface (si1[0]), geom->GetSurface (si2[0]),
+			  domain,
+			  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_SINGULAR)
+
+	      {
+		
+		scan.ReadNext();
+		switch (scan.GetToken())
+		  {
+		  case TOK_FACE:
+		    {
+		      scan.ReadNext();
+		      
+		      string name1 = scan.GetStringValue();  // tlo
+		      scan.ReadNext();
+		      
+		      string name2 = scan.GetStringValue();
+		      scan.ReadNext();
+		      
+		      Flags flags;
+		      ParseFlags (scan, flags);
+		      int factor = int(flags.GetNumFlag("factor",1)); 
+		      // cout << "Singular Face with factor " << factor << endl; 
+		      PrintMessageCR (3, "Singular Face  with factor ", factor);
+
+		      ParseChar (scan, ';');
+		      
+		      const Solid * sol = geom->GetSolid(name2);
+
+		      if(!sol)
+			scan.Error ("unknown solid in singular face definition");
+		      else
+			for (int i = 0; i < geom->GetNTopLevelObjects(); i++)
+			  if (name1 == geom->GetTopLevelObject (i)->GetSolid()->Name())
+			    geom->singfaces.Append (new SingularFace (i+1, sol,factor));
+
+		      break;
+		    }
+
+		  case TOK_EDGE:
+		    {
+		      scan.ReadNext();
+		      
+		      string name1 = scan.GetStringValue();
+		      scan.ReadNext();
+		      
+		      string name2 = scan.GetStringValue();
+		      scan.ReadNext();
+		      
+		      Flags flags;
+		      ParseFlags (scan, flags);
+		      int factor = int(flags.GetNumFlag("factor",1));
+		      double maxhinit = flags.GetNumFlag("maxh",-1);
+		      ParseChar (scan, ';');
+		      
+		      const Solid * s1 = geom->GetSolid(name1);
+		      const Solid * s2 = geom->GetSolid(name2);
+		      PrintMessageCR (3, "Singular Edge  with factor ", factor);
+
+		      int domnr = -1;
+		      if (flags.StringFlagDefined ("tlo"))
+			{
+			  const Solid * sol =
+			    geom->GetSolid(flags.GetStringFlag ("tlo",""));
+			  
+			  for (int i = 0; i < geom->GetNTopLevelObjects(); i++)
+			    if (geom->GetTopLevelObject(i)->GetSolid() == sol)
+			      domnr = i;
+			  
+			  // cout << "domnr = " << domnr;
+			}
+
+		      if(!s1 || !s2)
+			scan.Error ("unknown solid ins singular edge definition");
+		      else
+			geom->singedges.Append (new SingularEdge (1, domnr, 
+								  *geom, s1, s2, factor,
+								  maxhinit));
+		      break;
+		    }
+
+		  case TOK_POINT:
+		    {
+		      scan.ReadNext();
+		      
+		      string name1 = scan.GetStringValue();
+		      scan.ReadNext();
+		      string name2 = scan.GetStringValue();
+		      scan.ReadNext();
+		      string name3 = scan.GetStringValue();
+		      scan.ReadNext();
+		      
+		      Flags flags;
+		      ParseFlags (scan, flags);
+		      int factor = int(flags.GetNumFlag("factor",1)); 
+		      ParseChar (scan, ';');
+		      
+		      const Solid * s1 = geom->GetSolid(name1);
+		      const Solid * s2 = geom->GetSolid(name2);
+		      const Solid * s3 = geom->GetSolid(name3);
+		      // cout << "Singular Point with factor " << factor << endl; 
+		      PrintMessageCR (3, "Singular Point  with factor ", factor);
+		      geom->singpoints.Append (new SingularPoint (1, s1, s2, s3, factor));
+		      break;
+		    }
+		  default:
+		    scan.Error ("keyword 'face' or 'edge' or 'point' expected");
+		  }
+	      }
+
+	    
+	    else if (scan.GetToken() == TOK_POINT)
+	      {
+		Point<3> p;
+
+		scan.ReadNext();
+		ParseChar (scan, '(');
+		p = Point<3> (ParseVector (scan));
+		ParseChar (scan, ')');
+
+
+		Flags flags;
+		ParseFlags (scan, flags);
+		int factor = int(flags.GetNumFlag("factor",0)); 
+
+		ParseChar (scan, ';');
+
+		geom->AddUserPoint (p, factor);
+	      }
+
+	    else if (scan.GetToken() == TOK_BOUNDINGBOX)
+	      {
+		Point<3> p1, p2;
+		
+		scan.ReadNext();
+		ParseChar (scan, '(');
+		p1 = Point<3> (ParseVector (scan));
+		ParseChar (scan, ';');
+		p2 = Point<3> (ParseVector (scan));
+		ParseChar (scan, ')');
+		ParseChar (scan, ';');
+
+		geom->SetBoundingBox (Box<3> (p1, p2));
+	      }
+
+	    else if (scan.GetToken() == TOK_CURVE2D)
+	      {
+		scan.ReadNext();
+
+		
+		if (scan.GetToken() != TOK_STRING)
+		  scan.Error ("name identifier expected");
+		string curvename = scan.GetStringValue();
+
+		scan.ReadNext();
+
+		ParseChar (scan, '=');
+		ParseChar (scan, '(');
+		
+		SplineGeometry<2> * newspline = new SplineGeometry<2>;
+		// newspline->CSGLoad(scan);
+		LoadSpline (*newspline, scan);
+
+		ParseChar (scan, ')');
+		ParseChar (scan, ';');
+
+		geom->SetSplineCurve(curvename.c_str(),newspline);
+
+		PrintMessage (4, "define 2d curve ", curvename);
+	      }
+
+	    else if (scan.GetToken() == TOK_CURVE3D)
+	      {
+		scan.ReadNext();
+
+		
+		if (scan.GetToken() != TOK_STRING)
+		  scan.Error ("name identifier expected");
+		string curvename = scan.GetStringValue();
+
+		scan.ReadNext();
+
+		ParseChar (scan, '=');
+		ParseChar (scan, '(');
+		
+		SplineGeometry<3> * newspline = new SplineGeometry<3>;
+		// newspline->CSGLoad(scan);
+		LoadSpline (*newspline, scan);
+
+		ParseChar (scan, ')');
+		ParseChar (scan, ';');
+
+		geom->SetSplineCurve(curvename.c_str(),newspline);
+
+		PrintMessage (4, "define 3d curve ", curvename);
+	      }
+
+	    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;
+		bcm.bcname = NULL;
+		Array<int> si;
+		
+		geom->GetSolid(name1)->GetSurfaceIndices(si);
+		if(si.Size() == 0)
+		  {
+		    string errstring = "solid \""; errstring += name1; errstring += "\" has no surfaces";
+		    scan.Error (errstring);
+		  }
+	
+		bcm.tlonr = -1;
+		int i;	
+		for (i = 0; i < geom->GetNTopLevelObjects(); i++)
+		  if (string (geom->GetTopLevelObject(i)->GetSolid()->Name())
+		      == name2)
+		    {
+		      bcm.tlonr = i;
+		      break;
+		    }
+		if(bcm.tlonr == -1)
+		  {
+		    string errstring = "tlo \""; errstring += name2; errstring += "\" not found";
+		    scan.Error(errstring);
+		  }
+		
+		
+		bcm.bcnr = num;
+		for (i = 0; i < si.Size(); i++)
+		  {
+		    bcm.si = si[i];
+		    geom->bcmodifications.Append (bcm);
+		  }
+	      }
+	    
+	    else if (scan.GetToken() == TOK_BOUNDARYCONDITIONNAME)
+	      {
+		scan.ReadNext();
+		
+		string name1 = scan.GetStringValue();
+		scan.ReadNext();
+		
+		string name2 = scan.GetStringValue();
+		scan.ReadNext();
+
+		string bcname = scan.GetStringValue();
+		scan.ReadNext();
+		ParseChar(scan, ';');
+		
+
+		CSGeometry::BCModification bcm;
+		bcm.bcname = NULL;
+
+
+		Array<int> si;
+		
+		geom->GetSolid(name1)->GetSurfaceIndices(si);
+		if(si.Size() == 0)
+		  {
+		    string errstring = "solid \""; errstring += name1; errstring += "\" has no surfaces";
+		    scan.Error (errstring);
+		  }
+	
+		bcm.tlonr = -1;
+		int i;	
+		for (i = 0; i < geom->GetNTopLevelObjects(); i++)
+		  if (string (geom->GetTopLevelObject(i)->GetSolid()->Name())
+		      == name2)
+		    {
+		      bcm.tlonr = i;
+		      break;
+		    }
+		if(bcm.tlonr == -1)
+		  {
+		    string errstring = "tlo \""; errstring += name2; errstring += "\" not found";
+		    scan.Error(errstring);
+		  }
+		
+		
+		bcm.bcnr = -1;
+		for (i = 0; i < si.Size(); i++)
+		  {
+		    bcm.si = si[i];
+		    geom->bcmodifications.Append (bcm);
+		    geom->bcmodifications.Last().bcname = new string(bcname);
+		  }
+	      }
+	    
+	    else if (scan.GetToken() == TOK_DEFINE)
+	      {
+		scan.ReadNext();
+		string name;
+		double val;
+		
+		switch (scan.GetToken())
+		  {
+		  case TOK_CONSTANT:
+		    scan.ReadNext();
+		      
+		    name = scan.GetStringValue();
+		    scan.ReadNext();
+
+		    ParseChar(scan, '=');
+		    val = ParseNumber(scan);
+
+		    if(name == "identprec")
+		      geom->SetIdEps(val);
+		    
+		    
+
+		    break;
+		  default:
+		    scan.Error ("keyword 'constant' expected");
+		  }
+	      }
+
+
+	    else
+	      {
+		cout << "read unidentified token " << scan.GetToken() 
+		     << " (as char: \"" << char(scan.GetToken()) << "\")"
+		     << " string = " << scan.GetStringValue() << endl;
+		scan.ReadNext();
+	      }
+	  }
+      }
+    catch (string errstr)
+      {
+	cout << "caught error " << errstr << endl;
+	throw NgException (errstr);
+      }
+
+
+
+    (*testout) << geom->GetNTopLevelObjects() << " TLOs:" << endl;
+    for (int i = 0; i < geom->GetNTopLevelObjects(); i++)
+      {
+	const TopLevelObject * tlo = geom->GetTopLevelObject(i);
+	if (tlo->GetSolid())
+	  (*testout) << i << ": " << *tlo->GetSolid() << endl;
+      }
+
+    (*testout) << geom->GetNSurf() << " Surfaces" << endl;
+    for (int i = 0; i < geom->GetNSurf(); i++)
+      (*testout) << i << ": " << *geom->GetSurface(i) << 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/contrib/Netgen/libsrc/csg/csgparser.hpp b/contrib/Netgen/libsrc/csg/csgparser.hpp
new file mode 100644
index 0000000000..dfbd24ac04
--- /dev/null
+++ b/contrib/Netgen/libsrc/csg/csgparser.hpp
@@ -0,0 +1,101 @@
+#ifndef _CSGPARSER_HPP
+#define _CSGPARSER_HPP
+
+
+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_FACE, TOK_IDENTIFY, TOK_CLOSESURFACES,
+      TOK_CLOSEEDGES, TOK_PERIODIC,
+      TOK_SOLID, TOK_RECO, TOK_TLO, TOK_CURVE2D, TOK_CURVE3D, TOK_BOUNDINGBOX,
+      TOK_BOUNDARYCONDITION, TOK_BOUNDARYCONDITIONNAME,
+      TOK_DEFINE, TOK_CONSTANT,
+      TOK_END };
+
+  struct kwstruct
+  {
+    TOKEN_TYPE kw; 
+    const char * name;
+  };
+
+  enum PRIMITIVE_TYPE
+    {
+      TOK_SPHERE = 1, TOK_CYLINDER, TOK_PLANE, TOK_ELLIPTICCYLINDER, 
+      TOK_ELLIPSOID, TOK_CONE, 
+      TOK_ORTHOBRICK, TOK_POLYHEDRON, 
+      TOK_TORUS,
+      TOK_TUBE, TOK_GENCYL, TOK_EXTRUSION, TOK_REVOLUTION,
+
+      TOK_TRANSLATE, TOK_MULTITRANSLATE, TOK_ROTATE, TOK_MULTIROTATE
+    };
+
+  struct primstruct
+  {
+    PRIMITIVE_TYPE kw; 
+    const char * name;
+  };
+
+
+  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();
+
+    /*
+    CSGScanner & Parse (char ch);
+    CSGScanner & Parse (int & i);
+    CSGScanner & Parse (double & d);
+    CSGScanner & Parse (Point<3> & p);
+    CSGScanner & Parse (Vec<3> & p);
+    */
+    void Error (const string & err);
+  };
+
+
+  
+  CSGScanner & operator>> (CSGScanner & scan, char ch);
+  CSGScanner & operator>> (CSGScanner & scan, double & d);
+  CSGScanner & operator>> (CSGScanner & scan, int & i);
+  CSGScanner & operator>> (CSGScanner & scan, Point<3> & p);
+  CSGScanner & operator>> (CSGScanner & scan, Vec<3> & v);
+  
+
+
+}
+
+
+
+#endif
+
diff --git a/contrib/Netgen/libsrc/csg/csgpkg.cpp b/contrib/Netgen/libsrc/csg/csgpkg.cpp
new file mode 100644
index 0000000000..6ce6bf1a4e
--- /dev/null
+++ b/contrib/Netgen/libsrc/csg/csgpkg.cpp
@@ -0,0 +1,700 @@
+#include <mystdlib.h>
+#include <myadt.hpp>
+#include <linalg.hpp>
+#include <csg.hpp>
+
+
+#include <incvis.hpp>
+#include <visual.hpp>
+
+
+#include "vscsg.hpp"
+
+
+extern "C" int Ng_CSG_Init (Tcl_Interp * interp);
+
+
+
+namespace netgen
+{
+  extern DLL_HEADER NetgenGeometry * ng_geometry;
+  extern DLL_HEADER AutoPtr<Mesh> mesh;
+
+  static VisualSceneGeometry vsgeom;
+ 
+  char * err_needscsgeometry = (char*) "This operation needs an CSG geometry";
+  extern char * err_needsmesh;
+  extern char * err_jobrunning;
+
+ 
+
+
+  int Ng_ParseGeometry (ClientData clientData,
+			Tcl_Interp * interp,
+			int argc, tcl_const char *argv[])
+  {
+    CSGeometry * csgeom = dynamic_cast<CSGeometry*> (ng_geometry);
+    if (csgeom)
+      {
+	double detail = atof (Tcl_GetVar (interp, "::geooptions.detail", 0));
+	double facets = atof (Tcl_GetVar (interp, "::geooptions.facets", 0));
+      
+	if (atoi (Tcl_GetVar (interp, "::geooptions.drawcsg", 0)))
+	  csgeom->CalcTriangleApproximation(detail, facets);
+      }
+    return TCL_OK;
+  }
+
+
+
+
+  int Ng_GeometryOptions (ClientData clientData,
+			  Tcl_Interp * interp,
+			  int argc, tcl_const char *argv[])
+  {
+    CSGeometry * geometry = dynamic_cast<CSGeometry*> (ng_geometry);
+
+
+    const char * command = argv[1];
+
+    if (strcmp (command, "get") == 0)
+      {
+	if (geometry)
+	  {
+	    char buf[20];
+	    Point3d pmin = geometry->BoundingBox ().PMin();
+	    Point3d pmax = geometry->BoundingBox ().PMax();
+	    
+	    sprintf (buf, "%5.1lf", pmin.X());
+	    Tcl_SetVar (interp, "::geooptions.minx", buf, 0);
+	    sprintf (buf, "%5.1lf", pmin.Y());
+	    Tcl_SetVar (interp, "::geooptions.miny", buf, 0);
+	    sprintf (buf, "%5.1lf", pmin.Z());
+	    Tcl_SetVar (interp, "::geooptions.minz", buf, 0);
+	    
+	    sprintf (buf, "%5.1lf", pmax.X());
+	    Tcl_SetVar (interp, "::geooptions.maxx", buf, 0);
+	    sprintf (buf, "%5.1lf", pmax.Y());
+	    Tcl_SetVar (interp, "::geooptions.maxy", buf, 0);
+	    sprintf (buf, "%5.1lf", pmax.Z());
+	    Tcl_SetVar (interp, "::geooptions.maxz", buf, 0);
+	  }
+      }
+    else if (strcmp (command, "set") == 0)
+      {
+        Point<3> pmin (atof (Tcl_GetVar (interp, "::geooptions.minx", 0)),
+                       atof (Tcl_GetVar (interp, "::geooptions.miny", 0)),
+                       atof (Tcl_GetVar (interp, "::geooptions.minz", 0)));
+        Point<3> pmax (atof (Tcl_GetVar (interp, "::geooptions.maxx", 0)),
+                       atof (Tcl_GetVar (interp, "::geooptions.maxy", 0)),
+                       atof (Tcl_GetVar (interp, "::geooptions.maxz", 0)));
+	Box<3> box (pmin, pmax);
+	if (geometry)
+	  geometry -> SetBoundingBox (box);
+	CSGeometry::SetDefaultBoundingBox (box);
+      }
+
+    return TCL_OK;
+  }
+
+
+
+
+
+  // attempt of a simple modeller
+
+  int Ng_CreatePrimitive (ClientData clientData,
+			  Tcl_Interp * interp,
+			  int argc, tcl_const char *argv[])
+  {
+    CSGeometry * geometry = dynamic_cast<CSGeometry*> (ng_geometry);
+    if (!geometry)
+      {
+	Tcl_SetResult (interp, err_needscsgeometry, TCL_STATIC);
+	return TCL_ERROR;
+      }
+
+
+    tcl_const char * classname = argv[1];
+    tcl_const char * name = argv[2];
+
+    cout << "Create primitive, class = " << classname
+	 << ", name = " << name << endl;
+
+    Primitive * nprim = Primitive::CreatePrimitive (classname);
+    Solid * nsol = new Solid (nprim);
+
+    char sname[100];
+    for (int j = 1; j <= nprim->GetNSurfaces(); j++)
+      {
+	sprintf (sname, "%s,%d", name, j);
+	geometry -> AddSurface (sname, &nprim->GetSurface(j));
+	nprim -> SetSurfaceId (j, geometry->GetNSurf());
+      }
+
+    geometry->SetSolid (name, nsol);
+
+    return TCL_OK;
+  }
+
+
+  int Ng_SetPrimitiveData (ClientData clientData,
+			   Tcl_Interp * interp,
+			   int argc, tcl_const char *argv[])
+  {
+    CSGeometry * geometry = dynamic_cast<CSGeometry*> (ng_geometry);
+    if (!geometry)
+      {
+	Tcl_SetResult (interp, err_needscsgeometry, TCL_STATIC);
+	return TCL_ERROR;
+      }
+
+
+    tcl_const char * name = argv[1];
+    tcl_const char * value = argv[2];
+
+    Array<double> coeffs;
+
+
+    cout << "Set primitive data, name = " << name
+	 << ", value = " << value  << endl;
+
+
+    istringstream vst (value);
+    double val;
+    while (!vst.eof())
+      {
+	vst >> val;
+	coeffs.Append (val);
+      }
+
+    ((Primitive*)
+     geometry->GetSolid (name)->GetPrimitive())->SetPrimitiveData (coeffs);
+
+    return TCL_OK;
+  }
+
+
+
+  int Ng_SetSolidData (ClientData clientData,
+		       Tcl_Interp * interp,
+		       int argc, tcl_const char *argv[])
+  {
+    CSGeometry * geometry = dynamic_cast<CSGeometry*> (ng_geometry);
+    if (!geometry)
+      {
+	Tcl_SetResult (interp, err_needscsgeometry, TCL_STATIC);
+	return TCL_ERROR;
+      }
+
+
+    tcl_const char * name = argv[1];
+    tcl_const char * val = argv[2];
+
+    cout << "Set Solid Data, name = " << name
+	 << ", value = " << val << endl;
+
+    istringstream vst (val);
+
+    Solid * nsol = Solid::CreateSolid (vst, geometry->GetSolids());
+    geometry->SetSolid (name, nsol);
+
+    return TCL_OK;
+  }
+
+
+  int Ng_GetPrimitiveData (ClientData clientData,
+			   Tcl_Interp * interp,
+			   int argc, tcl_const char *argv[])
+  {
+    CSGeometry * geometry = dynamic_cast<CSGeometry*> (ng_geometry);
+    if (!geometry)
+      {
+	Tcl_SetResult (interp, err_needscsgeometry, TCL_STATIC);
+	return TCL_ERROR;
+      }
+
+
+    tcl_const char * name = argv[1];
+    tcl_const char * classnamevar = argv[2];
+    tcl_const char * valuevar = argv[3];
+
+    const char * classname;
+
+    Array<double> coeffs;
+
+    geometry->GetSolid (name)->GetPrimitive()->GetPrimitiveData (classname, coeffs);
+
+    ostringstream vst;
+    for (int i = 1; i <= coeffs.Size(); i++)
+      vst << coeffs.Get(i) << " ";
+
+    cout << "GetPrimitiveData, name = " << name
+	 << ", classnamevar = " << classnamevar
+	 << ", classname = " << classname << endl
+	 << " valuevar = " << valuevar
+	 << ", values = " << vst.str() << endl;
+
+    Tcl_SetVar  (interp, classnamevar, (char*)classname, 0);
+    Tcl_SetVar  (interp, valuevar, (char*)vst.str().c_str(), 0);
+
+    return TCL_OK;
+  }
+
+  int Ng_GetSolidData (ClientData clientData,
+		       Tcl_Interp * interp,
+		       int argc, tcl_const char *argv[])
+  {
+    CSGeometry * geometry = dynamic_cast<CSGeometry*> (ng_geometry);
+    if (!geometry)
+      {
+	Tcl_SetResult (interp, err_needscsgeometry, TCL_STATIC);
+	return TCL_ERROR;
+      }
+
+    tcl_const char * name = argv[1];
+    tcl_const char * valuevar = argv[2];
+
+    ostringstream vst;
+
+    const Solid * sol = geometry->GetSolid (name);
+    sol->GetSolidData (vst);
+
+    cout << "GetSolidData, name = " << name << ", data = " << vst.str() << endl;
+
+    Tcl_SetVar  (interp, valuevar, (char*)vst.str().c_str(), 0);
+
+    return TCL_OK;
+  }
+
+
+  int Ng_GetPrimitiveList (ClientData clientData,
+			   Tcl_Interp * interp,
+			   int argc, tcl_const char *argv[])
+  {
+    CSGeometry * geometry = dynamic_cast<CSGeometry*> (ng_geometry);
+    if (!geometry)
+      {
+	Tcl_SetResult (interp, err_needscsgeometry, TCL_STATIC);
+	return TCL_ERROR;
+      }
+
+
+    tcl_const char * valuevar = argv[1];
+    int i;
+
+    stringstream vst;
+
+    for (i = 1; i <= geometry->GetNSolids(); i++)
+      {
+	const Solid * sol = geometry->GetSolid(i);
+	if (sol->GetPrimitive())
+	  vst << sol->Name() << " ";
+      }
+
+    cout << "primnames = " << vst.str() << endl;
+
+    Tcl_SetVar  (interp, valuevar, (char*)vst.str().c_str(), 0);
+
+    return TCL_OK;
+  }
+
+
+
+  int Ng_GetSurfaceList (ClientData clientData,
+			 Tcl_Interp * interp,
+			 int argc, tcl_const char *argv[])
+  {
+    CSGeometry * geometry = dynamic_cast<CSGeometry*> (ng_geometry);
+    if (!geometry)
+      {
+	Tcl_SetResult (interp, err_needscsgeometry, TCL_STATIC);
+	return TCL_ERROR;
+      }
+
+
+    tcl_const char * valuevar = argv[1];
+    int i;
+
+    stringstream vst;
+
+    for (i = 1; i <= geometry->GetNSurf(); i++)
+      {
+	const Surface * surf = geometry->GetSurface(i);
+	vst << surf->Name() << " ";
+      }
+
+    cout << "surfnames = " << vst.str() << endl;
+
+    Tcl_SetVar  (interp, valuevar, (char*)vst.str().c_str(), 0);
+
+    return TCL_OK;
+  }
+
+
+  int Ng_GetSolidList (ClientData clientData,
+		       Tcl_Interp * interp,
+		       int argc, tcl_const char *argv[])
+  {
+    CSGeometry * geometry = dynamic_cast<CSGeometry*> (ng_geometry);
+    if (!geometry)
+      {
+	Tcl_SetResult (interp, err_needscsgeometry, TCL_STATIC);
+	return TCL_ERROR;
+      }
+
+    tcl_const char * valuevar = argv[1];
+    int i;
+
+    stringstream vst;
+
+    for (i = 1; i <= geometry->GetNSolids(); i++)
+      {
+	const Solid * sol = geometry->GetSolid(i);
+	if (!sol->GetPrimitive())
+	  vst << sol->Name() << " ";
+      }
+
+    cout << "solnames = " << vst.str() << endl;
+
+    Tcl_SetVar  (interp, valuevar, (char*)vst.str().c_str(), 0);
+
+    return TCL_OK;
+  }
+
+
+  int Ng_TopLevel (ClientData clientData,
+		   Tcl_Interp * interp,
+		   int argc, tcl_const char *argv[])
+  {
+    CSGeometry * geometry = dynamic_cast<CSGeometry*> (ng_geometry);
+    if (!geometry)
+      {
+	Tcl_SetResult (interp, err_needscsgeometry, TCL_STATIC);
+	return TCL_ERROR;
+      }
+
+
+    int i;
+    /*
+      for (i = 0; i < argc; i++)
+      cout << argv[i] << ", ";
+      cout << endl;
+    */
+
+    if (strcmp (argv[1], "getlist") == 0)
+      {
+	stringstream vst;
+
+	for (i = 0; i < geometry->GetNTopLevelObjects(); i++)
+	  {
+	    const Solid * sol;
+	    const Surface * surf;
+	    geometry->GetTopLevelObject (i, sol, surf);
+
+	    if (!surf)
+	      vst << "{ " << sol->Name() << " } ";
+	    else
+	      vst << "{ " << sol->Name() << " " << surf->Name() << " } ";
+	  }
+
+	tcl_const char * valuevar = argv[2];
+	Tcl_SetVar  (interp, valuevar, (char*)vst.str().c_str(), 0);
+      }
+
+    if (strcmp (argv[1], "set") == 0)
+      {
+	tcl_const char * solname = argv[2];
+	tcl_const char * surfname = argv[3];
+	Solid * sol = (Solid*)geometry->GetSolid (solname);
+	Surface * surf = (Surface*)geometry->GetSurface (surfname);
+	geometry->SetTopLevelObject (sol, surf);
+      }
+
+    if (strcmp (argv[1], "remove") == 0)
+      {
+	tcl_const char * solname = argv[2];
+	tcl_const char * surfname = argv[3];
+	Solid * sol = (Solid*)geometry->GetSolid (solname);
+	Surface * surf = (Surface*)geometry->GetSurface (surfname);
+	geometry->RemoveTopLevelObject (sol, surf);
+      }
+
+    if (strcmp (argv[1], "setprop") == 0)
+      {
+	tcl_const char * solname = argv[2];
+	tcl_const char * surfname = argv[3];
+	tcl_const char * propvar = argv[4];
+	Solid * sol = (Solid*)geometry->GetSolid (solname);
+	Surface * surf = (Surface*)geometry->GetSurface (surfname);
+	TopLevelObject * tlo = geometry->GetTopLevelObject (sol, surf);
+
+	if (!tlo) return TCL_OK;
+
+	char varname[50];
+	sprintf (varname, "%s(red)", propvar);
+	double red = atof (Tcl_GetVar (interp, varname, 0));
+	sprintf (varname, "%s(blue)", propvar);
+	double blue = atof (Tcl_GetVar (interp, varname, 0));
+	sprintf (varname, "%s(green)", propvar);
+	double green = atof (Tcl_GetVar (interp, varname, 0));
+	tlo -> SetRGB (red, green, blue);
+
+	sprintf (varname, "%s(visible)", propvar);
+	tlo -> SetVisible (bool(atoi (Tcl_GetVar (interp, varname, 0))));
+	sprintf (varname, "%s(transp)", propvar);
+	tlo -> SetTransparent (bool(atoi (Tcl_GetVar (interp, varname, 0))));
+      }
+
+    if (strcmp (argv[1], "getprop") == 0)
+      {
+	tcl_const char * solname = argv[2];
+	tcl_const char * surfname = argv[3];
+	tcl_const char * propvar = argv[4];
+
+	Solid * sol = (Solid*)geometry->GetSolid (solname);
+	Surface * surf = (Surface*)geometry->GetSurface (surfname);
+	TopLevelObject * tlo = geometry->GetTopLevelObject (sol, surf);
+
+	if (!tlo) return TCL_OK;
+
+	char varname[50], varval[10];
+
+	sprintf (varname, "%s(red)", propvar);
+	sprintf (varval, "%lf", tlo->GetRed());
+	Tcl_SetVar (interp, varname, varval, 0);
+
+	sprintf (varname, "%s(green)", propvar);
+	sprintf (varval, "%lf", tlo->GetGreen());
+	Tcl_SetVar (interp, varname, varval, 0);
+
+	sprintf (varname, "%s(blue)", propvar);
+	sprintf (varval, "%lf", tlo->GetBlue());
+	Tcl_SetVar (interp, varname, varval, 0);
+
+	sprintf (varname, "%s(visible)", propvar);
+	sprintf (varval, "%d", tlo->GetVisible());
+	Tcl_SetVar (interp, varname, varval, 0);
+
+	sprintf (varname, "%s(transp)", propvar);
+	sprintf (varval, "%d", tlo->GetTransparent());
+	Tcl_SetVar (interp, varname, varval, 0);
+      }
+
+
+    return TCL_OK;
+  }
+
+
+
+
+  int Ng_SingularEdgeMS (ClientData clientData,
+			 Tcl_Interp * interp,
+			 int argc, tcl_const char *argv[])
+  {
+    CSGeometry * geometry = dynamic_cast<CSGeometry*> (ng_geometry);
+    if (!geometry)
+      {
+	Tcl_SetResult (interp, err_needscsgeometry, TCL_STATIC);
+	return TCL_ERROR;
+      }
+
+    if (!mesh.Ptr())
+      {
+	Tcl_SetResult (interp, err_needsmesh, TCL_STATIC);
+	return TCL_ERROR;
+      }
+    if (multithread.running)
+      {
+	Tcl_SetResult (interp, err_jobrunning, TCL_STATIC);
+	return TCL_ERROR;
+      }
+
+    double globh = mparam.maxh;
+    for (int i = 1; i <= geometry->singedges.Size(); i++)
+      geometry->singedges.Get(i)->SetMeshSize (*mesh, globh);
+    return TCL_OK;
+  }
+
+
+  int Ng_SingularPointMS (ClientData clientData,
+			  Tcl_Interp * interp,
+			  int argc, tcl_const char *argv[])
+  {
+    CSGeometry * geometry = dynamic_cast<CSGeometry*> (ng_geometry);
+    if (!geometry)
+      {
+	Tcl_SetResult (interp, err_needscsgeometry, TCL_STATIC);
+	return TCL_ERROR;
+      }
+
+    double globh = mparam.maxh;
+    for (int i = 1; i <= geometry->singpoints.Size(); i++)
+      geometry->singpoints.Get(i)->SetMeshSize (*mesh, globh);
+    return TCL_OK;
+  }
+
+
+
+  int Ng_SelectSurface (ClientData clientData,
+			Tcl_Interp * interp,
+			int argc, tcl_const char *argv[])
+  {
+    int surfnr = atoi (argv[1]);
+    vsgeom.SelectSurface (surfnr);
+    return TCL_OK;
+  }
+
+
+  class CSGeometryRegister : public GeometryRegister
+  {
+  public:
+    virtual NetgenGeometry * Load (string filename) const;
+    virtual NetgenGeometry * LoadFromMeshFile (istream & ist) const;
+    virtual VisualScene * GetVisualScene (const NetgenGeometry * geom) const;
+  };
+
+	extern CSGeometry * ParseCSG (istream & istr);
+
+  NetgenGeometry *  CSGeometryRegister :: Load (string filename) const
+  {
+    const char * cfilename = filename.c_str();
+    if (strcmp (&cfilename[strlen(cfilename)-3], "geo") == 0)
+      {
+	PrintMessage (1, "Load CSG geometry file ", cfilename);
+	
+
+	ifstream infile(cfilename);
+
+	CSGeometry * hgeom = ParseCSG (infile);
+	if (!hgeom)
+	  throw NgException ("geo-file should start with 'algebraic3d'");
+
+	hgeom -> FindIdenticSurfaces(1e-8 * hgeom->MaxSize()); 
+	return hgeom;
+      }
+
+    if (strcmp (&cfilename[strlen(cfilename)-3], "ngg") == 0)
+      {
+	PrintMessage (1, "Load new CSG geometry file ", cfilename);
+
+	ifstream infile(cfilename);
+	CSGeometry * hgeom = new CSGeometry("");
+	hgeom -> Load (infile);
+
+	return hgeom;
+      }
+
+
+    
+    return NULL;
+  }
+
+  NetgenGeometry * CSGeometryRegister :: LoadFromMeshFile (istream & ist) const 
+  {
+    string auxstring;
+    if (ist.good())
+      {
+	ist >> auxstring;
+	if (auxstring == "csgsurfaces")
+	  {
+	    CSGeometry * geometry = new CSGeometry ("");
+	    geometry -> LoadSurfaces(ist);
+	    return geometry;
+	  }
+	// else
+	// ist.putback (auxstring);
+      }
+    return NULL;
+  }
+
+  VisualScene * CSGeometryRegister :: GetVisualScene (const NetgenGeometry * geom) const
+  {
+    CSGeometry * geometry = dynamic_cast<CSGeometry*> (ng_geometry);
+    if (geometry)
+      {
+	vsgeom.SetGeometry (geometry);
+	return &vsgeom;
+      }
+    return NULL;
+  }
+
+
+}
+
+
+using namespace netgen;
+
+int Ng_CSG_Init (Tcl_Interp * interp)
+{
+  geometryregister.Append (new CSGeometryRegister);
+  
+
+
+  Tcl_CreateCommand (interp, "Ng_ParseGeometry", Ng_ParseGeometry,
+		     (ClientData)NULL,
+		     (Tcl_CmdDeleteProc*) NULL);
+
+  // geometry
+  Tcl_CreateCommand (interp, "Ng_CreatePrimitive", Ng_CreatePrimitive,
+		     (ClientData)NULL,
+		     (Tcl_CmdDeleteProc*) NULL);
+
+  Tcl_CreateCommand (interp, "Ng_SetPrimitiveData", Ng_SetPrimitiveData,
+		     (ClientData)NULL,
+		     (Tcl_CmdDeleteProc*) NULL);
+
+  Tcl_CreateCommand (interp, "Ng_GetPrimitiveData", Ng_GetPrimitiveData,
+		     (ClientData)NULL,
+		     (Tcl_CmdDeleteProc*) NULL);
+
+  Tcl_CreateCommand (interp, "Ng_GetPrimitiveList", Ng_GetPrimitiveList,
+		     (ClientData)NULL,
+		     (Tcl_CmdDeleteProc*) NULL);
+
+
+  Tcl_CreateCommand (interp, "Ng_GetSurfaceList", Ng_GetSurfaceList,
+		     (ClientData)NULL,
+		     (Tcl_CmdDeleteProc*) NULL);
+
+
+
+  Tcl_CreateCommand (interp, "Ng_SetSolidData", Ng_SetSolidData,
+		     (ClientData)NULL,
+		     (Tcl_CmdDeleteProc*) NULL);
+
+  Tcl_CreateCommand (interp, "Ng_GetSolidData", Ng_GetSolidData,
+		     (ClientData)NULL,
+		     (Tcl_CmdDeleteProc*) NULL);
+
+  Tcl_CreateCommand (interp, "Ng_GetSolidList", Ng_GetSolidList,
+		     (ClientData)NULL,
+		     (Tcl_CmdDeleteProc*) NULL);
+
+
+  Tcl_CreateCommand (interp, "Ng_TopLevel", Ng_TopLevel,
+		     (ClientData)NULL,
+		     (Tcl_CmdDeleteProc*) NULL);
+
+  Tcl_CreateCommand (interp, "Ng_GeometryOptions", Ng_GeometryOptions,
+		     (ClientData)NULL,
+		     (Tcl_CmdDeleteProc*) NULL);
+
+  Tcl_CreateCommand (interp, "Ng_SingularEdgeMS", Ng_SingularEdgeMS,
+		     (ClientData)NULL,
+		     (Tcl_CmdDeleteProc*) NULL);
+  
+  Tcl_CreateCommand (interp, "Ng_SingularPointMS", Ng_SingularPointMS,
+		     (ClientData)NULL,
+		     (Tcl_CmdDeleteProc*) NULL);
+
+    Tcl_CreateCommand (interp, "Ng_SelectSurface", Ng_SelectSurface,
+		       (ClientData)NULL,
+		       (Tcl_CmdDeleteProc*) NULL);
+
+
+  return TCL_OK;
+}
+
+
+
diff --git a/contrib/Netgen/libsrc/csg/curve2d.cpp b/contrib/Netgen/libsrc/csg/curve2d.cpp
new file mode 100644
index 0000000000..7091e87af9
--- /dev/null
+++ b/contrib/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/contrib/Netgen/libsrc/csg/curve2d.hpp b/contrib/Netgen/libsrc/csg/curve2d.hpp
new file mode 100644
index 0000000000..066a40adb7
--- /dev/null
+++ b/contrib/Netgen/libsrc/csg/curve2d.hpp
@@ -0,0 +1,67 @@
+#ifndef FILE_CURVE2D
+#define FILE_CURVE2D
+
+/**************************************************************************/
+/* File:   curve2d.hh                                                     */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   24. Jul. 96                                                    */
+/**************************************************************************/
+
+namespace netgen
+{
+
+
+  /*
+
+  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/contrib/Netgen/libsrc/csg/edgeflw.cpp b/contrib/Netgen/libsrc/csg/edgeflw.cpp
new file mode 100644
index 0000000000..c9c5c1667c
--- /dev/null
+++ b/contrib/Netgen/libsrc/csg/edgeflw.cpp
@@ -0,0 +1,1850 @@
+#include <mystdlib.h>
+#include <meshing.hpp>
+#include <csg.hpp>
+
+// #undef DEVELOP
+// #define DEVELOP
+
+namespace netgen
+{
+
+  EdgeCalculation :: 
+  EdgeCalculation (const CSGeometry & ageometry,
+		   Array<SpecialPoint> & aspecpoints)
+    : geometry(ageometry), specpoints(aspecpoints)
+  {
+    Box<3> bbox = geometry.BoundingBox();
+
+    searchtree = new Point3dTree (bbox.PMin(), bbox.PMax());
+    meshpoint_tree = new Point3dTree (bbox.PMin(), bbox.PMax());
+
+    for (int i = 0; i < specpoints.Size(); i++)
+      searchtree->Insert (specpoints[i].p, i);
+
+    ideps = 1e-9;
+  }
+
+  EdgeCalculation :: ~EdgeCalculation()
+  {
+    delete searchtree;
+    delete meshpoint_tree;
+  }
+
+
+  void EdgeCalculation :: Calc(double h, Mesh & mesh)
+  {
+    static int timer = NgProfiler::CreateTimer ("CSG: mesh edges");
+    NgProfiler::RegionTimer reg (timer);
+
+
+    PrintMessage (1, "Find edges");
+    PushStatus ("Find edges");
+
+    for (int i = 1; i <= mesh.GetNP(); i++)
+      meshpoint_tree->Insert (mesh.Point(i), i);
+
+
+    // add all special points before edge points (important for periodic identification)
+    // JS, Jan 2007
+    const double di=1e-7*geometry.MaxSize();
+    Array<int> locsearch;
+
+    for (int i = 0; i < specpoints.Size(); i++)
+      if (specpoints[i].unconditional)
+	{
+	  Point<3> p = specpoints[i].p;
+          meshpoint_tree -> GetIntersecting (p-Vec<3> (di,di,di),
+                                             p+Vec<3> (di,di,di), locsearch);
+          
+	  if (locsearch.Size() == 0)
+            {
+              PointIndex pi = mesh.AddPoint (p, specpoints[i].GetLayer(), FIXEDPOINT);
+              meshpoint_tree -> Insert (p, pi); 
+            }
+        }
+
+    /*
+      // slow version
+    for (int i = 0; i < specpoints.Size(); i++)
+      if (specpoints[i].unconditional)
+	{
+	  Point<3> p = specpoints[i].p;
+	  bool found = false;
+	  for (int j = 1; j <= mesh.GetNP(); j++)
+	    if (Dist (p, mesh.Point(j)) < 1e-8)
+	      found = true;
+	  if (!found)
+	    mesh.AddPoint (p, specpoints[i].GetLayer(), FIXEDPOINT);
+	}
+    */
+
+
+
+    CalcEdges1 (h, mesh);
+    SplitEqualOneSegEdges (mesh);
+    FindClosedSurfaces (h, mesh);
+    PrintMessage (3, cntedge, " edges found");
+
+    PopStatus ();
+  }
+
+
+
+
+
+  void EdgeCalculation :: CalcEdges1 (double h, Mesh & mesh)
+  {
+    Array<int> hsp(specpoints.Size());
+    Array<int> glob2hsp(specpoints.Size());
+    Array<int> startpoints, endpoints;
+
+
+    int pos, ep;
+    int layer;
+
+    Point<3> p, np; 
+    int pi1, s1, s2, s1_orig, s2_orig;
+
+    Array<Point<3> > edgepoints;
+    Array<double> curvelength;
+    int copyedge = 0, copyfromedge = -1, copyedgeidentification = -1;
+
+    Array<int> locsurfind, locind;
+
+    int checkedcopy = 0;
+
+    // double size = geometry.MaxSize(); 
+    // double epspointdist2 = sqr (size) * 1e-12;
+    
+
+    // copy special points to work with
+    for (int i = 0; i < specpoints.Size(); i++)
+      {
+	hsp[i] = i;
+	glob2hsp[i] = i;
+      }
+
+    //for(int i=0; i<hsp.Size(); i++)
+    //  (*testout) << "hsp["<<i<<"] ... " << specpoints[hsp[i]].p << endl;
+     
+
+    cntedge = 0;
+    INDEX_2_HASHTABLE<int> identification_used(100);  // identification i already used for startpoint j
+
+    mesh.GetIdentifications().Delete();
+    
+    TABLE<int> specpoint2surface(specpoints.Size());
+    if (geometry.identifications.Size())
+      {
+	for (int i = 0; i < specpoints.Size(); i++)
+	  for (int j = 0; j < geometry.GetNSurf(); j++)
+	    if (geometry.GetSurface(j)->PointOnSurface (specpoints[i].p))
+	      specpoint2surface.Add (i, j);
+      }
+
+    TABLE<int> specpoint2tlo(specpoints.Size());
+    if (geometry.identifications.Size())
+      {
+	for (int i = 0; i < specpoints.Size(); i++)
+	  for (int j = 0; j < geometry.GetNTopLevelObjects(); j++)
+	    {
+	      const TopLevelObject * tlo = geometry.GetTopLevelObject (j);
+	      if (tlo->GetSolid() && tlo->GetSolid()->VectorIn (specpoints[i].p,specpoints[i].v))
+		//if (tlo->GetSolid() && tlo->GetSolid()->IsIn (specpoints[i].p))
+		{
+#ifdef DEVELOP
+		  (*testout) << "point " << specpoints[i].p << " v " <<specpoints[i].v <<" is in " << tlo->GetSolid()->Name() << endl;
+#endif
+		  specpoint2tlo.Add (i, j);
+		}
+	    }
+      }
+
+    for (int i = 0; i < specpoints.Size(); i++)
+      specpoints[i].nr = i;
+
+    while (hsp.Size())
+      {
+	SetThreadPercent(100 - 100 * double (hsp.Size()) / specpoints.Size());
+
+#ifdef DEVELOP
+	(*testout) << "hsp.Size() " << hsp.Size() << " specpoints.Size() " << specpoints.Size() << endl;
+	(*testout) << endl << "edge nr " << cntedge+1 << endl;
+#endif
+
+	edgepoints.SetSize (0);
+	curvelength.SetSize (0);
+      
+
+	pi1 = 0;
+	copyedge = 0;
+	// identifyable point available ?
+
+	
+	for (int i = 0; i < geometry.identifications.Size() && !pi1; i++)
+	  for (int j = checkedcopy; j < startpoints.Size() && !pi1; j++)
+	    {
+#ifdef DEVELOP
+	      (*testout) << "checking point " << specpoints[startpoints[j]].p
+			 << ", v = " << specpoints[startpoints[j]].v 
+			 << " for copying (i,j = " << i << ", " << j << ")" << endl;	  
+#endif
+ 	      if (geometry.identifications[i]->IdentifyableCandidate (specpoints[startpoints[j]]) &&
+		  geometry.identifications[i]->IdentifyableCandidate (specpoints[endpoints[j]]))
+		  
+	      
+		{
+		  int pi1cand = 0;
+		  double mindist = 1e10;
+		
+		  for (int k = 0; k < hsp.Size() && !pi1; k++)
+		    {
+		      //(*testout) << "   ? identifyable with " << specpoints[hsp[k]].p 
+		      //<< ", v = " << specpoints[hsp[k]].v
+		      //		 << endl;
+		      if (identification_used.Used (INDEX_2(i, startpoints[j])) ||
+			  identification_used.Used (INDEX_2(i, hsp[k])))
+			{
+			  //(*testout) << "failed at pos0" << endl;
+			  continue;
+			}
+		      
+		      if (geometry.identifications[i]
+			  ->Identifyable(specpoints[startpoints[j]], specpoints[hsp[k]], specpoint2tlo, specpoint2surface) ||
+			  geometry.identifications[i]
+			  ->Identifyable(specpoints[hsp[k]], specpoints[startpoints[j]], specpoint2tlo, specpoint2surface))
+			{
+#ifdef DEVELOP
+			  (*testout) << "identifyable: " << specpoints[hsp[k]].p << ", v = " << specpoints[hsp[k]].v
+				     << " and " << specpoints[startpoints[j]].p << ", v = " << specpoints[startpoints[j]].v 
+				     << " (identification " << i+1 << ")" << endl;
+#endif
+
+			  if (Dist (specpoints[startpoints[j]].p, specpoints[hsp[k]].p) < mindist)
+			    {
+			      mindist = Dist (specpoints[startpoints[j]].p, specpoints[hsp[k]].p);
+			      pi1cand = k+1;
+			    }
+			}
+		    }
+	
+	
+		  if (pi1cand)
+		    {
+		      pi1 = pi1cand;
+		      copyedge = 1;
+		      copyfromedge = j+1;
+		      copyedgeidentification = i+1;
+		    
+		      identification_used.Set (INDEX_2(i, startpoints[j]), 1);
+		      identification_used.Set (INDEX_2(i, hsp.Get(pi1)), 1);
+		    }
+		}
+	    }
+	
+      
+	// cannot copy from other ege ?
+	if (!pi1)
+	  checkedcopy = startpoints.Size();
+      
+	// unconditional special point available ?
+	if (!pi1)
+	  for (int i = 1; i <= hsp.Size(); i++)
+	    if (specpoints[hsp.Get(i)].unconditional == 1)
+	      {
+		pi1 = i;
+		break;
+	      }
+ 
+     
+	if (!pi1)
+	  {
+	    // no unconditional points available, choose first conitional
+	    pi1 = 1;	     
+	  }
+
+	layer = specpoints[hsp.Get(pi1)].GetLayer();
+      
+
+	if (!specpoints[hsp.Get(pi1)].unconditional)
+	  {
+	    specpoints[hsp.Elem(pi1)].unconditional = 1;
+	    for (int i = 1; i <= hsp.Size(); i++)
+	      if (i != pi1 && 
+		  Dist (specpoints[hsp.Get(pi1)].p, specpoints[hsp.Get(i)].p) < 1e-8*geometry.MaxSize() &&
+		  (specpoints[hsp.Get(pi1)].v + specpoints[hsp.Get(i)].v).Length() < 1e-4)
+		{
+		  // opposite direction
+		  specpoints[hsp.Elem(i)].unconditional = 1;
+		}
+	  }
+
+	cntedge++;
+	startpoints.Append (hsp.Get(pi1));
+
+#ifdef DEVELOP
+	(*testout) << "start followedge: p1 = " << specpoints[hsp.Get(pi1)].p 
+		   << ", v = " << specpoints[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);
+	    cout << "yes, this happens" << endl;
+	    continue;
+	  }
+
+
+
+	endpoints.Append (hsp.Get(ep));
+
+
+	double elen = 0;
+	for (int i = 1; i <= edgepoints.Size()-1; i++)
+	  elen += Dist (edgepoints.Get(i), edgepoints.Get(i+1));
+
+
+	int shortedge = 0;
+	for (int i = 1; i <= geometry.identifications.Size(); i++)
+	  if (geometry.identifications.Get(i)->ShortEdge(specpoints[hsp.Get(pi1)], specpoints[hsp.Get(ep)]))
+	    shortedge = 1;
+	// (*testout) << "shortedge = " << shortedge << endl;
+
+
+	if (!shortedge)
+	  {
+	    mesh.RestrictLocalHLine (Point3d (specpoints[hsp.Get(pi1)].p), 
+				     Point3d (specpoints[hsp.Get(ep)].p), 
+				     elen / mparam.segmentsperedge);
+	  }
+      
+	s1 = specpoints[hsp.Get(pi1)].s1;
+	s2 = specpoints[hsp.Get(pi1)].s2;
+	s1_orig = specpoints[hsp.Get(pi1)].s1_orig;
+	s2_orig = specpoints[hsp.Get(pi1)].s2_orig;
+
+
+	// delete initial, terminal and conditional points
+
+#ifdef DEVELOP
+	(*testout) << "terminal point: p = " << specpoints[hsp.Get(ep)].p 
+		   << ", v = " << specpoints[hsp.Get(ep)].v << endl;      
+#endif
+
+	searchtree -> DeleteElement (hsp.Get(ep));
+	searchtree -> DeleteElement (hsp.Get(pi1));
+
+	if (ep > pi1)
+	  {
+	    glob2hsp[hsp[ep-1]] = -1;
+	    glob2hsp[hsp.Last()] = ep-1;
+	    hsp.DeleteElement (ep);
+
+	    glob2hsp[hsp[pi1-1]] = -1;
+	    glob2hsp[hsp.Last()] = pi1-1;
+	    hsp.DeleteElement (pi1);
+	  }
+	else
+	  {
+	    glob2hsp[hsp[pi1-1]] = -1;
+	    glob2hsp[hsp.Last()] = pi1-1;
+	    hsp.DeleteElement (pi1);
+
+	    glob2hsp[hsp[ep-1]] = -1;
+	    glob2hsp[hsp.Last()] = ep-1;
+	    hsp.DeleteElement (ep);
+	  }
+
+
+	for (int j = 1; j <= edgepoints.Size()-1; j++)
+	  {
+	    p = edgepoints.Get(j);
+	    np = Center (p, edgepoints.Get(j+1));
+	    double hd = Dist (p, np);
+ 
+
+	    Box<3> boxp (np - (1.2 * hd) * Vec<3> (1, 1, 1),
+			 np + (1.2 * hd) * Vec<3> (1, 1, 1));
+	    searchtree -> GetIntersecting (boxp.PMin(), boxp.PMax(), locind);	    
+
+	    for (int i = 0; i < locind.Size(); i++)
+	      {
+		if ( specpoints[locind[i]].HasSurfaces (s1, s2) &&
+		     specpoints[locind[i]].unconditional == 0)
+		  {
+		    searchtree -> DeleteElement (locind[i]);
+
+		    int li = glob2hsp[locind[i]];
+		    glob2hsp[locind[i]] = -1;
+		    glob2hsp[hsp.Last()] = li;
+		    hsp.Delete (li);
+		  }
+	      }
+
+
+	    /*
+	    for (int i = 1; i <= hsp.Size(); i++)
+	      if ( specpoints[hsp.Get(i)].HasSurfaces (s1, s2) &&
+		   specpoints[hsp.Get(i)].unconditional == 0 &&
+		   Dist2 (np, specpoints[hsp.Get(i)].p) < 1.2 * hd)
+		{
+		  searchtree -> DeleteElement (hsp.Get(i)+1);
+		  hsp.DeleteElement (i);
+		  i--;
+		}
+	    */
+	  }
+
+      
+	Array<Segment> refedges;
+	Array<bool> refedgesinv;
+      
+
+	AnalyzeEdge (s1_orig, s2_orig, s1, s2, pos, layer,
+		     edgepoints,
+		     refedges, refedgesinv);
+
+
+	for (int i = 0; i < refedges.Size(); i++)
+	  refedges[i].edgenr = cntedge;
+
+	
+#ifdef DEVELOP
+	(*testout) << "edge " << cntedge << endl
+		   << "startp: " << specpoints[startpoints.Last()].p 
+		   << ", v = " << specpoints[startpoints.Last()].v << endl
+		   << "copy = " << copyedge << endl
+		   << refedges.Size() << " refedges: ";
+	for (int i = 1; i <= refedges.Size(); i++)
+	  (*testout) << " " << refedges.Get(i).si;
+	(*testout) << endl;
+	if (refedgesinv.Size())
+	  (*testout) << "inv[1] = " << refedgesinv.Get(1) << endl;
+#endif
+
+	if (refedges.Size() == 0)
+	  throw NgException ("Problem in edge detection");
+
+      
+	if (!copyedge)
+	  {
+	    // (*testout) << "store edge" << endl;
+	    // int oldnseg = mesh.GetNSeg();
+
+	    if (!shortedge)
+	      StoreEdge (refedges, refedgesinv, 
+			 edgepoints, curvelength, layer, mesh);
+	    else
+	      StoreShortEdge (refedges, refedgesinv, 
+			      edgepoints, curvelength, layer, mesh);
+
+
+	    for(int i = 0; i < refedges.Size(); i++)
+	      {
+		refedges[i].surfnr1 = geometry.GetSurfaceClassRepresentant(refedges[i].surfnr1);
+		refedges[i].surfnr2 = geometry.GetSurfaceClassRepresentant(refedges[i].surfnr2);
+	      }
+
+
+	    /*
+	      for (int i = oldnseg+1; i <= mesh.GetNSeg(); i++)
+	      for (int 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, 
+		      specpoints[startpoints.Get(copyfromedge)].p,
+		      specpoints[endpoints.Get(copyfromedge)].p,
+		      edgepoints.Get(1), edgepoints.Last(),
+		      copyedgeidentification, 
+		      layer,
+		      mesh);
+	  }
+	
+
+	/*
+	  // not available ...
+	for (int i = 0; i < refedges.Size(); i++)
+	  {
+	    EdgeDescriptor ed;
+	    ed.SetSurfNr(0, refedges[i].surfnr1);
+	    ed.SetSurfNr(1, refedges[i].surfnr2);
+	    int hnr = mesh.AddEdgeDescriptor(ed);
+	    if (hnr != refedges[i].edgenr)
+	      {
+		cerr << "edgedescriptor index wrong: new : " << hnr << " old = " << refedges[i].edgenr << endl;
+	      }
+	  }
+	*/
+
+
+
+// 	for(int i=0; i<hsp.Size(); i++)
+// 	  {
+// 	    (*testout) << "pos2 hsp["<<i<<"] ... " << specpoints[hsp[i]].p << endl;
+// 	  }
+      }
+  }
+  
+
+
+
+
+
+  /*
+    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;
+    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 (int 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[0], seg[1]);
+		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 !
+    point_on_edge_problem = 0;
+    for (int i = 1; i <= osedgesht.GetNBags(); i++)
+      for (int 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)
+		      {
+			PrintWarning ("Point on edge !!!");
+			cout << "seg: " << i2 << ", p = " << pi << endl;
+			osedgesht.Set (i2, 2);		      
+			point_on_edge_problem = 1;
+
+			(*testout) << "Point on edge" << endl
+				   << "seg = " << i2 << ", p = " << pi << endl
+				   << "pos = " << p << ", projected = " << hp << endl
+				   << "seg is = " << mesh.Point(i2.I1()) << " - " << mesh.Point(i2.I2()) << endl;
+		      }
+		  }
+	      }
+	}
+
+
+    // 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[0], seg[1]);
+	    i2.Sort ();
+	    if (osedgesht.Used (i2) &&
+		osedgesht.Get (i2) == 2 &&
+		osedges.Elem(seg.edgenr) == -1)
+	      {
+		Point<3> newp = Center (mesh[PointIndex(seg[0])],
+					mesh[PointIndex(seg[1])]);
+
+		ProjectToEdge (geometry.GetSurface(seg.surfnr1), 
+			       geometry.GetSurface(seg.surfnr2), 
+			       newp);
+
+		osedges.Elem(seg.edgenr) = 
+		  mesh.AddPoint (newp, mesh[PointIndex(seg[0])].GetLayer(), EDGEPOINT);
+		meshpoint_tree -> Insert (newp, osedges.Elem(seg.edgenr));
+	      }
+	  }
+      }
+    
+
+    for (int 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[0] = osedges.Get(seg.edgenr);
+		seg[1] = osedges.Get(seg.edgenr);
+		mesh.AddSegment (newseg);
+	      }
+	  }
+      }
+
+  }
+
+
+
+  void EdgeCalculation :: 
+  FollowEdge (int pi1, int & ep, int & pos,
+	      const Array<int> & hsp,
+	      double h, const Mesh & mesh,
+	      Array<Point<3> > & edgepoints,
+	      Array<double> & curvelength)
+  {
+    int s1, s2, s1_rep, s2_rep;
+    double len, steplen, cursteplen, loch;
+    Point<3> p, np, pnp;
+    Vec<3> a1, a2, t;
+
+    Array<int> locind;
+
+    double size = geometry.MaxSize();  
+    double epspointdist2 = size * 1e-6;
+    epspointdist2 = sqr (epspointdist2);
+    int uselocalh = mparam.uselocalh;
+
+
+    s1_rep = specpoints[hsp.Get(pi1)].s1;
+    s2_rep = specpoints[hsp.Get(pi1)].s2;
+    s1 = specpoints[hsp.Get(pi1)].s1_orig;
+    s2 = specpoints[hsp.Get(pi1)].s2_orig;
+  
+    p = specpoints[hsp.Get(pi1)].p;
+    //ProjectToEdge (geometry.GetSurface(s1), 
+    //               geometry.GetSurface(s2), p);
+    geometry.GetSurface(s1) -> CalcGradient (p, a1);
+    geometry.GetSurface(s2) -> CalcGradient (p, a2);
+
+    t = Cross (a1, a2);
+    t.Normalize();
+
+    pos = (specpoints[hsp.Get(pi1)].v * t) > 0;
+    if (!pos) t *= -1;
+
+  
+    edgepoints.Append (p);
+    curvelength.Append (0);
+    len = 0;
+
+    // (*testout) << "geometry.GetSurface(s1) -> LocH (p, 3, 1, h) " << geometry.GetSurface(s1) -> LocH (p, 3, 1, h)
+    // << " geometry.GetSurface(s2) -> LocH (p, 3, 1, h) " << geometry.GetSurface(s2) -> LocH (p, 3, 1, h) << endl;
+
+    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);
+	// (*testout) << "lh " << lh << endl;
+	if (lh < loch)
+	  loch = lh;
+      }
+
+    steplen = 0.1 * loch;
+  
+    do
+      {
+	if (multithread.terminate)
+	  return;
+      
+	if (fabs (p(0)) + fabs (p(1)) + fabs (p(2)) > 100000*size)
+	  {
+	    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;
+	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));
+
+	searchtree -> GetIntersecting (boxp.PMin(), boxp.PMax(), locind);
+	
+	for (int i = 0; i < locind.Size(); i++)
+	  {
+	    Vec<3> hv = specpoints[locind[i]].p - p;
+	    if (hv.Length2() > 9 * cursteplen * cursteplen)
+	      continue;
+
+	    double hvt = hv * t;
+	    hv -= hvt * t;
+
+	    if (hv.Length() < 0.2 * cursteplen &&
+		hvt > 0 && 
+		//		  hvt < 1.5 * cursteplen &&
+		hvt < hvtmin && 
+		specpoints[locind[i]].unconditional == 1 &&
+		(specpoints[locind[i]].v + t).Length() < 0.4  ) 
+	      {
+		Point<3> hep = specpoints[locind[i]].p;
+		ProjectToEdge (geometry.GetSurface(s1), 
+			       geometry.GetSurface(s2), hep);            
+	      
+	      
+		if (Dist2 (hep, specpoints[locind[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 ( (specpoints[locind[i]].v + ept).Length() < 1e-4 )
+		      {
+			np = specpoints[locind[i]].p;
+
+			for (int jj = 0; jj < hsp.Size(); jj++)
+			  if (hsp[jj] == locind[i])
+			    ep = jj+1;
+			    
+			if (!ep) 
+			  cerr << "endpoint not found" << endl;
+			  //			ep = i;
+			hvtmin = hvt;
+			//			  break;
+		      }
+		  }
+	      }
+	  }
+
+
+
+
+	/*
+	for (int i = 1; i <= hsp.Size(); i++)
+	  {
+	    if (!boxp.IsIn (specpoints[hsp.Get(i)].p))
+	      continue;
+	  
+	    Vec<3> hv = specpoints[hsp.Get(i)].p - p;
+	    if (hv.Length2() > 9 * cursteplen * cursteplen)
+	      continue;
+
+	    double hvt = hv * t;
+	    hv -= hvt * t;
+	  
+	    if (hv.Length() < 0.2 * cursteplen &&
+		hvt > 0 && 
+		//		  hvt < 1.5 * cursteplen &&
+		hvt < hvtmin && 
+		specpoints[hsp.Get(i)].unconditional == 1 &&
+		(specpoints[hsp.Get(i)].v + t).Length() < 0.4  ) 
+	      {
+		Point<3> hep = specpoints[hsp.Get(i)].p;
+		ProjectToEdge (geometry.GetSurface(s1), 
+			       geometry.GetSurface(s2), hep);            
+	      
+	      
+		if (Dist2 (hep, specpoints[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 ( (specpoints[hsp.Get(i)].v + ept).Length() < 1e-4 )
+		      {
+			np = specpoints[hsp.Get(i)].p;
+			ep = i;
+			hvtmin = hvt;
+			//			  break;
+		      }
+		  }
+	      }
+	  }
+	*/
+
+	loch = min2 (geometry.GetSurface(s1_rep) -> LocH (np, 3, 1, h), 
+		     geometry.GetSurface(s2_rep) -> LocH (np, 3, 1, h));
+        loch = max2 (loch, mparam.minh);
+
+	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 s1_rep, int s2_rep, int pos, int layer,
+	       const Array<Point<3> > & edgepoints,
+	       Array<Segment> & refedges,
+	       Array<bool> & refedgesinv)
+  {
+    Segment seg;
+    Array<int> locsurfind, locsurfind2;
+
+    Array<int> edges_priority;
+
+    double size = geometry.MaxSize();
+    bool debug = 0;
+
+#ifdef DEVELOP
+    debug = 1;
+#endif
+    
+    if (debug)
+      {
+	(*testout) << "debug edge !!!" << endl;
+	(*testout) << "edgepoints = " << edgepoints << endl;
+	(*testout) << "s1, s2 = " << s1 << " - " << s2 << endl;
+	(*testout) << "s1_rep, s2_rep = " << s1_rep << " - " << s2_rep << endl;
+      }
+
+    refedges.SetSize(0);
+    refedgesinv.SetSize(0);
+    Point<3> hp = Center (edgepoints[0], edgepoints[1]);
+    ProjectToEdge (geometry.GetSurface(s1), geometry.GetSurface(s2), hp);
+    
+    if (debug)
+      *testout << "hp = " << hp << endl;
+
+    Vec<3> t, a1, a2;
+    geometry.GetSurface(s1) -> CalcGradient (hp, a1);
+    geometry.GetSurface(s2) -> CalcGradient (hp, a2);
+    t = Cross (a1, a2);
+    t.Normalize();
+    if (!pos) t *= -1;    
+
+
+  
+    for (int i = 0; i < geometry.GetNTopLevelObjects(); i++)
+      {
+	Solid * locsol;
+
+	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, locsurfind, size*ideps);
+
+	//*testout << "hp = " << hp << endl;
+	//(*testout) << "locsol: " << endl;
+	//if (locsol) locsol->Print(*testout);
+	//(*testout) << endl;
+
+
+	if (!locsol) continue;
+
+	BoxSphere<3> boxp (hp, hp);
+	boxp.Increase (1e-8*size);
+	boxp.CalcDiamCenter();
+      
+	ReducePrimitiveIterator rpi(boxp);
+	UnReducePrimitiveIterator urpi;
+      
+	((Solid*)locsol) -> IterateSolid (rpi);
+
+	locsol -> CalcSurfaceInverse ();
+      
+	if (!surf)
+	  {
+	    locsol -> GetTangentialSurfaceIndices (hp,locsurfind,ideps*size);
+	  }
+	else
+	  {
+	    /*
+	      if (fabs (surf->CalcFunctionValue (hp)) < 1e-6)
+	      continue;
+	    */
+	    locsurfind.SetSize(1);
+	    locsurfind[0] = -1;
+	    for (int 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 (int j = locsurfind.Size()-1; j >= 0; j--)
+	  if (fabs (geometry.GetSurface(locsurfind[j])
+		    ->CalcFunctionValue (hp) ) > ideps*size)
+	    locsurfind.Delete(j);
+      
+	if (debug)
+	  (*testout) << locsurfind.Size() << " faces on hp" << endl;
+
+
+
+	for (int j = 0; j < locsurfind.Size(); j++)
+	  {      
+	    int lsi = locsurfind[j];
+	    int rlsi = geometry.GetSurfaceClassRepresentant(lsi);
+	  
+
+	    // n is outer normal to solid
+	    Vec<3> n = geometry.GetSurface(lsi) -> GetNormalVector (hp);
+            if (debug)
+              *testout << "n1 = " << n << endl;
+	    if (geometry.GetSurface (lsi)->Inverse())
+	      n *= -1;
+	  
+	    if (fabs (t * n) > 1e-4) continue;
+	    if (debug)
+	      {
+		(*testout) << "face " << locsurfind[j] << ", rep = " << rlsi 
+			   << " has (t*n) = " << (t*n) << endl;
+		(*testout) << "n = " << n << endl;
+	      }
+	  
+	    // rn is normal to class representant
+	    Vec<3> rn = geometry.GetSurface(rlsi) -> GetNormalVector (hp);
+	    if (debug)
+	      {
+		(*testout) << "rn = " << rn << endl;
+	      }
+	    
+	    //if( n*rn < 0)
+	    // rn *= -1;
+
+	    bool sameasref = ((n * rn) > 0);
+
+	    //m = Cross (t, rn);
+	    Vec<3> m = Cross (t, n); 
+	    if(!sameasref) m*=-1.;
+	    
+	    m.Normalize();
+
+	    
+	    if (debug)
+	      (*testout) << "m = " << m << endl;
+
+
+	    //bool founddirection = false;
+	    //int k;
+	    double eps = 1e-8*size;
+
+	    Array<bool> pre_ok(2);
+
+ 	    do
+ 	      {
+ 		eps *= 0.5;
+ 		pre_ok[0] = (locsol -> VectorIn2 (hp, m, n, eps) == IS_OUTSIDE &&
+			     locsol -> VectorIn2 (hp, m, -1. * n, eps) == IS_INSIDE);
+ 		pre_ok[1] = (locsol -> VectorIn2 (hp, -1.*m, n, eps) == IS_OUTSIDE &&
+			     locsol -> VectorIn2 (hp, -1.*m, -1. * n, eps) == IS_INSIDE);
+		
+		if (debug)
+		  {
+		    *testout << "eps = " << eps << endl;
+		    *testout << "in,1 = " << locsol -> VectorIn2 (hp, m, n, eps) << endl;
+		    *testout << "in,1 = " << locsol -> VectorIn2 (hp, m, -1. * n, eps) << endl;
+		    *testout << "in,1 = " << locsol -> VectorIn2 (hp, -1.*m, n, eps) << endl;
+		    *testout << "in,1 = " << locsol -> VectorIn2 (hp, -1.*m, -1. * n, eps) << endl;
+		  }
+ 	      }
+ 	    while(pre_ok[0] && pre_ok[1] && eps > 1e-16*size);
+
+            if (debug)
+              {
+                *testout << "eps = " << eps << ", size = " << size << endl;
+                *testout << "pre_ok[0,1] = " << pre_ok[0] << "," << pre_ok[1] << endl;
+              }
+
+	    eps = 1e-8*size;
+	    
+
+	    for (int k = 1; k <= 2; k ++)
+	      {
+		bool edgeinv = (k == 2);
+	      
+		if (debug)
+		  {
+		    (*testout) << "onface(" << hp << ", " << m << ")= " << flush;
+		    (*testout) << locsol->OnFace (hp, m, eps) << flush;
+		    (*testout) << " n " << n << flush;
+		    (*testout) << " vec2in = "
+			       << locsol -> VectorIn2 (hp, m, n, eps) << " and " 
+			       << locsol -> VectorIn2 (hp, m, -1 * n, eps) << endl;
+		  }
+
+		//	      if (locsol -> OnFace (hp, m))
+		
+
+		// one side must be inside, the other must be outside
+		bool ok = (pre_ok[k-1] || 
+			   (locsol -> VectorIn2 (hp, m, n, eps) == IS_OUTSIDE &&
+			    locsol -> VectorIn2 (hp, m, -1 * n, eps) == IS_INSIDE));
+
+		if (debug)
+		  (*testout) << "ok (before) " << ok <<  endl;
+
+		// compute second order approximation
+		// curve = hp + t m + t*t/2 m2
+		Vec<3> grad, m2;
+		Mat<3> hesse;
+		geometry.GetSurface(lsi) -> CalcGradient (hp, grad);
+		geometry.GetSurface(lsi) -> CalcHesse (hp, hesse);
+		double fac = -(m * (hesse * m)) / (grad * grad);
+		m2 = fac * grad;
+		// (*testout) << "hp = " << hp << ", m = " << m << ", m2 = " << m2 << endl;
+
+		Solid * locsol2;
+		locsol -> TangentialSolid3 (hp, m, m2, locsol2, locsurfind2, ideps*size);
+		if (!locsol2) ok = 0;
+		delete locsol2;
+
+
+		if (ok)
+		  {
+		    if (debug)
+		      (*testout) << "is true" << endl;
+		    int hi = 0;
+		    for (int l = 1; !hi && l <= refedges.Size(); l++)
+		      {
+			   if (refedges.Get(l).si == rlsi &&     // JS sept 2006
+			       // if (refedges.Get(l).si == lsi &&
+			       refedgesinv.Get(l) == edgeinv)
+			     {
+			       hi = l;
+			     }
+		      }
+		  
+		    if (!hi)
+		      {
+			 seg.si = rlsi;  // JS Sept 2006
+			 // seg.si = lsi;
+			seg.domin = -1;
+			seg.domout = -1;
+			seg.tlosurf = -1;
+			//seg.surfnr1 = s1_rep;
+			//seg.surfnr2 = s2_rep;
+			seg.surfnr1 = s1;
+			seg.surfnr2 = s2;
+			hi = refedges.Append (seg);
+			refedgesinv.Append (edgeinv);
+			edges_priority.Append((pre_ok[k-1]) ? 1 : 0);
+		      }
+		    else
+		      {
+			if(edges_priority[hi-1] / 10 == -i-1)
+			  edges_priority[hi-1] = 10*(i+1);
+			else
+			  edges_priority[hi-1] = -10*(i+1);
+		      }
+		  
+		    if (!surf)
+		      {
+			if (sameasref)
+			  refedges.Elem(hi).domin = i;
+			else 
+			  refedges.Elem(hi).domout = i;
+		      }
+		    else
+		      refedges.Elem(hi).tlosurf = i;
+
+		    if(pre_ok[k-1])
+		      edges_priority[hi-1] = 1;
+		    
+
+		    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
+				 << ", priority = " << edges_priority[hi-1]
+				 << ", hi = " << hi 
+				 << endl;
+		  }
+		else
+		  {
+		    if (debug)
+		      (*testout) << "is false" << endl;
+		  }
+		m *= -1;
+	      } 
+	  }
+	delete locsol;          
+      }
+
+   
+    if (debug)
+      {
+	*testout << "Refsegments, before delete: " << endl << refedges << endl;
+	*testout << "inv: " << endl << refedgesinv << endl;
+      }
+    
+    BitArray todelete(refedges.Size());
+    todelete.Clear();
+
+
+    for(int i=0; i<refedges.Size()-1; i++)
+      {
+	for(int j=i+1; !todelete.Test(i) && j<refedges.Size(); j++)
+	  {
+	    if(todelete.Test(j))
+	      continue;
+
+	    if(refedges[i].si == refedges[j].si &&
+	       refedges[i].domin == refedges[j].domin &&
+	       refedges[i].domout == refedges[j].domout &&
+	       geometry.GetSurfaceClassRepresentant(refedges[i].surfnr1) == geometry.GetSurfaceClassRepresentant(refedges[j].surfnr1) &&
+	       geometry.GetSurfaceClassRepresentant(refedges[i].surfnr2) == geometry.GetSurfaceClassRepresentant(refedges[j].surfnr2)
+	       // && refedgesinv[i] == refedgesinv[j] // JS, 20060802
+	       )
+	      {
+		if(debug)
+		  (*testout) << "equal segments: " << refedges[i] << " pri " << edges_priority[i] 
+			     << " tlosurf " << refedges[i].tlosurf
+			     << "\n and " << refedges[j] << " pri " << edges_priority[j]
+			     << " tlosurf " << refedges[i].tlosurf << endl;
+		
+		if(edges_priority[i] < 10 && edges_priority[i] < edges_priority[j])
+		  {
+		    todelete.Set(i);
+		  }
+		else if (edges_priority[j] < 10 && edges_priority[i] > edges_priority[j])
+		  {
+		    todelete.Set(j);
+		  }
+	      }
+	  }
+	  
+      }
+    
+    int num = refedges.Size();
+
+    for(int i=refedges.Size()-1; num>2 && i>=0; i--)
+      if(todelete.Test(i))
+	{
+	  refedges.Delete(i);
+	  refedgesinv.Delete(i);
+	  num--;
+	}
+
+    
+    if (debug)
+      {
+	*testout << "Refsegments: " << endl << refedges << endl;
+      }
+  }
+
+
+
+  void EdgeCalculation :: 
+  StoreEdge (const Array<Segment> & refedges,
+	     const Array<bool> & 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);
+
+    (*testout) << "s1 " << refedges.Get(1).surfnr1 << " s2 " << refedges.Get(1).surfnr2
+	       << " rs1 " << geometry.GetSurfaceClassRepresentant(refedges.Get(1).surfnr1)
+	       << " rs2 " << geometry.GetSurfaceClassRepresentant(refedges.Get(1).surfnr2) << endl;
+
+    len = curvelength.Last();
+    ne = int (len + 0.5);
+    if (ne == 0) ne = 1;
+    if (Dist (edgepoints.Get(1), edgepoints.Last()) < 1e-8*geometry.MaxSize() && 
+	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;
+	}
+    */
+
+    const double di=1e-7*geometry.MaxSize();
+
+    Array<int> locsearch;
+    meshpoint_tree -> GetIntersecting (p-Vec<3> (di,di,di),
+				       p+Vec<3> (di,di,di), locsearch);
+    if (locsearch.Size())
+      lastpi = locsearch[0];
+				       
+
+
+    if (lastpi == -1)
+      {
+	lastpi = mesh.AddPoint (p, layer, FIXEDPOINT);
+	meshpoint_tree -> Insert (p, lastpi); 
+	// (*testout) << "test1, store point " << lastpi << ", p = " << p << endl;
+      }
+  
+    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;
+	    */
+	    
+	    meshpoint_tree -> GetIntersecting (np-Vec<3> (di,di,di),
+					       np+Vec<3> (di,di,di), locsearch);
+	    if (locsearch.Size())
+	      thispi = locsearch[0];
+	  }
+
+	if (thispi == -1)
+	  {
+	    ProjectToEdge (surf1, surf2, np);
+	    thispi = mesh.AddPoint (np, layer, (i==ne) ? FIXEDPOINT : EDGEPOINT);
+	   
+	    meshpoint_tree -> Insert (np, thispi);
+	    // (*testout) << "test2, store point " << thispi << ", p = " << np << endl;
+	  }
+
+	for (k = 1; k <= refedges.Size(); k++)
+	  {
+	    if (refedgesinv.Get(k))
+	      {
+		seg[0] = lastpi;
+		seg[1] = thispi;
+	      }
+	    else
+	      {
+		seg[0] = thispi;
+		seg[1] = 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 " << mesh[seg.p1] << "-" << mesh[seg.p2] << endl;
+	    //(*testout) << "refedge " << k << " surf1 " << seg.surfnr1 << " surf2 " << seg.surfnr2 << " inv " << refedgesinv.Get(k) << 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<bool> & refedgesinv,
+		  const Array<Point<3> > & edgepoints,
+		  const Array<double> & curvelength,
+		  int layer,
+		  Mesh & mesh)
+  {
+  
+    // Calculate optimal element-length
+    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*geometry.MaxSize())
+	{
+	  pi1 = pi;
+	  break;
+	}
+
+    if (pi1 == -1) 
+      {
+	pi1 = mesh.AddPoint (p, layer, FIXEDPOINT);
+	meshpoint_tree -> Insert (p, pi1);
+	// (*testout) << "test3, store point " << pi1 << ", p = " << p << endl;
+      }
+
+    p = edgepoints.Last();
+    PointIndex pi2 = -1;
+    for (pi = PointIndex::BASE; 
+	 pi < mesh.GetNP()+PointIndex::BASE; pi++)
+
+      if (Dist (mesh[pi], p) < 1e-6*geometry.MaxSize())
+	{
+	  pi2 = pi;
+	  break;
+	}
+    if (pi2==-1) 
+      {
+	pi2 = mesh.AddPoint (p, layer, FIXEDPOINT);
+	meshpoint_tree -> Insert (p, pi2);
+	// (*testout) << "test4, store point " << pi2 << ", p = " << p << endl;
+      }
+
+    /*
+  
+    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);
+    }
+    */
+
+    // (*testout) << "short edge " << pi1 << " - " << pi2 << endl;
+  
+    for (int k = 1; k <= refedges.Size(); k++)
+      {
+	if (refedgesinv.Get(k))
+	  {
+	    seg[0] = pi1;
+	    seg[1] = pi2;
+	  }
+	else
+	  {
+	    seg[0] = pi2;
+	    seg[1] = 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[0] << "-" << seg[1] << endl;
+      }
+  }
+  
+
+
+
+
+
+
+  void EdgeCalculation :: 
+  CopyEdge (const Array<Segment> & refedges,
+	    const Array<bool> & 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 k;
+    PointIndex pi;
+
+    double size = geometry.MaxSize();
+    
+    // copy start and end points
+    for (int 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*size)
+	      frompi = pi;
+	    if (Dist2 (mesh[pi], top) <= 1e-16*size)
+	      topi = pi;
+	  }
+
+	
+	if (topi == -1)
+	  {
+	    topi = mesh.AddPoint (top, layer, FIXEDPOINT);
+	    meshpoint_tree -> Insert (top, topi);
+	  }
+
+	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);
+	  }
+#ifdef DEVELOP
+	(*testout) << "adding identification " << mesh[frompi] << "; " << mesh[topi]
+		   << " (id " << copyedgeidentification <<")" << endl;
+#endif
+
+
+	/*
+	  (*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 (int 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[0];
+	int pi2 = oldseg[1];
+
+	int npi1 = geometry.identifications.Get(copyedgeidentification)
+	  -> GetIdentifiedPoint (mesh, pi1);
+	int npi2 = geometry.identifications.Get(copyedgeidentification)
+	  -> GetIdentifiedPoint (mesh, pi2);
+
+	//(*testout) << "copy edge, pts = " << npi1 << " - " << npi2 << endl;
+
+	Segment seg;
+
+	for (k = 1; k <= refedges.Size(); k++)
+	  {
+	    bool inv = refedgesinv.Get(k);
+
+	    // other edge is inverse
+	    if (oldseg.seginfo == 1)
+	      inv = !inv;
+
+	    //	  (*testout) << "inv, now = " << inv << endl;
+
+	    if (inv)
+	      {
+		seg[0] = npi1;
+		seg[1] = npi2;
+	      }
+	    else
+	      {
+		seg[0] = npi2;
+		seg[1] = 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[0] << "-" << seg[1] << endl;
+#ifdef DEVELOP
+
+	    (*testout) << "copy seg, face = " << seg.si << ": " 
+		       << " inv = " << inv << ", refinv = " << refedgesinv.Get(k)
+		       << mesh.Point(seg[0]) << ", " << mesh.Point(seg[1]) << 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(0);
+
+    BitArray pointatsurface (nsurf);
+    Point<3> p1, p2;
+    Vec<3> nv, tv;
+    Solid * tansol;
+    Array<int> tansurfind;
+    //  const Solid * sol;
+
+    double size = geometry.MaxSize();
+    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();
+	    nv = s -> GetNormalVector (p1);
+		    
+	    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;
+	    seg1.surfnr2 = i;
+	    seg2.surfnr2 = i;
+
+	    for (j = 0; j < nsol; j++)
+	      {
+		if (geometry.GetTopLevelObject(j)->GetSurface())
+		  continue;
+		  
+		const Solid * sol = geometry.GetTopLevelObject(j)->GetSolid();
+		sol -> TangentialSolid (p1, tansol, tansurfind, ideps*size);
+		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, EDGEPOINT);
+		mesh.AddPoint (p2, layer, EDGEPOINT);
+		seg1[0] = mesh.GetNP()-1;
+		seg1[1] = mesh.GetNP();
+		seg2[1] = mesh.GetNP()-1;
+		seg2[0] = 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/contrib/Netgen/libsrc/csg/edgeflw.hpp b/contrib/Netgen/libsrc/csg/edgeflw.hpp
new file mode 100644
index 0000000000..4c2fc9495a
--- /dev/null
+++ b/contrib/Netgen/libsrc/csg/edgeflw.hpp
@@ -0,0 +1,110 @@
+#ifndef FILE_EDGEFLW
+#define FILE_EDGEFLW
+
+/**************************************************************************/
+/* File:   edgeflw.hh                                                     */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   01. Okt. 95                                                    */
+/**************************************************************************/
+
+namespace netgen
+{
+
+
+
+  /*
+  
+  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;
+    Array<SpecialPoint> & specpoints;
+    Point3dTree * searchtree;
+    Point3dTree * meshpoint_tree;
+    int cntedge;
+
+    double ideps;
+
+  public:
+    EdgeCalculation (const CSGeometry & ageometry,
+		     Array<SpecialPoint> & aspecpoints);
+
+    ~EdgeCalculation();
+
+    void SetIdEps(const double epsin) {ideps = epsin;}
+
+    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,
+		     const Array<int> & hsp,
+		     double h, const Mesh & mesh,
+		     Array<Point<3> > & edgepoints,
+		     Array<double> & curvelength);
+		   
+
+    void AnalyzeEdge (int s1, int s2, int s1_rep, int s2_rep, int pos, int layer,
+		      const Array<Point<3> > & edgepoints,
+		      Array<Segment> & refedges,
+		      Array<bool> & refedgesinv);
+
+    void StoreEdge (const Array<Segment> & refedges,
+		    const Array<bool> & refedgesinv,
+		    const Array<Point<3> > & edgepoints,
+		    const Array<double> & curvelength,
+		    int layer,
+		    Mesh & mesh);
+
+    void StoreShortEdge (const Array<Segment> & refedges,
+			 const Array<bool> & refedgesinv,
+			 const Array<Point<3> > & edgepoints,
+			 const Array<double> & curvelength,
+			 int layer,
+			 Mesh & mesh);
+
+    void CopyEdge (const Array<Segment> & refedges,
+		   const Array<bool> & 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);
+
+
+  public:
+    bool point_on_edge_problem;
+
+  };
+
+}
+
+
+#endif
diff --git a/contrib/Netgen/libsrc/csg/explicitcurve2d.cpp b/contrib/Netgen/libsrc/csg/explicitcurve2d.cpp
new file mode 100644
index 0000000000..81c0e7ac55
--- /dev/null
+++ b/contrib/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(-1);
+  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/contrib/Netgen/libsrc/csg/explicitcurve2d.hpp b/contrib/Netgen/libsrc/csg/explicitcurve2d.hpp
new file mode 100644
index 0000000000..559030b254
--- /dev/null
+++ b/contrib/Netgen/libsrc/csg/explicitcurve2d.hpp
@@ -0,0 +1,113 @@
+#ifndef FILE_EXPLICITCURVE2D
+#define FILE_EXPLICITCURVE2D
+
+/**************************************************************************/
+/* File:   explicitcurve2d.hh                                             */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   14. Oct. 96                                                    */
+/**************************************************************************/
+
+
+namespace netgen
+{
+
+  /*
+
+  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/contrib/Netgen/libsrc/csg/extrusion.cpp b/contrib/Netgen/libsrc/csg/extrusion.cpp
new file mode 100644
index 0000000000..29676395f8
--- /dev/null
+++ b/contrib/Netgen/libsrc/csg/extrusion.cpp
@@ -0,0 +1,876 @@
+#include <mystdlib.h>
+
+#include <linalg.hpp>
+#include <csg.hpp>
+
+
+namespace netgen
+{
+
+  Array<Point<3> > project1, project2;
+
+
+
+  void ExtrusionFace :: Init(void)
+  {
+    p0.SetSize(path->GetNSplines());
+    x_dir.SetSize(path->GetNSplines());
+    y_dir.SetSize(path->GetNSplines());
+    z_dir.SetSize(path->GetNSplines());
+    loc_z_dir.SetSize(path->GetNSplines());
+    spline3_path.SetSize(path->GetNSplines());
+    line_path.SetSize(path->GetNSplines());
+
+    for(int i=0; i<path->GetNSplines(); i++)
+      {
+	spline3_path[i] = dynamic_cast < const SplineSeg3<3>* >(&path->GetSpline(i));
+	line_path[i] = dynamic_cast < const LineSeg<3>* >(&path->GetSpline(i));
+	
+	if(line_path[i])
+	  {
+	    y_dir[i] = line_path[i]->EndPI() - line_path[i]->StartPI();
+	    y_dir[i].Normalize();
+	    z_dir[i] = glob_z_direction;
+	    Orthogonalize(y_dir[i],z_dir[i]);
+	    x_dir[i] = Cross(y_dir[i],z_dir[i]);
+	    loc_z_dir[i] = z_dir[i];
+	  }
+	else
+	  {
+	    z_dir[i] = glob_z_direction;
+	    loc_z_dir[i] = glob_z_direction;
+	  }
+      }
+    
+    profile->GetCoeff(profile_spline_coeff);
+    latest_point3d = -1.111e30;
+  }
+
+  
+  ExtrusionFace :: ExtrusionFace(const SplineSeg<2> * profile_in,
+				 const SplineGeometry<3> * path_in,
+				 const Vec<3> & z_direction) :
+    profile(profile_in), path(path_in), glob_z_direction(z_direction)
+  {
+    deletable = false;
+
+    Init();
+  }
+
+  ExtrusionFace :: ExtrusionFace(const Array<double> & raw_data)
+  {
+    deletable = true;
+
+    int pos=0;
+
+    Array< Point<2> > p(3);
+
+    int ptype = int(raw_data[pos]); pos++;
+
+    for(int i=0; i<ptype; i++)
+      {
+	p[i](0) = raw_data[pos]; pos++;
+	p[i](1) = raw_data[pos]; pos++;
+      }
+    if(ptype == 2)
+      {
+	profile = new LineSeg<2>(GeomPoint<2>(p[0],1),
+				 GeomPoint<2>(p[1],1));
+      }
+    else if(ptype == 3)
+      {
+	profile = new SplineSeg3<2>(GeomPoint<2>(p[0],1),
+				    GeomPoint<2>(p[1],1),
+				    GeomPoint<2>(p[2],1));
+      }
+
+    path = new SplineGeometry<3>;
+    pos = const_cast< SplineGeometry<3> *>(path)->Load(raw_data,pos);
+
+    for(int i = 0; i < 3; i++)
+      {
+	glob_z_direction(i) = raw_data[pos]; 
+	pos++;
+      }
+    
+    Init();
+  }
+
+  ExtrusionFace :: ~ExtrusionFace()
+  {
+    if(deletable)
+      {
+	delete profile;
+	delete path;
+      }
+  }
+
+  
+  int ExtrusionFace :: IsIdentic (const Surface & s2, int & inv, double eps) const
+  {
+    const ExtrusionFace * ext2 = dynamic_cast<const ExtrusionFace*>(&s2);
+
+    if(!ext2) return 0;
+
+    if(ext2 == this)
+      return 1;
+
+    return 0;
+  } 
+  
+  void ExtrusionFace :: Orthogonalize(const Vec<3> & v1, Vec<3> & v2) const
+  {
+    v2 -= (v1*v2)*v1;
+    v2.Normalize();
+  }
+
+
+  void ExtrusionFace :: CalcProj(const Point<3> & point3d, Point<2> & point2d,
+				 int & seg, double & t) const
+  {
+    if (Dist2 (point3d, latest_point3d) < 
+        1e-25 * Dist2(path->GetSpline(0).StartPI(), path->GetSpline(0).EndPI()))
+      {
+	point2d = latest_point2d;
+	seg = latest_seg;
+	t = latest_t;
+	return;
+      }
+    
+    latest_point3d = point3d;
+
+    double cutdist = -1;
+    
+
+    Array<double> mindist(path->GetNSplines());
+
+    for(int i = 0; i < path->GetNSplines(); i++)
+      {
+	double auxcut = -1;
+	double auxmin = -1;
+
+	if(spline3_path[i])
+	  {
+	    Point<3> startp(path->GetSpline(i).StartPI());
+	    Point<3> endp(path->GetSpline(i).EndPI());
+	    Point<3> tanp(spline3_path[i]->TangentPoint());
+            
+            // lower bound for dist
+            auxmin = sqrt (MinDistTP2 (startp, endp, tanp, point3d)); 
+            
+            // upper bound for dist
+            auxcut = min2 (Dist (startp, point3d), Dist (endp, point3d));
+	  }
+	else if(line_path[i])
+	  {
+            auxmin = auxcut = sqrt (MinDistLP2 (path->GetSpline(i).StartPI(),
+                                                path->GetSpline(i).EndPI(),
+                                                point3d));
+	  }
+	
+	mindist[i] = auxmin;
+	
+	if(i==0 || auxcut < cutdist)
+	  cutdist = auxcut;
+      }
+	
+
+
+    Point<2> testpoint2d;
+    Point<3> testpoint3d;
+    
+    double minproj(-1);
+    bool minproj_set(false);
+
+
+
+    for(int i=0; i<path->GetNSplines(); i++)
+      {
+	if(mindist[i] > cutdist) continue;
+
+	double thist = CalcProj(point3d,testpoint2d,i);
+
+	testpoint3d = p0[i] + testpoint2d(0)*x_dir[i] + testpoint2d(1)*loc_z_dir[i];
+	double d = Dist2(point3d,testpoint3d);
+
+
+	if(!minproj_set || d < minproj)
+	  {
+	    minproj_set = true;
+	    minproj = d;
+	    point2d = testpoint2d;
+	    t = thist;
+	    seg = i;
+	    latest_seg = i;
+	    latest_t = t;
+	    latest_point2d = point2d;
+	  }
+      }
+  }
+
+  double ExtrusionFace :: CalcProj(const Point<3> & point3d, Point<2> & point2d,
+				   int seg) const
+  {
+    double t = -1;
+
+    if(line_path[seg])
+      {
+	point2d(0) = (point3d-line_path[seg]->StartPI())*x_dir[seg];
+	point2d(1) = (point3d-line_path[seg]->StartPI())*z_dir[seg];
+	double l = Dist(line_path[seg]->StartPI(),
+			line_path[seg]->EndPI());
+	t = min2(max2((point3d - line_path[seg]->StartPI()) * y_dir[seg],0.),
+		 l);	
+	p0[seg] = line_path[seg]->StartPI() + t*y_dir[seg];
+	t *= 1./l;
+      }
+    else if(spline3_path[seg])
+      {
+	spline3_path[seg]->Project(point3d,p0[seg],t);
+	
+	y_dir[seg] = spline3_path[seg]->GetTangent(t); 
+        y_dir[seg].Normalize();
+	loc_z_dir[seg] = z_dir[seg];
+	Orthogonalize(y_dir[seg],loc_z_dir[seg]);
+	x_dir[seg] = Cross(y_dir[seg],loc_z_dir[seg]);
+	Vec<3> dir = point3d-p0[seg];
+	point2d(0) = x_dir[seg]*dir;
+	point2d(1) = loc_z_dir[seg]*dir;	
+      }
+    return t;
+  }
+
+
+
+  double ExtrusionFace :: CalcFunctionValue (const Point<3> & point) const
+  {
+    Point<2> p;
+
+    double dummyd;
+    int dummyi;
+
+    CalcProj(point, p, dummyi, dummyd);
+
+    return 
+      profile_spline_coeff(0)*p(0)*p(0) + 
+      profile_spline_coeff(1)*p(1)*p(1) + 
+      profile_spline_coeff(2)*p(0)*p(1) + 
+      profile_spline_coeff(3)*p(0) + 
+      profile_spline_coeff(4)*p(1) + 
+      profile_spline_coeff(5);    
+  }
+
+
+
+
+  void ExtrusionFace :: CalcGradient (const Point<3> & point, Vec<3> & grad) const
+  {
+    Point<2> p2d;
+
+    double t_path;
+    int seg;
+    CalcProj (point, p2d, seg, t_path);
+
+
+    Point<3> phi;
+    Vec<3> phip, phipp, phi_minus_point;
+
+    path->GetSpline(seg).GetDerivatives(t_path, phi, phip, phipp);
+    phi_minus_point = phi-point;
+
+    Vec<3> grad_t = (1.0/(phipp*phi_minus_point + phip*phip)) * phip;
+    Vec<3> grad_xbar, grad_ybar;
+
+    Vec<3> hex, hey, hez, dex, dey, dez;
+    CalcLocalCoordinatesDeriv (seg, t_path, hex, hey, hez, dex, dey, dez);
+
+    grad_xbar = hex - (phi_minus_point*dex + hex*phip) * grad_t;
+    grad_ybar = hez - (phi_minus_point*dez + hez*phip) * grad_t;
+
+    double dFdxbar = 2.*profile_spline_coeff(0)*p2d(0) +
+      profile_spline_coeff(2)*p2d(1) + profile_spline_coeff(3);
+
+    double dFdybar = 2.*profile_spline_coeff(1)*p2d(1) +
+      profile_spline_coeff(2)*p2d(0) + profile_spline_coeff(4);
+    
+
+    grad = dFdxbar * grad_xbar + dFdybar * grad_ybar;    
+  }
+
+  void ExtrusionFace :: CalcHesse (const Point<3> & point, Mat<3> & hesse) const
+  {
+    const double eps = 1e-7*Dist(path->GetSpline(0).StartPI(),path->GetSpline(0).EndPI());
+    
+
+    Point<3> auxpoint1(point),auxpoint2(point);
+    Vec<3> auxvec,auxgrad1,auxgrad2;
+
+    for(int i=0; i<3; i++)
+      {
+	auxpoint1(i) -= eps;
+	auxpoint2(i) += eps;
+	CalcGradient(auxpoint1,auxgrad1);
+	CalcGradient(auxpoint2,auxgrad2);
+	auxvec = (1./(2.*eps)) * (auxgrad2-auxgrad1);
+	for(int j=0; j<3; j++)
+	  hesse(i,j) = auxvec(j);
+	auxpoint1(i) = point(i);
+	auxpoint2(i) = point(i);
+      }
+
+    /*
+    Vec<3> grad;
+    CalcGradient(point,grad);
+
+    Point<3> auxpoint(point);
+    Vec<3> auxvec,auxgrad;
+
+    for(int i=0; i<3; i++)
+      {
+	auxpoint(i) -= eps;
+	CalcGradient(auxpoint,auxgrad);
+	auxvec = (1./eps) * (grad-auxgrad);
+	for(int j=0; j<3; j++)
+	  hesse(i,j) = auxvec(j);
+	auxpoint(i) = point(i);
+      }
+    */
+
+    
+    for(int i=0; i<3; i++)
+      for(int j=i+1; j<3; j++)
+	hesse(i,j) = hesse(j,i) = 0.5*(hesse(i,j)+hesse(j,i));
+  }
+  
+
+
+  double ExtrusionFace :: HesseNorm () const
+  {
+    return fabs(profile_spline_coeff(0) + profile_spline_coeff(1)) +
+      sqrt(pow(profile_spline_coeff(0)+profile_spline_coeff(1),2)+4.*pow(profile_spline_coeff(2),2));
+  }
+
+  double ExtrusionFace :: MaxCurvature () const
+  {
+    double retval,actmax;
+    
+    retval = profile->MaxCurvature();
+    for(int i=0; i<path->GetNSplines(); i++)
+      {
+	actmax = path->GetSpline(i).MaxCurvature();
+	if(actmax > retval)
+	  retval = actmax;
+      }
+
+    return 2.*retval;
+  }
+
+
+  void ExtrusionFace :: Project (Point<3> & p) const
+  {
+    double dummyt;
+    int seg;
+    Point<2> p2d;
+
+    CalcProj(p,p2d,seg,dummyt);
+
+    profile->Project(p2d,p2d,profile_par);
+    
+    p = p0[seg] + p2d(0)*x_dir[seg] + p2d(1)*loc_z_dir[seg];
+
+    Vec<2> tangent2d = profile->GetTangent(profile_par);
+    profile_tangent = tangent2d(0)*x_dir[seg] + tangent2d(1)*y_dir[seg];
+  }
+
+
+  
+  Point<3> ExtrusionFace :: GetSurfacePoint () const
+  {
+    p0[0] = path->GetSpline(0).GetPoint(0.5);
+    if(!line_path[0])
+      {
+	y_dir[0] = path->GetSpline(0).GetTangent(0.5);
+	y_dir[0].Normalize();
+	loc_z_dir[0] = z_dir[0];
+	Orthogonalize(y_dir[0],loc_z_dir[0]);
+	x_dir[0] = Cross(y_dir[0],loc_z_dir[0]);
+      }
+
+    Point<2> locpoint = profile->GetPoint(0.5);
+
+    return p0[0] + locpoint(0)*x_dir[0] + locpoint(1)*loc_z_dir[0];
+  }
+  
+
+  bool ExtrusionFace :: BoxIntersectsFace(const Box<3> & box) const
+  {
+    Point<3> center = box.Center();
+
+    Project(center);
+
+    //(*testout) << "box.Center() " << box.Center() << " projected " << center << " diam " << box.Diam() 
+    //       << " dist " << Dist(box.Center(),center) << endl;
+
+    return (Dist(box.Center(),center) < 0.5*box.Diam());
+  }
+
+
+  void ExtrusionFace :: LineIntersections ( const Point<3> & p,
+					    const Vec<3> & v,
+					    const double eps,
+					    int & before,
+					    int & after,
+					    bool & intersecting ) const
+  {
+    Point<2> p2d;
+    Vec<2> v2d;
+
+    intersecting = false;
+
+    double segt;
+    int seg;
+
+    CalcProj(p,p2d,seg,segt);
+
+    if(seg == 0 && segt < 1e-20)
+      {
+	Vec<3> v1,v2;
+	v1 = path->GetSpline(0).GetTangent(0);
+	v2 = p-p0[seg];
+	if(v1*v2 < -eps)
+	  return;
+      }
+    if(seg == path->GetNSplines()-1 && 1.-segt < 1e-20)
+      {
+	Vec<3> v1,v2;
+	v1 = path->GetSpline(seg).GetTangent(1);
+	v2 = p-p0[seg];
+	if(v1*v2 > eps)
+	  return;
+      }
+
+    v2d(0) = v * x_dir[seg];
+    v2d(1) = v * loc_z_dir[seg];
+    
+    Vec<2> n(v2d(1),-v2d(0));
+    Array < Point<2> > ips;
+
+
+    profile->LineIntersections(v2d(1),
+			      -v2d(0),
+			      -v2d(1)*p2d(0) + v2d(0)*p2d(1),
+			      ips,eps);
+    int comp;
+
+    if(fabs(v2d(0)) >= fabs(v2d(1)))
+      comp = 0;
+    else
+      comp = 1;
+
+    //(*testout) << "p2d " << p2d;
+
+    for(int i=0; i<ips.Size(); i++)
+      {
+	//(*testout) << " ip " << ips[i];
+
+	double t = (ips[i](comp)-p2d(comp))/v2d(comp);
+
+	if(t < -eps)
+	  before++;
+	else if(t > eps)
+	  after++;
+	else
+	  intersecting = true;
+      }
+    //(*testout) << endl;
+  }
+
+  void ExtrusionFace :: Print (ostream & str) const{}
+
+  INSOLID_TYPE ExtrusionFace :: VecInFace ( const Point<3> & p,
+					    const Vec<3> & v,
+					    const double eps ) const
+  {
+    
+    Vec<3> normal1;
+    CalcGradient(p,normal1); normal1.Normalize();
+
+    double d1 = normal1*v;
+
+
+    if(d1 > eps)
+      return IS_OUTSIDE;
+    if(d1 < -eps)
+      return IS_INSIDE;
+    
+
+    return DOES_INTERSECT;
+
+    /*
+    Point<2> p2d;
+
+    double t_path;
+    int seg;
+    CalcProj(p,p2d,seg,t_path);
+
+    double t;
+    profile.Project(p2d,p2d,t);
+
+
+    
+    Vec<2> profile_tangent = profile.GetTangent(t);
+
+    double d;
+
+    Vec<3> normal1;
+    CalcGradient(p,normal1); normal1.Normalize();
+
+    double d1 = normal1*v;
+
+    Vec<2> v2d;
+
+    v2d(0) = v*x_dir[seg];
+    v2d(1) = v*loc_z_dir[seg];
+
+			    	    
+    Vec<2> normal(-profile_tangent(1),profile_tangent(0));
+    
+    //d = normal*v2d;
+    
+
+    d = d1;
+
+
+    if(d > eps)
+      return IS_OUTSIDE;
+    if(d < -eps)
+      return IS_INSIDE;
+    
+
+    return DOES_INTERSECT;
+    */
+  }
+
+
+  void ExtrusionFace :: GetTriangleApproximation (TriangleApproximation & tas, 
+						  const Box<3> & boundingbox, 
+						  double facets) const
+  {
+    int n = int(facets) + 1;
+
+    for(int k = 0; k < path -> GetNSplines(); k++)
+      {
+	for(int i = 0; i <= n; i++)
+	  {
+	    Point<3> origin = path -> GetSpline(k).GetPoint(double(i)/double(n));
+	    if(!line_path[k])
+	      {
+		y_dir[k] = path->GetSpline(k).GetTangent(double(i)/double(n));
+		y_dir[k].Normalize();
+	      }
+	    loc_z_dir[k] = z_dir[k];
+	    Orthogonalize(y_dir[k],loc_z_dir[k]);
+	    if(!line_path[k])
+	      x_dir[k] = Cross(y_dir[k],loc_z_dir[k]);
+	    
+	    for(int j = 0; j <= n; j++)
+	      {
+		Point<2> locp = profile->GetPoint(double(j)/double(n));
+		tas.AddPoint(origin + locp(0)*x_dir[k] + locp(1)*loc_z_dir[k]);
+	      }
+	  }
+      }
+    
+    for(int k = 0; k < path->GetNSplines(); k++)
+      for(int i = 0; i < n; i++)
+	for(int j = 0; j < n; j++)
+	  {
+	    int pi = k*(n+1)*(n+1) + (n+1)*i +j;
+	  
+	    tas.AddTriangle( TATriangle (0, pi,pi+1,pi+n+1) );
+	    tas.AddTriangle( TATriangle (0, pi+1,pi+n+1,pi+n+2) );
+	  }
+  }
+  
+
+  void ExtrusionFace :: GetRawData(Array<double> & data) const
+  {
+    data.DeleteAll();
+    profile->GetRawData(data);
+    path->GetRawData(data);
+    for(int i=0; i<3; i++)
+      data.Append(glob_z_direction[i]);
+  }
+
+
+  void ExtrusionFace :: 
+  CalcLocalCoordinates (int seg, double t, 
+                        Vec<3> & ex, Vec<3> & ey, Vec<3> & ez) const
+  {
+    ey = path->GetSpline(seg).GetTangent(t); 
+    ey /= ey.Length();
+    ex = Cross (ey, glob_z_direction);
+    ex /= ex.Length();
+    ez = Cross (ex, ey);
+  }
+
+  void ExtrusionFace :: 
+  CalcLocalCoordinatesDeriv (int seg, double t, 
+                             Vec<3> & ex, Vec<3> & ey, Vec<3> & ez,
+                             Vec<3> & dex, Vec<3> & dey, Vec<3> & dez) const
+  {
+    Point<3> point;
+    Vec<3> first, second;
+    path->GetSpline(seg).GetDerivatives (t, point, first, second);
+
+    ey = first;
+    ex = Cross (ey, glob_z_direction);
+    ez = Cross (ex, ey);
+    
+    dey = second;
+    dex = Cross (dey, glob_z_direction);
+    dez = Cross (dex, ey) + Cross (ex, dey);
+    
+    double lenx = ex.Length();
+    double leny = ey.Length();
+    double lenz = ez.Length();
+
+    ex /= lenx;
+    ey /= leny;
+    ez /= lenz;
+    
+    dex /= lenx;
+    dex -= (dex * ex) * ex;
+
+    dey /= leny;
+    dey -= (dey * ey) * ey;
+
+    dez /= lenz;
+    dez -= (dez * ez) * ez;
+  }
+  
+
+  Extrusion :: Extrusion(const SplineGeometry<3> & path_in,
+			 const SplineGeometry<2> & profile_in,
+			 const Vec<3> & z_dir) :
+    path(path_in), profile(profile_in), z_direction(z_dir)
+  {
+    surfaceactive.SetSize(0);
+    surfaceids.SetSize(0);
+
+    for(int j=0; j<profile.GetNSplines(); j++)
+      {
+	ExtrusionFace * face = new ExtrusionFace(&(profile.GetSpline(j)),
+						 &path,
+						 z_direction);
+	faces.Append(face);
+	surfaceactive.Append(true);
+	surfaceids.Append(0);
+      }
+
+  }
+
+
+  Extrusion :: ~Extrusion()
+  {
+    for(int i=0; i<faces.Size(); i++)
+      delete faces[i];
+  }
+
+
+
+
+
+  INSOLID_TYPE Extrusion :: BoxInSolid (const BoxSphere<3> & box) const
+  {
+    for(int i=0; i<faces.Size(); i++)
+      {
+	if(faces[i]->BoxIntersectsFace(box))
+	  return DOES_INTERSECT;
+      }
+
+    return PointInSolid(box.Center(),0);
+  }
+
+
+  INSOLID_TYPE Extrusion :: PointInSolid (const Point<3> & p,
+					  const double eps,
+					  Array<int> * const facenums) const
+  {
+    Vec<3> random_vec(-0.4561,0.7382,0.4970247);
+
+    int before(0), after(0);
+    bool intersects(false);
+    bool does_intersect(false);
+
+    for(int i=0; i<faces.Size(); i++)
+      {
+	faces[i]->LineIntersections(p,random_vec,eps,before,after,intersects);
+
+	//(*testout) << "intersects " << intersects << " before " << before << " after " << after << endl;
+	if(intersects)
+	  {
+	    if(facenums)
+	      {
+		facenums->Append(i);
+		does_intersect = true;
+	      }
+	    else
+	      return DOES_INTERSECT;
+	  }
+      }
+
+    if(does_intersect)
+      return DOES_INTERSECT;
+
+
+    if(before % 2 == 0)
+      return IS_OUTSIDE;
+
+    return IS_INSIDE;
+  }
+
+
+  INSOLID_TYPE Extrusion :: PointInSolid (const Point<3> & p,
+					  double eps) const
+  {
+    return PointInSolid(p,eps,NULL);    
+  }
+
+  INSOLID_TYPE Extrusion :: VecInSolid (const Point<3> & p,
+					const Vec<3> & v,
+					double eps) const
+  {
+    Array<int> facenums;
+    INSOLID_TYPE pInSolid = PointInSolid(p,eps,&facenums);
+
+    if(pInSolid != DOES_INTERSECT)
+      return pInSolid;
+
+
+    double d(0);
+
+    if(facenums.Size() == 1)
+      {
+	Vec<3> normal;
+	faces[facenums[0]]->CalcGradient(p,normal);
+	normal.Normalize();
+	d = normal*v;
+	
+	latestfacenum = facenums[0];
+      }
+    else if (facenums.Size() == 2)
+      {
+	Vec<3> checkvec;
+
+	Point<3> dummy(p);
+	faces[facenums[0]]->Project(dummy);
+	if(fabs(faces[facenums[0]]->GetProfilePar()) < 0.1)
+	  {
+	    int aux = facenums[0];
+	    facenums[0] = facenums[1]; facenums[1] = aux;
+	  }
+	
+	checkvec = faces[facenums[0]]->GetYDir();
+     
+	Vec<3> n0, n1;
+	faces[facenums[0]]->CalcGradient(p,n0);
+	faces[facenums[1]]->CalcGradient(p,n1);
+	n0.Normalize();
+	n1.Normalize();
+	
+
+	Vec<3> t = Cross(n0,n1);
+	if(checkvec*t < 0) t*= (-1.);
+	
+	Vec<3> t0 = Cross(n0,t);
+	Vec<3> t1 = Cross(t,n1);
+	
+	t0.Normalize();
+	t1.Normalize();
+	
+
+	const double t0v = t0*v;
+	const double t1v = t1*v;
+
+	if(t0v > t1v)
+	  {
+	    latestfacenum = facenums[0];
+	    d = n0*v;
+	  }
+	else
+	  {
+	    latestfacenum = facenums[1];
+	    d = n1*v;
+	  }
+
+	if(fabs(t0v) < eps && fabs(t1v) < eps)
+	  latestfacenum = -1;
+      }
+
+    else
+      {
+	cerr << "WHY ARE THERE " << facenums.Size() << " FACES?" << endl;
+      }
+
+    if(d > eps)
+      return IS_OUTSIDE;
+    if(d < -eps)
+      return IS_INSIDE;
+      
+    return DOES_INTERSECT;
+  }
+
+
+
+  // checks if lim s->0 lim t->0  p + t(v1 + s v2) in solid
+  INSOLID_TYPE Extrusion :: VecInSolid2 (const Point<3> & p,
+					 const Vec<3> & v1,
+					 const Vec<3> & v2,
+					 double eps) const
+  {
+    INSOLID_TYPE retval;
+    retval = VecInSolid(p,v1,eps);
+
+    // *testout << "extr, vecinsolid=" << int(retval) << endl;
+
+    if(retval != DOES_INTERSECT)
+      return retval;
+
+    if(latestfacenum >= 0)
+      return faces[latestfacenum]->VecInFace(p,v2,0);
+    else
+      return VecInSolid(p,v2,eps);
+  }
+
+  
+  int Extrusion :: GetNSurfaces() const
+  {
+    return faces.Size();
+  }
+
+  Surface & Extrusion :: GetSurface (int i)
+  {
+    return *faces[i];
+  }
+
+  const Surface & Extrusion :: GetSurface (int i) const
+  {
+    return *faces[i];
+  }
+
+
+  void Extrusion :: Reduce (const BoxSphere<3> & box)
+  {
+    for(int i = 0; i < faces.Size(); i++)
+      surfaceactive[i] = faces[i]->BoxIntersectsFace(box);
+  }
+
+  void Extrusion :: UnReduce ()
+  {
+    for(int i = 0; i < faces.Size(); i++)
+      surfaceactive[i] = true;
+  }
+
+
+}
diff --git a/contrib/Netgen/libsrc/csg/extrusion.hpp b/contrib/Netgen/libsrc/csg/extrusion.hpp
new file mode 100644
index 0000000000..189639bd2e
--- /dev/null
+++ b/contrib/Netgen/libsrc/csg/extrusion.hpp
@@ -0,0 +1,155 @@
+#ifndef _EXTRUSION_HPP
+#define _EXTRUSION_HPP
+
+namespace netgen
+{
+
+  class Extrusion;
+
+  class ExtrusionFace : public Surface
+  {
+  private:
+    const SplineSeg<2> * profile;
+    const SplineGeometry<3> * path;
+    Vec<3> glob_z_direction;
+
+    bool deletable;
+  
+    Array< const SplineSeg3<3> * > spline3_path;
+    Array< const LineSeg<3> * > line_path;
+  
+    mutable Array < Vec<3> > x_dir, y_dir, z_dir, loc_z_dir;
+    mutable Array < Point<3> > p0;
+
+    mutable Vec<3> profile_tangent;
+    mutable double profile_par;
+  
+    mutable Vector profile_spline_coeff;
+
+    mutable int latest_seg;
+    mutable double latest_t;
+    mutable Point<2> latest_point2d;
+    mutable Point<3> latest_point3d;
+
+
+  private:
+    void Orthogonalize(const Vec<3> & v1, Vec<3> & v2) const;
+
+    void Init(void);
+
+  public:
+    double CalcProj(const Point<3> & point3d, Point<2> & point2d,
+		    int seg) const;
+    void CalcProj(const Point<3> & point3d, Point<2> & point2d,
+		  int & seg, double & t) const;
+
+  public:
+    ExtrusionFace(const SplineSeg<2> * profile_in,
+		  const SplineGeometry<3> * path_in,
+		  const Vec<3> & z_direction);
+
+    ExtrusionFace(const Array<double> & raw_data);
+    
+
+    ~ExtrusionFace();
+  
+    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 double MaxCurvature () const;
+    //virtual double MaxCurvatureLoc (const Point<3> & /* c */ , 
+    //				  double /* rad */) const;
+
+    virtual void Project (Point<3> & p) const;
+
+    virtual Point<3> GetSurfacePoint () const;
+    virtual void Print (ostream & str) const;
+  
+    virtual void GetTriangleApproximation (TriangleApproximation & tas, 
+					   const Box<3> & boundingbox, 
+					   double facets) const;
+
+    const SplineGeometry<3> & GetPath(void) const {return *path;}
+    const SplineSeg<2> & GetProfile(void) const {return *profile;}
+
+    bool BoxIntersectsFace(const Box<3> & box) const;
+
+    void LineIntersections ( const Point<3> & p,
+			     const Vec<3> & v,
+			     const double eps,
+			     int & before,
+			     int & after,
+			     bool & intersecting ) const;
+
+    INSOLID_TYPE VecInFace ( const Point<3> & p,
+			     const Vec<3> & v,
+			     const double eps ) const;
+
+    const Vec<3> & GetYDir ( void ) const {return y_dir[latest_seg];}
+    const Vec<3> & GetProfileTangent (void) const {return profile_tangent;}
+    double GetProfilePar(void) const {return profile_par;}
+
+    void GetRawData(Array<double> & data) const;
+
+    void CalcLocalCoordinates (int seg, double t, 
+			       Vec<3> & ex, Vec<3> & ey, Vec<3> & ez) const;
+
+    void CalcLocalCoordinatesDeriv (int seg, double t, 
+				    Vec<3> & ex, Vec<3> & ey, Vec<3> & ez,
+				    Vec<3> & dex, Vec<3> & dey, Vec<3> & dez) const;
+
+  };
+
+
+
+  class Extrusion : public Primitive
+  {
+  private:
+    const SplineGeometry<3> & path;
+    const SplineGeometry<2> & profile;
+
+    const Vec<3> & z_direction;
+
+    Array<ExtrusionFace*> faces;
+
+    mutable int latestfacenum;
+
+  public:
+    Extrusion(const SplineGeometry<3> & path_in,
+	      const SplineGeometry<2> & profile_in,
+	      const Vec<3> & z_dir);
+    ~Extrusion();
+    virtual INSOLID_TYPE BoxInSolid (const BoxSphere<3> & box) const;
+    virtual INSOLID_TYPE PointInSolid (const Point<3> & p,
+				       double eps) const;
+    INSOLID_TYPE PointInSolid (const Point<3> & p,
+			       double eps,
+			       Array<int> * const facenums) const;
+    virtual INSOLID_TYPE VecInSolid (const Point<3> & p,
+				     const Vec<3> & v,
+				     double eps) const;
+
+    // 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;
+    virtual Surface & GetSurface (int i = 0);
+    virtual const Surface & GetSurface (int i = 0) const;
+
+
+    virtual void Reduce (const BoxSphere<3> & box);
+    virtual void UnReduce ();
+
+  };
+
+}
+
+#endif //_EXTRUSION_HPP
diff --git a/contrib/Netgen/libsrc/csg/gencyl.cpp b/contrib/Netgen/libsrc/csg/gencyl.cpp
new file mode 100644
index 0000000000..1305c1b87b
--- /dev/null
+++ b/contrib/Netgen/libsrc/csg/gencyl.cpp
@@ -0,0 +1,179 @@
+#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(0, 0) = (1 - curvpp(0) * curvpp(0) ) / dist;  
+    h2d(0, 1) = h2d(1, 0) = (- curvpp(0) * curvpp(1) ) / dist;  
+    h2d(1, 1) = (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);
+  }
+  
+}
diff --git a/contrib/Netgen/libsrc/csg/gencyl.hpp b/contrib/Netgen/libsrc/csg/gencyl.hpp
new file mode 100644
index 0000000000..e5db270dec
--- /dev/null
+++ b/contrib/Netgen/libsrc/csg/gencyl.hpp
@@ -0,0 +1,70 @@
+#ifndef FILE_GENCYL
+#define FILE_GENCYL
+
+/**************************************************************************/
+/* File:   gencyl.hh                                                      */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   14. Oct. 96                                                    */
+/**************************************************************************/
+
+namespace netgen
+{
+
+
+  /*
+  
+  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/contrib/Netgen/libsrc/csg/genmesh.cpp b/contrib/Netgen/libsrc/csg/genmesh.cpp
new file mode 100644
index 0000000000..5e891639b8
--- /dev/null
+++ b/contrib/Netgen/libsrc/csg/genmesh.cpp
@@ -0,0 +1,849 @@
+#include <mystdlib.h>
+
+
+#include <myadt.hpp>
+
+#include <linalg.hpp>
+#include <csg.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)
+  {
+    PrintMessage (1, "Start Findpoints");
+
+    const char * savetask = multithread.task;
+    multithread.task = "Find points";
+
+    for (int i = 0; i < geom.GetNUserPoints(); i++)
+      {
+	mesh.AddPoint(geom.GetUserPoint (i));
+	mesh.Points().Last().Singularity (geom.GetUserPointRefFactor(i));
+	mesh.AddLockedPoint (PointIndex (i+1));
+      }
+
+    SpecialPointCalculation spc;
+
+    spc.SetIdEps(geom.GetIdEps());
+
+    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 (int i = 0; i < specpoints.Size(); i++)
+      specpoints[i].Print (*testout);
+
+    /*
+      for (int i = 1; i <= geom.identifications.Size(); i++)
+      geom.identifications.Elem(i)->IdentifySpecialPoints (specpoints);
+    */
+    multithread.task = savetask;
+  }
+
+
+
+
+
+
+  static void FindEdges (CSGeometry & geom, Mesh & mesh, const bool setmeshsize = false)
+  {
+    EdgeCalculation ec (geom, specpoints);
+    ec.SetIdEps(geom.GetIdEps());
+    ec.Calc (mparam.maxh, mesh);
+
+    for (int i = 0; i < geom.singedges.Size(); i++)
+      {
+	geom.singedges[i]->FindPointsOnEdge (mesh);
+	if(setmeshsize)
+	  geom.singedges[i]->SetMeshSize(mesh,10.*geom.BoundingBox().Diam());
+      }
+    for (int i = 0; i < geom.singpoints.Size(); i++)
+      geom.singpoints[i]->FindPoints (mesh);
+
+    for (int i = 1; i <= mesh.GetNSeg(); i++)
+      {
+	//(*testout) << "segment " << mesh.LineSegment(i) << endl;
+	int ok = 0;
+	for (int k = 1; k <= mesh.GetNFD(); k++)
+	  if (mesh.GetFaceDescriptor(k).SegmentFits (mesh.LineSegment(i)))
+	    {
+	      ok = k;
+	      //(*testout) << "fits to " << k << endl;
+	    }
+
+	if (!ok)
+	  {
+	    ok = mesh.AddFaceDescriptor (FaceDescriptor (mesh.LineSegment(i)));
+	    //(*testout) << "did not find, now " << ok << endl;
+	  }
+
+	//(*testout) << "change from " << mesh.LineSegment(i).si;
+	mesh.LineSegment(i).si = ok;
+	//(*testout) << " to " << mesh.LineSegment(i).si << endl;
+      }
+
+    if (geom.identifications.Size())
+      {
+	PrintMessage (3, "Find Identifications");
+	for (int i = 0; i < geom.identifications.Size(); i++)
+	  {
+	    geom.identifications[i]->IdentifyPoints (mesh);
+	    //(*testout) << "identification " << i << " is " 
+	    //	       << *geom.identifications[i] << endl;
+	    
+	  }
+	for (int i = 0; i < geom.identifications.Size(); i++)
+	  geom.identifications[i]->IdentifyFaces (mesh);
+      }
+
+
+    // find intersecting segments
+    PrintMessage (3, "Check intersecting edges");
+    
+    Point3d pmin, pmax;
+    mesh.GetBox (pmin, pmax);
+    Box3dTree segtree (pmin, pmax);
+    
+    for (SegmentIndex si = 0; si < mesh.GetNSeg(); si++)
+      {
+	if (mesh[si].seginfo)
+	  {
+	    Box<3> hbox;
+	    hbox.Set (mesh[mesh[si][0]]);
+	    hbox.Add (mesh[mesh[si][1]]);
+	    segtree.Insert (hbox.PMin(), hbox.PMax(), si);
+	  }
+      }
+
+    Array<int> loc;
+    if (!ec.point_on_edge_problem)
+      for (SegmentIndex si = 0; si < mesh.GetNSeg(); si++)
+	{
+	  if (!mesh[si].seginfo) continue;
+
+	  Box<3> hbox;
+	  hbox.Set (mesh[mesh[si][0]]);
+	  hbox.Add (mesh[mesh[si][1]]);
+	  hbox.Increase (1e-6);
+	  segtree.GetIntersecting (hbox.PMin(), hbox.PMax(), loc);
+	  	  
+	  // for (SegmentIndex sj = 0; sj < si; sj++)
+	  for (int j = 0; j < loc.Size(); j++)
+	    {
+	      SegmentIndex sj = loc[j];
+	      if (sj >= si) continue;
+	      if (!mesh[si].seginfo || !mesh[sj].seginfo) continue;
+	      if (mesh[mesh[si][0]].GetLayer() != mesh[mesh[sj][1]].GetLayer()) continue;
+	      
+	      Point<3> pi1 = mesh[mesh[si][0]];
+	      Point<3> pi2 = mesh[mesh[si][1]];
+	      Point<3> pj1 = mesh[mesh[sj][0]];
+	      Point<3> pj2 = mesh[mesh[sj][1]];
+	      Vec<3> vi = pi2 - pi1;
+	      Vec<3> vj = pj2 - pj1;
+	      
+	      if (sqr (vi * vj) > (1.-1e-6) * Abs2 (vi) * Abs2 (vj)) continue;
+	      
+	      // pi1 + vi t = pj1 + vj s
+	      Mat<3,2> mat;
+	      Vec<3> rhs;
+	      Vec<2> sol;
+	      
+	      for (int jj = 0; jj < 3; jj++)
+		{ 
+		  mat(jj,0) = vi(jj); 
+		  mat(jj,1) = -vj(jj); 
+		  rhs(jj) = pj1(jj)-pi1(jj); 
+		}
+	      
+	      mat.Solve (rhs, sol);
+
+	      //(*testout) << "mat " << mat << endl << "rhs " << rhs << endl << "sol " << sol << endl;
+	      
+	      if (sol(0) > 1e-6 && sol(0) < 1-1e-6 &&
+		  sol(1) > 1e-6 && sol(1) < 1-1e-6 &&
+		  Abs (rhs - mat*sol) < 1e-6)
+		{
+		  Point<3> ip = pi1 + sol(0) * vi;
+		  
+		  //(*testout) << "ip " << ip << endl;
+
+		  Point<3> pip = ip;
+		  ProjectToEdge (geom.GetSurface (mesh[si].surfnr1),
+				 geom.GetSurface (mesh[si].surfnr2), pip);
+		  
+		  //(*testout) << "Dist (ip, pip_si) " << Dist (ip, pip) << endl;
+		  if (Dist (ip, pip) > 1e-6*geom.MaxSize()) continue;
+		  pip = ip;
+		  ProjectToEdge (geom.GetSurface (mesh[sj].surfnr1),
+				 geom.GetSurface (mesh[sj].surfnr2), pip);
+
+		  //(*testout) << "Dist (ip, pip_sj) " << Dist (ip, pip) << endl;
+		  if (Dist (ip, pip) > 1e-6*geom.MaxSize()) continue;
+		  
+		  
+		  
+		  cout << "Intersection at " << ip << endl;
+		  
+		  geom.AddUserPoint (ip);
+		  spoints.Append (MeshPoint (ip, mesh[mesh[si][0]].GetLayer()));
+		  mesh.AddPoint (ip);
+		  
+		  (*testout) << "found intersection at " << ip << endl;
+		  (*testout) << "sol = " << sol << endl;
+		  (*testout) << "res = " << (rhs - mat*sol) << endl;
+		  (*testout) << "segs = " << pi1 << " - " << pi2 << endl;
+		  (*testout) << "and = " << pj1 << " - " << pj2 << endl << endl;
+		}
+	    }
+	}  
+  }
+
+
+
+
+
+
+  static void MeshSurface (CSGeometry & geom, Mesh & mesh)
+  {
+    const 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 (int i = 1; i <= mesh.GetNFD(); i++)
+      masterface.Elem(i) = i;
+  
+    Array<INDEX_2> fpairs;
+    bool changed;
+    do
+      {
+	changed = 0;
+	for (int i = 0; i < geom.identifications.Size(); i++)
+	  {
+	    geom.identifications[i]->GetIdentifiedFaces (fpairs);
+
+	    for (int 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 (int k = 0; k < geom.GetNSurf(); k++)
+      bccnt = max2 (bccnt, geom.GetSurface(k)->GetBCProperty());
+
+    for (int k = 1; k <= mesh.GetNFD(); k++)
+      {
+	bool increased = false;
+
+	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);
+	    increased = true;
+	  }      
+
+	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))
+	      {
+		if(geom.bcmodifications[l].bcname == NULL)
+		  fd.SetBCProperty (geom.bcmodifications[l].bcnr);
+		else
+		  {
+		    if(!increased)
+		      {
+			bccnt++;
+			fd.SetBCProperty (bccnt);
+			increased = true;
+		      }
+		  }
+	      }
+	  }
+      }
+
+    mesh.SetNBCNames( bccnt );
+
+    for (int k = 1; k <= mesh.GetNFD(); k++)
+      {
+	FaceDescriptor & fd = mesh.GetFaceDescriptor(k);
+	const Surface * surf = geom.GetSurface(fd.SurfNr());
+	if (fd.TLOSurface() )
+	  {
+	    int bcp = fd.BCProperty();
+	    string nextbcname = geom.GetTopLevelObject(fd.TLOSurface()-1) -> GetBCName();
+	    if ( nextbcname != "default" )
+	      mesh.SetBCName ( bcp - 1 , nextbcname );
+	  }
+	else // if (surf -> GetBCProperty() != -1)
+	  {
+	    int bcp = fd.BCProperty();
+	    string nextbcname = surf->GetBCName();
+	    if ( nextbcname != "default" )
+	      mesh.SetBCName ( bcp - 1, nextbcname );
+	  }
+      }
+    
+    for (int k = 1; k <= mesh.GetNFD(); k++)
+      {
+	FaceDescriptor & fd = mesh.GetFaceDescriptor(k);
+	fd.SetBCName ( mesh.GetBCNamePtr ( fd.BCProperty() - 1 ) );
+      }
+    
+
+    //!!
+    
+    for (int k = 1; k <= mesh.GetNFD(); k++)
+      {
+	FaceDescriptor & fd = mesh.GetFaceDescriptor(k);
+	//const Surface * surf = geom.GetSurface(fd.SurfNr());
+
+	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) &&
+		geom.bcmodifications[l].bcname != NULL
+		)
+	      {
+		int bcp = fd.BCProperty();
+		mesh.SetBCName ( bcp - 1, *(geom.bcmodifications[l].bcname) );
+		fd.SetBCName ( mesh.GetBCNamePtr ( bcp - 1) );
+	      }
+	  }
+      }
+
+    for(int k = 0; k<geom.bcmodifications.Size(); k++)
+      {
+	delete geom.bcmodifications[k].bcname;
+	geom.bcmodifications[k].bcname = NULL;
+      }
+
+    //!!
+
+
+    for (int j = 0; j < geom.singfaces.Size(); j++)
+      {
+	Array<int> surfs;
+	geom.GetIndependentSurfaceIndices (geom.singfaces[j]->GetSolid(),
+					   geom.BoundingBox(), surfs);
+	for (int k = 1; k <= mesh.GetNFD(); k++)
+	  {
+	    FaceDescriptor & fd = mesh.GetFaceDescriptor(k);
+	    for (int l = 0; l < surfs.Size(); l++)
+	      if (surfs[l] == fd.SurfNr())
+		{
+		  if (geom.singfaces[j]->GetDomainNr() == fd.DomainIn())
+		    fd.SetDomainInSingular (1);
+		  if (geom.singfaces[j]->GetDomainNr() == fd.DomainOut())
+		    fd.SetDomainOutSingular (1);
+		}
+	  }
+      }
+    
+
+    // assemble edge hash-table
+    mesh.CalcSurfacesOfNode();
+
+    for (int k = 1; k <= mesh.GetNFD(); k++)
+      {
+	multithread.percent = 100.0 * 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()));
+
+
+	Meshing2Surfaces meshing(*surf, mparam, geom.BoundingBox());
+	meshing.SetStartTime (starttime);
+
+        double eps = 1e-8 * geom.MaxSize();
+	for (PointIndex pi = PointIndex::BASE; pi < noldp+PointIndex::BASE; pi++)
+	  { 
+	    // if(surf->PointOnSurface(mesh[pi]))
+	    meshing.AddPoint (mesh[pi], pi, NULL,
+			      (surf->PointOnSurface(mesh[pi], eps) != 0));
+	  }
+
+	segments.SetSize (0);
+
+	for (SegmentIndex si = 0; si < mesh.GetNSeg(); si++)
+	  if (mesh[si].si == k)
+	    {
+	      segments.Append (mesh[si]);
+	      (*testout) << "appending segment " << mesh[si] << endl;
+	      //<< " from " << mesh[mesh[si][0]]
+	      //	 << " to " <<mesh[mesh[si][1]]<< endl;
+	    }
+
+	(*testout) << "num-segments " << segments.Size() << endl;
+
+	for (int i = 1; i <= geom.identifications.Size(); i++)
+	  {
+	    geom.identifications.Get(i)->
+	      BuildSurfaceElements(segments, mesh, surf);
+	  }
+
+	for (int si = 0; si < segments.Size(); si++)
+	  {
+	    PointGeomInfo gi;
+	    gi.trignum = k;
+	    meshing.AddBoundaryElement (segments[si][0] + 1 - PointIndex::BASE, 
+					segments[si][1] + 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;
+
+	mparam.checkoverlap = 0;
+
+	MESHING2_RESULT res =
+	  meshing.GenerateMesh (mesh, mparam, maxh, k);
+
+	if (res != MESHING2_OK)
+	  {
+	    PrintError ("Problem in Surface mesh generation");
+	    throw NgException ("Problem in Surface mesh generation");
+	  }
+
+	if (multithread.terminate) return;
+      
+	for (SurfaceElementIndex sei = oldnf; sei < mesh.GetNSE(); sei++)
+	  mesh[sei].SetIndex (k);
+
+
+	//      mesh.CalcSurfacesOfNode();
+
+	if (segments.Size())   
+	  { 
+	    // surface was meshed, not copied
+
+	    static int timer = NgProfiler::CreateTimer ("total surface mesh optimization");
+	    NgProfiler::RegionTimer reg (timer);
+
+
+	    PrintMessage (2, "Optimize Surface");
+	    for (int i = 1; i <= mparam.optsteps2d; i++)
+	      {
+		if (multithread.terminate) return;
+		
+		{
+		  MeshOptimize2dSurfaces meshopt(geom);
+		  meshopt.SetFaceIndex (k);
+		  meshopt.SetImproveEdges (0);
+		  meshopt.SetMetricWeight (mparam.elsizeweight);
+		  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 (mparam.elsizeweight);
+		  meshopt.SetWriteStatus (0);
+
+		  meshopt.ImproveMesh (mesh, mparam);
+		}
+		
+		{
+		  MeshOptimize2dSurfaces meshopt(geom);
+		  meshopt.SetFaceIndex (k);
+		  meshopt.SetImproveEdges (0);
+		  meshopt.SetMetricWeight (mparam.elsizeweight);
+		  meshopt.SetWriteStatus (0);
+
+		  meshopt.CombineImprove (mesh);
+		  //		mesh.CalcSurfacesOfNode();
+		}
+		
+		if (multithread.terminate) return;
+		{
+		  MeshOptimize2dSurfaces meshopt(geom);
+		  meshopt.SetFaceIndex (k);
+		  meshopt.SetImproveEdges (0);
+		  meshopt.SetMetricWeight (mparam.elsizeweight);
+		  meshopt.SetWriteStatus (0);
+
+		  meshopt.ImproveMesh (mesh, mparam);
+		}
+	      }
+	  }
+
+
+	PrintMessage (3, (mesh.GetNSE() - oldnf), " elements, ", mesh.GetNP(), " points");
+
+	extern void Render();
+	Render();
+      }
+    
+    mesh.Compress();
+
+    do
+      {
+	changed = 0;
+	for (int k = 1; k <= mesh.GetNFD(); k++)
+	  {
+	    multithread.percent = 100.0 * 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 (int i = 1; i <= mesh.GetNSeg(); i++)
+	      {
+		Segment * seg = &mesh.LineSegment(i);
+		if (seg->si == k)
+		  segments.Append (*seg);
+	      }
+
+	    for (int i = 1; i <= geom.identifications.Size(); i++)
+	      {
+		geom.identifications.Elem(i)->GetIdentifiedFaces (fpairs);
+		int found = 0;
+		for (int 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 (SurfaceElementIndex  sei = oldnf; sei < mesh.GetNSE(); sei++)
+	      mesh[sei].SetIndex (k);
+
+
+	    if (!segments.Size())
+	      {
+		masterface.Elem(k) = k;
+		changed = 1; 
+	      }
+
+	    PrintMessage (3, (mesh.GetNSE() - oldnf), " elements, ", mesh.GetNP(), " points");
+	  }
+      
+	extern void Render();
+	Render();
+      }
+    while (changed);
+
+    
+    mesh.SplitSeparatedFaces();
+    mesh.CalcSurfacesOfNode();
+
+    multithread.task = savetask;
+  }
+
+
+
+  int CSGGenerateMesh (CSGeometry & geom, 
+		       Mesh *& mesh, MeshingParameters & mparam,
+		       int perfstepsstart, int perfstepsend)
+  {
+    if (mesh && mesh->GetNSE() &&
+	!geom.GetNSolids())
+      {
+	if (perfstepsstart < MESHCONST_MESHVOLUME)
+	  perfstepsstart = MESHCONST_MESHVOLUME;
+      }
+
+    if (perfstepsstart <= MESHCONST_ANALYSE)
+      {
+        if (mesh)
+          mesh -> DeleteMesh();
+        else
+          mesh = new Mesh();
+
+	mesh->SetGlobalH (mparam.maxh);
+	mesh->SetMinimalH (mparam.minh);
+
+	Array<double> maxhdom(geom.GetNTopLevelObjects());
+	for (int i = 0; i < maxhdom.Size(); i++)
+	  maxhdom[i] = geom.GetTopLevelObject(i)->GetMaxH();
+
+	mesh->SetMaxHDomain (maxhdom);
+
+	if (mparam.uselocalh)
+	  {
+	    double maxsize = geom.MaxSize(); 
+	    mesh->SetLocalH (Point<3>(-maxsize, -maxsize, -maxsize),
+			     Point<3>(maxsize, maxsize, maxsize),
+			     mparam.grading);
+
+	    mesh -> LoadLocalMeshSize (mparam.meshsizefilename);
+	  }
+
+	spoints.SetSize(0);
+	FindPoints (geom, *mesh);
+      
+	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, true);
+	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(mparam.grading);
+	    mesh->DeleteMesh();
+	    
+	    FindPoints (geom, *mesh);
+	    if (multithread.terminate) return TCL_OK;
+	    FindEdges (geom, *mesh, true);
+	    if (multithread.terminate) return TCL_OK;
+	    
+	    mesh->DeleteMesh();
+	  
+	    FindPoints (geom, *mesh);
+	    if (multithread.terminate) return TCL_OK;
+	    FindEdges (geom, *mesh);
+	    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(mparam.grading);      
+	    mesh->DeleteMesh();
+
+	    FindPoints (geom, *mesh);
+	    if (multithread.terminate) return TCL_OK;
+	    FindEdges (geom, *mesh);
+	    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();
+      }
+  
+    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);
+	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
+      }
+
+    return TCL_OK;
+  }
+}
diff --git a/contrib/Netgen/libsrc/csg/geoml.hpp b/contrib/Netgen/libsrc/csg/geoml.hpp
new file mode 100644
index 0000000000..e7974ad206
--- /dev/null
+++ b/contrib/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/contrib/Netgen/libsrc/csg/identify.cpp b/contrib/Netgen/libsrc/csg/identify.cpp
new file mode 100644
index 0000000000..e3086a3bad
--- /dev/null
+++ b/contrib/Netgen/libsrc/csg/identify.cpp
@@ -0,0 +1,1662 @@
+#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 TABLE<int> & specpoint2solid,
+	      const TABLE<int> & specpoint2surface) 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 TABLE<int> & specpoint2solid,
+	      const TABLE<int> & specpoint2surface) 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;
+      n1 = s1->GetNormalVector (hsp1.p);
+      n1 /= n1.Length();
+      if ( fabs(n1 * hsp1.v) > 1e-3)
+	continue;
+
+
+      if (!s2->PointOnSurface(hsp2.p))
+	continue;
+
+      Vec<3> n2;
+      n2 = s2->GetNormalVector (hsp2.p);
+      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-6)
+        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 *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 newpi = 0;
+  for (int 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);
+
+  mesh.GetIdentifications().SetType(nr,Identifications::PERIODIC);
+	   
+  /* 
+  (*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;
+		*/
+	      }
+	}
+    }
+
+  mesh.GetIdentifications().SetType(nr,Identifications::PERIODIC);
+}
+
+
+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[0] << "-" << seg1[1] << ", seg2 = " << seg2[0] << "-" << seg2[1];
+
+		    if (side == 1)
+		      {
+			if (mesh.GetIdentifications().Get (seg1[0], seg2[0]) &&
+			    mesh.GetIdentifications().Get (seg1[1], seg2[1]))
+			  {
+			    foundother = 1;
+			    break;
+			  }
+			
+			if (mesh.GetIdentifications().Get (seg1[0], seg2[1]) &&
+			    mesh.GetIdentifications().Get (seg1[1], seg2[0]))
+			  {
+			    foundother = 1;
+			    break;
+			  }
+		      }
+		    else
+		      {
+			if (mesh.GetIdentifications().Get (seg2[0], seg1[0]) &&
+			    mesh.GetIdentifications().Get (seg2[1], seg1[1]))
+			  {
+			    foundother = 1;
+			    break;
+			  }
+			
+			if (mesh.GetIdentifications().Get (seg2[0], seg1[1]) &&
+			    mesh.GetIdentifications().Get (seg2[1], seg1[0]))
+			  {
+			    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 found = 0;
+  int fother = -1;
+
+  int facei = segs.Get(1).si;
+  int surfnr = mesh.GetFaceDescriptor(facei).SurfNr();
+
+  if (geom.GetSurface(surfnr) == s1 ||
+      geom.GetSurface(surfnr) == s2)
+    {
+      Array<int> copy_points;
+
+      for (SurfaceElementIndex sei = 0; sei < mesh.GetNSE(); sei++)
+	{
+	  const Element2d & sel = mesh[sei];
+	  INDEX_2 fpair (facei, sel.GetIndex());
+	  fpair.Sort();
+	  if (identfaces.Used (fpair))
+            {
+	      for (int k = 0; k < sel.GetNP(); k++)
+                if (!copy_points.Contains (sel[k]))
+                  copy_points.Append (sel[k]);
+            }      
+        }
+      BubbleSort (copy_points);
+      for (int k = 0; k < copy_points.Size(); k++)
+        GetIdentifiedPoint (mesh, copy_points[k]);
+
+
+
+      for (SurfaceElementIndex sei = 0; sei < mesh.GetNSE(); sei++)
+	{
+	  const Element2d & sel = mesh[sei];
+	  INDEX_2 fpair (facei, sel.GetIndex());
+	  fpair.Sort();
+	  if (identfaces.Used (fpair))
+	    {
+	      found = 1;
+	      fother = sel.GetIndex();
+
+	      // copy element
+	      Element2d newel(sel.GetType());
+	      newel.SetIndex (facei);
+	      for (int k = 0; k < sel.GetNP(); k++)
+                newel[k] = GetIdentifiedPoint (mesh, sel[k]);
+
+	      Vec<3> nt = Cross (Point<3> (mesh[newel[1]])- Point<3> (mesh[newel[0]]),
+				 Point<3> (mesh[newel[2]])- Point<3> (mesh[newel[0]]));
+	      
+	      Vec<3> nsurf = geom.GetSurface (surfnr)->GetNormalVector (mesh[newel[0]]);
+	      if (nsurf * nt < 0)
+                Swap (newel[0], newel[2]);
+				
+	      mesh.AddSurfaceElement (newel);
+	    }
+	}
+    }
+  
+  if (found)
+    {
+      // (*mycout) << " copy face " << facei << " from face " << fother;
+      PrintMessage (4, " 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 TopLevelObject * adomain,
+			    const Flags & flags)
+  : Identification(anr, ageom)
+{
+  s1 = as1;
+  s2 = as2;
+  domain = adomain;
+  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");
+  for(int i=0; i<slices.Size(); i++)
+    if((i==0 && slices[i] <= 0) ||
+       (i>0 && slices[i] <= slices[i-1]) ||
+       (slices[i] >= 1))
+      throw NgException ("slices have to be in ascending order, between 0 and 1");
+
+  // eps_n = 1e-3;
+  eps_n = 1e-6;
+
+  dom_surf_valid = 0;
+
+  if (domain)
+    for (int i = 0; i < geom.GetNTopLevelObjects(); i++)
+      if (domain == geom.GetTopLevelObject(i))
+	dom_nr = i;
+
+  usedirection = flags.NumListFlagDefined("direction");
+  if(usedirection)
+    {
+      for(int i=0; i<3; i++)
+	direction(i) = flags.GetNumListFlag("direction")[i];
+
+      direction.Normalize();
+    }
+}
+
+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 TABLE<int> & specpoint2solid,
+	      const TABLE<int> & specpoint2surface) const
+{
+  //(*testout) << "identcheck: " << sp1.p << "; " << sp2.p << endl;
+
+  if (!dom_surf_valid)
+    {
+      const_cast<bool&> (dom_surf_valid) = 1;
+      Array<int> & hsurf = const_cast<Array<int>&> (domain_surfaces);
+
+      if (domain)
+	{
+	  BoxSphere<3> hbox (geom.BoundingBox());
+	  geom.GetIndependentSurfaceIndices (domain->GetSolid(), hbox, hsurf);
+	  //(*testout) << "surfs of identification " << nr << ": " << endl << hsurf << endl;
+	}
+      else
+	{
+	  hsurf.SetSize (geom.GetNSurf());
+	  for (int j = 0; j < hsurf.Size(); j++)
+	    hsurf[j] = j;
+	}
+    }
+
+  if (domain)
+    {
+      bool has1 = 0, has2 = 0;
+      for (int i = 0; i < specpoint2solid[sp1.nr].Size(); i++)
+	if (specpoint2solid[sp1.nr][i] == dom_nr)
+	  { has1 = 1; break; }
+      for (int i = 0; i < specpoint2solid[sp2.nr].Size(); i++)
+	if (specpoint2solid[sp2.nr][i] == dom_nr)
+	  { has2 = 1; break; }
+
+      if (!has1 || !has2) 
+	{
+	  //(*testout) << "failed at pos1" << endl;
+	  return 0;
+	}
+    }
+
+  if (!s1->PointOnSurface (sp1.p))
+    {
+      //(*testout) << "failed at pos2" << endl;
+      return 0;
+    }
+
+//   (*testout) << "sp1 " << sp1.p << " sp2 " << sp2.p << endl
+// 	     << "specpoint2solid[sp1.nr] " << specpoint2solid[sp1.nr] << endl
+// 	     << "specpoint2solid[sp2.nr] " << specpoint2solid[sp2.nr] << endl;
+
+
+  Vec<3> n1 = s1->GetNormalVector (sp1.p);
+  n1.Normalize();
+  if ( fabs(n1 * sp1.v) > eps_n)
+    {
+      //(*testout) << "failed at pos3" << endl;
+      return 0;
+    }
+
+  if (!s2->PointOnSurface(sp2.p))
+    {
+      //(*testout) << "failed at pos4" << endl;
+      return 0;
+    }
+
+
+  Vec<3> n2 = s2->GetNormalVector (sp2.p);
+  n2.Normalize();
+  if ( fabs(n2 * sp2.v) > eps_n)
+    {
+      //(*testout) << "failed at pos5" << endl;
+      return 0;
+    }
+  
+  // must have joint surface 
+  bool joint = 0;
+
+  int j = 0, k = 0;
+  while (1)
+    {
+      int snr1 = specpoint2surface[sp1.nr][j];
+      int snr2 = specpoint2surface[sp2.nr][k];
+      if (snr1 < snr2) 
+	{
+	  j++;
+	  if (j == specpoint2surface[sp1.nr].Size()) break;
+	}
+      else if (snr2 < snr1) 
+	{
+	  k++;
+	  if (k == specpoint2surface[sp2.nr].Size()) break;
+	}
+      else
+	{
+	  bool dom_surf = 0;
+	  for (int l = 0; l < domain_surfaces.Size(); l++)
+	    if (domain_surfaces[l] == snr1)
+	      dom_surf = 1;
+
+	  if (dom_surf)
+	    {
+	      Vec<3> hn1 = geom.GetSurface(snr1)->GetNormalVector (sp1.p);
+	      Vec<3> hn2 = geom.GetSurface(snr1)->GetNormalVector (sp2.p);
+	      
+	      if (hn1 * hn2 > 0)
+		{
+		  joint = 1;
+		  break;
+		}
+	    }
+
+	  j++;
+	  if (j == specpoint2surface[sp1.nr].Size()) break;
+	  k++;
+	  if (k == specpoint2surface[sp2.nr].Size()) break;
+	}
+    }
+
+  if (!joint)
+    {
+      //(*testout) << "failed at pos6" << endl;
+      return 0;
+    }
+
+  Vec<3> v = sp2.p - sp1.p;
+  double vl = v.Length();
+  double cl = (usedirection) ? fabs(v*direction) : fabs (v*n1);
+
+
+  if(cl <= (1-eps_n*eps_n) * vl)
+    {
+      //(*testout) << "failed at pos7" << endl;
+      return 0;
+    }
+  
+  double dl;
+
+  if(usedirection)
+    {
+      Vec<3> v1 = sp1.v - (sp1.v*direction)*direction; v1.Normalize();
+      Vec<3> v2 = sp2.v - (sp2.v*direction)*direction; v2.Normalize();
+      
+      dl = (v1 - v2).Length();
+    }
+  else
+    dl = (sp1.v - sp2.v).Length();
+
+  if (dl < 0.1)
+    return 1;
+   
+
+  //(*testout) << "failed at pos8" << endl;
+  return 0;
+}
+
+int CloseSurfaceIdentification :: 
+Identifyable (const Point<3> & p1, const Point<3> & p2) const
+{  
+//   if (domain)
+//     if (!domain->GetSolid()->IsIn (p1) || !domain->GetSolid()->IsIn (p2))
+//       return 0;
+  return (s1->PointOnSurface (p1) && s2->PointOnSurface (p2));
+}
+  
+
+
+
+int CloseSurfaceIdentification :: 
+IdentifyableCandidate (const SpecialPoint & sp1) const
+{
+  if (domain)
+    if (!domain->GetSolid()->IsIn (sp1.p))
+      return 0;
+
+  if (s1->PointOnSurface (sp1.p))
+    {
+      Vec<3> n1;
+      n1 = s1->GetNormalVector (sp1.p);
+      n1.Normalize();
+      if ( fabs(n1 * sp1.v) > eps_n)
+	return 0;
+      return 1;
+    }
+
+  if (s2->PointOnSurface (sp1.p))
+    {
+      Vec<3> n1;
+      n1 = s2->GetNormalVector (sp1.p);
+      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
+{  
+  if ( (s1->PointOnSurface (sp1.p) && s2->PointOnSurface (sp2.p)) ||
+       (s1->PointOnSurface (sp2.p) && s2->PointOnSurface (sp1.p)) )
+    {
+      return 1;
+    }
+  return 0;
+}
+
+
+
+int CloseSurfaceIdentification :: 
+GetIdentifiedPoint (class Mesh & mesh,  int pi)
+{
+  const Surface *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) << endl
+		 << "surf2: " << (*s2) << endl;
+      
+      cerr << "GetIdenfifiedPoint: Not possible" << endl;
+      throw NgException ("GetIdenfifiedPoint: Not possible");
+    }    
+
+  // project to other surface
+  Point<3> hp = p;
+  if(usedirection)
+    snew->SkewProject(hp,direction);
+  else
+    snew->Project (hp);
+
+  //(*testout) << "projecting " << p << " to " << hp << endl;
+
+  int newpi = 0;
+  for (int 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);
+      //(*testout) << "add identification(1) " << pi << " - " << newpi << ", " << nr << endl;
+    }
+  else
+    {
+      mesh.GetIdentifications().Add (newpi, pi, nr);
+      //(*testout) << "add identification(2) " << newpi << " - " << pi << ", " << nr << endl;
+    }
+  mesh.GetIdentifications().SetType(nr,Identifications::CLOSESURFACES);
+	   
+
+  /*
+  (*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 np = mesh.GetNP();
+
+  Array<int> points_on_surf2;
+
+  for (int i2 = 1; i2 <= np; i2++)
+    if (s2->PointOnSurface (mesh.Point(i2)))
+      points_on_surf2.Append (i2);
+    
+  Array<int> surfs_of_p1;
+
+  for (int i1 = 1; i1 <= np; i1++)
+    {
+      Point<3> p1 = mesh.Point(i1);
+      //      (*testout) << "p1 = " << i1 << " = " << p1 << endl;
+      if (domain && !domain->GetSolid()->IsIn (p1))
+	continue;
+      
+      //if(domain) (*testout) << "p1 is in " << domain->GetSolid()->Name() << endl;
+
+      if (s1->PointOnSurface (p1))
+	{
+	  int candi2 = 0;
+	  double mindist = 1e10;
+
+	  Vec<3> n1;
+	  n1 = s1->GetNormalVector (p1);
+	  n1.Normalize();
+	   
+	  surfs_of_p1.SetSize(0);
+	  for (int jj = 0; jj < domain_surfaces.Size(); jj++)
+	    {
+	      int j = domain_surfaces[jj];
+	      if (geom.GetSurface(j) -> PointOnSurface(p1))
+		surfs_of_p1.Append (j);
+	    }
+	  //(*testout) << " surfs of p1 = " << endl << surfs_of_p1 << endl;
+
+	  for (int ii2 = 0; ii2 < points_on_surf2.Size(); ii2++)
+	    {
+	      int i2 = points_on_surf2[ii2];
+	      if (i2 == i1) continue;
+	      const Point<3> p2 = mesh.Point(i2);
+	      
+	      Vec<3> n = p2 - p1;
+	      n.Normalize();
+	      
+	      bool joint = 0;
+	      for (int jj = 0; jj < surfs_of_p1.Size(); jj++)
+		{
+		  int j = surfs_of_p1[jj];
+		  if (geom.GetSurface(j) -> PointOnSurface(p2))
+		    {
+		      Vec<3> hn1 = geom.GetSurface(j)->GetNormalVector (p1);
+		      Vec<3> hn2 = geom.GetSurface(j)->GetNormalVector (p2);
+		      
+		      if (hn1 * hn2 > 0)
+			{
+			  joint = 1;
+			  break;
+			}
+		    }
+		}
+
+	      if (!joint) continue;
+	      
+	      if(usedirection)
+		{
+		  if (fabs (n*direction) > 0.9)
+		    {
+		      Vec<3> p1p2 = p2-p1;
+		      double ndist = p1p2.Length2() - pow(p1p2*direction,2);
+		      if(ndist < mindist)
+			{
+			  candi2 = i2;
+			  mindist = ndist;
+			}
+		    }
+		      
+		}
+	      else
+		{
+		  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, nr = " << nr << ", p1 = " 
+			 << i1 << " = " 
+			 << mesh[PointIndex(i1)] << ", p2 = " << candi2 << " = " 
+			 << mesh[PointIndex(candi2)] << endl;
+	      */
+	      mesh.GetIdentifications().Add (i1, candi2, nr);
+	      mesh.GetIdentifications().SetType(nr,Identifications::CLOSESURFACES);
+	      //(*testout) << "add identification " << i1 << " - " << candi2 << ", " << nr << endl;
+	    }
+	}
+    }
+}
+
+
+
+void CloseSurfaceIdentification :: IdentifyFaces (class Mesh & mesh)
+{
+  int fi1, fi2, side;
+  int s1rep = -1, s2rep = -1;
+
+  for (int i = 0; i < geom.GetNSurf(); i++)
+    {
+      if (geom.GetSurface (i) == s1) 
+	s1rep = geom.GetSurfaceClassRepresentant(i);
+      if (geom.GetSurface (i) == s2) 
+	s2rep = geom.GetSurfaceClassRepresentant(i);
+    }
+
+  Array<int> segs_on_face1, segs_on_face2;
+
+  identfaces.DeleteData();
+
+  //(*testout) << "identify faces, nr = " << nr << endl;
+  
+  for (int i = 1; i <= mesh.GetNFD(); i++)
+    {
+      int surfi = mesh.GetFaceDescriptor(i).SurfNr();
+      if (s1rep != surfi) continue;
+
+
+      if (domain &&
+	  domain != geom.GetTopLevelObject (mesh.GetFaceDescriptor(i).DomainIn()-1) &&
+	  domain != geom.GetTopLevelObject (mesh.GetFaceDescriptor(i).DomainOut()-1))
+	continue;
+
+      for (int j = 1; j <= mesh.GetNFD(); j++)
+	{
+	  int surfj = mesh.GetFaceDescriptor(j).SurfNr();
+
+	  if (surfi == surfj) continue;
+	  if (s2rep != surfj) continue;
+
+  
+	  int idok = 1;
+	  
+	  for (side = 1; side <= 2 && idok; side++)
+	    {
+	      if (side == 1)
+		{
+		  fi1 = i; 
+		  fi2 = j;
+		}
+	      else
+		{
+		  fi1 = j;
+		  fi2 = i;
+		}
+	      
+
+	      segs_on_face1.SetSize(0);
+	      segs_on_face2.SetSize(0);
+
+	      for (int k = 1; k <= mesh.GetNSeg(); k++)
+		{
+		  if (mesh.LineSegment(k).si == fi1)
+		    segs_on_face1.Append (k);
+		  if (mesh.LineSegment(k).si == fi2)
+		    segs_on_face2.Append (k);
+		}
+
+
+	      for (int k = 1; k <= mesh.GetNSeg(); k++)
+		{
+		  const Segment & seg1 = mesh.LineSegment(k);
+		  if (seg1.si != fi1)
+		    continue;
+		  
+		  int foundother = 0;
+		  /*
+		  for (int l = 1; l <= mesh.GetNSeg(); l++)
+		    {
+		      const Segment & seg2 = mesh.LineSegment(l);
+		      if (seg2.si != fi2)
+			continue;
+		  */
+		  for (int ll = 0; ll < segs_on_face2.Size(); ll++)
+		    {
+		      int l = segs_on_face2[ll];
+		      const Segment & seg2 = mesh.LineSegment(l);
+		      
+		      if (side == 1)
+			{
+			  if (mesh.GetIdentifications().Get (seg1[0], seg2[0]) &&
+			      mesh.GetIdentifications().Get (seg1[1], seg2[1]))
+			    {
+			      foundother = 1;
+			      break;
+			    }
+			  
+			  if (mesh.GetIdentifications().Get (seg1[0], seg2[1]) &&
+			      mesh.GetIdentifications().Get (seg1[1], seg2[0]))
+			    {
+			      foundother = 1;
+			      break;
+			    }
+			}
+		      else
+			{
+			  if (mesh.GetIdentifications().Get (seg2[0], seg1[0]) &&
+			      mesh.GetIdentifications().Get (seg2[1], seg1[1]))
+			    {
+			      foundother = 1;
+			      break;
+			    }
+			  
+			  if (mesh.GetIdentifications().Get (seg2[0], seg1[1]) &&
+			      mesh.GetIdentifications().Get (seg2[1], seg1[0]))
+			    {
+			      foundother = 1;
+			      break;
+			    }
+			}
+		    }
+		  
+		  if (!foundother)
+		    {
+		      idok = 0;
+		      break;
+		    }
+		}
+	    }
+	  
+	  
+	  if (idok)
+	    {
+	      //(*testout) << "Identification " << nr << ", 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)
+{
+  bool found = 0;
+  int cntquads = 0;
+
+  Array<int,PointIndex::BASE>  identmap;
+  identmap = 0;
+
+  mesh.GetIdentifications().GetMap (nr, identmap);
+  
+  for (int i = PointIndex::BASE; i < identmap.Size()+PointIndex::BASE; i++)
+    if (identmap[i])  identmap[identmap[i]] = i;
+
+    
+  //(*testout) << "identification nr = " << nr << endl;
+  //(*testout) << "surf = " << (*surf) << endl;
+  //(*testout) << "domain = " << domain->GetSolid()->Name() << endl;
+  //(*testout) << "segs = " << endl << segs << endl;
+  //(*testout) << "identmap = " << endl << identmap << endl;
+  
+  //Array<bool> foundseg(segs.Size());
+  //foundseg = false;
+
+  // insert quad layer:
+  for (int i1 = 0; i1 < segs.Size(); i1++)
+    {
+      const Segment & s1 = segs[i1];
+      if (identmap[s1[0]] && identmap[s1[1]])
+	for (int i2 = 0; i2 < i1; i2++)
+	  {
+	    const Segment & s2 = segs[i2];
+	    //(*testout) << "checking " << s1 << " and " << s2 << " for ident." << endl;
+
+	    if(domain && !((s1.domin == dom_nr ||
+			    s1.domout == dom_nr) &&
+			   (s2.domin == dom_nr ||
+			    s2.domout == dom_nr)))
+	      continue;
+	 
+	    if ((mesh.GetIdentifications().Get (s1[0], s2[1], nr) && 
+		 mesh.GetIdentifications().Get (s1[1], s2[0], nr))    || 
+		(mesh.GetIdentifications().Get (s2[0], s1[1], nr) && 
+		 mesh.GetIdentifications().Get (s2[1], s1[0], nr)))
+	      {
+		Element2d el(s1[0], s1[1], s2[0], s2[1]);
+
+		Vec<3> n = Cross (mesh[el[1]] - mesh[el[0]],
+				  mesh[el[3]] - mesh[el[0]]);
+
+		Vec<3> ns = surf->GetNormalVector (mesh[el[0]]);
+
+		if (n * ns < 0)
+		  {
+		    Swap (el.PNum(1), el.PNum(2));
+		    Swap (el.PNum(3), el.PNum(4));
+		  }
+			     
+		mesh.AddSurfaceElement (el);
+//  		(*testout) << "(id nr "<< nr <<") 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 = true;
+		//foundseg[i1]=foundseg[i2] = true;
+		cntquads++;
+	      }
+	  }
+    }
+  if (found)
+    {
+      PrintMessage(3, "insert quad layer of ", cntquads,
+		   " elements at face ", segs.Get(1).si);
+      //Array<Segment> aux;
+      //for(int i=0; i<segs.Size();i++)
+      //	if(!foundseg[i])
+      //	  aux.Append(segs[i]);
+      segs.SetSize(0);
+    }
+  else
+    {
+      BuildSurfaceElements2 (segs, mesh, surf);
+    }
+}
+
+
+
+
+
+
+void CloseSurfaceIdentification :: 
+BuildSurfaceElements2 (Array<Segment> & segs,
+		       Mesh & mesh, const Surface * surf)
+{
+  // copy mesh
+
+
+  //  (*testout) << "copy trig face, identnr = " << nr << endl;
+  //  (*testout) << "identfaces = " << endl << identfaces << endl;
+
+  if (!segs.Size()) return;
+
+  bool found = 0;
+  int fother = -1;
+
+  int facei = segs[0].si;
+  int surfnr = mesh.GetFaceDescriptor(facei).SurfNr();
+
+  
+  bool foundid = 0;
+  for (INDEX_2_HASHTABLE<int>::Iterator it = identfaces.Begin();
+       it != identfaces.End(); it++)
+    {
+      INDEX_2 i2;
+      int data;
+      identfaces.GetData (it, i2, data);
+      if (i2.I1() == facei || i2.I2() == facei)
+	foundid = 1;
+    }
+
+  /*
+  for (int i = 1; i <= identfaces.GetNBags(); i++)
+    for (int 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) << "identface = " << i2 << endl;
+	(*testout) << "face " << i2.I1() << " = " << mesh.GetFaceDescriptor(i2.I1()) << endl;
+	(*testout) << "face " << i2.I2() << " = " << mesh.GetFaceDescriptor(i2.I2()) << endl;
+      }
+  */
+
+  if (foundid)
+    {
+      //	  (*testout) << "surfaces found" << endl;
+      // copy surface
+      for (SurfaceElementIndex sei = 0; sei < mesh.GetNSE(); sei++)
+	{
+	  const Element2d & sel = mesh[sei];
+	  INDEX_2 fpair (facei, sel.GetIndex());
+	  fpair.Sort();
+	  if (identfaces.Used (fpair))
+	    {
+	      found = 1;
+	      fother = sel.GetIndex();
+	      
+	      // copy element
+	      Element2d newel(sel.GetType());
+	      newel.SetIndex (facei);
+	      for (int k = 1; k <= sel.GetNP(); 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;
+	      nsurf = geom.GetSurface (surfnr)->GetNormalVector (mesh.Point(newel.PNum(1)));
+	      if (nsurf * nt < 0)
+		Swap (newel.PNum(2), newel.PNum(3));
+	      
+	      mesh.AddSurfaceElement (newel);
+	    }
+	}
+    }
+  
+  if (found)
+    {
+      // (*mycout) << " copy face " << facei << " from face " << fother;
+      PrintMessage (4, " 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 TABLE<int> & specpoint2solid,
+	      const TABLE<int> & specpoint2surface) 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;
+      n1 = s1->GetNormalVector (hsp1.p);
+      n1 /= n1.Length();
+      if ( fabs(n1 * hsp1.v) > 1e-3)
+	continue;
+
+
+      if (!s2->PointOnSurface(hsp2.p))
+	continue;
+
+      Vec<3> n2;
+      n2 = s2->GetNormalVector (hsp2.p);
+      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 np = mesh.GetNP();
+  for (int i1 = 1; i1 <= np; i1++)
+    for (int 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();
+
+	n1 = s1->GetNormalVector (p1);
+	nf = facet->GetNormalVector (p1);
+	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);
+	    mesh.GetIdentifications().SetType(nr,Identifications::CLOSEEDGES);
+	  }
+      }
+}
+
+void CloseEdgesIdentification :: 
+BuildSurfaceElements (Array<Segment> & segs,
+		      Mesh & mesh, const Surface * surf)
+{
+  int found = 0;
+
+  if (surf != facet)
+    return;
+
+  for (int i1 = 1; i1 <= segs.Size(); i1++)
+    for (int i2 = 1; i2 < i1; i2++)
+      {
+	const Segment & s1 = segs.Get(i1);
+	const Segment & s2 = segs.Get(i2);
+	if (mesh.GetIdentifications().Get (s1[0], s2[1]) &&
+	    mesh.GetIdentifications().Get (s1[1], s2[0]))
+	  {
+	    Element2d el(QUAD);
+	    el.PNum(1) = s1[0];
+	    el.PNum(2) = s1[1];
+	    el.PNum(3) = s2[1];
+	    el.PNum(4) = s2[0];
+
+	    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;
+	    ns = surf->GetNormalVector (mesh.Point(el.PNum(1)));
+	    //(*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/contrib/Netgen/libsrc/csg/identify.hpp b/contrib/Netgen/libsrc/csg/identify.hpp
new file mode 100644
index 0000000000..ef3f75564c
--- /dev/null
+++ b/contrib/Netgen/libsrc/csg/identify.hpp
@@ -0,0 +1,210 @@
+
+#ifndef FILE_IDENTIFY
+#define FILE_IDENTIFY
+
+/**************************************************************************/
+/* File:   identify.hh                                                    */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   1. Aug. 99                                                    */
+/**************************************************************************/
+
+
+namespace netgen
+{
+
+  /**
+     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:
+    DLL_HEADER Identification (int anr, const CSGeometry & ageom);
+    DLL_HEADER virtual ~Identification ();
+    DLL_HEADER virtual void Print (ostream & ost) const = 0;
+    DLL_HEADER 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 TABLE<int> & specpoint2solid,			  
+			      const TABLE<int> & specpoint2surface) 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 TABLE<int> & specpoint2solid,
+			      const TABLE<int> & specpoint2surface) 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 TopLevelObject;
+  class CloseSurfaceIdentification : public Identification
+  {
+    const Surface * s1;
+    const Surface * s2;
+    const TopLevelObject * domain;
+    ///
+    int dom_nr;
+    /// 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;
+    /// used only for domain-local identification:
+    Array<int> domain_surfaces;
+    ///
+    bool dom_surf_valid;
+
+    ///
+    Vec<3> direction;
+    ///
+    bool usedirection;
+  public:
+    CloseSurfaceIdentification (int anr, 
+				const CSGeometry & ageom,
+				const Surface * as1,
+				const Surface * as2,
+				const TopLevelObject * adomain,
+				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 TABLE<int> & specpoint2solid,
+			      const TABLE<int> & specpoint2surface) 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; }
+
+    bool IsSkewIdentification(void) const {return usedirection;}
+    const Vec<3> & GetDirection(void) const {return direction;}
+
+    const Surface & GetSurface1(void) const
+    { return *s1;}
+    const Surface & GetSurface2(void) const
+    { return *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 TABLE<int> & specpoint2solid,
+			      const TABLE<int> & specpoint2surface) const;
+
+
+    virtual void IdentifyPoints (class Mesh & mesh);
+    virtual void BuildSurfaceElements (Array<class Segment> & segs,
+				       class Mesh & mesh,
+				       const Surface * surf);
+  };
+
+}
+
+#endif
diff --git a/contrib/Netgen/libsrc/csg/manifold.cpp b/contrib/Netgen/libsrc/csg/manifold.cpp
new file mode 100644
index 0000000000..9733389d67
--- /dev/null
+++ b/contrib/Netgen/libsrc/csg/manifold.cpp
@@ -0,0 +1,14 @@
+#include <csg.hpp>
+
+namespace netgen
+{
+Manifold :: Manifold () 
+{
+  ;
+}
+
+Manifold :: ~Manifold () 
+{
+  ;
+}
+}
diff --git a/contrib/Netgen/libsrc/csg/manifold.hpp b/contrib/Netgen/libsrc/csg/manifold.hpp
new file mode 100644
index 0000000000..cc60e955e0
--- /dev/null
+++ b/contrib/Netgen/libsrc/csg/manifold.hpp
@@ -0,0 +1,29 @@
+#ifndef FILE_MANIFOLD
+#define FILE_MANIFOLD
+
+/**************************************************************************/
+/* File:   manifold.hh                                                    */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   7. Aug. 96                                                     */
+/**************************************************************************/
+
+namespace netgen
+{
+
+
+  /**
+     Basis class for manifolds in 2d and 3d
+  */
+  class Manifold
+  {
+  public:
+    ///
+    Manifold ();
+    ///
+    virtual ~Manifold ();
+  };
+
+}
+
+
+#endif
diff --git a/contrib/Netgen/libsrc/csg/meshsurf.cpp b/contrib/Netgen/libsrc/csg/meshsurf.cpp
new file mode 100644
index 0000000000..19e12eb226
--- /dev/null
+++ b/contrib/Netgen/libsrc/csg/meshsurf.cpp
@@ -0,0 +1,211 @@
+#include <mystdlib.h>
+
+#include <csg.hpp>
+#include <meshing.hpp>
+
+
+
+namespace netgen
+{
+  /*
+Meshing2Surfaces :: Meshing2Surfaces (const Surface & asurface)
+  : surface(asurface)
+{
+  ;
+}
+  */
+Meshing2Surfaces :: Meshing2Surfaces (const Surface & asurf,
+				      const MeshingParameters & mp,
+				      const Box<3> & abb)
+  : Meshing2(mp, abb), surface(asurf)
+{
+  ;
+}
+
+
+void Meshing2Surfaces :: DefineTransformation (const Point3d & p1, const 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, Point<3> & p) const
+{
+  Point<3> hp = p;
+  geometry.GetSurface(surfind)->Project (hp);
+  p = hp;
+}
+
+void MeshOptimize2dSurfaces :: ProjectPoint2 (INDEX surfind, INDEX surfind2, 
+					      Point<3> & p) const
+{
+  Point<3> hp = p;
+  ProjectToEdge ( geometry.GetSurface(surfind), 
+		  geometry.GetSurface(surfind2), hp);
+  p = hp;
+}
+
+
+void MeshOptimize2dSurfaces :: 
+GetNormalVector(INDEX surfind, const Point<3> & p, Vec<3> & 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)
+{
+  if(geometry.GetNSurf() == 0)
+    *testout << endl 
+             << "WARNING: Intializing 2D refinement with 0-surface geometry" << endl
+             << "==========================================================" << endl
+             << endl << endl;
+}
+
+RefinementSurfaces :: ~RefinementSurfaces ()
+{
+  ;
+}
+  
+void RefinementSurfaces :: 
+PointBetween (const Point<3> & p1, const Point<3> & p2, double secpoint,
+	      int surfi, 
+	      const PointGeomInfo & gi1, 
+	      const PointGeomInfo & gi2,
+	      Point<3> & newp, PointGeomInfo & newgi) const
+{
+  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 Point<3> & p1, const Point<3> & p2, double secpoint,
+	      int surfi1, int surfi2, 
+	      const EdgePointGeomInfo & ap1, 
+	      const EdgePointGeomInfo & ap2,
+	      Point<3> & newp, EdgePointGeomInfo & newgi) const
+{
+  Point<3> hnewp = p1+secpoint*(p2-p1);
+  //(*testout) << "hnewp " << hnewp << " s1 " << surfi1 << " s2 " << surfi2 << endl;
+  if (surfi1 != -1 && surfi2 != -1 && surfi1 != surfi2)
+    {
+      netgen::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;
+      //(*testout) << "hnewp (a1) " << hnewp << endl;
+    }
+  else if (surfi1 != -1)
+    {
+      geometry.GetSurface (surfi1) -> Project (hnewp);
+      //(*testout) << "hnewp (a2) " << hnewp << endl;
+    }
+
+  newp = hnewp;
+};
+
+Vec<3> RefinementSurfaces :: GetTangent (const Point<3> & p, int surfi1, int surfi2,
+                                         const EdgePointGeomInfo & ap1) const
+{
+  Vec<3> n1 = geometry.GetSurface (surfi1)->GetNormalVector (p);
+  Vec<3> n2 = geometry.GetSurface (surfi2)->GetNormalVector (p);
+  Vec<3> tau = Cross (n1, n2).Normalize();
+  return tau;
+}
+
+Vec<3> RefinementSurfaces :: GetNormal (const Point<3> & p, int surfi1, 
+                                        const PointGeomInfo & gi) const
+{
+  return geometry.GetSurface (surfi1)->GetNormalVector (p);
+}
+
+
+
+void RefinementSurfaces :: ProjectToSurface (Point<3> & p, int surfi) const
+{
+  if (surfi != -1)
+    geometry.GetSurface (surfi) -> Project (p);
+};
+
+void RefinementSurfaces :: ProjectToEdge (Point<3> & p, int surfi1, int surfi2, const EdgePointGeomInfo & egi) const
+{
+  netgen::ProjectToEdge (geometry.GetSurface(surfi1), 
+                         geometry.GetSurface(surfi2), 
+                         p);
+  
+}
+
+
+}
diff --git a/contrib/Netgen/libsrc/csg/meshsurf.hpp b/contrib/Netgen/libsrc/csg/meshsurf.hpp
new file mode 100644
index 0000000000..e6c6922555
--- /dev/null
+++ b/contrib/Netgen/libsrc/csg/meshsurf.hpp
@@ -0,0 +1,97 @@
+#ifndef FILE_MESHSURF
+#define FILE_MESHSURF
+
+namespace netgen
+{
+
+  ///
+  class Meshing2Surfaces : public Meshing2
+  {
+    ///
+    const Surface & surface;
+  
+  public:
+    ///
+    //  Meshing2Surfaces (const Surface & asurf);
+    ///
+    Meshing2Surfaces (const Surface & asurf, const MeshingParameters & mp, 
+		      const Box<3> & aboundingbox);
+
+  protected:
+    ///
+    virtual void DefineTransformation (const Point3d & p1, const 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, Point<3> & p) const;
+    ///
+    virtual void ProjectPoint2 (INDEX surfind, INDEX surfind2, Point<3> & p) const;
+    ///
+    virtual void GetNormalVector(INDEX surfind, const Point<3> & p, Vec<3> & n) const;
+  };
+
+
+
+  class RefinementSurfaces : public Refinement
+  {
+    const CSGeometry & geometry;
+
+  public:
+    RefinementSurfaces (const CSGeometry & ageometry);
+    virtual ~RefinementSurfaces ();
+  
+    virtual void PointBetween (const Point<3> & p1, const Point<3> & p2, double secpoint,
+			       int surfi, 
+			       const PointGeomInfo & gi1, 
+			       const PointGeomInfo & gi2,
+			       Point<3> & newp, PointGeomInfo & newgi) const;
+
+    virtual void PointBetween (const Point<3> & p1, const Point<3> & p2, double secpoint,
+			       int surfi1, int surfi2, 
+			       const EdgePointGeomInfo & ap1, 
+			       const EdgePointGeomInfo & ap2,
+			       Point<3> & newp, EdgePointGeomInfo & newgi) const;
+
+    virtual Vec<3> GetTangent (const Point<3> & p, int surfi1, int surfi2,
+			       const EdgePointGeomInfo & ap1) const;
+
+    virtual Vec<3> GetNormal (const Point<3> & p, int surfi1, 
+			      const PointGeomInfo & gi) const;
+
+
+    virtual void ProjectToSurface (Point<3> & p, int surfi) const;
+
+    virtual void ProjectToEdge (Point<3> & p, int surfi1, int surfi2, const EdgePointGeomInfo & egi) const;
+
+  };
+
+}
+
+#endif
+
diff --git a/contrib/Netgen/libsrc/csg/polyhedra.cpp b/contrib/Netgen/libsrc/csg/polyhedra.cpp
new file mode 100644
index 0000000000..6d96d7b437
--- /dev/null
+++ b/contrib/Netgen/libsrc/csg/polyhedra.cpp
@@ -0,0 +1,738 @@
+#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,
+		       int ainputnr)
+{
+  inputnr = ainputnr;
+
+  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;
+  for (int i = 0; i < 3; i++)
+    {
+      mat(0,i) = v1(i);
+      mat(1,i) = v2(i);
+    }
+  CalcInverse (mat, inv);
+  for (int i = 0; i < 3; i++)
+    {
+      w1(i) = inv(i,0);
+      w2(i) = inv(i,1);
+    }
+}
+
+
+Polyhedra :: Polyhedra ()
+{
+  surfaceactive.SetSize(0);
+  surfaceids.SetSize(0);
+  eps_base1 = 1e-8;
+}
+
+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;
+      //(*testout) << "face " << i << endl;
+
+      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;
+
+      //(*testout) << "still in loop" << endl;
+
+      double dist2 = MinDistTP2 (p1, p2, p3, box.Center());
+      //(*testout) << "p1 " << p1 << " p2 " << p2 << " p3 " << p3 << endl
+      //		 << " box.Center " << box.Center() << " box.Diam() " << box.Diam() << endl
+      //	 << " dist2 " << dist2 << " sqr(box.Diam()/2) " << sqr(box.Diam()/2) << endl;
+      if (dist2 < sqr (box.Diam()/2))
+	{
+	  //(*testout) << "DOES_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) << "PointInSolid p " << p << " eps " << eps << endl;
+  //(*testout) << "bbox " << poly_bbox << endl;
+
+  if((p(0) > poly_bbox.PMax()(0) + eps) || (p(0) < poly_bbox.PMin()(0) - eps) ||
+     (p(1) > poly_bbox.PMax()(1) + eps) || (p(1) < poly_bbox.PMin()(1) - eps) ||
+     (p(2) > poly_bbox.PMax()(2) + eps) || (p(2) < poly_bbox.PMin()(2) - eps))
+    {
+      //(*testout) << "returning IS_OUTSIDE" << endl;
+      return IS_OUTSIDE;
+    }
+
+  Vec<3> n, v1, v2;
+
+  // random (?) numbers:
+  n(0) = -0.424621;
+  n(1) = 0.15432;
+  n(2) = 0.89212238;
+
+  int cnt = 0;
+
+  for (int i = 0; i < faces.Size(); i++)
+    {
+      const Point<3> & p1 = points[faces[i].pnums[0]];
+      
+      Vec<3> v0 = p - p1;
+
+      double lam3 = faces[i].nn * v0;
+
+      if(fabs(lam3) < eps)
+	{
+	  double lam1 = (faces[i].w1 * v0);
+	  double lam2 = (faces[i].w2 * v0);
+	  if (lam1 >= -eps_base1 && lam2 >= -eps_base1 && lam1+lam2 <= 1+eps_base1)
+	    {
+	      //(*testout) << "returning DOES_INTERSECT" << endl;
+	      return DOES_INTERSECT;
+	    }
+	}
+      else
+	{
+	  lam3 = -(faces[i].n * v0) / (faces[i].n * n);
+
+	  if (lam3 < 0) continue;
+
+	  Vec<3> rs = v0 + lam3 * n;
+	  
+	  double lam1 = (faces[i].w1 * rs);
+	  double lam2 = (faces[i].w2 * rs);
+	  if (lam1 >= 0 && lam2 >= 0 && lam1+lam2 <= 1)
+	    cnt++;
+	}
+
+    }
+
+  //(*testout) << " cnt = " << cnt%2 << endl;
+  return (cnt % 2) ? IS_INSIDE : IS_OUTSIDE;
+}
+
+
+
+
+void Polyhedra :: GetTangentialSurfaceIndices (const Point<3> & p, 
+					       Array<int> & surfind, double eps) const
+{
+  for (int i = 0; i < faces.Size(); i++)
+    {
+      const Point<3> & p1 = points[faces[i].pnums[0]];
+      
+      Vec<3> v0 = p - p1;
+      double lam3 = -(faces[i].nn * v0); // n->nn
+
+      if (fabs (lam3) > eps) continue;
+
+      double lam1 = (faces[i].w1 * v0);
+      double lam2 = (faces[i].w2 * v0);
+
+      if (lam1 >= -eps_base1 && lam2 >= -eps_base1 && lam1+lam2 <= 1+eps_base1)
+	if (!surfind.Contains (GetSurfaceId(i)))
+	  surfind.Append (GetSurfaceId(i));
+    }
+
+}
+
+
+
+INSOLID_TYPE Polyhedra :: VecInSolid (const Point<3> & p,
+				      const Vec<3> & v,
+				      double eps) const
+{
+  Array<int> point_on_faces;
+  INSOLID_TYPE res(DOES_INTERSECT);
+
+  Vec<3> vn = v;
+  vn.Normalize();
+  for (int i = 0; i < faces.Size(); i++)
+    {
+      const Point<3> & p1 = points[faces[i].pnums[0]];
+      
+      Vec<3> v0 = p - p1;
+      double lam3 = -(faces[i].nn * v0); // n->nn 
+
+
+      if (fabs (lam3) > eps) continue;
+      //(*testout) << "lam3 <= eps" << endl;
+
+      double lam1 = (faces[i].w1 * v0);
+      double lam2 = (faces[i].w2 * v0);
+
+      if (lam1 >= -eps_base1 && lam2 >= -eps_base1 && lam1+lam2 <= 1+eps_base1)
+	{
+	  point_on_faces.Append(i);
+
+	  double scal = vn * faces[i].nn; // n->nn
+	
+	  res = DOES_INTERSECT;
+	  if (scal > eps_base1) res = IS_OUTSIDE;
+	  if (scal < -eps_base1) res = IS_INSIDE;
+	}
+    }
+  
+  //(*testout) << "point_on_faces.Size() " << point_on_faces.Size() 
+  //	     << " res " << res << endl;
+
+  if (point_on_faces.Size() == 0)
+    return PointInSolid (p, 0);
+  if (point_on_faces.Size() == 1)
+    return res;
+
+
+
+  
+  double mindist(0);
+  bool first = true;
+
+  for(int i=0; i<point_on_faces.Size(); i++)
+    {
+      for(int j=0; j<3; j++)
+	{
+	  double dist = Dist(p,points[faces[point_on_faces[i]].pnums[j]]);
+	  if(dist > eps && (first || dist < mindist))
+	    {
+	      mindist = dist;
+	      first = false;
+	    }
+	}
+    }
+  
+  Point<3> p2 = p + (1e-2*mindist) * vn;
+  res = PointInSolid (p2, eps);
+
+  //  (*testout) << "mindist " << mindist << " res " << res << endl;
+
+  return res;
+  
+ 
+}
+
+
+/*
+INSOLID_TYPE Polyhedra :: VecInSolid2 (const Point<3> & p,
+				       const Vec<3> & v1,
+				       const Vec<3> & v2,
+				       double eps) const
+{
+  INSOLID_TYPE res;
+
+  res = VecInSolid(p,v1,eps);
+  if(res != DOES_INTERSECT)
+    return res;
+
+  int point_on_n_faces = 0;
+
+  Vec<3> v1n = v1;
+  v1n.Normalize();
+  Vec<3> v2n = v2;
+  v2n.Normalize();
+
+
+  for (int i = 0; i < faces.Size(); i++)
+    {
+      const Point<3> & p1 = points[faces[i].pnums[0]];
+      
+      Vec<3> v0 = p - p1;
+      double lam3 = -(faces[i].n * v0);
+
+      if (fabs (lam3) > eps) continue;
+
+      double lam1 = (faces[i].w1 * v0);
+      double lam2 = (faces[i].w2 * v0);
+
+      if (lam1 >= -eps && lam2 >= -eps && lam1+lam2 <= 1+eps)
+	{
+	  double scal1 = v1n * faces[i].n;
+	  if (fabs (scal1) > eps) continue;
+
+
+	  point_on_n_faces++;
+
+	  double scal2 = v2n * faces[i].n;
+	  res = DOES_INTERSECT;
+	  if (scal2 > eps) res = IS_OUTSIDE;
+	  if (scal2 < -eps) res = IS_INSIDE;
+	}
+    }
+
+  if (point_on_n_faces == 1)
+    return res;
+
+  cerr << "primitive::vecinsolid2 makes nonsense for polyhedra" << endl;
+
+  return Primitive :: VecInSolid2 (p, v1, v2, eps);
+}
+*/
+
+
+
+INSOLID_TYPE Polyhedra :: VecInSolid2 (const Point<3> & p,
+				       const Vec<3> & v1,
+				       const Vec<3> & v2,
+				       double eps) const
+{
+  //(*testout) << "VecInSolid2 eps " << eps << endl;
+  INSOLID_TYPE res = VecInSolid(p,v1,eps);
+  //(*testout) << "VecInSolid = " <<res <<endl;
+
+  if(res != DOES_INTERSECT)
+    return res;
+
+  int point_on_n_faces = 0;
+
+  Vec<3> v1n = v1;
+  v1n.Normalize();
+  Vec<3> v2n = v2 - (v2 * v1n) * v1n;
+  v2n.Normalize();
+
+  double cosv2, cosv2max = -1;
+
+  
+  for (int i = 0; i < faces.Size(); i++)
+    {
+      const Point<3> & p1 = points[faces[i].pnums[0]];
+      
+      Vec<3> v0 = p - p1;
+      if (fabs (faces[i].nn * v0) > eps) continue; // n->nn
+      if (fabs (v1n * faces[i].nn) > eps_base1) continue; // n->nn
+
+      double lam1 = (faces[i].w1 * v0);
+      double lam2 = (faces[i].w2 * v0);
+
+      if (lam1 >= -eps_base1 && lam2 >= -eps_base1 && lam1+lam2 <= 1+eps_base1)
+	{
+	  // v1 is in face
+
+	  Point<3> fc = Center (points[faces[i].pnums[0]],
+				points[faces[i].pnums[1]],
+				points[faces[i].pnums[2]]);
+
+	  Vec<3> vpfc = fc - p;
+	  cosv2 = (v2n * vpfc) / vpfc.Length();
+	  if (cosv2 > cosv2max)
+	    {
+	      cosv2max = cosv2;
+	      point_on_n_faces++;
+
+	      double scal2 = v2n * faces[i].nn; // n->nn
+	      res = DOES_INTERSECT;
+	      if (scal2 > eps_base1) res = IS_OUTSIDE;
+	      if (scal2 < -eps_base1) res = IS_INSIDE;
+
+	    }
+	}
+    }
+
+  if (point_on_n_faces >= 1)
+    return res;
+
+  (*testout) << "primitive::vecinsolid2 makes nonsense for polyhedra" << endl;
+  cerr << "primitive::vecinsolid2 makes nonsense for polyhedra" << endl;
+
+  return Primitive :: VecInSolid2 (p, v1, v2, eps);
+}
+
+
+
+void Polyhedra :: GetTangentialVecSurfaceIndices2 (const Point<3> & p, const Vec<3> & v1, const Vec<3> & v2,
+						   Array<int> & surfind, double eps) const
+{
+  Vec<3> v1n = v1;
+  v1n.Normalize();
+  Vec<3> v2n = v2; //  - (v2 * v1n) * v1n;
+  v2n.Normalize();
+
+
+  for (int i = 0; i < faces.Size(); i++)
+    {
+      const Point<3> & p1 = points[faces[i].pnums[0]];
+      
+      Vec<3> v0 = p - p1;
+      if (fabs (v0 * faces[i].nn) > eps) continue; // n->nn
+      if (fabs (v1n * faces[i].nn) > eps_base1) continue; // n->nn
+      if (fabs (v2n * faces[i].nn) > eps_base1) continue; // n->nn
+
+      double lam01 = (faces[i].w1 * v0);
+      double lam02 = (faces[i].w2 * v0);
+      double lam03 = 1-lam01-lam02;
+      double lam11 = (faces[i].w1 * v1);
+      double lam12 = (faces[i].w2 * v1);
+      double lam13 = -lam11-lam12;
+      double lam21 = (faces[i].w1 * v2);
+      double lam22 = (faces[i].w2 * v2);
+      double lam23 = -lam21-lam22;
+
+      bool ok1 = lam01 > eps_base1 ||
+	(lam01 > -eps_base1 && lam11 > eps_base1) ||
+	(lam01 > -eps_base1 && lam11 > -eps_base1 && lam21 > eps_base1);
+
+      bool ok2 = lam02 > eps_base1 ||
+	(lam02 > -eps_base1 && lam12 > eps_base1) ||
+	(lam02 > -eps_base1 && lam12 > -eps_base1 && lam22 > eps_base1);
+      
+      bool ok3 = lam03 > eps_base1 ||
+	(lam03 > -eps_base1 && lam13 > eps_base1) ||
+	(lam03 > -eps_base1 && lam13 > -eps_base1 && lam23 > eps_base1);
+
+      if (ok1 && ok2 && ok3)
+	{
+	  if (!surfind.Contains (GetSurfaceId(faces[i].planenr)))
+	    surfind.Append (GetSurfaceId(faces[i].planenr));
+	}
+    }  
+}
+
+
+
+
+
+
+
+
+
+
+
+
+void Polyhedra :: GetPrimitiveData (const 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)
+{
+  for (int i = 0; i < planes.Size(); i++)
+    surfaceactive[i] = 0;
+
+  for (int i = 0; i < faces.Size(); i++)
+    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)
+{
+  if(points.Size() == 0)
+    poly_bbox.Set(p);
+  else
+    poly_bbox.Add(p);
+
+  return points.Append (p);
+}
+
+int Polyhedra :: AddFace (int pi1, int pi2, int pi3, int inputnum)
+{
+  (*testout) << "polyhedra, add face " << pi1 << ", " << pi2 << ", " << pi3 << endl;
+
+  if(pi1 == pi2 || pi2 == pi3 || pi3 == pi1)
+    {
+      ostringstream msg;
+      msg << "Illegal point numbers for polyhedron face: " << pi1+1 << ", " << pi2+1 << ", " << pi3+1;
+      throw NgException(msg.str());
+    }
+
+  faces.Append (Face (pi1, pi2, pi3, points, inputnum));
+  
+  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 (int i = 0; i < planes.Size(); i++)
+//     if (pl.IsIdentic (*planes[i], inverse, 1e-9*max3(v1.Length(),v2.Length(),Dist(p2,p3))))
+//       {
+// 	if (!inverse)
+// 	  identicto = i;
+//       }
+//   //  cout << "is identic = " << identicto << endl;
+//   identicto = -1;    // changed April 10, JS
+
+//   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;
+    }
+
+//  (*testout) << "is plane nr " << faces.Last().planenr << endl;
+
+  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;
+}
+
+
+void Polyhedra :: GetPolySurfs(Array < Array<int> * > & polysurfs)
+{
+  int maxnum = -1;
+  
+  for(int i = 0; i<faces.Size(); i++)
+    {
+      if(faces[i].inputnr > maxnum)
+	maxnum = faces[i].inputnr;
+    }
+  
+  polysurfs.SetSize(maxnum+1);
+  for(int i=0; i<polysurfs.Size(); i++)
+    polysurfs[i] = new Array<int>;
+
+  for(int i = 0; i<faces.Size(); i++)
+    polysurfs[faces[i].inputnr]->Append(faces[i].planenr);
+}
+
+
+void Polyhedra::CalcSpecialPoints (Array<Point<3> > & pts) const
+{
+  for (int i = 0; i < points.Size(); i++)
+    pts.Append (points[i]);
+}
+
+
+void Polyhedra :: AnalyzeSpecialPoint (const Point<3> & /* pt */, 
+				       Array<Point<3> > & /* specpts */) const
+{
+  ;
+}
+
+Vec<3> Polyhedra :: SpecialPointTangentialVector (const Point<3> & p, int s1, int s2) const
+{
+  const double eps = 1e-10*poly_bbox.Diam();
+
+  for (int fi1 = 0; fi1 < faces.Size(); fi1++)
+    for (int fi2 = 0; fi2 < faces.Size(); fi2++)
+      {
+	int si1 = faces[fi1].planenr;
+	int si2 = faces[fi2].planenr;
+
+	if (surfaceids[si1] != s1 || surfaceids[si2] != s2) continue;
+
+	//(*testout) << "check pair fi1/fi2 " << fi1 << "/" << fi2 << endl;
+	
+	Vec<3> n1 = GetSurface(si1) . GetNormalVector (p);
+	Vec<3> n2 = GetSurface(si2) . GetNormalVector (p);
+	Vec<3> t = Cross (n1, n2);
+
+	//(*testout) << "t = " << t << endl;
+
+
+	/*
+	int samepts = 0;
+	for (int j = 0; j < 3; j++)
+	  for (int k = 0; k < 3; k++)
+	    if (Dist(points[faces[fi1].pnums[j]],
+		     points[faces[fi2].pnums[k]]) < eps)
+	      samepts++;
+	if (samepts < 2) continue;
+	*/
+
+	bool shareedge = false;
+	for(int j = 0; !shareedge && j < 3; j++)
+	  {
+	    Vec<3> v1 = points[faces[fi1].pnums[(j+1)%3]] - points[faces[fi1].pnums[j]];
+	    double smax = v1.Length();
+	    v1 *= 1./smax;
+	    
+	    int pospos;
+	    if(fabs(v1(0)) > 0.5)
+	      pospos = 0;
+	    else if(fabs(v1(1)) > 0.5)
+	      pospos = 1;
+	    else
+	      pospos = 2;
+
+	    double sp = (p(pospos) - points[faces[fi1].pnums[j]](pospos)) / v1(pospos);
+	    if(sp < -eps || sp > smax+eps)
+	      continue;
+
+	    for (int k = 0; !shareedge && k < 3; k ++)
+	      {
+		 Vec<3> v2 = points[faces[fi2].pnums[(k+1)%3]] - points[faces[fi2].pnums[k]];
+		 v2.Normalize();
+		 if(v2 * v1 > 0)
+		   v2 -= v1;
+		 else
+		   v2 += v1;
+		 
+		 //(*testout) << "v2.Length2() " << v2.Length2() << endl;
+
+		 if(v2.Length2() > 1e-18)
+		   continue;
+
+		 double sa,sb;
+
+		 sa = (points[faces[fi2].pnums[k]](pospos) - points[faces[fi1].pnums[j]](pospos)) / v1(pospos);
+		 sb = (points[faces[fi2].pnums[(k+1)%3]](pospos) - points[faces[fi1].pnums[j]](pospos)) / v1(pospos);
+		 
+
+		 if(Dist(points[faces[fi1].pnums[j]] + sa*v1, points[faces[fi2].pnums[k]]) > eps)
+		   continue;
+
+		 if(sa > sb)
+		   {
+		     double aux = sa; sa = sb; sb = aux;
+		   }
+
+		 //testout->precision(20);
+		 //(*testout) << "sa " << sa << " sb " << sb << " smax " << smax << " sp " << sp  << " v1 " << v1 << endl;
+		 //testout->precision(8);
+
+
+		 shareedge = (sa < -eps && sb > eps) ||
+		   (sa < smax-eps && sb > smax+eps) ||
+		   (sa > -eps && sb < smax+eps);
+
+		 if(!shareedge)
+		   continue;
+
+		 sa = max2(sa,0.);
+		 sb = min2(sb,smax);
+
+		 if(sp < sa+eps)
+		   shareedge = (t * v1 > 0);
+		 else if (sp > sb-eps)
+		   shareedge = (t * v1 < 0);
+		   
+	      }
+	  }
+	if (!shareedge) continue;
+
+	t.Normalize();
+	  
+	
+	return t;
+      }
+
+  return Vec<3> (0,0,0);
+}
+
+
+}
+
+
diff --git a/contrib/Netgen/libsrc/csg/polyhedra.hpp b/contrib/Netgen/libsrc/csg/polyhedra.hpp
new file mode 100644
index 0000000000..0a78504256
--- /dev/null
+++ b/contrib/Netgen/libsrc/csg/polyhedra.hpp
@@ -0,0 +1,104 @@
+#ifndef FILE_POLYHEDRA
+#define FILE_POLYHEDRA
+
+
+/**************************************************************************/
+/* File:   polyhedra.hh                                                   */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   19. Mar. 2000                                                  */
+/**************************************************************************/
+
+namespace netgen
+{
+
+  /*
+
+  Polyhedral primitive
+  
+  */
+
+  class Polyhedra : public Primitive
+  {
+    class Face {
+    public:
+      int pnums[3];
+      int planenr;
+
+      int inputnr;
+
+      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,
+	    int ainputnr);
+    };
+
+    Array<Point<3> > points;
+    Array<Face> faces;
+    Array<Plane*> planes;
+    Box<3> poly_bbox;
+
+    double eps_base1;
+
+  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;
+
+    // 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 void GetTangentialSurfaceIndices (const Point<3> & p, 
+					      Array<int> & surfind, double eps) const;
+
+
+    virtual void GetTangentialVecSurfaceIndices2 (const Point<3> & p, const Vec<3> & v1, const Vec<3> & v2,
+						  Array<int> & surfind, double eps) const;
+
+    virtual void CalcSpecialPoints (Array<Point<3> > & pts) const;
+    virtual void AnalyzeSpecialPoint (const Point<3> & pt, 
+				      Array<Point<3> > & specpts) const;
+    virtual Vec<3> SpecialPointTangentialVector (const Point<3> & p, int s1, int s2) 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 (const 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, int inputnum);
+
+    void GetPolySurfs(Array < Array<int> * > & polysurfs);
+  
+  protected:
+    int FaceBoxIntersection (int fnr, const BoxSphere<3> & box) const;
+    //  void CalcData();
+  };
+
+}
+
+#endif
diff --git a/contrib/Netgen/libsrc/csg/revolution.cpp b/contrib/Netgen/libsrc/csg/revolution.cpp
new file mode 100644
index 0000000000..89863b6dd0
--- /dev/null
+++ b/contrib/Netgen/libsrc/csg/revolution.cpp
@@ -0,0 +1,900 @@
+#include <mystdlib.h>
+
+#include <linalg.hpp>
+#include <csg.hpp>
+
+namespace netgen
+{
+  void RevolutionFace :: Init(void)
+  {
+    const LineSeg<2> * line = dynamic_cast<const LineSeg<2>*>(spline);
+    const SplineSeg3<2> * spline3 = dynamic_cast<const SplineSeg3<2>*>(spline);
+
+    if(line)
+      {
+	checklines_start.Append(new Point<2>(line->StartPI()));
+	checklines_vec.Append(new Vec<2>(line->EndPI() - line->StartPI()));
+	(*checklines_vec.Last()) *= 1./pow(checklines_vec.Last()->Length(),2); //!!
+      }
+    else if (spline3)
+      {
+	checklines_start.Append(new Point<2>(spline3->EndPI()));
+	checklines_start.Append(new Point<2>(spline3->TangentPoint()));
+	checklines_start.Append(new Point<2>(spline3->StartPI()));
+	checklines_vec.Append(new Vec<2>(spline3->StartPI() - spline3->EndPI()));
+	(*checklines_vec.Last()) *= 1./pow(checklines_vec.Last()->Length(),2); //!!
+	checklines_vec.Append(new Vec<2>(spline3->EndPI() - spline3->TangentPoint()));
+	(*checklines_vec.Last()) *= 1./pow(checklines_vec.Last()->Length(),2); //!!
+	checklines_vec.Append(new Vec<2>(spline3->TangentPoint() - spline3->StartPI()));
+	(*checklines_vec.Last()) *= 1./pow(checklines_vec.Last()->Length(),2); //!!
+	
+      }
+    
+    for(int i=0; i<checklines_vec.Size(); i++)
+      {
+	checklines_normal.Append(new Vec<2>);
+	(*checklines_normal.Last())(0) = - (*checklines_vec[i])(1);
+	(*checklines_normal.Last())(1) = (*checklines_vec[i])(0);
+	checklines_normal.Last()->Normalize();
+      }
+  }
+
+  RevolutionFace :: RevolutionFace(const SplineSeg<2> & spline_in,
+				   const Point<3> & p,
+				   const Vec<3> & vec,
+				   bool first,
+				   bool last,
+				   const int id_in) :
+    isfirst(first), islast(last), spline(&spline_in), p0(p), v_axis(vec),  id(id_in)
+  {    
+    deletable = false;
+    Init();
+  }
+
+
+  RevolutionFace :: RevolutionFace(const Array<double> & raw_data)
+  {
+    deletable = true;
+    
+    int pos = 0;
+
+    Array< Point<2> > p(3);
+
+    int stype = int(raw_data[pos]); pos++;
+
+    for(int i=0; i<stype; i++)
+      {
+	p[i](0) = raw_data[pos]; pos++;
+	p[i](1) = raw_data[pos]; pos++;
+      }
+
+    if(stype == 2)
+      {
+	spline = new LineSeg<2>(GeomPoint<2>(p[0],1),
+				GeomPoint<2>(p[1],1));
+	//(*testout) << "appending LineSeg<2> " << p[0] 
+	//	   << " to " << p[1] << endl;
+      }
+    else if(stype == 3)
+      {
+	spline = new SplineSeg3<2>(GeomPoint<2>(p[0],1),
+				   GeomPoint<2>(p[1],1),
+				   GeomPoint<2>(p[2],1));
+	//(*testout) << "appending SplineSeg<3> "
+	//	   << p[0] << " -- " << p[1] << " -- " << p[2] << endl;
+      }
+
+    for(int i=0; i<3; i++)
+      {
+	p0(i) = raw_data[pos];
+	pos++;
+      }
+    for(int i=0; i<3; i++)
+      {
+	v_axis(i) = raw_data[pos];
+	pos++;
+      }
+    isfirst = (raw_data[pos] > 0.9);
+    pos++;
+    islast = (raw_data[pos] < 0.1);
+    pos++;
+    
+
+  }
+
+  
+  RevolutionFace :: ~RevolutionFace()
+  {
+    for(int i=0; i<checklines_start.Size(); i++)
+      {
+	delete checklines_start[i];
+	delete checklines_vec[i];
+	delete checklines_normal[i];
+      }
+
+    if(deletable)
+      delete spline;
+  }
+  
+  void RevolutionFace :: CalcProj(const Point<3> & point3d, Point<2> & point2d,
+				  const Vec<3> & vector3d, Vec<2> & vector2d) const
+  {
+    Vec<3> pmp0 = point3d-p0;
+    CalcProj0(pmp0,point2d);
+    Vec<3> y=pmp0-point2d(0)*v_axis; y.Normalize();
+    vector2d(0) = vector3d*v_axis;
+    vector2d(1) = vector3d*y;
+  }
+  
+
+  void RevolutionFace :: CalcProj(const Point<3> & point3d, Point<2> & point2d) const
+  {
+    Vec<3> pmp0 = point3d-p0;
+    CalcProj0(pmp0,point2d);
+  }
+  
+  void RevolutionFace :: CalcProj0(const Vec<3> & point3d_minus_p0, Point<2> & point2d) const
+  {
+    point2d(0) = point3d_minus_p0 * v_axis;
+    point2d(1) = sqrt( point3d_minus_p0 * point3d_minus_p0 - point2d(0)*point2d(0) );
+  }
+  
+
+  int  RevolutionFace ::IsIdentic (const Surface & s2, int & inv, double eps) const
+  {
+    const RevolutionFace * rev2 = dynamic_cast<const RevolutionFace*>(&s2);
+    
+    if(!rev2) return 0;
+    
+    if(rev2 == this)
+      return 1;
+        
+    return 0;
+  }
+
+  double RevolutionFace :: CalcFunctionValue (const Point<3> & point) const
+  {
+    if(spline_coefficient.Size() == 0)
+      spline->GetCoeff(spline_coefficient);
+
+    Point<2> p;
+    CalcProj(point,p);
+
+    return spline_coefficient(0)*p(0)*p(0) + spline_coefficient(1)*p(1)*p(1)
+      + spline_coefficient(2)*p(0)*p(1) + spline_coefficient(3)*p(0)
+      + spline_coefficient(4)*p(1) + spline_coefficient(5);
+  }
+
+  void RevolutionFace :: CalcGradient (const Point<3> & point, Vec<3> & grad) const
+  {
+    if(spline_coefficient.Size() == 0)
+      spline->GetCoeff(spline_coefficient);
+
+    Vec<3> point_minus_p0 = point-p0;
+
+    Point<2> p;
+    CalcProj0(point_minus_p0,p);
+
+    const double dFdxbar = 2.*spline_coefficient(0)*p(0) + spline_coefficient(2)*p(1) + spline_coefficient(3);
+
+    if(fabs(p(1)) > 1e-10)
+      {
+	const double dFdybar = 2.*spline_coefficient(1)*p(1) + spline_coefficient(2)*p(0) + spline_coefficient(4);
+
+	grad(0) = dFdxbar*v_axis(0) + dFdybar * ( point_minus_p0(0)-v_axis(0)*p(0) )/p(1);
+	grad(1) = dFdxbar*v_axis(1) + dFdybar * ( point_minus_p0(1)-v_axis(1)*p(0) )/p(1);
+	grad(2) = dFdxbar*v_axis(2) + dFdybar * ( point_minus_p0(2)-v_axis(2)*p(0) )/p(1);
+	//(*testout) << "grad1("<<point<<") = " << grad << endl;
+      }
+    else
+      {
+	grad(0) = dFdxbar*v_axis(0);
+	grad(1) = dFdxbar*v_axis(1);
+	grad(2) = dFdxbar*v_axis(2);
+	//(*testout) << "grad2("<<point<<") = " << grad << endl;
+      }
+  }
+
+  
+  void RevolutionFace :: CalcHesse (const Point<3> & point, Mat<3> & hesse) const
+  {
+    if(spline_coefficient.Size() == 0)
+      spline->GetCoeff(spline_coefficient);
+
+    Vec<3> point_minus_p0 = point-p0;
+
+    Point<2> p;
+    CalcProj0(point_minus_p0,p);
+
+
+    if(fabs(p(1)) > 1e-10)
+      {
+	const double dFdybar = 2.*spline_coefficient(1)*p(1) + spline_coefficient(2)*p(0) + spline_coefficient(4);
+	
+	const double aux = -pow(p(1),-3);
+	const double aux0 = point_minus_p0(0) - v_axis(0)*p(0);
+	const double aux1 = point_minus_p0(1) - v_axis(1)*p(0);
+	const double aux2 = point_minus_p0(2) - v_axis(2)*p(0);
+	
+
+	const double dybardx = aux0/p(1);
+	const double dybardy = aux1/p(1);
+	const double dybardz = aux2/p(1);
+    
+	const double dybardxx = aux*aux0*aux0 + (1.-v_axis(0)*v_axis(0))/p(1);
+	const double dybardyy = aux*aux1*aux1 + (1.-v_axis(1)*v_axis(1))/p(1);
+	const double dybardzz = aux*aux2*aux2 + (1.-v_axis(2)*v_axis(2))/p(1);
+	const double dybardxy = aux*aux0*aux1 - v_axis(0)*v_axis(1)/p(1);
+	const double dybardxz = aux*aux0*aux2 - v_axis(0)*v_axis(2)/p(1);
+	const double dybardyz = aux*aux1*aux2 - v_axis(1)*v_axis(2)/p(1);
+	
+	hesse(0,0) = 2.*spline_coefficient(0)*v_axis(0)*v_axis(0) + 2.*spline_coefficient(2)*v_axis(0)*dybardx + 2.*spline_coefficient(1)*dybardx*dybardx
+	  + dFdybar*dybardxx;
+	hesse(1,1) = 2.*spline_coefficient(0)*v_axis(1)*v_axis(1) + 2.*spline_coefficient(2)*v_axis(1)*dybardy + 2.*spline_coefficient(1)*dybardy*dybardy
+	  + dFdybar*dybardyy;
+	hesse(2,2) = 2.*spline_coefficient(0)*v_axis(2)*v_axis(2) + 2.*spline_coefficient(2)*v_axis(2)*dybardz + 2.*spline_coefficient(1)*dybardz*dybardz
+	  + dFdybar*dybardzz;
+	
+	hesse(0,1) = hesse(1,0) = 2.*spline_coefficient(0)*v_axis(0)*v_axis(1) + spline_coefficient(2)*v_axis(0)*dybardy + spline_coefficient(2)*dybardx*v_axis(1)
+	  + 2.*spline_coefficient(2)*dybardx*dybardy + dFdybar*dybardxy;
+	hesse(0,2) = hesse(2,0) = 2.*spline_coefficient(0)*v_axis(0)*v_axis(2) + spline_coefficient(2)*v_axis(0)*dybardz + spline_coefficient(2)*dybardx*v_axis(2)
+	  + 2.*spline_coefficient(2)*dybardx*dybardz + dFdybar*dybardxz;
+	hesse(1,2) = hesse(2,1) = 2.*spline_coefficient(0)*v_axis(1)*v_axis(2) + spline_coefficient(2)*v_axis(1)*dybardz + spline_coefficient(2)*dybardy*v_axis(2)
+	  + 2.*spline_coefficient(2)*dybardy*dybardz + dFdybar*dybardyz;
+
+	//(*testout) << "hesse1: " << hesse <<endl;
+      }
+    else if (fabs(spline_coefficient(2)) + fabs(spline_coefficient(4)) < 1.e-9 &&
+	     fabs(spline_coefficient(0)) > 1e-10)
+      {
+	double aux = spline_coefficient(0)-spline_coefficient(1);
+	
+	hesse(0,0) = aux*v_axis(0)*v_axis(0) + spline_coefficient(1);
+	hesse(0,0) = aux*v_axis(1)*v_axis(1) + spline_coefficient(1);
+	hesse(0,0) = aux*v_axis(2)*v_axis(2) + spline_coefficient(1);
+
+	hesse(0,1) = hesse(1,0) = aux*v_axis(0)*v_axis(1);
+	hesse(0,2) = hesse(2,0) = aux*v_axis(0)*v_axis(2);
+	hesse(1,2) = hesse(2,1) = aux*v_axis(1)*v_axis(2);
+	//(*testout) << "hesse2: " << hesse <<endl;
+	
+      }
+    else if (fabs(spline_coefficient(1)) + fabs(spline_coefficient(3)) + fabs(spline_coefficient(4)) + fabs(spline_coefficient(5)) < 1.e-9) // line
+      {
+	hesse = 0;
+	//(*testout) << "hesse3: " << hesse <<endl;
+      }
+    else
+      {
+	(*testout) << "hesse4: " << hesse <<endl;
+      }
+  }
+
+  
+
+  double RevolutionFace ::HesseNorm () const
+  {
+    if (fabs(spline_coefficient(1)) + fabs(spline_coefficient(3)) + fabs(spline_coefficient(4)) + fabs(spline_coefficient(5)) < 1.e-9) // line
+      return 0;
+      
+    if (fabs(spline_coefficient(2)) + fabs(spline_coefficient(4)) < 1.e-9 &&
+	fabs(spline_coefficient(0)) > 1e-10)
+      return 2.*max2(fabs(spline_coefficient(0)),fabs(spline_coefficient(1)));
+
+
+    double alpha = fabs(spline_coefficient(2)*(spline->StartPI()(0)-spline->EndPI()(0))) /
+      max2(fabs(spline->StartPI()(1)),fabs(spline->EndPI()(1)));
+
+    return max2(2.*fabs(spline_coefficient(0))+sqrt(2.)*fabs(spline_coefficient(2)),
+		2.*fabs(spline_coefficient(1))+spline_coefficient(2)+1.5*alpha);
+  }
+
+  double  RevolutionFace :: MaxCurvature() const
+  {
+    double retval = spline->MaxCurvature();
+
+    Array < Point<2> > checkpoints;
+
+    const SplineSeg3<2> * ss3 = dynamic_cast<const SplineSeg3<2> *>(spline);
+    const LineSeg<2> * ls = dynamic_cast<const LineSeg<2> *>(spline);
+    
+    if(ss3)
+      {
+	checkpoints.Append(ss3->StartPI());
+	checkpoints.Append(ss3->TangentPoint());
+	checkpoints.Append(ss3->TangentPoint());
+	checkpoints.Append(ss3->EndPI());
+      }
+    else if(ls)
+      {
+	checkpoints.Append(ls->StartPI());
+	checkpoints.Append(ls->EndPI());
+      }
+
+    for(int i=0; i<checkpoints.Size(); i+=2)
+      {
+	Vec<2> v = checkpoints[i+1]-checkpoints[i];
+	Vec<2> n(v(1),-v(0)); n.Normalize();
+
+	//if(ss3)
+	//  (*testout) << "n " << n << endl;
+
+	if(fabs(n(1)) < 1e-15)
+	  continue;
+
+	double t1 = -checkpoints[i](1)/n(1);
+	double t2 = -checkpoints[i+1](1)/n(1);
+	
+	double c1 = (t1 > 0) ? (1./t1) : -1;
+	double c2 = (t2 > 0) ? (1./t2) : -1;
+	
+	//if(ss3)
+	//  (*testout) << "t1 " << t1 << " t2 " << t2 << " c1 " << c1 << " c2 " << c2 << endl;
+
+	if(c1 > retval)
+	  retval = c1;
+	if(c2 > retval)
+	  retval = c2;
+      }
+	
+    //if(ss3)
+    //  (*testout) << "curvature " << retval << endl;
+
+    return retval;
+
+    /*
+
+
+    // find smallest y value of spline:
+    Array<double> testt;
+
+    if(!isfirst)
+      testt.Append(0);
+    if(!islast)
+      testt.Append(1);
+    
+    const SplineSegment3 * s3 = dynamic_cast<const SplineSegment3 *>(&spline);
+
+    if(s3)
+      {
+	double denom = (2.-sqrt(2.))*(s3->EndPI()(1) - s3->StartPI()(1));
+	
+	if(fabs(denom) < 1e-20)
+	  testt.Append(0.5);
+	else
+	  {
+	    double sD = sqrt(pow(s3->TangentPoint()(1) - s3->StartPI()(1),2)+
+			     pow(s3->TangentPoint()(1) - s3->EndPI()(1),2));
+	    testt.Append((s3->StartPI()(1)*(sqrt(2.)-1.) - sqrt(2.)*s3->TangentPoint()(1) + s3->EndPI()(1) + sD)/denom);
+	    testt.Append((s3->StartPI()(1)*(sqrt(2.)-1.) - sqrt(2.)*s3->TangentPoint()(1) + s3->EndPI()(1) - sD)/denom);
+	  }	
+      }
+
+    double miny = fabs(spline.GetPoint(testt[0])(1));
+    for(int i=1; i<testt.Size(); i++)
+      {
+	double thisy = fabs(spline.GetPoint(testt[i])(1));
+	if(thisy < miny)
+	  miny = thisy;
+      }
+
+    return max2(splinecurvature,1./miny);
+    */
+  }
+
+  void RevolutionFace :: Project (Point<3> & p) const
+  {
+    Point<2> p2d;
+
+    CalcProj(p,p2d);
+
+    const Vec<3> y = (p-p0)-p2d(0)*v_axis;
+    const double yl = y.Length();
+
+    double dummy;
+
+    spline->Project(p2d,p2d,dummy);
+
+    p = p0 + p2d(0)*v_axis;
+
+    if(yl > 1e-20*Dist(spline->StartPI(),spline->EndPI()))
+      p+= (p2d(1)/yl)*y;
+  }
+
+
+
+  
+  Point<3>  RevolutionFace :: GetSurfacePoint () const
+  {
+    Vec<3> random_vec(0.760320,-0.241175,0.60311534);
+
+    Vec<3> n = Cross(v_axis,random_vec); n.Normalize();
+
+    Point<2> sp = spline->GetPoint(0.5);
+
+    Point<3> retval = p0 + sp(0)*v_axis + sp(1)*n;
+
+    return retval;
+  }
+
+
+  void RevolutionFace :: Print (ostream & str) const
+  {
+    if(spline_coefficient.Size() == 0)
+      spline->GetCoeff(spline_coefficient);
+
+    str << p0(0) << " " << p0(1) << " " << p0(2) << " "
+	<< v_axis(0) << " " << v_axis(1) << " " << v_axis(2) << " ";
+    for(int i=0; i<6; i++) str << spline_coefficient(i) << " ";
+    str << endl;
+  }
+
+
+  void RevolutionFace :: GetTriangleApproximation (TriangleApproximation & tas, 
+						   const Box<3> & boundingbox, 
+						   double facets) const
+  {
+    Vec<3> random_vec(0.760320,-0.241175,0.60311534);
+
+    Vec<3> v1 = Cross(v_axis,random_vec); v1.Normalize();
+    Vec<3> v2 = Cross(v1,v_axis); v2.Normalize();
+
+    int n = int(2.*facets) + 1;
+
+    for(int i=0; i<=n; i++)
+      {
+	Point<2> sp = spline->GetPoint(double(i)/double(n));
+	for(int j=0; j<=n; j++)
+	  {
+	    double phi = 2.*M_PI*double(j)/double(n);
+	    
+	    Point<3> p = p0 + sp(0)*v_axis + sp(1)*cos(phi)*v1 + sp(1)*sin(phi)*v2;
+	    tas.AddPoint(p);   
+	  }
+      }
+    
+    for(int i=0; i<n; i++)
+      for(int j=0; j<n; j++)
+	{
+	  int pi = (n+1)*i+j;
+
+	  tas.AddTriangle( TATriangle (id, pi,pi+1,pi+n+1));
+	  tas.AddTriangle( TATriangle (id, pi+1,pi+n+1,pi+n+2));
+	}
+  }
+  
+
+  bool RevolutionFace :: BoxIntersectsFace(const Box<3> & box) const
+  {
+    Point<3> center = box.Center();
+
+    Project(center);
+
+    return (Dist(box.Center(),center) < 0.5*box.Diam());
+  }
+
+
+  /*
+  bool RevolutionFace :: BoxIntersectsFace (const BoxSphere<3> & box, bool & uncertain) const
+  {
+    Point<2> c,pmin,pmax;
+    CalcProj(box.Center(),c);
+    double aux = box.Diam()/sqrt(8.);
+    pmin(0) = c(0)-aux; pmin(1) = c(1)-aux;
+    pmax(0) = c(0)+aux; pmax(1) = c(1)+aux;
+    
+    BoxSphere<2> box2d(pmin,pmax);
+    return BoxIntersectsFace(box2d, uncertain);
+  }
+
+  bool RevolutionFace :: BoxIntersectsFace (const BoxSphere<2> & box, bool & uncertain) const
+  {
+    const LineSegment * line = dynamic_cast<const LineSegment*>(&spline);
+    const SplineSegment3 * spline3 = dynamic_cast<const SplineSegment3*>(&spline);
+
+    bool always_right = true, always_left = true;
+
+    bool retval = false;
+    bool thisint;
+    bool intdirect = false;
+    bool inttangent = false;
+    uncertain = false;
+
+    if(line) inttangent = true;
+  
+    for(int i=0; i<checklines_start.Size(); i++)
+      {
+	Vec<2> b = box.Center()- (*checklines_start[i]);
+
+	double d;
+
+	double checkdist = b * (*checklines_vec[i]);
+	double ncomp = b * (*checklines_normal[i]);
+
+	if(checkdist < 0)
+	  d = b.Length();
+	else if (checkdist > 1)
+	  {
+	    if(spline3)
+	      d = Dist(box.Center(),*checklines_start[(i+1)%3]);
+	    else
+	      d = Dist(box.Center(),(*checklines_start[i]) 
+		       + pow(checklines_vec[i]->Length(),2)*(*checklines_vec[i]));
+	  }
+	else 
+	  d = fabs(ncomp);
+	  
+	thisint = (box.Diam() >= 2.*d);
+	retval = retval || thisint;
+	if(thisint)
+	  {
+	    if(i==0)
+	      intdirect = true;
+	    else
+	      inttangent = true;
+	  }
+
+	if(ncomp > 0) always_right = false;
+	else if(ncomp < 0) always_left = false;
+      }
+
+    if(retval && !(intdirect && inttangent))
+      uncertain = true;
+
+    if(!retval && spline3 && (always_right || always_left))
+      {
+	retval = true;
+	uncertain = true;
+      }
+    
+    return retval;	
+  }  
+  */
+  
+
+  INSOLID_TYPE RevolutionFace :: PointInFace (const Point<3> & p, const double eps) const
+  {
+    Point<2> p2d;
+    CalcProj(p,p2d);
+
+    double val = spline_coefficient(0)*p2d(0)*p2d(0) + spline_coefficient(1)*p2d(1)*p2d(1) + spline_coefficient(2)*p2d(0)*p2d(1) +
+      spline_coefficient(3)*p2d(0) + spline_coefficient(4)*p2d(1) + spline_coefficient(5);
+
+    if(val > eps)
+      return IS_OUTSIDE;
+    if(val < -eps)
+      return IS_INSIDE;
+     
+    return DOES_INTERSECT;
+  }
+
+  
+
+  void RevolutionFace :: GetRawData(Array<double> & data) const
+  {
+    data.DeleteAll();
+    spline->GetRawData(data);
+    for(int i=0; i<3; i++)
+      data.Append(p0(i));
+    for(int i=0; i<3; i++)
+      data.Append(v_axis(i));
+    data.Append((isfirst) ? 1. : 0.);
+    data.Append((islast) ? 1. : 0.);
+  }
+
+
+
+  Revolution :: Revolution(const Point<3> & p0_in,
+			   const Point<3> & p1_in,
+			   const SplineGeometry<2> & spline_in) :
+    p0(p0_in), p1(p1_in), splinecurve(spline_in),
+    nsplines(spline_in.GetNSplines())
+  {
+    surfaceactive.SetSize(0);
+    surfaceids.SetSize(0);
+
+    v_axis = p1-p0;
+
+    v_axis.Normalize();
+
+    if(splinecurve.GetSpline(0).StartPI()(1) <= 0. &&
+       splinecurve.GetSpline(nsplines-1).EndPI()(1) <= 0.)
+      type = 2;
+    else if (Dist(splinecurve.GetSpline(0).StartPI(),
+		  splinecurve.GetSpline(nsplines-1).EndPI()) < 1e-7)
+      type = 1;
+    else
+      cerr << "Surface of revolution cannot be constructed" << endl;
+
+    for(int i=0; i<splinecurve.GetNSplines(); i++)
+      {
+	RevolutionFace * face = new RevolutionFace(splinecurve.GetSpline(i),
+						   p0,v_axis,
+						   type==2 && i==0,
+						   type==2 && i==splinecurve.GetNSplines()-1);
+	faces.Append(face);
+	surfaceactive.Append(1);
+	surfaceids.Append(0);
+      }
+  }
+  
+  Revolution::~Revolution()
+  {
+    for(int i=0; i<faces.Size(); i++)
+      delete faces[i];
+  }
+
+
+  INSOLID_TYPE Revolution :: BoxInSolid (const BoxSphere<3> & box) const
+  {
+    for(int i=0; i<faces.Size(); i++)
+      if(faces[i]->BoxIntersectsFace(box))
+	return DOES_INTERSECT;
+    
+    
+    return PointInSolid(box.Center(),0);
+	 
+
+    /*
+    Point<2> c,pmin,pmax;
+    faces[0]->CalcProj(box.Center(),c);
+    double aux = box.Diam()/sqrt(8.);
+    pmin(0) = c(0)-aux; pmin(1) = c(1)-aux;
+    pmax(0) = c(0)+aux; pmax(1) = c(1)+aux;
+    
+
+    BoxSphere<2> box2d(pmin,pmax);
+
+    bool intersection = false;
+    bool uncertain = true;
+
+    for(int i=0; !(intersection && !uncertain) && i<faces.Size(); i++)
+      {
+	bool thisintersects;
+	bool thisuncertain;
+	thisintersects = faces[i]->BoxIntersectsFace(box2d,thisuncertain);
+	intersection = intersection || thisintersects;
+	if(thisintersects && !thisuncertain)
+	  uncertain = false;
+      }
+
+    if(intersection)
+      {
+	if(!uncertain)
+	  return DOES_INTERSECT;
+	else
+	  {
+	    Array < Point<3> > pext(2);
+	    Point<3> p;
+
+	    pext[0] = box.PMin();
+	    pext[1] = box.PMax();
+
+	    INSOLID_TYPE position;
+	    bool firsttime = true;
+
+	    for(int i=0; i<2; i++)
+	      for(int j=0; j<2; j++)
+		for(int k=0; k<2; k++)
+		  {
+		    p(0) = pext[i](0);
+		    p(1) = pext[j](1);
+		    p(2) = pext[k](2);
+		    INSOLID_TYPE ppos = PointInSolid(p,0);
+		    if(ppos == DOES_INTERSECT)
+		      return DOES_INTERSECT;
+		    
+		    if(firsttime)
+		      {
+			firsttime = false;
+			position = ppos;
+		      }
+		    if(position != ppos)
+		      return DOES_INTERSECT;	    
+		  }
+	    return position;
+
+	  }
+      }
+
+    return PointInSolid(box.Center(),0);
+    */ 
+  }
+
+  INSOLID_TYPE Revolution :: PointInSolid (const Point<3> & p,
+					   double eps) const
+  {
+    Point<2> p2d;
+    faces[0]->CalcProj(p,p2d);
+
+    int intersections_before(0), intersections_after(0);
+    double randomx = 7.42357;
+    double randomy = 1.814756;
+    randomx *= 1./sqrt(randomx*randomx+randomy*randomy);
+    randomy *= 1./sqrt(randomx*randomx+randomy*randomy);
+    
+
+    const double a = randomy;
+    const double b = -randomx;
+    const double c = -a*p2d(0)-b*p2d(1);
+
+    Array < Point<2> > points;
+
+    //(*testout) << "face intersections at: " << endl;
+    for(int i=0; i<faces.Size(); i++)
+      {
+	faces[i]->GetSpline().LineIntersections(a,b,c,points,eps);
+	
+	for(int j=0; j<points.Size(); j++)
+	  {
+	    double t = (points[j](0)-p2d(0))/randomx;
+
+	    //(*testout) << t << endl;
+	    if ( t < -eps )
+	      intersections_before++;
+	    else if ( t > eps )
+	      intersections_after++;
+	    else
+	      {
+		intersecting_face = i;
+		return DOES_INTERSECT;
+	      }
+	  }
+      }
+
+    if(intersections_before % 2 == 0)
+      return IS_OUTSIDE;
+    else
+      return IS_INSIDE;
+  }
+
+  INSOLID_TYPE Revolution :: VecInSolid (const Point<3> & p,
+					 const Vec<3> & v,
+					 double eps) const
+  {
+    INSOLID_TYPE pInSolid = PointInSolid(p,eps);
+
+    if(pInSolid != DOES_INTERSECT)
+      {
+	//(*testout) << "pInSolid" << endl;
+	return pInSolid;
+      }
+
+    Array<int> intersecting_faces;
+
+    for(int i=0; i<faces.Size(); i++)
+      if(faces[i]->PointInFace(p,eps) == DOES_INTERSECT)
+	intersecting_faces.Append(i);
+
+     Vec<3> hv;
+
+    if(intersecting_faces.Size() == 1)
+      {
+	faces[intersecting_faces[0]]->CalcGradient(p,hv);
+
+	double hv1;
+	hv1 = v * hv;
+	
+	if (hv1 <= -eps)
+	  return IS_INSIDE;
+	if (hv1 >= eps)
+	  return IS_OUTSIDE;
+	
+	return DOES_INTERSECT; 
+      }
+    else if(intersecting_faces.Size() == 2)
+      {
+	Point<2> p2d;
+	Vec<2> v2d;
+	faces[intersecting_faces[0]]->CalcProj(p,p2d,v,v2d);
+
+	if(Dist(faces[intersecting_faces[0]]->GetSpline().StartPI(),p2d) <
+	   Dist(faces[intersecting_faces[0]]->GetSpline().EndPI(),p2d))
+	  {
+	    int aux = intersecting_faces[0];
+	    intersecting_faces[0] = intersecting_faces[1];
+	    intersecting_faces[1] = aux;
+	  }
+	
+	const SplineSeg3<2> * splinesegment3 = 
+	  dynamic_cast<const SplineSeg3<2> *>(&faces[intersecting_faces[0]]->GetSpline());
+	const LineSeg<2> * linesegment = 
+	  dynamic_cast<const LineSeg<2> *>(&faces[intersecting_faces[0]]->GetSpline());
+		
+	Vec<2> t1,t2;
+
+	if(linesegment)
+	  t1 = linesegment->StartPI() - linesegment->EndPI();
+	else if(splinesegment3)
+	  t1 = splinesegment3->TangentPoint() - splinesegment3->EndPI();
+
+	linesegment = 
+	  dynamic_cast<const LineSeg<2> *>(&faces[intersecting_faces[1]]->GetSpline());
+	splinesegment3 = 
+	  dynamic_cast<const SplineSeg3<2> *>(&faces[intersecting_faces[1]]->GetSpline());
+	
+	if(linesegment)
+	  t2 = linesegment->EndPI() - linesegment->StartPI();
+	else if(splinesegment3)
+	  t2 = splinesegment3->TangentPoint() - splinesegment3->StartPI();
+
+	t1.Normalize();
+	t2.Normalize();
+
+	double d1 = v2d*t1;
+	double d2 = v2d*t2;
+
+	Vec<2> n;
+
+	if(d1 > d2)
+	  {
+	    n(0) = t1(1);
+	    n(1) = -t1(0);
+	  }
+	else
+	  {
+	    n(0) = -t2(1);
+	    n(1) = t2(0);
+	  }
+
+	double d = v2d*n;
+
+	if(d > eps)
+	  return IS_OUTSIDE;
+	else if (d < -eps)
+	  return IS_INSIDE;
+	else
+	  return DOES_INTERSECT;
+
+
+      }
+    else
+      {
+	cerr << "Jo gibt's denn des?" << endl;
+      }
+
+    return DOES_INTERSECT;    
+  }
+
+  INSOLID_TYPE Revolution :: VecInSolid2 (const Point<3> & p,
+					  const Vec<3> & v1,
+					  const Vec<3> & v2,
+					  double eps) const
+  {
+    INSOLID_TYPE ret1 = VecInSolid(p,v1,eps);
+    if(ret1 != DOES_INTERSECT)
+      return ret1;
+
+    return VecInSolid(p,v1+0.01*v2,eps);
+  }
+  
+  int Revolution :: GetNSurfaces() const
+  {
+    return faces.Size();
+  }
+
+  Surface & Revolution :: GetSurface (int i)
+  {
+    return *faces[i];
+  }
+
+  const Surface & Revolution :: GetSurface (int i) const
+  {
+    return *faces[i];
+  }
+
+
+  void Revolution :: Reduce (const BoxSphere<3> & box)
+  { 
+    //bool dummy;
+    for(int i=0; i<faces.Size(); i++)
+      surfaceactive[i] = (faces[i]->BoxIntersectsFace(box));
+    //surfaceactive[i] = (faces[i]->BoxIntersectsFace(box,dummy));
+  }
+
+  void Revolution :: UnReduce ()
+  {
+    for(int i=0; i<faces.Size(); i++)
+      surfaceactive[i] = true;
+  }
+}
diff --git a/contrib/Netgen/libsrc/csg/revolution.hpp b/contrib/Netgen/libsrc/csg/revolution.hpp
new file mode 100644
index 0000000000..f1c719febb
--- /dev/null
+++ b/contrib/Netgen/libsrc/csg/revolution.hpp
@@ -0,0 +1,153 @@
+#ifndef _REVOLUTION_HPP
+#define _REVOLUTION_HPP
+
+namespace netgen
+{
+
+  class Revolution;
+
+  class RevolutionFace : public Surface
+  {
+  private:
+    bool isfirst, islast;
+    const SplineSeg<2> * spline;
+    bool deletable;
+
+    Point<3> p0;
+    Vec<3> v_axis;
+
+    int id;
+  
+    mutable Vector spline_coefficient;
+
+
+    Array < Vec<2>* > checklines_vec;
+    Array < Point<2>* > checklines_start;
+    Array < Vec<2>* > checklines_normal;
+  
+  private:
+    void Init (void);
+
+  public:
+    void CalcProj(const Point<3> & point3d, Point<2> & point2d) const;
+    void CalcProj(const Point<3> & point3d, Point<2> & point2d,
+		  const Vec<3> & vector3d, Vec<2> & vector2d) const;
+    void CalcProj0(const Vec<3> & point3d_minus_p0, Point<2> & point2d) const;
+
+  public:
+    RevolutionFace(const SplineSeg<2> & spline_in,
+		   const Point<3> & p,
+		   const Vec<3> & vec,
+		   bool first = false,
+		   bool last = false,
+		   const int id_in = 0);
+
+    RevolutionFace(const Array<double> & raw_data);
+
+    ~RevolutionFace();
+
+    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 double MaxCurvature () const;
+    //virtual double MaxCurvatureLoc (const Point<3> & /* c */ , 
+    //				  double /* rad */) const;
+
+    virtual void Project (Point<3> & p) const;
+
+    virtual Point<3> GetSurfacePoint () const;
+    virtual void Print (ostream & str) const;
+  
+    virtual void GetTriangleApproximation (TriangleApproximation & tas, 
+					   const Box<3> & boundingbox, 
+					   double facets) const;
+
+    bool BoxIntersectsFace (const Box<3> & box) const;
+    /*
+      bool BoxIntersectsFace (const BoxSphere<2> & box, bool & uncertain) const;
+      bool BoxIntersectsFace (const BoxSphere<3> & box, bool & uncertain) const;
+    */
+
+    const SplineSeg<2> & GetSpline(void) const {return *spline;}
+
+    INSOLID_TYPE PointInFace (const Point<3> & p, const double eps) const;
+
+    void GetRawData(Array<double> & data) const;
+
+  };
+
+
+
+  /*
+
+  Primitive of revolution
+  
+  */
+
+
+  class Revolution : public Primitive
+  {
+  private:
+    Point<3> p0,p1;
+    Vec<3> v_axis;
+    const SplineGeometry<2> & splinecurve;
+    const int nsplines;
+
+    // 1 ... torus-like
+    // 2 ... sphere-like
+    int type;
+  
+
+    Array<RevolutionFace*> faces;
+
+    mutable int intersecting_face;
+
+  public:
+    Revolution(const Point<3> & p0_in,
+	       const Point<3> & p1_in,
+	       const SplineGeometry<2> & spline_in);
+
+    ~Revolution();
+  
+  
+    /*
+      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;
+    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;
+
+    // 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;
+    virtual Surface & GetSurface (int i = 0);
+    virtual const Surface & GetSurface (int i = 0) const;
+
+
+    virtual void Reduce (const BoxSphere<3> & box);
+    virtual void UnReduce ();
+  
+	     
+  };
+
+}
+
+
+#endif
diff --git a/contrib/Netgen/libsrc/csg/singularref.cpp b/contrib/Netgen/libsrc/csg/singularref.cpp
new file mode 100644
index 0000000000..0ad13db9cf
--- /dev/null
+++ b/contrib/Netgen/libsrc/csg/singularref.cpp
@@ -0,0 +1,217 @@
+#include <mystdlib.h>
+#include <myadt.hpp>
+
+#include <linalg.hpp>
+#include <csg.hpp>
+#include <meshing.hpp>
+
+namespace netgen
+{
+
+  SingularEdge :: SingularEdge (double abeta, int adomnr, 
+                                const CSGeometry & ageom,
+                                const Solid * asol1, 
+                                const Solid * asol2, double sf,
+                                const double maxh_at_initialization)
+    : domnr(adomnr), geom(ageom)
+  {
+  beta = abeta;
+  maxhinit = maxh_at_initialization;
+
+  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;
+  factor = sf; 
+}
+
+void SingularEdge :: FindPointsOnEdge (class Mesh & mesh)
+{
+  (*testout) << "find points on edge" << endl;
+  points.SetSize(0);
+  segms.SetSize(0);
+
+
+  Array<int> si1, si2;
+  sol1->GetSurfaceIndices (si1);
+  sol2->GetSurfaceIndices (si2);
+
+  for (int i = 0; i < si1.Size(); i++)
+    si1[i] = geom.GetSurfaceClassRepresentant(si1[i]);
+  for (int i = 0; i < si2.Size(); i++)
+    si2[i] = geom.GetSurfaceClassRepresentant(si2[i]);
+
+
+  for (SegmentIndex si = 0; si < mesh.GetNSeg(); si++)
+    {
+      INDEX_2 i2 (mesh[si][0], mesh[si][1]);
+      /*
+      
+      bool onedge = 1;
+      for (j = 1; j <= 2; j++)
+	{
+	  const Point<3> p = mesh[ PointIndex (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 (domnr != -1 && domnr != mesh[si].domin && domnr != mesh[si].domout)
+	continue;
+
+      /*
+      bool onedge = 1;
+      for (int j = 0; j < 2; j++)
+	{
+	  int surfi = (j == 0) ? mesh[si].surfnr1 : mesh[si].surfnr2;
+	  surfi = geom.GetSurfaceClassRepresentant(surfi);
+	  if (!si1.Contains(surfi) && !si2.Contains(surfi))
+	    onedge = 0;
+	}
+      */
+      int surfi1 = geom.GetSurfaceClassRepresentant(mesh[si].surfnr1);
+      int surfi2 = geom.GetSurfaceClassRepresentant(mesh[si].surfnr2);
+
+      if ( (si1.Contains(surfi1) && si2.Contains(surfi2)) ||
+           (si1.Contains(surfi2) && si2.Contains(surfi1)) )
+
+	// if (onedge)
+	{
+	  segms.Append (i2);
+	  //	  PrintMessage (5, "sing segment ", i2.I1(), " - ", i2.I2());
+	  points.Append (mesh[ PointIndex (i2.I1())]);
+	  points.Append (mesh[ PointIndex (i2.I2())]);
+	  mesh[si].singedge_left = factor;
+	  mesh[si].singedge_right = factor;
+	}	    
+    }
+  
+  /*
+  (*testout) << "Singular edge points:" << endl;
+  for (int i = 0; i < points.Size(); i++)
+    (*testout) << points[i] << endl;
+  */
+ 
+}
+
+void SingularEdge :: SetMeshSize (class Mesh & mesh, double globalh)
+{
+  double hloc = pow (globalh, 1/beta);
+  if(maxhinit > 0 && maxhinit < hloc)
+    {
+      hloc = maxhinit;
+      if(points.Size() > 1)
+	{
+	  for (int i = 0; i < points.Size()-1; i++)
+	    mesh.RestrictLocalHLine(points[i],points[i+1],hloc);
+	}
+      else
+	{
+	  for (int i = 0; i < points.Size(); i++)
+	    mesh.RestrictLocalH (points[i], hloc);
+	}
+    }
+  else
+    {
+      for (int i = 0; i < points.Size(); i++)
+	mesh.RestrictLocalH (points[i], hloc);
+    }
+}
+
+
+
+SingularPoint :: SingularPoint (double abeta, 
+				const Solid * asol1, 
+				const Solid * asol2,
+				const Solid * asol3, double sf)
+{
+  beta = abeta;
+  sol1 = asol1;
+  sol2 = asol2;
+  sol3 = asol3;
+  factor = sf; 
+}
+
+
+void SingularPoint :: FindPoints (class Mesh & mesh)
+{
+  points.SetSize(0);
+  Array<int> surfk, surf;
+
+
+  for (PointIndex pi = PointIndex::BASE; 
+       pi < mesh.GetNP()+PointIndex::BASE; pi++)
+    {
+      if (mesh[pi].Type() != FIXEDPOINT) continue;
+      const Point<3> p = mesh[pi];
+
+      (*testout) << "check singular point" << p << endl;
+
+      if (sol1->IsIn (p) && sol2->IsIn(p) && sol3->IsIn(p) &&
+	  !sol1->IsStrictIn (p) && !sol2->IsStrictIn(p) && !sol3->IsStrictIn(p))
+	{
+	  surf.SetSize (0);
+	  for (int k = 1; k <= 3; k++)
+	    {
+	      const Solid * solk(NULL);
+	      Solid *tansol;
+	      switch (k)
+		{
+		case 1:  solk = sol1; break;
+		case 2:  solk = sol2; break;
+		case 3:  solk = sol3; break;
+		}
+
+	      solk -> TangentialSolid (p, tansol, surfk, 1e-3);
+	      (*testout) << "Tansol = " << *tansol << endl;
+
+	      if (!tansol) continue;
+
+	      ReducePrimitiveIterator rpi(Box<3> (p-Vec<3> (1e-3,1e-3,1e-3),
+						  p+Vec<3> (1e-3,1e-3,1e-3)));
+	      UnReducePrimitiveIterator urpi;
+	      
+	      tansol -> IterateSolid (rpi);
+	      tansol->GetSurfaceIndices (surfk);
+	      tansol -> IterateSolid (urpi);
+
+	      (*testout) << "surfinds = " << surfk << endl;
+
+	      for (int i = 0; i < surfk.Size(); i++)
+		if (!surf.Contains (surfk[i]))
+		  surf.Append (surfk[i]);
+	      
+	      delete tansol;
+	    }
+
+	  if (surf.Size() < 3) continue;
+
+	  points.Append (p);
+	  PrintMessage (5, "Point (", p(0), ", ", p(1), ", ", p(2), ") is singular");
+	  mesh[pi].Singularity(factor);
+	}
+    }  
+}
+
+
+void SingularPoint :: SetMeshSize (class Mesh & mesh, double globalh)
+{
+  double hloc = pow (globalh, 1/beta);
+  for (int i = 1; i <= points.Size(); i++)
+    mesh.RestrictLocalH (points.Get(i), hloc);  
+}
+}
diff --git a/contrib/Netgen/libsrc/csg/singularref.hpp b/contrib/Netgen/libsrc/csg/singularref.hpp
new file mode 100644
index 0000000000..c029fbef59
--- /dev/null
+++ b/contrib/Netgen/libsrc/csg/singularref.hpp
@@ -0,0 +1,84 @@
+#ifndef FILE_SINGULARREF
+#define FILE_SINGULARREF
+
+/**************************************************************************/
+/* File:   singularref.hh                                                 */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   25. Sep. 99                                                    */
+/**************************************************************************/
+
+namespace netgen
+{
+
+
+  /**
+     Control for local refinement
+  */
+
+
+
+  /**
+     Singular Face.
+     Causes a bounday layer mesh refinement.
+     All elements in subdomain domnr will get a boundary layer
+     on faces sharing the solid sol
+  */
+  class SingularFace 
+  {
+  public:
+    int domnr;
+    const Solid *sol;
+    double factor; 
+    // Array<Point<3> > points;
+    // Array<INDEX_2> segms;
+  public:
+    SingularFace (int adomnr, const Solid * asol, double sf)
+      : domnr(adomnr), sol(asol), factor(sf) { ; }
+    const Solid * GetSolid() const { return sol; }
+    int GetDomainNr () const { return domnr; }
+  };
+
+
+  ///
+  class SingularEdge 
+  {
+  public:
+    double beta;
+    int domnr;
+    const CSGeometry& geom;
+    const Solid *sol1, *sol2;
+    Array<Point<3> > points;
+    Array<INDEX_2> segms;
+    double factor; 
+
+    double maxhinit;
+  public:
+    SingularEdge (double abeta, int adomnr, 
+		  const CSGeometry & ageom,
+		  const Solid * asol1, const Solid * asol2, double sf,
+		  const double maxh_at_initialization = -1);
+    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;
+    double factor; 
+ 
+  public:
+    SingularPoint (double abeta, const Solid * asol1, const Solid * asol2,
+		   const Solid * asol3, double sf);
+    void FindPoints (class Mesh & mesh);
+    void SetMeshSize (class Mesh & mesh, double globalh);
+  };
+
+}
+
+
+#endif
diff --git a/contrib/Netgen/libsrc/csg/solid.cpp b/contrib/Netgen/libsrc/csg/solid.cpp
new file mode 100644
index 0000000000..aba39d8a57
--- /dev/null
+++ b/contrib/Netgen/libsrc/csg/solid.cpp
@@ -0,0 +1,1732 @@
+#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;
+    name = NULL;   
+  }
+
+  Solid :: Solid (optyp aop, Solid * as1, Solid * as2)
+  {
+    op = aop;
+    s1 = as1;
+    s2 = as2;
+    prim = NULL;
+    name = NULL;
+    maxh = 1e10;
+  }
+
+  Solid :: ~Solid ()
+  {
+    // cout << "delete solid, op = " << int(op) << endl;
+    delete [] name;
+
+    switch (op)
+      {
+      case UNION:
+      case SECTION:
+	{
+	  if (s1->op != ROOT) delete s1;
+	  if (s2->op != ROOT) delete s2;
+	  break;
+	}
+      case SUB:
+	// case ROOT:
+	{
+	  if (s1->op != ROOT) delete s1;
+	  break;
+	}
+      case TERM:
+	{
+	  // cout << "has term" << endl;
+	  delete prim;
+	  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(NULL);
+    switch (op)
+      {
+      case TERM: case TERM_REF:
+	{
+	  Primitive * nprim = prim->Copy();
+	  geom.AddSurfaces (nprim);
+	  nsol = new Solid (nprim);
+	  break;
+	}
+
+      case SECTION:
+      case UNION:
+	{
+	  nsol = new Solid (op, s1->Copy(geom), s2->Copy(geom));
+	  break;
+	}
+
+      case SUB:
+	{
+	  nsol = new Solid (SUB, s1 -> Copy (geom));
+	  break;
+	}
+      
+      case ROOT:
+	{
+	  nsol = s1->Copy(geom);
+	  break;
+	}
+      }
+
+    return nsol;
+  }
+
+ 
+  void Solid :: Transform (Transformation<3> & trans)
+  {
+    switch (op)
+      {
+      case TERM: case TERM_REF:
+	{
+	  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,
+			      bool 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;
+	}
+      case TERM:
+      case TERM_REF:
+	break;   // do nothing
+      } 
+  }
+
+
+
+
+  bool Solid :: IsIn (const Point<3> & p, double eps) const
+  {
+    switch (op)
+      {
+      case TERM: case TERM_REF:
+	{
+	  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;
+  }
+
+  bool Solid :: IsStrictIn (const Point<3> & p, double eps) const
+  {
+    switch (op)
+      {
+      case TERM: case TERM_REF:
+	{
+	  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;
+  }
+
+  bool Solid :: VectorIn (const Point<3> & p, const Vec<3> & v, 
+			 double eps) const
+  {
+    Vec<3> hv;
+    switch (op)
+      {
+      case TERM: case TERM_REF:
+	{
+	  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;
+  }
+
+  bool Solid :: VectorStrictIn (const Point<3> & p, const Vec<3> & v,
+			       double eps) const
+  {
+    Vec<3> hv;
+    switch (op)
+      {
+      case TERM: case TERM_REF:
+	{
+	  INSOLID_TYPE ist = prim->VecInSolid (p, v, eps);
+	  return (ist == IS_INSIDE) ? true : false;
+	}
+      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;
+  }
+
+
+  bool 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;
+  
+    bool res = VectorIn2Rec (p, v1, v2, eps);
+    return res;
+  }
+
+  bool Solid::VectorIn2Rec (const Point<3> & p, const Vec<3> & v1, 
+			   const Vec<3> & v2, double eps) const
+  {
+    switch (op)
+      {
+      case TERM: case TERM_REF:
+	return (prim->VecInSolid2 (p, v1, v2, eps) != IS_OUTSIDE); // Is this correct????
+      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: case TERM_REF:
+	{
+	  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: case TERM_REF:
+	{
+	  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;
+    for (int i = int(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;
+    for (int i = int(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: case TERM_REF:
+	{
+	  /*
+	    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, Array<int> & surfids, double eps) const
+  {
+    int in, strin;
+    RecTangentialSolid (p, tansol, surfids, in, strin, eps);
+    surfids.SetSize (0);
+    if (tansol)
+      tansol -> GetTangentialSurfaceIndices (p, surfids, eps);
+  }
+
+
+  void Solid :: RecTangentialSolid (const Point<3> & p, Solid *& tansol, Array<int> & surfids,
+				    int & in, int & strin, double eps) const
+  {
+    tansol = NULL;
+
+    switch (op)
+      {
+      case TERM: case TERM_REF:
+	{
+	  INSOLID_TYPE ist = prim->PointInSolid(p, eps);
+
+	  in = (ist == IS_INSIDE || ist == DOES_INTERSECT);
+	  strin = (ist == IS_INSIDE);
+
+	  if (ist == DOES_INTERSECT)
+	    {
+	      tansol = new Solid (prim);
+	      tansol -> op = TERM_REF;
+	    }
+	  break;
+	}
+      case SECTION:
+	{
+	  int in1, in2, strin1, strin2;
+	  Solid * tansol1, * tansol2;
+
+	  s1 -> RecTangentialSolid (p, tansol1, surfids, in1, strin1, eps);
+	  s2 -> RecTangentialSolid (p, tansol2, surfids, in2, strin2, eps);
+
+	  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 = 0, * tansol2 = 0;
+
+	  s1 -> RecTangentialSolid (p, tansol1, surfids, in1, strin1, eps);
+	  s2 -> RecTangentialSolid (p, tansol2, surfids, in2, strin2, eps);
+
+	  if (!strin1 && !strin2)
+	    {
+	      if (tansol1 && tansol2)
+		tansol = new Solid (UNION, tansol1, tansol2);
+	      else if (tansol1)
+		tansol = tansol1;
+	      else if (tansol2)
+		tansol = tansol2;
+	    }
+	  else
+	    {
+	      delete tansol1;
+	      delete tansol2;
+	    }
+	  in = (in1 || in2);
+	  strin = (strin1 || strin2);
+	  break;
+	}
+      case SUB:
+	{
+	  int hin, hstrin;
+	  Solid * tansol1;
+
+	  s1 -> RecTangentialSolid (p, tansol1, surfids, hin, hstrin, eps);
+
+	  if (tansol1)
+	    tansol = new Solid (SUB, tansol1);
+	  in = !hstrin;
+	  strin = !hin;
+	  break;
+	}
+      case ROOT:
+	{
+	  s1 -> RecTangentialSolid (p, tansol, surfids, in, strin, eps);
+	  break;
+	}
+      }
+  }
+
+
+
+
+  void Solid :: TangentialSolid2 (const Point<3> & p, 
+				  const Vec<3> & t,
+				  Solid *& tansol, Array<int> & surfids, double eps) const
+  {
+    int in, strin;
+    surfids.SetSize (0);
+    RecTangentialSolid2 (p, t, tansol, surfids, in, strin, eps);
+    if (tansol)
+      tansol -> GetTangentialSurfaceIndices2 (p, t, surfids, eps);
+  }
+
+  void Solid :: RecTangentialSolid2 (const Point<3> & p, const Vec<3> & t,
+				     Solid *& tansol, Array<int> & surfids, 
+				     int & in, int & strin, double eps) const
+  {
+    tansol = NULL;
+
+    switch (op)
+      {
+      case TERM: case TERM_REF:
+	{
+	  /*
+	    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, eps);
+	  if (ist == DOES_INTERSECT)
+	    ist = prim->VecInSolid (p, t, eps);
+
+	  in = (ist == IS_INSIDE || ist == DOES_INTERSECT);
+	  strin = (ist == IS_INSIDE);
+
+	  if (ist == DOES_INTERSECT)
+	    {
+	      tansol = new Solid (prim);
+	      tansol -> op = TERM_REF;
+	    }
+	  break;
+	}
+      case SECTION:
+	{
+	  int in1, in2, strin1, strin2;
+	  Solid * tansol1, * tansol2;
+
+	  s1 -> RecTangentialSolid2 (p, t, tansol1, surfids, in1, strin1, eps);
+	  s2 -> RecTangentialSolid2 (p, t, tansol2, surfids, in2, strin2, eps);
+
+	  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, surfids, in1, strin1, eps);
+	  s2 -> RecTangentialSolid2 (p, t, tansol2, surfids, in2, strin2, eps);
+
+	  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, surfids, hin, hstrin, eps);
+
+	  if (tansol1)
+	    tansol = new Solid (SUB, tansol1);
+	  in = !hstrin;
+	  strin = !hin;
+	  break;
+	}
+      case ROOT:
+	{
+	  s1 -> RecTangentialSolid2 (p, t, tansol, surfids, in, strin, eps);
+	  break;
+	}
+      }
+  }
+
+
+
+
+
+
+
+
+  void Solid :: TangentialSolid3 (const Point<3> & p, 
+				  const Vec<3> & t, const Vec<3> & t2,
+				  Solid *& tansol, Array<int> & surfids, 
+				  double eps) const
+  {
+    int in, strin;
+    surfids.SetSize (0);
+    RecTangentialSolid3 (p, t, t2, tansol, surfids, in, strin, eps);
+
+    if (tansol)
+      tansol -> GetTangentialSurfaceIndices3 (p, t, t2, surfids, eps);
+  }
+
+  void Solid :: RecTangentialSolid3 (const Point<3> & p, 
+				     const Vec<3> & t, const Vec<3> & t2,
+				     Solid *& tansol, Array<int> & surfids, 
+				     int & in, int & strin, double eps) const
+  {
+    tansol = NULL;
+
+    switch (op)
+      {
+      case TERM: case TERM_REF:
+	{
+	  INSOLID_TYPE ist = prim->PointInSolid(p, eps);
+
+	  if (ist == DOES_INTERSECT)
+	    ist = prim->VecInSolid3 (p, t, t2, eps);
+	  in = (ist == IS_INSIDE || ist == DOES_INTERSECT);
+	  strin = (ist == IS_INSIDE);
+
+	  if (ist == DOES_INTERSECT)
+	    {
+	      tansol = new Solid (prim);
+	      tansol -> op = TERM_REF;
+	    }
+	  break;
+	}
+      case SECTION:
+	{
+	  int in1, in2, strin1, strin2;
+	  Solid * tansol1, * tansol2;
+
+	  s1 -> RecTangentialSolid3 (p, t, t2, tansol1, surfids, in1, strin1, eps);
+	  s2 -> RecTangentialSolid3 (p, t, t2, tansol2, surfids, in2, strin2, eps);
+
+	  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 -> RecTangentialSolid3 (p, t, t2, tansol1, surfids, in1, strin1, eps);
+	  s2 -> RecTangentialSolid3 (p, t, t2, tansol2, surfids, in2, strin2, eps);
+
+	  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 -> RecTangentialSolid3 (p, t, t2, tansol1, surfids, hin, hstrin, eps);
+
+	  if (tansol1)
+	    tansol = new Solid (SUB, tansol1);
+	  in = !hstrin;
+	  strin = !hin;
+	  break;
+	}
+      case ROOT:
+	{
+	  s1 -> RecTangentialSolid3 (p, t, t2, tansol, surfids, in, strin, eps);
+	  break;
+	}
+      }
+  }
+
+
+
+
+
+
+
+
+
+
+
+  void Solid :: TangentialEdgeSolid (const Point<3> & p, 
+				     const Vec<3> & t, const Vec<3> & t2, const Vec<3> & m, 
+				     Solid *& tansol, Array<int> & surfids, 
+				     double eps) const
+  {
+    int in, strin;
+    surfids.SetSize (0);
+
+    // *testout << "tangentialedgesolid,sol = " << (*this) << endl;
+    RecTangentialEdgeSolid (p, t, t2, m, tansol, surfids, in, strin, eps);
+
+    if (tansol)
+      tansol -> RecGetTangentialEdgeSurfaceIndices (p, t, t2, m, surfids, eps);
+  }
+
+  void Solid :: RecTangentialEdgeSolid (const Point<3> & p, 
+					const Vec<3> & t, const Vec<3> & t2, const Vec<3> & m,
+					Solid *& tansol, Array<int> & surfids, 
+					int & in, int & strin, double eps) const
+  {
+    tansol = NULL;
+
+    switch (op)
+      {
+      case TERM: case TERM_REF:
+	{
+	  INSOLID_TYPE ist = prim->PointInSolid(p, eps);
+
+	  /*
+	  (*testout) << "tangedgesolid, p = " << p << ", t = " << t 
+		     << " for prim " << typeid (*prim).name() 
+		     << " with surf " << prim->GetSurface() << endl;
+	  (*testout) << "ist = " << ist << endl;
+	  */
+
+	  if (ist == DOES_INTERSECT)
+	    ist = prim->VecInSolid4 (p, t, t2, m, eps);
+
+	  // (*testout) << "ist2 = " << ist << endl;
+
+	  in = (ist == IS_INSIDE || ist == DOES_INTERSECT);
+	  strin = (ist == IS_INSIDE);
+
+	  if (ist == DOES_INTERSECT)
+	    {
+	      tansol = new Solid (prim);
+	      tansol -> op = TERM_REF;
+	    }
+	  break;
+	}
+      case SECTION:
+	{
+	  int in1, in2, strin1, strin2;
+	  Solid * tansol1, * tansol2;
+
+	  s1 -> RecTangentialEdgeSolid (p, t, t2, m, tansol1, surfids, in1, strin1, eps);
+	  s2 -> RecTangentialEdgeSolid (p, t, t2, m, tansol2, surfids, in2, strin2, eps);
+
+	  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 -> RecTangentialEdgeSolid (p, t, t2, m, tansol1, surfids, in1, strin1, eps);
+	  s2 -> RecTangentialEdgeSolid (p, t, t2, m, tansol2, surfids, in2, strin2, eps);
+
+	  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 -> RecTangentialEdgeSolid (p, t, t2, m, tansol1, surfids, hin, hstrin, eps);
+
+	  if (tansol1)
+	    tansol = new Solid (SUB, tansol1);
+	  in = !hstrin;
+	  strin = !hin;
+	  break;
+	}
+      case ROOT:
+	{
+	  s1 -> RecTangentialEdgeSolid (p, t, t2, m, tansol, surfids, in, strin, eps);
+	  break;
+	}
+      }
+  }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+  int Solid :: Edge (const Point<3> & p, const Vec<3> & v, double eps) const
+  {
+    int in, strin, faces;
+    RecEdge (p, v, in, strin, faces, eps);
+    return faces >= 2;
+  }
+
+  int Solid :: OnFace (const Point<3> & p, const Vec<3> & v, double eps) const
+  {
+    int in, strin, faces;
+    RecEdge (p, v, in, strin, faces, eps);
+    return faces >= 1;
+  }
+
+
+  void Solid :: RecEdge (const Point<3> & p, const Vec<3> & v,
+			 int & in, int & strin, int & faces, double eps) const
+  {
+    switch (op)
+      {
+      case TERM: case TERM_REF:
+	{
+	  INSOLID_TYPE ist = prim->VecInSolid (p, v, eps);
+	  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 = 0; i < prim->GetNSurfaces(); i++)
+		{
+		  double val = prim->GetSurface(i).CalcFunctionValue(p);
+		  prim->GetSurface(i).CalcGradient (p, grad);
+		  if (fabs (val) < eps && 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, eps);
+	  s2 -> RecEdge (p, v, in2, strin2, faces2, eps);
+
+	  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, eps);
+	  s2 -> RecEdge (p, v, in2, strin2, faces2, eps);
+
+	  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, eps);
+	  in = !strin1;
+	  strin = !in1;
+	  break;
+	}
+      case ROOT:
+	{
+	  s1 -> RecEdge (p, v, in, strin, faces, eps);
+	  break;
+	}
+      }
+  }
+
+
+  void Solid :: CalcSurfaceInverse ()
+  {
+    CalcSurfaceInverseRec (0);
+  }
+
+  void Solid :: CalcSurfaceInverseRec (int inv)
+  {
+    switch (op)
+      {
+      case TERM: case TERM_REF:
+	{
+	  bool priminv;
+	  for (int i = 0; i < prim->GetNSurfaces(); i++)
+	    {
+	      priminv = (prim->SurfaceInverted(i) != 0);
+	      if (inv) priminv = !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
+  {
+    INSOLID_TYPE in;
+    return RecGetReducedSolid (box, in);
+  }
+
+  Solid * Solid :: RecGetReducedSolid (const BoxSphere<3> & box, INSOLID_TYPE & in) const
+  {
+    Solid * redsol = NULL;
+
+    switch (op)
+      {
+      case TERM: 
+      case TERM_REF:
+	{
+	  in = prim -> BoxInSolid (box);
+	  if (in == DOES_INTERSECT)
+	    {
+	      redsol = new Solid (prim);
+	      redsol -> op = TERM_REF;
+	    }
+	  break;
+	}
+      case SECTION:
+	{
+	  INSOLID_TYPE in1, in2;
+	  Solid * redsol1, * redsol2;
+
+	  redsol1 = s1 -> RecGetReducedSolid (box, in1);
+	  redsol2 = s2 -> RecGetReducedSolid (box, in2);
+
+	  if (in1 == IS_OUTSIDE || in2 == IS_OUTSIDE)
+	    {
+	      if (in1 == DOES_INTERSECT) delete redsol1;
+	      if (in2 == DOES_INTERSECT) delete redsol2;
+	      in = IS_OUTSIDE;
+	    }
+	  else
+	    {
+	      if (in1 == DOES_INTERSECT || in2 == DOES_INTERSECT) 
+		in = DOES_INTERSECT;
+	      else 
+		in = IS_INSIDE;
+
+	      if (in1 == DOES_INTERSECT && in2 == DOES_INTERSECT)
+		redsol = new Solid (SECTION, redsol1, redsol2);
+	      else if (in1 == DOES_INTERSECT)
+		redsol = redsol1;
+	      else if (in2 == DOES_INTERSECT)
+		redsol = redsol2;
+	    }
+	  break;
+	}
+
+      case UNION:
+	{
+	  INSOLID_TYPE in1, in2;
+	  Solid * redsol1, * redsol2;
+
+	  redsol1 = s1 -> RecGetReducedSolid (box, in1);
+	  redsol2 = s2 -> RecGetReducedSolid (box, in2);
+
+	  if (in1 == IS_INSIDE || in2 == IS_INSIDE)
+	    {
+	      if (in1 == DOES_INTERSECT) delete redsol1;
+	      if (in2 == DOES_INTERSECT) delete redsol2;
+	      in = IS_INSIDE;
+	    }
+	  else
+	    {
+	      if (in1 == DOES_INTERSECT || in2 == DOES_INTERSECT) in = DOES_INTERSECT;
+	      else in = IS_OUTSIDE;
+
+	      if (in1 == DOES_INTERSECT && in2 == DOES_INTERSECT)
+		redsol = new Solid (UNION, redsol1, redsol2);
+	      else if (in1 == DOES_INTERSECT)
+		redsol = redsol1;
+	      else if (in2 == DOES_INTERSECT)
+		redsol = redsol2;
+	    }
+	  break;
+	}
+
+      case SUB:
+	{
+	  INSOLID_TYPE in1;
+	  Solid * redsol1 = s1 -> RecGetReducedSolid (box, in1);
+
+	  switch (in1)
+	    {
+	    case IS_OUTSIDE: in = IS_INSIDE; break;
+	    case IS_INSIDE:  in = IS_OUTSIDE; break;
+	    case DOES_INTERSECT: in = DOES_INTERSECT; break;
+	    }
+
+	  if (redsol1)
+	    redsol = new Solid (SUB, redsol1);
+	  break;
+	}
+      
+      case ROOT:
+	{
+	  INSOLID_TYPE in1;
+	  redsol = s1 -> RecGetReducedSolid (box, in1);
+	  in = in1;
+	  break;
+	}
+      }
+
+    /*
+    if (redsol)
+      (*testout) << "getrecsolid, redsol = " << endl << (*redsol) << endl;
+    else
+      (*testout) << "redsol is null" << endl;
+    */
+
+    return redsol;
+  }
+
+
+  int Solid :: NumPrimitives () const
+  {
+    switch (op)
+      {
+      case TERM: case TERM_REF:
+	{
+	  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: case TERM_REF:
+	{
+	  /*
+	    int i;
+	    for (i = 1; i <= surfind.Size(); i++)
+	    if (surfind.Get(i) == prim->GetSurfaceId())
+	    return;
+	    surfind.Append (prim->GetSurfaceId());
+	    break;
+	  */
+	  for (int j = 0; j < prim->GetNSurfaces(); j++)
+	    if (prim->SurfaceActive (j))
+	      {
+		bool found = 0;
+		int siprim = prim->GetSurfaceId(j);
+
+		for (int 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 :: GetTangentialSurfaceIndices (const Point<3> & p, Array<int> & surfind, double eps) const
+  {
+    surfind.SetSize (0);
+    RecGetTangentialSurfaceIndices (p, surfind, eps);
+  }
+
+  void Solid :: RecGetTangentialSurfaceIndices (const Point<3> & p, Array<int> & surfind, double eps) const
+  {
+    switch (op)
+      {
+      case TERM: case TERM_REF:
+	{
+	  /*
+	  for (int j = 0; j < prim->GetNSurfaces(); j++)
+	    if (fabs (prim->GetSurface(j).CalcFunctionValue (p)) < eps)
+	      if (!surfind.Contains (prim->GetSurfaceId(j)))
+		surfind.Append (prim->GetSurfaceId(j));
+	  */
+	  prim->GetTangentialSurfaceIndices (p, surfind, eps);
+	  break;
+	}
+      case UNION:
+      case SECTION:
+	{
+	  s1 -> RecGetTangentialSurfaceIndices (p, surfind, eps);
+	  s2 -> RecGetTangentialSurfaceIndices (p, surfind, eps);
+	  break;
+	}
+      case SUB:
+      case ROOT:
+	{
+	  s1 -> RecGetTangentialSurfaceIndices (p, surfind, eps);
+	  break;
+	}
+      }
+  }
+
+
+
+
+
+
+  void Solid :: GetTangentialSurfaceIndices2 (const Point<3> & p, const Vec<3> & v,
+					     Array<int> & surfind, double eps) const
+  {
+    surfind.SetSize (0);
+    RecGetTangentialSurfaceIndices2 (p, v, surfind, eps);
+  }
+
+  void Solid :: RecGetTangentialSurfaceIndices2 (const Point<3> & p, const Vec<3> & v,
+						 Array<int> & surfind, double eps) const
+  {
+    switch (op)
+      {
+      case TERM: case TERM_REF:
+	{
+	  for (int j = 0; j < prim->GetNSurfaces(); j++)
+	    {
+	      if (fabs (prim->GetSurface(j).CalcFunctionValue (p)) < eps)
+		{
+		  Vec<3> grad;
+		  prim->GetSurface(j).CalcGradient (p, grad);
+		  if (sqr (grad * v) < 1e-6 * v.Length2() * grad.Length2())
+		    {
+		      if (!surfind.Contains (prim->GetSurfaceId(j)))
+			surfind.Append (prim->GetSurfaceId(j));
+		    }
+		}
+	    }
+	  break;
+	}
+      case UNION:
+      case SECTION:
+	{
+	  s1 -> RecGetTangentialSurfaceIndices2 (p, v, surfind, eps);
+	  s2 -> RecGetTangentialSurfaceIndices2 (p, v, surfind, eps);
+	  break;
+	}
+      case SUB:
+      case ROOT:
+	{
+	  s1 -> RecGetTangentialSurfaceIndices2 (p, v, surfind, eps);
+	  break;
+	}
+      }
+  }
+
+
+
+
+
+
+
+
+  void Solid :: GetTangentialSurfaceIndices3 (const Point<3> & p, const Vec<3> & v, const Vec<3> & v2, 
+					     Array<int> & surfind, double eps) const
+  {
+    surfind.SetSize (0);
+    RecGetTangentialSurfaceIndices3 (p, v, v2, surfind, eps);
+  }
+
+  void Solid :: RecGetTangentialSurfaceIndices3 (const Point<3> & p, const Vec<3> & v, const Vec<3> & v2, 
+						 Array<int> & surfind, double eps) const
+  {
+    switch (op)
+      {
+      case TERM: case TERM_REF:
+	{
+	  for (int j = 0; j < prim->GetNSurfaces(); j++)
+	    {
+	      if (fabs (prim->GetSurface(j).CalcFunctionValue (p)) < eps)
+		{
+		  Vec<3> grad;
+		  prim->GetSurface(j).CalcGradient (p, grad);
+		  if (sqr (grad * v) < 1e-6 * v.Length2() * grad.Length2())
+		    {
+		      Mat<3> hesse;
+		      prim->GetSurface(j).CalcHesse (p, hesse);
+		      double hv2 = v2 * grad + v * (hesse * v);
+		      
+		      if (fabs (hv2) < 1e-6) 
+			{
+			  if (!surfind.Contains (prim->GetSurfaceId(j)))
+			    surfind.Append (prim->GetSurfaceId(j));
+			}
+		      /*
+		      else
+			{
+			  *testout << "QUAD NOT OK" << endl;
+			  *testout << "v = " << v << ", v2 = " << v2 << endl;
+			  *testout << "v * grad = " << v*grad << endl;
+			  *testout << "v2 * grad = " << v2*grad << endl;
+			  *testout << "v H v = " << v*(hesse*v) << endl;
+			  *testout << "grad = " << grad << endl;
+			  *testout << "hesse = " << hesse << endl;
+			  *testout << "hv2 = " << v2 * grad + v * (hesse * v) << endl;
+			}
+		      */
+		    }
+		}
+	    }
+	  break;
+	}
+      case UNION:
+      case SECTION:
+	{
+	  s1 -> RecGetTangentialSurfaceIndices3 (p, v, v2, surfind, eps);
+	  s2 -> RecGetTangentialSurfaceIndices3 (p, v, v2, surfind, eps);
+	  break;
+	}
+      case SUB:
+      case ROOT:
+	{
+	  s1 -> RecGetTangentialSurfaceIndices3 (p, v, v2, surfind, eps);
+	  break;
+	}
+      }
+  }
+
+
+
+
+
+  void Solid :: RecGetTangentialEdgeSurfaceIndices (const Point<3> & p, const Vec<3> & v, const Vec<3> & v2, const Vec<3> & m,
+						    Array<int> & surfind, double eps) const
+  {
+    switch (op)
+      {
+      case TERM: case TERM_REF:
+	{
+	  // *testout << "check vecinsolid4, p = " << p << ", v = " << v << "; m = " << m << endl;
+	  if (prim->VecInSolid4 (p, v, v2, m, eps) == DOES_INTERSECT)
+	    {
+	      prim->GetTangentialVecSurfaceIndices2 (p, v, m, surfind, eps);
+	      /*
+	      for (int j = 0; j < prim->GetNSurfaces(); j++)
+		{
+		  if (fabs (prim->GetSurface(j).CalcFunctionValue (p)) < eps)
+		    {
+		      Vec<3> grad;
+		      prim->GetSurface(j).CalcGradient (p, grad);
+		      *testout << "grad = " << grad << endl;
+		      if (sqr (grad * v) < 1e-6 * v.Length2() * grad.Length2()  && 
+			  sqr (grad * m) < 1e-6 * m.Length2() * grad.Length2() )   // new, 18032006 JS
+			  
+			{
+			  *testout << "add surf " << prim->GetSurfaceId(j) << endl;
+			  if (!surfind.Contains (prim->GetSurfaceId(j)))
+			    surfind.Append (prim->GetSurfaceId(j));
+			}
+		    }
+		}
+	      */
+	    }
+	  break;
+	}
+      case UNION:
+      case SECTION:
+	{
+	  s1 -> RecGetTangentialEdgeSurfaceIndices (p, v, v2, m, surfind, eps);
+	  s2 -> RecGetTangentialEdgeSurfaceIndices (p, v, v2, m, surfind, eps);
+	  break;
+	}
+      case SUB:
+      case ROOT:
+	{
+	  s1 -> RecGetTangentialEdgeSurfaceIndices (p, v, v2, m, surfind, eps);
+	  break;
+	}
+      }
+  }
+
+
+
+
+
+
+
+
+
+
+
+
+  void Solid :: GetSurfaceIndices (IndexSet & iset) const
+  {
+    iset.Clear();
+    RecGetSurfaceIndices (iset);
+  }
+
+  void Solid :: RecGetSurfaceIndices (IndexSet & iset) const
+  {
+    switch (op)
+      {
+      case TERM: case TERM_REF:
+	{
+	  /*
+	    int i;
+	    for (i = 1; i <= surfind.Size(); i++)
+	    if (surfind.Get(i) == prim->GetSurfaceId())
+	    return;
+	    surfind.Append (prim->GetSurfaceId());
+	    break;
+	  */
+	  for (int 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;
+	}
+      }
+  }
+
+
+  void Solid :: CalcOnePrimitiveSpecialPoints (const Box<3> & box, Array<Point<3> > & pts) const
+  {
+    double eps = 1e-8 * box.Diam ();
+
+    pts.SetSize (0);
+    this -> RecCalcOnePrimitiveSpecialPoints (pts);
+    for (int i = pts.Size()-1; i >= 0; i--)
+      {
+	if (!IsIn (pts[i],eps) || IsStrictIn (pts[i],eps))
+	  pts.Delete (i);
+      }
+  }
+
+  void Solid :: RecCalcOnePrimitiveSpecialPoints (Array<Point<3> > & pts) const
+  {
+    switch (op)
+      {
+      case TERM: case TERM_REF:
+	{
+	  prim -> CalcSpecialPoints (pts);
+	  break;
+	}
+      case UNION:
+      case SECTION:
+	{
+	  s1 -> RecCalcOnePrimitiveSpecialPoints (pts);
+	  s2 -> RecCalcOnePrimitiveSpecialPoints (pts);
+	  break;
+	}
+      case SUB:
+      case ROOT:
+	{
+	  s1 -> RecCalcOnePrimitiveSpecialPoints (pts);
+	  break;
+	}
+      } 
+  }
+
+
+
+
+  BlockAllocator Solid :: ball(sizeof (Solid));
+}
diff --git a/contrib/Netgen/libsrc/csg/solid.hpp b/contrib/Netgen/libsrc/csg/solid.hpp
new file mode 100644
index 0000000000..ebd7c88c98
--- /dev/null
+++ b/contrib/Netgen/libsrc/csg/solid.hpp
@@ -0,0 +1,246 @@
+#ifndef FILE_SOLID
+#define FILE_SOLID
+
+/**************************************************************************/
+/* File:   solid.hh                                                       */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   1. Dez. 95                                                     */
+/**************************************************************************/
+
+namespace netgen 
+{
+
+  
+  /*
+    
+  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, TERM_REF, SECTION, UNION, SUB, ROOT /*, DUMMY */ } optyp;
+  
+  private:
+    char * name;
+    Primitive * prim;
+    Solid * s1, * s2;
+  
+    optyp op;
+    bool visited;
+    double maxh;
+
+    // static int cntnames;
+
+  public:
+    Solid (Primitive * aprim);
+    Solid (optyp aop, Solid * as1, Solid * as2 = NULL);
+    ~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, bool 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;
+
+    void GetTangentialSurfaceIndices (const Point<3> & p, Array<int> & surfids, double eps) const;
+    void GetTangentialSurfaceIndices2 (const Point<3> & p, const Vec<3> & v, Array<int> & surfids, double eps) const;
+    void GetTangentialSurfaceIndices3 (const Point<3> & p, const Vec<3> & v, const Vec<3> & v2, Array<int> & surfids, double eps) const;
+
+
+    Primitive * GetPrimitive ()
+    { return (op == TERM || op == TERM_REF) ? prim : NULL; }
+    const Primitive * GetPrimitive () const
+    { return (op == TERM || op == TERM_REF) ? prim : NULL; }
+
+    Solid * S1() { return s1; }
+    Solid * S2() { return s2; }
+
+    // geometric tests
+
+    bool IsIn (const Point<3> & p, double eps = 1e-6) const;
+    bool IsStrictIn (const Point<3> & p, double eps = 1e-6) const;
+    bool VectorIn (const Point<3> & p, const Vec<3> & v, double eps = 1e-6) const;
+    bool VectorStrictIn (const Point<3> & p, const Vec<3> & v, double eps = 1e-6) const;
+  
+    bool VectorIn2 (const Point<3> & p, const Vec<3> & v1, const Vec<3> & v2,
+		    double eps) const;
+    bool VectorIn2Rec (const Point<3> & p, const Vec<3> & v1, const Vec<3> & v2,
+		       double eps) const;
+
+
+    /// compute localization in point p
+    void TangentialSolid (const Point<3> & p, Solid *& tansol, Array<int> & surfids, double eps) const;
+
+    /// compute localization in point p tangential to vector t
+    void TangentialSolid2 (const Point<3> & p, const Vec<3> & t,
+			   Solid *& tansol, Array<int> & surfids, double eps) const;
+
+    /** compute localization in point p, with second order approximation to edge
+	p + s t + s*s/2 t2 **/
+    void TangentialSolid3 (const Point<3> & p, const Vec<3> & t, const Vec<3> & t2, 
+			   Solid *& tansol, Array<int> & surfids, double eps) const;
+
+
+
+    /** tangential solid, which follows the edge
+	p + s t + s*s/2 t2
+	with second order, and the neighbouring face
+	p + s t + s*s/2 t2 + r m
+	with first order
+    **/
+    void TangentialEdgeSolid (const Point<3> & p, const Vec<3> & t, const Vec<3> & t2, 
+			      const Vec<3> & m, 
+			      Solid *& tansol, Array<int> & surfids, double eps) const;
+
+
+    void CalcOnePrimitiveSpecialPoints (const Box<3> & box, Array<Point<3> > & pts) const;
+
+    ///
+    int Edge (const Point<3> & p, const Vec<3> & v, double eps) const;
+    ///
+    int OnFace (const Point<3> & p, const Vec<3> & v, double eps) const;
+    ///
+    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 /* s */) 
+    {
+      return ball.Alloc();
+    }
+
+    void operator delete (void * p)
+    {
+      ball.Free (p);
+    }
+
+
+  protected:
+    ///
+
+    void RecBoundaries (const Point<3> & p, Array<int> & bounds, 
+			int & in, int & strin) const;
+    ///
+    void RecTangentialSolid (const Point<3> & p, Solid *& tansol, Array<int> & surfids, 
+			     int & in, int & strin, double eps) const;
+
+    void RecTangentialSolid2 (const Point<3> & p, const Vec<3> & vec, 
+			      Solid *& tansol, Array<int> & surfids, 
+			      int & in, int & strin, double eps) const;
+    ///
+    void RecTangentialSolid3 (const Point<3> & p, const Vec<3> & vec,const Vec<3> & vec2, 
+			      Solid *& tansol, Array<int> & surfids, 
+			      int & in, int & strin, double eps) const;
+    ///
+    void RecTangentialEdgeSolid (const Point<3> & p, const Vec<3> & t, const Vec<3> & t2, 
+				 const Vec<3> & m, 
+				 Solid *& tansol, Array<int> & surfids, 
+				 int & in, int & strin, double eps) const;
+
+    ///
+    void RecEdge (const Point<3> & p, const Vec<3> & v,
+		  int & in, int & strin, int & faces, double eps) const;
+    ///
+    void CalcSurfaceInverseRec (int inv);
+    ///
+    Solid * RecGetReducedSolid (const BoxSphere<3> & box, INSOLID_TYPE & in) const;
+    ///
+    void RecGetSurfaceIndices (Array<int> & surfind) const;
+    void RecGetTangentialSurfaceIndices (const Point<3> & p, Array<int> & surfids, double eps) const;
+    void RecGetTangentialSurfaceIndices2 (const Point<3> & p, const Vec<3> & v, Array<int> & surfids, double eps) const;
+    void RecGetTangentialSurfaceIndices3 (const Point<3> & p, const Vec<3> & v, const Vec<3> & v2, 
+					  Array<int> & surfids, double eps) const;
+    void RecGetTangentialEdgeSurfaceIndices (const Point<3> & p, const Vec<3> & v, const Vec<3> & v2, const Vec<3> & m,
+					     Array<int> & surfids, double eps) const;
+    void RecGetSurfaceIndices (IndexSet & iset) const;
+
+    void RecCalcOnePrimitiveSpecialPoints (Array<Point<3> > & pts) const;
+
+    friend class SolidIterator;
+    friend class ClearVisitedIt;
+    friend class RemoveDummyIterator;
+    friend class CSGeometry;
+  };
+
+
+  inline ostream & operator<< (ostream & ost, const Solid & sol)
+  {
+    sol.Print (ost);
+    return ost;
+  }
+
+
+
+
+
+
+  class ReducePrimitiveIterator : public SolidIterator
+  {
+    const BoxSphere<3> & box;
+  public:
+    ReducePrimitiveIterator (const BoxSphere<3> & abox)
+      : SolidIterator(), box(abox) { ; }
+    virtual ~ReducePrimitiveIterator () { ; }
+    virtual void Do (Solid * sol)
+    {
+      if (sol -> GetPrimitive())
+	sol -> GetPrimitive() -> Reduce (box);
+    }
+  };
+
+
+  class UnReducePrimitiveIterator : public SolidIterator
+  {
+  public:
+    UnReducePrimitiveIterator () { ; }
+    virtual ~UnReducePrimitiveIterator () { ; }
+    virtual void Do (Solid * sol)
+    {
+      if (sol -> GetPrimitive())
+	sol -> GetPrimitive() -> UnReduce ();
+    }
+  };
+
+}
+
+#endif
diff --git a/contrib/Netgen/libsrc/csg/specpoin.cpp b/contrib/Netgen/libsrc/csg/specpoin.cpp
new file mode 100644
index 0000000000..f4c5f946a9
--- /dev/null
+++ b/contrib/Netgen/libsrc/csg/specpoin.cpp
@@ -0,0 +1,2099 @@
+#include <mystdlib.h>
+#include <meshing.hpp>
+#include <csg.hpp>
+
+
+/*
+  Special Point calculation uses the global Flags:
+
+  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 
+*/
+
+
+// #define DEVELOP
+
+
+namespace netgen
+{
+  Array<Box<3> > boxes;
+
+
+  void ProjectToEdge (const Surface * f1, const Surface * f2, Point<3> & hp);
+
+  enum { check_crosspoint = 5 };
+
+  SpecialPoint :: SpecialPoint (const SpecialPoint & sp)
+  {
+    p = sp.p;
+    v = sp.v;
+    s1 = sp.s1;
+    s2 = sp.s2;
+    s1_orig = sp.s1_orig;
+    s2_orig = sp.s2_orig;
+    layer = sp.layer;
+    unconditional = sp.unconditional;
+  }
+  
+  SpecialPoint & SpecialPoint :: operator= (const SpecialPoint & sp)
+  {
+    p = sp.p;
+    v = sp.v;
+    s1 = sp.s1;
+    s2 = sp.s2;
+    s1_orig = sp.s1_orig;
+    s2_orig = sp.s2_orig;
+    layer = sp.layer;
+    unconditional = sp.unconditional;
+    return *this;
+  }
+
+
+  void SpecialPoint :: Print (ostream & str) const
+  {
+    str << "p = " << p << "   v = " << v 
+	<< " s1/s2 = " << s1 << "/" << s2;
+    str << " layer = " << layer
+	<< " unconditional = " << unconditional
+	<< endl;
+  }
+
+
+  static Array<int> numprim_hist;
+
+  SpecialPointCalculation :: SpecialPointCalculation ()
+  {
+    ideps = 1e-9;
+  }
+
+  void SpecialPointCalculation :: 
+  CalcSpecialPoints (const CSGeometry & ageometry, 
+		     Array<MeshPoint> & apoints)
+  {
+    static int timer = NgProfiler::CreateTimer ("CSG: find special points");
+    NgProfiler::RegionTimer reg (timer);
+
+
+    geometry = &ageometry;
+    points = &apoints;
+
+    size = geometry->MaxSize();
+    (*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());
+
+    numprim_hist.SetSize (geometry->GetNSurf()+1);
+    numprim_hist = 0;
+
+    for (int i = 0; i < geometry->GetNTopLevelObjects(); i++)
+      {
+	const TopLevelObject * tlo = geometry->GetTopLevelObject(i);
+
+	(*testout) << "tlo " << i << ":" << endl
+		   << *tlo->GetSolid() << endl;
+
+	if (tlo->GetSolid())
+	  {
+	    Array<Point<3> > hpts;
+	    tlo->GetSolid()->CalcOnePrimitiveSpecialPoints (box, hpts);
+            // if (hpts.Size())
+            //  cout << "oneprimitivespecialpoints = " << hpts << endl;
+	    for (int j = 0; j < hpts.Size(); j++)
+	      AddPoint (hpts[j], tlo->GetLayer());
+	  }
+
+	CalcSpecialPointsRec (tlo->GetSolid(), tlo->GetLayer(),
+			      box, 1, 1, 1);
+      }
+ 
+  
+    geometry->DeleteIdentPoints();
+    for (int i = 0; i < geometry->GetNIdentifications(); i++)
+      {
+	CloseSurfaceIdentification * ident =
+	  dynamic_cast<CloseSurfaceIdentification * >(geometry->identifications[i]);
+	
+	if(!ident || !ident->IsSkewIdentification())
+	  continue;
+
+	for(int j=0; j<points->Size(); j++)
+	  {
+	    if(fabs(ident->GetSurface1().CalcFunctionValue((*points)[j])) < 1e-15)
+	      {
+		Point<3> auxpoint = (*points)[j];
+		ident->GetSurface2().SkewProject(auxpoint,ident->GetDirection());
+		geometry->AddIdentPoint(auxpoint);
+		geometry->AddIdentPoint((*points)[j]);
+		AddPoint (auxpoint,1);
+
+#ifdef DEVELOP
+		(*testout) << "added identpoint " << auxpoint << "; proj. of "
+			   <<  (*points)[j] << endl;
+#endif
+		break;
+	      }
+	  }
+      }
+    
+
+    // add user point:
+    for (int i = 0; i < geometry->GetNUserPoints(); i++)
+      AddPoint (geometry->GetUserPoint(i), 1);
+	
+
+    PrintMessage (3, "Found points ", apoints.Size());
+
+    for (int i = 0; i < boxesinlevel.Size(); i++)
+      (*testout) << "level " << i << " has " 
+		 << boxesinlevel[i] << " boxes" << endl;
+    (*testout) << "numprim_histogramm = " << endl << numprim_hist << endl;
+  }
+  
+
+
+  void SpecialPointCalculation :: 
+  CalcSpecialPointsRec (const Solid * sol, int layer,
+			const BoxSphere<3> & box, 
+			int level, bool calccp, bool calcep)
+  {
+    // boxes.Append (box);
+
+#ifdef DEVELOP
+    *testout << "lev " << level << ", box = " << box << endl;
+    *testout << "calccp = " << calccp << ", calcep = " << calcep << endl;
+    *testout << "locsol = " << *sol << endl;
+#endif
+
+    if (multithread.terminate)
+      {
+	*testout << "boxes = " << boxes << endl;
+	*testout << "boxesinlevel = " << boxesinlevel << endl;
+	throw NgException ("Meshing stopped");
+      }
+
+
+    if (!sol) return;
+
+    if (level >= 100)
+      {
+	MyStr err =
+	  MyStr("Problems in CalcSpecialPoints\nPoint: ") + MyStr (box.Center());
+	throw NgException (err.c_str());
+      }
+
+
+    bool decision;
+    bool possiblecrossp, possibleexp;  // possible cross or extremalpoint
+    bool surecrossp = 0, sureexp = 0;          // sure ...
+  
+    static Array<int> locsurf;  // attention: array is static
+
+    static int cntbox = 0;
+    cntbox++;
+
+    if (level <= boxesinlevel.Size())
+      boxesinlevel.Elem(level)++;
+    else
+      boxesinlevel.Append (1);
+
+    /*
+      numprim = sol -> NumPrimitives();
+      sol -> GetSurfaceIndices (locsurf);
+    */
+
+    geometry -> GetIndependentSurfaceIndices (sol, box, locsurf);
+    int numprim = locsurf.Size();
+
+#ifdef DEVELOP
+    (*testout) << "numprim = " << numprim << endl;
+#endif
+
+    numprim_hist[numprim]++;
+
+    Point<3> p = box.Center();
+
+
+    // explicit solution for planes only and at most one quadratic
+    if (numprim <= check_crosspoint)
+      {
+	int nplane = 0, nquad = 0, quadi = -1, nsphere = 0;
+	const QuadraticSurface *qsurf = 0, *qsurfi;
+
+	for (int i = 0; i < numprim; i++)
+	  {
+	    qsurfi = dynamic_cast<const QuadraticSurface*> 
+	      (geometry->GetSurface(locsurf[i]));
+
+	    if (qsurfi) nquad++;
+	    if (dynamic_cast<const Plane*> (qsurfi))
+	      nplane++;
+	    else
+	      {
+		quadi = i;
+		qsurf = qsurfi;
+	      }
+
+	    if (dynamic_cast<const Sphere*> (qsurfi))
+	      nsphere++;
+	  }
+
+	/*
+	if (nquad == numprim && nplane == numprim-2)
+	  return;
+	*/
+
+#ifdef DEVELOP
+	(*testout) << "nquad " << nquad << " nplane " << nplane << endl;
+#endif
+
+	if (nquad == numprim && nplane >= numprim-1)
+	  {
+	    Array<Point<3> > pts;
+	    Array<int> surfids;
+
+	    for (int k1 = 0; k1 < numprim - 2; k1++)
+	      for (int k2 = k1 + 1; k2 < numprim - 1; k2++)
+		for (int k3 = k2 + 1; k3 < numprim; k3++)
+		  if (k1 != quadi && k2 != quadi && k3 != quadi)
+		    {
+		      ComputeCrossPoints (dynamic_cast<const Plane*> (geometry->GetSurface(locsurf[k1])),
+					  dynamic_cast<const Plane*> (geometry->GetSurface(locsurf[k2])),
+					  dynamic_cast<const Plane*> (geometry->GetSurface(locsurf[k3])),
+					  pts);
+
+		      for (int j = 0; j < pts.Size(); j++)
+			if (Dist (pts[j], box.Center()) < box.Diam()/2)
+			  {
+			    Solid * tansol;
+			    sol -> TangentialSolid (pts[j], tansol, surfids, 1e-9*size);
+
+			    if(!tansol)
+			      continue;
+
+			    bool ok1 = false, ok2 = false, ok3 = false;
+			    int rep1 = geometry->GetSurfaceClassRepresentant(locsurf[k1]);
+			    int rep2 = geometry->GetSurfaceClassRepresentant(locsurf[k2]);
+			    int rep3 = geometry->GetSurfaceClassRepresentant(locsurf[k3]);
+			    for(int jj=0; jj<surfids.Size(); jj++)
+			      {
+				int actrep = geometry->GetSurfaceClassRepresentant(surfids[jj]);
+				if(actrep == rep1) ok1 = true;
+				if(actrep == rep2) ok2 = true;
+				if(actrep == rep3) ok3 = true;				  
+			      }
+
+			    
+			    if (tansol && ok1 && ok2 && ok3)
+			    // if (sol -> IsIn (pts[j], 1e-6*size) && !sol->IsStrictIn (pts[j], 1e-6*size))
+			      {
+				if (AddPoint (pts[j], layer))
+				  (*testout) << "cross point found, 1: " << pts[j] << endl;
+			      }  
+			    delete tansol;
+			  }
+		    }
+
+
+	    if (qsurf)
+	      {
+		for (int k1 = 0; k1 < numprim - 1; k1++)
+		  for (int k2 = k1 + 1; k2 < numprim; k2++)
+		    if (k1 != quadi && k2 != quadi)
+		      {
+			ComputeCrossPoints (dynamic_cast<const Plane*> (geometry->GetSurface(locsurf[k1])),
+					    dynamic_cast<const Plane*> (geometry->GetSurface(locsurf[k2])),
+					    qsurf, pts);
+			//(*testout) << "checking pot. crosspoints: " << pts << endl;
+
+			for (int j = 0; j < pts.Size(); j++)
+			  if (Dist (pts[j], box.Center()) < box.Diam()/2)
+			    {
+			      Solid * tansol;
+			      sol -> TangentialSolid (pts[j], tansol, surfids, 1e-9*size);
+
+			      if(!tansol)
+				continue;
+			      			      
+			      bool ok1 = false, ok2 = false, ok3 = true;//false;
+			      int rep1 = geometry->GetSurfaceClassRepresentant(locsurf[k1]);
+			      int rep2 = geometry->GetSurfaceClassRepresentant(locsurf[k2]);
+			      //int rep3 = geometry->GetSurfaceClassRepresentant(quadi);
+			      for(int jj=0; jj<surfids.Size(); jj++)
+				{
+				  int actrep = geometry->GetSurfaceClassRepresentant(surfids[jj]);
+				  if(actrep == rep1) ok1 = true;
+				  if(actrep == rep2) ok2 = true;
+				  //if(actrep == rep3) ok3 = true;				  
+				}
+
+
+			      if (tansol && ok1 && ok2 && ok3)
+				//if (sol -> IsIn (pts[j], 1e-6*size) && !sol->IsStrictIn (pts[j], 1e-6*size) )
+				{
+				  if (AddPoint (pts[j], layer))
+				    (*testout) << "cross point found, 2: " << pts[j] << endl;
+				}  
+			      delete tansol;
+			    }
+		      }
+
+
+		for (int k1 = 0; k1 < numprim; k1++)
+		  if (k1 != quadi)
+		    {
+		      ComputeExtremalPoints (dynamic_cast<const Plane*> (geometry->GetSurface(locsurf[k1])),
+					     qsurf, pts);
+		      
+		      for (int j = 0; j < pts.Size(); j++)
+			if (Dist (pts[j], box.Center()) < box.Diam()/2)
+			  {
+			    Solid * tansol;
+			    sol -> TangentialSolid (pts[j], tansol, surfids, 1e-9*size);
+			    if (tansol)
+			      // sol -> IsIn (pts[j], 1e-6*size) && !sol->IsStrictIn (pts[j], 1e-6*size) )
+			      {
+				if (AddPoint (pts[j], layer))
+				  (*testout) << "extremal point found, 1: " << pts[j] << endl;
+			      }  
+			    delete tansol;
+			  }
+		    }
+	      }
+	    
+	    return;
+	  }
+
+
+
+	if (nsphere == numprim) //  && calccp == false)
+	  {
+	    Array<Point<3> > pts;
+	    Array<int> surfids;
+
+
+	    
+	    for (int k1 = 0; k1 < numprim; k1++)
+	      for (int k2 = 0; k2 < k1; k2++)
+		for (int k3 = 0; k3 < k2; k3++)
+		  {
+		    ComputeCrossPoints (dynamic_cast<const Sphere*> (geometry->GetSurface(locsurf[k1])),
+					dynamic_cast<const Sphere*> (geometry->GetSurface(locsurf[k2])),
+					dynamic_cast<const Sphere*> (geometry->GetSurface(locsurf[k3])),
+					pts);
+		    
+		    for (int j = 0; j < pts.Size(); j++)
+		      if (Dist (pts[j], box.Center()) < box.Diam()/2)
+			{
+			  Solid * tansol;
+			  sol -> TangentialSolid (pts[j], tansol, surfids, 1e-9*size);
+			  
+			  if(!tansol)
+			    continue;
+			  
+			  bool ok1 = false, ok2 = false, ok3 = false;
+			  int rep1 = geometry->GetSurfaceClassRepresentant(locsurf[k1]);
+			  int rep2 = geometry->GetSurfaceClassRepresentant(locsurf[k2]);
+			  int rep3 = geometry->GetSurfaceClassRepresentant(locsurf[k3]);
+			  for(int jj=0; jj<surfids.Size(); jj++)
+			    {
+			      int actrep = geometry->GetSurfaceClassRepresentant(surfids[jj]);
+			      if(actrep == rep1) ok1 = true;
+			      if(actrep == rep2) ok2 = true;
+			      if(actrep == rep3) ok3 = true;				  
+			    }
+			  
+			  
+			  if (tansol && ok1 && ok2 && ok3)
+			    // if (sol -> IsIn (pts[j], 1e-6*size) && !sol->IsStrictIn (pts[j], 1e-6*size))
+			    {
+			      if (AddPoint (pts[j], layer))
+				(*testout) << "cross point found, 1: " << pts[j] << endl;
+			    }  
+			  delete tansol;
+			}
+		  }
+	    
+
+	    for (int k1 = 0; k1 < numprim; k1++)
+	      for (int k2 = 0; k2 < k1; k2++)
+		{
+		  ComputeExtremalPoints (dynamic_cast<const Sphere*> (geometry->GetSurface(locsurf[k1])),
+					 dynamic_cast<const Sphere*> (geometry->GetSurface(locsurf[k2])),
+					 pts);
+		  
+		  for (int j = 0; j < pts.Size(); j++)
+		    if (Dist (pts[j], box.Center()) < box.Diam()/2)
+		      {
+			Solid * tansol;
+			sol -> TangentialSolid (pts[j], tansol, surfids, 1e-9*size);
+			if (tansol)
+			  // sol -> IsIn (pts[j], 1e-6*size) && !sol->IsStrictIn (pts[j], 1e-6*size) )
+			  {
+			    if (AddPoint (pts[j], layer))
+			      (*testout) << "extremal point found, spheres: " << pts[j] << endl;
+			  }  
+			delete tansol;
+		      }
+		}
+	    
+	    return;
+	  }
+      }
+
+
+    
+    possiblecrossp = (numprim >= 3) && calccp;
+    surecrossp = 0;
+
+    if (possiblecrossp && (locsurf.Size() <= check_crosspoint || level > 50))
+      {
+	decision = 1;
+	surecrossp = 0;
+
+	for (int k1 = 1; k1 <= locsurf.Size() - 2; k1++)
+	  for (int k2 = k1 + 1; k2 <= locsurf.Size() - 1; k2++)
+	    for (int 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)), box );
+	      
+		deg = CrossPointDegenerated 
+		  (geometry->GetSurface(locsurf.Get(k1)), 
+		   geometry->GetSurface(locsurf.Get(k2)), 
+		   geometry->GetSurface(locsurf.Get(k3)), box );
+	      
+#ifdef DEVELOP
+		(*testout) << "k1,2,3 = " << k1 << "," << k2 << "," << k3 << ", nc = " << nc << ", deg = " << deg << endl;
+#endif
+
+
+		if (!nc && !deg) decision = 0;
+		if (nc) surecrossp = 1;
+	      }
+
+#ifdef DEVELOP
+        (*testout) << "dec = " << decision << ", surcp = " << surecrossp << endl;
+#endif
+
+	if (decision && surecrossp)
+	  {
+	    for (int k1 = 1; k1 <= locsurf.Size() - 2; k1++)
+	      for (int k2 = k1 + 1; k2 <= locsurf.Size() - 1; k2++)
+		for (int k3 = k2 + 1; k3 <= locsurf.Size(); k3++)
+		  {
+		    if (CrossPointNewtonConvergence 
+			(geometry->GetSurface(locsurf.Get(k1)), 
+			 geometry->GetSurface(locsurf.Get(k2)), 
+			 geometry->GetSurface(locsurf.Get(k3)), box ) )
+		      {
+                        
+			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*size);
+
+			if (pp(0) > box.PMin()(0) - 1e-5*size && 
+			    pp(0) < box.PMax()(0) + 1e-5*size &&
+			    pp(1) > box.PMin()(1) - 1e-5*size && 
+			    pp(1) < box.PMax()(1) + 1e-5*size &&
+			    pp(2) > box.PMin()(2) - 1e-5*size && 
+			    pp(2) < box.PMax()(2) + 1e-5*size &&
+			    sol -> IsIn (pp, 1e-6*size) && !sol->IsStrictIn (pp, 1e-6*size) &&
+			    !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*size);
+			    boxp.CalcDiamCenter();
+			    Array<int> locsurf2;
+
+			    geometry -> GetIndependentSurfaceIndices (sol, boxp, locsurf2);
+			  
+			    bool found1 = false, found2 = false, found3 = false;
+			    for (int i = 0; i < locsurf2.Size(); i++)
+			      {
+				if (locsurf2[i] == locsurf.Get(k1)) found1 = true;
+				if (locsurf2[i] == locsurf.Get(k2)) found2 = true;
+				if (locsurf2[i] == locsurf.Get(k3)) found3 = true;
+			      }
+
+			    if (found1 && found2 && found3)
+			      if (AddPoint (pp, layer))
+				{
+				  (*testout) << "Crosspoint found: " << pp 
+					     << " diam = " << box.Diam()
+					     << ",  surfs: " 
+					     << locsurf.Get(k1) << "," 
+					     << locsurf.Get(k2) << "," 
+					     << locsurf.Get(k3) << endl;
+				}
+			  }
+		      }
+		  }
+	  }
+      
+	if (decision)
+	  possiblecrossp = 0;
+      }
+
+
+    possibleexp = (numprim >= 2) && calcep;
+
+    // (*testout) << "l = " << level << "locsize = " << locsurf.Size() << " possexp = " << possibleexp << "\n";
+    if (possibleexp && (numprim <= check_crosspoint || level >= 50))
+      {
+	decision = 1;
+	sureexp = 0;
+
+	/*
+	(*testout) << "extremal surfs = ";
+	for (int k5 = 0; k5 < locsurf.Size(); k5++)
+	  (*testout) << typeid(*geometry->GetSurface(locsurf[k5])).name() << " ";
+	(*testout) << "\n";
+	*/
+
+	for (int k1 = 0; k1 < locsurf.Size() - 1; k1++)
+	  for (int k2 = k1+1; k2 < locsurf.Size(); k2++)
+	    {
+	      const Surface * surf1 = geometry->GetSurface(locsurf[k1]);
+	      const Surface * surf2 = geometry->GetSurface(locsurf[k2]);
+	      /*
+	      (*testout) << "edgecheck, types = " << typeid(*surf1).name() << ", " << typeid(*surf2).name()
+			 << "edge-newton-conv = " << EdgeNewtonConvergence (surf1, surf2, p)
+			 << "edge-deg = " << EdgeDegenerated (surf1, surf2, box)
+			 << "\n";
+	      */
+
+	      if (EdgeNewtonConvergence (surf1, surf2, p) ) 
+		sureexp = 1;
+	      else
+		{
+		  if (!EdgeDegenerated (surf1, surf2, box)) 
+		    decision = 0;
+		}
+	    }
+
+	// (*testout) << "l = " << level << " dec/sureexp = " << decision << sureexp << endl;
+
+	if (decision && sureexp)
+	  {
+	    for (int k1 = 0; k1 < locsurf.Size() - 1; k1++)
+	      for (int k2 = k1+1; k2 < locsurf.Size(); k2++)
+		{
+		  const Surface * surf1 = geometry->GetSurface(locsurf[k1]);
+		  const Surface * surf2 = geometry->GetSurface(locsurf[k2]);
+
+		  if (EdgeNewtonConvergence (surf1, surf2, p))
+		    {
+		      EdgeNewton (surf1, surf2, p);
+		    
+		      Point<3> pp;
+		      if (IsEdgeExtremalPoint (surf1, surf2, p, pp, box.Diam()/2))
+			{
+			  (*testout) << "extremalpoint (nearly) found:" << pp << endl;
+
+			  if (Dist (pp, box.Center()) < box.Diam()/2 &&
+			      sol -> IsIn (pp, 1e-6*size) && !sol->IsStrictIn (pp, 1e-6*size) )
+			    {
+			      if (AddPoint (pp, layer))
+				(*testout) << "Extremal point found: " << pp << endl;//"(eps="<<1e-9*size<<")"<< endl;
+			    }  
+			}            
+		    }
+		}
+	  }
+	if (decision)
+	  possibleexp = 0;
+      }
+ 
+
+    // (*testout) << "l = " << level << " poss cp/ep sure exp = " << possiblecrossp << " " << possibleexp << " " << sureexp << "\n";
+    if (possiblecrossp || possibleexp)
+      {
+	BoxSphere<3> sbox;
+	for (int i = 0; i < 8; i++)
+	  {
+	    box.GetSubBox (i, sbox);
+	    sbox.Increase (1e-4 * sbox.Diam());
+	    sbox.CalcDiamCenter();
+	    Solid * 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 BoxSphere<3> & box)
+  {
+    Vec<3> grad, rs, x;
+    Mat<3> jacobi, inv;
+    Point<3> p = box.Center();
+
+    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);
+
+    if (fabs (Det (jacobi)) > 1e-8)
+      {
+	double gamma = f1 -> HesseNorm() + f2 -> HesseNorm() + f3 -> HesseNorm();
+	if (gamma == 0.0) return 1;
+
+	CalcInverse (jacobi, inv);
+
+	rs(0) = f1->CalcFunctionValue (p);
+	rs(1) = f2->CalcFunctionValue (p);
+	rs(2) = f3->CalcFunctionValue (p);
+
+	x = inv * rs;
+
+	double beta = 0;
+	for (int i = 0; i < 3; i++)
+	  {
+	    double sum = 0;
+	    for (int j = 0; j < 3; j++)
+	      sum += fabs (inv(i,j));
+	    if (sum > beta)  beta = sum;
+	  }
+	double eta = Abs (x);
+
+
+#ifdef DEVELOP
+        *testout << "check Newton: " << "beta = " << beta << ", gamma = " << gamma << ", eta = " << eta << endl;
+        double rad = 1.0 / (beta * gamma);
+        *testout << "rad = " << rad << endl;
+	*testout << "rs = " << rs << endl;
+#endif
+        
+	return (beta * gamma * eta < 0.1) && (2 > box.Diam()*beta*gamma);
+      }
+    return 0;
+
+  }
+
+
+
+
+  bool SpecialPointCalculation :: 
+  CrossPointDegenerated (const Surface * f1,
+			 const Surface * f2, 
+			 const Surface * f3, 
+			 const BoxSphere<3> & box) const
+  {
+    Mat<3> mat;
+    Vec<3> g1, g2, g3;
+    double normprod;
+
+    if (box.Diam() > relydegtest) return 0;
+
+    f1->CalcGradient (box.Center(), g1);
+    normprod = Abs2 (g1);
+
+    f2->CalcGradient (box.Center(), g2);
+    normprod *= Abs2 (g2);
+ 
+    f3->CalcGradient (box.Center(), g3);
+    normprod *= Abs2 (g3);
+
+    for (int i = 0; i < 3; i++)
+      {
+	mat(i,0) = g1(i);
+	mat(i,1) = g2(i);
+	mat(i,2) = g3(i);
+      }
+
+    return sqr (Det (mat)) < sqr(cpeps1) * normprod;
+  }
+ 
+
+
+
+
+  void SpecialPointCalculation :: CrossPointNewton (const Surface * f1, 
+						    const Surface * f2, 
+						    const Surface * f3, Point<3> & p)
+  {
+    Vec<3> g1, g2, g3;
+    Vec<3> rs, sol;
+    Mat<3> mat;
+
+    int 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);
+	if (sol.Length2() < 1e-24 && i > 1) i = 1;
+
+#ifdef DEVELOP
+        *testout << "CrossPointNewton, err = " << sol.Length2() << endl;
+#endif
+	p -= sol;
+      }
+  }
+
+
+
+
+  /******* Tests for Point on edges **********************/
+
+
+
+
+  bool SpecialPointCalculation :: 
+  EdgeNewtonConvergence (const Surface * f1, const Surface * f2, 
+			 const Point<3> & p)
+  {
+    Vec<3> g1, g2, sol;
+    Vec<2> vrs;
+    Mat<2,3> mat;
+    Mat<3,2> inv;
+
+    f1->CalcGradient (p, g1);
+    f2->CalcGradient (p, g2);
+
+    if ( sqr(g1 * g2) < (1 - 1e-8) * Abs2 (g1) * Abs2 (g2))
+      {
+	double gamma = f1 -> HesseNorm() + f2 -> HesseNorm();
+	if (gamma < 1e-32) return 1;
+	gamma = sqr (gamma);
+      
+	for (int i = 0; i < 3; i++)
+	  {
+	    mat(0,i) = g1(i);
+	    mat(1,i) = g2(i);
+	  }
+
+	CalcInverse (mat, inv);
+
+	vrs(0) = f1->CalcFunctionValue (p);
+	vrs(1) = f2->CalcFunctionValue (p);
+	sol = inv * vrs;
+
+	double beta = 0;
+	for (int i = 0; i < 3; i++)
+	  for (int j = 0; j < 2; j++)
+	    beta += inv(i,j) * inv(i,j);
+	// beta = sqrt (beta);
+
+	double eta = Abs2 (sol);
+
+	// alpha = beta * gamma * eta;
+	return (beta * gamma * eta < 0.01);
+      }
+    return 0;
+  }
+
+
+
+
+  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();
+    Vec<3> g1, g2, sol;
+    Vec<2> vrs;
+    Mat<2,3> mat;
+
+    int i = 20;
+    while (i > 0)
+      {
+	if (Dist2 (p, box.Center()) > sqr(box.Diam()))
+	  return 0;
+
+	i--;
+	vrs(0) = f1->CalcFunctionValue (p);
+	vrs(1) = f2->CalcFunctionValue (p);
+
+	f1->CalcGradient (p, g1);
+	f2->CalcGradient (p, g2);
+
+	if ( sqr (g1 * g2) > (1 - 1e-10) * Abs2 (g1) * Abs2 (g2))
+	  return 1;
+
+	for (int j = 0; j < 3; j++)
+	  {
+	    mat(0,j) = g1(j);
+	    mat(1,j) = g2(j);
+	  }
+	mat.Solve (vrs, sol);
+
+	if (Abs2 (sol) < 1e-24 && i > 1) i = 1;
+	p -= sol;
+      }
+
+    return 0;
+  }
+
+
+
+
+
+
+  void SpecialPointCalculation :: EdgeNewton (const Surface * f1, 
+					      const Surface * f2, Point<3> & p)
+  {
+    Vec<3> g1, g2, sol;
+    Vec<2> vrs;
+    Mat<2,3> mat;
+
+    int i = 10;
+    while (i > 0)
+      {
+	i--;
+	vrs(0) = f1->CalcFunctionValue (p);
+	vrs(1) = f2->CalcFunctionValue (p);
+
+	f1->CalcGradient (p, g1);
+	f2->CalcGradient (p, g2);
+
+	//(*testout) << "p " << p << " f1 " << vrs(0) << " f2 " << vrs(1) << " g1 " << g1 << " g2 " << g2 << endl;
+
+	for (int j = 0; j < 3; j++)
+	  {
+	    mat(0,j) = g1(j);
+	    mat(1,j) = g2(j);
+	  }
+	mat.Solve (vrs, sol);
+	
+	if (Abs2 (sol) < 1e-24 && 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;
+
+    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 (int 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)
+  {
+    Vec<3> g1, g2, v, curv;
+    Vec<3> rs, x, y1, y2, y;
+    Mat<3> h1, h2;
+    Mat<3> jacobi;
+
+    int 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);
+
+	/*
+	(*testout) << "p " << p << " f1 " << rs(0) << " f2 " << rs(1) << endl
+		   << " jacobi " << jacobi << endl
+		   << " rhs " << rs << endl;
+	*/	
+
+	jacobi.Solve (rs, x);
+
+	if (Abs2 (x) < 1e-24 && i > 1)
+	  {
+	    i = 1;
+	  }
+
+	
+	double minval(Abs2(rs)),minfac(1);
+	double startval(minval);
+	for(double fac = 1; fac > 1e-7; fac *= 0.6)
+	  {
+	    Point<3> testpoint = p-fac*x;
+
+	    rs(0) = f1->CalcFunctionValue (testpoint);
+	    rs(1) = f2->CalcFunctionValue (testpoint);
+
+	    f1 -> CalcGradient (testpoint, g1);
+	    f2 -> CalcGradient (testpoint, g2);
+
+	    v = Cross (g1, g2);
+
+	    rs(2) = v(dir-1);
+
+	    double val = Abs2(rs);
+
+	    if(val < minval)
+	      {
+		minfac = fac;
+		if(val < 0.5 * startval)
+		  break;
+		minval = val;
+	      }
+
+	  }
+	p -= minfac*x;
+	
+
+	//p -= x;
+      }
+
+
+    if (Abs2 (x) > 1e-20)
+      {
+	(*testout) << "Error: extremum Newton not convergent" << endl;
+	(*testout) << "dir = " << dir << endl;
+	(*testout) << "p = " << p << endl;
+	(*testout) << "x = " << x << endl;
+      }
+  }
+
+  void SpecialPointCalculation :: 
+  ComputeCrossPoints (const Plane * plane1, 
+		      const Plane * plane2, 
+		      const Plane * plane3, 
+		      Array<Point<3> > & pts)
+  {
+    Mat<3> mat;
+    Vec<3> rhs, sol;
+    Point<3> p0(0,0,0);
+
+    pts.SetSize (0);
+    for (int i = 0; i < 3; i++)
+      {
+	const Plane * pi(NULL);
+	switch (i)
+	  {
+	  case 0: pi = plane1; break;
+	  case 1: pi = plane2; break;
+	  case 2: pi = plane3; break;
+	  }
+
+	double val;
+	Vec<3> hvec;
+	val = pi -> CalcFunctionValue(p0);
+	pi -> CalcGradient (p0, hvec);
+
+	for (int j = 0; j < 3; j++)
+	  mat(i,j) = hvec(j);
+	rhs(i) = -val;
+      }
+
+    if (fabs (Det (mat)) > 1e-8)
+      {
+	mat.Solve (rhs, sol);
+	pts.Append (Point<3> (sol));
+      }
+  }
+
+
+
+
+
+  void SpecialPointCalculation :: 
+  ComputeCrossPoints (const Plane * plane1, 
+		      const Plane * plane2, 
+		      const QuadraticSurface * quadric, 
+		      Array<Point<3> > & pts)
+  {
+    Mat<2,3> mat;
+    Mat<3,2> inv;
+    Vec<2> rhs;
+    Vec<3> sol, t;
+    Point<3> p0(0,0,0);
+
+    pts.SetSize (0);
+    for (int i = 0; i < 2; i++)
+      {
+	const Plane * pi(NULL);
+	switch (i)
+	  {
+	  case 0: pi = plane1; break;
+	  case 1: pi = plane2; break;
+	  }
+
+	double val;
+	Vec<3> hvec;
+	val = pi -> CalcFunctionValue(p0);
+	pi -> CalcGradient (p0, hvec);
+
+	for (int j = 0; j < 3; j++)
+	  mat(i,j) = hvec(j);
+	rhs(i) = -val;
+      }
+    CalcInverse (mat, inv);
+    sol = inv * rhs;
+    t = Cross (mat.Row(0), mat.Row(1));
+
+    if (t.Length() > 1e-8)
+      {
+	Point<3> p (sol);
+	// quadratic on  p + s t = 0
+	double quad_a;
+	Vec<3> quad_b;
+	Mat<3> quad_c;
+	
+	quad_a = quadric -> CalcFunctionValue(p);
+	quadric -> CalcGradient (p, quad_b);
+	quadric -> CalcHesse (p, quad_c);
+	
+	double a, b, c;
+	a = quad_a;
+	b = quad_b * t;
+	c = 0.5 * t * (quad_c * t);
+
+	// a  + s b + s^2 c = 0;
+	double disc = b*b-4*a*c;
+	if (disc > 1e-10 * fabs (b))
+	  {
+	    disc = sqrt (disc);
+	    double s1 = (-b-disc) / (2*c);
+	    double s2 = (-b+disc) / (2*c);
+
+	    pts.Append (p + s1 * t);
+	    pts.Append (p + s2 * t);
+	  }
+      }
+  }
+
+
+
+
+
+  void SpecialPointCalculation :: 
+  ComputeCrossPoints (const Sphere * sphere1, 
+		      const Sphere * sphere2, 
+		      const Sphere * sphere3, 
+		      Array<Point<3> > & pts)
+  {
+    Mat<2,3> mat;
+    Mat<3,2> inv;
+    Vec<2> rhs;
+    Vec<3> sol, t;
+    Point<3> p0(0,0,0);
+
+    pts.SetSize (0);
+
+
+    Point<3> c1 = sphere1 -> Center();
+    Point<3> c2 = sphere2 -> Center();
+    Point<3> c3 = sphere3 -> Center();
+    double r1 = sphere1 -> Radius();
+    double r2 = sphere2 -> Radius();
+    double r3 = sphere3 -> Radius();
+
+
+    Vec<3> a1 = c2-c1;
+    double b1 = 0.5 * (sqr(r1) - sqr(r2) - Abs2(Vec<3> (c1)) + Abs2(Vec<3> (c2)) );
+
+    Vec<3> a2 = c3-c1;
+    double b2 = 0.5 * (sqr(r1) - sqr(r3) - Abs2(Vec<3> (c1)) + Abs2(Vec<3> (c3)) );
+
+
+    for (int j = 0; j < 3; j++)
+      {
+	mat(0,j) = a1(j);
+	mat(1,j) = a2(j);
+      }
+    
+    rhs(0) = b1;
+    rhs(1) = b2;
+
+
+    CalcInverse (mat, inv);
+    sol = inv * rhs;
+    t = Cross (mat.Row(0), mat.Row(1));
+
+    if (t.Length() > 1e-8)
+      {
+	Point<3> p (sol);
+	// quadratic on  p + s t = 0
+	double quad_a;
+	Vec<3> quad_b;
+	Mat<3> quad_c;
+	
+	quad_a = sphere1 -> CalcFunctionValue(p);
+	sphere1 -> CalcGradient (p, quad_b);
+	sphere1 -> CalcHesse (p, quad_c);
+	
+	double a, b, c;
+	a = quad_a;
+	b = quad_b * t;
+	c = 0.5 * t * (quad_c * t);
+
+	// a  + s b + s^2 c = 0;
+	double disc = b*b-4*a*c;
+	if (disc > 1e-10 * fabs (b))
+	  {
+	    disc = sqrt (disc);
+	    double s1 = (-b-disc) / (2*c);
+	    double s2 = (-b+disc) / (2*c);
+
+	    pts.Append (p + s1 * t);
+	    pts.Append (p + s2 * t);
+	  }
+      }
+  }
+
+
+
+
+
+
+
+
+
+
+  void SpecialPointCalculation :: 
+  ComputeExtremalPoints (const Plane * plane, 
+			 const QuadraticSurface * quadric, 
+			 Array<Point<3> > & pts)
+  {
+    // 3 equations:
+    // surf1 = 0  <===> plane_a + plane_b x = 0;
+    // surf2 = 0  <===> quad_a + quad_b x + x^T quad_c x = 0
+    // (grad 1 x grad 2)(i) = 0  <====> (grad 1 x e_i) . grad_2 = 0
+
+    pts.SetSize (0);
+
+    Point<3> p0(0,0,0);
+    double plane_a, quad_a;
+    Vec<3> plane_b, quad_b, ei;
+    Mat<3> quad_c;
+
+    plane_a = plane -> CalcFunctionValue(p0);
+    plane -> CalcGradient (p0, plane_b);
+
+    quad_a = quadric -> CalcFunctionValue(p0);
+    quadric -> CalcGradient (p0, quad_b);
+    quadric -> CalcHesse (p0, quad_c);
+    for (int i = 0; i < 3; i++)
+      for (int j = 0; j < 3; j++)
+	quad_c(i,j) *= 0.5;
+
+    for (int dir = 0; dir <= 2; dir++)
+      {
+	ei = 0.0; ei(dir) = 1;
+	Vec<3> v1 = Cross (plane_b, ei);
+	
+	// grad_2 . v1 ... linear:
+	double g2v1_c = v1 * quad_b;
+	Vec<3> g2v1_l = 2.0 * (quad_c * v1);
+
+	// find line of two linear equations:
+	
+	Vec<2> rhs;
+	Vec<3> sol;
+	Mat<2,3> mat;
+
+	for (int j = 0; j < 3; j++)
+	  {
+	    mat(0,j) = plane_b(j);
+	    mat(1,j) = g2v1_l(j);
+	  }
+	rhs(0) = -plane_a;
+	rhs(1) = -g2v1_c;
+
+	Vec<3> t = Cross (plane_b, g2v1_l);
+	if (Abs2(t) > 0)
+	  {
+	    mat.Solve (rhs, sol);
+	    
+	    // solve quadratic equation along line  sol + alpha t ....
+	    double a = quad_a + quad_b * sol + sol * (quad_c * sol);
+	    double b = quad_b * t + 2 * (sol * (quad_c * t));
+	    double c = t * (quad_c * t);
+
+	    // solve a + b alpha + c alpha^2:
+
+	    if (fabs (c) > 1e-32)
+	      {
+		double disc = sqr (0.5*b/c) - a/c;
+		if (disc > 0)
+		  {
+		    disc = sqrt (disc);
+		    double alpha1 = -0.5*b/c + disc;
+		    double alpha2 = -0.5*b/c - disc;
+
+		    pts.Append (Point<3> (sol+alpha1*t));
+		    pts.Append (Point<3> (sol+alpha2*t));
+		    /*
+		    cout << "sol1 = " << sol + alpha1 * t
+			 << ", sol2 = " << sol + alpha2 * t << endl;
+		    */
+		  }
+	      }
+	  }
+      }
+  }
+
+
+
+
+
+
+
+  void SpecialPointCalculation :: 
+  ComputeExtremalPoints (const Sphere * sphere1,
+			 const Sphere * sphere2,
+			 Array<Point<3> > & pts)
+  {
+    // 3 equations:
+    // surf1 = 0  <===> |x-c1|^2 - r1^2 = 0;
+    // surf2 = 0  <===> |x-c2|^2 - r2^2 = 0;
+    // (grad 1 x grad 2)(i) = 0  <====> (x-p1) x (p1-p2) . e_i = 0;
+
+    pts.SetSize (0);
+
+    Point<3> c1 = sphere1 -> Center();
+    Point<3> c2 = sphere2 -> Center();
+    double r1 = sphere1 -> Radius();
+    double r2 = sphere2 -> Radius();
+
+    /*
+    *testout << "\n\ncompute extremalpoint, sphere-sphere" << endl;
+    *testout << "c1 = " << c1 << ", r1 = " << r1 << endl;
+    *testout << "c2 = " << c2 << ", r2 = " << r2 << endl;
+    *testout << "dist = " << Abs (c2-c1) << ", r1+r2 = " << r1+r2 << endl;
+    */
+
+    Vec<3> v12 = c2 - c1;
+
+    Vec<3> a1, a2;
+    double b1, b2;
+
+    // eqn: ai . x = bi
+
+    a1 = v12;
+    b1 = 0.5 * (sqr(r1) - sqr(r2) - Abs2(Vec<3> (c1)) + Abs2(Vec<3> (c2)) );
+
+    int dir = 0;
+    for (int j = 1; j < 3; j++)
+      if (fabs (v12(j)) > v12(dir))
+	dir = j;
+    
+    // *testout << "dir = " << dir << endl;
+
+    Vec<3> ei = 0.0;
+    ei(dir) = 1;
+    a2 = Cross (v12, ei);
+    b2 = Vec<3>(c1) * a2;
+    
+    
+    Point<3> p0 (0,0,0);
+    double quad_a;
+    Vec<3> quad_b;
+    Mat<3> quad_c;
+
+    quad_a = sphere1 -> CalcFunctionValue(p0);
+    sphere1 -> CalcGradient (p0, quad_b);
+    sphere1 -> CalcHesse (p0, quad_c);
+    for (int i = 0; i < 3; i++)
+      for (int j = 0; j < 3; j++)
+	quad_c(i,j) *= 0.5;
+
+    
+    // find line of two linear equations:
+    
+    Vec<2> rhs;
+    Vec<3> sol;
+    Mat<2,3> mat;
+    
+    for (int j = 0; j < 3; j++)
+      {
+	mat(0,j) = a1(j);
+	mat(1,j) = a2(j);
+      }
+    rhs(0) = b1;
+    rhs(1) = b2;
+
+
+    // *testout << "mat = " << endl << mat << endl;
+    // *testout << "rhs = " << endl << rhs << endl;
+
+    Vec<3> t = Cross (a1, a2);
+    if (Abs2(t) > 0)
+      {
+	mat.Solve (rhs, sol);
+	
+	/*
+	*testout << "sol = " << endl << sol << endl;
+
+	*testout << "a * sol = " << mat * sol << endl;
+
+	*testout << "c1-sol = " << Abs (Vec<3>(c1)-sol) << endl;
+	*testout << "c2-sol = " << Abs (Vec<3>(c2)-sol) << endl;
+	*/
+
+	// solve quadratic equation along line  sol + alpha t ....
+	double a = quad_a + quad_b * sol + sol * (quad_c * sol);
+	double b = quad_b * t + 2 * (sol * (quad_c * t));
+	double c = t * (quad_c * t);
+
+	// solve a + b alpha + c alpha^2:
+	
+	if (fabs (c) > 1e-32)
+	  {
+	    double disc = sqr (0.5*b/c) - a/c;
+	    if (disc > 0)
+	      {
+		disc = sqrt (disc);
+		double alpha1 = -0.5*b/c + disc;
+		double alpha2 = -0.5*b/c - disc;
+		
+		pts.Append (Point<3> (sol+alpha1*t));
+		pts.Append (Point<3> (sol+alpha2*t));
+
+		// *testout << "pts = " << endl << pts << endl;
+
+		/*
+		  cout << "sol1 = " << sol + alpha1 * t
+		  << ", sol2 = " << sol + alpha2 * t << 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);
+
+    //  (*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 false;
+
+    points->Append (MeshPoint(p, layer));
+    PrintMessageCR (3, "Found points ", points->Size());
+    return true;
+  }
+
+
+
+
+
+
+
+  void SpecialPointCalculation :: 
+  AnalyzeSpecialPoints (const CSGeometry & ageometry,
+			Array<MeshPoint> & apoints, 
+			Array<SpecialPoint> & specpoints)
+  {
+    static int timer = NgProfiler::CreateTimer ("CSG: analyze special points");
+    NgProfiler::RegionTimer reg (timer);
+
+
+    Array<int> surfind, rep_surfind, surfind2, rep_surfind2, surfind3;
+
+    Array<Vec<3> > normalvecs;
+    Vec<3> nsurf = 0.0;
+
+    Array<int> specpoint2point;
+    specpoints.SetSize (0);
+
+    geometry = &ageometry;
+
+    double geomsize = ageometry.MaxSize();
+ 
+    (*testout) << "AnalyzeSpecialPoints\n";
+
+    if (!apoints.Size()) return;
+
+
+    {
+      /*
+	sort points in the (arbitrary) direction dir
+	important for periodic boundaries: 
+	corner points on the left and the right boundary come in the same ordering
+      */
+      Vec<3> dir(1.2, 1.7, 0.9);
+      
+      Array<double> coord(apoints.Size());
+      for (int i = 0; i < apoints.Size(); i++)
+	coord[i] = dir * Vec<3> (apoints[i]);
+      
+      QuickSort (coord, apoints);
+    }
+
+
+
+
+
+    Box<3> bbox (apoints[0], apoints[0]);
+    for (int i = 1; i < apoints.Size(); i++)
+      bbox.Add (apoints[i]);
+    bbox.Increase (0.1 * bbox.Diam());
+
+    (*testout) << "points = " << apoints << endl;
+
+    Point3dTree searchtree (bbox.PMin(), bbox.PMax());
+    Array<int> locsearch;
+
+    for (int si = 0; si < ageometry.GetNTopLevelObjects(); si++)
+      {
+	const TopLevelObject * tlo = ageometry.GetTopLevelObject(si);
+
+	const Solid * sol = tlo->GetSolid();
+	const Surface * surf = tlo->GetSurface();
+
+
+	for (int i = 0; i < apoints.Size(); i++)
+	  {
+	    Point<3> p = apoints[i];
+	    
+#ifdef DEVELOP
+	    *testout << "                               test point " << p << endl;
+#endif	    
+
+	    if (tlo->GetLayer() != apoints[i].GetLayer())
+	      continue;
+	    
+
+	    Solid * locsol;
+	    sol -> TangentialSolid (p, locsol, surfind, ideps*geomsize);
+
+
+	    rep_surfind.SetSize (surfind.Size());
+	    int num_indep_surfs = 0;
+	    
+	    for (int j = 0; j < surfind.Size(); j++)
+	      {
+		rep_surfind[j] = ageometry.GetSurfaceClassRepresentant (surfind[j]);
+		bool found = false;
+		for (int k = 0; !found && k < j; k++)
+		  found = (rep_surfind[k] == rep_surfind[j]);
+		if(!found)
+		  num_indep_surfs++;
+	      }
+	    
+
+#ifdef DEVELOP
+	    *testout << "surfs = " << surfind << endl;
+	    *testout << "rep_surfs = " << rep_surfind << endl;
+#endif
+
+	    if (!locsol) continue;
+
+	  
+	    // get all surface indices, 
+	    if (surf)
+	      {
+		// locsol -> GetSurfaceIndices (surfind);
+		bool hassurf = 0;
+		for (int m = 0; m < surfind.Size(); m++)
+		  if (ageometry.GetSurface(surfind[m]) == surf)
+		    hassurf = 1;
+
+		if (!hassurf)
+		  continue;
+
+		nsurf = surf->GetNormalVector (p);
+	      }
+
+	    /*
+	    // get independent surfaces of tangential solid
+	    BoxSphere<3> box(p,p);
+	    box.Increase (1e-6*geomsize);
+	    box.CalcDiamCenter();
+	    ageometry.GetIndependentSurfaceIndices (locsol, box, surfind);
+	    */
+
+	    // ageometry.GetIndependentSurfaceIndices (surfind);
+
+
+	    normalvecs.SetSize(surfind.Size());
+	    for (int j = 0; j < surfind.Size(); j++)
+	      normalvecs[j] = 
+		ageometry.GetSurface(surfind[j]) -> GetNormalVector(apoints[i]);
+
+
+	    for (int j = 0; j < normalvecs.Size(); j++)
+	      for (int k = 0; k < normalvecs.Size(); k++)
+		{
+		  if (rep_surfind[j] == rep_surfind[k]) continue;
+		  //if (j == k) continue;
+
+		  Vec<3> t;
+
+		  if (dynamic_cast<const Polyhedra*> (ageometry.surf2prim[surfind[j]]) && 
+		      ageometry.surf2prim[surfind[j]] == 
+		      ageometry.surf2prim[surfind[k]])
+		    {
+		      t = ageometry.surf2prim[surfind[j]] -> 
+			SpecialPointTangentialVector (p, surfind[j], surfind[k]);
+		    }
+		  else
+		    {
+		      t = Cross (normalvecs[j], normalvecs[k]);
+		    }
+
+
+		  if (Abs2 (t) < 1e-8)
+		    continue;
+
+#ifdef DEVELOP
+		  *testout << "           tangential vector " << t << endl;
+#endif
+
+		  t.Normalize();
+
+		  
+		  // try tangential direction t
+		  if (surf && fabs (nsurf * t) > 1e-6)
+		    continue;
+
+		
+#ifdef DEVELOP
+		  *testout << "           j " << j << " k " << k << endl;
+#endif  
+
+		  if (!surf)
+		    {
+		      // compute second order approximation
+		      // c(s) = p + s t + s*s/2 t2
+		      Vec<3> gradj, gradk;
+		      Mat<3> hessej, hessek;
+		      ageometry.GetSurface (surfind[j]) -> CalcGradient (p, gradj);
+		      ageometry.GetSurface (surfind[k]) -> CalcGradient (p, gradk);
+		      ageometry.GetSurface (surfind[j]) -> CalcHesse (p, hessej);
+		      ageometry.GetSurface (surfind[k]) -> CalcHesse (p, hessek);
+		      
+		      Vec<2> rhs;
+		      Vec<3> t2;
+		      Mat<2,3> mat;
+		      Mat<3,2> inv;
+		      for (int l = 0; l < 3; l++)
+			{
+			  mat(0,l) = gradj(l);
+			  mat(1,l) = gradk(l);
+			}
+		      rhs(0) = -t * (hessej * t);
+		      rhs(1) = -t * (hessek * t);
+
+		      CalcInverse (mat, inv);
+		      t2 = inv * rhs;
+
+		      
+		      /*
+		      ageometry.GetIndependentSurfaceIndices 
+			(locsol, p, t, surfind2);
+		      */
+
+		      Solid * locsol2;
+		      locsol -> TangentialSolid3 (p, t, t2, locsol2, surfind2, ideps*geomsize); 
+		      if (!locsol2) continue;
+		      
+		      // locsol2 -> GetTangentialSurfaceIndices3 (p, t, t2, surfind2, 1e-9*geomsize);
+
+		      rep_surfind2.SetSize (surfind2.Size());
+		      for (int j2 = 0; j2 < surfind2.Size(); j2++)
+			rep_surfind2[j2] = ageometry.GetSurfaceClassRepresentant (surfind2[j2]);
+
+#ifdef DEVELOP
+		      (*testout) << "surfind2 = " << endl << surfind2 << endl;
+#endif
+		      Array<int> surfind2_aux(surfind2);
+		      ageometry.GetIndependentSurfaceIndices (surfind2_aux);
+#ifdef DEVELOP
+		      (*testout) << "surfind2,rep = " << endl << surfind2_aux << endl;
+#endif
+
+		      bool ok = true;
+
+		      // intersecting surfaces must be in second order tangential solid
+		      /*
+		      if (!surfind2.Contains(surfind[j]) ||
+			  !surfind2.Contains(surfind[k]))
+			ok = false;
+		      */
+		      if (!surfind2_aux.Contains(rep_surfind[j]) ||
+			  !surfind2_aux.Contains(rep_surfind[k]))
+			ok = false;
+
+#ifdef DEVELOP
+		      (*testout) << "ok,1 = " << ok << endl;
+#endif
+
+		      // there must be 2 different tangential faces to the edge
+		      int cnt_tang_faces = 0;
+		      for (int l = 0; l < surfind2.Size(); l++)
+			{
+			  Vec<3> nv =
+			    ageometry.GetSurface(surfind2[l]) -> GetNormalVector(p);
+
+			 
+			  Vec<3> m1 = Cross (t, nv);
+			  Vec<3> m2 = -m1;
+			  bool isface1 = 0, isface2 = 0;
+			  
+			  Solid * locsol3;
+
+			  // locsol2 -> TangentialSolid2 (p, m1, locsol3, surfind3, 1e-9*geomsize);
+			  locsol -> TangentialEdgeSolid (p, t, t2, m1, locsol3, surfind3, ideps*geomsize);
+
+			  //ageometry.GetIndependentSurfaceIndices (surfind3);
+
+			  if (surfind3.Contains(surfind2[l]))
+			    isface1 = 1;
+			  delete locsol3;
+			  
+			  // locsol2 -> TangentialSolid2 (p, m2, locsol3, surfind3, 1e-9*geomsize);
+			  locsol -> TangentialEdgeSolid (p, t, t2, m2, locsol3, surfind3, ideps*geomsize); 
+
+			  // ageometry.GetIndependentSurfaceIndices (surfind3);
+
+			  
+			  if (surfind3.Contains(surfind2[l]))
+			    isface2 = 1;
+			  delete locsol3;
+
+			  if (isface1 != isface2)
+			    cnt_tang_faces++;
+			}
+
+#ifdef DEVELOP
+		      (*testout) << "cnt_tang = " << cnt_tang_faces << endl;
+#endif
+
+		      if (cnt_tang_faces < 1)
+			ok = false;
+
+		      delete locsol2;
+		      if (!ok) continue;
+		    }
+
+		  
+		  // edge must be on tangential surface
+		  bool isedge = 
+		    locsol->VectorIn (p, t) &&
+		    !locsol->VectorStrictIn (p, t);
+		  
+#ifdef DEVELOP
+		  (*testout) << "isedge,1 = " << isedge << "\n";
+#endif		
+  
+		  // there must exist at least two different faces on edge
+		  if (isedge)
+		    {
+		      // *testout << "succ 1" << endl;
+		      int cnts = 0;
+		      for (int 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;
+			  
+			  bool isface =
+			    (locsol->VectorIn (p, t2a, 1e-6*geomsize) &&
+			     !locsol->VectorStrictIn (p, t2a, 1e-6*geomsize))
+			    ||
+			    (locsol->VectorIn (p, t2b, 1e-6*geomsize) &&
+			     !locsol->VectorStrictIn (p, t2b, 1e-6*geomsize));
+			  
+			  /*
+			  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)
+		    {
+#ifdef DEVELOP
+		      *testout << "success" << endl;
+#endif
+		      int spi = -1;
+		      
+		      const double searchradius = 1e-4*geomsize;//1e-5*geomsize;
+		      searchtree.GetIntersecting (apoints[i]-Vec3d(searchradius,searchradius,searchradius), 
+						  apoints[i]+Vec3d(searchradius,searchradius,searchradius), 
+						  locsearch);
+		      
+		      for (int m = 0; m < locsearch.Size(); m++)
+			{
+			  if (Dist2 (specpoints[locsearch[m]].p, apoints[i]) < 1e-10*geomsize
+			      && Abs2(specpoints[locsearch[m]].v - t) < 1e-8)
+			    {
+			      spi = locsearch[m];
+			      break;
+			    }
+			}
+		      
+		      
+		      if (spi == -1)
+			{
+			  spi = specpoints.Append (SpecialPoint()) - 1;
+			  specpoint2point.Append (i);
+			  specpoints.Last().unconditional = 0;
+			  searchtree.Insert (apoints[i], spi);
+			}
+
+		      if(!specpoints[spi].unconditional)
+			{
+			  specpoints[spi].p = apoints[i];
+			  specpoints[spi].v = t;
+			  //if (surfind.Size() >= 3)
+			  if (num_indep_surfs >= 3)
+			    specpoints[spi].unconditional = 1;
+			  specpoints[spi].s1 = rep_surfind[j];
+			  specpoints[spi].s2 = rep_surfind[k];
+			  specpoints[spi].s1_orig = surfind[j];
+			  specpoints[spi].s2_orig = surfind[k];
+			  specpoints[spi].layer = apoints[i].GetLayer();
+			  for (int up = 0; up < geometry->GetNUserPoints(); up++)
+			    if (Dist (geometry->GetUserPoint(up), apoints[i]) < 1e-8*geomsize)
+			      specpoints[spi].unconditional = 1;
+			  for (int ip = 0; ip < geometry->GetNIdentPoints(); ip++)
+			    if (Dist (geometry->GetIdentPoint(ip), apoints[i]) < 1e-8*geomsize)
+			      specpoints[spi].unconditional = 1;
+			}
+		    }
+		  
+		}
+
+	    delete locsol;
+	  }
+      }
+
+    /*
+    BitArray testuncond (specpoints.Size());
+    testuncond.Clear();
+    for(int i = 0; i<specpoints.Size(); i++)
+      {
+	if(testuncond.Test(i))
+	  continue;
+	
+	Array<int> same;
+	same.Append(i);
+	
+	for(int j = i+1; j<specpoints.Size(); j++)
+	  {
+	    if(Dist(specpoints[i].p,specpoints[j].p) < 1e-20)
+	      {
+		same.Append(j);
+		testuncond.Set(j);
+	      }
+	  }
+	
+	if(same.Size() < 3)
+	  for(int j=0; j<same.Size(); j++)
+	    {
+	      (*testout) << "setting " << specpoints[same[j]].p << "; " << specpoints[same[j]].v << "; " 
+			 <<specpoints[same[j]].unconditional << " to conditional" << endl;
+	      specpoints[same[j]].unconditional=0;
+	    }
+      }
+    */
+
+
+    // if special point is unconditional on some solid,
+    // it must be unconditional everywhere:
+
+    BitArray uncond (apoints.Size());
+    uncond.Clear();
+
+    for (int i = 0; i < specpoints.Size(); i++)
+      if (specpoints[i].unconditional)
+	uncond.Set (specpoint2point[i]);
+  
+    for (int i = 0; i < specpoints.Size(); i++)
+      specpoints[i].unconditional = 
+	uncond.Test (specpoint2point[i]) ? 1 : 0;
+  }
+}
diff --git a/contrib/Netgen/libsrc/csg/specpoin.hpp b/contrib/Netgen/libsrc/csg/specpoin.hpp
new file mode 100644
index 0000000000..a6d850c932
--- /dev/null
+++ b/contrib/Netgen/libsrc/csg/specpoin.hpp
@@ -0,0 +1,191 @@
+#ifndef FILE_SPECPOIN
+#define FILE_SPECPOIN
+
+
+/**************************************************************************/
+/* File:   specpoin.hpp                                                   */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   01. Okt. 95                                                    */
+/**************************************************************************/
+
+namespace netgen
+{
+
+  extern DLL_HEADER MeshingParameters mparam;
+
+  /*
+
+  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;
+    /// if s1 and s2 are only representatives, then these are the original indices
+    int s1_orig, s2_orig;
+    int nr;
+    ///
+    SpecialPoint () : p(0,0,0), v(0,0,0), layer(0), unconditional(0), s1(0), s2(0), s1_orig(0), s2_orig(0)
+    { ; }
+
+    ///
+    SpecialPoint (const SpecialPoint & sp2);
+
+    ///
+    SpecialPoint & operator= (const SpecialPoint & sp2);
+  
+    ///
+    void Print (ostream & str) const;
+
+
+    int GetLayer() const { return layer; }
+
+    ///
+    bool HasSurfaces (int as1, int as2) const
+    {
+      return ( (s1 == as1 && s2 == as2) || (s1 == as2 && s2 == as1) );
+    }
+  };
+
+  inline ostream & operator<< (ostream & ost, const SpecialPoint & sp)
+  {
+    sp.Print (ost);
+    return ost;
+  }
+
+
+
+
+  ///
+  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;
+
+    double ideps;
+
+  public: 
+
+    ///
+    SpecialPointCalculation (); 
+  
+    ///
+    void SetIdEps(const double epsin) {ideps = epsin;}
+
+    ///
+    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 BoxSphere<3> & box);  
+    ///
+    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);
+
+    void ComputeExtremalPoints (const Plane * plane, 
+				const QuadraticSurface * quadric, 
+				Array<Point<3> > & pts);
+
+    void ComputeExtremalPoints (const Sphere * sphere1, 
+				const Sphere * sphere2, 
+				Array<Point<3> > & pts);
+
+
+    void ComputeCrossPoints (const Plane * plane1, 
+			     const Plane * plane2, 
+			     const Plane * plane3, 
+			     Array<Point<3> > & pts);
+
+    void ComputeCrossPoints (const Plane * plane1, 
+			     const Plane * plane2, 
+			     const QuadraticSurface * quadratic, 
+			     Array<Point<3> > & pts);
+
+    void ComputeCrossPoints (const Sphere * sphere1, 
+			     const Sphere * sphere2, 
+			     const Sphere * sphere3, 
+			     Array<Point<3> > & pts);
+  };
+
+}
+
+#endif
+
+
diff --git a/contrib/Netgen/libsrc/csg/spline3d.cpp b/contrib/Netgen/libsrc/csg/spline3d.cpp
new file mode 100644
index 0000000000..b89e7f7093
--- /dev/null
+++ b/contrib/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(0);
+  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/contrib/Netgen/libsrc/csg/spline3d.hpp b/contrib/Netgen/libsrc/csg/spline3d.hpp
new file mode 100644
index 0000000000..db3a40c56d
--- /dev/null
+++ b/contrib/Netgen/libsrc/csg/spline3d.hpp
@@ -0,0 +1,99 @@
+namespace netgen
+{
+
+  ///
+  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/contrib/Netgen/libsrc/csg/surface.cpp b/contrib/Netgen/libsrc/csg/surface.cpp
new file mode 100644
index 0000000000..fe0415ec72
--- /dev/null
+++ b/contrib/Netgen/libsrc/csg/surface.cpp
@@ -0,0 +1,568 @@
+#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;
+  bcname = "default";
+}
+
+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();
+}
+*/
+Vec<3> Surface :: GetNormalVector (const Point<3> & p) const
+{
+  Vec<3> n;
+  CalcGradient (p, n);
+  n.Normalize();
+  return n;
+}
+
+void Surface :: DefineTangentialPlane (const Point<3> & ap1, 
+				       const Point<3> & ap2)
+{
+  p1 = ap1;
+  p2 = ap2;
+  
+  ez = GetNormalVector (p1);
+  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;
+
+  n = GetNormalVector (p3d);
+  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;
+    }
+}
+
+void Surface :: SkewProject (Point<3> & p, const Vec<3> & direction) const
+{
+  Point<3> startp(p);
+  double t_old(0),t_new(1);
+  Vec<3> grad;
+  for(int i=0; fabs(t_old-t_new) > 1e-20 && i<15; i++)
+    {
+      t_old = t_new;
+      CalcGradient(p,grad);
+      t_new = t_old - CalcFunctionValue(p)/(grad*direction);
+      p = startp + t_new*direction;
+    }
+}
+
+
+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 (const 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();
+
+
+  stringstream ost;
+  ost << "Primitve::CreatePrimitive not implemented for " << classname << endl;
+  throw NgException (ost.str());
+}
+
+
+Primitive * Primitive :: Copy () const
+{
+  stringstream ost;
+  ost << "Primitve::Copy not implemented for " << typeid(*this).name() << endl;
+  throw NgException (ost.str());
+}
+
+
+void Primitive :: Transform (Transformation<3> & trans)
+{
+  stringstream ost;
+  ost << "Primitve::Transform not implemented for " << typeid(*this).name() << endl;
+  throw NgException (ost.str());
+}
+
+void Primitive :: GetTangentialSurfaceIndices (const Point<3> & p, 
+					       Array<int> & surfind, double eps) const
+{
+  for (int j = 0; j < GetNSurfaces(); j++)
+    if (fabs (GetSurface(j).CalcFunctionValue (p)) < eps)
+      if (!surfind.Contains (GetSurfaceId(j)))
+	surfind.Append (GetSurfaceId(j));
+}
+
+
+void Primitive :: 
+GetTangentialVecSurfaceIndices (const Point<3> & p, const Vec<3> & v,
+				Array<int> & surfind, double eps) const
+{
+  cout << "get tangvecsurfind not implemented" << endl;
+  surfind.SetSize (0);
+}
+
+void Primitive :: 
+GetTangentialVecSurfaceIndices2 (const Point<3> & p, const Vec<3> & v1, const Vec<3> & v2,
+				 Array<int> & surfind, double eps) const
+{
+  for (int j = 0; j < GetNSurfaces(); j++)
+    {
+      if (fabs (GetSurface(j).CalcFunctionValue (p)) < eps)
+	{
+	  Vec<3> grad;
+	  GetSurface(j).CalcGradient (p, grad);
+	  if (sqr (grad * v1) < 1e-6 * v1.Length2() * grad.Length2()  && 
+	      sqr (grad * v2) < 1e-6 * v2.Length2() * grad.Length2() )   // new, 18032006 JS
+	    {
+	      if (!surfind.Contains (GetSurfaceId(j)))
+		surfind.Append (GetSurfaceId(j));
+	    }
+	}
+    }
+}
+
+
+
+
+INSOLID_TYPE Primitive :: 
+VecInSolid2 (const Point<3> & p,
+	     const Vec<3> & v1,
+	     const Vec<3> & v2,
+	     double eps) const
+{
+  //(*testout) << "Primitive::VecInSolid2" << endl;
+  Point<3> hp = p + 1e-3 * v1 + 1e-5 * v2;
+
+  INSOLID_TYPE res = PointInSolid (hp, eps);
+  //  (*testout) << "vectorin2, type = " << typeid(*this).name() << ", res = " << res << endl;
+
+  return res;
+}
+
+INSOLID_TYPE Primitive :: 
+VecInSolid3 (const Point<3> & p,
+	     const Vec<3> & v1,
+	     const Vec<3> & v2,
+	     double eps) const
+{
+  //(*testout) << "Primitive::VecInSolid3" << endl;
+  return VecInSolid (p, v1, eps);
+}
+
+INSOLID_TYPE Primitive :: 
+VecInSolid4 (const Point<3> & p,
+	     const Vec<3> & v,
+	     const Vec<3> & v2,
+	     const Vec<3> & m,
+	     double eps) const
+{
+  return VecInSolid2 (p, v, m, 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
+{
+  double hv1 = (GetSurface(0).CalcFunctionValue(p));
+  if (hv1 <= -eps)
+    return IS_INSIDE;
+  if (hv1 >= eps)
+    return IS_OUTSIDE;
+
+
+  Vec<3> hv;
+  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
+{
+  double hv1 = (GetSurface(0).CalcFunctionValue(p));
+  if (hv1 <= -eps)
+    return IS_INSIDE;
+  if (hv1 >= eps)
+    return IS_OUTSIDE;
+
+  Vec<3> hv;
+
+  GetSurface(0).CalcGradient (p, hv);
+
+  hv1 = v1 * hv;
+  if (hv1 <= -eps)
+    return IS_INSIDE;
+  if (hv1 >= eps)
+    return IS_OUTSIDE;
+
+  double hv2 = v2 * hv;
+  if (hv2 <= 0)
+    return IS_INSIDE;
+  else
+    return IS_OUTSIDE;
+}
+  
+
+
+INSOLID_TYPE OneSurfacePrimitive :: 
+VecInSolid3 (const Point<3> & p, const Vec<3> & v, const Vec<3> & v2,
+	     double eps) const
+{
+  //(*testout) << "OneSurfacePrimitive::VecInSolid3" << endl;
+  double hv1 = (GetSurface(0).CalcFunctionValue(p));
+  if (hv1 <= -eps)
+    return IS_INSIDE;
+  if (hv1 >= eps)
+    return IS_OUTSIDE;
+
+  Vec<3> grad;
+  GetSurface(0).CalcGradient (p, grad);
+
+  hv1 = v * grad;
+  if (hv1 <= -eps) return IS_INSIDE;
+  if (hv1 >= eps) return IS_OUTSIDE;
+
+  Mat<3> hesse;
+  GetSurface(0).CalcHesse (p, hesse);
+
+  double hv2 = v2 * grad + v * (hesse * v);
+
+  if (hv2 <= -eps) return IS_INSIDE;
+  if (hv2 >= eps) return IS_OUTSIDE;
+
+  return DOES_INTERSECT;
+}
+
+
+
+
+INSOLID_TYPE OneSurfacePrimitive :: 
+VecInSolid4 (const Point<3> & p, const Vec<3> & v, const Vec<3> & v2,
+	     const Vec<3> & m,
+	     double eps) const
+{
+  double hv1 = (GetSurface(0).CalcFunctionValue(p));
+  if (hv1 <= -eps)
+    return IS_INSIDE;
+  if (hv1 >= eps)
+    return IS_OUTSIDE;
+
+  Vec<3> grad;
+  GetSurface(0).CalcGradient (p, grad);
+
+  hv1 = v * grad;
+  if (hv1 <= -eps) return IS_INSIDE;
+  if (hv1 >= eps) return IS_OUTSIDE;
+
+  Mat<3> hesse;
+  GetSurface(0).CalcHesse (p, hesse);
+
+  double hv2 = v2 * grad + v * (hesse * v);
+
+  if (hv2 <= -eps) return IS_INSIDE;
+  if (hv2 >= eps) return IS_OUTSIDE;
+
+
+  double hv3 = m * grad;
+  if (hv3 <= -eps) return IS_INSIDE;
+  if (hv3 >= eps) return IS_OUTSIDE;
+
+  return DOES_INTERSECT;
+}
+
+
+
+
+
+
+
+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);
+
+      double alpha = fabs(a1*a2)/sqrt(a1.Length2()*a2.Length2());
+      if(fabs(1.-alpha) < 1e-6)
+	{
+	  if(fabs(rs(0)) >= fabs(rs(1)))
+	    f1 -> Project(hp);
+	  else
+	    f2 -> Project(hp);
+	}
+      else
+	{
+
+	  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/contrib/Netgen/libsrc/csg/surface.hpp b/contrib/Netgen/libsrc/csg/surface.hpp
new file mode 100644
index 0000000000..21821241ee
--- /dev/null
+++ b/contrib/Netgen/libsrc/csg/surface.hpp
@@ -0,0 +1,374 @@
+#ifndef FILE_SURFACE
+#define FILE_SURFACE
+
+/**************************************************************************/
+/* File:   surface.hh                                                     */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   1. Dez. 95                                                     */
+/**************************************************************************/
+
+
+namespace netgen 
+{
+
+  class TriangleApproximation;
+
+
+  /**
+     Basis class for implicit surface geometry.
+     This class is used for generation of surface meshes
+     in NETGEN 
+  */
+  class Surface
+  {
+  protected:
+    /// invert normal vector
+    bool inverse;
+    /// maximal h in surface
+    double maxh;
+    /// name of surface
+    char * name;
+    /// boundary condition nr
+    int bcprop;
+    /// boundary condition label
+    string bcname;
+  
+  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 points 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;
+    //@}
+
+
+    /// Project point p onto surface (closest point)
+    virtual void Project (Point<3> & p) const;
+
+    /// Project along direction
+    virtual void SkewProject(Point<3> & p, const Vec<3> & direction) const;
+
+    /// Is current surface identic to surface 2 ?
+    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;
+    virtual Vec<3> GetNormalVector (const Point<3> & p) 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 { };
+
+
+    string GetBCName() const { return bcname; }
+
+    void SetBCName( string abc ) { bcname = abc; }
+  };
+
+
+  inline ostream & operator<< (ostream & ost, const Surface & surf)
+  {
+    surf.Print(ost);
+    return ost;
+  }
+
+
+
+  typedef enum { IS_OUTSIDE = 0, IS_INSIDE = 1, DOES_INTERSECT = 2}
+    INSOLID_TYPE;
+
+
+
+
+  class DummySurface : public Surface
+  {
+    virtual double CalcFunctionValue (const Point<3> & /* point */) const
+    { return 0; }
+
+    virtual void CalcGradient (const Point<3> & /* point */, Vec<3> & grad) const
+    { grad = Vec<3> (0,0,0); }
+  
+    virtual Point<3> GetSurfacePoint () const
+    { return Point<3> (0,0,0); }
+
+    virtual double HesseNorm () const
+    { return 0; }
+
+    virtual void Project (Point<3> & /* p */) const
+    { ; }
+
+    virtual void Print (ostream & ost) const
+    { ost << "dummy surface"; }
+  };
+
+
+
+  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 void GetTangentialSurfaceIndices (const Point<3> & p, 
+					      Array<int> & surfind, double eps) const;
+
+    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;
+
+    // checks if  p + s v1 + s*s/2 v2 is inside
+    virtual INSOLID_TYPE VecInSolid3 (const Point<3> & p,
+				      const Vec<3> & v1,
+				      const Vec<3> & v2,
+				      double eps) const;
+
+    // like VecInSolid2, but second order approximation
+    virtual INSOLID_TYPE VecInSolid4 (const Point<3> & p,
+				      const Vec<3> & v,
+				      const Vec<3> & v2,
+				      const Vec<3> & m,
+				      double eps) const;
+
+    virtual void GetTangentialVecSurfaceIndices (const Point<3> & p, const Vec<3> & v,
+						 Array<int> & surfind, double eps) const;
+
+    virtual void GetTangentialVecSurfaceIndices2 (const Point<3> & p, const Vec<3> & v1, const Vec<3> & v2,
+						  Array<int> & surfind, double eps) const;
+
+
+    virtual void CalcSpecialPoints (Array<Point<3> > & /* pts */) const { ; }
+    virtual void AnalyzeSpecialPoint (const Point<3> & /* pt */, 
+				      Array<Point<3> > & /* specpts */) const { ; }
+    virtual Vec<3> SpecialPointTangentialVector (const Point<3> & /* p */, 
+						 int /* s1 */, int /* s2 */) const 
+    { return Vec<3> (0,0,0); }
+
+  
+    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 (const 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 INSOLID_TYPE VecInSolid3 (const Point<3> & p,
+				      const Vec<3> & v1,
+				      const Vec<3> & v2,
+				      double eps) const;
+
+    virtual INSOLID_TYPE VecInSolid4 (const Point<3> & p,
+				      const Vec<3> & v,
+				      const Vec<3> & v2,
+				      const Vec<3> & m,
+				      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/contrib/Netgen/libsrc/csg/triapprox.cpp b/contrib/Netgen/libsrc/csg/triapprox.cpp
new file mode 100644
index 0000000000..0c4f2b14de
--- /dev/null
+++ b/contrib/Netgen/libsrc/csg/triapprox.cpp
@@ -0,0 +1,59 @@
+#include <mystdlib.h>
+#include <myadt.hpp>
+
+#include <linalg.hpp>
+#include <csg.hpp>
+
+
+namespace netgen
+{
+
+  TriangleApproximation :: TriangleApproximation ()
+  {
+    ;
+  }
+
+  int TriangleApproximation :: 
+  AddTriangle (const TATriangle & tri, bool invert)
+  { 
+    trigs.Append (tri);
+    if (invert)
+      {
+	trigs.Last()[1] = tri[2];
+	trigs.Last()[2] = tri[1];
+      }
+    return trigs.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++;
+  
+    for (i = 0; i < GetNT(); i++)
+      for (j = 0; j < 3; j++)
+	trigs[i][j] = map[trigs[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/contrib/Netgen/libsrc/csg/triapprox.hpp b/contrib/Netgen/libsrc/csg/triapprox.hpp
new file mode 100644
index 0000000000..c17a3e9466
--- /dev/null
+++ b/contrib/Netgen/libsrc/csg/triapprox.hpp
@@ -0,0 +1,63 @@
+#ifndef FILE_TRIAPPROX
+#define FILE_TRIAPPROX
+
+/**************************************************************************/
+/* File:   triapprox.hh                                                   */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   2. Mar. 98                                                    */
+/**************************************************************************/
+
+
+namespace netgen
+{
+
+  /**
+     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 & 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> trigs;
+
+  public:
+    TriangleApproximation();
+    int GetNP () const { return points.Size(); }
+    int GetNT () const { return trigs.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 trigs[i]; }
+    const Vec<3> & GetNormal (int i) const { return normals[i]; }
+
+    void RemoveUnusedPoints ();
+
+    friend class CSGeometry;
+  };
+
+}
+
+#endif
diff --git a/contrib/Netgen/libsrc/csg/vscsg.cpp b/contrib/Netgen/libsrc/csg/vscsg.cpp
new file mode 100644
index 0000000000..a49f3a0db8
--- /dev/null
+++ b/contrib/Netgen/libsrc/csg/vscsg.cpp
@@ -0,0 +1,559 @@
+#include <mystdlib.h>
+#include "incvis.hpp"
+
+#include <myadt.hpp>
+#include <meshing.hpp>
+#include <csg.hpp>
+#include <stlgeom.hpp>
+
+#include <visual.hpp>
+
+#include "vscsg.hpp"
+
+namespace netgen
+{
+
+
+
+  /* *********************** Draw Geometry **************** */
+
+  extern AutoPtr<Mesh> mesh;
+  extern Array<SpecialPoint> specpoints;
+  extern Array<Box<3> > boxes;
+
+
+  extern Array<Point<3> > project1, project2;
+
+
+  // extern AutoPtr<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);
+
+    /*
+      cout << "draw " << project1.Size() << " lines " << endl;
+      glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
+      glLineWidth (1.0f);
+      glEnable (GL_COLOR_MATERIAL);
+
+      glColor3f (1.0f, 0.0f, 0.0f);
+
+      glBegin (GL_LINES);
+      for (int i = 0; i < project1.Size(); i++)
+      {
+      glVertex3dv (project1[i]);
+      glVertex3dv (project2[i]);
+      }
+      glEnd();
+    */
+
+
+    glPopMatrix();
+    glDisable(GL_CLIP_PLANE0);
+ 
+
+
+    /*
+      glFlush();
+  
+      int err;
+      do
+      {
+      err = glGetError();
+      // cout << "glerr,1 = " << err << endl;
+      }
+      while (err != GL_NO_ERROR);
+
+
+      // CreateTexture (0, 1, GL_DECAL);
+      CreateTexture (0, 1, GL_MODULATE);
+      glEnable (GL_TEXTURE_1D);
+
+      float mat_col[] = { 1.0, 1.0, 1.0 }; 
+      glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_col);
+
+      glDisable (GL_BLEND);
+      glDisable (GL_COLOR_MATERIAL);
+      glEnable (GL_NORMALIZE);
+
+      if (geometry->GetNTopLevelObjects())
+      {
+      cout << "call list" << endl;
+      glCallList (trilists[0]);
+      }
+
+      glColor3d (1.0, 1.0, 1.0);
+  
+      glBegin (GL_TRIANGLES);
+      glNormal3f (0, 0, 1);
+      SetOpenGlColor  (-1.0, 0, 1, 0);
+      glVertex3f (0.0, 0.0, 0.0);
+      SetOpenGlColor  (0.5, 0, 1, 0);
+      glNormal3f (0, 0, 1);
+      glVertex3f (1.0, 0.0, 0.0);
+      SetOpenGlColor  (2.0, 0, 1, 0);
+      glNormal3f (0, 0, 1);
+      glVertex3f (0.0, 1.0, 0.0);
+
+      glEnd ();
+
+      cout << "trig drawn" << endl;
+
+      glDisable (GL_TEXTURE_1D);
+      glDisable (GL_COLOR_MATERIAL);
+      glFlush();
+
+      cout << "glerr,2 = " << glGetError() << endl;
+    */
+
+
+
+    DrawCoordinateCross ();
+    DrawNetgenLogo ();  
+
+    glFinish();  
+  }
+
+
+  void VisualSceneGeometry :: BuildScene (int zoomall)
+  {
+    Box<3> box;
+    int hasp = 0;
+    for (int i = 0; i < geometry->GetNTopLevelObjects(); i++)
+      {
+	const TriangleApproximation & ta =
+	  *geometry->GetTriApprox(i);
+	if (!&ta) continue;
+
+	for (int 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 (int i = 0; i < trilists.Size(); i++)
+      glDeleteLists (trilists[i], 1);
+    trilists.SetSize(0);
+
+    for (int 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 (int j = 0; j < ta.GetNT(); j++)
+	      {
+		for (int k = 0; k < 3; k++)
+		  {
+		    int pi = ta.GetTriangle(j)[k];
+		    glNormal3dv (ta.GetNormal (pi));
+		    glVertex3dv (ta.GetPoint(pi));
+		  }
+	      }
+	    glEnd ();
+	  }
+	glEndList ();
+      }
+
+  }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+  VisualSceneSpecPoints :: VisualSceneSpecPoints ()
+    : VisualScene()
+  {
+    ;
+  }
+
+  VisualSceneSpecPoints :: ~VisualSceneSpecPoints ()
+  {
+    ;
+  }
+
+
+  void VisualSceneSpecPoints :: DrawScene ()
+  {
+    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 (int 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 (int i = 1; i <= mesh->GetNSeg(); i++)
+	  {
+	    const Segment & seg = mesh -> LineSegment (i);
+	    glVertex3dv ( (*mesh)[seg[0]] );
+            glVertex3dv ( (*mesh)[seg[1]] );
+	    // glVertex3dv ( &(*mesh)[seg[0]].X() );
+	    // glVertex3dv ( &(*mesh)[seg[1]].X() );
+	  }
+	glEnd();
+      }
+
+    glColor3d (1, 0, 0);
+    glBegin (GL_LINES);
+    int edges[12][2] = 
+      { { 0, 1 },
+	{ 2, 3 },
+	{ 4, 5 },
+	{ 6, 7 },
+	{ 0, 2 },
+	{ 1, 3 },
+	{ 4, 6 },
+	{ 5, 7 },
+	{ 0, 4 },
+	{ 1, 5 },
+	{ 2, 6 },
+	{ 3, 7 } };
+    for (int i = 0; i < boxes.Size(); i++)
+      {
+	for (int j = 0; j < 12; j++)
+	  {
+	    glVertex3dv ( boxes[i].GetPointNr(edges[j][0]) );
+	    glVertex3dv ( boxes[i].GetPointNr(edges[j][1]) );
+	  }
+	/*
+	glVertex3dv ( boxes[i].PMin() );
+	glVertex3dv ( boxes[i].PMax() );
+	*/
+      }
+    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 (int i = 1; i <= mesh->GetNSeg(); i++)
+	  {
+	    const Segment & seg = mesh -> LineSegment (i);
+	    const Point3d p1 = mesh -> Point (seg[0]);
+	    const Point3d p2 = mesh -> Point (seg[1]);
+
+	    const Point3d p = Center (p1, p2);
+	    glRasterPos3d (p.X(), p.Y(), p.Z());
+	  
+	    sprintf (buf, "%d", seg.edgenr);
+	    // glCallLists (GLsizei(strlen (buf)), GL_UNSIGNED_BYTE, buf);
+	    MyOpenGLText (buf);
+	  }
+      
+	glPopAttrib ();
+	glDisable (GL_COLOR_MATERIAL);
+      }
+
+
+    if (vispar.drawedpoints)
+      {
+
+	glColor3d (0, 0, 1);
+	/*
+	  glPointSize( 3.0 );
+
+	float range[2];
+	glGetFloatv(GL_POINT_SIZE_RANGE, &range[0]);
+	cout << "max ptsize = " << range[0] << "-" << range[1] << endl;
+      
+
+	glBegin( GL_POINTS );
+	for (int i = 1; i <= mesh -> GetNP(); i++)
+	  {
+	    const Point3d & p = mesh -> Point(i);
+	    if (i % 2)
+	      glVertex3f( p.X(), p.Y(), p.Z());
+	  }
+	glEnd();
+	*/
+
+	static GLubyte knoedel[] = 
+	  {
+	    0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe,
+	  };
+	glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+
+	glDisable (GL_COLOR_MATERIAL);
+	glDisable (GL_LIGHTING);
+	glDisable (GL_CLIP_PLANE0);
+      
+	for (int i = 1; i <= mesh -> GetNP(); i++)
+	  {
+	    const Point3d & p = mesh -> Point(i);
+	    glRasterPos3d (p.X(), p.Y(), p.Z());
+	    glBitmap (7, 7, 3, 3, 0, 0, &knoedel[0]);
+	  }
+      }
+
+    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 (int i = 1; i <= mesh->GetNP(); i++)
+	  {
+	    const Point3d & p = mesh->Point(i);
+	    glRasterPos3d (p.X(), p.Y(), p.Z());
+	  
+	    sprintf (buf, "%d", i);
+	    // glCallLists (GLsizei(strlen (buf)), GL_UNSIGNED_BYTE, buf);
+	    MyOpenGLText (buf);
+	  }
+      
+	glPopAttrib ();
+	glDisable (GL_COLOR_MATERIAL);
+      }
+
+
+    
+    
+    
+
+    glPopMatrix();
+
+    if (vispar.drawcoordinatecross)
+      DrawCoordinateCross ();
+    DrawNetgenLogo ();
+
+    glFinish();  
+  }
+
+
+  void VisualSceneSpecPoints :: BuildScene (int zoomall)
+  {
+    if (!mesh) 
+      {
+	VisualScene::BuildScene(zoomall);
+	return;
+      }
+  
+    Box3d box;
+  
+    if (mesh->GetNSeg())
+      {
+	box.SetPoint (mesh->Point (mesh->LineSegment(1)[0]));
+	for (int i = 1; i <= mesh->GetNSeg(); i++)
+	  {
+	    box.AddPoint (mesh->Point (mesh->LineSegment(i)[0]));
+	    box.AddPoint (mesh->Point (mesh->LineSegment(i)[1]));
+	  }
+      }
+    else if (specpoints.Size() >= 2)
+      {
+	box.SetPoint (specpoints.Get(1).p);
+	for (int 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()) ||
+			 vispar.use_center_coords))
+      {
+	if (vispar.use_center_coords)
+	  {
+	    center.X() = vispar.centerx; center.Y() = vispar.centery; center.Z() = vispar.centerz; 
+	  }
+	else
+	  center = mesh->Point (vispar.centerpoint);
+      }
+    else
+      center = Center (box.PMin(), box.PMax());
+        
+
+    rad = 0.5 * Dist (box.PMin(), box.PMax());
+  
+  
+    CalcTransformationMatrices();
+  }
+
+
+
+
+
+
+}
+
+
diff --git a/contrib/Netgen/libsrc/csg/vscsg.hpp b/contrib/Netgen/libsrc/csg/vscsg.hpp
new file mode 100644
index 0000000000..c32f5da83a
--- /dev/null
+++ b/contrib/Netgen/libsrc/csg/vscsg.hpp
@@ -0,0 +1,34 @@
+#ifndef FILE_VSCSG
+#define FILE_VSCSG
+
+/**************************************************************************/
+/* File:   vscsg.hpp                                                      */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   05. Jan. 2011                                                  */
+/**************************************************************************/
+
+namespace netgen
+{
+
+  class VisualSceneGeometry : public VisualScene
+  {
+    class CSGeometry * geometry;
+    Array<int> trilists;
+    int selsurf;
+  public:
+    VisualSceneGeometry ();
+    virtual ~VisualSceneGeometry ();
+
+    void SetGeometry (class CSGeometry * ageometry) { geometry = ageometry; }
+    virtual void SelectSurface (int aselsurf);
+    virtual void BuildScene (int zoomall = 0);
+    virtual void DrawScene ();
+  };
+
+
+
+}
+
+
+
+#endif
diff --git a/contrib/Netgen/libsrc/general/Makefile.am b/contrib/Netgen/libsrc/general/Makefile.am
new file mode 100644
index 0000000000..9c555b0238
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/Makefile.am
@@ -0,0 +1,14 @@
+noinst_HEADERS = array.hpp myadt.hpp optmem.hpp sort.hpp table.hpp autodiff.hpp flags.hpp mystring.hpp spbita2d.hpp template.hpp autoptr.hpp hashtabl.hpp netgenout.hpp profiler.hpp stack.hpp bitarray.hpp seti.hpp symbolta.hpp dynamicmem.hpp  parthreads.hpp mpi_interface.hpp
+
+#  moveablemem.hpp
+
+include_HEADERS = ngexception.hpp
+
+AM_CPPFLAGS =  $(MPI_INCLUDES) -I$(top_srcdir)/libsrc/include
+METASOURCES = AUTO
+noinst_LTLIBRARIES = libgen.la
+libgen_la_SOURCES = array.cpp bitarray.cpp dynamicmem.cpp flags.cpp \
+	hashtabl.cpp mystring.cpp ngexception.cpp optmem.cpp parthreads.cpp \
+	profiler.cpp seti.cpp sort.cpp spbita2d.cpp symbolta.cpp table.cpp
+
+#  moveablemem.cpp
diff --git a/contrib/Netgen/libsrc/general/array.cpp b/contrib/Netgen/libsrc/general/array.cpp
new file mode 100644
index 0000000000..d3f48d36cc
--- /dev/null
+++ b/contrib/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/contrib/Netgen/libsrc/general/array.hpp b/contrib/Netgen/libsrc/general/array.hpp
new file mode 100644
index 0000000000..40b6048d38
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/array.hpp
@@ -0,0 +1,661 @@
+#ifndef FILE_Array
+#define FILE_Array
+
+/**************************************************************************/
+/* File:   array.hpp                                                      */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   01. Jun. 95                                                    */
+/**************************************************************************/
+
+
+namespace netgen
+{
+
+  // template <class T, int B1, int B2> class IndirectArray;
+
+
+
+  /**
+     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; }
+
+    int Begin() const { return BASE; }
+    int End() const { return size+BASE; }
+
+    /// Access array. BASE-based
+    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]; 
+    }
+
+    /// Access array, one-based  (old fashioned)
+    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]; 
+    }
+  
+    /// Access array, one-based  (old fashioned)
+    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]; 
+    }
+
+    /// Access array, one-based  (old fashioned)
+    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 first element
+    T & First () const
+    {
+      return data[0];
+    }
+
+
+    /// access last element. check by macro CHECK_RANGE
+    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;
+    }
+
+    /// takes range starting from position start of end-start elements
+    const FlatArray<T> Range (int start, int end)
+    {
+      return FlatArray<T> (end-start, data+start);
+    }
+
+    /// first position of element elem, returns -1 if element not contained in array 
+    int Pos(const T & elem) const
+    {
+      int pos = -1;
+      for(int i=0; pos==-1 && i < this->size; i++)
+	if(elem == data[i]) pos = i;
+      return pos;
+    }
+
+    /// does the array contain element elem ?
+    bool Contains(const T & elem) const
+    {
+      return ( Pos(elem) >= 0 );
+    }
+  };
+
+
+
+  // print array
+  template <class T, int BASE>
+  inline ostream & operator<< (ostream & s, const FlatArray<T,BASE> & a)
+  {
+    for (int i = a.Begin(); i < a.End(); 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:
+    using FlatArray<T,BASE>::size;
+    using FlatArray<T,BASE>::data;
+
+    /// 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 = size;
+      ownmem = 1;
+      for (int i = BASE; i < size+BASE; i++)
+	(*this)[i] = a2[i];
+    }
+
+
+
+    /// if responsible, deletes memory
+    ~Array()
+    {
+      if (ownmem)
+	delete [] data;
+    }
+
+    /// Change logical size. If necessary, do reallocation. Keeps contents.
+    void SetSize(int nsize)
+    {
+      if (nsize > allocsize) 
+	ReSize (nsize);
+      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 (size == allocsize) 
+	ReSize (size+1);
+      data[size] = el;
+      size++;
+      return size;
+    }
+
+    template <typename T2, int B2>
+    void Append (FlatArray<T2, B2> a2)
+    {
+      if (size+a2.Size() > allocsize)
+	ReSize (size+a2.Size());
+      for (int i = 0; i < a2.Size(); i++)
+	data[size+i] = a2[i+B2];
+      size += a2.Size();
+    }
+
+
+    /// Delete element i (0-based). Move last element to position i.
+    void Delete (int i)
+    {
+#ifdef CHECK_Array_RANGE
+      RangeCheck (i+1);
+#endif
+
+      data[i] = data[size-1];
+      size--;
+      //    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
+
+      data[i-1] = data[size-1];
+      size--;
+    }
+
+    /// Delete last element. 
+    void DeleteLast ()
+    {
+      size--;
+    }
+
+    /// Deallocate memory
+    void DeleteAll ()
+    {
+      if (ownmem)
+	delete [] data;
+      data = 0;
+      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 < size+BASE; i++)
+	(*this)[i] = a2[i];
+      return *this;
+    }
+
+    /// array copy
+    Array & operator= (const FlatArray<T> & a2)
+    {
+      SetSize (a2.Size());
+      for (int i = BASE; i < 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 (data)
+	{
+	  T * p = new T[nsize];
+	
+	  int mins = (nsize < size) ? nsize : size; 
+	  memcpy (p, data, mins * sizeof(T));
+
+	  if (ownmem)
+	    delete [] data;
+	  ownmem = 1;
+	  data = p;
+	}
+      else
+	{
+	  data = new T[nsize];
+	  ownmem = 1;
+	}
+    
+      allocsize = nsize;
+    }
+  };
+
+
+
+  template <class T, int S> 
+  class ArrayMem : public Array<T>
+  {
+    using Array<T>::size;
+    using Array<T>::data;
+    using Array<T>::ownmem;
+
+    // T mem[S];     // Intel C++ calls dummy constructor
+    // char mem[S*sizeof(T)];
+    double mem[(S*sizeof(T)+7) / 8];
+  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])))
+    {
+      size = asize;
+      if (asize > S)
+	{
+	  data = new T[asize];
+	  ownmem = 1;
+	}
+      // SetSize (asize);
+    }
+
+    ArrayMem & operator= (const T & val)  
+    {
+      Array<T>::operator= (val);
+      return *this;
+    }
+
+    /// array copy
+    ArrayMem & operator= (const FlatArray<T> & a2)
+    {
+      SetSize (a2.Size());
+      for (int i = 0; i < size; i++)
+	(*this)[i] = a2[i];
+      return *this;
+    }
+
+  };
+
+
+
+
+
+  /*
+    template <class T, int B1, int B2>
+    class IndirectArray
+    {
+    const FlatArray<T, B1> & array;
+    const FlatArray<int, B2> & ia; 
+
+    public:
+    IndirectArray (const FlatArray<T,B1> & aa, const FlatArray<int, B2> & aia)
+    : array(aa), ia(aia) { ; }
+    int Size() const { return ia.Size(); }
+    const T & operator[] (int i) const { return array[ia[i]]; }
+    };
+  */
+
+
+
+
+
+
+
+
+
+  ///
+  template <class T, int BASE = 0> 
+  class MoveableArray 
+  {
+    int size;
+    int allocsize;
+    DynamicMem<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-BASE]; }
+
+    ///
+    const T & operator[] (int i) const
+    { return ((const T*)data)[i-BASE]; }
+
+    ///
+    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;
+    }
+
+
+    MoveableArray & Copy (const MoveableArray & a2)
+    {
+      SetSize (a2.Size());
+      for (int i = 0; i < this->size; i++)
+	data[i] = a2.data[i];
+      return *this;
+    }
+
+    /// array copy
+    MoveableArray & operator= (const MoveableArray & a2)
+    {
+      return Copy(a2);
+    }
+
+
+    void SetName (const 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;
+  }
+
+
+
+  /// bubble sort array
+  template <class T>
+  inline void BubbleSort (const FlatArray<T> & data)
+  {
+    for (int i = 0; i < data.Size(); i++)
+      for (int j = i+1; j < data.Size(); j++)
+	if (data[i] > data[j])
+	  {
+	    T hv = data[i];
+	    data[i] = data[j];
+	    data[j] = hv;
+	  }
+  }
+
+  /// bubble sort array
+  template <class T, class S>
+  inline void BubbleSort (FlatArray<T> & data, FlatArray<S> & slave)
+  {
+    for (int i = 0; i < data.Size(); i++)
+      for (int j = i+1; j < data.Size(); j++)
+	if (data[i] > data[j])
+	  {
+	    T hv = data[i];
+	    data[i] = data[j];
+	    data[j] = hv;
+	    
+	    S hvs = slave[i];
+	    slave[i] = slave[j];
+	    slave[j] = hvs;
+	  }
+  }
+
+
+  template <class T, class S>
+  void QuickSortRec (FlatArray<T> & data,
+		     FlatArray<S> & slave,
+		     int left, int right)
+  {
+    int i = left;
+    int j = right;
+    T midval = data[(left+right)/2];
+  
+    do
+      {
+	while (data[i] < midval) i++;
+	while (midval < data[j]) j--;
+      
+	if (i <= j)
+	  {
+	    Swap (data[i], data[j]);
+	    Swap (slave[i], slave[j]);
+	    i++; j--;
+	  }
+      }
+    while (i <= j);
+    if (left < j) QuickSortRec (data, slave, left, j);
+    if (i < right) QuickSortRec (data, slave, i, right);
+  }
+
+  template <class T, class S>
+  void QuickSort (FlatArray<T> & data, FlatArray<S> & slave)
+  {
+    QuickSortRec (data, slave, 0, data.Size()-1);
+  }
+
+
+
+
+
+
+
+
+
+  template <class T> 
+  void Intersection (const FlatArray<T> & in1, const FlatArray<T> & in2, 
+		     Array<T> & out)
+  {
+    out.SetSize(0);
+    for(int i=0; i<in1.Size(); i++)
+      if(in2.Contains(in1[i]))
+	out.Append(in1[i]);
+  }
+  template <class T> 
+  void Intersection (const FlatArray<T> & in1, const FlatArray<T> & in2, const FlatArray<T> & in3,
+		     Array<T> & out)
+  {
+    out.SetSize(0);
+    for(int i=0; i<in1.Size(); i++)
+      if(in2.Contains(in1[i]) && in3.Contains(in1[i]))
+	out.Append(in1[i]);
+  }
+
+
+}
+
+#endif
+
diff --git a/contrib/Netgen/libsrc/general/autodiff.hpp b/contrib/Netgen/libsrc/general/autodiff.hpp
new file mode 100644
index 0000000000..e2ba63d0e7
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/autodiff.hpp
@@ -0,0 +1,351 @@
+#ifndef FILE_AUTODIFF
+#define FILE_AUTODIFF
+
+/**************************************************************************/
+/* File:   autodiff.hpp                                                   */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   24. Oct. 02                                                    */
+/**************************************************************************/
+
+// Automatic differentiation datatype
+
+
+/**
+   Datatype for automatic differentiation.
+   Contains function value and D derivatives. Algebraic
+   operations are overloaded by using product-rule etc. etc. 
+**/
+template <int D, typename SCAL = double>
+class AutoDiff
+{
+  SCAL val;
+  SCAL dval[D];
+public:
+
+  typedef AutoDiff<D,SCAL> TELEM;
+  typedef SCAL TSCAL;
+
+
+  /// elements are undefined
+  AutoDiff  () throw() { }; 
+  // { val = 0; for (int i = 0; i < D; i++) dval[i] = 0; }  // !
+
+  /// copy constructor
+  AutoDiff  (const AutoDiff & ad2) throw()
+  {
+    val = ad2.val;
+    for (int i = 0; i < D; i++)
+      dval[i] = ad2.dval[i];
+  }
+
+  /// initial object with constant value
+  AutoDiff  (SCAL aval) throw()
+  {
+    val = aval;
+    for (int i = 0; i < D; i++)
+      dval[i] = 0;
+  }
+
+  /// init object with (val, e_diffindex)
+  AutoDiff  (SCAL aval, int diffindex)  throw()
+  {
+    val = aval;
+    for (int i = 0; i < D; i++)
+      dval[i] = 0;
+    dval[diffindex] = 1;
+  }
+
+  /// assign constant value
+  AutoDiff & operator= (SCAL aval) throw()
+  {
+    val = aval;
+    for (int i = 0; i < D; i++)
+      dval[i] = 0;
+    return *this;
+  }
+
+  /// returns value
+  SCAL Value() const throw() { return val; }
+
+  /// returns partial derivative
+  SCAL DValue (int i) const throw() { return dval[i]; }
+
+  /// access value
+  SCAL & Value() throw() { return val; }
+
+  /// accesses partial derivative 
+  SCAL & DValue (int i) throw() { return dval[i]; }
+
+  /// 
+  AutoDiff<D,SCAL> & operator+= (const AutoDiff<D,SCAL> & y) throw()
+  {
+    val += y.val;
+    for (int i = 0; i < D; i++)
+      dval[i] += y.dval[i];
+    return *this;
+  }
+
+  ///
+  AutoDiff<D,SCAL> & operator-= (const AutoDiff<D,SCAL> & y) throw()
+  {
+    val -= y.val;
+    for (int i = 0; i < D; i++)
+      dval[i] -= y.dval[i];
+    return *this;
+
+  }
+
+  ///
+  AutoDiff<D,SCAL> & operator*= (const AutoDiff<D,SCAL> & y) throw()
+  {
+    for (int i = 0; i < D; i++)
+      {
+	// dval[i] *= y.val;
+	// dval[i] += val * y.dval[i];
+        dval[i] = dval[i] * y.val + val * y.dval[i];
+      }
+    val *= y.val;
+    return *this;
+  }
+
+  ///
+  AutoDiff<D,SCAL> & operator*= (const SCAL & y) throw()
+  {
+    val *= y;
+    for (int i = 0; i < D; i++)
+      dval[i] *= y;
+    return *this;
+  }
+
+  ///
+  AutoDiff<D,SCAL> & operator/= (const SCAL & y) throw()
+  {
+    SCAL iy = 1.0 / y;
+    val *= iy;
+    for (int i = 0; i < D; i++)
+      dval[i] *= iy;
+    return *this;
+  }
+
+  /// 
+  bool operator== (SCAL val2) throw()
+  {
+    return val == val2;
+  }
+
+  ///
+  bool operator!= (SCAL val2) throw()
+  {
+    return val != val2;
+  }
+
+  ///
+  bool operator< (SCAL val2) throw()
+  {
+    return val < val2;
+  }
+  
+  ///
+  bool operator> (SCAL val2) throw()
+  {
+    return val > val2;
+  }
+};
+
+
+//@{  AutoDiff helper functions.
+
+/// prints AutoDiff
+template<int D, typename SCAL>
+inline ostream & operator<< (ostream & ost, const AutoDiff<D,SCAL> & x)
+{
+  ost << x.Value() << ", D = ";
+  for (int i = 0; i < D; i++)
+    ost << x.DValue(i) << " ";
+  return ost;
+}
+
+/// AutoDiff plus AutoDiff
+template<int D, typename SCAL>
+inline AutoDiff<D,SCAL> operator+ (const AutoDiff<D,SCAL> & x, const AutoDiff<D,SCAL> & y) throw()
+{
+  AutoDiff<D,SCAL> res;
+  res.Value () = x.Value()+y.Value();
+  // AutoDiff<D,SCAL> res(x.Value()+y.Value());
+  for (int i = 0; i < D; i++)
+    res.DValue(i) = x.DValue(i) + y.DValue(i);
+  return res;
+}
+
+
+/// AutoDiff minus AutoDiff
+template<int D, typename SCAL>
+inline AutoDiff<D,SCAL> operator- (const AutoDiff<D,SCAL> & x, const AutoDiff<D,SCAL> & y) throw()
+{
+  AutoDiff<D,SCAL> res;
+  res.Value() = x.Value()-y.Value();
+  // AutoDiff<D,SCAL> res (x.Value()-y.Value());
+  for (int i = 0; i < D; i++)
+    res.DValue(i) = x.DValue(i) - y.DValue(i);
+  return res;
+}
+
+/// double plus AutoDiff
+template<int D, typename SCAL>
+inline AutoDiff<D,SCAL> operator+ (double x, const AutoDiff<D,SCAL> & y) throw()
+{
+  AutoDiff<D,SCAL> res;
+  res.Value() = x+y.Value();
+  for (int i = 0; i < D; i++)
+    res.DValue(i) = y.DValue(i);
+  return res;
+}
+
+/// AutoDiff plus double
+template<int D, typename SCAL>
+inline AutoDiff<D,SCAL> operator+ (const AutoDiff<D,SCAL> & y, double x) throw()
+{
+  AutoDiff<D,SCAL> res;
+  res.Value() = x+y.Value();
+  for (int i = 0; i < D; i++)
+    res.DValue(i) = y.DValue(i);
+  return res;
+}
+
+
+/// minus AutoDiff
+template<int D, typename SCAL>
+inline AutoDiff<D,SCAL> operator- (const AutoDiff<D,SCAL> & x) throw()
+{
+  AutoDiff<D,SCAL> res;
+  res.Value() = -x.Value();
+  for (int i = 0; i < D; i++)
+    res.DValue(i) = -x.DValue(i);
+  return res;
+}
+
+/// AutoDiff minus double
+template<int D, typename SCAL>
+inline AutoDiff<D,SCAL> operator- (const AutoDiff<D,SCAL> & x, double y) throw()
+{
+  AutoDiff<D,SCAL> res;
+  res.Value() = x.Value()-y;
+  for (int i = 0; i < D; i++)
+    res.DValue(i) = x.DValue(i);
+  return res;
+}
+
+///
+template<int D, typename SCAL>
+inline AutoDiff<D,SCAL> operator- (double x, const AutoDiff<D,SCAL> & y) throw()
+{
+  AutoDiff<D,SCAL> res;
+  res.Value() = x-y.Value();
+  for (int i = 0; i < D; i++)
+    res.DValue(i) = -y.DValue(i);
+  return res;
+}
+
+
+/// double times AutoDiff
+template<int D, typename SCAL>
+inline AutoDiff<D,SCAL> operator* (double x, const AutoDiff<D,SCAL> & y) throw()
+{
+  AutoDiff<D,SCAL> res;
+  res.Value() = x*y.Value();
+  for (int i = 0; i < D; i++)
+    res.DValue(i) = x*y.DValue(i);
+  return res;
+}
+
+/// AutoDiff times double
+template<int D, typename SCAL>
+inline AutoDiff<D,SCAL> operator* (const AutoDiff<D,SCAL> & y, double x) throw()
+{
+  AutoDiff<D,SCAL> res;
+  res.Value() = x*y.Value();
+  for (int i = 0; i < D; i++)
+    res.DValue(i) = x*y.DValue(i);
+  return res;
+}
+
+/// AutoDiff times AutoDiff
+template<int D, typename SCAL>
+inline AutoDiff<D,SCAL> operator* (const AutoDiff<D,SCAL> & x, const AutoDiff<D,SCAL> & y) throw()
+{
+  AutoDiff<D,SCAL> res;
+  SCAL hx = x.Value();
+  SCAL hy = y.Value();
+
+  res.Value() = hx*hy;
+  for (int i = 0; i < D; i++)
+    res.DValue(i) = hx*y.DValue(i) + hy*x.DValue(i);
+
+  return res;
+}
+
+/// AutoDiff times AutoDiff
+template<int D, typename SCAL>
+inline AutoDiff<D,SCAL> sqr (const AutoDiff<D,SCAL> & x) throw()
+{
+  AutoDiff<D,SCAL> res;
+  SCAL hx = x.Value();
+  res.Value() = hx*hx;
+  hx *= 2;
+  for (int i = 0; i < D; i++)
+    res.DValue(i) = hx*x.DValue(i);
+  return res;
+}
+
+/// Inverse of AutoDiff
+template<int D, typename SCAL>
+inline AutoDiff<D,SCAL> Inv (const AutoDiff<D,SCAL> & x)
+{
+  AutoDiff<D,SCAL> res(1.0 / x.Value());
+  for (int i = 0; i < D; i++)
+    res.DValue(i) = -x.DValue(i) / (x.Value() * x.Value());
+  return res;
+}
+
+
+/// AutoDiff div AutoDiff
+template<int D, typename SCAL>
+inline AutoDiff<D,SCAL> operator/ (const AutoDiff<D,SCAL> & x, const AutoDiff<D,SCAL> & y)
+{
+  return x * Inv (y);
+}
+
+/// AutoDiff div double
+template<int D, typename SCAL>
+inline AutoDiff<D,SCAL> operator/ (const AutoDiff<D,SCAL> & x, double y)
+{
+  return (1/y) * x;
+}
+
+/// double div AutoDiff
+template<int D, typename SCAL>
+inline AutoDiff<D,SCAL> operator/ (double x, const AutoDiff<D,SCAL> & y)
+{
+  return x * Inv(y);
+}
+
+
+
+
+template<int D, typename SCAL>
+inline AutoDiff<D,SCAL> fabs (const AutoDiff<D,SCAL> & x)
+{
+  double abs = fabs (x.Value());
+  AutoDiff<D,SCAL> res( abs );
+  if (abs != 0.0)
+    for (int i = 0; i < D; i++)
+      res.DValue(i) = x.DValue(i) / abs;
+  else
+    for (int i = 0; i < D; i++)
+      res.DValue(i) = 0.0;
+  return res;
+}
+
+//@}
+
+#endif
diff --git a/contrib/Netgen/libsrc/general/autoptr.hpp b/contrib/Netgen/libsrc/general/autoptr.hpp
new file mode 100644
index 0000000000..352a6105f8
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/autoptr.hpp
@@ -0,0 +1,36 @@
+#ifndef FILE_AUTOPTR
+#define FILE_AUTOPTR
+
+/**************************************************************************/
+/* File:   autoptr.hpp                                                    */
+/* Author: STL, Joachim Schoeberl                                         */
+/* Date:   29. Dec. 02                                                    */
+/**************************************************************************/
+
+namespace netgen
+{
+
+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/contrib/Netgen/libsrc/general/bitarray.cpp b/contrib/Netgen/libsrc/general/bitarray.cpp
new file mode 100644
index 0000000000..1c36e5fc04
--- /dev/null
+++ b/contrib/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/contrib/Netgen/libsrc/general/bitarray.hpp b/contrib/Netgen/libsrc/general/bitarray.hpp
new file mode 100644
index 0000000000..64a4ee6e60
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/bitarray.hpp
@@ -0,0 +1,227 @@
+#ifndef FILE_BitArray
+#define FILE_BitArray
+
+/**************************************************************************/
+/* File:   bitarray.hpp                                                   */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   01. Jun. 95                                                    */
+/**************************************************************************/
+
+#include <limits.h>
+
+namespace netgen
+{
+
+
+/**
+   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);
+  ///
+  INDEX Size () const
+  {
+    return size;
+  }
+
+  ///
+  void Set ();
+  ///
+  void Set (INDEX i)
+  {
+    data[Addr(i)] |= Mask(i);
+  }
+  
+  void Clear ();
+
+
+  void Clear (INDEX i)
+  {
+    data[Addr(i)] &= ~Mask(i);
+  }
+
+  bool Test (INDEX i) const
+  {
+    return (data[i / CHAR_BIT] & (char(1) << (i % CHAR_BIT) ) ) ? true : false;
+  }
+
+  ///
+  void Invert ();
+  ///
+  void And (const BitArray & ba2);
+  ///
+  void Or (const BitArray & ba2);
+private:
+  ///
+  inline unsigned char Mask (INDEX i) const
+  {
+    return char(1) << (i % CHAR_BIT);
+  }
+  ///
+  inline INDEX Addr (INDEX i) const
+  {
+  return (i / CHAR_BIT);
+  }
+
+  ///
+  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 << int (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 = BASE; i < a.Size()+BASE; i++)
+    {
+      s << a.Test(i);
+      if ( (i-BASE) % 40 == 39) s << "\n";
+    }
+  if (a.Size() % 40 != 0) s << "\n";
+  return s;
+}
+
+}
+
+#endif
diff --git a/contrib/Netgen/libsrc/general/dynamicmem.cpp b/contrib/Netgen/libsrc/general/dynamicmem.cpp
new file mode 100644
index 0000000000..56fb1182ad
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/dynamicmem.cpp
@@ -0,0 +1,201 @@
+#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];
+
+    if (!ptr)
+      {
+	cerr << "BaseynamicMem, cannot allocate " << s << " bytes" << endl;
+	Print ();
+	throw ("BaseDynamicMem::Alloc: out of memory");
+      }
+    // ptr = (char*)malloc (s);
+    // ptr = (char*) _mm_malloc (s,16);
+  }
+
+  void BaseDynamicMem :: ReAlloc (size_t s)
+  {
+    if (size == s) return;
+
+    char * old = ptr;
+    ptr = new char[s];
+
+    if (!ptr)
+      {
+	cerr << "BaseynamicMem, cannot Reallocate " << s << " bytes" << endl;
+	Print ();
+	throw ("BaseDynamicMem::Alloc: out of memory");
+      }
+
+
+    // ptr = (char*)malloc(s);
+    // ptr = (char*) _mm_malloc (s,16);
+    memmove (ptr, old, (s < size) ? s : size);
+    delete [] old;
+    // free (old);
+    // _mm_free (old);
+    size = s;
+  }
+
+  void BaseDynamicMem :: Free ()
+  {
+    delete [] ptr;
+    // free (ptr);
+    // _mm_free (ptr);
+    ptr = 0;
+  }
+
+  void BaseDynamicMem :: Swap (BaseDynamicMem & m2)
+  {
+    size_t 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;
+    size_t mem = 0;
+    int cnt = 0;
+    while (p)
+      {
+	mem += p->size;
+	cnt++;
+
+	cout << setw(10) << p->size << " Bytes";
+	cout << ", addr = " << (void*)p->ptr;
+	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;
+  }
+
+
+#ifdef __INTEL_COMPILER
+#pragma warning(push)
+#pragma warning(disable:1684)
+#endif
+
+  void BaseDynamicMem :: GetUsed (int nr, char * ch)
+  {
+    BaseDynamicMem * p = first;
+
+    for (int i = 0; i < nr; i++)
+      ch[i] = '0';
+
+    while (p)
+      {
+        long unsigned hptr = (long unsigned) (p->ptr);
+	// uintptr_t hptr = reinterpret_cast<uintptr_t>(p->ptr); //??
+
+	hptr /= (1024*1024);
+	hptr /= (4096/nr);
+
+	size_t blocks = p->size / (1024*1024);
+	blocks /= (4096/nr);
+	
+	// cout << "ptr = " << (void*)(p->ptr) << ", size = " << p->size << ", hptr = " << hptr << " blocks = " << blocks << endl;
+
+	for (size_t i = 0; i <= blocks; i++)
+	  ch[hptr+i] = '1';
+
+	p = p->next;
+      }
+    
+    {
+
+      /*
+    BaseMoveableMem * pm = BaseMoveableMem::first;
+    while (pm)
+      {
+        long unsigned hptr = (long unsigned) pm->ptr;
+        // uintptr_t hptr = reinterpret_cast<uintptr_t>(pm->ptr);
+
+	hptr /= (1024*1024);
+	hptr /= (4096/nr);
+
+	size_t blocks = pm->size / (1024*1024);
+	blocks /= (4096/nr);
+	
+	// cout << "moveable, ptr = " << (void*)(pm->ptr) << ", size = " << pm->size << ", hptr = " << hptr << " blocks = " << blocks << endl;
+
+	for (size_t i = 0; i <= blocks; i++)
+	  ch[hptr+i] = '1';
+
+	pm = pm->next;
+      }
+      */
+    }
+
+
+
+  }
+
+#ifdef __INTEL_COMPILER
+#pragma warning(pop)
+#endif
+
+}
diff --git a/contrib/Netgen/libsrc/general/dynamicmem.hpp b/contrib/Netgen/libsrc/general/dynamicmem.hpp
new file mode 100644
index 0000000000..a080cbdaa2
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/dynamicmem.hpp
@@ -0,0 +1,98 @@
+#ifndef FILE_DYNAMICMEM
+#define FILE_DYNAMICMEM
+
+/**************************************************************************/
+/* File:   dynamicmem.hpp                                                 */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   12. Feb. 2003                                                  */
+/**************************************************************************/
+
+namespace netgen
+{
+
+
+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 ();
+  static void GetUsed (int nr, char * ch);
+};
+
+
+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/contrib/Netgen/libsrc/general/flags.cpp b/contrib/Netgen/libsrc/general/flags.cpp
new file mode 100644
index 0000000000..e5916f8758
--- /dev/null
+++ b/contrib/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 ()
+  {
+    for (int i = 0; i < strflags.Size(); i++)
+      delete [] strflags[i];
+    for (int i = 0; i < numlistflags.Size(); i++)
+      delete numlistflags[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;
+  }
+  
+  bool 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*> dummy_array(0);
+	return dummy_array;
+      }
+  }
+
+  const Array<double> & 
+  Flags ::GetNumListFlag (const char * name) const
+  {
+    if (numlistflags.Used (name))
+      return *numlistflags.Get(name);
+    else
+      {
+	static Array<double> dummy_array(0);
+	return dummy_array;
+      }
+  }
+
+
+  bool Flags :: StringFlagDefined (const char * name) const
+  {
+    return strflags.Used (name);
+  }
+
+  bool Flags :: NumFlagDefined (const char * name) const
+  {
+    return numflags.Used (name);
+  }
+
+  bool Flags :: StringListFlagDefined (const char * name) const
+  {
+    return strlistflags.Used (name);
+  }
+
+  bool 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/contrib/Netgen/libsrc/general/flags.hpp b/contrib/Netgen/libsrc/general/flags.hpp
new file mode 100644
index 0000000000..810fbfbe6b
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/flags.hpp
@@ -0,0 +1,88 @@
+#ifndef FILE_FLAGS
+#define FILE_FLAGS
+
+
+/**************************************************************************/
+/* File:   flags.hh                                                       */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   10. Oct. 96                                                   */
+/**************************************************************************/
+
+namespace netgen
+{
+
+/** 
+   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:
+  ///
+  DLL_HEADER Flags ();
+  ///
+  DLL_HEADER ~Flags ();
+  
+  /// Deletes all flags
+  DLL_HEADER void DeleteFlags ();
+  /// Sets string flag, overwrite if exists
+  DLL_HEADER void SetFlag (const char * name, const char * val);
+  /// Sets numerical flag, overwrite if exists
+  DLL_HEADER void SetFlag (const char * name, double val);
+  /// Sets boolean flag
+  DLL_HEADER void SetFlag (const char * name);
+  /// Sets string arary falg
+  DLL_HEADER void SetFlag (const char * name, const Array<char*> & val);
+  /// Sets double array flag
+  DLL_HEADER void SetFlag (const char * name, const Array<double> & val);
+  
+  /// Save flags to file
+  DLL_HEADER void SaveFlags (const char * filename) const;
+  /// write flags to stream
+  DLL_HEADER void PrintFlags (ostream & ost) const;
+  /// Load flags from file
+  DLL_HEADER void LoadFlags (const char * filename);
+  /// set flag of form -name=hello -val=0.5 -defined
+  DLL_HEADER void SetCommandLineFlag (const char * st);
+
+  /// Returns string flag, default value if not exists
+  DLL_HEADER const char * GetStringFlag (const char * name, const char * def) const;
+  /// Returns numerical flag, default value if not exists
+  DLL_HEADER double GetNumFlag (const char * name, double def) const;
+  /// Returns address of numerical flag, null if not exists
+  DLL_HEADER const double * GetNumFlagPtr (const char * name) const;
+  /// Returns address of numerical flag, null if not exists
+  DLL_HEADER double * GetNumFlagPtr (const char * name);
+  /// Returns boolean flag
+  DLL_HEADER bool GetDefineFlag (const char * name) const;
+  /// Returns string list flag, empty array if not exist
+  DLL_HEADER const Array<char*> & GetStringListFlag (const char * name) const;
+  /// Returns num list flag, empty array if not exist
+  DLL_HEADER const Array<double> & GetNumListFlag (const char * name) const;
+
+
+  /// Test, if string flag is defined
+  DLL_HEADER bool StringFlagDefined (const char * name) const;
+  /// Test, if num flag is defined
+  DLL_HEADER bool NumFlagDefined (const char * name) const;
+  /// Test, if string list flag is defined
+  DLL_HEADER bool StringListFlagDefined (const char * name) const;
+  /// Test, if num list flag is defined
+  DLL_HEADER bool NumListFlagDefined (const char * name) const;
+};
+
+}
+  
+#endif
+
diff --git a/contrib/Netgen/libsrc/general/hashtabl.cpp b/contrib/Netgen/libsrc/general/hashtabl.cpp
new file mode 100644
index 0000000000..53d7eafb46
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/hashtabl.cpp
@@ -0,0 +1,326 @@
+/**************************************************************************/
+/* File:   hashtabl.cpp                                                   */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   01. Jun. 95                                                    */
+/**************************************************************************/
+
+/* 
+   Abstract data type HASHTABLE
+*/
+
+#include <algorithm>
+#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
+  {
+    for (int 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_CLOSED_HASHTABLE ::
+  BASE_INDEX_CLOSED_HASHTABLE (int size)
+    : hash(size)
+  {
+    hash.SetName ("index-hashtable, hash");
+
+    invalid = -1;
+    for (int i = 1; i <= size; i++)
+      hash.Elem(i) = invalid;
+  }
+
+  void BASE_INDEX_CLOSED_HASHTABLE ::
+  BaseSetSize (int size)
+  {
+    hash.SetSize(size);
+    for (int i = 1; i <= size; i++)
+      hash.Elem(i) = invalid;
+  }
+
+  int BASE_INDEX_CLOSED_HASHTABLE ::
+  Position2 (const INDEX & ind) const
+  {
+    int i = HashValue(ind);
+    while (1)
+      {
+	i++;
+	if (i > hash.Size()) i = 1;
+	if (hash.Get(i) == ind) return i;
+	if (hash.Get(i) == invalid) return 0;
+      }
+  }
+
+  int BASE_INDEX_CLOSED_HASHTABLE ::
+  PositionCreate2 (const INDEX & ind, int & apos) 
+  {
+    int i = HashValue(ind);
+    int startpos = i;
+    while (1)
+      {
+	i++;
+	if (i > hash.Size()) i = 1;
+	if (hash.Get(i) == ind) 
+	  {
+	    apos = i;
+	    return 0;
+	  }
+	if (hash.Get(i) == invalid) 
+	  {
+	    hash.Elem(i) = ind;
+	    apos = i;
+	    return 1;
+	  }
+	if (i == startpos)
+	  throw NgException ("Try to set new element in full closed hashtable");
+      }
+  }
+
+  int BASE_INDEX_CLOSED_HASHTABLE :: UsedElements () const
+  {
+    int n = hash.Size();
+    int cnt = 0;
+    for (int i = 1; i <= n; i++)
+      if (hash.Get(i) != invalid)
+	cnt++;
+    return cnt;
+  }
+
+
+
+
+
+
+
+
+
+
+
+  BASE_INDEX_2_CLOSED_HASHTABLE ::
+  BASE_INDEX_2_CLOSED_HASHTABLE (int size)
+    : hash(size)
+  {
+    hash.SetName ("i2-hashtable, hash");
+
+    invalid = -1;
+    for (int i = 1; i <= size; i++)
+      hash.Elem(i).I1() = invalid;
+  }
+
+  void BASE_INDEX_2_CLOSED_HASHTABLE ::
+  BaseSetSize (int size)
+  {
+    hash.SetSize(size);
+    for (int i = 1; i <= size; i++)
+      hash.Elem(i).I1() = invalid;
+  }
+
+
+  int BASE_INDEX_2_CLOSED_HASHTABLE ::
+  Position2 (const INDEX_2 & ind) const
+  {
+    int 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 = HashValue(ind);
+    int startpos = i;
+    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;
+	  }
+	if (i == startpos)
+	  throw NgException ("Try to set new element in full closed hashtable");
+      }
+  }
+
+  int BASE_INDEX_2_CLOSED_HASHTABLE :: UsedElements () const
+  {
+    int n = hash.Size();
+    int cnt = 0;
+    for (int i = 1; i <= n; i++)
+      if (hash.Get(i).I1() != invalid)
+	cnt++;
+    return cnt;
+  }
+
+
+
+
+
+
+
+
+  void BASE_INDEX_3_CLOSED_HASHTABLE ::
+  BaseSetSize (int size)
+  {
+    hash.SetSize(size);
+    for (int i = 0; i < size; i++)
+      hash[i].I1() = invalid;
+  }
+
+  bool BASE_INDEX_3_CLOSED_HASHTABLE ::
+  PositionCreate2 (const INDEX_3 & ind, int & apos) 
+  {
+    int i = HashValue(ind);
+    int startpos = i;
+    while (1)
+      {
+        /*
+	i++;
+	if (i >= hash.Size()) i = 0;
+        */
+        i = (i+1) % hash.Size();
+	if (hash[i] == ind) 
+	  {
+	    apos = i;
+	    return false;
+	  }
+	if (hash[i].I1() == invalid) 
+	  {
+	    hash[i] = ind;
+	    apos = i;
+	    return true;
+	  }
+	if (i == startpos)
+	  throw NgException ("Try to set new element in full closed hashtable");
+      }
+  }
+}
+
diff --git a/contrib/Netgen/libsrc/general/hashtabl.hpp b/contrib/Netgen/libsrc/general/hashtabl.hpp
new file mode 100644
index 0000000000..bd82518240
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/hashtabl.hpp
@@ -0,0 +1,1362 @@
+#ifndef FILE_HASHTABL
+#define FILE_HASHTABL
+
+/**************************************************************************/
+/* File:   hashtabl.hh                                                    */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   01. Jun. 95                                                    */
+/**************************************************************************/
+
+namespace netgen
+{
+
+/**
+   Abstract data type HASHTABLE.
+   Hash is done by one INDEX
+*/
+class BASE_INDEX_HASHTABLE
+{
+protected:
+  /// keys are stored in this table
+  TABLE<INDEX,1> 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,1> 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 bool 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:
+  ///
+ INDEX_2_HASHTABLE (int size)
+   : BASE_INDEX_2_HASHTABLE (size), cont(size)
+  { ; }  
+
+  ///
+  void SetSize(int s) 
+  { 
+    cont.SetSize(s); 
+    BaseSetSize(s);
+  }
+
+  ///
+  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);
+	}    
+  }
+  
+  ///
+  const T & Get (const INDEX_2 & ahash) const
+  {
+    int bnr = HashValue (ahash);
+    int pos = Position (bnr, ahash);
+    return cont.Get (bnr, pos);
+  }
+  
+  ///
+  bool Used (const INDEX_2 & ahash) const
+  {
+    return (Position (HashValue (ahash), ahash)) ? 1 : 0;
+  }
+ ///
+  int GetNBags () const
+  {
+    return cont.Size();
+  }
+  
+  ///
+  int GetBagSize (int bnr) const
+  {
+    return cont.EntrySize (bnr);
+  }
+    
+  ///
+  void GetData (int bnr, int colnr, 
+		INDEX_2 & ahash, T & acont) const
+  {
+    ahash = hash.Get(bnr, colnr);
+    acont = cont.Get(bnr, colnr);
+  }
+
+  ///
+  void SetData (int bnr, int colnr, 
+		const INDEX_2 & ahash, const T & acont) 
+  {
+    hash.Set(bnr, colnr, ahash);
+    cont.Set(bnr, colnr, acont);
+  }
+  
+  ///
+  void PrintMemInfo (ostream & ost) const
+  {
+    ost << "Hash: " << endl;
+    hash.PrintMemInfo (ost);
+    ost << "Cont: " << endl;
+    cont.PrintMemInfo (ost);
+  }
+
+
+  void DeleteData ()
+  {
+    int n = hash.Size();
+    hash.SetSize (n);
+    cont.SetSize (n);
+  }
+
+
+  class Iterator
+  {
+    const INDEX_2_HASHTABLE & ht;    
+    int bagnr, pos;
+  public:
+    Iterator (const INDEX_2_HASHTABLE & aht,
+	      int abagnr, int apos)
+      : ht(aht), bagnr(abagnr), pos(apos)
+    { ; }
+
+    int BagNr() const { return bagnr; }
+    int Pos() const { return pos; }
+
+    void operator++ (int)
+    {
+      // cout << "begin Operator ++: bagnr = " << bagnr << " -  pos = " << pos << endl;
+      pos++;
+      while (bagnr < ht.GetNBags() && 
+	     pos == ht.GetBagSize(bagnr+1))
+	{
+	  pos = 0;
+	  bagnr++;
+	}
+      // cout << "end Operator ++: bagnr = " << bagnr << " - pos = " << pos << endl;
+    }
+
+    bool operator != (int i) const
+    {
+      return bagnr != i;
+    }
+
+  };
+  
+  Iterator Begin () const
+  {
+    Iterator it(*this, 0, -1);
+    it++;
+    return it;
+  }
+
+  int End() const
+  {
+    return GetNBags();
+  }
+
+  void GetData (const Iterator & it,
+		INDEX_2 & ahash, T & acont) const
+  {
+    ahash = hash[it.BagNr()][it.Pos()];
+    acont = cont[it.BagNr()][it.Pos()];
+  }
+
+  const INDEX_2 & GetHash (const Iterator & it) const
+  { return hash[it.BagNr()][it.Pos()]; }
+
+  const T & GetData (const Iterator & it) const
+  { return cont[it.BagNr()][it.Pos()]; }
+};
+
+
+
+template <typename T> 
+inline ostream & operator<< (ostream & ost, const INDEX_2_HASHTABLE<T> & ht)
+{
+  for (typename INDEX_2_HASHTABLE<T>::Iterator it = ht.Begin();
+       it != ht.End(); it++)
+    {
+      ost << ht.GetHash(it) << ": " << ht.GetData(it) << endl;
+    }
+
+  return ost;
+}
+
+
+
+
+
+
+
+///
+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 bool 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 ();
+
+
+
+
+
+
+
+
+
+  class Iterator
+  {
+    const INDEX_3_HASHTABLE & ht;    
+    int bagnr, pos;
+  public:
+    Iterator (const INDEX_3_HASHTABLE & aht,
+	      int abagnr, int apos)
+      : ht(aht), bagnr(abagnr), pos(apos)
+    { ; }
+
+    int BagNr() const { return bagnr; }
+    int Pos() const { return pos; }
+
+    void operator++ (int)
+    {
+      // cout << "begin Operator ++: bagnr = " << bagnr << " -  pos = " << pos << endl;
+      pos++;
+      while (bagnr < ht.GetNBags() && 
+	     pos == ht.GetBagSize(bagnr+1))
+	{
+	  pos = 0;
+	  bagnr++;
+	}
+      // cout << "end Operator ++: bagnr = " << bagnr << " - pos = " << pos << endl;
+    }
+
+    bool operator != (int i) const
+    {
+      return bagnr != i;
+    }
+
+  };
+  
+  Iterator Begin () const
+  {
+    Iterator it(*this, 0, -1);
+    it++;
+    return it;
+  }
+
+  int End() const
+  {
+    return GetNBags();
+  }
+
+  void GetData (const Iterator & it,
+		INDEX_3 & ahash, T & acont) const
+  {
+    ahash = hash[it.BagNr()][it.Pos()];
+    acont = cont[it.BagNr()][it.Pos()];
+  }
+
+  const INDEX_3 & GetHash (const Iterator & it) const
+  { return hash[it.BagNr()][it.Pos()]; }
+
+  const T & GetData (const Iterator & it) const
+  { return cont[it.BagNr()][it.Pos()]; }
+
+
+
+};
+
+
+
+
+
+
+template <typename T> 
+inline ostream & operator<< (ostream & ost, const INDEX_3_HASHTABLE<T> & ht)
+{
+  for (typename INDEX_3_HASHTABLE<T>::Iterator it = ht.Begin();
+       it != ht.End(); it++)
+    {
+      ost << ht.GetHash(it) << ": " << ht.GetData(it) << endl;
+    }
+
+  return ost;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/// Closed Hashing HT
+
+class BASE_INDEX_CLOSED_HASHTABLE
+{
+protected:
+  ///
+  MoveableArray<INDEX> hash;
+  ///
+  int invalid;
+public:
+  ///
+  BASE_INDEX_CLOSED_HASHTABLE (int size);
+
+  int Size() const { return hash.Size(); }
+  int UsedPos (int pos) const { return ! (hash.Get(pos) == invalid); }
+  int UsedElements () const;
+
+  ///
+  int HashValue (const INDEX & ind) const
+  {
+    return (3*ind) % hash.Size() + 1;
+  }
+
+
+  int Position (const INDEX & ind) const
+  {
+    int i = HashValue(ind);
+    while (1)
+      {
+	if (hash.Get(i) == ind) return i;
+	if (hash.Get(i) == invalid) return 0;
+	i++;
+	if (i > hash.Size()) i = 1;
+      }
+  }
+
+  int CalcPositionCosts (const INDEX & ind) const
+  {
+    int i = HashValue(ind);
+    int costs = 1;
+    while (1)
+      {
+	if (hash.Get(i) == ind) return costs;
+	if (hash.Get(i) == invalid) return costs;
+	i++;
+	if (i > hash.Size()) i = 1;
+	costs++;
+      }
+  }
+
+
+
+  // returns 1, if new postion is created
+  int PositionCreate (const INDEX & ind, int & apos)
+  {
+    int i = HashValue (ind);
+    if (hash.Get(i) == ind) 
+      {
+	apos = i;
+	return 0;
+      }
+    if (hash.Get(i) == invalid)
+      {
+	hash.Elem(i) = ind; 
+	apos = i;
+	return 1;
+      }
+    return PositionCreate2 (ind, apos);    
+  }
+
+protected:
+  int Position2 (const INDEX & ind) const;
+  int PositionCreate2 (const INDEX & ind, int & apos);
+  void BaseSetSize (int asize);
+};
+
+
+template <class T>
+class INDEX_CLOSED_HASHTABLE : public BASE_INDEX_CLOSED_HASHTABLE
+{
+  ///
+  MoveableArray<T> cont;
+
+public:
+  ///
+  INDEX_CLOSED_HASHTABLE (int size)
+    : BASE_INDEX_CLOSED_HASHTABLE(size), cont(size)
+  {
+    cont.SetName ("ind-hashtable, contents");
+  }
+
+
+  void Set (const INDEX & ahash, const T & acont)
+  {
+    int pos;
+    PositionCreate (ahash, pos);
+    hash.Elem(pos) = ahash;
+    cont.Elem(pos) = acont;
+  }
+
+  const T & Get (const INDEX & ahash) const
+  {
+    int pos = Position (ahash);
+    return cont.Get(pos);
+  }
+
+  ///
+  bool Used (const INDEX & ahash) const
+  {
+    int pos = Position (ahash);
+    return (pos != 0);
+  }
+  
+  
+  ///
+  inline void SetData (int pos, const INDEX & ahash, const T & acont)
+  {
+    hash.Elem(pos) = ahash;
+    cont.Elem(pos) = acont;
+  }
+
+  ///
+  void GetData (int pos, INDEX & ahash, T & acont) const
+  {
+    ahash = hash.Get(pos);
+    acont = cont.Get(pos);
+  }
+  
+  ///
+  inline void SetData (int pos, const T & acont)
+  {
+    cont.Elem(pos) = acont;
+  }
+  
+  ///
+  void GetData (int pos, T & acont) const
+  {
+    acont = cont.Get(pos);
+  }
+  
+  ///
+  const T & GetData (int pos) { return cont.Get(pos); }
+  ///
+  inline void SetSize (int size)
+  {
+    BaseSetSize(size);
+  cont.SetSize(size);
+  }
+  
+  ///
+  inline void DeleteData ()
+  { SetSize (cont.Size()); }
+
+  void SetName (const char * aname)
+  {
+    cont.SetName(aname);
+    hash.SetName(aname);
+  }
+};
+
+
+
+
+
+
+
+/// 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;
+      }
+  }
+
+  // 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 bool 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;
+  ///
+  const T & GetData (int pos) { return cont.Get(pos); }
+  ///
+  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 <typename T> 
+inline ostream & operator<< (ostream & ost, const INDEX_2_CLOSED_HASHTABLE<T> & ht)
+{
+  for (int i = 0; i < ht.Size(); i++)
+    if (ht.UsedPos(i))
+      {
+	INDEX_2 hash;
+	T data;
+	ht.GetData (i, hash, data);
+	ost << "hash = " << hash << ", data = " << data << endl;
+      }
+  return ost;
+}
+
+
+
+
+
+
+class BASE_INDEX_3_CLOSED_HASHTABLE
+{
+protected:
+  MoveableArray<INDEX_3> hash;
+  int invalid;
+
+protected: 
+  BASE_INDEX_3_CLOSED_HASHTABLE (int size)
+    : hash(size)
+  {
+    hash.SetName ("i3-hashtable, hash");
+    invalid = -1;
+    for (int i = 0; i < size; i++)
+      hash[i].I1() = invalid;
+  }
+
+public:
+  int Size() const 
+  {
+    return hash.Size(); 
+  }
+
+  bool UsedPos (int pos) const 
+  { 
+    return ! (hash[pos].I1() == invalid); 
+  }
+
+  int UsedElements () const
+  {
+    int n = hash.Size();
+    int cnt = 0;
+    for (int i = 0; i < n; i++)
+      if (hash[i].I1() != invalid)
+	cnt++;
+    return cnt;
+  }
+
+  int HashValue (const INDEX_3 & ind) const
+  {
+    return (ind.I1() + 15 * ind.I2() + 41 * ind.I3()) % hash.Size();
+  }
+  
+  int Position (const INDEX_3 & ind) const
+  {
+    int i = HashValue(ind);
+    while (1)
+      {
+	if (hash[i] == ind) return i;
+	if (hash[i].I1() == invalid) return -1;
+        i = (i+1) % hash.Size();
+      }
+  }
+
+  int Costs (const INDEX_3 & ind) const
+  {
+    int i = HashValue(ind);
+    int c = 1;
+    while (1)
+      {
+	if (hash[i] == ind) return c;
+	if (hash[i].I1() == invalid) return c;
+        i = (i+1) % hash.Size();
+        c++;
+      }
+  }
+
+
+  
+  // returns true, if new postion is created
+  bool PositionCreate (const INDEX_3 & ind, int & apos)
+  {
+    int i = HashValue (ind);
+    if (hash[i] == ind) 
+      {
+	apos = i;
+	return false;
+      }
+    if (hash[i].I1() == invalid)
+      {
+	hash[i] = ind; 
+	apos = i;
+	return true;
+      }
+    return PositionCreate2 (ind, apos);    
+  }
+
+protected:
+  bool 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,0> cont;
+
+public:
+  INDEX_3_CLOSED_HASHTABLE (int size)
+    : BASE_INDEX_3_CLOSED_HASHTABLE(size), cont(size)
+  {
+    cont.SetName ("i3-hashtable, contents");
+  }
+  
+  void Set (const INDEX_3 & ahash, const T & acont)
+  {
+    int pos;
+    PositionCreate (ahash, pos);
+    hash[pos] = ahash;
+    cont[pos] = acont;
+  }
+
+  const T & Get (const INDEX_3 & ahash) const
+  {
+    return cont[Position (ahash)];
+  }
+
+  bool Used (const INDEX_3 & ahash) const
+  {
+    return (Position (ahash) != -1);
+  }
+
+  void SetData (int pos, const INDEX_3 & ahash, const T & acont)
+  {
+    hash[pos] = ahash;
+    cont[pos] = acont;
+  }
+
+  void GetData (int pos, INDEX_3 & ahash, T & acont) const
+  {
+    ahash = hash[pos];
+    acont = cont[pos];
+  }
+
+  void SetData (int pos, const T & acont)
+  {
+    cont[pos] = acont;
+  }
+
+  void GetData (int pos, T & acont) const
+  {
+    acont = cont[pos];
+  }
+
+  const T & GetData (int pos) const
+  {
+    return cont[pos];
+  }
+
+   void SetSize (int size)
+  {
+    BaseSetSize(size);
+    cont.SetSize(size);
+  }
+
+  void PrintMemInfo (ostream & ost) const
+  {
+    cout << "Hashtable: " << Size() 
+         << " entries of size " << sizeof(INDEX_3) << " + " << sizeof(T) 
+         << " = " << Size() * (sizeof(INDEX_3) + sizeof(T)) << " bytes" << endl;
+    
+  }
+
+  void DeleteData ()
+  { 
+    SetSize (cont.Size()); 
+  }
+
+  void SetName (const char * aname)
+  {
+    cont.SetName(aname);
+    hash.SetName(aname);
+  }
+};
+
+
+
+template <typename T> 
+inline ostream & operator<< (ostream & ost, const INDEX_3_CLOSED_HASHTABLE<T> & ht)
+{
+  for (int i = 0; i < ht.Size(); i++)
+    if (ht.UsedPos(i))
+      {
+	INDEX_3 hash;
+	T data;
+	ht.GetData (i, hash, data);
+	ost << "hash = " << hash << ", data = " << data << endl;
+      }
+  return ost;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+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 bool 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 bool 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);
+  }
+
+
+    
+    
+    
+    
+    
+
+
+
+
+
+
+
+
+/* *********** 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 bool 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[pos];
+}
+
+template<class T>
+inline bool 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 const T & INDEX_3_CLOSED_HASHTABLE<T> :: 
+GetData (int pos) const
+{
+  return 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/contrib/Netgen/libsrc/general/mpi_interface.hpp b/contrib/Netgen/libsrc/general/mpi_interface.hpp
new file mode 100644
index 0000000000..53f2257946
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/mpi_interface.hpp
@@ -0,0 +1,300 @@
+#ifndef FILE_PARALLEL
+#define FILE_PARALLEL
+
+
+
+#ifdef VTRACE
+#include "vt_user.h"
+#else
+  #define VT_USER_START(n)
+  #define VT_USER_END(n)
+  #define VT_TRACER(n)
+#endif
+
+
+namespace netgen
+{
+
+  extern DLL_HEADER int id, ntasks;
+  
+
+#ifdef PARALLEL
+  
+  enum { MPI_TAG_CMD = 110 };
+  enum { MPI_TAG_MESH = 210 };
+  enum { MPI_TAG_VIS = 310 };
+
+  extern MPI_Comm mesh_comm;
+
+  template <class T>
+  MPI_Datatype MyGetMPIType ( ) { cerr << "ERROR in GetMPIType() -- no type found" << endl;return 0;}
+
+  template <>
+  inline MPI_Datatype MyGetMPIType<int> ( ) 
+  { return MPI_INT; }
+  
+  template <>
+  inline MPI_Datatype MyGetMPIType<double> ( ) 
+  { return MPI_DOUBLE; }
+
+  
+  template <int S> class Vec;
+  template <> 
+  inline MPI_Datatype MyGetMPIType<Vec<3> > ()
+  {
+    static MPI_Datatype MPI_T = 0;
+    if (!MPI_T)
+      {
+	MPI_Type_contiguous ( 3, MPI_DOUBLE, &MPI_T);
+	MPI_Type_commit ( &MPI_T );
+      }
+    return MPI_T;
+  };
+
+
+  inline void MyMPI_Send (int i, int dest, int tag)
+  {
+    int hi = i;
+    MPI_Send( &hi, 1, MPI_INT, dest, tag, MPI_COMM_WORLD);
+  }
+
+  inline void MyMPI_Recv (int & i, int src, int tag)
+  {
+    MPI_Status status;
+    MPI_Recv( &i, 1, MPI_INT, src, tag, MPI_COMM_WORLD, &status);
+  }
+
+
+
+  inline void MyMPI_Send (const string & s, int dest, int tag)
+  {
+    MPI_Send( const_cast<char*> (s.c_str()), s.length(), MPI_CHAR, dest, tag, MPI_COMM_WORLD);
+  }
+
+  inline void MyMPI_Recv (string & s, int src, int tag)
+  {
+    MPI_Status status;
+    int len;
+    MPI_Probe (src, tag, MPI_COMM_WORLD, &status);
+    MPI_Get_count (&status, MPI_CHAR, &len);
+    s.assign (len, ' ');
+    MPI_Recv( &s[0], len, MPI_CHAR, src, tag, MPI_COMM_WORLD, &status);
+  }
+
+ 
+
+
+  template <class T, int BASE>
+  inline void MyMPI_Send (FlatArray<T, BASE> s, int dest, int tag)
+  {
+    MPI_Send( &s.First(), s.Size(), MyGetMPIType<T>(), dest, tag, MPI_COMM_WORLD);
+  }
+
+  template <class T, int BASE>
+  inline void MyMPI_Recv ( FlatArray<T, BASE> s, int src, int tag)
+  {
+    MPI_Status status;
+    MPI_Recv( &s.First(), s.Size(), MyGetMPIType<T>(), src, tag, MPI_COMM_WORLD, &status);
+  }
+
+  template <class T, int BASE>
+  inline void MyMPI_Recv ( Array <T, BASE> & s, int src, int tag)
+  {
+    MPI_Status status;
+    int len;
+    MPI_Probe (src, tag, MPI_COMM_WORLD, &status);
+    MPI_Get_count (&status, MyGetMPIType<T>(), &len);
+
+    s.SetSize (len);
+    MPI_Recv( &s.First(), len, MyGetMPIType<T>(), src, tag, MPI_COMM_WORLD, &status);
+  }
+
+  template <class T, int BASE>
+  inline int MyMPI_Recv ( Array <T, BASE> & s, int tag)
+  {
+    MPI_Status status;
+    int len;
+    MPI_Probe (MPI_ANY_SOURCE, tag, MPI_COMM_WORLD, &status);
+
+    int src = status.MPI_SOURCE;
+
+    MPI_Get_count (&status, MyGetMPIType<T>(), &len);
+
+    s.SetSize (len);
+    MPI_Recv( &s.First(), len, MyGetMPIType<T>(), src, tag, MPI_COMM_WORLD, &status);
+
+    return src;
+  }
+
+
+  /*
+  template <class T, int BASE>
+  inline void MyMPI_ISend (FlatArray<T, BASE> s, int dest, int tag, MPI_Request & request)
+  {
+    MPI_Isend( &s.First(), s.Size(), MyGetMPIType<T>(), dest, tag, MPI_COMM_WORLD, & request);
+  }
+
+
+  template <class T, int BASE>
+  inline void MyMPI_IRecv (FlatArray<T, BASE> s, int dest, int tag, MPI_Request & request)
+  {
+    MPI_Irecv( &s.First(), s.Size(), MyGetMPIType<T>(), dest, tag, MPI_COMM_WORLD, & request);
+  }
+  */
+
+  template <class T, int BASE>
+  inline MPI_Request MyMPI_ISend (FlatArray<T, BASE> s, int dest, int tag, MPI_Comm comm = MPI_COMM_WORLD)
+  {
+    MPI_Request request;
+    MPI_Isend( &s.First(), s.Size(), MyGetMPIType<T>(), dest, tag, comm, &request);
+    return request;
+  }
+
+
+  template <class T, int BASE>
+  inline MPI_Request MyMPI_IRecv (FlatArray<T, BASE> s, int dest, int tag, MPI_Comm comm = MPI_COMM_WORLD)
+  {
+    MPI_Request request;
+    MPI_Irecv( &s.First(), s.Size(), MyGetMPIType<T>(), dest, tag, comm, &request);
+    return request;
+  }
+
+  /*
+  template <class T, int BASE>
+  inline void MyMPI_ISend (FlatArray<T, BASE> s, int dest, int tag)
+  {
+    MPI_Request request;
+    MPI_Isend( &s.First(), s.Size(), MyGetMPIType<T>(), dest, tag, MPI_COMM_WORLD, &request);
+    MPI_Request_free (&request);
+  }
+
+
+  template <class T, int BASE>
+  inline void MyMPI_IRecv (FlatArray<T, BASE> s, int dest, int tag)
+  {
+    MPI_Request request;
+    MPI_Irecv( &s.First(), s.Size(), MyGetMPIType<T>(), dest, tag, MPI_COMM_WORLD, &request);
+    MPI_Request_free (&request);
+  }
+  */
+
+  inline void MyMPI_SendCmd (const char * cmd)
+  {
+    char buf[100];
+    strcpy (buf, cmd);
+    // MPI_Bcast (&buf, 100, MPI_CHAR, 0, MPI_COMM_WORLD);
+
+    for (int dest = 1; dest < ntasks; dest++)
+      MPI_Bsend( &buf, 100, MPI_CHAR, dest, MPI_TAG_CMD, MPI_COMM_WORLD);
+  }
+
+  inline string MyMPI_RecvCmd ()
+  {
+    char buf[100];
+    // MPI_Bcast (&buf, 100, MPI_CHAR, 0, MPI_COMM_WORLD);
+
+    MPI_Status status;
+    int flag;
+    do
+      {
+	MPI_Iprobe (0, MPI_TAG_CMD, MPI_COMM_WORLD, &flag, &status);
+	if (!flag) usleep (1000);
+      }
+    while (!flag);
+    MPI_Recv( &buf, 100, MPI_CHAR, 0, MPI_TAG_CMD, MPI_COMM_WORLD, &status);
+    
+    return string(buf);
+  }
+
+  template <class T>
+  inline void MyMPI_Bcast (T & s, MPI_Comm comm = MPI_COMM_WORLD)
+  {
+    MPI_Bcast (&s, 1, MyGetMPIType<T>(), 0, comm);
+  }
+
+  template <class T>
+  inline void MyMPI_Bcast (Array<T, 0> & s, MPI_Comm comm = MPI_COMM_WORLD)
+  {
+    int size = s.Size();
+    MyMPI_Bcast (size, comm);
+    if (id != 0) s.SetSize (size);
+    MPI_Bcast (&s[0], size, MyGetMPIType<T>(), 0, comm);
+  }
+
+  template <class T>
+  inline void MyMPI_Bcast (Array<T, 0> & s, int root, MPI_Comm comm = MPI_COMM_WORLD)
+  {
+    int id;
+    MPI_Comm_rank(comm, &id);
+
+    int size = s.Size();
+    MPI_Bcast (&size, 1, MPI_INT, root, comm);
+    if (id != root) s.SetSize (size);
+    if ( !size ) return;
+    MPI_Bcast (&s[0], size, MyGetMPIType<T>(), root, comm);
+  }
+
+  template <class T, class T2>
+  inline void MyMPI_Allgather (const T & send, FlatArray<T2> recv, MPI_Comm comm)
+  {
+    MPI_Allgather( const_cast<T*> (&send), 1, MyGetMPIType<T>(), &recv[0], 1, MyGetMPIType<T2>(), comm);
+  }
+
+  template <class T, class T2>
+  inline void MyMPI_Alltoall (FlatArray<T> send, FlatArray<T2> recv, MPI_Comm comm)
+  {
+    MPI_Alltoall( &send[0], 1, MyGetMPIType<T>(), &recv[0], 1, MyGetMPIType<T2>(), comm);
+  }
+
+//   template <class T, class T2>
+//   inline void MyMPI_Alltoall_Block (FlatArray<T> send, FlatArray<T2> recv, int blocklen, MPI_Comm comm)
+//   {
+//     MPI_Alltoall( &send[0], blocklen, MyGetMPIType<T>(), &recv[0], blocklen, MyGetMPIType<T2>(), comm);
+//   }
+
+
+
+  /*
+  inline void MyMPI_Send (  int *& s, int len,  int dest, int tag)
+  {
+    int hlen = len;
+    MPI_Send( &hlen, 1, MPI_INT, dest, tag, MPI_COMM_WORLD);
+    MPI_Send( s, len, MPI_INT, dest, tag, MPI_COMM_WORLD);
+  }
+
+
+  inline void MyMPI_Recv ( int *& s, int & len, int src, int tag)
+  {
+    MPI_Status status;
+    MPI_Recv( &len, 1, MPI_INT, src, tag, MPI_COMM_WORLD, &status);
+    if ( s ) 
+      delete [] s;
+    s = new int [len];
+    MPI_Recv( s, len, MPI_INT, src, tag, MPI_COMM_WORLD, &status);
+  }
+
+
+
+  inline void MyMPI_Send ( double * s, int len,  int dest, int tag)
+  {
+     MPI_Send( &len, 1, MPI_INT, dest, tag, MPI_COMM_WORLD);
+     MPI_Send( s, len, MPI_DOUBLE, dest, tag, MPI_COMM_WORLD);
+  }
+
+
+  inline void MyMPI_Recv ( double *& s, int & len, int src, int tag)
+  {
+    MPI_Status status;
+    MPI_Recv( &len, 1, MPI_INT, src, tag, MPI_COMM_WORLD, &status);
+    if ( s )
+      delete [] s;
+    s = new double [len];
+    MPI_Recv( s, len, MPI_DOUBLE, src, tag, MPI_COMM_WORLD, &status);
+  }
+  */
+
+#endif // PARALLEL
+
+}
+
+#endif
diff --git a/contrib/Netgen/libsrc/general/myadt.hpp b/contrib/Netgen/libsrc/general/myadt.hpp
new file mode 100644
index 0000000000..100e7a3a0b
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/myadt.hpp
@@ -0,0 +1,48 @@
+#ifndef FILE_MYADT
+#define FILE_MYADT
+
+/**************************************************************************/
+/* File:   myadt.hpp                                                      */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   01. Jun. 95                                                    */
+/**************************************************************************/
+
+/* 
+   include for all abstract data types
+*/
+
+
+
+#include "../include/mystdlib.h"
+#include "../include/mydefs.hpp"
+
+
+#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"
+#include "profiler.hpp"
+
+#include "mpi_interface.hpp"
+#include "netgenout.hpp"
+
+
+#endif
diff --git a/contrib/Netgen/libsrc/general/mystring.cpp b/contrib/Netgen/libsrc/general/mystring.cpp
new file mode 100644
index 0000000000..dc59c80ee3
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/mystring.cpp
@@ -0,0 +1,426 @@
+
+//**************************************************************
+//
+// 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>
+
+
+namespace netgen
+{
+
+  void ReadEnclString(istream & in, string & str, const char encl)
+  {
+    char currchar;
+    str = "";
+
+    in.get(currchar);
+    while(in && (currchar == ' ' || currchar == '\t' || currchar == '\n') )
+      in.get(currchar);
+	
+    if(currchar == encl)
+      {
+	in.get(currchar);
+	while(in && currchar != encl)
+	  {
+	    str += currchar;
+	    in.get(currchar);
+	  }
+      }
+    else
+      {
+	in.putback(currchar);
+	in >> str;
+      }
+  }
+	    
+	
+    
+  
+
+
+void DefaultStringErrHandler()
+{
+  cerr << "Error : string operation out of range\n" << flush;
+}
+
+void (*MyStr::ErrHandler)() = DefaultStringErrHandler;
+
+  /*     
+MyStr::MyStr()
+{
+  length = 0;
+  str = shortstr;
+  str[0] = 0;
+}
+  */
+
+MyStr::MyStr(const char *s)
+{
+  length = unsigned(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 = unsigned(strlen(buffer));
+  if (length > SHORTLEN)
+    str = new char[length + 1];
+  else
+    str = shortstr;
+  strcpy(str, buffer);
+}
+
+MyStr::MyStr(void * p)
+{
+  char buffer[32];
+  sprintf(buffer, "%p", p);
+  length = unsigned(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 = unsigned(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 = unsigned(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 = unsigned(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 = unsigned(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 string & st)
+{
+  length = unsigned(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;
+  }
+  unsigned 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;
+  }
+}
+
+string MyStr::cpp_string(void) const
+{
+  string aux(str,length);
+  return aux;
+}
+
+/*
+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/contrib/Netgen/libsrc/general/mystring.hpp b/contrib/Netgen/libsrc/general/mystring.hpp
new file mode 100644
index 0000000000..49cc7001fa
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/mystring.hpp
@@ -0,0 +1,220 @@
+
+//**************************************************************
+//
+// 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
+
+namespace netgen
+{
+
+class Point3d;
+class Vec3d;
+
+
+// extract string str which is enclosed by the given character encl from a given string in
+void ReadEnclString(istream & in, string & str, const char encl);
+
+
+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:
+  DLL_HEADER MyStr();
+  DLL_HEADER MyStr(const char *);
+  DLL_HEADER MyStr(char);
+  DLL_HEADER MyStr(const MyStr &);
+  DLL_HEADER MyStr(int);
+  DLL_HEADER MyStr(void *);
+  DLL_HEADER MyStr(long);
+  DLL_HEADER MyStr(double);
+  DLL_HEADER MyStr(const Point3d& p);
+  DLL_HEADER MyStr(const Vec3d& p);
+  DLL_HEADER MyStr(const 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();
+  string cpp_string(void) const;
+
+  //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()
+{
+  length = 0;
+  str = shortstr;
+  str[0] = 0;
+}
+
+inline MyStr::MyStr(char s)
+{
+  length = 1;
+  str = shortstr;
+  str[0] = s;
+  str[1] = (char)0;
+}
+
+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/contrib/Netgen/libsrc/general/netgenout.hpp b/contrib/Netgen/libsrc/general/netgenout.hpp
new file mode 100644
index 0000000000..06b23c22d5
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/netgenout.hpp
@@ -0,0 +1,187 @@
+#ifndef NETGEN_OUT_STREAM_HPP__
+#define NETGEN_OUT_STREAM_HPP__
+
+// #include <ostream>
+// #include <mystdlib.h>
+// #include <meshing.hpp>
+
+namespace netgen
+{
+
+#ifdef PARALLEL
+extern int id;
+extern int ntasks;
+#endif
+DLL_HEADER extern int printmessage_importance;
+
+
+
+class Imp
+{
+  int importance;
+public:
+  Imp () : importance(0) { ; }
+
+  Imp ( int aimportance ) : importance(aimportance) { ; }
+
+  int GetImp () const { return importance; }
+};
+
+
+class Proc
+{
+  int proc;
+public:
+  Proc () : proc(0) { ; }
+
+  Proc ( int aproc ) : proc(aproc) { ; }
+
+  int GetProc () const { return proc; }
+};
+
+class Procs
+{
+  const netgen::FlatArray<int> procs;
+
+public:
+
+  Procs ( const netgen::FlatArray<int> & aprocs ) : procs (aprocs) { ; }
+
+  const netgen::FlatArray<int> & GetProcs () const { return procs; }
+};
+
+
+
+class NetgenOutStream
+{
+  ostream * out;
+
+  bool print;
+  bool printheader;
+
+
+public:
+  NetgenOutStream() :
+    out(&std::cout),
+    print(1),
+    printheader(1)
+  {
+    ;
+  }  
+
+  NetgenOutStream(ostream * aout, Imp imp ) :
+    out(aout),
+    printheader(1)
+  { 
+    if ( netgen::printmessage_importance >= imp.GetImp() )
+      print = true;
+    else
+      print = false;
+  }
+
+  NetgenOutStream(ostream * aout, Proc proc ) :
+    out(aout),
+    printheader(1)
+  { 
+#ifdef PARALLEL
+    if ( netgen::id == proc.GetProc() )
+      print = true;
+    else
+      print = false;
+#else
+    if ( 0 == proc.GetProc() )
+      print = true;
+    else
+      print = false;
+
+#endif
+  }
+
+  NetgenOutStream(ostream * aout, Procs & procs ) :
+    out(aout),
+    printheader(1)
+  { 
+#ifdef PARALLEL
+    if ( procs.GetProcs().Contains(netgen::id) )
+      print = true;
+    else
+      print = false;
+#else
+    if ( procs.GetProcs().Contains(0) )
+      print = true;
+    else
+      print = false;
+
+#endif
+  }
+
+  ostream & OStream ()
+  {
+    return *out;
+  }
+
+  template <typename T>
+  NetgenOutStream & operator<< (T & var)
+  {
+    if ( print )
+      {
+#ifdef PARALLEL
+	if ( printheader )
+	  {
+	    *out << "proc " << netgen::id << ": ";
+	    printheader = false;
+	  }
+#endif
+	*out << var;
+      }
+    return (*this); 
+  }
+
+  NetgenOutStream& operator<< (ostream& ( *pf )(ostream&))
+  {
+    if ( print )
+      *out << (*pf) ;
+
+    return (*this);
+  }
+
+  NetgenOutStream& operator<< (ios& ( *pf )(ios&))
+  {
+    if ( print)
+      *out << (*pf) ;
+
+    printheader = 1;
+
+    return (*this);
+  }
+
+  NetgenOutStream& operator<< (ios_base& ( *pf )(ios_base&))
+  {
+    if (print )
+      *out << (*pf) ;
+    return (*this);
+  }
+
+
+};
+
+
+NetgenOutStream operator<< ( ostream & ost, Imp  imp );
+NetgenOutStream operator<< ( ostream & ost, Proc proc );
+NetgenOutStream operator<< ( ostream & ost, Procs & procs );
+// {
+//   return ( NetgenOutStream ( &ost, imp.GetImp() ) );
+// }
+
+// template <typename T>
+// NetgenOutStream& operator<< (NetgenOutStream& out, T c )
+// {
+//   out.OStream() << c << endl;
+//   return out;
+// }
+
+
+}
+
+
+#endif
diff --git a/contrib/Netgen/libsrc/general/ngexception.cpp b/contrib/Netgen/libsrc/general/ngexception.cpp
new file mode 100644
index 0000000000..2496f6b3be
--- /dev/null
+++ b/contrib/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/contrib/Netgen/libsrc/general/ngexception.hpp b/contrib/Netgen/libsrc/general/ngexception.hpp
new file mode 100644
index 0000000000..70dc0a4a5d
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/ngexception.hpp
@@ -0,0 +1,33 @@
+#ifndef FILE_NGEXCEPTION
+#define FILE_NGEXCEPTION
+
+/**************************************************************************/
+/* File:   ngexception.hpp                                                */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   16. Jan. 2002                                                  */
+/**************************************************************************/
+
+namespace netgen
+{
+
+/// Base class for all ng exceptions
+class NgException 
+{
+  /// verbal description of exception
+  string what;
+public:
+  ///
+  DLL_HEADER NgException (const string & s);
+  ///
+  DLL_HEADER virtual ~NgException ();
+
+  /// append string to description
+  DLL_HEADER void Append (const string & s);
+  //  void Append (const char * s);
+  
+  /// verbal description of exception
+  const string & What() const { return what; }
+};
+}
+
+#endif
diff --git a/contrib/Netgen/libsrc/general/optmem.cpp b/contrib/Netgen/libsrc/general/optmem.cpp
new file mode 100644
index 0000000000..adb4b36e99
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/optmem.cpp
@@ -0,0 +1,63 @@
+/**************************************************************************/
+/* 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 (int i = 0; i < bablocks.Size(); i++)
+      delete [] bablocks[i];
+  }
+
+  void * BlockAllocator :: Alloc ()
+  {
+    //  return new char[size];
+    if (!freelist)
+      {
+	// cout << "freelist = " << freelist << endl;
+	// 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/contrib/Netgen/libsrc/general/optmem.hpp b/contrib/Netgen/libsrc/general/optmem.hpp
new file mode 100644
index 0000000000..cd55f16ea5
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/optmem.hpp
@@ -0,0 +1,62 @@
+#ifndef FILE_OPTMEM
+#define FILE_OPTMEM
+
+/**************************************************************************/
+/* File:   optmem.hh                                                      */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   04. Apr. 97                                                    */
+/**************************************************************************/
+
+namespace netgen
+{
+
+/** 
+    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 ();
+  /*
+  {
+    if (!freelist)
+      Alloc2();
+
+    void * p = freelist;
+    // freelist = *(void**)freelist;
+    freelist = *static_cast<void**> (freelist);
+
+    return p;
+  }
+  */
+
+
+  ///
+  void Free (void * p)
+  {
+    *(void**)p = freelist;
+    freelist = p;
+  }
+  
+
+private:
+  //  void Alloc2 ();
+};
+
+}
+
+#endif
diff --git a/contrib/Netgen/libsrc/general/parthreads.cpp b/contrib/Netgen/libsrc/general/parthreads.cpp
new file mode 100644
index 0000000000..81e9d0b6cc
--- /dev/null
+++ b/contrib/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/contrib/Netgen/libsrc/general/parthreads.hpp b/contrib/Netgen/libsrc/general/parthreads.hpp
new file mode 100644
index 0000000000..c103790955
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/parthreads.hpp
@@ -0,0 +1,192 @@
+#ifndef FILE_PARTHREADS
+#define FILE_PARTHREADS
+
+/**************************************************************************/
+/* File:   parthreads.hh                                                  */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   22. Nov. 2000                                                  */
+/**************************************************************************/
+
+/*
+  Parallel thread, Mutex,
+*/
+
+namespace netgen
+{
+
+#ifdef NO_PARALLEL_THREADS
+
+class NgMutex { };
+
+class NgLock
+{
+public:
+  NgLock (NgMutex & mut, bool lock = 0) { ; }
+  void Lock () { ; }
+  void UnLock () { ; }
+};
+
+
+#else
+
+#ifdef _MSC_VER
+
+#ifdef MSVC_EXPRESS
+// #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 = false)
+    : 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 = true;
+  }
+  void UnLock ()
+  {
+    pthread_mutex_unlock (&mut);
+    locked = false;
+  }
+  /*
+  int TryLock ()
+  {
+    return pthread_mutex_trylock (&mut);
+  }
+  */
+};
+
+#else // Using MS VC++ Standard / Enterprise / Professional edition...
+
+
+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;
+  }
+};
+
+#endif // MSVC_EXPRESS
+
+#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 = false)
+    : 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 = true;
+  }
+  void UnLock ()
+  {
+    pthread_mutex_unlock (&mut);
+    locked = false;
+  }
+  /*
+  int TryLock ()
+  {
+    return pthread_mutex_trylock (&mut);
+  }
+  */
+};
+
+#endif
+
+#endif
+
+}
+
+#endif
diff --git a/contrib/Netgen/libsrc/general/profiler.cpp b/contrib/Netgen/libsrc/general/profiler.cpp
new file mode 100644
index 0000000000..91db4effd3
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/profiler.cpp
@@ -0,0 +1,118 @@
+/**************************************************************************/
+/* File:   profiler.cpp                                                   */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   19. Apr. 2002                                                  */
+/**************************************************************************/
+
+
+#include <myadt.hpp>
+
+namespace netgen
+{
+  //using namespace netgen;
+
+  long int NgProfiler::tottimes[SIZE];
+  long int NgProfiler::starttimes[SIZE];
+  long int NgProfiler::counts[SIZE];
+  string NgProfiler::names[SIZE];
+  int NgProfiler::usedcounter[SIZE];
+  
+
+  NgProfiler :: NgProfiler()
+  {
+    for (int i = 0; i < SIZE; i++)
+      {
+	tottimes[i] = 0;
+	usedcounter[i] = 0;
+      }
+
+    total_timer = CreateTimer ("total CPU time");
+    StartTimer (total_timer);
+  }
+
+  NgProfiler :: ~NgProfiler()
+  {
+#ifndef PARALLEL
+    StopTimer (total_timer);
+#endif
+
+    //ofstream prof;
+    //prof.open("ng.prof");
+
+    // ofstream-constructor may be called after STL-stuff is destructed,
+    // which leads to an "order of destruction"-problem,
+    // thus we use the C-variant:
+
+    if (getenv ("NGPROFILE"))
+      {
+	char filename[100];
+#ifdef PARALLEL
+	sprintf (filename, "netgen.prof.%d", id);
+#else
+	sprintf (filename, "netgen.prof");
+#endif
+	
+	if (id == 0) printf ("write profile to file netgen.prof\n"); 
+	FILE *prof = fopen(filename,"w");
+	Print (prof);
+	fclose(prof);
+      }
+  }
+
+
+//   void NgProfiler :: Print (ostream & prof)
+//   {
+//     for (int i = 0; i < SIZE; i++)
+//       if (counts[i] != 0 || usedcounter[i] != 0)
+// 	{
+// 	  prof.setf (ios::fixed, ios::floatfield);
+// 	  prof.setf (ios::showpoint);
+
+// 	  prof // << "job " << setw(3) << i 
+// 	    << "calls " << setw(8) << counts[i] 
+// 	    << ", time " << setprecision(2) << setw(6) << double(tottimes[i]) / CLOCKS_PER_SEC << " sec";
+
+// 	  if (usedcounter[i]) 
+// 	    prof << " " << names[i];
+// 	  else
+// 	    prof << " " << i;
+	    
+// 	  prof << endl;
+// 	}
+//   }
+
+
+  void NgProfiler :: Print (FILE * prof)
+  {
+    for (int i = 0; i < SIZE; i++)
+      if (counts[i] != 0 || usedcounter[i] != 0)
+	{
+	  //fprintf(prof,"job %3i calls %8i, time %6.2f sec",i,counts[i],double(tottimes[i]) / CLOCKS_PER_SEC);
+	  fprintf(prof,"calls %8li, time %6.2f sec",counts[i],double(tottimes[i]) / CLOCKS_PER_SEC);
+	  if(usedcounter[i])
+	    fprintf(prof," %s",names[i].c_str());
+	  else
+	    fprintf(prof," %i",i);
+	  fprintf(prof,"\n");
+	}
+  }
+
+  int NgProfiler :: CreateTimer (const string & name)
+  {
+    for (int i = SIZE-1; i > 0; i--)
+      if(names[i] == name)
+	return i;
+
+    for (int i = SIZE-1; i > 0; i--)
+      if (!usedcounter[i])
+	{
+	  usedcounter[i] = 1;
+	  names[i] = name;
+	  return i;
+	}
+    return -1;
+  }
+
+
+  NgProfiler prof;
+}
diff --git a/contrib/Netgen/libsrc/general/profiler.hpp b/contrib/Netgen/libsrc/general/profiler.hpp
new file mode 100644
index 0000000000..a3ad811c5a
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/profiler.hpp
@@ -0,0 +1,66 @@
+#ifndef FILE_NG_PROFILER
+#define FILE_NG_PROFILER
+
+/**************************************************************************/
+/* File:   profiler.hpp                                                   */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   5. Jan. 2005                                                  */
+/**************************************************************************/
+
+
+
+#ifdef VTRACE
+#include "vt_user.h"
+#else
+  #define VT_USER_START(n)
+  #define VT_USER_END(n)
+  #define VT_TRACER(n)
+#endif
+
+namespace netgen
+{
+
+class NgProfiler
+{
+  enum { SIZE = 1000 };
+
+  static long int tottimes[SIZE];
+  static long int starttimes[SIZE];
+  static long int counts[SIZE];
+  static string names[SIZE];
+  static int usedcounter[SIZE];
+
+  int total_timer;
+public: 
+  NgProfiler();
+  ~NgProfiler();
+  static int CreateTimer (const string & name);
+
+  static void StartTimer (int nr) 
+  { 
+    starttimes[nr] = clock(); counts[nr]++; 
+    // VT_USER_START (const_cast<char*> (names[nr].c_str())); 
+    VT_USER_START ( (char * const) (names[nr].c_str())); 
+  }
+  static void StopTimer (int nr) 
+  { 
+    tottimes[nr] += clock()-starttimes[nr]; 
+    VT_USER_END (const_cast<char*> (names[nr].c_str())); 
+  }
+
+  //static void Print (ostream & ost);
+  static void Print (FILE * prof);
+
+  class RegionTimer
+  {
+    int nr;
+  public:
+    RegionTimer (int anr) : nr(anr)
+      { StartTimer (nr); }
+    ~RegionTimer () { StopTimer (nr); }
+  };
+};
+
+}
+
+#endif
diff --git a/contrib/Netgen/libsrc/general/seti.cpp b/contrib/Netgen/libsrc/general/seti.cpp
new file mode 100644
index 0000000000..e7f5b2ea74
--- /dev/null
+++ b/contrib/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/contrib/Netgen/libsrc/general/seti.hpp b/contrib/Netgen/libsrc/general/seti.hpp
new file mode 100644
index 0000000000..4adbb09c57
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/seti.hpp
@@ -0,0 +1,50 @@
+#ifndef FILE_SETI
+#define FILE_SETI
+
+
+/**************************************************************************/
+/* File:   seti.hh                                                        */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   20. Mar. 98                                                    */
+/**************************************************************************/
+
+namespace netgen
+{
+
+/**
+  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> & GetArray() { return set; }
+};
+
+}
+
+#endif
+
diff --git a/contrib/Netgen/libsrc/general/sort.cpp b/contrib/Netgen/libsrc/general/sort.cpp
new file mode 100644
index 0000000000..a6adda1a04
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/sort.cpp
@@ -0,0 +1,75 @@
+/**************************************************************************/
+/* File:   sort.cc                                                        */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   07. Jan. 00                                                    */
+/**************************************************************************/
+
+/* 
+   Sorting
+*/
+
+
+#include <algorithm>
+#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 QuickSortRec (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) QuickSortRec (values, order, left, j);
+    if (i < right) QuickSortRec (values, order, i, right);
+  }
+
+  void QuickSort (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;
+
+    QuickSortRec (values, order, 1, order.Size());
+  }
+}
diff --git a/contrib/Netgen/libsrc/general/sort.hpp b/contrib/Netgen/libsrc/general/sort.hpp
new file mode 100644
index 0000000000..3a9b41db9f
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/sort.hpp
@@ -0,0 +1,46 @@
+#ifndef FILE_SORT
+#define FILE_SORT
+
+/**************************************************************************/
+/* File:   sort.hh                                                        */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   07. Jan. 00                                                    */
+/**************************************************************************/
+
+namespace netgen
+{
+
+// order(i) is sorted index of element i
+extern void Sort (const Array<double> & values,
+		  Array<int> & order);
+
+extern void QuickSort (const Array<double> & values,
+		      Array<int> & order);
+
+
+
+
+template <class T>
+inline void BubbleSort (int size, T * data)
+{
+  T hv;
+  for (int i = 0; i < size; i++)
+    for (int j = i+1; j < size; j++)
+      if (data[i] > data[j])
+	{
+	  hv = data[i];
+	  data[i] = data[j];
+	  data[j] = hv;
+	}
+}
+
+template <class T>
+inline void BubbleSort (Array<T> & data)
+{
+  if(data.Size() > 0)
+	  BubbleSort (data.Size(), &data[data.Begin()]);
+}
+
+}
+
+#endif
diff --git a/contrib/Netgen/libsrc/general/spbita2d.cpp b/contrib/Netgen/libsrc/general/spbita2d.cpp
new file mode 100644
index 0000000000..45e8641370
--- /dev/null
+++ b/contrib/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/contrib/Netgen/libsrc/general/spbita2d.hpp b/contrib/Netgen/libsrc/general/spbita2d.hpp
new file mode 100644
index 0000000000..ba451fc789
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/spbita2d.hpp
@@ -0,0 +1,59 @@
+#ifndef FILE_SPBITA2D
+#define FILE_SPBITA2D
+
+/**************************************************************************/
+/* File:   spbita2d.hh                                                    */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   01. Jun. 95                                                    */
+/**************************************************************************/
+
+/** 
+   Implementation of sparse 2 dimensional bitarray
+*/
+
+namespace netgen
+{
+
+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/contrib/Netgen/libsrc/general/stack.hpp b/contrib/Netgen/libsrc/general/stack.hpp
new file mode 100644
index 0000000000..83adee640c
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/stack.hpp
@@ -0,0 +1,114 @@
+#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"
+
+namespace netgen
+{
+
+///
+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/contrib/Netgen/libsrc/general/symbolta.cpp b/contrib/Netgen/libsrc/general/symbolta.cpp
new file mode 100644
index 0000000000..bd35ac7cb2
--- /dev/null
+++ b/contrib/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/contrib/Netgen/libsrc/general/symbolta.hpp b/contrib/Netgen/libsrc/general/symbolta.hpp
new file mode 100644
index 0000000000..cfb6d9574b
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/symbolta.hpp
@@ -0,0 +1,161 @@
+#ifndef FILE_SYMBOLTA
+#define FILE_SYMBOLTA
+
+
+/**************************************************************************/
+/* File:   symbolta.hh                                                    */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   01. Jun. 95                                                    */
+/**************************************************************************/
+
+namespace netgen
+{
+
+/**
+   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
+{
+private:
+  /// 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 bool 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 = 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 bool SYMBOLTABLE<T> :: Used (const char * name) const
+{
+  return (Index(name)) ? true : false;
+}
+
+template <class T>
+inline void SYMBOLTABLE<T> :: DeleteAll () 
+{	
+  DelNames();
+  data.DeleteAll();
+}
+
+}
+#endif
diff --git a/contrib/Netgen/libsrc/general/table.cpp b/contrib/Netgen/libsrc/general/table.cpp
new file mode 100644
index 0000000000..d9d6cf139d
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/table.cpp
@@ -0,0 +1,214 @@
+/**************************************************************************/
+/* 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)
+  {
+    for (int i = 0; i < data.Size(); i++)
+      delete [] (char*)data[i].col;
+    
+    data.SetSize(size);
+    for (int i = 0; i < size; i++)
+      {
+	data[i].maxsize = 0;
+	data[i].size = 0;
+	data[i].col = NULL;
+      }    
+  }
+  
+  void BASE_TABLE :: ChangeSize (int size)
+  {
+    int oldsize = data.Size();
+    if (size == oldsize) 
+      return;
+
+    if (size < oldsize)
+      for (int i = size; i < oldsize; i++)
+	delete [] (char*)data[i].col;
+    
+    data.SetSize(size);
+
+    for (int i = oldsize; i < size; i++)
+      {
+	data[i].maxsize = 0;
+	data[i].size = 0;
+	data[i].col = NULL;
+      }    
+  }
+
+  void BASE_TABLE :: IncSize2 (int i, int elsize)
+  {
+#ifdef DEBUG
+    if (i < 0 || i >= data.Size())
+      {
+	MyError ("BASE_TABLE::Inc: Out of range");
+	return;
+      }
+#endif
+
+    linestruct & line = data[i];
+    if (line.size == line.maxsize)
+      {
+	void * p = new char [(line.maxsize+5) * elsize];
+      
+	memcpy (p, line.col, line.maxsize * elsize);
+	delete [] (char*)line.col;
+
+	line.col = p;
+	line.maxsize += 5;
+      }
+  
+    line.size++;
+  }
+
+
+
+
+  void BASE_TABLE :: SetEntrySize2 (int i, int newsize, int elsize)
+  {
+    linestruct & line = data[i];
+    if (newsize > line.maxsize)
+      {
+	void * p = new char [newsize * elsize];
+      
+	memcpy (p, line.col, min2 (newsize, line.size) * elsize);
+	delete [] (char*)line.col;
+
+	line.col = p;
+      }
+
+    line.size = newsize;
+  }
+
+
+
+
+
+  /*
+  void BASE_TABLE :: DecSize (int i)
+  {
+#ifdef DEBUG
+    if (i < 0 || i >= data.Size())
+      {
+	MyError ("BASE_TABLE::Dec: Out of range");
+	return;
+      }
+#endif
+
+    linestruct & line = data[i];
+  
+#ifdef DEBUG
+    if (line.size == 0)
+      {
+	MyError ("BASE_TABLE::Dec: EntrySize < 0");
+	return;      
+      }
+#endif
+  
+    line.size--;
+  }
+  */
+
+
+
+  void BASE_TABLE :: AllocateElementsOneBlock (int elemsize)
+  {
+    int cnt = 0;
+    int n = data.Size();
+
+    for (int i = 0; i < n; i++)
+      cnt += data[i].maxsize;
+    oneblock = new char[elemsize * cnt];
+
+    cnt = 0;
+    for (int i = 0; i < n; i++)
+      {
+	data[i].size = 0;
+	data[i].col = &oneblock[elemsize * cnt];
+	cnt += data[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;
+  }
+
+  void BASE_TABLE :: SetElementSizesToMaxSizes ()
+  {
+    for (int i = 0; i < data.Size(); i++)
+      data[i].size = data[i].maxsize;
+  }
+
+}
diff --git a/contrib/Netgen/libsrc/general/table.hpp b/contrib/Netgen/libsrc/general/table.hpp
new file mode 100644
index 0000000000..f63b80746a
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/table.hpp
@@ -0,0 +1,239 @@
+#ifndef FILE_TABLE
+#define FILE_TABLE
+
+/**************************************************************************/
+/* File:   table.hpp                                                      */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   01. Jun. 95                                                    */
+/**************************************************************************/
+
+namespace netgen
+{
+
+
+/// 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 ChangeSize (int size);
+
+  /// increment size of entry i by one, i is 0-based
+  void IncSize (int i, int elsize)
+  {
+    if (data[i].size < data[i].maxsize)
+      data[i].size++;
+    else
+      IncSize2 (i, elsize);
+  }
+
+  void SetEntrySize (int i, int newsize, int elsize)
+  {
+    if (newsize < data[i].maxsize)
+      data[i].size = newsize;
+    else
+      SetEntrySize2 (i, newsize, elsize);
+  }
+
+  ///
+  void IncSize2 (int i, int elsize);
+  void SetEntrySize2 (int i, int newsize, int elsize);
+
+  //  void DecSize (int i);
+
+  ///
+  void AllocateElementsOneBlock (int elemsize);
+  
+  int AllocatedElements () const;
+  int UsedElements () const;
+
+  void SetElementSizesToMaxSizes ();
+};
+
+
+
+
+
+
+
+/** 
+   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 maximal 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);
+  }
+
+  /// Changes Size of table to size, keep data
+  inline void ChangeSize (int size)
+  {
+    BASE_TABLE::ChangeSize (size);
+  }
+
+
+  /// Inserts element acont into row i, BASE-based. Does not test if already used.
+  inline void Add (int i, const T & acont)
+  {
+    IncSize (i-BASE, sizeof (T));
+    ((T*)data[i-BASE].col)[data[i-BASE].size-1] = acont;
+  }
+
+
+  /// Inserts element acont into row i, 1-based. Does not test if already used.
+  inline void Add1 (int i, const T & acont)
+  {
+    IncSize (i-1, sizeof (T));
+    ((T*)data.Elem(i).col)[data.Elem(i).size-1] = acont;
+  }
+  
+  ///
+  void IncSizePrepare (int i)
+  {
+    data[i-BASE].maxsize++;
+  }
+
+
+  /// Inserts element acont into row i. BASE-based. Does not test if already used, assumes to have enough memory
+  inline void AddSave (int i, const T & acont)
+    {
+      ((T*)data[i-BASE].col)[data[i-BASE].size] = acont;
+      data[i-BASE].size++;
+    }
+
+  /// Inserts element acont into row i. 1-based. Does not test if already used, assumes to have mem
+  inline void AddSave1 (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-BASE, 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, const TABLE<T,BASE> & table)
+{
+  for (int i = BASE; i < table.Size()+BASE; i++)
+    {
+      ost << i << ": ";
+      FlatArray<T> row = table[i];
+      ost << "(" << row.Size() << ") ";
+      for (int j = 0; j < row.Size(); j++)
+	ost << row[j] << " ";
+      ost << endl;
+    }
+  return ost;
+}
+
+}
+
+#endif
+
diff --git a/contrib/Netgen/libsrc/general/template.hpp b/contrib/Netgen/libsrc/general/template.hpp
new file mode 100644
index 0000000000..0bb83f2732
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/template.hpp
@@ -0,0 +1,460 @@
+#ifndef FILE_TEMPLATE
+#define FILE_TEMPLATE
+
+/**************************************************************************/
+/* File:   template.hh                                                    */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   01. Jun. 95                                                    */
+/**************************************************************************/
+
+namespace netgen 
+{
+
+/*
+   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 */
+DLL_HEADER 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 */
+DLL_HEADER 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]; }
+
+  ///
+
+
+  INDEX_2 Sort ()
+  {
+    if (i[0] > i[1]) 
+      {
+	INDEX hi = i[0];
+	i[0] = i[1];
+	i[1] = hi;
+      }
+    return *this;
+  }
+
+  static INDEX_2 Sort (int i1, int i2)
+  {
+    if (i1 > i2)
+      return INDEX_2 (i2,i1);
+    else
+      return INDEX_2 (i1,i2);
+  }
+
+
+  ///
+  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]; }
+
+
+  static INDEX_3 Sort (INDEX_3 i3)
+  {
+    return i3.Sort();
+  }
+
+  static INDEX_3 Sort (int i1, int i2, int i3)
+  {
+    if (i1 > i2) Swap (i1, i2);
+    if (i2 > i3) Swap (i2, i3);
+    if (i1 > i2) Swap (i1, i2);
+    return INDEX_3 (i1, i2, i3);
+  }
+
+  INDEX_3 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]);
+    return *this;
+  }
+
+  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);
+};
+
+
+inline bool operator< (const INDEX_4 & a, const INDEX_4 & b)
+{
+  for (int j = 0; j < 4; j++)
+    {
+      if (a[j] < b[j]) return true;
+      if (a[j] > b[j]) return false;
+    }
+  return false;
+}
+
+
+
+
+
+
+
+
+
+
+///
+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/contrib/Netgen/libsrc/geom2d/Makefile.am b/contrib/Netgen/libsrc/geom2d/Makefile.am
new file mode 100644
index 0000000000..82d95667b3
--- /dev/null
+++ b/contrib/Netgen/libsrc/geom2d/Makefile.am
@@ -0,0 +1,14 @@
+noinst_HEADERS = geom2dmesh.hpp geometry2d.hpp vsgeom2d.hpp 
+
+AM_CPPFLAGS = -I$(top_srcdir)/libsrc/include  $(TCL_INCLUDES)
+
+METASOURCES = AUTO
+lib_LTLIBRARIES = libgeom2d.la libgeom2dvis.la
+
+libgeom2d_la_SOURCES = genmesh2d.cpp geom2dmesh.cpp geometry2d.cpp
+libgeom2d_la_LIBADD = 	$(top_builddir)/libsrc/meshing/libmesh.la
+
+libgeom2dvis_la_SOURCES = geom2dpkg.cpp vsgeom2d.cpp
+libgeom2dvis_la_LIBADD = libgeom2d.la
+
+
diff --git a/contrib/Netgen/libsrc/geom2d/genmesh2d.cpp b/contrib/Netgen/libsrc/geom2d/genmesh2d.cpp
new file mode 100644
index 0000000000..000e5ad67d
--- /dev/null
+++ b/contrib/Netgen/libsrc/geom2d/genmesh2d.cpp
@@ -0,0 +1,542 @@
+#include <meshing.hpp>
+#include <geometry2d.hpp>
+
+namespace netgen
+{
+  extern DLL_HEADER MeshingParameters mparam;
+
+  extern void Optimize2d (Mesh & mesh, MeshingParameters & mp);
+
+
+
+  void CalcPartition (double l, double h, double h1, double h2,
+		      double hcurve, double elto0, Array<double> & points);
+
+  // partitionizes spline curve
+  void Partition (const SplineSegExt & spline,
+		  double h, double elto0,
+		  Mesh & mesh, Point3dTree & searchtree, int segnr) 
+  {
+    enum { D = 2 };
+    int i, j;
+    double l; // , r1, r2, ra;
+    double lold, dt, frac;
+    int n = 100;
+    Point<D> p, pold, mark, oldmark;
+    Array<double> curvepoints;
+    double edgelength, edgelengthold;
+    l = spline.Length();
+
+    double h1 = min (spline.StartPI().hmax, h/spline.StartPI().refatpoint);
+    double h2 = min (spline.EndPI().hmax, h/spline.EndPI().refatpoint);
+    double hcurve = min (spline.hmax, h/spline.reffak);
+
+    CalcPartition (l, h, h1, h2, hcurve, elto0, curvepoints);
+    //  cout << "curvepoints = " << curvepoints << endl;
+
+    dt = 1.0 / n;
+
+    l = 0;
+    j = 1;
+
+    pold = spline.GetPoint (0);
+    lold = 0;
+    oldmark = pold;
+    edgelengthold = 0;
+    Array<int> locsearch;
+    
+    for (i = 1; i <= n; i++)
+      {
+	p = spline.GetPoint (i*dt);
+	l = lold + Dist (p, pold);
+	while (j < curvepoints.Size() && (l >= curvepoints[j] || i == n))
+	  {
+	    frac = (curvepoints[j]-lold) / (l-lold);
+	    edgelength = i*dt + (frac-1)*dt;
+	    // mark = pold + frac * (p-pold);
+	    mark = spline.GetPoint (edgelength);
+	  
+	    // cout << "mark = " << mark << " =?= " << GetPoint (edgelength) << endl;
+
+	    {
+	      PointIndex pi1 = -1, pi2 = -1;
+	  
+	      Point3d mark3(mark(0), mark(1), 0);
+	      Point3d oldmark3(oldmark(0), oldmark(1), 0);
+
+	      Vec<3> v (1e-4*h, 1e-4*h, 1e-4*h);
+	      searchtree.GetIntersecting (oldmark3 - v, oldmark3 + v, locsearch);
+
+	      for (int k = 0; k < locsearch.Size(); k++)
+		if ( mesh[PointIndex(locsearch[k])].GetLayer() == spline.layer)
+		  pi1 = locsearch[k];
+	      // if (locsearch.Size()) pi1 = locsearch[0];
+	      
+	      searchtree.GetIntersecting (mark3 - v, mark3 + v, locsearch);
+	      for (int k = 0; k < locsearch.Size(); k++)
+		if ( mesh[PointIndex(locsearch[k])].GetLayer() == spline.layer)
+		  pi2 = locsearch[k];
+	      // if (locsearch.Size()) pi2 = locsearch[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, spline.layer);
+		  searchtree.Insert (oldmark3, pi1);
+		}
+	      if (pi2 == -1)
+		{
+		  pi2 = mesh.AddPoint(mark3, spline.layer);
+		  searchtree.Insert (mark3, pi2);
+		}
+
+	      Segment seg;
+	      seg.edgenr = segnr;
+	      seg.si = spline.bc; // segnr;
+	      seg[0] = pi1;
+	      seg[1] = pi2;
+	      seg.domin = spline.leftdom;
+	      seg.domout = spline.rightdom;
+	      seg.epgeominfo[0].edgenr = segnr;
+	      seg.epgeominfo[0].dist = edgelengthold;
+	      seg.epgeominfo[1].edgenr = segnr;
+	      seg.epgeominfo[1].dist = edgelength;
+	      seg.singedge_left = spline.hpref_left;
+	      seg.singedge_right = spline.hpref_right;
+	      mesh.AddSegment (seg);
+	    }
+	
+	    oldmark = mark;
+	    edgelengthold = edgelength;
+	    j++;
+	  }
+    
+	pold = p;
+	lold = l;
+      }
+  }
+
+
+
+  void SplineGeometry2d :: PartitionBoundary (double h, Mesh & mesh2d)
+  {
+    enum { D = 2 };
+    Box<D> bbox;
+    GetBoundingBox (bbox);
+    double dist = Dist (bbox.PMin(), bbox.PMax());
+    Point<3> pmin;
+    Point<3> pmax;
+  
+    pmin(2) = -dist; pmax(2) = dist;
+    for(int j=0;j<D;j++)
+      {
+	pmin(j) = bbox.PMin()(j);
+	pmax(j) = bbox.PMax()(j);
+      }
+
+    Point3dTree searchtree (pmin, pmax);
+
+    for (int i = 0; i < splines.Size(); i++)
+      for (int side = 0; side <= 1; side++)
+	{
+	  int dom = (side == 0) ? GetSpline(i).leftdom : GetSpline(i).rightdom;
+	  if (dom != 0) GetSpline(i).layer = GetDomainLayer (dom);
+	}
+
+    for (int i = 0; i < splines.Size(); i++)
+      if (GetSpline(i).copyfrom == -1)
+	{
+	  // astrid - set boundary meshsize to  domain meshsize h
+	  // if no domain mesh size is given, the max h value from the bounding box is used
+	  double minimum = min2 ( GetDomainMaxh ( GetSpline(i).leftdom ), GetDomainMaxh ( GetSpline(i).rightdom ) );
+	  double maximum = max2 ( GetDomainMaxh ( GetSpline(i).leftdom ), GetDomainMaxh ( GetSpline(i).rightdom ) );
+	  minimum = min2 ( minimum, h );
+	  maximum = min2 ( maximum, h);
+	  if ( minimum > 0 )
+	    // GetSpline(i).Partition(minimum, elto0, mesh2d, searchtree, i+1);
+	    Partition(GetSpline(i), minimum, elto0, mesh2d, searchtree, i+1);	    
+	  else if ( maximum > 0 )
+	    // GetSpline(i).Partition(maximum, elto0, mesh2d, searchtree, i+1);
+	    Partition(GetSpline(i), maximum, elto0, mesh2d, searchtree, i+1);
+	  else
+	    // GetSpline(i).Partition(h, elto0, mesh2d, searchtree, i+1);
+	    Partition(GetSpline(i), h, elto0, mesh2d, searchtree, i+1);
+	}
+      else
+	{
+	  CopyEdgeMesh (GetSpline(i).copyfrom, i+1, mesh2d, searchtree);
+	}
+  }
+
+
+
+
+
+
+  void SplineGeometry2d :: CopyEdgeMesh (int from, int to, Mesh & mesh, Point3dTree & searchtree)
+  {
+    const int D = 2;
+    int i;
+
+    Array<int, PointIndex::BASE> mappoints (mesh.GetNP());
+    Array<double, PointIndex::BASE> param (mesh.GetNP());
+    mappoints = -1;
+    param = 0;
+
+    Point3d pmin, pmax;
+    mesh.GetBox (pmin, pmax);
+    double diam2 = Dist2(pmin, pmax);
+
+    if (printmessage_importance>0)
+      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[0]) = 1;
+	    param.Elem(seg[0]) = seg.epgeominfo[0].dist;
+
+	    mappoints.Elem(seg[1]) = 1;
+	    param.Elem(seg[1]) = seg.epgeominfo[1].dist;
+	  }
+      }
+
+    bool mapped = false;
+    for (i = 1; i <= mappoints.Size(); i++)
+      {
+	if (mappoints.Get(i) != -1)
+	  {
+	    Point<D> newp = splines.Get(to)->GetPoint (param.Get(i));
+	    Point<3> newp3;
+	    for(int j=0; j<min2(D,3); j++)
+	      newp3(j) = newp(j);
+	    for(int j=min2(D,3); j<3; j++)
+	      newp3(j) = 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);
+		searchtree.Insert (newp3, npi);
+	      }
+
+	    mappoints.Elem(i) = npi;
+
+	    mesh.GetIdentifications().Add (i, npi, to);
+	    mapped = true;
+	  }
+      }
+    if(mapped)
+      mesh.GetIdentifications().SetType(to,Identifications::PERIODIC);
+
+    // 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 = GetSpline(to-1).bc;      // splines.Get(to)->bc;
+	    nseg[0] = mappoints.Get(seg[0]);
+	    nseg[1] = mappoints.Get(seg[1]);
+	    nseg.domin = GetSpline(to-1).leftdom;
+	    nseg.domout = GetSpline(to-1).rightdom;
+	  
+	    nseg.epgeominfo[0].edgenr = to;
+	    nseg.epgeominfo[0].dist = param.Get(seg[0]);
+	    nseg.epgeominfo[1].edgenr = to;
+	    nseg.epgeominfo[1].dist = param.Get(seg[1]);
+	    mesh.AddSegment (nseg);
+	  }
+      }
+  }
+
+
+
+
+
+  void MeshFromSpline2D (SplineGeometry2d & geometry,
+			 Mesh *& mesh, 
+			 MeshingParameters & mp)
+  {
+    PrintMessage (1, "Generate Mesh from spline geometry");
+
+    double h = mp.maxh;
+
+    Box<2> bbox = geometry.GetBoundingBox ();
+
+    if (bbox.Diam() < h) 
+      {
+	h = bbox.Diam();
+	mp.maxh = h;
+      }
+
+    mesh = new Mesh;
+    mesh->SetDimension (2);
+
+    geometry.PartitionBoundary (h, *mesh);
+
+
+    // marks mesh points for hp-refinement
+    for (int i = 0; i < geometry.GetNP(); i++)
+      if (geometry.GetPoint(i).hpref)
+	{
+	  double mindist = 1e99;
+	  PointIndex mpi(0);
+	  Point<2> gp = geometry.GetPoint(i);
+	  Point<3> gp3(gp(0), gp(1), 0);
+	  for (PointIndex pi = PointIndex::BASE; 
+	       pi < mesh->GetNP()+PointIndex::BASE; pi++)
+	    if (Dist2(gp3, (*mesh)[pi]) < mindist)
+	      {
+		mpi = pi;
+		mindist = Dist2(gp3, (*mesh)[pi]);
+	      }
+	  (*mesh)[mpi].Singularity(1.);
+	}
+
+
+    int maxdomnr = 0;
+    for (SegmentIndex 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 (int i = 1; i <= maxdomnr; i++)
+      mesh->AddFaceDescriptor (FaceDescriptor (i, 0, 0, i));
+
+    // set Array<string*> bcnames... 
+    // number of bcnames
+    int maxsegmentindex = 0;
+    for (SegmentIndex si = 0; si < mesh->GetNSeg(); si++)
+      {
+	if ( (*mesh)[si].si > maxsegmentindex) maxsegmentindex = (*mesh)[si].si;
+      }
+
+    mesh->SetNBCNames(maxsegmentindex);
+
+    for ( int sindex = 0; sindex < maxsegmentindex; sindex++ )
+      mesh->SetBCName ( sindex, geometry.GetBCName( sindex+1 ) );
+
+    for (SegmentIndex si = 0; si < mesh->GetNSeg(); si++)
+      (*mesh)[si].SetBCName ( (*mesh).GetBCNamePtr( (*mesh)[si].si-1 ) );
+
+    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(mparam.grading);
+
+    int bnp = mesh->GetNP(); // boundary points
+
+    int hquad = mparam.quad;
+
+
+    for (int domnr = 1; domnr <= maxdomnr; domnr++)
+      if (geometry.GetDomainTensorMeshing (domnr))
+        { // tensor product mesh
+          
+          Array<PointIndex, PointIndex::BASE> nextpi(bnp);
+          Array<int, PointIndex::BASE> si1(bnp), si2(bnp);
+          PointIndex firstpi;
+          
+          nextpi = -1;
+          si1 = -1;
+          si2 = -1;
+          for (SegmentIndex si = 0; si < mesh->GetNSeg(); si++)
+            {
+              int p1 = -1, p2 = -2;
+
+              if ( (*mesh)[si].domin == domnr)
+                { p1 = (*mesh)[si][0]; p2 = (*mesh)[si][1]; }
+              if ( (*mesh)[si].domout == domnr)
+                { p1 = (*mesh)[si][1]; p2 = (*mesh)[si][0]; }
+              
+              if (p1 == -1) continue;
+
+              nextpi[p1] = p2;       // counter-clockwise
+              
+              int index = (*mesh)[si].si;
+              if (si1[p1] != index && si2[p1] != index)
+                { si2[p1] = si1[p1]; si1[p1] = index; }
+              if (si1[p2] != index && si2[p2] != index)
+                { si2[p2] = si1[p2]; si1[p2] = index; }
+            }
+
+          PointIndex c1(0), c2, c3, c4;  // 4 corner points
+          int nex = 1, ney = 1;
+
+          for (PointIndex pi = 1; pi <= si2.Size(); pi++)
+            if (si2[pi] != -1)
+              { c1 = pi; break; }      
+
+          for (c2 = nextpi[c1]; si2[c2] == -1; c2 = nextpi[c2], nex++);
+          for (c3 = nextpi[c2]; si2[c3] == -1; c3 = nextpi[c3], ney++);
+          for (c4 = nextpi[c3]; si2[c4] == -1; c4 = nextpi[c4]);
+
+
+
+          Array<PointIndex> pts ( (nex+1) * (ney+1) );   // x ... inner loop
+          pts = -1;
+
+          for (PointIndex pi = c1, i = 0; pi != c2; pi = nextpi[pi], i++)
+            pts[i] = pi;
+          for (PointIndex pi = c2, i = 0; pi != c3; pi = nextpi[pi], i++)
+            pts[(nex+1)*i+nex] = pi;
+          for (PointIndex pi = c3, i = 0; pi != c4; pi = nextpi[pi], i++)
+            pts[(nex+1)*(ney+1)-i-1] = pi;
+          for (PointIndex pi = c4, i = 0; pi != c1; pi = nextpi[pi], i++)
+            pts[(nex+1)*(ney-i)] = pi;
+
+
+          for (PointIndex pix = nextpi[c1], ix = 0; pix != c2; pix = nextpi[pix], ix++)
+            for (PointIndex piy = nextpi[c2], iy = 0; piy != c3; piy = nextpi[piy], iy++)
+              {
+                Point<3> p = (*mesh)[pix] + ( (*mesh)[piy] - (*mesh)[c2] );
+                pts[(nex+1)*(iy+1) + ix+1] = mesh -> AddPoint (p , 1, FIXEDPOINT);
+              }
+
+          for (int i = 0; i < ney; i++)
+            for (int j = 0; j < nex; j++)
+              {
+                Element2d el(QUAD);
+                el[0] = pts[i*(nex+1)+j];
+                el[1] = pts[i*(nex+1)+j+1];
+                el[2] = pts[(i+1)*(nex+1)+j+1];
+                el[3] = pts[(i+1)*(nex+1)+j];
+                el.SetIndex (domnr);
+
+                mesh -> AddSurfaceElement (el);
+              }
+        }
+
+
+
+
+    for (int domnr = 1; domnr <= maxdomnr; domnr++)
+      {
+        if (geometry.GetDomainTensorMeshing (domnr)) continue;
+
+	if ( geometry.GetDomainMaxh ( domnr ) > 0 )
+	  h = geometry.GetDomainMaxh(domnr);
+
+
+	PrintMessage (3, "Meshing domain ", domnr, " / ", maxdomnr);
+
+	int oldnf = mesh->GetNSE();
+
+        mparam.quad = hquad || geometry.GetDomainQuadMeshing (domnr);
+
+	Meshing2 meshing (mparam, Box<3> (pmin, pmax));
+
+	Array<int, PointIndex::BASE> compress(bnp);
+	compress = -1;
+	int cnt = 0;
+	for (PointIndex pi = PointIndex::BASE; pi < bnp+PointIndex::BASE; pi++)
+	  if ( (*mesh)[pi].GetLayer() == geometry.GetDomainLayer(domnr))
+	    {
+	      meshing.AddPoint ( (*mesh)[pi], pi);
+	      cnt++;
+	      compress[pi] = cnt;
+	    }
+
+	PointGeomInfo gi;
+	gi.trignum = 1;
+	for (SegmentIndex si = 0; si < mesh->GetNSeg(); si++)
+	  {
+	    if ( (*mesh)[si].domin == domnr)
+	      {
+		meshing.AddBoundaryElement ( compress[(*mesh)[si][0]], 
+					     compress[(*mesh)[si][1]], gi, gi);
+	      }
+	    if ( (*mesh)[si].domout == domnr)
+	      {
+		meshing.AddBoundaryElement ( compress[(*mesh)[si][1]],
+					     compress[(*mesh)[si][0]], gi, gi);
+		
+	      }
+
+	  }
+
+
+	mparam.checkoverlap = 0;
+	
+	/*
+	if (!mparam.quad)
+	  meshing.Delaunay (*mesh, domnr, mparam);
+	else
+	*/
+	meshing.GenerateMesh (*mesh, mparam, h, domnr);
+
+	for (SurfaceElementIndex sei = oldnf; sei < mesh->GetNSE(); sei++)
+	  (*mesh)[sei].SetIndex (domnr);
+
+
+	// astrid
+	char * material;
+	geometry.GetMaterial( domnr, material );
+	if ( material )
+	  {
+	    (*mesh).SetMaterial ( domnr,  material );
+	  }
+
+      }
+
+    mparam.quad = hquad;
+
+
+
+    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();
+
+
+    extern DLL_HEADER void Render();
+    Render();
+  }
+
+
+
+
+
+
+
+
+}
diff --git a/contrib/Netgen/libsrc/geom2d/geom2dmesh.cpp b/contrib/Netgen/libsrc/geom2d/geom2dmesh.cpp
new file mode 100644
index 0000000000..87472d21c9
--- /dev/null
+++ b/contrib/Netgen/libsrc/geom2d/geom2dmesh.cpp
@@ -0,0 +1,82 @@
+#include <meshing.hpp>
+#include <geometry2d.hpp>
+
+namespace netgen
+{
+
+  Refinement2d :: Refinement2d (const SplineGeometry2d & ageometry)
+    : Refinement(), geometry(ageometry)
+  {
+    ;
+  }
+
+  Refinement2d :: ~Refinement2d ()
+  {
+    ;
+  }
+  
+
+  void Refinement2d :: 
+  PointBetween (const Point<3> & p1, const Point<3> & p2, double secpoint,
+		int surfi, 
+		const PointGeomInfo & gi1, 
+		const PointGeomInfo & gi2,
+		Point<3> & newp, PointGeomInfo & newgi) const
+  {
+    newp = p1+secpoint*(p2-p1);
+    newgi.trignum = 1;
+  }
+
+
+
+  void Refinement2d :: 
+  PointBetween (const Point<3> & p1, const Point<3> & p2, double secpoint, 
+		int surfi1, int surfi2, 
+		const EdgePointGeomInfo & ap1, 
+		const EdgePointGeomInfo & ap2,
+		Point<3> & newp, EdgePointGeomInfo & newgi) const
+  {
+    Point<2> p2d;
+  
+    p2d = geometry.GetSplines().Get(ap1.edgenr) -> 
+      GetPoint (((1-secpoint)*ap1.dist+secpoint*ap2.dist));
+  
+    //  (*testout) << "refine 2d line, ap1.dist, ap2.dist = " << ap1.dist << ", " << ap2.dist << endl;
+    //  (*testout) << "p1, p2 = " << p1 << p2 << ", newp = " << p2d << endl;
+
+    newp = Point3d (p2d(0), p2d(1), 0);
+    newgi.edgenr = ap1.edgenr;
+    newgi.dist = ((1-secpoint)*ap1.dist+secpoint*ap2.dist);
+  };
+
+
+
+  Vec<3> Refinement2d :: GetTangent (const Point<3> & p, int surfi1, int surfi2,
+                                     const EdgePointGeomInfo & ap1) const
+  {
+    Vec<2> t2d = geometry.GetSplines().Get(ap1.edgenr) -> GetTangent(ap1.dist);
+    return Vec<3> (t2d(0), t2d(1), 0);
+  }
+
+  Vec<3> Refinement2d :: GetNormal (const Point<3> & p, int surfi1, 
+                                    const PointGeomInfo & gi) const
+  {
+    return Vec<3> (0,0,1);
+  }
+
+
+  void Refinement2d :: ProjectToSurface (Point<3> & p, int surfi, const PointGeomInfo & /* gi */) const
+  {
+    p(2) = 0;
+  }
+
+
+  void Refinement2d :: ProjectToEdge (Point<3> & p, int surfi1, int surfi2, 
+                                      const EdgePointGeomInfo & egi) const
+  {
+    Point<2> p2d (p(0), p(1)), pp;
+    double t;
+    geometry.GetSplines().Get(egi.edgenr) -> Project (p2d, pp, t);
+    p = Point<3> (pp(0), pp(1), 0);
+  }
+}
diff --git a/contrib/Netgen/libsrc/geom2d/geom2dmesh.hpp b/contrib/Netgen/libsrc/geom2d/geom2dmesh.hpp
new file mode 100644
index 0000000000..9b72216df3
--- /dev/null
+++ b/contrib/Netgen/libsrc/geom2d/geom2dmesh.hpp
@@ -0,0 +1,52 @@
+#ifndef FILE_GEOM2DMESH
+#define FILE_GEOM2DMESH
+
+/**************************************************************************/
+/* File:   geom2dmesh.hh                                                  */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   22. Jan. 01                                                    */
+/**************************************************************************/
+
+
+namespace netgen
+{
+
+  class Refinement2d : public Refinement
+  {
+    const class SplineGeometry2d & geometry;
+
+  public:
+    Refinement2d (const class SplineGeometry2d & ageometry);
+    virtual ~Refinement2d ();
+  
+    virtual void PointBetween (const Point<3> & p1, const Point<3> & p2, double secpoint,
+			       int surfi, 
+			       const PointGeomInfo & gi1, 
+			       const PointGeomInfo & gi2,
+			       Point<3> & newp, PointGeomInfo & newgi) const;
+
+    virtual void PointBetween (const Point<3> & p1, const Point<3> & p2, double secpoint,
+			       int surfi1, int surfi2, 
+			       const EdgePointGeomInfo & ap1, 
+			       const EdgePointGeomInfo & ap2,
+			       Point<3> & newp, EdgePointGeomInfo & newgi) const;
+
+
+    virtual Vec<3> GetTangent (const Point<3> & p, int surfi1, int surfi2,
+			       const EdgePointGeomInfo & ap1) const;
+
+    virtual Vec<3> GetNormal (const Point<3> & p, int surfi1, 
+			      const PointGeomInfo & gi) const;
+
+    virtual void ProjectToSurface (Point<3> & p, int surfi, const PointGeomInfo & /* gi */) const;
+
+    virtual void ProjectToEdge (Point<3> & p, int surfi1, int surfi2, 
+				const EdgePointGeomInfo & egi) const;			     
+  };
+
+
+}
+
+
+
+#endif
diff --git a/contrib/Netgen/libsrc/geom2d/geom2dpkg.cpp b/contrib/Netgen/libsrc/geom2d/geom2dpkg.cpp
new file mode 100644
index 0000000000..1456c6ac1d
--- /dev/null
+++ b/contrib/Netgen/libsrc/geom2d/geom2dpkg.cpp
@@ -0,0 +1,72 @@
+#include <meshing.hpp>
+#include <geometry2d.hpp>
+#include <visual.hpp>
+
+#include "vsgeom2d.hpp"
+
+// extern "C" int Ng_CSG_Init (Tcl_Interp * interp);
+
+namespace netgen
+{
+	
+
+  extern DLL_HEADER NetgenGeometry * ng_geometry;
+  static VisualSceneGeometry2d vsgeom2d;
+
+
+
+  class SplineGeometryRegister : public GeometryRegister
+  {
+  public:
+    virtual NetgenGeometry * Load (string filename) const;
+    virtual VisualScene * GetVisualScene (const NetgenGeometry * geom) const;
+  };
+
+
+  NetgenGeometry *  SplineGeometryRegister :: Load (string filename) const
+  {
+    const char * cfilename = filename.c_str();
+    if (strcmp (&cfilename[strlen(cfilename)-4], "in2d") == 0)
+      {
+	PrintMessage (1, "Load 2D-Spline geometry file ", cfilename);
+	
+
+	ifstream infile(cfilename);
+
+	SplineGeometry2d * hgeom = new SplineGeometry2d();
+	hgeom -> Load (cfilename);
+	return hgeom;
+      }
+    
+    return NULL;
+  }
+
+
+
+  VisualScene * SplineGeometryRegister :: GetVisualScene (const NetgenGeometry * geom) const
+  {
+    SplineGeometry2d * geometry = dynamic_cast<SplineGeometry2d*> (ng_geometry);
+    if (geometry)
+      {
+	vsgeom2d.SetGeometry (geometry);
+	return &vsgeom2d;
+      }
+    return NULL;
+  }
+
+
+}
+
+
+using namespace netgen;
+#ifdef WIN32
+extern "C" __declspec(dllexport) int Ng_geom2d_Init (Tcl_Interp * interp);
+#else
+extern "C" int Ng_geom2d_Init (Tcl_Interp * interp);
+#endif
+
+int Ng_geom2d_Init (Tcl_Interp * interp)
+{
+  geometryregister.Append (new SplineGeometryRegister);
+  return TCL_OK;
+}
diff --git a/contrib/Netgen/libsrc/geom2d/geometry2d.cpp b/contrib/Netgen/libsrc/geom2d/geometry2d.cpp
new file mode 100644
index 0000000000..e8b10c5ebc
--- /dev/null
+++ b/contrib/Netgen/libsrc/geom2d/geometry2d.cpp
@@ -0,0 +1,938 @@
+/*
+
+2d Spline curve for Mesh generator
+
+*/
+
+#include <meshing.hpp>
+#include <geometry2d.hpp>
+
+namespace netgen
+{
+
+
+
+  SplineGeometry2d :: ~SplineGeometry2d()
+  {
+    for ( int i = 0; i < bcnames.Size(); i++ )
+      delete bcnames[i];
+    for (int i=0; i<materials.Size(); i++)
+      delete materials[i];
+  }
+
+
+  void SplineGeometry2d :: Load (const char * filename)
+  {
+
+    ifstream infile;
+    Point<2> x;
+    char buf[50];
+
+
+    infile.open (filename);
+  
+    if ( ! infile.good() )
+      throw NgException(string ("Input file '") + 
+			string (filename) +
+			string ("' not available!"));
+
+    TestComment ( infile );
+  
+    infile >> buf;   // file recognition
+
+    tensormeshing.SetSize(0);
+    quadmeshing.SetSize(0);
+
+    TestComment ( infile );
+    if ( strcmp (buf, "splinecurves2dnew") == 0 )
+      {
+	LoadDataNew ( infile );
+      }
+    else if ( strcmp (buf, "splinecurves2dv2") == 0 )
+      {
+	LoadDataV2 ( infile );
+      }
+    else
+      {
+	LoadData(infile );
+      }
+    infile.close();
+  }
+
+
+
+  // herbert: fixed TestComment
+  void SplineGeometry2d :: TestComment ( ifstream & infile )
+  {
+    bool comment = true;
+    char ch;
+    while ( comment == true && !infile.eof() ) {
+      infile.get(ch);
+      if ( ch == '#' ) { // skip comments
+	while (  ch != '\n' && !infile.eof() ) {
+	  infile.get(ch);
+	}
+      }
+      else if ( ch == '\n' )  { // skip empty lines
+	;
+      }
+      else if ( isspace(ch) ) { // skip whitespaces
+	; 
+      }
+      else { // end of comment
+	infile.putback(ch);
+	comment = false;
+      }
+    }
+    return;
+  }
+
+
+
+
+  void SplineGeometry2d :: LoadData ( ifstream & infile )
+  {      
+    enum { D = 2 };
+
+    int nump, numseg, leftdom, rightdom;
+    Point<D> x;
+    int hi1, hi2, hi3;
+    double hd;
+    char buf[50], ch;
+
+    materials.SetSize(0);
+    maxh.SetSize(0);
+    infile >> elto0;
+
+    TestComment ( infile );
+
+    infile >> nump;
+    for (int i = 0; i < nump; i++)
+      {
+	TestComment ( infile );
+	for(int j=0; j<D; j++)
+	  infile >> x(j);
+	infile >> hd;
+
+	Flags flags;
+
+	ch = 'a';
+	// infile >> ch;
+	do {
+	  infile.get (ch);
+	} while (isspace(ch) && ch != '\n');
+	while (ch == '-')
+	  {
+	    char flag[100];
+	    flag[0]='-';
+	    infile >> (flag+1);
+	    flags.SetCommandLineFlag (flag);
+	    ch = 'a';
+	    do {
+	      infile.get (ch);
+	    } while (isspace(ch) && ch != '\n');
+	  }
+    
+	if (infile.good())
+	  infile.putback (ch);
+
+	geompoints.Append (GeomPoint<D>(x, hd));
+	geompoints.Last().hpref = flags.GetDefineFlag ("hpref");
+	geompoints.Last().hmax = 1e99;
+      }
+
+    PrintMessage (3, nump, " points loaded");
+    TestComment ( infile );
+
+    infile >> numseg;
+    bcnames.SetSize(numseg);
+    for ( int i = 0; i < numseg; i++ )
+      bcnames[i] = 0; // "default";
+
+    SplineSeg<D> * spline = 0;
+
+    PrintMessage (3, numseg, " segments loaded");
+    for (int i = 0; i < numseg; i++)
+      {
+	TestComment ( infile );
+      
+	infile >> leftdom >> rightdom;
+
+	// cout << "add spline " << i << ", left = " << leftdom << ", right = " << rightdom << endl;
+      
+	infile >> buf;
+	// type of spline segement
+	if (strcmp (buf, "2") == 0)
+	  { // a line
+	    infile >> hi1 >> hi2;
+	    spline = new LineSeg<D>(geompoints[hi1-1],
+				    geompoints[hi2-1]);
+	  }
+	else if (strcmp (buf, "3") == 0)
+	  { // a rational spline
+	    infile >> hi1 >> hi2 >> hi3;
+	    spline = new SplineSeg3<D> (geompoints[hi1-1],
+					geompoints[hi2-1],
+					geompoints[hi3-1]);
+	  }
+	else if (strcmp (buf, "4") == 0)
+	  { // an arc
+	    infile >> hi1 >> hi2 >> hi3;
+	    spline = new CircleSeg<D> (geompoints[hi1-1],
+				       geompoints[hi2-1],
+				       geompoints[hi3-1]);
+	    // 	  break;
+	  }
+	else if (strcmp (buf, "discretepoints") == 0)
+	  {
+	    int npts;
+	    infile >> npts;
+	    Array< Point<D> > pts(npts);
+	    for (int j = 0; j < npts; j++)
+	      for(int k=0; k<D; k++)
+		infile >> pts[j](k);
+
+	    spline = new DiscretePointsSeg<D> (pts);
+	  }
+    
+
+	SplineSegExt * spex = new SplineSegExt (*spline);
+	
+	infile >> spex->reffak;
+	spex -> leftdom = leftdom;
+	spex -> rightdom = rightdom;
+	spex -> hmax = 1e99;
+	splines.Append (spex);
+
+
+	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);
+    
+	spex->bc = int (flags.GetNumFlag ("bc", i+1));
+	spex->hpref_left = int (flags.GetDefineFlag ("hpref")) || 
+	  int (flags.GetDefineFlag ("hprefleft"));
+	spex->hpref_right = int (flags.GetDefineFlag ("hpref")) || 
+	  int (flags.GetDefineFlag ("hprefright"));
+	spex->copyfrom = int (flags.GetNumFlag ("copy", -1));
+	if ( flags.StringFlagDefined("bcname") )
+	  {
+	    int mybc = spex->bc-1;
+	    delete bcnames[mybc];
+	    bcnames[mybc] = new string (flags.GetStringFlag("bcname","") );
+	  }
+      }
+  }
+
+
+
+
+  void SplineGeometry2d :: LoadDataNew ( ifstream & infile )
+  {
+    enum { D = 2 };
+    int nump, numseg, leftdom, rightdom;
+    Point<D> x;
+    int hi1, hi2, hi3;
+    double hd;
+    char buf[50], ch;
+    int pointnr;
+
+
+    TestComment ( infile );
+    infile >> elto0;
+    TestComment ( infile );
+      
+    infile >> nump;
+    geompoints.SetSize(nump);
+      
+    for (int i = 0; i < nump; i++)
+      {
+	TestComment ( infile );
+	infile >> pointnr;
+	if ( pointnr > nump )
+	  {
+	    throw NgException(string ("Point number greater than total number of points") );
+	  }
+	for(int j=0; j<D; j++)
+	  infile >> x(j);
+
+
+	// hd is now optional, default 1
+	//  infile >> hd;
+	hd = 1;
+
+	Flags flags;
+
+
+	// get flags, 
+	ch = 'a';
+	// infile >> ch;
+	do 
+	  {
+
+	    infile.get (ch);
+	    // if another int-value, set refinement flag to this value
+	    // (corresponding to old files)
+	    if ( int (ch) >= 48 && int(ch) <= 57 )
+	      {
+		infile.putback(ch);
+		infile >> hd;
+		infile.get(ch);
+	      }
+	  } 
+	while (isspace(ch) && ch != '\n');
+	while (ch == '-')
+	  {
+	    char flag[100];
+	    flag[0]='-';
+	    infile >> (flag+1);
+	    flags.SetCommandLineFlag (flag);
+	    ch = 'a';
+	    do {
+	      infile.get (ch);
+	    } while (isspace(ch) && ch != '\n');
+	  }
+    
+	if (infile.good())
+	  infile.putback (ch);
+
+	if ( hd == 1 )
+	  hd = flags.GetNumFlag ( "ref", 1.0);
+	//       geompoints.Append (GeomPoint<D>(x, hd));
+	geompoints[pointnr-1] = GeomPoint<D>(x, hd);
+	geompoints[pointnr-1].hpref = flags.GetDefineFlag ("hpref");
+      }
+
+    TestComment ( infile );
+
+    infile >> numseg;
+    bcnames.SetSize(numseg);
+    for ( int i = 0; i < numseg; i++ )
+      bcnames[i] = 0;//new"default";
+
+    SplineSeg<D> * spline = 0;
+    for (int i = 0; i < numseg; i++)
+      {
+	TestComment ( infile );
+      
+	infile >> leftdom >> rightdom;
+
+	// cout << "add spline " << i << ", left = " << leftdom << endl;
+
+	infile >> buf;
+	// type of spline segement
+	if (strcmp (buf, "2") == 0)
+	  { // a line
+	    infile >> hi1 >> hi2;
+	    spline = new LineSeg<D> (geompoints[hi1-1],
+				     geompoints[hi2-1]);
+	  }
+	else if (strcmp (buf, "3") == 0)
+	  { // a rational spline
+	    infile >> hi1 >> hi2 >> hi3;
+	    spline = new SplineSeg3<D> (geompoints[hi1-1],
+					geompoints[hi2-1],
+					geompoints[hi3-1]);
+	  }
+	else if (strcmp (buf, "4") == 0)
+	  { // an arc
+	    infile >> hi1 >> hi2 >> hi3;
+	    spline = new CircleSeg<D> (geompoints[hi1-1],
+				       geompoints[hi2-1],
+				       geompoints[hi3-1]);
+	    // 	  break;
+	  }
+	else if (strcmp (buf, "discretepoints") == 0)
+	  {
+	    int npts;
+	    infile >> npts;
+	    Array< Point<D> > pts(npts);
+	    for (int j = 0; j < npts; j++)
+	      for(int k=0; k<D; k++)
+		infile >> pts[j](k);
+
+	    spline = new DiscretePointsSeg<D> (pts);
+	  }
+    
+	//      infile >> spline->reffak;
+
+	SplineSegExt * spex = new SplineSegExt (*spline);
+
+	spex -> leftdom = leftdom;
+	spex -> rightdom = rightdom;
+	splines.Append (spex);
+
+	// hd is now optional, default 1
+	//  infile >> hd;
+	hd = 1;
+	infile >> ch;
+      
+	// get refinement parameter, if it is there
+	// infile.get (ch);
+	// if another int-value, set refinement flag to this value
+	// (corresponding to old files)
+	if ( int (ch) >= 48 && int(ch) <= 57 )
+	  {
+	    infile.putback(ch);
+	    infile >> hd;
+	    infile >> ch ;
+	  }
+      
+	Flags flags;
+	while (ch == '-')
+	  {
+	    char flag[100];
+	    flag[0]='-';
+	    infile >> (flag+1);
+	    flags.SetCommandLineFlag (flag);
+	    ch = 'a';
+	    infile >> ch;
+	  }
+    
+	if (infile.good())
+	  infile.putback (ch);
+    
+	spex->bc = int (flags.GetNumFlag ("bc", i+1));
+	spex->hpref_left = int (flags.GetDefineFlag ("hpref")) || 
+	  int (flags.GetDefineFlag ("hprefleft"));
+	spex->hpref_right = int (flags.GetDefineFlag ("hpref")) || 
+	  int (flags.GetDefineFlag ("hprefright"));
+	spex->copyfrom = int (flags.GetNumFlag ("copy", -1));
+	spex->reffak = flags.GetNumFlag ("ref", 1 );
+	spex->hmax = flags.GetNumFlag ("maxh", 1e99 );
+
+	if ( flags.StringFlagDefined("bcname") )
+	  {
+	    int mybc = spex->bc-1;
+	    if ( bcnames[mybc] ) delete bcnames[mybc];
+	    bcnames[mybc] = new string (flags.GetStringFlag("bcname","") );
+	  }
+
+	if ( hd != 1 )
+	  spex->reffak = hd;
+      }
+    if ( !infile.good() )
+      return;
+    TestComment ( infile );
+    int numdomains;
+    int domainnr;
+    char material[100];
+
+    if ( !infile.good() ) 
+      return;
+
+    infile >> numdomains;
+    materials.SetSize(numdomains) ;
+    maxh.SetSize ( numdomains ) ;
+    for ( int i = 0; i < numdomains; i++)
+      maxh[i] = 1000;
+
+    TestComment ( infile );
+
+    for ( int i=0; i<numdomains; i++)
+      materials [ i ] = new char (100);
+
+    for ( int i=0; i<numdomains && infile.good(); i++)
+      {
+	TestComment ( infile );
+	infile >> domainnr;
+	infile >> material;
+	strcpy(materials[domainnr-1], material);
+
+	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);
+	 
+	maxh[domainnr-1] = flags.GetNumFlag ( "maxh", 1000);
+      }
+    return;
+  }
+
+
+
+
+  void SplineGeometry2d :: LoadDataV2 ( ifstream & infile )
+  { 
+    enum { D = 2 };
+    // new parser by Astrid Sinwel
+    
+    PrintMessage (1, "Load 2D Geometry V2");
+    int nump, leftdom, rightdom;
+    Point<D> x;
+    int hi1, hi2, hi3;
+    double hd;
+    char buf[50], ch;
+    int pointnr;
+
+    string keyword;
+
+    Array < GeomPoint<D> > infilepoints (0);
+    Array <int> pointnrs (0);
+    nump = 0;
+    int numdomains = 0;
+
+
+    TestComment ( infile );
+    // refinement factor
+    infile >> elto0;
+    TestComment ( infile );
+      
+
+    // test if next ch is a letter, i.e. new keyword starts
+    bool ischar = false;
+
+    while ( infile.good() )
+      {
+	infile >> keyword;
+
+	ischar = false;
+
+	if ( keyword == "points" )
+	  {
+	    PrintMessage (3, "load points");
+	    infile.get(ch);
+	    infile.putback(ch);
+
+	    // test if ch is a letter
+	    if ( int(ch) >= 65 && int(ch) <=90 )
+	      ischar = true;
+	    if ( int(ch) >= 97 && int(ch) <= 122 )
+	      ischar = true;
+
+	    while ( ! ischar )
+	      {
+		TestComment ( infile );
+		infile >> pointnr;
+		// pointnrs 1-based
+		if ( pointnr > nump ) nump = pointnr; 
+		pointnrs.Append(pointnr);
+	      
+		for(int j=0; j<D; j++)
+		  infile >> x(j);
+		// hd is now optional, default 1
+		//  infile >> hd;
+		hd = 1;
+	      
+		Flags flags;
+	      
+	      
+		// get flags, 
+		ch = 'a';
+		// infile >> ch;
+		do 
+		  {
+		    infile.get (ch);
+		    // if another int-value, set refinement flag to this value
+		    // (corresponding to old files)
+		    if ( int (ch) >= 48 && int(ch) <= 57 )
+		      {
+			infile.putback(ch);
+			infile >> hd;
+			infile.get(ch);
+		      }
+		  } 
+		while (isspace(ch) && ch != '\n');
+		while (ch == '-')
+		  {
+		    char flag[100];
+		    flag[0]='-';
+		    infile >> (flag+1);
+		    flags.SetCommandLineFlag (flag);
+		    ch = 'a';
+		    do {
+		      infile.get (ch);
+		    } while (isspace(ch) && ch != '\n');
+		  }
+		if (infile.good())
+		  infile.putback (ch);
+	      
+		if ( hd == 1 )
+		  hd = flags.GetNumFlag ( "ref", 1.0);
+		//       geompoints.Append (GeomPoint<D>(x, hd));
+
+		infilepoints.Append ( GeomPoint<D>(x, hd) );
+		infilepoints.Last().hpref = flags.GetDefineFlag ("hpref");
+		infilepoints.Last().hmax = flags.GetNumFlag ("maxh", 1e99);
+
+		TestComment(infile);
+		infile.get(ch);
+		infile.putback(ch);
+
+		// test if letter
+		if ( int(ch) >= 65 && int(ch) <=90 )
+		  ischar = true;
+		if ( int(ch) >= 97 && int(ch) <= 122 )
+		  ischar = true;
+	      }
+
+	    //	  infile.putback (ch);
+
+	    geompoints.SetSize(nump);
+	    for ( int i = 0; i < nump; i++ )
+	      {
+		geompoints[pointnrs[i] - 1] = infilepoints[i];
+		geompoints[pointnrs[i] - 1].hpref = infilepoints[i].hpref; 
+	      }
+	    TestComment(infile);
+	  }
+
+	else if ( keyword == "segments" )
+	  {
+	    PrintMessage (3, "load segments");
+
+	    bcnames.SetSize(0);
+	    infile.get(ch);
+	    infile.putback(ch);
+	    int i = 0;
+
+	    // test if ch is a letter
+	    if ( int(ch) >= 65 && int(ch) <=90 )
+	      ischar = true;
+	    if ( int(ch) >= 97 && int(ch) <= 122 )
+	      ischar = true;
+
+	    while ( !ischar ) //ch != 'p' && ch != 'm' )
+	      {
+		i++;
+		TestComment ( infile );
+
+		SplineSeg<D> * spline = 0;
+		TestComment ( infile );
+		  
+		infile >> leftdom >> rightdom;
+	      
+		if ( leftdom > numdomains ) numdomains = leftdom;
+		if ( rightdom > numdomains ) numdomains = rightdom;
+
+	      
+		infile >> buf;
+		// type of spline segement
+		if (strcmp (buf, "2") == 0)
+		  { // a line
+		    infile >> hi1 >> hi2;
+		    spline = new LineSeg<D>(geompoints[hi1-1],
+					    geompoints[hi2-1]);
+		  }
+		else if (strcmp (buf, "3") == 0)
+		  { // a rational spline
+		    infile >> hi1 >> hi2 >> hi3;
+		    spline = new SplineSeg3<D> (geompoints[hi1-1],
+						geompoints[hi2-1],
+						geompoints[hi3-1]);
+		  }
+		else if (strcmp (buf, "4") == 0)
+		  { // an arc
+		    infile >> hi1 >> hi2 >> hi3;
+		    spline = new CircleSeg<D> (geompoints[hi1-1],
+					       geompoints[hi2-1],
+					       geompoints[hi3-1]);
+		  }
+		else if (strcmp (buf, "discretepoints") == 0)
+		  {
+		    int npts;
+		    infile >> npts;
+		    Array< Point<D> > pts(npts);
+		    for (int j = 0; j < npts; j++)
+		      for(int k=0; k<D; k++)
+			infile >> pts[j](k);
+		  
+		    spline = new DiscretePointsSeg<D> (pts);
+		  }
+		else if (strcmp (buf, "bsplinepoints") == 0)
+		  {
+		    int npts,order;
+		    infile >> npts;    
+		    infile >> order;
+		    Array< Point<D> > pts(npts);
+		    for (int j = 0; j < npts; j++)
+		      for(int k=0; k<D; k++)
+			infile >> pts[j](k);	    		    
+		    if(order<2)		      
+			cerr<<"Minimum order of 2 is required!!"<<endl;
+		    else if(order==2)
+		      spline = new BSplineSeg<D,2> (pts);
+		      else if(order==3)
+			spline = new BSplineSeg<D,3> (pts);
+		      else if(order==4)
+			spline = new BSplineSeg<D,4> (pts);
+		      else if(order>4)		      
+			cerr<<"Maximum allowed order is 4!!"<<endl;
+		  }
+	      
+		//      infile >> spline->reffak;
+		SplineSegExt * spex = new SplineSegExt (*spline);
+
+		spex -> leftdom = leftdom;
+		spex -> rightdom = rightdom;
+		splines.Append (spex);
+	      
+	      
+		// hd is now optional, default 1
+		//  infile >> hd;
+		hd = 1;
+		infile >> ch;
+	      
+		// get refinement parameter, if it is there
+		//infile.get (ch);
+		// if another int-value, set refinement flag to this value
+		// (corresponding to old files)
+
+		if ( int (ch) >= 48 && int(ch) <= 57 )
+		  {
+		    infile.putback(ch);
+		    infile >> hd;
+		    infile >> ch ;
+		  }
+
+		// get flags, 
+		Flags flags;
+		while (ch == '-')
+		  {
+		    char flag[100];
+		    flag[0]='-';
+		    infile >> (flag+1);
+		    flags.SetCommandLineFlag (flag);
+		    ch = 'a';
+		    infile >> ch;
+		  }
+	      
+		if (infile.good())
+		  infile.putback (ch);
+	      
+		spex->bc = int (flags.GetNumFlag ("bc", i+1));
+		spex->hpref_left = int (flags.GetDefineFlag ("hpref")) || 
+		  int (flags.GetDefineFlag ("hprefleft"));
+		spex->hpref_right = int (flags.GetDefineFlag ("hpref")) || 
+		  int (flags.GetDefineFlag ("hprefright"));
+		spex->copyfrom = int (flags.GetNumFlag ("copy", -1));
+		spex->reffak = flags.GetNumFlag ("ref", 1 );
+		spex->hmax = flags.GetNumFlag ("maxh", 1e99 );
+		if ( hd != 1 ) spex->reffak = hd;
+
+		if ( flags.StringFlagDefined("bcname") )
+		  {
+		    int mybc = spex->bc-1;
+		    for ( int ii = bcnames.Size(); ii <= mybc; ii++ )
+		      bcnames.Append ( new string ("default"));
+		    if ( bcnames[mybc] ) delete bcnames[mybc];
+		    bcnames[mybc] = new string (flags.GetStringFlag("bcname","") );
+		  }
+
+		TestComment(infile);
+		infile.get(ch);
+		infile.putback(ch);
+
+		// test if ch is a letter
+		if ( int(ch) >= 65 && int(ch) <=90 )
+		  ischar = true;
+		if ( int(ch) >= 97 && int(ch) <= 122 )
+		  ischar = true;
+
+	      }
+	  
+	    infile.get(ch);
+	    infile.putback(ch);
+	
+
+	  }
+	else if ( keyword == "materials" )
+	  {
+	    TestComment ( infile );
+	    int domainnr;
+	    char material[100];
+	  
+	    if ( !infile.good() ) 
+	      return;
+	  
+	    materials.SetSize(numdomains) ;
+	    maxh.SetSize ( numdomains ) ;
+	    for ( int i = 0; i < numdomains; i++)
+	      maxh[i] = 1000;
+	    quadmeshing.SetSize ( numdomains );
+	    quadmeshing = false;
+	    tensormeshing.SetSize ( numdomains );
+	    tensormeshing = false;
+	    layer.SetSize ( numdomains );
+	    layer = 1;
+
+	  
+	    TestComment ( infile );
+	  
+	    for ( int i=0; i<numdomains; i++)
+	      materials [ i ] = new char[100];
+	  
+	    for ( int i=0; i<numdomains && infile.good(); i++)
+	      {
+		TestComment ( infile );
+		infile >> domainnr;
+		infile >> material;
+
+		strcpy (materials[domainnr-1], material);
+	      
+		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);
+	      
+		maxh[domainnr-1] = flags.GetNumFlag ( "maxh", 1000);
+		if (flags.GetDefineFlag("quad")) quadmeshing[domainnr-1] = true;
+		if (flags.GetDefineFlag("tensor")) tensormeshing[domainnr-1] = true;
+		layer[domainnr-1] = int(flags.GetNumFlag ("layer", 1));
+	      }
+	  }
+      }
+    return;
+  }
+
+
+
+
+
+
+
+
+
+
+
+
+  void CalcPartition (double l, double h, double h1, double h2,
+		      double hcurve, double elto0, Array<double> & points)
+  {
+    // cout << "calcpart, h = " << h << ", h1 = " << h1 << ", h2 = " << h2 << ", hcurve = " << hcurve << endl;
+    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 (hcurve, t/elto0 + h1, (l-t)/elto0 + h2);
+	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 (hcurve, t/elto0 + h1, (l-t)/elto0 + h2);
+
+	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);
+  }
+
+
+
+  string SplineGeometry2d :: GetBCName( const int  bcnr ) const
+  {
+    if ( bcnames.Size() >= bcnr)
+      if (bcnames[bcnr-1] )
+	return *bcnames[bcnr-1];
+    return "default";
+  }
+
+  string * SplineGeometry2d :: BCNamePtr( const int bcnr ) 
+  {
+    if ( bcnr > bcnames.Size() )
+      return 0;
+    else
+      return bcnames[bcnr-1];
+  }
+
+
+
+
+
+  void SplineGeometry2d :: GetMaterial( const int  domnr, char* & material )
+  {
+    if ( materials.Size() >= domnr)
+      material =  materials[domnr-1];
+    else 
+      material = 0;
+  }
+
+
+  double SplineGeometry2d :: GetDomainMaxh( const int  domnr )
+  {
+    if ( maxh.Size() >= domnr  && domnr > 0)
+      return maxh[domnr-1];
+    else
+      return -1;
+  }
+
+
+
+  extern void MeshFromSpline2D (SplineGeometry2d & geometry,
+				Mesh *& mesh, 
+				MeshingParameters & mp);
+
+
+  int SplineGeometry2d :: GenerateMesh (Mesh*& mesh, MeshingParameters & mparam,
+					int perfstepsstart, int perfstepsend)
+  {
+    MeshFromSpline2D (*this, mesh, mparam);
+    return 0;
+  }
+
+
+  Refinement & SplineGeometry2d :: GetRefinement () const
+  {
+    return * new Refinement2d (*this);
+  }
+
+}
diff --git a/contrib/Netgen/libsrc/geom2d/geometry2d.hpp b/contrib/Netgen/libsrc/geom2d/geometry2d.hpp
new file mode 100644
index 0000000000..ef0bd015f5
--- /dev/null
+++ b/contrib/Netgen/libsrc/geom2d/geometry2d.hpp
@@ -0,0 +1,184 @@
+#ifndef FILE_GEOMETRY2D
+#define FILE_GEOMETRY2D
+
+/* *************************************************************************/
+/* File:   geometry2d.hpp                                                  */
+/* Author: Joachim Schoeberl                                               */
+/* Date:   20. Jul. 02                                                     */
+/* *************************************************************************/
+
+#include <myadt.hpp>
+#include <gprim.hpp>
+
+
+// #include "../gprim/spline.hpp"
+// #include "../gprim/splinegeometry.hpp"
+#include "geom2dmesh.hpp"
+
+namespace netgen
+{
+
+  class SplineSegExt : public SplineSeg<2>
+  {
+  public:
+    const SplineSeg<2> & seg;
+    
+    /// left domain
+    int leftdom;
+    /// right domain
+    int rightdom;
+    /// refinement at line
+    double reffak;
+    /// maximal h;
+    double hmax;
+    /// boundary condition number
+    int bc;
+    /// copy spline mesh from other spline (-1.. do not copy)
+    int copyfrom;
+    /// perfrom anisotropic refinement (hp-refinement) to edge
+    bool hpref_left;
+    /// perfrom anisotropic refinement (hp-refinement) to edge
+    bool hpref_right;
+    ///
+    int layer;
+
+    SplineSegExt (const SplineSeg<2> & hseg) 
+      : seg(hseg)
+    {
+      layer = 1;
+    }
+
+    
+    virtual const GeomPoint<2> & StartPI () const 
+    { 
+      return seg.StartPI(); 
+    }
+
+    virtual const GeomPoint<2> & EndPI () const 
+    {
+      return seg.EndPI();
+    }
+
+    virtual Point<2> GetPoint (double t) const 
+    {
+      return seg.GetPoint(t);
+    }
+
+    virtual Vec<2> GetTangent (const double t) const
+    {
+      return seg.GetTangent(t);
+    }
+
+    virtual void GetDerivatives (const double t,  
+				 Point<2> & point,
+				 Vec<2> & first,
+				 Vec<2> & second) const
+    {
+      seg.GetDerivatives (t, point, first, second);
+    }
+
+    virtual void GetCoeff (Vector & coeffs) const 
+    {
+      seg.GetCoeff (coeffs);
+    }
+
+    virtual void GetPoints (int n, Array<Point<2> > & points) const
+    {
+      seg.GetPoints (n, points);
+    }
+
+    virtual double MaxCurvature () const 
+    {
+      return seg.MaxCurvature();
+    }
+
+    virtual string GetType () const
+    {
+      return seg.GetType();
+    }
+
+  };
+
+
+
+
+  class SplineGeometry2d : public SplineGeometry<2>, public NetgenGeometry
+  {
+  protected:
+    Array<char*> materials;
+    Array<double> maxh;
+    Array<bool> quadmeshing;
+    Array<bool> tensormeshing;
+    Array<int> layer;
+    Array<string*> bcnames;
+    double elto0;
+
+
+  public:
+    DLL_HEADER virtual ~SplineGeometry2d();
+
+    DLL_HEADER void Load (const char * filename);
+
+    DLL_HEADER void LoadData( ifstream & infile );
+    DLL_HEADER void LoadDataNew ( ifstream & infile );
+    DLL_HEADER void LoadDataV2 ( ifstream & infile );
+
+    void TestComment ( ifstream & infile ) ;
+
+    
+
+    const SplineSegExt & GetSpline (const int i) const 
+    { 
+      return dynamic_cast<const SplineSegExt&> (*splines[i]);
+    }
+
+    SplineSegExt & GetSpline (const int i) 
+    { 
+      return dynamic_cast<SplineSegExt&> (*splines[i]);
+    }
+
+    
+    DLL_HEADER virtual int GenerateMesh (Mesh*& mesh, MeshingParameters & mparam,
+			      int perfstepsstart, int perfstepsend);
+    
+    void PartitionBoundary (double h, Mesh & mesh2d);
+
+    void CopyEdgeMesh (int from, int to, Mesh & mesh2d, Point3dTree & searchtree);
+
+
+    void GetMaterial( const int  domnr, char* & material );
+
+    double GetDomainMaxh ( const int domnr );
+    bool GetDomainQuadMeshing ( int domnr ) 
+    { 
+      if ( quadmeshing.Size() ) return quadmeshing[domnr-1]; 
+      else return false;
+    }
+    bool GetDomainTensorMeshing ( int domnr ) 
+    { 
+      if ( tensormeshing.Size() ) return tensormeshing[domnr-1]; 
+      else return false;
+    }
+    int GetDomainLayer ( int domnr ) 
+    { 
+      if ( layer.Size() ) return layer[domnr-1]; 
+      else return 1;
+    }
+
+
+    string GetBCName ( const int bcnr ) const;
+
+    string * BCNamePtr ( const int bcnr );
+
+    
+    DLL_HEADER virtual Refinement & GetRefinement () const; 
+  };
+}
+
+
+
+
+
+
+
+#endif
diff --git a/contrib/Netgen/libsrc/geom2d/spline2d.hpp b/contrib/Netgen/libsrc/geom2d/spline2d.hpp
new file mode 100644
index 0000000000..20affa49aa
--- /dev/null
+++ b/contrib/Netgen/libsrc/geom2d/spline2d.hpp
@@ -0,0 +1,234 @@
+
+
+
+
+das File sollte nicht mehr verwendet werden ---> spline.hpp
+
+
+
+
+
+
+
+#ifndef FILE_SPLINE2D
+#define FILE_SPLINE2D
+
+/**************************************************************************/
+/* File:   spline2d.hh                                                    */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   24. Jul. 96                                                    */
+/**************************************************************************/
+
+
+/*
+  Spline curves for 2D mesh generation
+  */
+
+#include "spline.hpp"
+
+
+//#define OLDSPLINEVERSION
+#ifdef OLDSPLINEVERSION
+
+/// Geometry point
+class GeomPoint2d : public Point<2>
+{
+public:
+  /// refinement to point
+  double refatpoint;
+  bool hpref;
+
+  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;
+  /// perfrom anisotropic refinement (hp-refinement) to edge
+  bool hpref_left;
+  bool hpref_right;
+  /// 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, Point3dTree & searchtree, 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 */
+  void PrintCoeff (ostream & ost) const;
+
+  virtual void GetCoeff (Vector & coeffs) const = 0;
+
+  virtual void GetPoints (int n, Array<Point<2> > & points);
+
+  /** calculates lineintersections:
+      for lines $$ a x + b y + c = 0 $$ the interecting points are calculated
+      and stored in points */
+  virtual void LineIntersections (const double a, const double b, const double c,
+				  Array < Point<2> > & points, const double eps) const
+  {points.SetSize(0);}
+
+  virtual double MaxCurvature(void) const = 0;
+
+  virtual string GetType(void) const {return "splinebase";}
+};
+
+
+/// 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;
+  virtual void GetCoeff (Vector & coeffs) const;
+
+  virtual string GetType(void) const {return "line";}
+
+  virtual void LineIntersections (const double a, const double b, const double c,
+				  Array < Point<2> > & points, const double eps) const;
+
+  virtual double MaxCurvature(void) const {return 0;}
+};
+
+
+/// 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;
+  virtual void GetCoeff (Vector & coeffs) const;
+
+  virtual string GetType(void) const {return "spline3";}
+
+  const GeomPoint2d & TangentPoint (void) const { return p2; }
+
+  virtual void LineIntersections (const double a, const double b, const double c,
+				  Array < Point<2> > & points, const double eps) const;
+
+  virtual double MaxCurvature(void) 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;
+  virtual void GetCoeff (Vector & coeffs) const;
+  ///
+  double Radius() const { return radius; }
+  ///
+  double StartAngle() const { return w1; }
+  ///
+  double EndAngle() const { return w3; }
+  ///
+  const Point<2> & MidPoint(void) const {return pm; }
+
+  virtual string GetType(void) const {return "circle";}
+
+  virtual void LineIntersections (const double a, const double b, const double c,
+				  Array < Point<2> > & points, const double eps) const;
+
+  virtual double MaxCurvature(void) const {return 1./radius;}
+};
+
+
+
+
+
+
+/// 
+class DiscretePointsSegment : public SplineSegment
+{
+  Array<Point<2> > pts;
+  GeomPoint2d p1, p2;
+public:
+  ///
+  DiscretePointsSegment (const Array<Point<2> > & apts);
+  ///
+  virtual ~DiscretePointsSegment ();
+  ///
+  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 { ; }
+  virtual void GetCoeff (Vector & coeffs) const {;}
+
+  virtual double MaxCurvature(void) const {return 1;}
+};
+
+
+#endif
+
+#endif
diff --git a/contrib/Netgen/libsrc/geom2d/splinegeometry2.hpp b/contrib/Netgen/libsrc/geom2d/splinegeometry2.hpp
new file mode 100644
index 0000000000..6b1428bedb
--- /dev/null
+++ b/contrib/Netgen/libsrc/geom2d/splinegeometry2.hpp
@@ -0,0 +1,103 @@
+
+
+OLD IMPLEMENTATION, NOT USED ANYMORE!
+
+
+
+
+#ifndef FILE_SPLINEGEOMETRY2
+#define FILE_SPLINEGEOMETRY2
+
+/**************************************************************************/
+/* File:   splinegeometry2.hpp                                            */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   24. Jul. 96                                                    */
+/**************************************************************************/
+
+#include "splinegeometry.hpp"
+
+#ifdef OLDSPLINEGEOMETRY
+
+
+/// 
+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 CSGScanner;
+
+class SplineGeometry2d
+{
+  Array<GeomPoint2d> geompoints;
+  Array<SplineSegment*> splines;
+  double elto0;
+
+
+private:
+  void AppendSegment(SplineSegment * spline, const int leftdomain, const int rightdomain,
+		     const int bc,
+		     const double reffac, const bool hprefleft, const bool hprefright,
+		     const int copyfrom);
+
+public:
+  ~SplineGeometry2d();
+
+  void Load (const char * filename);
+  void CSGLoad (CSGScanner & scan);
+  void PartitionBoundary (double h, Mesh & mesh2d);
+
+  void CopyEdgeMesh (int from, int to, Mesh & mesh2d, Point3dTree & searchtree);
+
+  const Array<SplineSegment*> & GetSplines () const
+  { return splines; }
+
+  int GetNSplines (void) const { return splines.Size(); }
+  string GetSplineType (const int i) const { return splines[i]->GetType(); }
+  SplineSegment & GetSpline (const int i) {return *splines[i];}
+  const SplineSegment & GetSpline (const int i) const {return *splines[i];}
+
+  void GetBoundingBox (Box<2> & box) const;
+
+  int GetNP () const { return geompoints.Size(); }
+  const GeomPoint2d & GetPoint(int i) const { return geompoints[i]; }
+
+  void SetGrading (const double grading);
+  void AppendPoint (const double x, const double y, const double reffac = 1., const bool hpref = false);
+  
+  void AppendLineSegment (const int n1, const int n2,
+			  const int leftdomain, const int rightdomain, const int bc = -1,
+			  const double reffac = 1.,
+			  const bool hprefleft = false, const bool hprefright = false,
+			  const int copyfrom = -1);
+  void AppendSplineSegment (const int n1, const int n2, const int n3,
+			    const int leftdomain, const int rightdomain, const int bc = -1,
+			    const double reffac = 1.,
+			    const bool hprefleft = false, const bool hprefright = false,
+			    const int copyfrom = -1);
+  void AppendCircleSegment (const int n1, const int n2, const int n3,
+			    const int leftdomain, const int rightdomain, const int bc = -1,
+			    const double reffac = 1.,
+			    const bool hprefleft = false, const bool hprefright = false,
+			    const int copyfrom = -1);
+  void AppendDiscretePointsSegment (const Array< Point<2> > & points, 
+				    const int leftdomain, const int rightdomain, const int bc = -1,
+				    const double reffac = 1.,
+				    const bool hprefleft = false, const bool hprefright = false,
+				    const int copyfrom = -1);
+  
+};
+
+
+void MeshFromSpline2D (SplineGeometry2d & geometry,
+		       Mesh *& mesh, 
+		       MeshingParameters & mp);
+
+#endif
+
+#endif
diff --git a/contrib/Netgen/libsrc/geom2d/vsgeom2d.cpp b/contrib/Netgen/libsrc/geom2d/vsgeom2d.cpp
new file mode 100644
index 0000000000..6d1081453a
--- /dev/null
+++ b/contrib/Netgen/libsrc/geom2d/vsgeom2d.cpp
@@ -0,0 +1,110 @@
+#include <meshing.hpp>
+#include <geometry2d.hpp>
+#include <visual.hpp>
+
+#include "vsgeom2d.hpp"
+
+namespace netgen
+{
+
+
+  /* *********************** Draw 2D Geometry **************** */
+
+
+  VisualSceneGeometry2d :: VisualSceneGeometry2d ()
+    : VisualScene()
+  {
+    ;
+  }
+
+  VisualSceneGeometry2d :: ~VisualSceneGeometry2d ()
+  {
+    ;
+  }
+
+
+
+  void VisualSceneGeometry2d :: DrawScene ()
+  {
+    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 (int i = 1; i <= geometry2d->GetSplines().Size(); i++)
+      {
+	geometry2d->GetSplines().Get(i)->GetPoints (20, points);
+      
+	glBegin (GL_LINE_STRIP);
+	for (int j = 0; j < points.Size(); j++)
+	  glVertex3d (points[j](0), points[j](1), 0);
+	glEnd(); 
+      }
+
+    glColor3f (1, 0, 0);
+
+    for (int i = 1; i <= geometry2d->GetSplines().Size(); i++)
+      {
+	int other = geometry2d->GetSpline(i-1).copyfrom;
+	if (other != -1)
+	  {
+	    geometry2d->GetSplines().Get(i)->GetPoints (6, points);
+	    geometry2d->GetSplines().Get(other)->GetPoints (6, otherpoints);
+	    glBegin (GL_LINES);
+	    for (int j = 1; j < 5; j++)
+	      {
+		glVertex3d (points[j](0), points[j](1), 0);
+		glVertex3d (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();
+  }
+}
diff --git a/contrib/Netgen/libsrc/geom2d/vsgeom2d.hpp b/contrib/Netgen/libsrc/geom2d/vsgeom2d.hpp
new file mode 100644
index 0000000000..ffb44711e1
--- /dev/null
+++ b/contrib/Netgen/libsrc/geom2d/vsgeom2d.hpp
@@ -0,0 +1,28 @@
+#ifndef FILE_VSGEOM2D
+#define FILE_VSGEOM2D
+
+/**************************************************************************/
+/* File:   vsgeom2d.hpp                                                   */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   05. Jan. 2011                                                  */
+/**************************************************************************/
+
+namespace netgen
+{
+
+  class VisualSceneGeometry2d : public VisualScene
+  {
+    const class SplineGeometry2d * geometry2d;
+  public:
+    VisualSceneGeometry2d ();
+    virtual ~VisualSceneGeometry2d ();
+    void SetGeometry (const class SplineGeometry2d * ageometry2d) { geometry2d = ageometry2d; }
+    virtual void BuildScene (int zoomall = 0);
+    virtual void DrawScene ();
+  };
+
+}
+
+
+
+#endif
diff --git a/contrib/Netgen/libsrc/gprim/Makefile.am b/contrib/Netgen/libsrc/gprim/Makefile.am
new file mode 100644
index 0000000000..7d60c42d85
--- /dev/null
+++ b/contrib/Netgen/libsrc/gprim/Makefile.am
@@ -0,0 +1,7 @@
+noinst_HEADERS = adtree.hpp  geom3d.hpp     geomobjects2.hpp  geomops2.hpp  geomtest3d.hpp  transform3d.hpp geom2d.hpp  geomfuncs.hpp  geomobjects.hpp   geomops.hpp   gprim.hpp spline.hpp splinegeometry.hpp
+
+AM_CPPFLAGS = -I$(top_srcdir)/libsrc/include
+METASOURCES = AUTO
+noinst_LTLIBRARIES = libgprim.la
+libgprim_la_SOURCES = adtree.cpp geom2d.cpp geom3d.cpp geomfuncs.cpp \
+	geomtest3d.cpp transform3d.cpp spline.cpp splinegeometry.cpp
diff --git a/contrib/Netgen/libsrc/gprim/adtree.cpp b/contrib/Netgen/libsrc/gprim/adtree.cpp
new file mode 100644
index 0000000000..592a6238c4
--- /dev/null
+++ b/contrib/Netgen/libsrc/gprim/adtree.cpp
@@ -0,0 +1,2165 @@
+#include <mystdlib.h>
+
+
+#include <myadt.hpp>
+// class DenseMatrix;
+#include <gprim.hpp>
+
+namespace netgen
+{
+
+
+  /* ******************************* ADTree ******************************* */
+
+
+  ADTreeNode :: ADTreeNode(int adim)
+  {
+    pi = -1;
+
+    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(NULL);
+    ADTreeNode *next;
+    int dir;
+    int lr(1);
+
+    float * bmin = new float [dim];
+    float * bmax = new float [dim];
+  
+    memcpy (bmin, cmin, dim * sizeof(float));
+    memcpy (bmax, cmax, dim * sizeof(float));
+
+
+    next = root;
+    dir = 0;
+    while (next)
+      {
+	node = next;
+
+	if (node->pi == -1)
+	  {    
+	    memcpy (node->data, p, dim * sizeof(float));
+	    node->pi = pi;
+
+	    if (ela.Size() < pi+1)
+	      ela.SetSize (pi+1);
+	    ela[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;
+      }
+
+
+    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+1)
+      ela.SetSize (pi+1);
+    ela[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[pi];
+
+    node->pi = -1;
+
+    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 -1;
+
+    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 != -1)
+	      return node->pi;
+	  }
+      }
+    while (stackindex > 0);
+
+    return -1;
+  }
+
+
+  void ADTree :: GetMatch (Array <int> & matches)
+  {
+    int nodenr;
+
+    Reset();
+
+    while ( (nodenr = Next()) != -1)
+      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 = -1;
+
+    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)
+  {
+    return ball.Alloc();
+  }
+
+  void ADTreeNode3 :: operator delete (void * p)
+  {
+    ball.Free (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(NULL);
+    ADTreeNode3 *next;
+    int dir;
+    int lr(0);
+
+    float bmin[3];
+    float bmax[3];
+  
+    memcpy (bmin, cmin, 3 * sizeof(float));
+    memcpy (bmax, cmax, 3 * sizeof(float));
+
+    next = root;
+    dir = 0;
+    while (next)
+      {
+	node = next;
+
+	if (node->pi == -1)
+	  {    
+	    memcpy (node->data, p, 3 * sizeof(float));
+	    node->pi = pi;
+
+	    if (ela.Size() < pi+1)
+	      ela.SetSize (pi+1);
+	    ela[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;
+      }
+
+
+    next = new ADTreeNode3;
+    memcpy (next->data, p, 3 * sizeof(float));
+    next->pi = pi;
+    next->sep = (bmin[dir] + bmax[dir]) / 2;
+
+
+    if (ela.Size() < pi+1)
+      ela.SetSize (pi+1);
+    ela[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[pi];
+
+    node->pi = -1;
+
+    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, 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 != -1)
+	  {
+	    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);
+  }
+
+
+
+
+
+
+
+
+#ifdef ABC
+
+  /* ******************************* 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));
+
+
+    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;
+      }
+
+
+    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));
+
+    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;
+      }
+
+
+    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));
+
+
+    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));
+
+    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]);
+  }
+
+
+
+
+#endif
+
+
+
+
+
+
+  /* ******************************* ADTree6 ******************************* */
+
+
+  ADTreeNode6 :: ADTreeNode6()
+  {
+    pi = -1;
+
+    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 s)
+  {
+    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(NULL);
+    ADTreeNode6 *next;
+    int dir;
+    int lr(0);
+
+    float bmin[6];
+    float bmax[6];
+
+  
+    memcpy (bmin, cmin, 6 * sizeof(float));
+    memcpy (bmax, cmax, 6 * sizeof(float));
+
+    next = root;
+    dir = 0;
+    while (next)
+      {
+	node = next;
+
+	if (node->pi == -1)
+	  {    
+	    memcpy (node->data, p, 6 * sizeof(float));
+	    node->pi = pi;
+
+	    if (ela.Size() < pi+1)
+	      ela.SetSize (pi+1);
+	    ela[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;
+      }
+
+
+    next = new ADTreeNode6;
+    memcpy (next->data, p, 6 * sizeof(float));
+    next->pi = pi;
+    next->sep = (bmin[dir] + bmax[dir]) / 2;
+
+    if (ela.Size() < pi+1)
+      ela.SetSize (pi+1);
+    ela[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[pi];
+
+    node->pi = -1;
+
+    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);
+
+    stack.SetSize (10000);
+    pis.SetSize(0);
+
+    stack[0].node = root;
+    stack[0].dir = 0;
+    int stacks = 0;
+
+    while (stacks >= 0)
+      {
+	ADTreeNode6 * node = stack[stacks].node;
+	int dir = stack[stacks].dir; 
+
+	stacks--;
+
+	if (node->pi != -1)
+	  {
+	    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) % 6;
+
+	if (node->left && bmin[dir] <= node->sep)
+	  {
+	    stacks++;
+	    stack[stacks].node = node->left;
+	    stack[stacks].dir = ndir;
+	  }
+	if (node->right && bmax[dir] >= node->sep)
+	  {
+	    stacks++;
+	    stack[stacks].node = node->right;
+	    stack[stacks].dir = 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;
+  }
+
+
+
+
+
+
+#ifdef ABC
+
+  /* ******************************* 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));
+
+    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]);
+  }
+
+
+
+#endif
+
+
+
+  /* ************************************* Point3dTree ********************** */
+
+
+
+  Point3dTree :: Point3dTree (const Point<3> & pmin, const Point<3> & pmax)
+  {
+    float pmi[3], pma[3];
+    for (int i = 0; i < 3; i++)
+      {
+	pmi[i] = pmin(i);
+	pma[i] = pmax(i);
+      }
+    tree = new ADTree3 (pmi, pma);
+  }
+
+  Point3dTree :: ~Point3dTree ()
+  {
+    delete tree;
+  }
+
+
+
+  void Point3dTree :: Insert (const Point<3> & p, int pi)
+  {
+    float pd[3];
+    pd[0] = p(0);
+    pd[1] = p(1);
+    pd[2] = p(2);
+    tree->Insert (pd, pi);
+  }
+
+  void Point3dTree :: GetIntersecting (const Point<3> & pmin, const Point<3> & pmax, 
+				       Array<int> & pis) const
+  {
+    float pmi[3], pma[3];
+    for (int i = 0; i < 3; i++)
+      {
+	pmi[i] = pmin(i);
+	pma[i] = pmax(i);
+      }
+    tree->GetIntersecting (pmi, pma, pis);
+  }
+
+
+
+
+
+
+
+
+
+
+  Box3dTree :: Box3dTree (const Point<3> & apmin, const Point<3> & apmax)
+  {
+    boxpmin = apmin;
+    boxpmax = apmax;
+    float tpmin[6], tpmax[6];
+    for (int i = 0; i < 3; i++)
+      {
+	tpmin[i] = tpmin[i+3] = boxpmin(i);
+	tpmax[i] = tpmax[i+3] = boxpmax(i);
+      }
+    tree = new ADTree6 (tpmin, tpmax);
+  }
+
+  Box3dTree :: ~Box3dTree ()
+  {
+    delete tree;
+  }
+
+  void Box3dTree :: Insert (const Point<3> & bmin, const Point<3> & bmax, int pi)
+  {
+    float tp[6];
+
+    for (int i = 0; i < 3; i++)
+      {
+	tp[i] = bmin(i);
+	tp[i+3] = bmax(i);
+      }
+
+    tree->Insert (tp, pi);
+  }
+
+  void Box3dTree ::GetIntersecting (const Point<3> & pmin, const Point<3> & pmax, 
+				    Array<int> & pis) const
+  {
+    float tpmin[6];
+    float tpmax[6];
+
+    for (int i = 0; i < 3; i++)
+      {
+	tpmin[i] = boxpmin(i);
+	tpmax[i] = pmax(i);
+      
+	tpmin[i+3] = pmin(i);
+	tpmax[i+3] = boxpmax(i);
+      }
+
+    tree->GetIntersecting (tpmin, tpmax, pis);
+  }
+
+}
diff --git a/contrib/Netgen/libsrc/gprim/adtree.hpp b/contrib/Netgen/libsrc/gprim/adtree.hpp
new file mode 100644
index 0000000000..d0f02b6dee
--- /dev/null
+++ b/contrib/Netgen/libsrc/gprim/adtree.hpp
@@ -0,0 +1,486 @@
+#ifndef FILE_ADTREE
+#define FILE_ADTREE
+
+/* *************************************************************************/
+/* File:   adtree.hh                                                       */
+/* Author: Joachim Schoeberl                                               */
+/* Date:   16. Feb. 98                                                     */
+/* Redesigned by Wolfram Muehlhuber, May 1998                              */
+/* *************************************************************************/
+
+
+namespace netgen
+{
+
+/**
+  Alternating Digital Tree
+ */
+
+// #include "../include/mystdlib.h"
+// #include "../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:
+  DLL_HEADER Point3dTree (const Point<3> & pmin, const Point<3> & pmax);
+  DLL_HEADER ~Point3dTree ();
+  DLL_HEADER void Insert (const Point<3> & p, int pi);
+  void DeleteElement (int pi) 
+    { tree->DeleteElement(pi); }
+  DLL_HEADER void GetIntersecting (const Point<3> & pmin, const Point<3> & pmax, 
+			Array<int> & pis) const;
+  const ADTree3 & Tree() const { return *tree; };
+};
+
+
+
+class Box3dTree
+{
+  ADTree6 * tree;
+  Point<3> boxpmin, boxpmax;
+public:
+  Box3dTree (const Point<3> & apmin, const Point<3> & apmax);
+  ~Box3dTree ();
+  void Insert (const Point<3> & bmin, const Point<3> & bmax, int pi);
+  void Insert (const Box<3> & box, int pi)
+  {
+    Insert (box.PMin(), box.PMax(), pi);
+  }
+  void DeleteElement (int pi) 
+    { tree->DeleteElement(pi); }
+  void GetIntersecting (const Point<3> & pmin, const Point<3> & pmax, 
+			Array<int> & pis) const;
+
+  const ADTree6 & Tree() const { return *tree; };
+};
+
+}
+
+#endif
diff --git a/contrib/Netgen/libsrc/gprim/geom2d.cpp b/contrib/Netgen/libsrc/gprim/geom2d.cpp
new file mode 100644
index 0000000000..34263348cc
--- /dev/null
+++ b/contrib/Netgen/libsrc/gprim/geom2d.cpp
@@ -0,0 +1,489 @@
+#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/contrib/Netgen/libsrc/gprim/geom2d.hpp b/contrib/Netgen/libsrc/gprim/geom2d.hpp
new file mode 100644
index 0000000000..334df09ca5
--- /dev/null
+++ b/contrib/Netgen/libsrc/gprim/geom2d.hpp
@@ -0,0 +1,886 @@
+#ifndef FILE_GEOM2D
+#define FILE_GEOM2D
+
+/* *************************************************************************/
+/* File:   geom2d.hh                                                       */
+/* Author: Joachim Schoeberl                                               */
+/* Date:   5. Aug. 95                                                      */
+/* *************************************************************************/
+
+namespace netgen 
+{
+
+  /* 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);
+  DLL_HEADER double Angle (const Vec2d & v);
+  DLL_HEADER double FastAngle (const Vec2d & v);
+  DLL_HEADER double Angle (const Vec2d & v1, const Vec2d & v2);
+  DLL_HEADER 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);
+  DLL_HEADER Point2d CrossPoint (const PLine2d & l1, const PLine2d & l2);
+  DLL_HEADER Point2d CrossPoint (const Line2d & l1, const Line2d & 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);
+  double Dist2 (const Point2d & p1, const Point2d & p2);
+
+  ///
+  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 bool 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;
+    }  /**
+	  Points counter-clock-wise ?
+	  Are the points (p1, p2, p3) counter-clock-wise ?
+       */
+    friend inline bool CCW (const Point2d & p1, const Point2d & p2, const Point2d & p3, double eps)
+    {
+      //      return Cross (p2 - p1, p3 - p2) > 0;
+      double ax = p2.px - p1.px;
+      double ay = p2.py - p1.py;
+      double bx = p3.px - p2.px;
+      double by = p3.py - p2.py;
+
+      return ax*by - ay*bx > eps*eps*max2(ax*ax+ay*ay,bx*bx+by*by);
+    }
+
+    ///
+    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 DLL_HEADER double Angle (const Vec2d & v);
+    ///
+    friend DLL_HEADER double FastAngle (const Vec2d & v);
+    ///
+    friend DLL_HEADER double Angle (const Vec2d & v1, const Vec2d & v2);
+    ///
+    friend DLL_HEADER 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 DLL_HEADER 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/contrib/Netgen/libsrc/gprim/geom3d.cpp b/contrib/Netgen/libsrc/gprim/geom3d.cpp
new file mode 100644
index 0000000000..04ecd13764
--- /dev/null
+++ b/contrib/Netgen/libsrc/gprim/geom3d.cpp
@@ -0,0 +1,731 @@
+#include <algorithm>
+#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];
+    }
+}
+
+Box3d :: Box3d ( const Box<3> & b2 )
+{
+  for (int i = 0; i < 3; i++)
+    {
+      minx[i] = b2.PMin()(i);
+      maxx[i] = b2.PMax()(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)
+{
+  // changed by MW
+  double matrix[3][3];
+  double locrhs[3];
+  int retval = 0;
+
+  for(int i=0; i<3; i++)
+    {
+      matrix[i][0] = col1.X(i+1);
+      matrix[i][1] = col2.X(i+1);
+      matrix[i][2] = col3.X(i+1);
+      locrhs[i] = rhs.X(i+1);
+    }
+
+  for(int i=0; i<2; i++)
+    {
+      int pivot = i;
+      double maxv = fabs(matrix[i][i]);
+      for(int j=i+1; j<3; j++)
+	if(fabs(matrix[j][i]) > maxv)
+	  {
+	    maxv = fabs(matrix[j][i]);
+	    pivot = j;
+	  }
+
+      if(fabs(maxv) > 1e-40)
+	{
+	  if(pivot != i)
+	    {
+	      swap(matrix[i][0],matrix[pivot][0]);
+	      swap(matrix[i][1],matrix[pivot][1]);
+	      swap(matrix[i][2],matrix[pivot][2]);
+	      swap(locrhs[i],locrhs[pivot]);
+	    }
+	  for(int j=i+1; j<3; j++)
+	    {
+	      double fac = matrix[j][i] / matrix[i][i];
+	      
+	      for(int k=i+1; k<3; k++)
+		matrix[j][k] -= fac*matrix[i][k];
+	      locrhs[j] -= fac*locrhs[i];
+	    }
+	}
+      else
+	retval = 1;
+    }
+
+  if(fabs(matrix[2][2]) < 1e-40)
+    retval = 1;
+
+  if(retval != 0)
+    return retval;
+  
+
+  for(int i=2; i>=0; i--)
+    {
+      double sum = locrhs[i];
+      for(int j=2; j>i; j--)
+	sum -= matrix[i][j]*sol.X(j+1);
+
+      sol.X(i+1) = sum/matrix[i][i];
+    }
+
+  return 0;
+  
+  
+  
+
+
+  /*
+  double 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;
+  */
+  /*
+  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/contrib/Netgen/libsrc/gprim/geom3d.hpp b/contrib/Netgen/libsrc/gprim/geom3d.hpp
new file mode 100644
index 0000000000..05216d8f0f
--- /dev/null
+++ b/contrib/Netgen/libsrc/gprim/geom3d.hpp
@@ -0,0 +1,746 @@
+#ifndef FILE_GEOM3D
+#define FILE_GEOM3D
+
+/* *************************************************************************/
+/* File:   geom3d.hh                                                       */
+/* Author: Joachim Schoeberl                                               */
+/* Date:   5. Aug. 95                                                      */
+/* *************************************************************************/
+
+namespace netgen
+{
+
+
+  extern DLL_HEADER 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);
+
+  inline double Dist2 (const Point3d & p1, const Point3d & p2);
+
+  /// 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]; }
+
+    ///
+    inline friend double Dist (const Vec3d & v1, const Vec3d & v2)
+    { return sqrt (  (v1.x[0]-v2.x[0]) * (v1.x[0]-v2.x[0]) + 
+		     (v1.x[1]-v2.x[1]) * (v1.x[1]-v2.x[1]) +
+                     (v1.x[2]-v2.x[2]) * (v1.x[2]-v2.x[2])); }
+    ///
+    inline friend double Dist2 (const Vec3d & v1, const Vec3d & v2)
+    { return  (  (v1.x[0]-v2.x[0]) * (v1.x[0]-v2.x[0]) + 
+		 (v1.x[1]-v2.x[1]) * (v1.x[1]-v2.x[1]) +
+		 (v1.x[2]-v2.x[2]) * (v1.x[2]-v2.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;
+      }
+#ifdef DEBUG
+    else
+      {
+	cerr << "Vec div by 0, v = " << (*this) << endl;
+	//      MyError ("Vec3d::operator /=: Divisioin by zero");
+      }
+#endif
+    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);
+    ///
+    Box3d (const Box<3> & b2);
+    ///
+    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/contrib/Netgen/libsrc/gprim/geomfuncs.cpp b/contrib/Netgen/libsrc/gprim/geomfuncs.cpp
new file mode 100644
index 0000000000..b2ac83824a
--- /dev/null
+++ b/contrib/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/contrib/Netgen/libsrc/gprim/geomfuncs.hpp b/contrib/Netgen/libsrc/gprim/geomfuncs.hpp
new file mode 100644
index 0000000000..66cbca81ef
--- /dev/null
+++ b/contrib/Netgen/libsrc/gprim/geomfuncs.hpp
@@ -0,0 +1,170 @@
+#ifndef FILE_GEOMFUNCS
+#define FILE_GEOMFUNCS
+
+/* *************************************************************************/
+/* File:   geomfuncs.hpp                                                   */
+/* Author: Joachim Schoeberl                                               */
+/* Date:   20. Jul. 02                                                     */
+/* *************************************************************************/
+
+
+namespace netgen 
+{
+
+  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;
+  }
+
+  template <int D>
+  inline Point<D> Center (const Point<D> & a, const Point<D> & b, const Point<D> & c, const Point<D> & d)
+  {
+    Point<D> res;
+    for (int i = 0; i < D; i++)
+      res(i) = (1.0/4.0) * (a(i) + b(i) + c(i) + d(i));
+    return res;
+  }
+
+
+
+
+  /*
+    new wrong code problem with MSVC2010:
+    using Cross ( & , & ) computes wrong cross-product, problem arises in 
+    Surface::DefineTangentialPlane, e.g. with example boxcyl.geo
+   */
+  // inline Vec<3> Cross (const Vec<3> & v1, const Vec<3> & v2)
+
+  inline Vec<3> Cross (Vec<3> v1, 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) );
+  }
+
+
+  inline double Determinant (const Vec<3> & col1,
+			     const Vec<3> & col2,
+			     const Vec<3> & col3)
+  {
+    return
+      col1(0) * ( col2(1) * col3(2) - col2(2) * col3(1)) +
+      col1(1) * ( col2(2) * col3(0) - col2(0) * col3(2)) +
+      col1(2) * ( col2(0) * col3(1) - col2(1) * col3(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);
+
+  inline void CalcInverse (const Mat<3,2> & m, Mat<2,3> & inv)
+  {
+    Mat<2,2> a = Trans (m) * m;
+    Mat<2,2> ainv;
+    CalcInverse (a, ainv);
+    inv = ainv * Trans (m);
+  }
+
+
+  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/contrib/Netgen/libsrc/gprim/geomobjects.hpp b/contrib/Netgen/libsrc/gprim/geomobjects.hpp
new file mode 100644
index 0000000000..29b9bb1b53
--- /dev/null
+++ b/contrib/Netgen/libsrc/gprim/geomobjects.hpp
@@ -0,0 +1,370 @@
+#ifndef FILE_OBJECTS
+#define FILE_OBJECTS
+
+/* *************************************************************************/
+/* File:   geomobjects.hpp                                                 */
+/* Author: Joachim Schoeberl                                               */
+/* Date:   20. Jul. 02                                                     */
+/* *************************************************************************/
+
+
+namespace netgen
+{
+
+
+  template <int D> class Vec;
+  template <int D> class Point;
+
+
+  template <int D>
+  class Point
+  {
+
+  protected:
+    double x[D];
+
+  public:
+    Point () { ; }
+    Point (double ax) { for (int i = 0; i < D; i++) x[i] = 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;
+    }
+
+    Point & operator= (double val)
+    {
+      for (int i = 0; i < D; i++) x[i] = val;
+      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 () { ; } // for (int i = 0; i < D; i++) x[i] = 0; }
+    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 (const Vec<D> & p1, const Vec<D> & p2)
+    { for(int i=0; i<D; i++) x[i] = p2(i)-p1(1); }
+  
+
+
+    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]; }
+    double & operator() (int i) { return x[i]; }
+    const double & operator() (int i) const { return x[i]; }
+
+    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)
+    {
+      for (int i = 0; i < D; i++)
+	pmin(i) = pmax(i) = p1(i);
+    }
+
+
+    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));
+	}
+    }
+
+    enum EB_TYPE { EMPTY_BOX = 1 };
+    Box ( EB_TYPE et ) 
+    {
+      pmin = Point<3> (1e99, 1e99, 1e99);
+      pmax = Point<3> (-1e99, -1e99, -1e99);
+    }
+
+    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 (const Box<D> & box) 
+      : Box<D> (box) 
+    { 
+      CalcDiamCenter();
+    };
+
+    ///
+    BoxSphere ( Point<D> apmin, Point<D> apmax )
+      : Box<D> (apmin, apmax)
+    {
+      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/contrib/Netgen/libsrc/gprim/geomobjects2.hpp b/contrib/Netgen/libsrc/gprim/geomobjects2.hpp
new file mode 100644
index 0000000000..014a38525a
--- /dev/null
+++ b/contrib/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/contrib/Netgen/libsrc/gprim/geomops.hpp b/contrib/Netgen/libsrc/gprim/geomops.hpp
new file mode 100644
index 0000000000..90c3cb6bf5
--- /dev/null
+++ b/contrib/Netgen/libsrc/gprim/geomops.hpp
@@ -0,0 +1,394 @@
+#ifndef FILE_GEOMOPS
+#define FILE_GEOMOPS
+
+/* *************************************************************************/
+/* File:   geomops.hpp                                                     */
+/* Author: Joachim Schoeberl                                               */
+/* Date:   20. Jul. 02                                                     */
+/* *************************************************************************/
+
+
+namespace netgen
+{
+
+  /*
+
+  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<2,3> operator* (const Mat<2,2> & a, const Mat<2,3> & b)
+  {
+    Mat<2,3> m;
+    for (int i = 0; i < 2; i++)
+      for (int j = 0; j < 3; 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/contrib/Netgen/libsrc/gprim/geomops2.hpp b/contrib/Netgen/libsrc/gprim/geomops2.hpp
new file mode 100644
index 0000000000..c615da14ec
--- /dev/null
+++ b/contrib/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/contrib/Netgen/libsrc/gprim/geomtest3d.cpp b/contrib/Netgen/libsrc/gprim/geomtest3d.cpp
new file mode 100644
index 0000000000..bb4000b36d
--- /dev/null
+++ b/contrib/Netgen/libsrc/gprim/geomtest3d.cpp
@@ -0,0 +1,1150 @@
+#include <mystdlib.h>
+#include <myadt.hpp>
+
+#include <linalg.hpp>
+#include <gprim.hpp>
+
+namespace netgen
+{
+int
+IntersectTriangleLine (const Point<3> ** tri, const Point<3> ** 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 = 0; i < 3; i++)
+    {
+      a(i, 0) = -vl.X(i+1);
+      a(i, 1) = vt1.X(i+1);
+      a(i, 2) = vt2.X(i+1);
+      rs(i) = vrs.X(i+1);
+    }
+
+  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(0) >= -eps && lami(0) <= 1+eps && 
+       lami(1) >= -eps && lami(2) >= -eps && 
+       lami(1) + lami(2) <= 1+eps)  && !
+      (lami(0) >= eps && lami(0) <= 1-eps && 
+       lami(1) >= eps && lami(2) >= eps && 
+       lami(1) + lami(2) <= 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(0) >= 0 && lami(0) <= 1 && 
+      lami(1) >= 0 && lami(2) >= 0 && lami(1) + lami(2) <= 1)
+    {
+
+      return 1;
+    }
+
+  return 0;
+}
+
+
+
+
+
+int IntersectTetTriangle (const Point<3> ** tet, const Point<3> ** 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;
+
+  double eps2 = eps * eps;
+  int cnt = 0;
+
+  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;
+
+
+  //  (*testout) << "tet-trig inters, cnt = " << cnt << endl;
+  
+  // cnt .. number of common points
+  switch (cnt)
+    {
+    case 0:
+      {
+	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 Point<3> * 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:
+      {
+	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:
+      {
+	// 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:
+      {
+	// common face
+	return 0;
+      }
+    }
+
+  (*testout) << "hit, cnt = " << cnt << endl;
+  return 1;
+}
+
+
+
+
+
+int IntersectTetTriangleRef (const Point<3> ** tri, const int * tripi)
+{
+  int i, j;
+  double eps = 1e-8;
+  // double eps2 = eps * eps;
+
+  static Point<3> rtetp1(0, 0, 0);
+  static Point<3> rtetp2(1, 0, 0);  
+  static Point<3> rtetp3(0, 1, 0); 
+  static Point<3> rtetp4(0, 0, 1);
+
+  static const Point<3> * 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;
+
+
+  switch (cnt)
+    {
+    case 0:
+      {
+	Vec3d no, n;
+	//	int inpi[3];
+	int pside[3][4];
+
+	for (j = 0; j < 3; j++)
+	  {
+	    pside[j][0] = (*tri[j])(0) > -eps;
+	    pside[j][1] = (*tri[j])(1) > -eps;
+	    pside[j][2] = (*tri[j])(2) > -eps;
+	    pside[j][3] = (*tri[j])(0) + (*tri[j])(1) + (*tri[j])(2) < 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 Point<3> * 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:
+      {
+	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:
+      {
+	// 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:
+      {
+	// common face
+	return 0;
+      }
+    }
+
+  (*testout) << "hit, cnt = " << cnt << endl;
+  return 1;
+}
+
+
+
+
+
+
+
+
+
+
+
+int IntersectTriangleTriangle (const Point<3> ** tri1, const Point<3> ** 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 Point<3> * 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 Point<3> ** pts, Point<3> & c)
+{
+  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(0) = v1 * v1;
+  rs(1) = v2 * v2;
+
+  a(0,0) = 2 * rs(0);
+  a(0,1) = a(1,0) = 2 * (v1 * v2);
+  a(1,1) = 2 * rs(1);
+
+  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(0);
+  v2 *= sol(1);
+
+  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/contrib/Netgen/libsrc/gprim/geomtest3d.hpp b/contrib/Netgen/libsrc/gprim/geomtest3d.hpp
new file mode 100644
index 0000000000..05387da00f
--- /dev/null
+++ b/contrib/Netgen/libsrc/gprim/geomtest3d.hpp
@@ -0,0 +1,87 @@
+#ifndef FILE_GEOMTEST3D
+#define FILE_GEOMTEST3D
+
+/* *************************************************************************/
+/* File:   geomtest3d.hh                                                   */
+/* Author: Joachim Schoeberl                                               */
+/* Date:   13. Feb. 98                                                     */
+/* *************************************************************************/
+
+
+namespace netgen
+{
+
+
+extern int
+IntersectTriangleLine (const Point<3> ** tri, const Point<3> ** 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 Point<3> ** tet, const Point<3> ** 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 Point<3> ** tri1, const Point<3> ** 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 Point<3> ** pts, Point<3> & 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);
+
+/// Minimal distance of point p to the line segment [lp1,lp2]
+extern double MinDistLP2 (const Point2d & lp1, const Point2d & lp2, const Point2d & p);
+
+/// Minimal distance of point p to the line segment [lp1,lp2]
+extern double MinDistLP2 (const Point3d & lp1, const Point3d & lp2, const Point3d & p);
+
+/// Minimal distance of point p to the triangle segment [tp1,tp2,pt3]
+extern double MinDistTP2 (const Point3d & tp1, const Point3d & tp2, 
+			  const Point3d & tp3, const Point3d & p);
+
+/// Minimal distance of the 2 lines [l1p1,l1p2] and [l2p1,l2p2]
+extern double MinDistLL2 (const Point3d & l1p1, const Point3d & l1p2,
+			  const Point3d & l2p1, const Point3d & l2p2);
+
+}
+
+#endif
diff --git a/contrib/Netgen/libsrc/gprim/gprim.hpp b/contrib/Netgen/libsrc/gprim/gprim.hpp
new file mode 100644
index 0000000000..016b1280aa
--- /dev/null
+++ b/contrib/Netgen/libsrc/gprim/gprim.hpp
@@ -0,0 +1,33 @@
+#ifndef FILE_GPRIM
+#define FILE_GPRIM
+
+/* *************************************************************************/
+/* File:   gprim.hpp                                                        */
+/* Author: Joachim Schoeberl                                               */
+/* Date:   14. Aug. 97                                                     */
+/* *************************************************************************/
+
+
+#include <myadt.hpp>
+#include <linalg.hpp>
+
+
+
+
+#include "geomobjects.hpp"
+#include "geomops.hpp"
+#include "geomfuncs.hpp"
+
+#include "geom2d.hpp"
+#include "geom3d.hpp"
+
+#include "geomtest3d.hpp"
+#include "transform3d.hpp"
+
+#include "adtree.hpp"
+
+#include "spline.hpp"
+#include "splinegeometry.hpp"
+
+
+#endif
diff --git a/contrib/Netgen/libsrc/gprim/spline.cpp b/contrib/Netgen/libsrc/gprim/spline.cpp
new file mode 100644
index 0000000000..b6789913e4
--- /dev/null
+++ b/contrib/Netgen/libsrc/gprim/spline.cpp
@@ -0,0 +1,497 @@
+/*
+
+Spline curve for Mesh generator
+
+*/
+
+#include <mystdlib.h>
+#include <linalg.hpp>
+#include <gprim.hpp>
+#include "spline.hpp"
+
+namespace netgen
+{
+
+  // just for testing (JS)
+  template <int D>
+  void ProjectTrivial (const SplineSeg3<D> & seg, 
+                       const Point<D> point, Point<D> & point_on_curve, double & t)
+  {
+    double mindist = -1;
+    for (int i = 0; i <= 1000; i++)
+      {
+        double ht = double(i)/1000;
+        Point<D> p = seg.GetPoint(ht);
+        double dist = Dist2 (p, point);
+        if (i == 0 || dist < mindist)
+          {
+            mindist = dist;
+            t = ht;
+          }
+      }
+    point_on_curve = seg.GetPoint(t);
+  }
+
+
+  template <> 
+  void CircleSeg<3> :: LineIntersections (const double a, const double b, const double c,
+					  Array < Point<3> > & points, const double eps) const
+  {
+    cerr << "CircleSeg<3>::LineIntersections not implemented" << endl;
+  }
+  
+  template <> 
+  void CircleSeg<2> :: LineIntersections (const double a, const double b, const double c,
+					  Array < Point<2> > & points, const double eps) const
+  {
+    points.SetSize(0);
+
+    double px=0,py=0;
+
+    if(fabs(b) > 1e-20)
+      py = -c/b;
+    else
+      px = -c/a;
+
+    const double c1 = a*a + b*b;
+    const double c2 = 2. * ( a*(py-pm(1)) - b*(px-pm(0)));
+    const double c3 = pow(px-pm(0),2) + pow(py-pm(1),2) - pow(Radius(),2);
+    
+    const double discr = c2*c2 - 4*c1*c3;
+
+    if(discr < 0)
+      return;
+
+    Array<double> t;
+
+    if(fabs(discr) < 1e-20)
+      t.Append(-0.5*c2/c1);
+    else
+      {
+	t.Append((-c2+sqrt(discr))/(2.*c1));
+	t.Append((-c2-sqrt(discr))/(2.*c1));
+      }
+
+    for(int i=0; i<t.Size(); i++)
+      {
+	Point<2> p (px-t[i]*b,py+t[i]*a);
+
+	double angle = atan2(p(1),p(0))+M_PI;
+
+	if(angle > StartAngle()-eps && angle < EndAngle()+eps)
+	  points.Append(p);
+      }
+  }
+
+
+
+
+  template<int D>
+  SplineSeg3<D> :: SplineSeg3 (const GeomPoint<D> & ap1, 
+			       const GeomPoint<D> & ap2,
+			       const GeomPoint<D> & ap3)
+    : p1(ap1), p2(ap2), p3(ap3)
+  {
+    weight = Dist (p1, p3) / sqrt (0.5 * (Dist2 (p1, p2) + Dist2 (p2, p3)));
+    // weight = sqrt(2);
+    // cout << "weight = " << weight << endl;
+    proj_latest_t = 0.5;
+  }
+
+  template<int D>
+  inline Point<D> SplineSeg3<D> :: GetPoint (double t) const
+  {
+    double x, y, w;
+    double b1, b2, b3;
+
+    b1 = (1-t)*(1-t);
+    b2 = weight * 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;
+
+    if(D==3)
+      {
+	double z = p1(2) * b1 + p2(2) * b2 + p3(2) * b3;
+	return Point<D> (x/w, y/w, z/w);
+      }
+    else
+      return Point<D> (x/w, y/w);
+  }
+
+
+
+
+  template<int D>
+  Vec<D> SplineSeg3<D> :: GetTangent (const double t) const
+  {
+    const double b1 = (1.-t)*((weight-2.)*t-weight);
+    const double b2 = weight*(1.-2.*t);
+    const double b3 = t*((weight-2)*t+2.);
+
+
+    Vec<D> retval;
+    for(int i=0; i<D; i++) 
+      retval(i) = b1*p1(i) + b2*p2(i) + b3*p3(i);
+
+    return retval;
+
+  }
+
+
+  template<int D>
+  void SplineSeg3<D> :: GetCoeff (Vector & u) const
+  {
+    DenseMatrix a(6, 6);
+    DenseMatrix ata(6, 6);
+    Vector f(6);
+
+    u.SetSize(6);
+
+    //  ata.SetSymmetric(1);
+
+    double t = 0;
+    for (int i = 0; i < 5; i++, t += 0.25)
+      {
+	Point<D> p = GetPoint (t);
+	a(i, 0) = p(0) * p(0);
+	a(i, 1) = p(1) * p(1);
+	a(i, 2) = p(0) * p(1);
+	a(i, 3) = p(0);
+	a(i, 4) = p(1);
+	a(i, 5) = 1;
+      }
+    a(5, 0) = 1;
+
+    CalcAtA (a, ata);
+
+    u = 0;
+    u(5) = 1;
+    a.MultTrans (u, f);
+    ata.Solve (f, u);
+
+    // the sign
+    Point<D> p0 = GetPoint(0);
+    Vec<D> ht = GetTangent(0);
+    Vec<2> tang(ht(0), ht(1));
+
+    double gradx = 2.*u(0)*p0(0) + u(2)*p0(1) + u(3);
+    double grady = 2.*u(1)*p0(1) + u(2)*p0(0) + u(4);
+    Vec<2> gradn (grady, -gradx);
+  
+    if (tang * gradn < 0) u *= -1;
+  }
+
+  
+
+
+  template<int D>
+  void SplineSeg3<D> :: Project (const Point<D> point, Point<D> & point_on_curve, double & t) const
+  {
+    double t_old = -1;
+
+    if(proj_latest_t > 0. && proj_latest_t < 1.)
+      t = proj_latest_t;
+    else
+      t = 0.5;
+	
+    Point<D> phi;
+    Vec<D> phip,phipp,phimp;
+    
+    int i=0;
+
+    while(t > -0.5 && t < 1.5 && i<20 && fabs(t-t_old) > 1e-15 )
+      {
+        GetDerivatives(t,phi,phip,phipp);
+	
+        t_old = t;
+
+        phimp = phi-point;
+
+        //t = min2(max2(t-(phip*phimp)/(phipp*phimp + phip*phip),0.),1.);
+        t -= (phip*phimp)/(phipp*phimp + phip*phip);
+
+        i++;
+      }
+    
+    //if(i<10 && t > 0. && t < 1.)
+    if(i<20 && t > -0.4 && t < 1.4)
+      {
+        if(t < 0)
+          {
+            t = 0.;
+          }
+        if(t > 1)
+          {
+            t = 1.;
+          }
+
+        point_on_curve = SplineSeg3<D>::GetPoint(t);
+	
+        double dist = Dist(point,point_on_curve);
+	
+        phi =  SplineSeg3<D> ::GetPoint(0);
+        double auxdist = Dist(phi,point);
+        if(auxdist < dist)
+          {
+            t = 0.;
+            point_on_curve = phi;
+            dist = auxdist;
+          }
+        phi =  SplineSeg3<D> ::GetPoint(1);
+        auxdist = Dist(phi,point);
+        if(auxdist < dist)
+          {
+            t = 1.;
+            point_on_curve = phi;
+            dist = auxdist;
+          }
+      }
+    else
+      {
+        double t0 = 0;
+        double t1 = 0.5;
+        double t2 = 1.;
+
+        double d0,d1,d2;
+
+	
+        //(*testout) << "newtonersatz" << endl;
+        while(t2-t0 > 1e-8)
+          {
+	    
+            phi =  SplineSeg3<D> ::GetPoint(t0); d0 = Dist(phi,point);
+            phi =  SplineSeg3<D> ::GetPoint(t1); d1 = Dist(phi,point);
+            phi =  SplineSeg3<D> ::GetPoint(t2); d2 = Dist(phi,point);
+
+            double a = (2.*d0 - 4.*d1 +2.*d2)/pow(t2-t0,2);
+
+            if(a <= 0)
+              {
+                if(d0 < d2)
+                  t2 -= 0.3*(t2-t0);
+                else
+                  t0 += 0.3*(t2-t0);
+
+                t1 = 0.5*(t2+t0);
+              }
+            else
+              {
+                double b = (d1-d0-a*(t1*t1-t0*t0))/(t1-t0);
+
+                double auxt1 = -0.5*b/a;
+
+                if(auxt1 < t0)
+                  {
+                    t2 -= 0.4*(t2-t0);
+                    t0 = max2(0.,t0-0.1*(t2-t0));
+                  }
+                else if (auxt1 > t2)
+                  {
+                    t0 += 0.4*(t2-t0);
+                    t2 = min2(1.,t2+0.1*(t2-t0));
+                  }
+                else
+                  {
+                    t1 = auxt1;
+                    auxt1 = 0.25*(t2-t0);
+                    t0 = max2(0.,t1-auxt1);
+                    t2 = min2(1.,t1+auxt1);
+                  }
+		
+                t1 = 0.5*(t2+t0);
+              }  
+
+          }
+
+	
+        phi =  SplineSeg3<D> ::GetPoint(t0); d0 = Dist(phi,point);
+        phi =  SplineSeg3<D> ::GetPoint(t1); d1 = Dist(phi,point);
+        phi =  SplineSeg3<D> ::GetPoint(t2); d2 = Dist(phi,point);
+
+        double mind = d0;
+        t = t0;
+        if(d1 < mind)
+          {
+            t = t1;
+            mind = d1;
+          }
+        if(d2 < mind)
+          {
+            t = t2;
+            mind = d2;
+          }
+
+        point_on_curve =  SplineSeg3<D> ::GetPoint(t);
+      }
+    //(*testout) << " latest_t " << proj_latest_t << " t " << t << endl;
+
+    proj_latest_t = t;
+
+    /*
+    // test it by trivial sampling
+    double ht;
+    Point<D> hp;
+    ProjectTrivial (*this, point, hp, ht);
+    if (fabs (t-ht) > 1e-3)
+    {
+    // if (Dist2 (point, hp) < Dist2 (point, point_on_curve))
+    cout << "project is wrong" << endl;
+    cout << "t = " << t << ", ht = " << ht << endl;
+    cout << "dist org = " << Dist(point, point_on_curve) << endl;
+    cout << "dist trivial = " << Dist(point, hp) << endl;
+    }
+    */
+  }
+
+
+
+
+
+
+  template<int D>
+  void SplineSeg3<D> :: GetDerivatives (const double t, 
+                                        Point<D> & point,
+                                        Vec<D> & first,
+                                        Vec<D> & second) const
+  {
+    Vec<D> v1(p1), v2(p2), v3(p3);
+
+    double b1 = (1.-t)*(1.-t);
+    double b2 = weight*t*(1.-t);
+    double b3 = t*t;
+    double w = b1+b2+b3;
+    b1 *= 1./w; b2 *= 1./w; b3 *= 1./w;
+
+    double b1p = 2.*(t-1.);
+    double b2p = weight*(1.-2.*t);
+    double b3p = 2.*t;
+    const double wp = b1p+b2p+b3p;
+    const double fac1 = wp/w;
+    b1p *= 1./w; b2p *= 1./w; b3p *= 1./w;
+
+    const double b1pp = 2.;
+    const double b2pp = -2.*weight;
+    const double b3pp = 2.;
+    const double wpp = b1pp+b2pp+b3pp;
+    const double fac2 = (wpp*w-2.*wp*wp)/(w*w);
+
+    for(int i=0; i<D; i++)
+      point(i) = b1*p1(i) + b2*p2(i) + b3*p3(i);
+    
+ 
+    first = (b1p - b1*fac1) * v1 +
+      (b2p - b2*fac1) * v2 +
+      (b3p - b3*fac1) * v3;
+
+    second = (b1pp/w - 2*b1p*fac1 - b1*fac2) * v1 +
+      (b2pp/w - 2*b2p*fac1 - b2*fac2) * v2 +
+      (b3pp/w - 2*b3p*fac1 - b3*fac2) * v3;
+  }
+
+
+
+  template<>
+  double SplineSeg3<2> :: MaxCurvature(void) const
+  {
+    Vec<2> v1 = p1-p2;
+    Vec<2> v2 = p3-p2;
+    double l1 = v1.Length();
+    double l2 = v2.Length();
+        
+    double cosalpha = (v1*v2)/(l1*l2);
+    
+            
+    return sqrt(cosalpha + 1.)/(min2(l1,l2)*(1.-cosalpha));
+  }
+
+  template<>
+  double SplineSeg3<3> :: MaxCurvature(void) const
+  {
+    Vec<3> v1 = p1-p2;
+    Vec<3> v2 = p3-p2;
+    double l1 = v1.Length();
+    double l2 = v2.Length();
+        
+    double cosalpha = v1*v2/(l1*l2);
+    
+        
+    return sqrt(cosalpha + 1.)/(min2(l1,l2)*(1.-cosalpha));
+  }
+
+
+  template<int D>
+  void SplineSeg3<D> :: LineIntersections (const double a, const double b, const double c,
+					   Array < Point<D> > & points, const double eps) const
+  {
+    points.SetSize(0);
+
+    double t;
+
+    const double c1 = a*p1(0) - weight*a*p2(0) + a*p3(0) 
+      + b*p1(1) - weight*b*p2(1) + b*p3(1) 
+      + (2.-weight)*c;
+    const double c2 = -2.*a*p1(0) + weight*a*p2(0) -2.*b*p1(1) + weight*b*p2(1) + (weight-2.)*c;
+    const double c3 = a*p1(0) + b*p1(1) + c;
+
+    if(fabs(c1) < 1e-20)
+      {
+	if(fabs(c2) < 1e-20)
+	  return;
+
+	t = -c3/c2;
+	if((t > -eps) && (t < 1.+eps))
+	  points.Append(GetPoint(t));
+	return;
+      }
+
+    const double discr = c2*c2-4.*c1*c3;
+
+    if(discr < 0)
+      return;
+
+    if(fabs(discr/(c1*c1)) < 1e-14)
+      {
+	t = -0.5*c2/c1;
+	if((t > -eps) && (t < 1.+eps))
+	  points.Append(GetPoint(t));
+	return;
+      }
+
+    t = (-c2 + sqrt(discr))/(2.*c1);
+    if((t > -eps) && (t < 1.+eps))
+      points.Append(GetPoint(t));
+
+    t = (-c2 - sqrt(discr))/(2.*c1);
+    if((t > -eps) && (t < 1.+eps))
+      points.Append(GetPoint(t));
+  }
+
+
+  template < int D >
+  void SplineSeg3<D> :: GetRawData (Array<double> & data) const
+  {
+    data.Append(3);
+    for(int i=0; i<D; i++)
+      data.Append(p1[i]);
+    for(int i=0; i<D; i++)
+      data.Append(p2[i]);
+    for(int i=0; i<D; i++)
+      data.Append(p3[i]);
+  }
+
+
+
+  template class  SplineSeg3<2>;
+  template class  SplineSeg3<3>;
+
+
+
+
+
+
+
+
+}
diff --git a/contrib/Netgen/libsrc/gprim/spline.hpp b/contrib/Netgen/libsrc/gprim/spline.hpp
new file mode 100644
index 0000000000..f2701c3e1a
--- /dev/null
+++ b/contrib/Netgen/libsrc/gprim/spline.hpp
@@ -0,0 +1,647 @@
+#ifndef FILE_SPLINE_HPP
+#define FILE_SPLINE_HPP
+
+/**************************************************************************/
+/* File:   spline.hpp                                                     */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   24. Jul. 96                                                    */
+/**************************************************************************/
+
+namespace netgen
+{
+
+
+
+  /*
+    Spline curves for 2D mesh generation
+  */
+
+
+  /// Geometry point
+  template < int D >
+  class GeomPoint : public Point<D>
+  {
+  public:
+    /// refinement factor at point
+    double refatpoint;
+    /// max mesh-size at point
+    double hmax;
+    /// hp-refinement
+    bool hpref;
+
+    ///
+    GeomPoint () { ; }
+
+    ///
+    GeomPoint (const Point<D> & ap, double aref = 1, bool ahpref=false)
+      : Point<D>(ap), refatpoint(aref), hmax(1e99), hpref(ahpref) { ; }
+  };
+
+
+
+
+  /// base class for 2d - segment
+  template < int D >
+  class SplineSeg
+  {
+  public:
+    SplineSeg () { ; }
+    /// calculates length of curve
+    virtual double Length () const;
+    /// returns point at curve, 0 <= t <= 1
+    virtual Point<D> GetPoint (double t) const = 0;
+    /// returns a (not necessarily unit-length) tangent vector for 0 <= t <= 1
+    virtual Vec<D> GetTangent (const double t) const
+    { cerr << "GetTangent not implemented for spline base-class"  << endl; Vec<D> dummy; return dummy;}
+    virtual void GetDerivatives (const double t, 
+				 Point<D> & point,
+				 Vec<D> & first,
+				 Vec<D> & second) const {;}
+
+
+    /// returns initial point on curve
+    virtual const GeomPoint<D> & StartPI () const = 0;
+    /// returns terminal point on curve
+    virtual const GeomPoint<D> & 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 */
+    void PrintCoeff (ostream & ost) const;
+
+    virtual void GetCoeff (Vector & coeffs) const = 0;
+
+    virtual void GetPoints (int n, Array<Point<D> > & points) const;
+
+    /** calculates (2D) lineintersections:
+	for lines $$ a x + b y + c = 0 $$ the interecting points are calculated
+	and stored in points */
+    virtual void LineIntersections (const double a, const double b, const double c,
+				    Array < Point<D> > & points, const double eps) const
+    {points.SetSize(0);}
+
+    virtual double MaxCurvature(void) const = 0;
+
+    virtual string GetType(void) const {return "splinebase";}
+
+    virtual void Project (const Point<D> point, Point<D> & point_on_curve, double & t) const
+    { cerr << "Project not implemented for spline base-class" << endl;}
+
+    virtual void GetRawData (Array<double> & data) const
+    { cerr << "GetRawData not implemented for spline base-class" << endl;}
+
+  };
+
+
+  /// Straight line form p1 to p2
+  template< int D >
+  class LineSeg : public SplineSeg<D>
+  {
+    ///
+    GeomPoint<D> p1, p2;
+  public:
+    ///
+    LineSeg (const GeomPoint<D> & ap1, const GeomPoint<D> & ap2);
+    ///
+    virtual double Length () const;
+    ///
+    inline virtual Point<D> GetPoint (double t) const;
+    ///
+    virtual Vec<D> GetTangent (const double t) const;
+
+  
+    virtual void GetDerivatives (const double t, 
+				 Point<D> & point,
+				 Vec<D> & first,
+				 Vec<D> & second) const;
+    ///
+    virtual const GeomPoint<D> & StartPI () const { return p1; };
+    ///
+    virtual const GeomPoint<D> & EndPI () const { return p2; }
+    ///
+    virtual void GetCoeff (Vector & coeffs) const;
+
+    virtual string GetType(void) const {return "line";}
+
+    virtual void LineIntersections (const double a, const double b, const double c,
+				    Array < Point<D> > & points, const double eps) const;
+
+    virtual double MaxCurvature(void) const {return 0;}
+
+    virtual void Project (const Point<D> point, Point<D> & point_on_curve, double & t) const;
+
+    virtual void GetRawData (Array<double> & data) const;
+  };
+
+
+  /// curve given by a rational, quadratic spline (including ellipses)
+  template< int D >
+  class SplineSeg3 : public SplineSeg<D>
+  {
+    ///
+    GeomPoint<D> p1, p2, p3;
+    double weight;
+    mutable double proj_latest_t;
+  public:
+    ///
+    SplineSeg3 (const GeomPoint<D> & ap1, 
+		const GeomPoint<D> & ap2, 
+		const GeomPoint<D> & ap3);
+    ///
+    inline virtual Point<D> GetPoint (double t) const;
+    ///
+    virtual Vec<D> GetTangent (const double t) const;
+
+  
+    DLL_HEADER virtual void GetDerivatives (const double t, 
+				 Point<D> & point,
+				 Vec<D> & first,
+				 Vec<D> & second) const;
+    ///
+    virtual const GeomPoint<D> & StartPI () const { return p1; };
+    ///
+    virtual const GeomPoint<D> & EndPI () const { return p3; }
+    ///
+    virtual void GetCoeff (Vector & coeffs) const;
+
+    virtual string GetType(void) const {return "spline3";}
+
+    const GeomPoint<D> & TangentPoint (void) const { return p2; }
+
+    DLL_HEADER virtual void LineIntersections (const double a, const double b, const double c,
+				    Array < Point<D> > & points, const double eps) const;
+
+    DLL_HEADER virtual double MaxCurvature(void) const;
+
+    DLL_HEADER virtual void Project (const Point<D> point, Point<D> & point_on_curve, double & t) const;
+
+    DLL_HEADER virtual void GetRawData (Array<double> & data) const;
+  };
+
+
+  // Gundolf Haase  8/26/97
+  /// A circle
+  template < int D >
+  class CircleSeg : public SplineSeg<D>
+  {
+    ///
+  private:
+    GeomPoint<D>	p1, p2, p3;
+    //const GeomPoint<D>	&p1, &p2, &p3;
+    Point<D>		pm;
+    double		radius, w1,w3;
+  public:
+    ///
+    CircleSeg (const GeomPoint<D> & ap1, 
+	       const GeomPoint<D> & ap2, 
+	       const GeomPoint<D> & ap3);
+    ///
+    virtual Point<D> GetPoint (double t) const;
+    ///
+    virtual const GeomPoint<D> & StartPI () const { return p1; }
+    ///
+    virtual const GeomPoint<D> & EndPI () const { return p3; }
+    ///
+    virtual void GetCoeff (Vector & coeffs) const;
+    ///
+    double Radius() const { return radius; }
+    ///
+    double StartAngle() const { return w1; }
+    ///
+    double EndAngle() const { return w3; }
+    ///
+    const Point<D> & MidPoint(void) const {return pm; }
+
+    virtual string GetType(void) const {return "circle";}
+
+    virtual void LineIntersections (const double a, const double b, const double c,
+				    Array < Point<D> > & points, const double eps) const;
+
+    virtual double MaxCurvature(void) const {return 1./radius;}
+  };
+
+
+
+
+
+
+  /// 
+  template<int D>
+  class DiscretePointsSeg : public SplineSeg<D>
+  {
+    Array<Point<D> > pts;
+    GeomPoint<D> p1n, p2n;
+  public:
+    ///
+    DiscretePointsSeg (const Array<Point<D> > & apts);
+    ///
+    virtual ~DiscretePointsSeg ();
+    ///
+    virtual Point<D> GetPoint (double t) const;
+    ///
+    virtual const GeomPoint<D> & StartPI () const { return p1n; };
+    ///
+    virtual const GeomPoint<D> & EndPI () const { return p2n; }
+    ///
+    virtual void GetCoeff (Vector & coeffs) const {;}
+
+    virtual double MaxCurvature(void) const {return 1;}
+  };
+
+
+
+
+
+
+  // calculates length of spline-curve
+  template<int D>
+  double SplineSeg<D> :: Length () const
+  {
+    int n = 100;
+    double dt = 1.0 / n;
+
+    Point<D> pold = GetPoint (0);
+
+    double l = 0;
+    for (int i = 1; i <= n; i++)
+      {
+	Point<D> p = GetPoint (i * dt);
+	l += Dist (p, pold);
+	pold = p;
+      }
+
+    return l;
+  }
+
+
+  template<int D>
+  void SplineSeg<D> :: GetPoints (int n, Array<Point<D> > & points) const
+  {
+    points.SetSize (n);
+    if (n >= 2)
+      for (int i = 0; i < n; i++)
+	points[i] = GetPoint(double(i) / (n-1));
+  }
+
+
+  template<int D>
+  void SplineSeg<D> :: PrintCoeff (ostream & ost) const
+  {
+    Vector u(6);
+
+    GetCoeff(u);
+
+    for ( int i=0; i<6; i++)
+      ost << u[i] << "  ";
+    ost << endl;
+  }
+
+
+
+  /* 
+     Implementation of line-segment from p1 to p2
+  */
+
+
+  template<int D>
+  LineSeg<D> :: LineSeg (const GeomPoint<D> & ap1, 
+			 const GeomPoint<D> & ap2)
+    : p1(ap1), p2(ap2)
+  {
+    ;
+  }
+
+
+  template<int D>
+  inline Point<D> LineSeg<D> :: GetPoint (double t) const
+  {
+    return p1 + t * (p2 - p1);
+  }
+
+  template<int D>
+  Vec<D> LineSeg<D> :: GetTangent (const double t) const
+  {
+    return p2-p1;
+  }
+
+  template<int D>
+  void LineSeg<D> :: GetDerivatives (const double t, 
+				     Point<D> & point,
+				     Vec<D> & first,
+				     Vec<D> & second) const
+  {
+    first = p2 - p1;
+    point = p1 + t * first;
+    second = 0;
+  }
+
+
+  template<int D>
+  double LineSeg<D> :: Length () const
+  {
+    return Dist (p1, p2);
+  }
+
+
+  template<int D>
+  void LineSeg<D> :: GetCoeff (Vector & coeffs) const
+  {
+    coeffs.SetSize(6);
+
+    double dx = p2(0) - p1(0);
+    double dy = p2(1) - p1(1);
+
+    coeffs[0] = coeffs[1] = coeffs[2] = 0;
+    coeffs[3] = -dy;
+    coeffs[4] = dx;
+    coeffs[5] = -dx * p1(1) + dy * p1(0);
+  }
+
+
+
+  template<int D>
+  void LineSeg<D> :: LineIntersections (const double a, const double b, const double c,
+					Array < Point<D> > & points, const double eps) const
+  {
+    points.SetSize(0);
+
+    double denom = -a*p2(0)+a*p1(0)-b*p2(1)+b*p1(1);
+    if(fabs(denom) < 1e-20)
+      return;
+
+    double t = (a*p1(0)+b*p1(1)+c)/denom;
+    if((t > -eps) && (t <  1.+eps))
+      points.Append(GetPoint(t));
+  }
+
+
+
+  template<int D>
+  void LineSeg<D> :: Project (const Point<D> point, Point<D> & point_on_curve, double & t) const
+  {
+    Vec<D> v = p2-p1;
+    double l = v.Length();
+    v *= 1./l;
+    t = (point-p1)*v;
+
+    if(t<0) t = 0;
+    if(t>l) t = l;
+
+    point_on_curve = p1+t*v;
+
+    t *= 1./l;
+  }
+
+
+  template<int D>
+  void LineSeg<D> :: GetRawData (Array<double> & data) const
+  {
+    data.Append(2);
+    for(int i=0; i<D; i++)
+      data.Append(p1[i]);
+    for(int i=0; i<D; i++)
+      data.Append(p2[i]);
+  }
+
+
+
+
+
+  /*
+    template<int D>
+    double SplineSeg3<D> :: MaxCurvature(void) const
+    {
+    Vec<D> v1 = p1-p2;
+    Vec<D> v2 = p3-p2;
+    double l1 = v1.Length();
+    double l2 = v2.Length();
+    (*testout) << "v1 " << v1 << " v2 " << v2 << endl;
+
+    double cosalpha = v1*v2/(l1*l2);
+
+    (*testout) << "cosalpha " << cosalpha << endl;
+
+    return sqrt(cosalpha + 1.)/(min2(l1,l2)*(1.-cosalpha));
+    }
+  */
+  
+
+
+  //########################################################################
+  //		circlesegment
+
+  template<int D>
+  CircleSeg<D> :: CircleSeg (const GeomPoint<D> & ap1, 
+			     const GeomPoint<D> & ap2,
+			     const GeomPoint<D> & ap3)
+    : p1(ap1), p2(ap2), p3(ap3)
+  {
+    Vec<D> v1,v2;
+  
+    v1 = p1 - p2;
+    v2 = p3 - p2;
+  
+    Point<D> p1t(p1+v1);
+    Point<D> p2t(p3+v2);
+
+    // works only in 2D!!!!!!!!!
+    
+    Line2d g1t,g2t;
+
+    g1t.P1() = Point<2>(p1(0),p1(1));
+    g1t.P2() = Point<2>(p1t(0),p1t(1));
+    g2t.P1() = Point<2>(p3(0),p3(1));
+    g2t.P2() = Point<2>(p2t(0),p2t(1));
+
+    Point<2> mp = CrossPoint (g1t,g2t);
+
+    pm(0) = mp(0); pm(1) = mp(1);
+    radius  = Dist(pm,StartPI());
+    Vec2d auxv;
+    auxv.X() = p1(0)-pm(0); auxv.Y() = p1(1)-pm(1);
+    w1      = Angle(auxv);
+    auxv.X() = p3(0)-pm(0); auxv.Y() = p3(1)-pm(1);
+    w3      = Angle(auxv);
+    if ( fabs(w3-w1) > M_PI )
+      {  
+	if ( w3>M_PI )   w3 -= 2*M_PI;
+	if ( w1>M_PI )   w1 -= 2*M_PI;
+      }
+  }
+ 
+
+  template<int D>
+  Point<D> CircleSeg<D> :: GetPoint (double t) const
+  {
+    if (t >= 1.0)  { return p3; }
+     
+    double phi = StartAngle() + t*(EndAngle()-StartAngle());
+    Vec<D>  tmp(cos(phi),sin(phi));
+     
+    return pm + Radius()*tmp;
+  }
+  
+  template<int D>
+  void CircleSeg<D> :: GetCoeff (Vector & coeff) const
+  { 
+    coeff[0] = coeff[1] = 1.0;
+    coeff[2] = 0.0;
+    coeff[3] = -2.0 * pm[0];
+    coeff[4] = -2.0 * pm[1];
+    coeff[5] = sqr(pm[0]) + sqr(pm[1]) - sqr(Radius());
+  }
+
+  
+
+
+
+  template<int D>
+  DiscretePointsSeg<D> ::   DiscretePointsSeg (const Array<Point<D> > & apts)
+    : pts (apts)
+  { 
+    for(int i=0; i<D; i++)
+      {
+	p1n(i) = apts[0](i);
+	p2n(i) = apts.Last()(i);
+      }
+    p1n.refatpoint = 1;
+    p2n.refatpoint = 1;
+    p1n.hmax = 1e99;
+    p2n.hmax = 1e99;
+  }
+
+
+  template<int D>
+  DiscretePointsSeg<D> :: ~DiscretePointsSeg ()
+  { ; }
+
+  template<int D>
+  Point<D> DiscretePointsSeg<D> :: GetPoint (double t) const
+  {
+    double t1 = t * (pts.Size()-1);
+    int segnr = int(t1);
+    if (segnr < 0) segnr = 0;
+    if (segnr >= pts.Size()) segnr = pts.Size()-1;
+
+    double rest = t1 - segnr;
+    
+    return pts[segnr] + rest*Vec<D>(pts[segnr+1]-pts[segnr]);
+  }
+
+
+
+
+
+
+
+  
+
+  // *************************************
+  // Template for B-Splines of order ORDER
+  // thx to Gerhard Kitzler
+  // *************************************
+  
+  template<int D, int ORDER>
+  class BSplineSeg : public SplineSeg<D>
+  {
+    Array<Point<D> > pts;
+    GeomPoint<D> p1n, p2n;    
+    Array<int> ti; 
+
+  public:
+    ///
+    BSplineSeg (const Array<Point<D> > & apts);
+    ///
+    virtual ~BSplineSeg();
+    ///
+    virtual Point<D> GetPoint (double t) const;
+    ///
+    virtual const GeomPoint<D> & StartPI () const { return p1n; };
+    ///
+    virtual const GeomPoint<D> & EndPI () const { return p2n; }
+    ///
+    virtual void GetCoeff (Vector & coeffs) const {;}
+
+    virtual double MaxCurvature(void) const {return 1;}
+  };
+
+  // Constructor
+  template<int D,int ORDER>
+  BSplineSeg<D,ORDER> :: BSplineSeg (const Array<Point<D> > & apts)
+    : pts (apts)
+  { 
+    /*
+    for(int i=0; i<D; i++)
+      {
+	p1n(i) = apts[0](i);
+	p2n(i) = apts.Last()(i);
+      }
+    */
+    p1n = apts[0];
+    p2n = apts.Last();
+
+    /*
+    p1n.refatpoint = 1;
+    p2n.refatpoint = 1;
+    p1n.hmax = 1e99;
+    p2n.hmax = 1e99;
+    */
+
+    int m=pts.Size()+ORDER;
+    ti.SetSize(m);
+    // b.SetSize(m-1);
+    ti=0;    
+    //    b=0.0;
+    for(int i=ORDER;i<m-ORDER+1;i++)
+      ti[i]=i-ORDER+1;   
+    for(int i=m-ORDER+1;i<m;i++)
+      ti[i]=m-2*ORDER+1;
+  }
+  // Destructor
+  template<int D,int ORDER>
+  BSplineSeg<D, ORDER> :: ~BSplineSeg ()
+  { ; }
+
+
+  // GetPoint Method...(evaluation of BSpline Curve)
+  template<int D,int ORDER>
+  Point<D> BSplineSeg<D,ORDER> :: GetPoint (double t_in) const
+  {    
+    int m=pts.Size()+ORDER;           
+
+    double t = t_in * (m-2*ORDER+1);    
+
+    double b[ORDER];
+    
+    int interval_nr = int(t)+ORDER-1;    
+    if (interval_nr < ORDER-1) interval_nr = ORDER-1;
+    if (interval_nr > m-ORDER-1) interval_nr = m-ORDER-1;
+
+    b[ORDER-1] = 1.0;
+    
+    for(int degree=1;degree<ORDER;degree++)
+      for (int k = 0; k <= degree; k++)
+	{
+	  int j = interval_nr-degree+k;
+	  double bnew = 0;
+
+	  if (k != 0) 
+	    bnew += (t-ti[j]) / ( ti[j+degree]-ti[j] ) * b[k-degree+ORDER-1];
+	  if (k != degree)
+	    bnew += (ti[j+degree+1]-t) / ( ti[j+degree+1]-ti[j+1] ) * b[k-degree+ORDER];
+	  b[k-degree+ORDER-1] = bnew;
+	}
+
+    Point<D> p = 0.0;
+    for(int i=0; i < ORDER; i++) 
+      p += b[i] * Vec<D> (pts[i+interval_nr-ORDER+1]);
+    return p;
+  }
+
+
+
+}
+
+
+#endif
diff --git a/contrib/Netgen/libsrc/gprim/splinegeometry.cpp b/contrib/Netgen/libsrc/gprim/splinegeometry.cpp
new file mode 100644
index 0000000000..580e61abaf
--- /dev/null
+++ b/contrib/Netgen/libsrc/gprim/splinegeometry.cpp
@@ -0,0 +1,134 @@
+/*
+
+2d Spline curve for Mesh generator
+
+*/
+
+
+#include <mystdlib.h>
+#include <linalg.hpp>
+#include <gprim.hpp>
+#include "splinegeometry.hpp"
+ 
+namespace netgen
+{
+
+
+  template<int D>
+  SplineGeometry<D> :: ~SplineGeometry()
+  {
+    for(int i = 0; i < splines.Size(); i++)
+      delete splines[i];
+  }
+
+
+  template<int D>
+  void SplineGeometry<D> :: GetRawData (Array<double> & raw_data) const
+  {
+    raw_data.Append(D);
+    // raw_data.Append(elto0);
+
+    raw_data.Append(splines.Size());
+    for(int i=0; i<splines.Size(); i++)
+      splines[i]->GetRawData(raw_data);
+  }
+
+
+
+  template<int D>
+  int SplineGeometry<D> :: Load (const Array<double> & raw_data, const int startpos)
+  {
+    int pos = startpos;
+    if(raw_data[pos] != D)
+      throw NgException("wrong dimension of spline raw_data");
+
+    pos++;
+
+    // elto0 = raw_data[pos]; pos++;
+
+    splines.SetSize(int(raw_data[pos]));
+    pos++;
+
+    Array< Point<D> > pts(3);
+
+    for(int i=0; i<splines.Size(); i++)
+      {
+	int type = int(raw_data[pos]);
+	pos++;
+      
+	for(int j=0; j<type; j++)
+	  for(int k=0; k<D; k++)
+	    {
+	      pts[j](k) = raw_data[pos];
+	      pos++;
+	    }
+
+	if (type == 2)
+	  {
+	    splines[i] = new LineSeg<D>(GeomPoint<D>(pts[0],1),
+					GeomPoint<D>(pts[1],1));
+	  }
+	else if (type == 3)
+	  {
+	    splines[i] = new SplineSeg3<D>(GeomPoint<D>(pts[0],1),
+					   GeomPoint<D>(pts[1],1),
+					   GeomPoint<D>(pts[2],1));
+	  }
+	else
+	  throw NgException("something wrong with spline raw data");
+
+      }
+    return pos;
+  }
+
+
+
+
+
+
+
+  
+
+  template<int D>
+  void SplineGeometry<D> :: GetBoundingBox (Box<D> & box) const
+  {
+    if (!splines.Size())
+      {
+	Point<D> auxp = 0.;
+	box.Set (auxp);
+	return;
+      }
+
+    Array<Point<D> > 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]);
+      }
+  }
+
+  /*
+  template<int D>
+  void SplineGeometry<D> :: SetGrading (const double grading)
+  { 
+    elto0 = grading;
+  }
+  */
+
+  template<int D>
+  void SplineGeometry<D> :: AppendPoint (const Point<D> & p, const double reffac, const bool hpref)
+  {
+    geompoints.Append (GeomPoint<D>(p, reffac));
+    geompoints.Last().hpref = hpref;
+  }
+
+
+
+  template class SplineGeometry<2>;
+  template class SplineGeometry<3>;
+}
+
+
diff --git a/contrib/Netgen/libsrc/gprim/splinegeometry.hpp b/contrib/Netgen/libsrc/gprim/splinegeometry.hpp
new file mode 100644
index 0000000000..d29adbc42e
--- /dev/null
+++ b/contrib/Netgen/libsrc/gprim/splinegeometry.hpp
@@ -0,0 +1,68 @@
+/*
+
+
+JS, Nov 2007
+
+
+The 2D/3D template-base classes should go into the libsrc/gprim directory
+
+in geom2d only 2D - Geometry classes (with material properties etc.)
+
+
+*/
+
+#include "spline.hpp"
+
+
+#ifndef _FILE_SPLINEGEOMETRY
+#define _FILE_SPLINEGEOMETRY
+
+namespace netgen
+{
+
+
+  template < int D >
+  class SplineGeometry 
+  {
+    // protected:
+  public:  
+    Array < GeomPoint<D> > geompoints;
+    Array < SplineSeg<D>* > splines;
+
+    DLL_HEADER ~SplineGeometry();
+
+    DLL_HEADER int Load (const Array<double> & raw_data, const int startpos = 0);
+
+    DLL_HEADER void GetRawData (Array<double> & raw_data) const;
+
+
+    const Array<SplineSeg<D>*> & GetSplines () const
+    { return splines; }
+
+    int GetNSplines (void) const { return splines.Size(); }
+    string GetSplineType (const int i) const { return splines[i]->GetType(); }
+    SplineSeg<D> & GetSpline (const int i) {return *splines[i];}
+    const SplineSeg<D> & GetSpline (const int i) const {return *splines[i];}
+
+    DLL_HEADER void GetBoundingBox (Box<D> & box) const;
+    Box<D> GetBoundingBox () const 
+    { Box<D> box; GetBoundingBox (box); return box; }
+
+    int GetNP () const { return geompoints.Size(); }
+    const GeomPoint<D> & GetPoint(int i) const { return geompoints[i]; }
+
+    // void SetGrading (const double grading);
+    DLL_HEADER void AppendPoint (const Point<D> & p, const double reffac = 1., const bool hpref = false);
+
+
+    void AppendSegment(SplineSeg<D> * spline)
+    {
+      splines.Append (spline);
+    }
+  };
+
+
+
+}
+
+#endif // _FILE_SPLINEGEOMETRY
diff --git a/contrib/Netgen/libsrc/gprim/transform3d.cpp b/contrib/Netgen/libsrc/gprim/transform3d.cpp
new file mode 100644
index 0000000000..dcc4cef116
--- /dev/null
+++ b/contrib/Netgen/libsrc/gprim/transform3d.cpp
@@ -0,0 +1,165 @@
+#include <mystdlib.h>
+
+#include <myadt.hpp>
+#include <gprim.hpp>
+#include <linalg.hpp>
+
+namespace netgen
+{
+
+Transformation3d :: Transformation3d ()
+{
+  for (int i = 0; i < 3; i++)
+    {
+      offset[i] = 0;
+      for (int j = 0; j < 3; j++)
+	lin[i][j] = 0;
+    }
+}
+
+Transformation3d :: Transformation3d (const Vec3d & translate)
+{
+  for (int i = 0; i < 3; i++)
+    for (int j = 0; j < 3; j++)
+      lin[i][j] = 0;
+  for (int 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);
+
+  // cout << "Rotation - Transformation:" << (*this) << endl;
+  //  (*testout) << "Rotation - Transformation:" << (*this) << endl;
+}
+
+
+
+
+Transformation3d :: Transformation3d (const Point3d ** pp)
+{
+  for (int i = 1; i <= 3; i++)
+    {
+      offset[i-1] = (*pp[0]).X(i);
+      for (int j = 1; j <= 3; j++)
+	lin[i-1][j-1] = (*pp[j]).X(i) - (*pp[0]).X(i);
+    }
+}
+
+Transformation3d :: Transformation3d (const Point3d pp[])
+{
+  for (int i = 1; i <= 3; i++)
+    {
+      offset[i-1] = pp[0].X(i);
+      for (int 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);
+  
+  for (int i = 0; i < 3; i++)
+    {
+      b(i) = offset[i];
+      for (int j = 0; j < 3; j++)
+	a(i, j) = lin[i][j];
+    }
+
+  ::netgen::CalcInverse (a, inva);
+  inva.Mult (b, sol);
+
+  for (int i = 0; i < 3; i++)
+    {
+      inv.offset[i] = -sol(i);
+      for (int j = 0; j < 3; j++)
+	inv.lin[i][j] = inva(i, j);
+    }
+}
+
+
+void  Transformation3d:: 
+Combine (const Transformation3d & ta, const Transformation3d & tb)
+{
+  // o = o_a+ m_a o_b
+  // m = m_a m_b
+
+  for (int i = 0; i <= 2; i++)
+    {
+      offset[i] = ta.offset[i];
+      for (int j = 0; j <= 2; j++)
+	offset[i] += ta.lin[i][j] * tb.offset[j];
+    }
+  
+  for (int i = 0; i <= 2; i++)
+    for (int j = 0; j <= 2; j++)
+      {
+	lin[i][j] = 0;
+	for (int 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)
+{
+  ost << "offset = ";
+  for (int i = 0; i <= 2; i++)
+    ost << trans.offset[i] << " ";
+  ost << endl << "linear = " << endl;
+  for (int i = 0; i <= 2; i++)
+    {
+      for (int j = 0; j <= 2; j++)
+	ost << trans.lin[i][j] << " ";
+      ost << endl;
+    }
+  return ost;
+}
+}
diff --git a/contrib/Netgen/libsrc/gprim/transform3d.hpp b/contrib/Netgen/libsrc/gprim/transform3d.hpp
new file mode 100644
index 0000000000..cd4124335c
--- /dev/null
+++ b/contrib/Netgen/libsrc/gprim/transform3d.hpp
@@ -0,0 +1,193 @@
+#ifndef FILE_TRANSFORM3D
+#define FILE_TRANSFORM3D
+
+/* *************************************************************************/
+/* File:   transform3d.hh                                                  */
+/* Author: Joachim Schoeberl                                               */
+/* Date:   22. Mar. 98                                                     */
+/* *************************************************************************/
+
+/*
+  Affine - Linear mapping in 3D space
+ */
+
+namespace netgen
+{
+
+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);
+	}
+    }
+
+  ///
+  void Transform (Point3d & p) const
+  {
+    Point3d hp;
+    Transform (p, hp);
+    p = hp;
+  }
+
+  /// 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)
+  {
+    // total = T_c x Rot_0 x T_c^{-1}
+    // Use Euler angles, see many books from tech mech, e.g. 
+    // Shabana "multibody systems"
+    
+    Vec<D> vc(c);
+    Transformation<D> tc(vc);
+    Transformation<D> tcinv(-vc);
+    // tc.CalcInverse (tcinv);
+    
+    Transformation<D> 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);
+    
+    // cout << "Rotation - Transformation:" << (*this) << endl;
+    //  (*testout) << "Rotation - Transformation:" << (*this) << endl;
+  }
+
+  /// 
+  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)
+  {
+    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++)
+    {
+      v(i) = 0;
+      for (j = 0; j <= 2; j++)
+	m(i,j) = 0;
+    }
+    
+    m(dir,dir) = 1;
+    m(pos1, pos1) = co;
+    m(pos2, pos2) = co;
+    m(pos1, pos2) = si;
+    m(pos2, pos1) = -si;
+  }
+
+  ///
+  void Transform (const Point<D> & from, Point<D> & to) const
+  {
+    to = Point<D> (v + m * Vec<D>(from));
+  }
+
+  void Transform (Point<D> & p) const
+  {
+    p = Point<D> (v + m * Vec<D>(p));
+  }
+
+
+
+  /// 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/contrib/Netgen/libsrc/include/Makefile.am b/contrib/Netgen/libsrc/include/Makefile.am
new file mode 100644
index 0000000000..f84db193a3
--- /dev/null
+++ b/contrib/Netgen/libsrc/include/Makefile.am
@@ -0,0 +1,8 @@
+noinst_HEADERS = acisgeom.hpp gprim.hpp meshing.hpp occgeom.hpp	\
+visual.hpp csg.hpp incvis.hpp myadt.hpp opti.hpp geometry2d.hpp	\
+linalg.hpp mydefs.hpp parallel.hpp stlgeom.hpp mystdlib.h
+
+include_HEADERS = nginterface.h nginterface_v2.hpp 
+
+AM_CPPFLAGS = 
+METASOURCES = AUTO
diff --git a/contrib/Netgen/libsrc/include/acisgeom.hpp b/contrib/Netgen/libsrc/include/acisgeom.hpp
new file mode 100644
index 0000000000..491b7720db
--- /dev/null
+++ b/contrib/Netgen/libsrc/include/acisgeom.hpp
@@ -0,0 +1,3 @@
+#ifdef ACIS
+#include "../acisgeom/acisgeom.hpp"
+#endif
diff --git a/contrib/Netgen/libsrc/include/csg.hpp b/contrib/Netgen/libsrc/include/csg.hpp
new file mode 100644
index 0000000000..ffd45ef0bf
--- /dev/null
+++ b/contrib/Netgen/libsrc/include/csg.hpp
@@ -0,0 +1 @@
+#include "../csg/csg.hpp"
diff --git a/contrib/Netgen/libsrc/include/geometry2d.hpp b/contrib/Netgen/libsrc/include/geometry2d.hpp
new file mode 100644
index 0000000000..bf0965c228
--- /dev/null
+++ b/contrib/Netgen/libsrc/include/geometry2d.hpp
@@ -0,0 +1 @@
+#include "../geom2d/geometry2d.hpp"
diff --git a/contrib/Netgen/libsrc/include/gprim.hpp b/contrib/Netgen/libsrc/include/gprim.hpp
new file mode 100644
index 0000000000..1e827aaf8c
--- /dev/null
+++ b/contrib/Netgen/libsrc/include/gprim.hpp
@@ -0,0 +1 @@
+#include "../gprim/gprim.hpp"
diff --git a/contrib/Netgen/libsrc/include/incvis.hpp b/contrib/Netgen/libsrc/include/incvis.hpp
new file mode 100644
index 0000000000..bd31bfccd6
--- /dev/null
+++ b/contrib/Netgen/libsrc/include/incvis.hpp
@@ -0,0 +1,39 @@
+// libraries for User interface:
+
+
+#include <tcl.h>
+#include <tk.h>
+
+#if TK_MAJOR_VERSION==8 && TK_MINOR_VERSION>=4
+#define tcl_const const
+#else
+#define tcl_const
+#endif
+
+
+#  if defined(TOGL_AGL) || defined(TOGL_AGL_CLASSIC)
+#    include <OpenGL/gl.h>
+#    include <OpenGL/glu.h>
+#  else
+#    include <GL/gl.h>
+#    include <GL/glu.h>
+#  endif
+
+
+#ifdef TOGL_X11
+// parallel
+#define GLX_GLXEXT_PROTOTYPES
+#include <GL/glx.h>
+#include <GL/glxext.h>
+#endif
+
+
+
+// part of OpenGL 1.2, but not in Microsoft's OpenGL 1.1 header:
+// GL version sould be checked at runtime
+#ifndef GL_CLAMP_TO_EDGE
+#define GL_CLAMP_TO_EDGE 0x812F
+#endif
+
+
+
diff --git a/contrib/Netgen/libsrc/include/linalg.hpp b/contrib/Netgen/libsrc/include/linalg.hpp
new file mode 100644
index 0000000000..e96bd036c3
--- /dev/null
+++ b/contrib/Netgen/libsrc/include/linalg.hpp
@@ -0,0 +1 @@
+#include "../linalg/linalg.hpp"
diff --git a/contrib/Netgen/libsrc/include/meshing.hpp b/contrib/Netgen/libsrc/include/meshing.hpp
new file mode 100644
index 0000000000..e41a88f9f2
--- /dev/null
+++ b/contrib/Netgen/libsrc/include/meshing.hpp
@@ -0,0 +1 @@
+#include <../meshing/meshing.hpp>
diff --git a/contrib/Netgen/libsrc/include/myadt.hpp b/contrib/Netgen/libsrc/include/myadt.hpp
new file mode 100644
index 0000000000..d36bef05c1
--- /dev/null
+++ b/contrib/Netgen/libsrc/include/myadt.hpp
@@ -0,0 +1 @@
+#include <../general/myadt.hpp>
diff --git a/contrib/Netgen/libsrc/include/mydefs.hpp b/contrib/Netgen/libsrc/include/mydefs.hpp
new file mode 100644
index 0000000000..54c14eba22
--- /dev/null
+++ b/contrib/Netgen/libsrc/include/mydefs.hpp
@@ -0,0 +1,49 @@
+#ifndef FILE_MYDEFS
+#define FILE_MYDEFS
+
+/**************************************************************************/
+/* File:   mydefs.hh                                                      */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   10. Mar. 98                                                    */
+/**************************************************************************/
+
+/*
+  defines for graphics, testmodes, ...
+*/
+
+
+// #define DEBUG
+
+// Philippose - 31/01/2009
+// Hack for the Windows Version
+// in Linux, "PACKAGE_VERSION" is replaced 
+// in the configure/make phases, with the 
+// right version number
+#ifdef WIN32
+#define PACKAGE_VERSION "4.9.14"
+#endif
+
+
+#ifdef WIN32
+   #if NGINTERFACE_EXPORTS || NGLIB_EXPORTS || nglib_EXPORTS
+      #define DLL_HEADER   __declspec(dllexport)
+   #else
+      #define DLL_HEADER   __declspec(dllimport)
+   #endif
+#else
+   #define DLL_HEADER 
+#endif
+
+
+#define noDEMOVERSION
+#define noDEVELOP
+#define noSTEP
+#define noSOLIDGEOM
+
+#define noDEMOAPP
+#define noMODELLER
+
+#define noSTAT_STREAM
+#define noLOG_STREAM
+
+#endif
diff --git a/contrib/Netgen/libsrc/include/mystdlib.h b/contrib/Netgen/libsrc/include/mystdlib.h
new file mode 100644
index 0000000000..a3a9103aa5
--- /dev/null
+++ b/contrib/Netgen/libsrc/include/mystdlib.h
@@ -0,0 +1,88 @@
+#ifndef FILE_MYSTDLIB
+#define FILE_MYSTDLIB
+
+#ifndef WIN32
+#include <config.h>
+#endif
+
+
+#include <iostream>
+#include <iomanip>
+#include <fstream>
+#include <sstream>
+
+
+#include <cstdlib>
+#include <cstdio>
+#include <cmath>
+#include <cctype>
+#include <ctime>
+#include <cstring>
+#include <climits>
+#include <algorithm>
+
+
+#include <new>
+#include <string>
+#include <typeinfo>
+
+#ifdef PARALLEL
+// #undef SEEK_SET
+// #undef SEEK_CUR
+// #undef SEEK_END
+#include <mpi.h>
+#endif
+
+#ifdef _OPENMP
+#include <omp.h>
+#endif
+
+
+/*
+#ifdef METIS
+namespace metis { extern "C" {
+#include <metis.h>
+} }
+#endif
+*/
+
+
+#ifndef NO_PARALLEL_THREADS
+#ifndef WIN32
+#include <pthread.h>
+#endif
+#endif
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+
+/*** Windows headers ***/
+#ifdef _MSC_VER
+# define WIN32_LEAN_AND_MEAN
+# ifndef NO_PARALLEL_THREADS
+#  ifdef MSVC_EXPRESS
+#   include <pthread.h>
+#  else
+#   include <afxwin.h>
+#   include <afxmt.h>
+#  endif // MSVC_EXPRESS
+# endif
+# include <windows.h>
+# undef WIN32_LEAN_AND_MEAN
+# include <winnt.h>
+
+#else // Not using MC VC++
+
+# ifndef NO_PARALLEL_THREADS
+#  include <pthread.h>
+# endif
+
+#endif
+
+
+using namespace std;
+
+#endif
+
diff --git a/contrib/Netgen/libsrc/include/nginterface.h b/contrib/Netgen/libsrc/include/nginterface.h
new file mode 100644
index 0000000000..85ae8d6d78
--- /dev/null
+++ b/contrib/Netgen/libsrc/include/nginterface.h
@@ -0,0 +1,510 @@
+#ifndef NGINTERFACE
+#define NGINTERFACE
+
+
+
+
+
+/**************************************************************************/
+/* File:   nginterface.h                                                  */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   20. Nov. 99                                                    */
+/**************************************************************************/
+
+/*
+  Application program interface to Netgen
+
+*/
+
+#ifdef WIN32
+   #if NGINTERFACE_EXPORTS || NGLIB_EXPORTS || nglib_EXPORTS
+      #define DLL_HEADER   __declspec(dllexport)
+   #else
+      #define DLL_HEADER   __declspec(dllimport)
+   #endif
+#else
+   #define DLL_HEADER 
+#endif
+
+
+// max number of nodes per element
+#define NG_ELEMENT_MAXPOINTS 12
+
+// max number of nodes per surface element
+#define NG_SURFACE_ELEMENT_MAXPOINTS 8
+
+
+
+// implemented element types:
+enum NG_ELEMENT_TYPE { 
+  NG_SEGM = 1, NG_SEGM3 = 2,
+  NG_TRIG = 10, NG_QUAD=11, NG_TRIG6 = 12, NG_QUAD6 = 13,
+  NG_TET = 20, NG_TET10 = 21, 
+  NG_PYRAMID = 22, NG_PRISM = 23, NG_PRISM12 = 24,
+  NG_HEX = 25
+};
+
+typedef double NG_POINT[3];  // coordinates
+typedef int NG_EDGE[2];      // initial point, end point
+typedef int NG_FACE[4];      // points, last one is 0 for trig
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+  
+  // load geomtry from file 
+  DLL_HEADER void Ng_LoadGeometry (const char * filename);
+  
+  // load netgen mesh
+  DLL_HEADER void Ng_LoadMesh (const char * filename);
+
+  // load netgen mesh
+  DLL_HEADER void Ng_LoadMeshFromString (const char * mesh_as_string);
+
+  // space dimension (2 or 3)
+  DLL_HEADER int Ng_GetDimension ();
+
+  // number of mesh points
+  DLL_HEADER int Ng_GetNP ();
+  
+  // number of mesh vertices (differs from GetNP for 2nd order elements)
+  DLL_HEADER int Ng_GetNV ();
+  
+  // number of mesh elements
+  DLL_HEADER int Ng_GetNE ();
+  
+  // number of surface triangles
+  DLL_HEADER int Ng_GetNSE ();
+  
+  // Get Point coordintes, index from 1 .. np
+  DLL_HEADER void Ng_GetPoint (int pi, double * p);
+  
+  // Get Element Points
+  DLL_HEADER NG_ELEMENT_TYPE Ng_GetElement (int ei, int * epi, int * np = 0);
+
+  // Get Element Type
+  DLL_HEADER NG_ELEMENT_TYPE Ng_GetElementType (int ei);
+
+  // Get sub-domain of element ei
+  DLL_HEADER int Ng_GetElementIndex (int ei);
+
+  DLL_HEADER void Ng_SetElementIndex(const int ei, const int index);
+
+  // Get Material of element ei
+  DLL_HEADER char * Ng_GetElementMaterial (int ei);
+
+  // Get Material of domain dom
+  DLL_HEADER char * Ng_GetDomainMaterial (int dom);
+  
+  // Get User Data
+  DLL_HEADER int Ng_GetUserDataSize (char * id);
+  DLL_HEADER void Ng_GetUserData (char * id, double * data);
+
+  // Get Surface Element Points
+  DLL_HEADER NG_ELEMENT_TYPE Ng_GetSurfaceElement (int ei, int * epi, int * np = 0);
+
+  // Get Surface Element Type
+  DLL_HEADER NG_ELEMENT_TYPE Ng_GetSurfaceElementType (int ei);
+
+  // Get Surface Element Index
+  DLL_HEADER int Ng_GetSurfaceElementIndex (int ei);
+
+  // Get Surface Element Surface Number
+  DLL_HEADER int Ng_GetSurfaceElementSurfaceNumber (int ei);
+  
+  // Get Surface Element Number
+  DLL_HEADER int Ng_GetSurfaceElementFDNumber (int ei);
+
+  // Get BCName for Surface Element  
+  DLL_HEADER char * Ng_GetSurfaceElementBCName (int ei);
+  //void Ng_GetSurfaceElementBCName (int ei, char * name);
+
+  // Get BCName for bc-number
+  DLL_HEADER char * Ng_GetBCNumBCName (int bcnr);
+  //void Ng_GetBCNumBCName (int bcnr, char * name);
+
+  // Get normal vector of surface element node
+  DLL_HEADER void Ng_GetNormalVector (int sei, int locpi, double * nv);     
+  
+
+  DLL_HEADER void Ng_SetPointSearchStartElement(int el);
+  
+  // Find element of point, returns local coordinates
+  DLL_HEADER int Ng_FindElementOfPoint (double * p, double * lami,
+                                        int build_searchtrees = 0, 
+                                        const int * const indices = NULL, const int numind = 0);
+  
+  // Find surface element of point, returns local coordinates
+  DLL_HEADER int Ng_FindSurfaceElementOfPoint (double * p, double * lami,
+                                               int build_searchtrees = 0, 
+                                               const int * const indices = NULL, const int numind = 0);
+  
+
+  // is elment ei curved ?
+  DLL_HEADER int Ng_IsElementCurved (int ei);
+  // is elment sei curved ?
+  DLL_HEADER int Ng_IsSurfaceElementCurved (int sei);
+
+  /// Curved Elemens:
+  /// xi..local coordinates
+  /// x ..global coordinates
+  /// dxdxi...D x D Jacobian matrix (row major storage)
+  DLL_HEADER void Ng_GetElementTransformation (int ei, const double * xi, 
+                                               double * x, double * dxdxi);
+
+  
+  /// buffer must be at least 100 doubles, alignment of double
+  DLL_HEADER void Ng_GetBufferedElementTransformation (int ei, const double * xi, 
+                                                       double * x, double * dxdxi,
+                                                       void * buffer, int buffervalid);
+  
+
+
+  /// Curved Elemens:
+  /// xi..local coordinates
+  /// x ..global coordinates
+  /// dxdxi...D x D-1 Jacobian matrix (row major storage)
+  /// curved ...is element curved ?
+  DLL_HEADER void Ng_GetSurfaceElementTransformation (int sei, const double * xi, 
+                                                      double * x, double * dxdxi);
+  
+  /// Curved Elemens:
+  /// xi..local coordinates
+  /// sxi..step xi
+  /// x ..global coordinates
+  /// dxdxi...D x D Jacobian matrix (row major storage)
+  DLL_HEADER void Ng_GetMultiElementTransformation (int ei, int n,
+                                                    const double * xi, size_t sxi,
+                                                    double * x, size_t sx,
+                                                    double * dxdxi, size_t sdxdxi);
+
+  
+  
+  DLL_HEADER int Ng_GetSegmentIndex (int elnr);
+  DLL_HEADER NG_ELEMENT_TYPE Ng_GetSegment (int elnr, int * epi, int * np = 0);
+
+
+
+
+  // Mark element for refinement
+  DLL_HEADER void Ng_SetRefinementFlag (int ei, int flag);
+  DLL_HEADER void Ng_SetSurfaceRefinementFlag (int sei, int flag);
+
+  // Do local refinement
+  enum NG_REFINEMENT_TYPE { NG_REFINE_H = 0, NG_REFINE_P = 1, NG_REFINE_HP = 2 };
+  DLL_HEADER void Ng_Refine (NG_REFINEMENT_TYPE reftype);
+
+  // Use second order elements
+  DLL_HEADER void Ng_SecondOrder ();
+  DLL_HEADER void Ng_HighOrder (int order, bool rational = false);
+  //void Ng_HPRefinement (int levels, double parameter = 0.125);
+  DLL_HEADER void Ng_HPRefinement (int levels, double parameter = 0.125,
+                                   bool setorders = true,bool ref_level = false);
+  // void Ng_HPRefinement (int levels);
+  // void Ng_HPRefinement (int levels, double parameter);
+
+
+  // Topology and coordinate information of master element:
+
+  DLL_HEADER int Ng_ME_GetNVertices (NG_ELEMENT_TYPE et);
+  DLL_HEADER int Ng_ME_GetNEdges (NG_ELEMENT_TYPE et);
+  DLL_HEADER int Ng_ME_GetNFaces (NG_ELEMENT_TYPE et);
+
+  DLL_HEADER const NG_POINT * Ng_ME_GetVertices (NG_ELEMENT_TYPE et);
+  DLL_HEADER const NG_EDGE * Ng_ME_GetEdges (NG_ELEMENT_TYPE et);
+  DLL_HEADER const NG_FACE * Ng_ME_GetFaces (NG_ELEMENT_TYPE et);
+
+  DLL_HEADER void Ng_UpdateTopology();
+
+  DLL_HEADER int Ng_GetNEdges();
+  DLL_HEADER int Ng_GetNFaces();
+
+  
+  DLL_HEADER int Ng_GetElement_Edges (int elnr, int * edges, int * orient = 0);
+  DLL_HEADER int Ng_GetElement_Faces (int elnr, int * faces, int * orient = 0);
+
+  DLL_HEADER int Ng_GetSurfaceElement_Edges (int selnr, int * edges, int * orient = 0);
+  DLL_HEADER int Ng_GetSurfaceElement_Face (int selnr, int * orient = 0);
+
+  DLL_HEADER void Ng_GetSurfaceElementNeighbouringDomains(const int selnr, int & in, int & out);
+       
+  DLL_HEADER int Ng_GetFace_Vertices (int fnr, int * vert);
+  DLL_HEADER void Ng_GetEdge_Vertices (int ednr, int * vert);
+  DLL_HEADER int Ng_GetFace_Edges (int fnr, int * edge);
+
+  DLL_HEADER int Ng_GetNVertexElements (int vnr);
+  DLL_HEADER void Ng_GetVertexElements (int vnr, int * els);
+
+  DLL_HEADER int Ng_GetElementOrder (int enr);
+  DLL_HEADER void Ng_GetElementOrders (int enr, int * ox, int * oy, int * oz);
+
+  DLL_HEADER void Ng_SetElementOrder (int enr, int order);
+  DLL_HEADER void Ng_SetElementOrders (int enr, int ox, int oy, int oz);
+
+  DLL_HEADER int Ng_GetSurfaceElementOrder (int enr);
+  DLL_HEADER void Ng_GetSurfaceElementOrders (int enr, int * ox, int * oy);
+
+  DLL_HEADER void Ng_SetSurfaceElementOrder (int enr, int order);
+  DLL_HEADER void Ng_SetSurfaceElementOrders (int enr, int ox, int oy);
+
+  // Multilevel functions:
+
+  // number of levels:
+  DLL_HEADER int Ng_GetNLevels ();
+  // get two parent nodes (indeed vertices !) of node ni
+  DLL_HEADER void Ng_GetParentNodes (int ni, int * parents);
+
+  // get parent element (first child has always same number)
+  DLL_HEADER int Ng_GetParentElement (int ei);
+
+  // get parent surface element (first child has always same number)
+  DLL_HEADER int Ng_GetParentSElement (int ei);
+
+  // representant of anisotropic cluster
+  DLL_HEADER int Ng_GetClusterRepVertex (int vi);
+  DLL_HEADER int Ng_GetClusterRepEdge (int edi);
+  DLL_HEADER int Ng_GetClusterRepFace (int fai);
+  DLL_HEADER int Ng_GetClusterRepElement (int eli);
+
+
+  void Ng_SurfaceElementTransformation (int eli, double x, double y, 
+					double * p3d, double * jacobian);
+
+#ifdef PARALLEL
+  // Is Element ei an element of this processor ??
+  bool Ng_IsGhostEl (int ei);
+
+  void Ng_SetGhostEl(const int ei, const bool aisghost );
+
+  bool Ng_IsGhostSEl (int ei);
+
+  void Ng_SetGhostSEl(const int ei, const bool aisghost );
+
+  bool Ng_IsGhostVert ( int pnum );
+  bool Ng_IsGhostEdge ( int ednum );
+  bool Ng_IsGhostFace ( int fanum );
+
+  bool Ng_IsExchangeEl ( int elnum );
+  bool Ng_IsExchangeSEl ( int selnr );
+
+  void Ng_UpdateOverlap ();
+  int Ng_Overlap();
+/*   void Ng_SetGhostVert ( const int pnum, const bool aisghost ); */
+/*   void Ng_SetGhostEdge ( const int ednum, const bool aisghost ); */
+/*   void Ng_SetGhostFace ( const int fanum, const bool aisghost ); */
+
+
+
+
+  // the folling functions are 0-base  !!
+  int NgPar_GetLoc2Glob_VolEl ( int locnum );
+
+  // int NgPar_GetDistantNodeNums ( int nt, int locnum, int * procs, int * distnum);
+
+  // number on distant processor 
+
+  // gibt anzahl an distant pnums zurueck
+  // * pnums entspricht ARRAY<int[2] >
+  int NgPar_GetDistantNodeNums ( int nodetype, int locnum, int * pnums );
+  int NgPar_GetNDistantNodeNums ( int nodetype, int locnum );
+
+  int NgPar_GetDistantPNum ( int proc, int locnum ) ;
+  int NgPar_GetDistantEdgeNum ( int proc, int locnum ) ;
+  int NgPar_GetDistantFaceNum ( int proc, int locnum ) ;
+  int NgPar_GetDistantElNum ( int proc, int locnum );
+
+  bool NgPar_IsExchangeFace ( int fnr ) ;
+  bool NgPar_IsExchangeVert ( int vnum );
+  bool NgPar_IsExchangeEdge ( int ednum );
+  bool NgPar_IsExchangeElement ( int elnum );
+
+  void NgPar_PrintParallelMeshTopology ();
+  bool NgPar_IsElementInPartition ( int elnum, int dest );
+
+  bool NgPar_IsGhostFace ( int facenum );
+  bool NgPar_IsGhostEdge ( int edgenum );
+
+
+#endif
+  
+  namespace netgen {
+  // #include "../visualization/soldata.hpp"
+    class SolutionData;
+  }
+
+  enum Ng_SolutionType
+  { NG_SOLUTION_NODAL = 1, 
+    NG_SOLUTION_ELEMENT = 2, 
+    NG_SOLUTION_SURFACE_ELEMENT = 3, 
+    NG_SOLUTION_NONCONTINUOUS = 4,
+    NG_SOLUTION_SURFACE_NONCONTINUOUS = 5,
+    NG_SOLUTION_VIRTUAL_FUNCTION = 6,
+    NG_SOLUTION_MARKED_ELEMENTS = 10,
+    NG_SOLUTION_ELEMENT_ORDER = 11
+  };
+  
+  struct Ng_SolutionData
+  {
+    const char * name; // name of gridfunction
+    double * data;    // solution values
+    int components;   // relevant (double) components in solution vector
+    int dist;         // # doubles per entry alignment! 
+    int iscomplex;    // complex vector ? 
+    bool draw_surface;
+    bool draw_volume;
+    int order;        // order of elements, only partially supported 
+    Ng_SolutionType soltype;  // type of solution function
+    netgen::SolutionData * solclass;
+  };
+  
+  // initialize solution data with default arguments
+  DLL_HEADER void Ng_InitSolutionData (Ng_SolutionData * soldata);
+  // set solution data
+  DLL_HEADER void Ng_SetSolutionData (Ng_SolutionData * soldata);
+  /// delete gridfunctions
+  DLL_HEADER void Ng_ClearSolutionData();
+  // redraw 
+  DLL_HEADER void Ng_Redraw();
+  //
+  DLL_HEADER void Ng_SetVisualizationParameter (const char * name, 
+                                                const char * value);
+  
+
+  // number of periodic vertices  
+  DLL_HEADER int Ng_GetNPeriodicVertices (int idnr);
+  // pairs should be an integer array of 2*npairs
+  DLL_HEADER void Ng_GetPeriodicVertices (int idnr, int * pairs); 
+
+  // number of periodic edges  
+  DLL_HEADER int Ng_GetNPeriodicEdges (int idnr);
+  // pairs should be an integer array of 2*npairs
+  DLL_HEADER void Ng_GetPeriodicEdges (int idnr, int * pairs); 
+
+  DLL_HEADER void RunParallel ( void * (*fun)(void *), void * in);
+
+  DLL_HEADER void Ng_PushStatus (const char * str);
+  DLL_HEADER void Ng_PopStatus ();
+  DLL_HEADER void Ng_SetThreadPercentage (double percent);
+  DLL_HEADER void Ng_GetStatus (char ** str, double & percent);
+
+  DLL_HEADER void Ng_SetTerminate(void);
+  DLL_HEADER void Ng_UnSetTerminate(void);
+  DLL_HEADER int Ng_ShouldTerminate(void);
+  DLL_HEADER void Ng_SetRunning(int flag);
+  DLL_HEADER int Ng_IsRunning();
+  
+  //// added by Roman Stainko ....
+  DLL_HEADER int Ng_GetVertex_Elements( int vnr, int* elems);
+  DLL_HEADER int Ng_GetVertex_SurfaceElements( int vnr, int* elems );
+  DLL_HEADER int Ng_GetVertex_NElements( int vnr );
+  DLL_HEADER int Ng_GetVertex_NSurfaceElements( int vnr );
+
+
+#ifdef SOCKETS
+  int Ng_SocketClientOpen( const int port, const char * host );
+  void Ng_SocketClientWrite( const char * write, char ** reply);
+  void Ng_SocketClientClose ( void );
+  void Ng_SocketClientGetServerHost ( const int number, char ** host );
+  void Ng_SocketClientGetServerPort ( const int number, int * port );
+  void Ng_SocketClientGetServerClientID ( const int number, int * id );
+#endif
+
+  DLL_HEADER void Ng_InitPointCurve(double red, double green, double blue);
+  DLL_HEADER void Ng_AddPointCurvePoint(const double * point);
+
+
+#ifdef PARALLEL
+  void Ng_SetElementPartition ( int elnr, int part );
+  int  Ng_GetElementPartition ( int elnr );
+#endif
+
+  DLL_HEADER void Ng_SaveMesh ( const char * meshfile );
+  DLL_HEADER void Ng_Bisect ( const char * refinementfile );
+
+  // if qualityloss is not equal to NULL at input, a (1-based) list of qualitylosses (due to projection)
+  // is saved in *qualityloss, its size is the return value
+  DLL_HEADER int Ng_Bisect_WithInfo ( const char * refinementfile, double ** qualityloss);
+
+  typedef void * Ng_Mesh;
+  DLL_HEADER Ng_Mesh Ng_SelectMesh (Ng_Mesh mesh);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
+
+
+
+
+/*
+  The new node interface ...
+  it is 0-based !
+ */
+
+extern "C" {
+  
+  /*
+    number of nodes of type nt
+    nt = 0 is Vertex
+    nt = 1 is Edge
+    nt = 2 is Face
+    nt = 3 is Cell
+   */
+  DLL_HEADER int Ng_GetNNodes (int nt);
+
+  /*
+    closure nodes of node (nt, nodenr):
+    nodeset is bit-coded, bit 0 includes Vertices, bit 1 edges, etc
+    E.g., nodeset = 6 includes edge and face nodes
+    nodes consists of pairs of integers (nodetype, nodenr) 
+    return value is number of nodes
+   */
+  DLL_HEADER int Ng_GetClosureNodes (int nt, int nodenr, int nodeset, int * nodes);
+
+  
+  /*
+    number of dim-dimensional elements 
+    dim = 3 ... volume elements
+    dim = 2 ... surface elements
+    dim = 1 ... segments
+    dim = 0 ... not available
+  */
+  DLL_HEADER int Ng_GetNElements (int dim);
+
+  /*
+    closure nodes of dim-dimensional element elmentnr:
+    nodeset is bit-coded, bit 0 includes Vertices, bit 1 edges, etc
+    E.g., nodeset = 6 includes edge and face nodes
+    nodes consists of pairs of integers (nodetype, nodenr) 
+    return value is number of nodes
+   */
+  DLL_HEADER int Ng_GetElementClosureNodes (int dim, int elementnr, int nodeset, int * nodes);
+
+
+  struct Ng_Tcl_Interp;
+  typedef int (Ng_Tcl_CmdProc) (Ng_Tcl_Interp *interp, int argc, const char *argv[]);
+
+  DLL_HEADER void Ng_Tcl_CreateCommand (Ng_Tcl_Interp * interp, 
+                                        const char * cmdName, Ng_Tcl_CmdProc * proc);
+
+  void Ng_Tcl_SetResult (Ng_Tcl_Interp * interp, const char * result);
+}
+
+
+
+
+
+#ifdef __cplusplus
+#include <iostream>
+namespace netgen 
+{
+  DLL_HEADER extern std::ostream * testout;
+  DLL_HEADER extern int printmessage_importance;
+}
+
+#endif
+
diff --git a/contrib/Netgen/libsrc/include/nginterface_v2.hpp b/contrib/Netgen/libsrc/include/nginterface_v2.hpp
new file mode 100644
index 0000000000..957b7b4dce
--- /dev/null
+++ b/contrib/Netgen/libsrc/include/nginterface_v2.hpp
@@ -0,0 +1,175 @@
+#ifndef NGINTERFACE_V2
+#define NGINTERFACE_V2
+
+
+/**************************************************************************/
+/* File:   nginterface_v2.hpp                                             */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   May  09                                                        */
+/**************************************************************************/
+
+/*
+  C++ interface to Netgen
+*/
+
+
+namespace netgen
+{
+  class Ng_Element
+  {
+
+    class Ng_Points
+    {
+    public:
+      int num;
+      const int * ptr;
+  
+      int Size() const { return num; }
+      int operator[] (int i) const { return ptr[i]-1; }
+    };
+
+
+    class Ng_Vertices
+    {
+    public:
+      int num;
+      const int * ptr;
+  
+      int Size() const { return num; }
+      int operator[] (int i) const { return ptr[i]-1; }
+    };
+
+    class Ng_Edges
+    {
+    public:
+      int num;
+      const int * ptr;
+  
+      int Size() const { return num; }
+      int operator[] (int i) const { return abs (ptr[i])-1; }
+    };
+
+    class Ng_Faces
+    {
+    public:
+      int num;
+      const int * ptr;
+  
+      int Size() const { return num; }
+      int operator[] (int i) const { return (ptr[i]-1) / 8; }
+    };
+
+  public:
+    NG_ELEMENT_TYPE type;
+    NG_ELEMENT_TYPE GetType() const { return type; }
+    
+    Ng_Points points;      // all points
+    Ng_Vertices vertices;
+    Ng_Edges edges;
+    Ng_Faces faces;
+  };
+
+
+
+
+  template <int DIM> 
+  DLL_HEADER int Ng_GetNElements ();
+
+  template <int DIM> 
+  DLL_HEADER Ng_Element Ng_GetElement (int nr);
+
+
+  
+  class Ng_Point
+  {
+  public:
+    double * pt;
+    double operator[] (int i)
+    { return pt[i]; }
+  };
+
+  DLL_HEADER Ng_Point Ng_GetPoint (int nr);
+
+
+
+
+  template <int DIM> class Ng_Node;
+
+  template <>
+  class Ng_Node<1>
+  {
+    class Ng_Vertices
+    {
+    public:
+      const int * ptr;
+  
+      int Size() const { return 2; }
+      int operator[] (int i) const { return ptr[i]-1; }
+    };
+
+
+  public:
+    Ng_Vertices vertices;
+  };
+
+
+
+  template <>
+  class Ng_Node<2>
+  {
+    class Ng_Vertices
+    {
+    public:
+      int nv;
+      const int * ptr;
+  
+      int Size() const { return nv; }
+      int operator[] (int i) const { return ptr[i]-1; }
+    };
+
+    class Ng_Edges
+    {
+    public:
+      int ned;
+      const int * ptr;
+  
+      int Size() const { return ned; }
+      int operator[] (int i) const { return ptr[i]-1; }
+    };
+
+
+  public:
+    Ng_Vertices vertices;
+    Ng_Edges edges;
+  };
+
+
+
+    
+  template <int DIM>
+  DLL_HEADER Ng_Node<DIM> Ng_GetNode (int nr);
+  
+
+  template <int DIM>
+  DLL_HEADER int Ng_GetNNodes ();
+
+
+
+
+
+  /// Curved Elements:
+  /// xi..... DIM_EL local coordinates
+  /// sxi ... step xi
+  /// x ..... DIM_SPACE global coordinates
+  /// dxdxi...DIM_SPACE x DIM_EL Jacobian matrix (row major storage)
+  template <int DIM_EL, int DIM_SPACE> 
+  DLL_HEADER void Ng_MultiElementTransformation (int elnr, int npts,
+                                                 const double * xi, size_t sxi,
+                                                 double * x, size_t sx,
+                                                 double * dxdxi, size_t sdxdxi);
+  
+  template <int DIM> 
+  DLL_HEADER int Ng_GetElementIndex (int nr);
+}
+#endif
+
diff --git a/contrib/Netgen/libsrc/include/occgeom.hpp b/contrib/Netgen/libsrc/include/occgeom.hpp
new file mode 100644
index 0000000000..af258e0df0
--- /dev/null
+++ b/contrib/Netgen/libsrc/include/occgeom.hpp
@@ -0,0 +1 @@
+#include "../occ/occgeom.hpp"
diff --git a/contrib/Netgen/libsrc/include/opti.hpp b/contrib/Netgen/libsrc/include/opti.hpp
new file mode 100644
index 0000000000..5792d70f2a
--- /dev/null
+++ b/contrib/Netgen/libsrc/include/opti.hpp
@@ -0,0 +1 @@
+#include "../linalg/opti.hpp"
diff --git a/contrib/Netgen/libsrc/include/parallel.hpp b/contrib/Netgen/libsrc/include/parallel.hpp
new file mode 100644
index 0000000000..4ba662f810
--- /dev/null
+++ b/contrib/Netgen/libsrc/include/parallel.hpp
@@ -0,0 +1 @@
+#include "../parallel/parallel.hpp"
diff --git a/contrib/Netgen/libsrc/include/parallelinterface.hpp b/contrib/Netgen/libsrc/include/parallelinterface.hpp
new file mode 100644
index 0000000000..4fb8b8e2ec
--- /dev/null
+++ b/contrib/Netgen/libsrc/include/parallelinterface.hpp
@@ -0,0 +1,49 @@
+gibt's nicht mehr
+
+
+#ifndef FILE_PARALLELINTERFACE
+#define FILE_PARALLELINTERFACE
+
+#ifdef PARALLEL
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+  // this interface is 0-base  !!
+
+
+  int NgPar_GetLoc2Glob_VolEl ( int locnum );
+
+  // int NgPar_GetDistantNodeNums ( int nt, int locnum, int * procs, int * distnum);
+
+  // number on distant processor 
+
+  // gibt anzahl an distant pnums zurueck
+  // * pnums entspricht ARRAY<int[2] >
+  int NgPar_GetDistantNodeNums ( int nodetype, int locnum, int * pnums );
+  int NgPar_GetNDistantNodeNums ( int nodetype, int locnum );
+
+  int NgPar_GetDistantPNum ( int proc, int locnum ) ;
+  int NgPar_GetDistantEdgeNum ( int proc, int locnum ) ;
+  int NgPar_GetDistantFaceNum ( int proc, int locnum ) ;
+  int NgPar_GetDistantElNum ( int proc, int locnum );
+
+  bool NgPar_IsExchangeFace ( int fnr ) ;
+  bool NgPar_IsExchangeVert ( int vnum );
+  bool NgPar_IsExchangeEdge ( int ednum );
+  bool NgPar_IsExchangeElement ( int elnum );
+
+  void NgPar_PrintParallelMeshTopology ();
+  bool NgPar_IsElementInPartition ( int elnum, int dest );
+
+  bool NgPar_IsGhostFace ( int facenum );
+  bool NgPar_IsGhostEdge ( int edgenum );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+#endif
diff --git a/contrib/Netgen/libsrc/include/stlgeom.hpp b/contrib/Netgen/libsrc/include/stlgeom.hpp
new file mode 100644
index 0000000000..f1eea264e1
--- /dev/null
+++ b/contrib/Netgen/libsrc/include/stlgeom.hpp
@@ -0,0 +1 @@
+#include <../stlgeom/stlgeom.hpp>
diff --git a/contrib/Netgen/libsrc/include/visual.hpp b/contrib/Netgen/libsrc/include/visual.hpp
new file mode 100644
index 0000000000..f026f5a458
--- /dev/null
+++ b/contrib/Netgen/libsrc/include/visual.hpp
@@ -0,0 +1 @@
+#include "../visualization/visual.hpp"
diff --git a/contrib/Netgen/libsrc/interface/Makefile.am b/contrib/Netgen/libsrc/interface/Makefile.am
new file mode 100644
index 0000000000..013797957c
--- /dev/null
+++ b/contrib/Netgen/libsrc/interface/Makefile.am
@@ -0,0 +1,12 @@
+noinst_HEADERS = writeuser.hpp
+
+AM_CPPFLAGS = -I$(top_srcdir)/libsrc/include -I$(top_srcdir)/libsrc/interface  $(MPI_INCLUDES) $(TCL_INCLUDES) -DOPENGL
+METASOURCES = AUTO
+lib_LTLIBRARIES = libinterface.la
+libinterface_la_SOURCES = nginterface.cpp nginterface_v2.cpp \
+	read_fnf_mesh.cpp readtetmesh.cpp readuser.cpp writeabaqus.cpp writediffpack.cpp \
+	writedolfin.cpp writeelmer.cpp writefeap.cpp writefluent.cpp writegmsh.cpp writejcm.cpp \
+	writepermas.cpp writetecplot.cpp writetet.cpp writetochnog.cpp writeuser.cpp \
+	wuchemnitz.cpp writegmsh2.cpp writeOpenFOAM15x.cpp 
+
+
diff --git a/contrib/Netgen/libsrc/interface/nginterface.cpp b/contrib/Netgen/libsrc/interface/nginterface.cpp
new file mode 100644
index 0000000000..a5f7e7a145
--- /dev/null
+++ b/contrib/Netgen/libsrc/interface/nginterface.cpp
@@ -0,0 +1,2448 @@
+#include <mystdlib.h>
+
+#include <meshing.hpp>
+#include <csg.hpp>
+
+
+#ifdef SOCKETS
+#include "../sockets/sockets.hpp"
+#endif
+
+#ifndef NOTCL
+#include <visual.hpp>
+#endif
+
+
+#include "nginterface.h"
+#include "../visualization/soldata.hpp"
+
+
+#ifdef _MSC_VER
+// Philippose - 30/01/2009
+// MSVC Express Edition Support
+#ifdef MSVC_EXPRESS
+
+// #include <pthread.h>
+
+  static pthread_t meshingthread;
+  void RunParallel ( void * (*fun)(void *), void * in)
+  {
+    if (netgen::mparam.parthread) //  && (ntasks == 1) )
+     {
+	     pthread_attr_t attr;
+	     pthread_attr_init (&attr);
+	     // the following call can be removed if not available:
+	     pthread_attr_setstacksize(&attr, 1000000);
+	     //pthread_create (&meshingthread, &attr, fun, NULL);
+	     pthread_create (&meshingthread, &attr, fun, in);
+     }
+     else
+       fun (in);
+  }
+
+#else // Using MS VC++ Standard / Enterprise / Professional edition
+
+  // Afx - Threads need different return - value:
+
+  static void* (*sfun)(void *);
+  unsigned int fun2 (void * val)
+  {
+    sfun (val);
+    return 0;
+  }
+
+  void RunParallel ( void* (*fun)(void *), void * in)
+  {
+    sfun = fun;
+    if (netgen::mparam.parthread)
+      AfxBeginThread (fun2, in);
+    //AfxBeginThread (fun2, NULL);
+    else
+      fun (in);
+  }
+
+#endif // #ifdef MSVC_EXPRESS
+
+#else  // For #ifdef _MSC_VER
+
+// #include <pthread.h>
+ 
+  static pthread_t meshingthread;
+  void RunParallel ( void * (*fun)(void *), void * in)
+  {
+    bool parthread = netgen::mparam.parthread;
+
+#ifdef PARALLEL
+    int provided;
+    MPI_Query_thread(&provided);
+    if (provided < 3)
+      if (netgen::ntasks > 1) parthread = false;
+    // cout << "runparallel = " << parthread << endl;
+#endif
+
+    if (parthread)
+      {
+	pthread_attr_t attr;
+	pthread_attr_init (&attr);
+	// the following call can be removed if not available:
+	pthread_attr_setstacksize(&attr, 1000000);
+	//pthread_create (&meshingthread, &attr, fun, NULL);
+	pthread_create (&meshingthread, &attr, fun, in);
+      }
+    else
+      fun (in);
+  }
+
+#endif // #ifdef _MSC_VER
+
+
+
+
+
+
+namespace netgen
+{
+#include "writeuser.hpp"
+
+  MeshingParameters mparam;
+
+  // global variable mesh (should not be used in libraries)
+  AutoPtr<Mesh> mesh;
+  NetgenGeometry * ng_geometry = new NetgenGeometry;
+
+  // extern NetgenGeometry * ng_geometry;
+  // extern AutoPtr<Mesh> mesh;
+
+#ifndef NOTCL
+  extern Tcl_Interp * tcl_interp;
+#endif
+
+
+#ifdef OPENGL 
+  extern VisualSceneSolution vssolution;
+#endif
+  extern CSGeometry * ParseCSG (istream & istr);
+
+#ifdef SOCKETS
+  extern AutoPtr<ClientSocket> clientsocket;
+  //extern Array< AutoPtr < ServerInfo > > servers;
+  extern Array< ServerInfo* > servers;
+#endif
+
+  
+}
+
+
+using namespace netgen;
+
+
+void Ng_LoadGeometry (const char * filename)
+{
+
+  for (int i = 0; i < geometryregister.Size(); i++)
+    {
+      NetgenGeometry * hgeom = geometryregister[i]->Load (filename);
+      if (hgeom)
+	{
+	  delete ng_geometry;
+	  ng_geometry = hgeom;
+	  
+	  mesh.Reset();
+	  return;
+	}
+    }
+
+  // he: if filename is empty, return
+  // can be used to reset geometry
+  if (strcmp(filename,"")==0) 
+    {
+      delete ng_geometry;
+      ng_geometry = new NetgenGeometry();
+      return;
+    }
+
+  cerr << "cannot load geometry '" << filename << "'" << endl;
+}                          
+
+
+void Ng_LoadMeshFromStream ( istream & input )
+{
+  mesh.Reset (new Mesh());
+  mesh -> Load(input);
+  
+  for (int i = 0; i < geometryregister.Size(); i++)
+    {
+      NetgenGeometry * hgeom = geometryregister[i]->LoadFromMeshFile (input);
+      if (hgeom)
+	{
+	  delete ng_geometry;
+	  ng_geometry = hgeom;
+	  break;
+	}
+    }
+
+
+#ifdef LOADOLD
+  if(input.good())
+    {
+      string auxstring;
+      input >> auxstring;
+      if(auxstring == "csgsurfaces")
+	{
+	  /*
+	    if (geometry)
+            {
+	    geometry.Reset (new CSGeometry (""));
+            }
+	    if (stlgeometry)
+	    {
+	    delete stlgeometry;
+	    stlgeometry = NULL;
+	    }
+	    #ifdef OCCGEOMETRY
+	    if (occgeometry)
+	    {
+	    delete occgeometry;
+	    occgeometry = NULL;
+	    }
+	    #endif
+	    #ifdef ACIS
+	    if (acisgeometry)
+	    {
+	    delete acisgeometry;
+	    acisgeometry = NULL;
+	    }
+	    #endif
+	    geometry2d.Reset (0);
+	  */
+ 	  // geometry -> LoadSurfaces(input);
+	  CSGeometry * geometry = new CSGeometry ("");
+	  geometry -> LoadSurfaces(input);
+
+	  delete ng_geometry;
+	  ng_geometry = geometry;
+	}
+    }
+#endif 
+}
+
+
+
+
+void Ng_LoadMesh (const char * filename)
+{
+  if ( (strlen (filename) > 4) &&
+       strcmp (filename + (strlen (filename)-4), ".vol") != 0 )
+    {
+      mesh.Reset (new Mesh());
+      ReadFile(*mesh,filename);
+
+      //mesh->SetGlobalH (mparam.maxh);
+      //mesh->CalcLocalH();
+      return;
+    }
+
+  ifstream infile(filename);
+  Ng_LoadMeshFromStream(infile);
+}
+
+void Ng_LoadMeshFromString (const char * mesh_as_string)
+{
+  istringstream instream(mesh_as_string);
+  Ng_LoadMeshFromStream(instream);
+}
+  
+
+
+
+int Ng_GetDimension ()
+{
+  return (mesh) ? mesh->GetDimension() : -1;
+}
+
+int Ng_GetNP ()
+{
+  return (mesh) ? mesh->GetNP() : 0;
+}
+
+int Ng_GetNV ()
+{
+  return (mesh) ? mesh->GetNV() : 0;
+}
+
+int Ng_GetNE ()
+{
+  if(!mesh) return 0;
+  if (mesh->GetDimension() == 3)
+    return mesh->GetNE();
+  else
+    return mesh->GetNSE();
+}
+
+int Ng_GetNSE ()
+{
+  if(!mesh) return 0;
+  if (mesh->GetDimension() == 3)
+    return mesh->GetNSE();
+  else
+    return mesh->GetNSeg();
+}
+
+void Ng_GetPoint (int pi, double * p)
+{
+  if (pi < 1 || pi > mesh->GetNP())
+    {
+      if (printmessage_importance>0)
+        cout << "Ng_GetPoint: illegal point " << pi << endl;
+      return;
+    }
+
+  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:
+                if (printmessage_importance>0)
+                  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:
+	      {
+                if (printmessage_importance>0)
+                  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
+    {
+      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;
+    }
+}
+
+void Ng_SetElementIndex(const int ei, const int index)
+{
+  mesh->VolumeElement(ei).SetIndex(index);
+}
+
+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;
+    }
+  // add astrid
+  else
+    {
+      int ind = mesh->SurfaceElement(ei).GetIndex();
+      ind = mesh->GetFaceDescriptor(ind).BCProperty();
+      const char * mat = mesh->GetMaterial ( ind );
+      if (mat)
+	return const_cast<char*> (mat);
+      else
+	return empty;
+    }
+  return 0;
+}
+
+char * Ng_GetDomainMaterial (int dom)
+{
+  static char empty[] = "";
+  // astrid
+  if ( 1 ) // mesh->GetDimension() == 3)
+    {
+      const char * mat = mesh->GetMaterial(dom);
+      if (mat)
+	return const_cast<char*> (mat);
+      else 
+	return empty;      
+    }
+
+  return 0;
+}
+
+int Ng_GetUserDataSize (char * id)
+{
+  Array<double> da;
+  mesh->GetUserData (id, da);
+  return da.Size();
+}
+
+void Ng_GetUserData (char * id, double * data)
+{
+  Array<double> da;
+  mesh->GetUserData (id, da);
+  for (int i = 0; i < da.Size(); i++)
+    data[i] = da[i];
+}
+
+
+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[2] < 0)
+	{
+	  epi[0] = seg[0];
+	  epi[1] = seg[1];
+	  
+	  if (np) *np = 2;
+	  return NG_SEGM;
+	}
+      else
+	{
+	  epi[0] = seg[0];
+	  epi[1] = seg[1];
+	  epi[2] = seg[2];
+
+	  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;
+}
+
+int Ng_GetSurfaceElementSurfaceNumber (int ei)
+{
+  if (mesh->GetDimension() == 3)
+    return mesh->GetFaceDescriptor(mesh->SurfaceElement(ei).GetIndex()).SurfNr();
+  else
+    return mesh->LineSegment(ei).si;
+}
+int Ng_GetSurfaceElementFDNumber (int ei)
+{
+  if (mesh->GetDimension() == 3)
+    return mesh->SurfaceElement(ei).GetIndex();
+  else
+    return -1;
+}
+
+
+char * Ng_GetSurfaceElementBCName (int ei)
+{
+  if ( mesh->GetDimension() == 3 )
+    return const_cast<char *>(mesh->GetFaceDescriptor(mesh->SurfaceElement(ei).GetIndex()).GetBCName().c_str());
+  else
+    return const_cast<char *>(mesh->LineSegment(ei).GetBCName().c_str());
+}
+
+
+// Inefficient (but maybe safer) version:
+//void Ng_GetSurfaceElementBCName (int ei, char * name)
+//{
+//  if ( mesh->GetDimension() == 3 )
+//      strcpy(name,mesh->GetFaceDescriptor(mesh->SurfaceElement(ei).GetIndex()).GetBCName().c_str());
+//  else
+//      strcpy(name,mesh->LineSegment(ei).GetBCName().c_str());
+//}
+
+char * Ng_GetBCNumBCName (int bcnr)
+{
+  return const_cast<char *>(mesh->GetBCName(bcnr).c_str());
+}
+
+
+// Inefficient (but maybe safer) version:
+//void Ng_GetBCNumBCName (int bcnr, char * name)
+//{
+//    strcpy(name,mesh->GetBCName(bcnr).c_str());
+//}
+
+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();
+      
+      (*testout) << "surfi = " << surfi << endl;
+#ifdef OCCGEOMETRYxxx
+      OCCGeometry * occgeometry = dynamic_cast<OCCGeometry*> (ng_geometry);
+      if (occgeometry)
+	{
+	  PointGeomInfo gi = mesh->SurfaceElement(sei).GeomInfoPi(locpi);
+	  occgeometry->GetSurface (surfi).GetNormalVector(p, gi, n);
+	  nv[0] = n(0);
+	  nv[1] = n(1);
+	  nv[2] = n(2);
+	}
+#endif
+      CSGeometry * geometry = dynamic_cast<CSGeometry*> (ng_geometry);
+      if (geometry)
+	{
+	  n = geometry->GetSurface (surfi) -> GetNormalVector(p);
+	  nv[0] = n(0);
+	  nv[1] = n(1);
+	  nv[2] = n(2);
+	}
+    }
+}
+
+
+
+void Ng_SetPointSearchStartElement(const int el)
+{
+  mesh->SetPointSearchStartElement(el);
+}
+
+
+int Ng_FindElementOfPoint (double * p, double * lami, int build_searchtree, 
+			   const int * const indices, const int numind)
+  
+{
+  Array<int> * dummy(NULL);
+  int ind = -1;
+
+  if(indices != NULL)
+    {
+      dummy = new Array<int>(numind);
+      for(int i=0; i<numind; i++) (*dummy)[i] = indices[i];
+    }
+
+  if (mesh->GetDimension() == 3)
+    {
+      Point3d p3d(p[0], p[1], p[2]);
+      ind = 
+	mesh->GetElementOfPoint(p3d, lami, dummy, build_searchtree != 0);
+    }
+  else
+    {
+      double lam3[3];
+      Point3d p2d(p[0], p[1], 0);
+      ind = 
+	mesh->GetElementOfPoint(p2d, lam3, dummy, build_searchtree != 0);
+
+      if (ind > 0)
+	{
+	  if(mesh->SurfaceElement(ind).GetType()==QUAD)
+	    {
+	      lami[0] = lam3[0];
+	      lami[1] = lam3[1];
+	    }
+	  else 
+	    {
+	      lami[0] = 1-lam3[0]-lam3[1];
+	      lami[1] = lam3[0];
+	    }
+	}
+    }
+
+  delete dummy;
+
+  return ind;
+}
+
+int Ng_FindSurfaceElementOfPoint (double * p, double * lami, int build_searchtree, 
+				  const int * const indices, const int numind)
+  
+{
+  Array<int> * dummy(NULL);
+  int ind = -1;
+
+  if(indices != NULL)
+    {
+      dummy = new Array<int>(numind);
+      for(int i=0; i<numind; i++) (*dummy)[i] = indices[i];
+    }
+
+  if (mesh->GetDimension() == 3)
+    {
+      Point3d p3d(p[0], p[1], p[2]);
+      ind = 
+	mesh->GetSurfaceElementOfPoint(p3d, lami, dummy, build_searchtree != 0);
+    }
+  else
+    {
+      //throw NgException("FindSurfaceElementOfPoint for 2D meshes not yet implemented");
+      cerr << "FindSurfaceElementOfPoint for 2D meshes not yet implemented" << endl;
+    }
+
+  delete dummy;
+
+  return ind;
+}
+
+
+int Ng_IsElementCurved (int ei)
+{
+  if (mesh->GetDimension() == 2)
+    return mesh->GetCurvedElements().IsSurfaceElementCurved (ei-1);
+  else
+    return mesh->GetCurvedElements().IsElementCurved (ei-1);
+}
+
+
+int Ng_IsSurfaceElementCurved (int sei)
+{
+  if (mesh->GetDimension() == 2)
+    return mesh->GetCurvedElements().IsSegmentCurved (sei-1);
+  else
+    return mesh->GetCurvedElements().IsSurfaceElementCurved (sei-1);
+}
+
+
+
+
+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);
+
+      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]);
+      Point<3> xg;
+      Mat<3,3> dx;
+
+      mesh->GetCurvedElements().CalcElementTransformation (xl, ei-1, xg, dx);
+
+      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);
+	    }
+	}
+    }
+}
+
+
+#ifdef OLD
+void Ng_GetBufferedElementTransformation (int ei, const double * xi, 
+                                          double * x, double * dxdxi,
+                                          void * buffer, int buffervalid)
+{
+  // buffer = 0;
+  // buffervalid = 0;
+  if (mesh->GetDimension() == 2)
+    {
+      return Ng_GetElementTransformation (ei, xi, x, dxdxi);
+    }
+  else
+    {
+      mesh->GetCurvedElements().CalcElementTransformation (reinterpret_cast<const Point<3> &> (*xi), 
+                                                           ei-1, 
+                                                           reinterpret_cast<Point<3> &> (*x), 
+                                                           reinterpret_cast<Mat<3,3> &> (*dxdxi), 
+                                                           buffer, (buffervalid != 0));
+
+      /*
+	Point<3> xl(xi[0], xi[1], xi[2]);
+	Point<3> xg;
+	Mat<3,3> dx;
+	// buffervalid = 0;
+	mesh->GetCurvedElements().CalcElementTransformation (xl, ei-1, xg, dx, buffer, buffervalid);
+
+	// 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);
+	}
+	}
+      */
+    }
+}
+#endif
+
+
+
+
+
+
+void Ng_GetMultiElementTransformation (int ei, int n,
+                                       const double * xi, size_t sxi,
+                                       double * x, size_t sx,
+                                       double * dxdxi, size_t sdxdxi)
+{
+  if (mesh->GetDimension() == 2)
+    mesh->GetCurvedElements().CalcMultiPointSurfaceTransformation<2> (ei-1, n, xi, sxi, x, sx, dxdxi, sdxdxi);
+  else
+    mesh->GetCurvedElements().CalcMultiPointElementTransformation (ei-1, n, xi, sxi, x, sx, dxdxi, sdxdxi);
+}
+
+
+
+void Ng_GetSurfaceElementTransformation (int sei, const double * xi, 
+					 double * x, double * dxdxi)
+{
+  if (mesh->GetDimension() == 2)
+    {
+      Point<3> xg;
+      Vec<3> dx;
+
+      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;
+      
+      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);
+	    }
+	}
+    }
+}
+
+
+
+
+
+int Ng_GetSegmentIndex (int ei)
+{
+  const Segment & seg = mesh->LineSegment (ei);
+  return seg.edgenr;
+}
+
+
+NG_ELEMENT_TYPE Ng_GetSegment (int ei, int * epi, int * np)
+{
+  const Segment & seg = mesh->LineSegment (ei);
+  
+  epi[0] = seg[0];
+  epi[1] = seg[1];
+
+  if (seg[2] < 0)
+    {
+      if (np) *np = 2;
+      return NG_SEGM;
+    }
+  else
+    {
+      epi[2] = seg[2];
+      if (np) *np = 3;
+      return NG_SEGM3;
+    }
+}
+
+
+
+
+
+
+void Ng_GetSurfaceElementNeighbouringDomains(const int selnr, int & in, int & out)
+{
+  if ( mesh->GetDimension() == 3 )
+    {
+      in = mesh->GetFaceDescriptor(mesh->SurfaceElement(selnr).GetIndex()).DomainIn();
+      out = mesh->GetFaceDescriptor(mesh->SurfaceElement(selnr).GetIndex()).DomainOut();
+    }
+  else
+    {
+      in = mesh -> LineSegment(selnr) . domin;
+      out = mesh -> LineSegment(selnr) . domout;
+    }
+}
+
+
+#ifdef PARALLEL
+// Is Element ei an element of this processor ??
+bool Ng_IsGhostEl (int ei)
+{
+  return false;
+  /*
+  if ( mesh->GetDimension() == 3 )
+    return mesh->VolumeElement(ei).IsGhost();
+  else
+    return false;
+  */
+}
+
+void Ng_SetGhostEl(const int ei, const bool aisghost )
+{
+  ;
+  /*
+  if ( mesh -> GetDimension () == 3 )
+    mesh -> VolumeElement(ei).SetGhost (aisghost);
+  */
+}
+
+bool Ng_IsGhostSEl (int ei)
+{
+  return false;
+  /*
+  if ( mesh -> GetDimension () == 3 )
+    return mesh->SurfaceElement(ei).IsGhost();
+  else
+    return false;
+  */
+}
+
+void Ng_SetGhostSEl(const int ei, const bool aisghost )
+{
+  ;
+  /*
+  if ( mesh -> GetDimension () == 3 )
+    mesh -> SurfaceElement(ei).SetGhost (aisghost);
+  */
+}
+
+
+bool Ng_IsGhostVert ( int pnum )
+{
+  return false;
+  // return mesh -> Point ( pnum ).IsGhost() ;  
+}
+bool Ng_IsGhostEdge ( int ednum )
+{
+  return false;
+  // return mesh -> GetParallelTopology() . IsGhostEdge ( ednum ); 
+}
+
+bool Ng_IsGhostFace ( int fanum )
+{
+  return false;
+  // return mesh -> GetParallelTopology() . IsGhostFace ( fanum ); 
+}
+
+// void Ng_SetGhostVert ( const int pnum, const bool aisghost );
+// void Ng_SetGhostEdge ( const int ednum, const bool aisghost );
+// void Ng_SetGhostFace ( const int fanum, const bool aisghost );
+
+
+bool Ng_IsExchangeEl ( int elnum )
+{ return mesh -> GetParallelTopology() . IsExchangeElement ( elnum ); }
+
+bool Ng_IsExchangeSEl ( int selnum )
+{ return mesh -> GetParallelTopology() . IsExchangeSEl ( selnum ); }
+
+void Ng_UpdateOverlap()
+{ 
+  ; // mesh->UpdateOverlap(); 
+}
+
+int Ng_Overlap ()
+{ 
+  return 0;
+  // return mesh->GetParallelTopology() . Overlap(); 
+}
+
+
+
+ int NgPar_GetLoc2Glob_VolEl ( int locnum )
+  { 
+    return mesh -> GetParallelTopology().GetLoc2Glob_VolEl ( locnum+1) -1; 
+  }
+
+  // gibt anzahl an distant pnums zurueck
+  // * pnums entspricht ARRAY<int[2] >
+  int NgPar_GetDistantNodeNums ( int nodetype, int locnum, int * distnums )
+  {
+    int size;
+    switch ( nodetype )
+      {
+      case 0:
+	size = mesh->GetParallelTopology().GetDistantPNums( locnum+1, distnums ); 
+	break;
+      case 1:
+	size = mesh->GetParallelTopology().GetDistantEdgeNums( locnum+1, distnums ); 
+	break;
+      case 2:
+	size = mesh->GetParallelTopology().GetDistantFaceNums( locnum+1, distnums );
+	break;
+      case 3:
+	size = mesh->GetParallelTopology().GetDistantElNums( locnum+1, distnums );
+	break;
+      default:
+	cerr << "NgPar_GetDistantNodeNums() Unknown nodetype " << nodetype << endl;
+	size = -1;
+      }
+    // 0 - based 
+    for ( int i = 0; i < size; i++ )
+      distnums[2*i+1]--;
+
+    return size;
+  }
+
+  int NgPar_GetNDistantNodeNums ( int nodetype, int locnum )
+  {
+    switch ( nodetype )
+      {
+      case 0:
+	return mesh->GetParallelTopology().GetNDistantPNums( locnum+1 );
+      case 1:
+	return mesh->GetParallelTopology().GetNDistantEdgeNums( locnum+1 );
+      case 2:
+	return mesh->GetParallelTopology().GetNDistantFaceNums( locnum+1 );
+      case 3:
+	return mesh->GetParallelTopology().GetNDistantElNums( locnum+1 );
+      }
+    return -1;
+  }
+
+  int NgPar_GetDistantPNum ( int proc, int locpnum )  
+  { 
+    return mesh->GetParallelTopology().GetDistantPNum( proc, locpnum+1) - 1; 
+  }
+
+  int NgPar_GetDistantEdgeNum ( int proc, int locpnum )  
+  { 
+    return mesh->GetParallelTopology().GetDistantEdgeNum( proc, locpnum+1) - 1; 
+  }
+
+  int NgPar_GetDistantFaceNum ( int proc, int locpnum )  
+  { 
+    return mesh->GetParallelTopology().GetDistantFaceNum (proc, locpnum+1 ) - 1; 
+  }
+
+  int NgPar_GetDistantElNum ( int proc, int locelnum )
+  { 
+    return mesh->GetParallelTopology().GetDistantElNum (proc, locelnum+1 ) - 1; 
+  }
+
+  bool NgPar_IsExchangeFace ( int fnr ) 
+  { 
+    return (mesh->GetParallelTopology().GetNDistantFaceNums( fnr+1 ) > 0);
+    // return mesh->GetParallelTopology().IsExchangeFace ( fnr+1 ); 
+  }
+
+  bool NgPar_IsExchangeVert ( int vnum )
+  { 
+    return (mesh->GetParallelTopology().GetNDistantPNums( vnum+1 ) > 0);
+    // return mesh->GetParallelTopology().IsExchangeVert ( vnum+1 ); 
+  }
+
+  bool NgPar_IsExchangeEdge ( int ednum )  
+  { 
+    return (mesh->GetParallelTopology().GetNDistantEdgeNums( ednum+1 ) > 0);
+    // return mesh->GetParallelTopology().IsExchangeEdge ( ednum+1 ); 
+  }
+
+  bool NgPar_IsExchangeElement ( int elnum )  
+  { 
+    return (mesh->GetParallelTopology().GetNDistantElNums( elnum+1 ) > 0);
+    // return mesh->GetParallelTopology().IsExchangeElement ( elnum+1 ); 
+  }
+
+
+  void NgPar_PrintParallelMeshTopology ()
+  { 
+    mesh -> GetParallelTopology().Print (); 
+  }
+
+
+#endif
+
+void Ng_SetRefinementFlag (int ei, int flag)
+{
+  if (mesh->GetDimension() == 3)
+    {
+      mesh->VolumeElement(ei).SetRefinementFlag (flag != 0);
+      mesh->VolumeElement(ei).SetStrongRefinementFlag (flag >= 10);
+    }
+  else
+    {
+      mesh->SurfaceElement(ei).SetRefinementFlag (flag != 0);
+      mesh->SurfaceElement(ei).SetStrongRefinementFlag (flag >= 10);
+    }
+}
+
+void Ng_SetSurfaceRefinementFlag (int ei, int flag)
+{
+  if (mesh->GetDimension() == 3)
+    {
+      mesh->SurfaceElement(ei).SetRefinementFlag (flag != 0);
+      mesh->SurfaceElement(ei).SetStrongRefinementFlag (flag >= 10);
+    }
+}
+
+
+void Ng_Refine (NG_REFINEMENT_TYPE reftype)
+{
+  NgLock meshlock (mesh->MajorMutex(), 1);
+
+  BisectionOptions biopt;
+  biopt.usemarkedelements = 1;
+  biopt.refine_p = 0;
+  biopt.refine_hp = 0;
+  if (reftype == NG_REFINE_P)
+    biopt.refine_p = 1;
+  if (reftype == NG_REFINE_HP)
+    biopt.refine_hp = 1;
+
+  const Refinement & ref = ng_geometry->GetRefinement();
+
+  // Refinement * ref;
+  MeshOptimize2d * opt = NULL;
+
+  /*
+    if (geometry2d)
+    ref = new Refinement2d(*geometry2d);
+    else if (stlgeometry)
+    ref = new RefinementSTLGeometry(*stlgeometry);
+    #ifdef OCCGEOMETRY
+    else if (occgeometry)
+    ref = new OCCRefinementSurfaces (*occgeometry);
+    #endif
+    #ifdef ACIS
+    else if (acisgeometry)
+    {
+    ref = new ACISRefinementSurfaces (*acisgeometry);
+    opt = new ACISMeshOptimize2dSurfaces(*acisgeometry);
+    ref->Set2dOptimizer(opt);
+    }
+    #endif
+    else if (geometry && mesh->GetDimension() == 3)
+    {
+    ref = new RefinementSurfaces(*geometry);
+    opt = new MeshOptimize2dSurfaces(*geometry);
+    ref->Set2dOptimizer(opt);
+    }
+    else
+    {
+    ref = new Refinement();
+    }
+  */
+
+  ref.Bisect (*mesh, biopt);
+
+  mesh -> UpdateTopology();
+  mesh -> GetCurvedElements().SetIsHighOrder (false);
+
+  // mesh -> GetCurvedElements().BuildCurvedElements (ref, mparam.elementorder);
+  // delete ref;
+  delete opt;
+}
+
+void Ng_SecondOrder ()
+{
+  const_cast<Refinement&> (ng_geometry->GetRefinement()).MakeSecondOrder(*mesh);
+  /*
+    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
+    {
+    if (printmessage_importance>0)
+    cout << "no geom" << endl;
+    Refinement ref;
+    ref.MakeSecondOrder (*mesh);
+    }
+  */
+  mesh -> UpdateTopology();
+}
+
+/*
+  void Ng_HPRefinement (int levels)
+  {
+  Refinement * ref;
+
+  if (stlgeometry)
+  ref = new RefinementSTLGeometry (*stlgeometry);
+  else if (geometry2d)
+  ref = new Refinement2d (*geometry2d);
+  else
+  ref = new RefinementSurfaces (*geometry);
+
+
+  HPRefinement (*mesh, ref, levels);
+  }
+
+  void Ng_HPRefinement (int levels, double parameter)
+  {
+  Refinement * ref;
+
+  if (stlgeometry)
+  ref = new RefinementSTLGeometry (*stlgeometry);
+  else if (geometry2d)
+  ref = new Refinement2d (*geometry2d);
+  else
+  ref = new RefinementSurfaces (*geometry);
+
+
+  HPRefinement (*mesh, ref, levels, parameter);
+  }
+*/
+
+void Ng_HPRefinement (int levels, double parameter, bool setorders,
+                      bool ref_level)
+{
+  NgLock meshlock (mesh->MajorMutex(), true);
+  Refinement & ref = const_cast<Refinement&> (ng_geometry -> GetRefinement());
+  HPRefinement (*mesh, &ref, levels);
+  /*
+    Refinement * ref;
+
+    if (stlgeometry)
+    ref = new RefinementSTLGeometry (*stlgeometry);
+    else if (geometry2d)
+    ref = new Refinement2d (*geometry2d);
+    else
+    ref = new RefinementSurfaces (*geometry);
+
+    HPRefinement (*mesh, ref, levels, parameter, setorders, ref_level);
+  */
+}
+
+
+void Ng_HighOrder (int order, bool rational)
+{
+  NgLock meshlock (mesh->MajorMutex(), true);
+  /*
+    Refinement * ref;
+
+    if (stlgeometry)
+    ref = new RefinementSTLGeometry (*stlgeometry);
+    #ifdef OCCGEOMETRY
+    else if (occgeometry)
+    ref = new OCCRefinementSurfaces (*occgeometry);
+    #endif
+    #ifdef ACIS
+    else if (acisgeometry)
+    {
+    ref = new ACISRefinementSurfaces (*acisgeometry);
+    }
+    #endif
+    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 (&const_cast<Refinement&> (ng_geometry -> GetRefinement()),
+						   order, rational);
+  mesh -> SetNextMajorTimeStamp();
+
+  /*
+    if(mesh)
+    mesh -> GetCurvedElements().BuildCurvedElements (ref, order, rational);
+  */
+
+  // 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;
+}
+
+
+
+void Ng_UpdateTopology()
+{
+  if (mesh)
+    mesh -> UpdateTopology();
+}
+
+Ng_Mesh Ng_SelectMesh (Ng_Mesh newmesh)
+{
+  Mesh * hmesh = mesh.Ptr();
+  mesh.Ptr() = (Mesh*)newmesh;
+  return hmesh;
+}
+
+
+
+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_GetNVertexElements (int vnr)
+{
+  if (mesh->GetDimension() == 3)
+    return mesh->GetTopology().GetVertexElements(vnr).Size();
+  else
+    return mesh->GetTopology().GetVertexSurfaceElements(vnr).Size();
+}
+
+void Ng_GetVertexElements (int vnr, int * els)
+{
+  FlatArray<int> ia(0,0);
+  if (mesh->GetDimension() == 3)
+    ia = mesh->GetTopology().GetVertexElements(vnr);
+  else
+    ia = mesh->GetTopology().GetVertexSurfaceElements(vnr);
+  for (int i = 0; i < ia.Size(); i++)
+    els[i] = ia[i];
+}
+
+
+int Ng_GetElementOrder (int enr)
+{
+  if (mesh->GetDimension() == 3)
+    return mesh->VolumeElement(enr).GetOrder();
+  else
+    return mesh->SurfaceElement(enr).GetOrder();
+}
+
+void Ng_GetElementOrders (int enr, int * ox, int * oy, int * oz)
+{
+  if (mesh->GetDimension() == 3)
+    mesh->VolumeElement(enr).GetOrder(*ox, *oy, *oz);
+  else
+    mesh->SurfaceElement(enr).GetOrder(*ox, *oy, *oz);
+}
+
+void Ng_SetElementOrder (int enr, int order)
+{
+  if (mesh->GetDimension() == 3)
+    return mesh->VolumeElement(enr).SetOrder(order);
+  else
+    return mesh->SurfaceElement(enr).SetOrder(order);
+}
+
+void Ng_SetElementOrders (int enr, int ox, int oy, int oz)
+{
+  if (mesh->GetDimension() == 3)
+    mesh->VolumeElement(enr).SetOrder(ox, oy, oz);
+  else
+    mesh->SurfaceElement(enr).SetOrder(ox, oy);
+}
+
+
+int Ng_GetSurfaceElementOrder (int enr)
+{
+  return mesh->SurfaceElement(enr).GetOrder();
+}
+
+//HERBERT: falsche Anzahl von Argumenten
+//void Ng_GetSurfaceElementOrders (int enr, int * ox, int * oy, int * oz)
+void Ng_GetSurfaceElementOrders (int enr, int * ox, int * oy)
+{
+  int d; 
+  mesh->SurfaceElement(enr).GetOrder(*ox, *oy, d);
+}
+
+void Ng_SetSurfaceElementOrder (int enr, int order)
+{
+  return mesh->SurfaceElement(enr).SetOrder(order);
+}
+
+void Ng_SetSurfaceElementOrders (int enr, int ox, int oy)
+{
+  mesh->SurfaceElement(enr).SetOrder(ox, oy);
+}
+
+
+int Ng_GetNLevels ()
+{
+  return (mesh) ? mesh->mglevels : 0;
+}
+
+
+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);
+}
+
+
+
+
+		
+int Ng_GetNPeriodicVertices (int idnr)
+{
+  Array<INDEX_2> apairs;
+  mesh->GetIdentifications().GetPairs (idnr, apairs);
+  return apairs.Size();
+}
+
+
+// pairs should be an integer array of 2*npairs
+void Ng_GetPeriodicVertices (int idnr, int * pairs)
+{
+  Array<INDEX_2> apairs;
+  mesh->GetIdentifications().GetPairs (idnr, apairs);
+  for (int i = 0; i < apairs.Size(); i++)
+    {
+      pairs[2*i] = apairs[i].I1();
+      pairs[2*i+1] = apairs[i].I2();
+    }
+      
+}
+
+
+
+int Ng_GetNPeriodicEdges (int idnr)
+{
+  Array<INDEX,PointIndex::BASE> map;
+  //const MeshTopology & top = mesh->GetTopology();
+  int nse = mesh->GetNSeg();
+
+  int cnt = 0;
+  //  for (int id = 1; id <= mesh->GetIdentifications().GetMaxNr(); id++)
+  {
+    mesh->GetIdentifications().GetMap(idnr, map);
+    //(*testout) << "ident-map " << id << ":" << endl << map << endl;
+
+    for (SegmentIndex si = 0; si < nse; si++)
+      {
+	PointIndex other1 = map[(*mesh)[si][0]];
+	PointIndex other2 = map[(*mesh)[si][1]];
+	//  (*testout) << "seg = " << (*mesh)[si] << "; other = " 
+	//     << other1 << "-" << other2 << endl;
+	if (other1 && other2 && mesh->IsSegment (other1, other2))
+	  {
+	    cnt++;
+	  }
+      }
+  }
+  return cnt;
+}
+
+void Ng_GetPeriodicEdges (int idnr, int * pairs)
+{
+  Array<INDEX,PointIndex::BASE> map;
+  const MeshTopology & top = mesh->GetTopology();
+  int nse = mesh->GetNSeg();
+
+  int cnt = 0;
+  //  for (int id = 1; id <= mesh->GetIdentifications().GetMaxNr(); id++)
+  {
+    mesh->GetIdentifications().GetMap(idnr, map);
+      
+    //(*testout) << "map = " << map << endl;
+
+    for (SegmentIndex si = 0; si < nse; si++)
+      {
+	PointIndex other1 = map[(*mesh)[si][0]];
+	PointIndex other2 = map[(*mesh)[si][1]];
+	if (other1 && other2 && mesh->IsSegment (other1, other2))
+	  {
+	    SegmentIndex otherseg = mesh->SegmentNr (other1, other2);
+	    pairs[cnt++] = top.GetSegmentEdge (si+1);
+	    pairs[cnt++] = top.GetSegmentEdge (otherseg+1);
+	  }
+      }
+  }
+}
+
+
+
+void Ng_PushStatus (const char * str)
+{
+  PushStatus (MyStr (str));
+}
+
+void Ng_PopStatus ()
+{
+  PopStatus ();
+}
+
+void Ng_SetThreadPercentage (double percent)
+{
+  SetThreadPercent (percent);
+}
+
+void Ng_GetStatus (char ** str, double & percent)
+{
+  MyStr s;
+  GetStatus(s,percent);
+  *str = new char[s.Length()+1];
+  strcpy(*str,s.c_str());  
+}
+
+
+void Ng_SetTerminate(void)
+{
+  multithread.terminate = 1;
+}
+void Ng_UnSetTerminate(void)
+{
+  multithread.terminate = 0;
+}
+
+int Ng_ShouldTerminate(void)
+{
+  return multithread.terminate;
+}
+
+void Ng_SetRunning(int flag)
+{
+  multithread.running = flag;
+}
+int Ng_IsRunning()
+{
+  return multithread.running;
+}
+
+///// Added by Roman Stainko ....
+int Ng_GetVertex_Elements( int vnr, int* elems )
+{
+  const MeshTopology& topology = mesh->GetTopology();
+  ArrayMem<int,4> indexArray;
+  topology.GetVertexElements( vnr, indexArray );
+  
+  for( int i=0; i<indexArray.Size(); i++ )
+    elems[i] = indexArray[i];
+  
+  return indexArray.Size();
+}
+
+///// Added by Roman Stainko ....
+int Ng_GetVertex_SurfaceElements( int vnr, int* elems )
+{
+  const MeshTopology& topology = mesh->GetTopology();
+  ArrayMem<int,4> indexArray;
+  topology.GetVertexSurfaceElements( vnr, indexArray );
+  
+  for( int i=0; i<indexArray.Size(); i++ )
+    elems[i] = indexArray[i];
+  
+  return indexArray.Size();
+}
+
+///// Added by Roman Stainko ....
+int Ng_GetVertex_NElements( int vnr )
+{
+  const MeshTopology& topology = mesh->GetTopology();
+  ArrayMem<int,4> indexArray;
+  topology.GetVertexElements( vnr, indexArray );
+  
+  return indexArray.Size();
+}
+
+///// Added by Roman Stainko ....
+int Ng_GetVertex_NSurfaceElements( int vnr )
+{
+  const MeshTopology& topology = mesh->GetTopology();
+  ArrayMem<int,4> indexArray;
+  topology.GetVertexSurfaceElements( vnr, indexArray );
+
+  return indexArray.Size();
+}
+
+
+
+#ifdef SOCKETS
+int Ng_SocketClientOpen( const int port, const char * host )
+{
+  try
+    {
+      if(host)
+	clientsocket.Reset(new ClientSocket(port,host));
+      else
+	clientsocket.Reset(new ClientSocket(port));
+    }
+  catch( SocketException e)
+    {
+      cerr << e.Description() << endl;
+      return 0;
+    }
+  return 1;
+}
+ 
+void Ng_SocketClientWrite( const char * write, char** reply)
+{
+  string output = write;
+  (*clientsocket) << output;
+  string sreply;
+  (*clientsocket) >> sreply;
+  *reply = new char[sreply.size()+1];
+  strcpy(*reply,sreply.c_str());
+}
+
+
+void Ng_SocketClientClose ( void )
+{
+  clientsocket.Reset(NULL);
+}
+
+
+void Ng_SocketClientGetServerHost ( const int number, char ** host )
+{
+  *host = new char[servers[number]->host.size()+1];
+  strcpy(*host,servers[number]->host.c_str());
+}
+
+void Ng_SocketClientGetServerPort ( const int number, int * port )
+{
+  *port = servers[number]->port;
+}
+
+void Ng_SocketClientGetServerClientID ( const int number, int * id )
+{
+  *id = servers[number]->clientid;
+}
+
+#endif // SOCKETS
+
+
+
+
+#ifdef PARALLEL
+void Ng_SetElementPartition ( const int elnr, const int part )
+{
+  mesh->VolumeElement(elnr+1).SetPartition(part);
+
+}
+int Ng_GetElementPartition ( const int elnr )
+{
+  return mesh->VolumeElement(elnr+1).GetPartition();
+}
+#endif
+
+
+void Ng_InitPointCurve(double red, double green, double blue)
+{
+  mesh->InitPointCurve(red, green, blue);
+}
+
+void Ng_AddPointCurvePoint(const double * point)
+{
+  Point3d pt;
+  pt.X() = point[0];
+  pt.Y() = point[1];
+  pt.Z() = point[2];
+  mesh->AddPointCurvePoint(pt);
+}
+
+
+void Ng_SaveMesh ( const char * meshfile )
+{
+  mesh -> Save(string(meshfile));
+}
+
+
+int Ng_Bisect_WithInfo ( const char * refinementfile, double ** qualityloss, int * qualityloss_size )
+{
+  BisectionOptions biopt;
+  biopt.outfilename = NULL; // "ngfepp.vol";
+  biopt.femcode = "fepp";
+  biopt.refinementfilename = refinementfile;
+  
+  Refinement * ref = const_cast<Refinement*> (&ng_geometry -> GetRefinement());
+  MeshOptimize2d * opt = NULL;
+  /*
+    if (stlgeometry)
+    ref = new RefinementSTLGeometry(*stlgeometry);
+    #ifdef OCCGEOMETRY
+    else if (occgeometry)
+    ref = new OCCRefinementSurfaces (*occgeometry);
+    #endif
+    #ifdef ACIS
+    else if (acisgeometry)
+    {
+    ref = new ACISRefinementSurfaces(*acisgeometry);
+    opt = new ACISMeshOptimize2dSurfaces(*acisgeometry);
+    ref->Set2dOptimizer(opt);
+    }
+    #endif
+    else
+    {
+    ref = new RefinementSurfaces(*geometry);
+    opt = new MeshOptimize2dSurfaces(*geometry);
+    ref->Set2dOptimizer(opt);
+    }
+  */
+#ifdef ACIS
+  if (acisgeometry)
+    {
+      // ref = new ACISRefinementSurfaces(*acisgeometry);
+      opt = new ACISMeshOptimize2dSurfaces(*acisgeometry);
+      ref->Set2dOptimizer(opt);
+    }
+  else
+#endif
+    {
+      // ref = new RefinementSurfaces(*geometry);
+      CSGeometry * geometry = dynamic_cast<CSGeometry*> (ng_geometry);
+      if (geometry)
+	{
+	  opt = new MeshOptimize2dSurfaces(*geometry);
+	  ref->Set2dOptimizer(opt);
+	}
+    }
+
+  if(!mesh->LocalHFunctionGenerated())
+    mesh->CalcLocalH(mparam.grading);
+  
+  mesh->LocalHFunction().SetGrading (mparam.grading);
+
+  Array<double> * qualityloss_arr = NULL;
+  if(qualityloss != NULL)
+    qualityloss_arr = new Array<double>;
+
+  ref -> Bisect (*mesh, biopt, qualityloss_arr);
+
+  int retval = 0;
+
+  if(qualityloss != NULL)
+    {
+      *qualityloss = new double[qualityloss_arr->Size()+1];
+
+      for(int i = 0; i<qualityloss_arr->Size(); i++)
+	(*qualityloss)[i+1] = (*qualityloss_arr)[i];
+
+      retval = qualityloss_arr->Size();
+
+      delete qualityloss_arr;
+    }
+
+  mesh -> UpdateTopology();
+  mesh -> GetCurvedElements().BuildCurvedElements (ref, mparam.elementorder);
+  
+  multithread.running = 0;
+  delete ref;
+  delete opt;
+
+  return retval;
+}
+
+void Ng_Bisect ( const char * refinementfile )
+{
+  Ng_Bisect_WithInfo( refinementfile, NULL, NULL );
+}
+
+
+
+
+
+/*
+  number of nodes of type nt
+  nt = 0 is Vertex
+  nt = 1 is Edge
+  nt = 2 is Face
+  nt = 3 is Cell
+*/
+int Ng_GetNNodes (int nt)
+{
+  switch (nt)
+    {
+    case 0: return mesh -> GetNV();
+    case 1: return mesh->GetTopology().GetNEdges();
+    case 2: return mesh->GetTopology().GetNFaces();
+    case 3: return mesh -> GetNE();
+    }
+  return -1;
+}
+
+
+int Ng_GetClosureNodes (int nt, int nodenr, int nodeset, int * nodes)
+{
+  switch (nt)
+    {
+    case 3:  // The closure of a cell
+      {
+        int cnt = 0;
+        if (nodeset & 1)  // Vertices
+          {
+            const Element & el = (*mesh)[ElementIndex(nodenr)];
+            for (int i = 0; i < el.GetNP(); i++)
+              { 
+                nodes[cnt++] = 0;
+                nodes[cnt++] = el[i] - PointIndex::BASE;
+              }
+          }
+
+        if (nodeset & 2)  // Edges
+          {
+            int edges[12];
+            int ned;
+            ned = mesh->GetTopology().GetElementEdges (nodenr+1, edges, 0);
+            for (int i = 0; i < ned; i++)
+              {
+                nodes[cnt++] = 1;
+                nodes[cnt++] = edges[i]-1;
+              }
+          }
+
+        if (nodeset & 4)  // Faces
+          {
+            int faces[12];
+            int nfa;
+            nfa = mesh->GetTopology().GetElementFaces (nodenr+1, faces, 0);
+            for (int i = 0; i < nfa; i++)
+              {
+                nodes[cnt++] = 2;
+                nodes[cnt++] = faces[i]-1;
+              }
+          }
+
+        if (nodeset & 8)  // Cell
+          {
+            nodes[cnt++] = 3;
+            nodes[cnt++] = nodenr;
+          }
+
+        return cnt/2;
+      }
+    default:
+      {
+        cerr << "GetClosureNodes not implemented for Nodetype " << nt << endl;
+      }
+    }
+  return 0;
+}
+
+
+
+int Ng_GetNElements (int dim)
+{
+  switch (dim)
+    {
+    case 0: return mesh -> GetNV();
+    case 1: return mesh -> GetNSeg();
+    case 2: return mesh -> GetNSE();
+    case 3: return mesh -> GetNE();
+    }
+  return -1;
+}
+
+
+
+/*
+  closure nodes of element
+  nodeset is bit-coded, bit 0 includes Vertices, bit 1 edges, etc
+  E.g., nodeset = 6 includes edge and face nodes
+  nodes is pair of integers (nodetype, nodenr) 
+  return value is number of nodes
+*/
+int Ng_GetElementClosureNodes (int dim, int elementnr, int nodeset, int * nodes)
+{
+  switch (dim)
+    {
+    case 3:  // The closure of a volume element = CELL
+      {
+        return Ng_GetClosureNodes (3, elementnr, nodeset, nodes);
+      }
+    case 2:
+      {
+        int cnt = 0;
+        if (nodeset & 1)  // Vertices
+          {
+            const Element2d & el = (*mesh)[SurfaceElementIndex(elementnr)];
+            for (int i = 0; i < el.GetNP(); i++)
+              { 
+                nodes[cnt++] = 0;
+                nodes[cnt++] = el[i] - PointIndex::BASE;
+              }
+          }
+
+        if (nodeset & 2)  // Edges
+          {
+            int edges[12];
+            int ned;
+            ned = mesh->GetTopology().GetSurfaceElementEdges (elementnr+1, edges, 0);
+            for (int i = 0; i < ned; i++)
+              {
+                nodes[cnt++] = 1;
+                nodes[cnt++] = edges[i]-1;
+              }
+          }
+
+        if (nodeset & 4)  // Faces
+          {
+            int face = mesh->GetTopology().GetSurfaceElementFace (elementnr+1);
+            nodes[cnt++] = 2;
+            nodes[cnt++] = face-1;
+          }
+
+        return cnt/2;
+      }
+    default:
+      {
+        cerr << "GetClosureNodes not implemented for Element of dimension " << dim << endl;
+      }
+    }
+  return 0;
+}
diff --git a/contrib/Netgen/libsrc/interface/nginterface_v2.cpp b/contrib/Netgen/libsrc/interface/nginterface_v2.cpp
new file mode 100644
index 0000000000..f59d61130c
--- /dev/null
+++ b/contrib/Netgen/libsrc/interface/nginterface_v2.cpp
@@ -0,0 +1,221 @@
+#include <mystdlib.h>
+#include <meshing.hpp>
+
+
+
+#ifdef SOCKETS
+#include "../sockets/sockets.hpp"
+#endif
+
+#ifndef NOTCL
+#include <visual.hpp>
+#endif
+
+
+#include "nginterface.h"
+#include "nginterface_v2.hpp"
+
+
+
+namespace netgen
+{
+#include "writeuser.hpp"
+
+  extern AutoPtr<Mesh> mesh;
+}
+
+
+
+namespace netgen
+{
+
+
+
+  template <> int DLL_HEADER Ng_GetNElements<1> ()
+  {
+    return mesh->GetNSeg();
+  }
+
+  template <> DLL_HEADER int Ng_GetNElements<2> ()
+  {
+    return mesh->GetNSE();
+  }
+
+  template <> DLL_HEADER int Ng_GetNElements<3> ()
+  {
+    return mesh->GetNE();
+  }
+
+
+
+
+  template <> DLL_HEADER Ng_Element Ng_GetElement<1> (int nr)
+  {
+    const Segment & el = mesh->LineSegment (SegmentIndex(nr));
+
+    Ng_Element ret;
+    ret.type = NG_ELEMENT_TYPE(el.GetType());
+
+    ret.points.num = el.GetNP();
+    ret.points.ptr = (int*)&(el[0]);
+
+    ret.vertices.num = 2;
+    ret.vertices.ptr = (int*)&(el[0]);
+
+    ret.edges.num = 1;
+    ret.edges.ptr = mesh->GetTopology().GetSegmentElementEdgesPtr (nr);
+
+    ret.faces.num = 0;
+    ret.faces.ptr = NULL;
+
+    return ret;
+  }
+
+  template <> DLL_HEADER Ng_Element Ng_GetElement<2> (int nr)
+  {
+    const Element2d & el = mesh->SurfaceElement (SurfaceElementIndex (nr));
+  
+    Ng_Element ret;
+    ret.type = NG_ELEMENT_TYPE(el.GetType());
+    ret.points.num = el.GetNP();
+    ret.points.ptr  = (int*)&el[0];
+
+    ret.vertices.num = el.GetNV();
+    ret.vertices.ptr = (int*)&(el[0]);
+
+    ret.edges.num = MeshTopology::GetNEdges (el.GetType());
+    ret.edges.ptr = mesh->GetTopology().GetSurfaceElementEdgesPtr (nr);
+
+    ret.faces.num = MeshTopology::GetNFaces (el.GetType());
+    ret.faces.ptr = mesh->GetTopology().GetSurfaceElementFacesPtr (nr);
+
+    return ret;
+  }
+
+  template <> DLL_HEADER Ng_Element Ng_GetElement<3> (int nr)
+  {
+    const Element & el = mesh->VolumeElement (ElementIndex (nr));
+  
+    Ng_Element ret;
+    ret.type = NG_ELEMENT_TYPE(el.GetType());
+    ret.points.num = el.GetNP();
+    ret.points.ptr = (int*)&el[0];
+
+    ret.vertices.num = el.GetNV();
+    ret.vertices.ptr = (int*)&(el[0]);
+
+    ret.edges.num = MeshTopology::GetNEdges (el.GetType());
+    ret.edges.ptr = mesh->GetTopology().GetElementEdgesPtr (nr);
+
+    ret.faces.num = MeshTopology::GetNFaces (el.GetType());
+    ret.faces.ptr = mesh->GetTopology().GetElementFacesPtr (nr);
+
+    return ret;
+  }
+
+
+  DLL_HEADER Ng_Point Ng_GetPoint (int nr)
+  {
+    Ng_Point ret;
+    ret.pt = &mesh->Point(nr + PointIndex::BASE)(0);
+    return ret;
+  }
+
+
+  template <>
+  DLL_HEADER int Ng_GetElementIndex<1> (int nr)
+  {
+    return (*mesh)[SegmentIndex(nr)].si;
+  }
+  
+  template <>
+  DLL_HEADER int Ng_GetElementIndex<2> (int nr)
+  {
+    int ind = (*mesh)[SurfaceElementIndex(nr)].GetIndex(); 
+    return mesh->GetFaceDescriptor(ind).BCProperty();
+  }
+  
+  template <>
+  DLL_HEADER int Ng_GetElementIndex<3> (int nr)
+  {
+    return (*mesh)[ElementIndex(nr)].GetIndex();
+  }
+  
+  
+  template <>
+  DLL_HEADER void Ng_MultiElementTransformation<3,3> (int elnr, int npts,
+                                                      const double * xi, size_t sxi,
+                                                      double * x, size_t sx,
+                                                      double * dxdxi, size_t sdxdxi)
+  {
+    mesh->GetCurvedElements().CalcMultiPointElementTransformation (elnr, npts, xi, sxi, x, sx, dxdxi, sdxdxi);
+  }
+  
+  template <>
+  DLL_HEADER void Ng_MultiElementTransformation<2,2> (int elnr, int npts,
+                                                      const double * xi, size_t sxi,
+                                                      double * x, size_t sx,
+                                                      double * dxdxi, size_t sdxdxi)
+  {
+    mesh->GetCurvedElements().CalcMultiPointSurfaceTransformation<2> (elnr, npts, xi, sxi, x, sx, dxdxi, sdxdxi);
+  }
+
+  template <>
+  DLL_HEADER void Ng_MultiElementTransformation<2,3> (int elnr, int npts,
+                                                      const double * xi, size_t sxi,
+                                                      double * x, size_t sx,
+                                                      double * dxdxi, size_t sdxdxi)
+  {
+    mesh->GetCurvedElements().CalcMultiPointSurfaceTransformation<3> (elnr, npts, xi, sxi, x, sx, dxdxi, sdxdxi);
+  }
+
+  template <>
+  DLL_HEADER void Ng_MultiElementTransformation<1,2> (int elnr, int npts,
+                                                      const double * xi, size_t sxi,
+                                                      double * x, size_t sx,
+                                                      double * dxdxi, size_t sdxdxi)
+  {
+    mesh->GetCurvedElements().CalcMultiPointSegmentTransformation<2> (elnr, npts, xi, sxi, x, sx, dxdxi, sdxdxi);
+  }
+
+  template <>
+  DLL_HEADER void Ng_MultiElementTransformation<1,1> (int elnr, int npts,
+                                                      const double * xi, size_t sxi,
+                                                      double * x, size_t sx,
+                                                      double * dxdxi, size_t sdxdxi)
+  {
+    cout << "1D not supported" << endl;
+  }
+
+
+
+  template <> DLL_HEADER int Ng_GetNNodes<1> ()
+  {
+    return mesh->GetTopology().GetNEdges();
+  }
+
+  template <> DLL_HEADER int Ng_GetNNodes<2> ()
+  {
+    return mesh->GetTopology().GetNFaces();
+  }
+
+  template <> DLL_HEADER Ng_Node<1> Ng_GetNode<1> (int nr)
+  {
+    Ng_Node<1> node;
+    node.vertices.ptr = mesh->GetTopology().GetEdgeVerticesPtr(nr);
+    return node;
+  }
+
+  template <> DLL_HEADER Ng_Node<2> Ng_GetNode<2> (int nr)
+  {
+    Ng_Node<2> node;
+    node.vertices.ptr = mesh->GetTopology().GetFaceVerticesPtr(nr);
+    node.vertices.nv = (node.vertices.ptr[3] == 0) ? 3 : 4;
+    return node;
+  }
+
+}
+
+
+int link_it_nginterface_v2;
+
diff --git a/contrib/Netgen/libsrc/interface/read_fnf_mesh.cpp b/contrib/Netgen/libsrc/interface/read_fnf_mesh.cpp
new file mode 100644
index 0000000000..d1cff5fc4f
--- /dev/null
+++ b/contrib/Netgen/libsrc/interface/read_fnf_mesh.cpp
@@ -0,0 +1,451 @@
+
+//
+//  Read Pro/ENGINEER neutral format
+//
+
+#include <mystdlib.h>
+
+#include <myadt.hpp>
+#include <linalg.hpp>
+#include <csg.hpp>
+#include <meshing.hpp>
+#include <sys/stat.h>
+
+
+namespace netgen
+{
+#include "writeuser.hpp"
+
+  bool ReadLine (istream & in, string & buf)
+  {
+    do
+      {
+        buf = "";
+        
+        while (in.good())
+          {
+            char ch = in.get();
+            if (ch == '\n') break;
+            if (ch == '\r') break;
+            if (ch == '\\')
+              {
+                // while (iswhite (ch = in.get() )
+                ch = in.get();   // '\n'   CR
+                ch = in.get();   // '\n'   LF
+              }
+            else
+              buf += ch;
+          }
+      }
+    while (in.good() && (buf == "" || buf[0] == '#'));
+    
+    return in.good();
+  }
+  
+
+
+
+  
+  class LoadType
+  {
+  public:
+    int id;
+    string name;
+    string placement;
+    string valuetype;
+    Array<double> places;
+  };
+
+
+
+  
+  void ReadFNFFormat (Mesh & mesh, 
+                      const string & filename)
+  {
+    ifstream fin (filename.c_str());
+
+    string buf;
+
+    mesh.SetDimension (3);
+
+    while (ReadLine (fin, buf))
+      {
+        stringstream sbuf(buf);
+        string start_sect, token; char ch;
+        
+        sbuf >> start_sect;
+
+        if (start_sect == "%START_SECT")
+          {
+            sbuf >> ch >> token;
+            
+            if (token == "HEADER")
+              {
+                while (1)
+                  {
+                    ReadLine (fin, buf);
+                    stringstream sbuf(buf);
+                    string token;
+                    
+                    sbuf >> token;
+                    
+                    if (token == "%TITLE")
+                      {
+                        char ch;
+                        string name;
+                        sbuf >> ch >> name;
+                        cout << "Title: " << name << endl;
+                      }
+                    else if (token == "%STATISTICS")
+                      {
+                        ;
+                      }
+                    else if (token == "%END_SECT")
+                      {
+                        break;
+                      }
+                    else
+                      {
+                        cout << "SECTION HEADER, unknown field: " << buf << endl;
+                      }
+                  }                
+              }
+ 
+
+            else if (token == "ELEM_TYPES")
+              {
+                while (1)
+                  {
+                    ReadLine (fin, buf);
+                    stringstream sbuf(buf);
+                    string token;
+                    
+                    sbuf >> token;
+                    
+                    if (token == "%ELEM_TYPE")
+                      {
+			int nr;
+			string def;
+                        char ch;
+                        sbuf >> nr >> def >> ch;
+			if (def == "DEF")
+			  {
+			    string classname, type;
+			    sbuf >> classname >> type;
+			    if (classname != "SOLID" || type != "TETRA")
+			      cerr << "Element not supported: " << buf << endl;
+			  }
+                      }
+                    else if (token == "%END_SECT")
+                      {
+                        break;
+                      }
+                    else
+                      {
+                        cout << "SECTION ELEM_TYPE, unknown field: " << buf << endl;
+                      }
+                  }                
+              }
+ 
+
+            else if (token == "COORD_SYSTEMS")
+              {
+                while (1)
+                  {
+                    ReadLine (fin, buf);
+                    stringstream sbuf(buf);
+                    string token;
+                    
+                    sbuf >> token;
+                    
+                    if (token == "%END_SECT")
+                      {
+                        break;
+                      }
+                    else
+                      {
+                        // cout << "COORD_SYSTEMS, unknown field: " << buf << endl;
+                      }
+                  }                
+              }
+
+
+ 
+            else if (token == "MATERIALS")
+              {
+		*testout << "parse materials" << endl;
+                Array<double> young_modulus, poisson_ratio, mass_density;
+
+                while (1)
+                  {
+                    ReadLine (fin, buf);
+                    stringstream sbuf(buf);
+                    string token;
+                    
+                    sbuf >> token;
+                    
+                    if (token == "%MATERIAL")
+                      {
+                        int nr;
+                        string prop;
+                        char ch;
+                        double val;
+
+                        sbuf >> nr >> prop >> ch;
+                        if (prop == "DEF")
+                          {
+                            ;
+                          }
+                        else
+                          {
+                            sbuf >> val;
+			    *testout << "prop = " << prop << ", val = " << val << endl;
+                            if (prop == "YOUNG_MODULUS")
+                              young_modulus.Append (val);
+                            else if  (prop == "POISSON_RATIO")
+                              poisson_ratio.Append (val);
+                            else if  (prop == "MASS_DENSITY")
+                              mass_density.Append (val);
+                          }
+                      }
+                    else if (token == "%END_SECT")
+                      {
+                        mesh.SetUserData ("YOUNG_MODULUS", young_modulus);
+                        mesh.SetUserData ("POISSON_RATIO", poisson_ratio);
+                        mesh.SetUserData ("MASS_DENSITY", mass_density);
+			*testout << "young = " << young_modulus << endl;
+			*testout << "poisson = " << poisson_ratio << endl;
+                        break;
+                      }
+                    else
+                      {
+                        cout << "SECTION MATERIALS, unknown field: " << buf << endl;
+                      }
+                  }
+              }
+
+            
+            else if (token == "MESH")
+              {
+                while (1)
+                  {
+                    ReadLine (fin, buf);
+                    stringstream sbuf(buf);
+                    string token;
+                    sbuf >> token;
+                    if (token == "%NODE")
+                      {
+                        string st;
+                        char ch;
+                        int nr, ks_id;
+                        double x,y,z;
+                        sbuf >> nr >> st >> ch >> x >> y >> z >> ks_id;
+                        mesh.AddPoint (Point3d (x,y,z) );
+                      }
+                    else if (token == "%ELEM")
+                      {
+                        string elemid, def;
+                        char ch;
+                        int elnr, typid, matid;
+                        string propid;
+                        sbuf >> elnr >> def >> ch;
+                        sbuf >> typid >> matid >> propid;
+                        Array<int> pnums;
+                        while (1)
+                          {
+                            int pn;
+                            sbuf >> pn;
+                            if (!sbuf.good()) break;
+                            pnums.Append (pn);
+                          }
+                        int pe2ng [] = { 0, 1, 2, 3, 4, 7, 5, 6,  8, 9 };
+                        Element el(pnums.Size());
+                        for (int j = 0; j < pnums.Size(); j++)
+                          el[pe2ng[j]] = pnums[j];
+                        el.SetIndex (matid);
+                        mesh.AddVolumeElement (el);
+                      }
+                    else if (token == "%END_SECT")
+                      {
+                        break;
+                      }
+                    else
+                      {
+                        cout << "SECTION MESH, unknown: " << buf << endl;
+                      }
+                  }
+              }
+            else if (token == "MESH_TOPOLOGY")
+              {
+                while (1)
+                  {
+                    ReadLine (fin, buf);
+                    stringstream sbuf(buf);
+                    string token, kw;
+                    int nr;
+                    char ch;
+
+                    sbuf >> token;
+                    if (token == "%EDGE")
+                      {
+                        sbuf >> nr >> kw >> ch;
+                        if (kw == "NODES")
+                          {
+                            Array<int> enums;
+                            while (1)
+                              {
+                                int en;
+                                sbuf >> en;
+                                if (!sbuf.good()) break;
+                                enums.Append (en);
+                              }
+                            for (int j = 0; j+2 < enums.Size(); j+=2)
+                              {
+                                Segment seg;
+                                seg[0] = enums[j];
+                                seg[1] = enums[j+2];
+                                seg[2] = enums[j+1];
+                                seg.edgenr = nr;
+                                mesh.AddSegment (seg);
+                              }
+                          }
+                      }
+                    else if (token == "%SURFACE")
+                      {
+                        sbuf >> nr >> kw >> ch;
+                        if (kw == "FACES")
+                          {
+                            Array<int> fnums;
+                            while (1)
+                              {
+                                int fn;
+                                sbuf >> fn;
+                                if (!sbuf.good()) break;
+                                fnums.Append (fn);
+                              }                            
+
+                            FaceDescriptor fd(-1, -1, -1, -1);
+                            fd.SetBCProperty (nr);
+			    *testout << "add fd " << mesh.GetNFD() << ", nr = " << nr << endl;
+                            mesh.AddFaceDescriptor (fd);
+                              
+                            for (int j = 0; j < fnums.Size(); j += 2)
+                              {
+                                int elnr = fnums[j];
+                                int fnr = fnums[j+1];
+                                
+                                const Element & el = mesh.VolumeElement (elnr);
+                                Element2d el2d;
+                                el.GetFace (fnr, el2d);
+                                el2d.SetIndex (nr);
+                                  
+                                mesh.AddSurfaceElement (el2d);
+                              }
+                          }
+                      }
+                    else if (token == "%END_SECT")
+                      {
+                        break;
+                      }
+                    else
+                      {
+                        cout << "SECTION MESH, unknown: " << buf << endl;
+                      }
+                  }
+              }
+
+
+
+ 
+            else if (token == "LOADS")
+              {
+                Array<LoadType*> loadtypes;
+
+                while (1)
+                  {
+                    ReadLine (fin, buf);
+                    stringstream sbuf(buf);
+                    string token;
+                    
+                    sbuf >> token;
+                    
+                    if (token == "%LOAD_TYPE")
+                      {
+                        string def;
+                        char ch;
+
+                        LoadType * lt = new LoadType;
+                        sbuf >> lt->id >> def >> ch >> lt->name >> lt->placement >> lt->valuetype;
+                        
+                        if (lt->name == "DISPLACEMENT")
+                          cout << "loadtype DISPLACEMENT found" << endl;
+
+                        if (lt->placement != "FACE" && lt->placement != "EDGE" && lt->placement != "NODE")
+                          cout << "unsupported placement " << lt->placement << endl;
+
+                        loadtypes.Append (lt);
+                      }
+
+                    else if (token == "%LOAD")
+                      {
+                        int id;
+                        string def;
+                        char ch;
+                        int placement;
+                        int load_type_id, con_case_id;
+                        sbuf >> id >> def >> ch;
+                        
+                        if (def == "DEF")
+                          {
+                            sbuf >> load_type_id >> con_case_id;
+                          }
+                        if (def == "VAL")
+                          {
+                            sbuf >> placement;
+                            for (int i = 0; i < loadtypes.Size(); i++)
+                              if (load_type_id == loadtypes[i]->id)
+                                loadtypes[i]->places.Append (placement);
+                          }
+                      }                    
+                    
+                    else if (token == "%END_SECT")
+                      {
+                        for (int i = 0; i < loadtypes.Size(); i++)
+                          {
+                            if (loadtypes[i]->placement == "FACE" && loadtypes[i]->name == "DISPLACEMENT")
+                              {
+                                mesh.SetUserData ("CONSTRAINT_DISP_FACE", loadtypes[i]->places);
+                                cout << "constrained faces: " << loadtypes[i]->places << endl;
+                              }
+                            if (loadtypes[i]->placement == "EDGE" && loadtypes[i]->name == "DISPLACEMENT")
+                              {
+                                mesh.SetUserData ("CONSTRAINT_DISP_EDGE", loadtypes[i]->places);
+                                cout << "constrained edges: " << loadtypes[i]->places << endl;
+                              }
+                            if (loadtypes[i]->placement == "NODE" && loadtypes[i]->name == "DISPLACEMENT")
+                              {
+                                mesh.SetUserData ("CONSTRAINT_DISP_NODE", loadtypes[i]->places);
+                                cout << "constrained nodes: " << loadtypes[i]->places << endl;
+                              }
+                          }
+                        break;
+                      }
+                    else
+                      {
+                        cout << "SECTION LOADS, unknown field: " << buf << endl;
+                      }
+                  }
+              }
+
+
+
+            else
+              {
+                cout << "unknown section " << token << endl;
+              }
+          }
+        else
+          cout << "parse line: (" << buf << ")" << endl;
+      }
+  }
+}
diff --git a/contrib/Netgen/libsrc/interface/readtetmesh.cpp b/contrib/Netgen/libsrc/interface/readtetmesh.cpp
new file mode 100644
index 0000000000..1258068b9d
--- /dev/null
+++ b/contrib/Netgen/libsrc/interface/readtetmesh.cpp
@@ -0,0 +1,797 @@
+
+//
+//  Read CST file format
+//
+
+#include <mystdlib.h>
+
+#include <myadt.hpp>
+#include <linalg.hpp>
+#include <csg.hpp>
+#include <meshing.hpp>
+#include <sys/stat.h>
+
+
+namespace netgen
+{
+#include "writeuser.hpp"
+
+
+
+
+  void ReadTETFormat (Mesh & mesh, 
+                      const string & hfilename)
+  {
+    const char * filename = hfilename.c_str();
+
+    cout << "Reading .tet mesh" << endl;
+
+    ifstream in (filename);
+
+    int inputsection = 0;
+    bool done = false;
+
+    char ch;
+    string str;
+
+    string version;
+
+    int unitcode;
+    double tolerance;
+    double dS1, dS2, alphaDeg, x3D, y3D, z3D;
+    int nelts,nfaces,nedges,nnodes;
+    int nperiodicmasternodes,ncornerperiodicmasternodes,ncubicperiodicmasternodes;
+    int nperiodicmasteredges,ncornerperiodicmasteredges;
+    int nperiodicmasterfaces;
+    int nodeid,type,pid;
+    int dummyint;
+    int modelverts,modeledges,modelfaces,modelcells;
+    Point3d p;
+    int numObj3D,numObj2D,numObj1D,numObj0D;
+    bool nullstarted;
+    Array<int> eldom;
+    int minId3D = -1, minId2D = -1;
+    int maxId3D(-1), maxId2D(-1), maxId1D(-1), maxId0D(-1);
+    Array<Array<int> *> segmentdata;
+    Array<Element2d* > tris;
+
+    Array<int> userdata_int;  // just save data for 1:1 output
+    Array<double> userdata_double;
+    Array<int> point_pids;
+    Array<int> tetfacedata;
+    Array<int> uid_to_group_3D, uid_to_group_2D, uid_to_group_1D, uid_to_group_0D;
+
+    while(!done)
+      {
+        // skip "//" comment
+        bool comment = true;
+        while(comment)
+          {
+            ch = in.get();
+            while(ch == ' ' || ch == '\n' || ch == '\t' || ch =='\r')
+              ch = in.get();
+	      
+            if(ch != '/')
+              {
+                comment = false;
+                in.putback(ch);
+              }
+            else
+              {
+                ch = in.get();
+                if(ch != '/')
+                  {
+                    comment = false;
+                    in.putback(ch);
+                    in.putback('/');
+                  }
+                else
+                  {
+                    in.ignore(10000,'\n');
+                  }
+              }
+          }
+
+	  
+        switch(inputsection)
+          {
+          case 0:
+            // version number
+            in >> version;
+            cout << "Version number " << version << endl;
+            if(version != "1.1" && version != "2" && version != "2.0")
+              {
+                cerr << "WARNING: import only tested for versions 1.1 and 2" << endl;
+                //done = true;
+              }
+            userdata_double.Append(atof(version.c_str()));
+            break;
+
+          case 1:
+            // unit code (1=CM 2=MM 3=M 4=MIC 5=NM 6=FT 7=IN 8=MIL)
+            in >> unitcode;
+            cout << "unit code " << unitcode << endl;
+            userdata_int.Append(unitcode);
+            break;
+
+          case 2:
+            // Geometric coord "zero" tolerance threshold
+            in >> tolerance;
+            cout << "tolerance " << tolerance << endl;
+            userdata_double.Append(tolerance);
+            break;
+
+          case 3:
+            // Periodic UnitCell dS1 , dS2 , alphaDeg
+            in >> dS1 >> dS2 >> alphaDeg;
+            userdata_double.Append(dS1);
+            userdata_double.Append(dS2);
+            userdata_double.Append(alphaDeg);
+            break;
+
+          case 4:
+            // Periodic UnitCell origin in global coords (x3D,y3D,z3D)
+            in >> x3D >> y3D >> z3D;
+            userdata_double.Append(x3D);
+            userdata_double.Append(y3D);
+            userdata_double.Append(z3D);
+            break;
+
+          case 5:
+            // Model entity count: Vertices, Edges, Faces, Cells (Version 2)
+            in >> modelverts >> modeledges >> modelfaces >> modelcells;
+            userdata_int.Append(modelverts);
+            userdata_int.Append(modeledges);
+            userdata_int.Append(modelfaces);
+            userdata_int.Append(modelcells);
+            break;
+
+          case 6:
+            // Topological mesh-entity counts (#elements,#faces,#edges,#nodes)
+            in >> nelts >> nfaces >> nedges >> nnodes;
+            cout << nelts << " elements, " << nfaces << " faces, " << nedges << " edges, " << nnodes << " nodes" << endl;
+            mesh.SetAllocSize(nnodes,2*nedges,nfaces,nelts);
+            break;
+
+          case 7:
+            // NodeID, X, Y, Z, Type (0=Reg 1=PMaster 2=PSlave 3=CPMaster 4=CPSlave), PID:
+            {
+              cout << "read nodes" << endl;
+              for(int i=0; i<nnodes; i++)
+                {
+                  in >> nodeid >> p.X() >> p.Y() >> p.Z() >> type >> pid;
+                  mesh.AddPoint(p);		  
+                  point_pids.Append(pid);
+                  if(pid > maxId0D)
+                    maxId0D = pid;
+                  //(*testout) << "point " << p << " type " << type << " mastersexist " << mastersexist << endl;
+                }
+            }
+            break;
+
+          case 8:
+            // Number of Periodic Master Nodes
+            in >> nperiodicmasternodes;
+            break;
+
+          case 9:
+            // MasterNodeID, SlaveNodeID, TranslCode (1=dS1 2=dS2 3=dS1+dS2)
+            for(int i=0; i<nperiodicmasternodes; i++)
+              {
+                for(int j=0; j<2; j++)
+                  in >> dummyint;
+
+                in >> dummyint;
+              }
+            break;
+
+          case 10:
+            // Number of Corner Periodic Master Nodes
+            in >> ncornerperiodicmasternodes;
+            break;
+
+          case 11:
+            // MasterNodeID, 3-SlaveNodeID's, 3-TranslCodes (1=dS1 2=dS2 3=dS1+dS2)
+            for(int i=0; i<ncornerperiodicmasternodes; i++)
+              {
+                for(int j=0; j<4; j++)
+                  in >> dummyint;
+
+                for(int j=0; j<3; j++)
+                  in >> dummyint;
+              }
+            break;
+
+          case 12:
+            // Number of Cubic Periodic Master Nodes
+            in >> ncubicperiodicmasternodes;
+            break;
+
+          case 13:
+            //MasterNodeID, 7-SlaveNodeID's, TranslCodes
+            for(int i=0; i<ncubicperiodicmasternodes; i++)
+              {
+                for(int j=0; j<8; j++)
+                  in >> dummyint;
+
+                for(int j=0; j<7; j++)
+                  in >> dummyint;
+              }
+            break;
+
+          case 14:
+            // EdgeID, NodeID0, NodeID1, Type (0=Reg 1=PMaster 2=PSlave 3=CPMaster 4=CPSlave), PID
+            cout << "read edges" << endl;
+            nullstarted = false;
+            segmentdata.SetSize(nedges);
+            for(int i=0; i<nedges; i++)
+              {
+                segmentdata[i] = new Array<int>(7);
+                *segmentdata[i] = -1;
+                in >> dummyint;
+                in >> (*segmentdata[i])[0] >> (*segmentdata[i])[1];
+                in >> type;
+                in >> (*segmentdata[i])[2];
+                if((*segmentdata[i])[2] > maxId1D)
+                  maxId1D = (*segmentdata[i])[2];
+              }
+            break;
+
+          case 15:
+            // Number of Periodic Master Edges
+            in >> nperiodicmasteredges;
+            break;
+
+          case 16:
+            // MasterEdgeID, SlaveEdgeID, TranslCode (1=dS1 2=dS2 3=dS1+dS2)
+            for(int i=0; i<nperiodicmasteredges; i++)
+              in >> dummyint >> dummyint >> dummyint;
+            break;
+
+          case 17:
+            // Number of Corner Periodic Master Edges
+            in >> ncornerperiodicmasteredges;
+            break;
+
+          case 18:
+            // MasterEdgeID, 3 SlaveEdgeID's, 3 TranslCode (1=dS1 2=dS2 3=dS1+dS2)
+            for(int i=0; i<ncornerperiodicmasteredges; i++)
+              {
+                in >> dummyint;
+                for(int j=0; j<3; j++)
+                  in >> dummyint;
+                for(int j=0; j<3; j++)
+                  in >> dummyint;
+              }
+            break;
+
+          case 19:
+            // FaceID, EdgeID0, EdgeID1, EdgeID2, FaceType (0=Reg 1=PMaster 2=PSlave), PID
+            {
+              //Segment seg;
+              int segnum_ng[3];
+              bool neg[3];
+              cout << "read faces" << endl;
+              nullstarted = false;
+              for(int i=0; i<nfaces; i++)
+                {
+                  int trinum;
+                  int segnum;
+		    
+                  tris.Append(new Element2d(TRIG));
+
+                  in >> trinum;
+                  for(int j=0; j<3; j++)
+                    {
+                      in >> segnum;
+                      neg[j] = (segnum<0);
+                      if(!neg[j])
+                        segnum_ng[j] = segnum-1;
+                      else
+                        segnum_ng[j] = -segnum-1;
+			
+                      if(neg[j])
+                        tris.Last()->PNum(j+1) = (*segmentdata[segnum_ng[j]])[1];
+                      else
+                        tris.Last()->PNum(j+1) = (*segmentdata[segnum_ng[j]])[0];
+
+                      tris.Last()->GeomInfoPi(j+1).trignum = trinum;
+                    }
+                  in >> type;
+                  int faceid;
+                  in >> faceid;
+		    
+                  if(faceid > maxId2D)
+                    maxId2D = faceid;
+
+                  if(i==0 || faceid < minId2D)
+                    minId2D = faceid;
+		    
+                  tris.Last()->SetIndex(faceid);
+
+                  if(faceid > 0)
+                    {
+                      //if(nullstarted)
+                      //  {
+                      //    cout << "Faces: Assumption about index 0 wrong (face"<<trinum <<")" << endl;
+                      //  }
+                      //mesh.AddSurfaceElement(tri);
+			
+                      for(int j=0; j<3; j++)
+                        {
+                          if(neg[j])
+                            {
+                              (*segmentdata[segnum_ng[j]])[4] = faceid;
+                              (*segmentdata[segnum_ng[j]])[6] = trinum;
+                            }
+                          else
+                            {
+                              (*segmentdata[segnum_ng[j]])[3] = faceid;
+                              (*segmentdata[segnum_ng[j]])[5] = trinum;
+                            }
+                        }
+                    }
+                  else
+                    nullstarted = true;
+                }
+            }
+            break;
+
+          case 20:
+            // Number of Periodic Master Faces
+            in >> nperiodicmasterfaces;
+            break;
+
+          case 21:
+            // MasterFaceID, SlaveFaceID, TranslCode (1=dS1 2=dS2)
+            {
+              Vec<3> randomvec(-1.32834,3.82399,0.5429151);
+              int maxtransl = -1;
+              for(int i=0; i<nperiodicmasterfaces; i++)
+                {
+                  int tri1,tri2,transl;
+                  Array<PointIndex> nodes1(3),nodes2(3);
+                  Array<double> sortval1(3),sortval2(3);
+                  in >> tri1 >> tri2 >> transl;
+
+                  if(transl > maxtransl)
+                    maxtransl = transl;
+		    
+		    
+                  for(int j=0; j<3; j++)
+                    {
+                      nodes1[j] = tris[tri1-1]->PNum(j+1);
+                      sortval1[j] = Vec<3>(mesh[nodes1[j]])*randomvec;
+                      nodes2[j] = tris[tri2-1]->PNum(j+1);
+                      sortval2[j] = Vec<3>(mesh[nodes2[j]])*randomvec;
+                    }
+
+                  BubbleSort(sortval1,nodes1);
+                  BubbleSort(sortval2,nodes2);
+
+                  for(int j=0; j<3; j++)
+                    mesh.GetIdentifications().Add(nodes1[j],nodes2[j],transl);
+			
+                }
+              for(int i=1; i<= maxtransl; i++)
+                mesh.GetIdentifications().SetType(i,Identifications::PERIODIC);
+            }	      
+            break;
+
+          case 22:
+            // ElemID, FaceID0, FaceID1, FaceID2, FaceID3, PID
+            {
+              cout << "read elements (1)" << endl;
+
+              //SurfaceElementIndex surf[4];
+              bool neg[4];
+              int elemid;
+              int domain;
+		
+              eldom.SetSize(nelts);
+
+              for(int i=0; i<nelts; i++)
+                {
+                  if(int(100.*i/nelts) % 5 == 0)
+                    cout << int(100.*i/nelts)
+#ifdef WIN32
+                         << "%%\r"
+#else
+                         << "\%\r"
+#endif 
+                         << flush;
+                  in >> elemid;
+                  for(int j=0; j<4;j++)
+                    {
+                      in >> dummyint;
+                      neg[j] = (dummyint < 0);
+                      if(neg[j])
+                        tetfacedata.Append(-dummyint-1);
+                      //surf[j] = -dummyint-1;
+                      else
+                        tetfacedata.Append(dummyint-1);
+                      tetfacedata.Append(((neg[j]) ? 1 : 0));
+                      //surf[j] = dummyint-1;
+                    }
+		    
+                  in >> domain;
+                  eldom[i] = domain;
+                  tetfacedata.Append(domain);
+
+                  if(i==0 || domain < minId3D)
+                    minId3D = domain;
+
+                  if(domain > maxId3D)
+                    maxId3D = domain;
+		    
+                  // 		    for(int j=0; j<4; j++)
+                  // 		      {
+                  // 			if(mesh.GetNSE() <= surf[j])
+                  // 			  continue;
+
+                  // 			int faceind = 0;
+                  // 			for(int k=1; k<=mesh.GetNFD(); k++)
+                  // 			  {
+                  // 			    if(mesh.GetFaceDescriptor(k).SurfNr() == mesh[surf[j]].GetIndex())
+                  // 			      faceind = k;
+                  // 			  }
+                  // 			if(faceind)
+                  // 			  {
+                  // 			    if(neg[j])
+                  // 			      mesh.GetFaceDescriptor(faceind).SetDomainOut(domain);
+                  // 			    else
+                  // 			      mesh.GetFaceDescriptor(faceind).SetDomainIn(domain);
+                  // 			  }
+                  // 			else
+                  // 			  {
+                  // 			    if(neg[j])
+                  // 			      faceind = mesh.AddFaceDescriptor(FaceDescriptor(mesh[surf[j]].GetIndex(),0,domain,0));
+                  // 			    else
+                  // 			      faceind = mesh.AddFaceDescriptor(FaceDescriptor(mesh[surf[j]].GetIndex(),domain,0,0));
+                  // 			    mesh.GetFaceDescriptor(faceind).SetBCProperty(mesh[surf[j]].GetIndex());
+                  // 			  }
+                  // 		      }
+                }
+              cout << endl;
+		
+		
+              // 		Array<int> indextodescriptor(maxId2D+1);
+		
+              // 		for(int i=1; i<=mesh.GetNFD(); i++)
+              // 		  indextodescriptor[mesh.GetFaceDescriptor(i).SurfNr()] = i;
+		
+		
+              // 		for(SurfaceElementIndex i=0; i<mesh.GetNSE(); i++)
+              // 		  mesh[i].SetIndex(indextodescriptor[mesh[i].GetIndex()]);
+            }
+            break;
+
+          case 23:
+            // ElemID, NodeID0, NodeID1, NodeID2, NodeID3
+            { 
+              cout << "read elements (2)" << endl;
+              Element el(TET);
+              for(ElementIndex i=0; i<nelts; i++)
+                {
+                  in >> dummyint;
+                  for(int j=1; j<=4; j++)
+                    in >> el.PNum(j);
+                  swap(el.PNum(1),el.PNum(2));
+		    
+                  el.SetIndex(eldom[i]);
+                  mesh.AddVolumeElement(el);
+                }	
+            }	  
+            break;
+	      
+          case 24:
+            // Physical Object counts (#Obj3D,#Obj2D,#Obj1D,#Obj0D)
+            {
+              in >> numObj3D;
+              userdata_int.Append(numObj3D);
+              in >> numObj2D;
+              userdata_int.Append(numObj2D);
+              in >> numObj1D;
+              userdata_int.Append(numObj1D);
+              in >> numObj0D;
+              userdata_int.Append(numObj0D);
+            }
+            break;
+
+          case 25:
+            // Number of Ports (Ports are a subset of Object2D list)
+            {
+              in >> dummyint;
+              //userdata_int.Append(dummyint);
+            }
+            break;
+
+          case 26:
+            // Object3D GroupID, #Elems <immediately followed by> ElemID List
+            {
+              uid_to_group_3D.SetSize(maxId3D+1);
+              uid_to_group_3D = -1;
+              for(int i=0; i<numObj3D; i++)
+                {
+                  int groupid;
+                  in >> groupid;
+                  (*testout) << "3d groupid " << groupid << endl;
+                  //userdata_int.Append(groupid);
+                  int nelems;
+                  in >> nelems;
+                  //userdata_int.Append(nelems);
+                  for(int j=0; j<nelems; j++)
+                    {
+                      in >> dummyint;
+			
+                      (*testout) << "read " << dummyint << endl;
+                      //userdata_int.Append(dummyint);
+			
+                      if(dummyint < 0) 
+                        dummyint *= -1;
+                      uid_to_group_3D[eldom[dummyint-1]] = groupid;
+                    }
+                }
+            }
+            break;
+
+          case 27:
+            // Object2D GroupID, #Faces <immediately followed by> FaceID List
+            {
+              Array<int> ports;
+              //int totnum = 0;
+              uid_to_group_2D.SetSize(maxId2D+1);
+              uid_to_group_2D = -1;
+
+              for(int i=0; i<numObj2D; i++)
+                {
+                  int groupid;
+                  in >> groupid;
+                  (*testout) << "2d groupid " << groupid << endl;
+                  //userdata_int.Append(groupid);
+                  int nelems;
+                  in >> nelems;
+                  //userdata_int.Append(nelems);
+                  for(int j=0; j<nelems; j++)
+                    {
+                      in >> dummyint;
+                      char port;
+                      while((port = in.get()) == ' ')
+                        ;
+
+                      (*testout) << "read " << dummyint << endl;
+                      if(dummyint < 0) 
+                        dummyint *= -1;
+                      int uid = tris[dummyint-1]->GetIndex();
+
+                      if(port == 'P' || port == 'p')
+                        {
+                          if(!ports.Contains(uid))
+                            ports.Append(uid);
+                        }
+                      else
+                        in.putback(port);
+			
+                      //userdata_int.Append(dummyint);
+			
+                      uid_to_group_2D[uid] = groupid;
+                      (*testout) << "setting " << uid << endl;
+
+                      //totnum++;
+                    }
+                }
+              mesh.SetUserData("TETmesh:ports",ports);
+            }
+            break;
+
+          case 28:
+            // Object1D GroupID, #Edges <immediately followed by> EdgeID List
+            {
+              uid_to_group_1D.SetSize(maxId1D+1);
+              uid_to_group_1D = -1;
+
+              for(int i=0; i<numObj1D; i++)
+                {
+                  int groupid;
+                  in >> groupid;
+                  //userdata_int.Append(groupid);
+                  int nelems;
+                  in >> nelems;
+                  //userdata_int.Append(nelems);
+                  for(int j=0; j<nelems; j++)
+                    {
+                      in >> dummyint;
+                      //userdata_int.Append(dummyint);
+
+                      if(dummyint < 0) 
+                        dummyint *= -1;
+                      uid_to_group_1D[(*segmentdata[dummyint-1])[2]] = groupid;
+                    }
+                }
+            }
+            break;
+
+          case 29:
+            // Object0D GroupID, #Nodes <immediately followed by> NodeID List
+            {
+              uid_to_group_0D.SetSize(maxId0D+1);
+              uid_to_group_0D = -1;
+              for(int i=0; i<numObj0D; i++)
+                {
+                  int groupid;
+                  in >> groupid;
+                  //userdata_int.Append(groupid);
+                  int nelems;
+                  in >> nelems;
+                  //userdata_int.Append(nelems);
+                  for(int j=0; j<nelems; j++)
+                    {
+                      in >> dummyint;
+                      //userdata_int.Append(dummyint);
+
+                      if(dummyint < 0) 
+                        dummyint *= -1;
+                      uid_to_group_0D[point_pids[dummyint-1]] = groupid;
+                    }
+                }
+            }
+            break;
+
+
+
+          default:
+            done = true;
+	      
+          }
+	  
+        if(inputsection == 4 && version == "1.1")
+          inputsection++;
+
+        inputsection++;
+      }
+    in.close();
+
+
+    mesh.SetUserData("TETmesh:double",userdata_double);
+    userdata_int.Append(minId2D);
+    userdata_int.Append(minId3D);
+    mesh.SetUserData("TETmesh:int",userdata_int);   
+    //if(version == "1.1")
+    mesh.SetUserData("TETmesh:point_id",point_pids);
+
+    mesh.SetUserData("TETmesh:uid_to_group_3D",uid_to_group_3D);
+    mesh.SetUserData("TETmesh:uid_to_group_2D",uid_to_group_2D);
+    mesh.SetUserData("TETmesh:uid_to_group_1D",uid_to_group_1D);
+    mesh.SetUserData("TETmesh:uid_to_group_0D",uid_to_group_0D);
+
+
+    Array<SurfaceElementIndex> surfindices(tris.Size());
+    surfindices = -1;
+
+    for(int i=0; i<tris.Size(); i++)
+      {
+        if(atof(version.c_str()) <= 1.999999)
+          {
+            if(tris[i]->GetIndex() > 0)
+              surfindices[i] = mesh.AddSurfaceElement(*tris[i]);
+          }
+        else
+          {
+            if(tris[i]->GetIndex() > 0 &&
+               tris[i]->GetIndex() < minId3D)
+              {
+                tris[i]->SetIndex(tris[i]->GetIndex()-minId2D+1);
+                surfindices[i] = mesh.AddSurfaceElement(*tris[i]);
+              }
+          }
+        delete tris[i];
+      }
+
+      
+    mesh.ClearFaceDescriptors();
+    if(atof(version.c_str()) <= 1.999999)
+      for(int i = 1; i <= maxId2D; i++)
+        mesh.AddFaceDescriptor(FaceDescriptor(i,0,0,0));
+    else
+      for(int i=minId2D; i<minId3D; i++)
+        mesh.AddFaceDescriptor(FaceDescriptor(i,0,0,0));
+	
+
+    for(int i=0; i<tetfacedata.Size(); i+=9)
+      {
+        for(int j=0; j<4; j++)
+          {
+            SurfaceElementIndex surf = surfindices[tetfacedata[i+2*j]];
+	      
+            //if(mesh.GetNSE() <= surf)
+            if(surf == -1)
+              continue;
+
+            if(tetfacedata[i+2*j+1] == 1)
+              mesh.GetFaceDescriptor(mesh[surf].GetIndex()).SetDomainOut(tetfacedata[i+8]);
+            else
+              mesh.GetFaceDescriptor(mesh[surf].GetIndex()).SetDomainIn(tetfacedata[i+8]);
+			
+
+            /*
+	      int faceind = 0;
+	      for(int k=1; k<=mesh.GetNFD(); k++)
+              {
+              if(mesh.GetFaceDescriptor(k).SurfNr() == mesh[surf].GetIndex())
+              faceind = k;
+              }
+	      if(faceind)
+              {
+              if(tetfacedata[i+4+j] == 1)
+              mesh.GetFaceDescriptor(faceind).SetDomainOut(tetfacedata[i+8]);
+              else
+              mesh.GetFaceDescriptor(faceind).SetDomainIn(tetfacedata[i+8]);
+              }
+	      else
+              {
+              if(tetfacedata[i+4+j] == 1)
+              faceind = mesh.AddFaceDescriptor(FaceDescriptor(mesh[surf].GetIndex(),0,tetfacedata[i+8],0));
+              else
+              faceind = mesh.AddFaceDescriptor(FaceDescriptor(mesh[surf].GetIndex(),tetfacedata[i+8],0,0));
+              mesh.GetFaceDescriptor(faceind).SetBCProperty(mesh[surf].GetIndex());
+              }
+            */
+          }
+
+      }
+      
+    //       Array<int> indextodescriptor(maxId2D+1);
+		
+    //       for(int i=1; i<=mesh.GetNFD(); i++)
+    // 	indextodescriptor[mesh.GetFaceDescriptor(i).SurfNr()] = i;
+		
+		
+    //       for(SurfaceElementIndex i=0; i<mesh.GetNSE(); i++)
+    // 	mesh[i].SetIndex(indextodescriptor[mesh[i].GetIndex()]);
+
+
+    for(int i=0; i<segmentdata.Size(); i++)
+      {
+        Segment seg;
+
+	  
+        if((atof(version.c_str()) <= 1.999999 && (*segmentdata[i])[2] > 0) ||
+           (atof(version.c_str()) > 1.999999  && (*segmentdata[i])[2] > 0 && (*segmentdata[i])[2] < minId2D))
+          {
+            seg[0] = (*segmentdata[i])[0];
+            seg[1] = (*segmentdata[i])[1];
+            seg.edgenr = (*segmentdata[i])[2];
+            seg.epgeominfo[0].edgenr = (*segmentdata[i])[2];
+            seg.epgeominfo[1].edgenr = (*segmentdata[i])[2];
+            seg.si = (*segmentdata[i])[3]-minId2D+1;
+            seg.surfnr1 = -1;//(*segmentdata[i])[3];
+            seg.surfnr2 = -1;//(*segmentdata[i])[4];
+            seg.geominfo[0].trignum = (*segmentdata[i])[5];
+            seg.geominfo[1].trignum = (*segmentdata[i])[5];
+            mesh.AddSegment(seg);
+
+            seg[0] = (*segmentdata[i])[1];
+            seg[1] = (*segmentdata[i])[0];
+            seg.si = (*segmentdata[i])[4]-minId2D+1;
+            seg.surfnr1 = -1;//(*segmentdata[i])[3];
+            seg.surfnr2 = -1;//(*segmentdata[i])[4];
+            seg.geominfo[0].trignum = (*segmentdata[i])[6];
+            seg.geominfo[1].trignum = (*segmentdata[i])[6];
+            mesh.AddSegment(seg);
+          }
+        delete segmentdata[i];
+      }
+
+    /*
+      for(int i=mesh.GetNSeg(); i>=1; i--)
+      if(mesh.LineSegment(i).epgeominfo[0].edgenr == 0 ||
+      mesh.LineSegment(i).epgeominfo[1].edgenr == 0)
+      mesh.FullDeleteSegment(i);
+    */	
+  
+    mesh.CalcSurfacesOfNode();
+      
+  }
+}
+
+
diff --git a/contrib/Netgen/libsrc/interface/readuser.cpp b/contrib/Netgen/libsrc/interface/readuser.cpp
new file mode 100644
index 0000000000..f21466af8d
--- /dev/null
+++ b/contrib/Netgen/libsrc/interface/readuser.cpp
@@ -0,0 +1,422 @@
+//
+//  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 string & hfilename)
+  {
+    cout << "Read User File" << endl;
+
+    const char * filename = hfilename.c_str();
+
+    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 (int i = 1; i <= np; i++)
+          {
+            Point3d p;
+            in >> p.X() >> p.Y() >> p.Z();
+	    p.Z() *= 10;
+            mesh.AddPoint (p);
+          }
+
+        mesh.ClearFaceDescriptors();
+        mesh.AddFaceDescriptor (FaceDescriptor(0,1,0,0));
+      
+        in >> nbe;
+        //      int invert = globflags.GetDefineFlag ("invertsurfacemesh");
+        for (int i = 1; i <= nbe; i++)
+          {
+            Element2d el;
+            el.SetIndex(1);
+
+            for (int j = 1; j <= 3; j++)
+              {
+                in >> el.PNum(j);
+                // 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);
+          }
+      
+      
+        cout << "points: " << np << " faces: " << nbe << endl;
+      }
+  
+  
+  
+
+  
+    if ( (strlen (filename) > 4) &&
+         strcmp (&filename[strlen (filename)-4], ".unv") == 0 )
+      {  
+        char reco[100];
+        int invert;
+      
+        ifstream in(filename);
+
+        mesh.ClearFaceDescriptors();
+        mesh.AddFaceDescriptor (FaceDescriptor(0,1,0,0));
+
+
+        while (in.good())
+          {
+            in >> reco;
+	    cout << "reco = " << reco << endl;
+
+            if (strcmp (reco, "2411") == 0)
+              {
+                cout << "nodes found" << endl;
+
+                while (1)
+                  {
+                    int pi, hi;
+                    Point<3> p;
+
+                    in >> pi;
+                    if (pi == -1)
+                      break;
+		    
+                    in >> hi >> hi >> hi;
+                    in >> p(0) >> p(1) >> p(2);
+
+		    cout << "p(" << pi << ") = "
+			 << p << endl;
+
+                    mesh.AddPoint (p);
+                  }
+		cout << "read " << mesh.GetNP() << " points" << endl;
+              }
+
+            if (strcmp (reco, "2412") == 0)
+              {
+                cout << "elements found" << endl;
+
+                while (1)
+                  {
+		    int label, fe_id, phys_prop, mat_prop, color, nnodes;
+		    int nodes[100];
+		    int hi;
+
+		    in >> label;
+		    if (label == -1) break;
+		    in >> fe_id >> phys_prop >> mat_prop >> color >> nnodes;
+		    
+		    cout << "fe_id = " << fe_id << " col = " << color << ", nnodes = " << nnodes << endl;
+
+		    if (fe_id >= 11 && fe_id <= 32)
+		      in >> hi >> hi >> hi;
+		      
+
+		    for (int j = 0; j < nnodes; j++)
+		      in >> nodes[j];
+		    
+		    switch (fe_id)
+		      {
+		      case 41:
+			{
+			  Element2d el (TRIG);
+			  el.SetIndex (1);
+			  for (int j = 0; j < nnodes; j++)
+			    el[j] = nodes[j];
+			  mesh.AddSurfaceElement (el);
+			  
+			  break;
+			}
+		      case 111:
+			{
+			  Element el (TET);
+			  el.SetIndex (1);
+			  for (int j = 0; j < nnodes; j++)
+			    el[j] = nodes[j];
+			  mesh.AddVolumeElement (el);
+			  
+			  break;
+			}
+		      }
+                  }
+              }
+          }
+      
+
+        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 == 3 ? TRIG : QUAD);
+            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;
+      
+        int np, ne, nse, i, j;
+
+        ifstream in (filename);
+
+        in >> np;
+
+        if (in.good())
+          {
+            // file starts with an integer
+
+            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);
+              }
+
+            mesh.AddFaceDescriptor (FaceDescriptor (1, 1, 0, 0));
+	  
+            in >> nse;
+            for (i = 1; i <= nse; i++)
+              {
+                int mat; // , nelp;
+                in >> mat;
+                Element2d el (TRIG);
+                el.SetIndex (mat);
+                for (j = 1; j <= 3; j++)
+                  in >> el.PNum(j);
+                mesh.AddSurfaceElement (el);
+              }
+          }
+        else
+          {
+            char buf[100];
+            in.clear();
+            do
+              {
+                in >> buf;
+                cout << "buf = " << buf << endl;
+                if (strcmp (buf, "points") == 0)
+                  {
+                    in >> np;
+                    cout << "np = " << np << endl;
+                  }
+              }
+            while (in.good());
+          }
+      }
+
+
+    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 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)(0) < 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);
+          }
+      }
+
+
+    // .tet mesh
+    if ( (strlen (filename) > 4) &&
+         strcmp (&filename[strlen (filename)-4], ".tet") == 0 )
+      {
+        ReadTETFormat (mesh, filename);
+      }
+
+
+    // .fnf mesh (FNF - PE neutral format)
+    if ( (strlen (filename) > 4) &&
+         strcmp (&filename[strlen (filename)-4], ".fnf") == 0 )
+      {
+        ReadFNFFormat (mesh, filename);
+      }
+
+  }
+  
+}
+
diff --git a/contrib/Netgen/libsrc/interface/writeOpenFOAM15x.cpp b/contrib/Netgen/libsrc/interface/writeOpenFOAM15x.cpp
new file mode 100644
index 0000000000..337e49eff1
--- /dev/null
+++ b/contrib/Netgen/libsrc/interface/writeOpenFOAM15x.cpp
@@ -0,0 +1,768 @@
+/*! \file writeOpenFOAM15x.cpp
+*  \brief Export Netgen Mesh in the OpenFOAM 1.5+ File format
+*  \author Philippose Rajan
+*  \date 25 October 2009
+*
+*  This function extends the export capabilities of
+*  Netgen to include the OpenFOAM 1.5+ File Format.
+*
+*  The OpenFOAM 1.5+ mesh format consists of a set of 5 files 
+*  which together define the mesh points, faces, cells and 
+*  boundary conditions. 
+*
+*  The files are:
+*  1. points    -> A list of the point co-ordinates
+*  2. faces     -> A list of the faces with format <n>(pnt_ind1 pnt_ind2 .... pnt_ind<n>)
+*  3. owner     -> The owner cell of each face 
+*  4. neighbour -> The neighbour cell of each face
+*  5. boundary  -> The set of boundaries with name, start face, and num. of faces
+*
+*  For a detailed description of the format, refer to the following link:
+*  http://openfoamwiki.net/index.php/Write_OpenFOAM_meshes
+*
+*/
+
+#include <mystdlib.h>
+
+#include <myadt.hpp>
+#include <linalg.hpp>
+#include <csg.hpp>
+#include <meshing.hpp>
+#include <sys/stat.h>
+
+
+namespace netgen
+{
+#include "writeuser.hpp"
+
+   // Global arrays used to maintain the owner, neighbour and face lists 
+   // so that they are accessible across functions
+   static Array<int> owner_facelist;
+   static Array<int> owner_celllist;
+   static Array<int> neighbour_celllist;
+   static Array<int> surfelem_bclist;
+   static Array<INDEX_2> surfelem_lists;
+
+
+
+   static void WriteOpenFOAM15xBanner(ofstream & outfile)
+   {
+      static char FOAMversion[4] = "1.5";
+      static char spaces[40];
+
+      memset(spaces, ' ', 40);
+      spaces[38 - strlen(FOAMversion)] = '\0';
+      
+      outfile << 
+              "/*--------------------------------*- C++ -*----------------------------------*\\\n";
+
+      outfile <<
+              "| =========                 |                                                 |\n"
+              "| \\\\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |\n"
+              "|  \\\\    /   O peration     | Version:  " << FOAMversion << spaces << "|\n"
+              "|   \\\\  /    A nd           | Web:      http://www.OpenFOAM.org               |\n"
+              "|    \\\\/     M anipulation  |                                                 |\n"
+              "\\*---------------------------------------------------------------------------*/\n";
+
+   }
+
+
+
+   static void WriteOpenFOAM15xDividerStart(ofstream & outfile)
+   {
+      outfile  <<
+               "// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //\n";
+   }
+
+
+
+   static void WriteOpenFOAM15xDividerEnd(ofstream & outfile)
+   {
+      outfile <<
+              "// ************************************************************************* //\n";
+   }
+
+
+
+   static bool BuildOwnerNeighbourLists (const Mesh & mesh)
+   {
+      // Clear all the arrays
+      owner_facelist.DeleteAll();
+      owner_celllist.DeleteAll();
+      neighbour_celllist.DeleteAll();
+      surfelem_bclist.DeleteAll();
+      surfelem_lists.DeleteAll();
+
+      const MeshTopology& meshtopo = mesh.GetTopology();
+      
+      // Update the mesh topology structures
+      const_cast<MeshTopology&> (meshtopo).SetBuildEdges(true);
+      const_cast<MeshTopology&> (meshtopo).SetBuildFaces(true);
+      const_cast<MeshTopology&> (meshtopo).Update();
+
+      // Extract important mesh metrics
+      int ne = mesh.GetNE();
+      int nse = mesh.GetNSE();
+      int totfaces = meshtopo.GetNFaces();
+
+      // Preset the size of the arrays to speed up future operations
+      // Number of internal faces = total faces - num. of surface faces
+      owner_facelist.SetSize(totfaces - nse);
+      owner_celllist.SetSize(totfaces - nse);
+      neighbour_celllist.SetSize(totfaces - nse);
+      surfelem_bclist.SetSize(nse);
+      surfelem_lists.SetSize(nse);
+
+      // Initialise arrays to zero if required
+      neighbour_celllist = 0;
+
+      // Array used to keep track of Faces which have already been 
+      // processed and added to the Owner list... In addition, also the 
+      // location where the face appears in the Owner list is also stored 
+      // to speed up creation of the Neighbour list
+      Array<int> ownerfaces(totfaces);
+      ownerfaces = 0;
+
+      // Array to hold the set of local faces of each volume element 
+      // while running through the set of volume elements
+      // NOTE: The size is set automatically by the Netgen topology function
+      Array<int> locfaces;
+
+      // Secondary indices used to independently advance the owner 
+      // and boundary condition arrays within the main loop
+      int owner_ind = 1;
+      int bc_ind = 1;
+
+      // Loop through all the volume elements
+      for(int elind = 1; elind <= ne; elind++)
+      {
+         // Extract the current volume element
+	// const Element & el = mesh.VolumeElement(elind);
+
+         // Get the face numbers of the faces of the current volume element
+         // The values returned are given a sign depending on the orientation 
+         // of the faces. This is used while writing the faces file, to 
+         // determine whether or not to invert the face triangle before writing 
+         // it to file
+         meshtopo.GetElementFaces(elind,locfaces,true);
+
+         // Loop through the faces
+         for(int i = 1; i <= locfaces.Size(); i++)
+         {
+            // The absolute value of a face number (because the faces 
+            // returned by the GetElementFaces function prepend it 
+            // with a sign depending on the face orientation)
+            int absfacenr = abs(locfaces.Elem(i));
+
+            // If the face already exists in the owner list, add 
+            // the current cell into the neighbour list, in the 
+            // same location where the face appears in the owner list
+            int owner_face = ownerfaces.Elem(absfacenr);
+            if(owner_face)
+            {
+               neighbour_celllist.Elem(owner_face) = elind;
+
+               // From this point on, the code within this "if" block 
+               // basically sorts the order of the the Neighbour cells (along 
+               // with the faces list) in ascending order.
+               // The approach used is..... to traverse the owner and neighbour cell lists
+               // up and down, and sort the neighbour cells of a given owner cell 
+               // as the list evolves.
+               // NOTE: A value of "zero" in the neighbour list implies that 
+               // the neighbour has not been found yet, so the "zero" locations need 
+               // to be skipped while sorting in ascending order
+               int curr_owner = owner_celllist.Elem(owner_face);
+
+               int peek_loc = owner_face - 1;
+               int new_loc = owner_face;
+
+               // Traversing upwards in the list
+               while((owner_celllist.Elem(peek_loc) == curr_owner) && (peek_loc >= 1))
+               {
+                  if((neighbour_celllist.Elem(peek_loc) != 0) 
+                     && (neighbour_celllist.Elem(new_loc) < neighbour_celllist.Elem(peek_loc)))
+                  {
+                     Swap(neighbour_celllist.Elem(new_loc),neighbour_celllist.Elem(peek_loc));
+                     Swap(owner_facelist.Elem(new_loc),owner_facelist.Elem(peek_loc));
+                     new_loc = peek_loc;
+                  }
+
+                  peek_loc--;
+               }
+
+               peek_loc = owner_face + 1;
+
+               // Traversing downwards in the list
+               while((owner_celllist.Elem(peek_loc) == curr_owner) && (peek_loc <= owner_ind))
+               {
+                  if((neighbour_celllist.Elem(peek_loc) != 0) 
+                     && (neighbour_celllist.Elem(new_loc) > neighbour_celllist.Elem(peek_loc)))
+                  {
+                     Swap(neighbour_celllist.Elem(new_loc),neighbour_celllist.Elem(peek_loc));
+                     Swap(owner_facelist.Elem(new_loc),owner_facelist.Elem(peek_loc));
+                     new_loc = peek_loc;
+                  }
+
+                  peek_loc++;
+               }
+
+               continue;
+            }
+
+            // Check if the face is a surface element (boundary face)
+            // if not, add the current volume element and the corresponding face into 
+            // the owner list
+            int surfelem = meshtopo.GetFace2SurfaceElement(absfacenr);
+            if(!surfelem)
+            {
+               // If it is a new face which has not been listed before, 
+               // add the current cell into the owner list, and save 
+               // the index location to be used later by the neighbour list
+               owner_celllist.Elem(owner_ind) = elind;
+               owner_facelist.Elem(owner_ind) = locfaces.Elem(i);
+               // Update the array to indicate that the face is already processed
+               ownerfaces.Elem(absfacenr) = owner_ind;
+
+               owner_ind++;
+            }
+            // If the face is a boundary face, extract the boundary condition number of the 
+            // face, and append that along with the face number and the current cell 
+            // into the various surface elements lists
+            else
+            {
+               Element2d sel = mesh.SurfaceElement(surfelem);
+               surfelem_bclist.Elem(bc_ind) = mesh.GetFaceDescriptor(sel.GetIndex()).BCProperty();
+               surfelem_lists.Elem(bc_ind) = INDEX_2(locfaces.Elem(i),elind);
+
+               bc_ind++;
+            }
+         }
+      }
+
+      // This correction is required in cases where the mesh has been "uniform refined".... for 
+      // some reason, the number of faces reported by Netgen is higher than the actual number 
+      // of faces in the mesh
+      owner_facelist.SetSize(owner_ind-1);
+      owner_celllist.SetSize(owner_ind-1);
+      neighbour_celllist.SetSize(owner_ind-1);
+
+
+      // Sort the list of surface elements in ascending order of boundary condition number
+      // also sort the cell list in the same manner
+      QuickSort(surfelem_bclist,surfelem_lists);
+
+/*    
+      // Debugging output to a file 
+      ofstream dbg("OpenFOAMDebug.log");
+
+      dbg << " ------- Boundary List -------- \n";
+
+      for(int i = 1; i <= surfelem_bclist.Size(); i++)
+      {
+         dbg << "bc = " << surfelem_bclist.Elem(i) 
+              << " : face = " << surfelem_lists.Elem(i).I1()
+              << " : cell = " << surfelem_lists.Elem(i).I2() << "\n";
+      }
+
+      dbg << "\n ------- Owner / Face / Neighbour List ------- \n";
+
+      for(int i = 1; i <= owner_celllist.Size(); i++)
+      {
+         dbg << "Ind:" << i << " :: (" 
+              << owner_celllist.Elem(i) << " "
+              << owner_facelist.Elem(i) << "  "
+              << neighbour_celllist.Elem(i) << ")\n";
+      }
+
+      dbg.close();
+*/
+      return(false);
+   }
+
+
+
+   static void WriteNeighbourFile (ofstream & outfile)
+   {
+      // Write the OpenFOAM standard banner and dividers, etc...
+      WriteOpenFOAM15xBanner(outfile);
+      outfile << "FoamFile \n"
+              << "{ \n"
+              << "    version     2.0; \n"
+              << "    format      ascii; \n"
+              << "    class       labelList; \n"
+              << "    note        \"Mesh generated and converted using NETGEN-" << PACKAGE_VERSION << "\"; \n"
+              << "    location    \"constant\\polyMesh\"; \n"
+              << "    object      neighbour; \n"
+              << "} \n";
+      WriteOpenFOAM15xDividerStart(outfile);
+
+      outfile << "\n\n";
+
+      int nneighbours = neighbour_celllist.Size();
+
+      outfile << nneighbours << "\n";
+
+      outfile << "(\n";
+
+      // Write the neighbour cells to file
+      for(int i = 1; i <= neighbour_celllist.Size(); i++)
+      {
+         outfile << neighbour_celllist.Elem(i) - 1 << "\n";
+      }
+      outfile << ")\n\n";
+      WriteOpenFOAM15xDividerEnd(outfile);
+   }
+
+
+
+   static void WriteOwnerFile (ofstream & outfile)
+   {
+      // Write the OpenFOAM standard banner and dividers, etc...
+      WriteOpenFOAM15xBanner(outfile);
+      outfile << "FoamFile \n"
+              << "{ \n"
+              << "    version     2.0; \n"
+              << "    format      ascii; \n"
+              << "    class       labelList; \n"
+              << "    note        \"Mesh generated and converted using NETGEN-" << PACKAGE_VERSION << "\"; \n"
+              << "    location    \"constant\\polyMesh\"; \n"
+              << "    object      owner; \n"
+              << "} \n";
+      WriteOpenFOAM15xDividerStart(outfile);
+
+      outfile << "\n\n";
+
+      int nowners = owner_celllist.Size() + surfelem_lists.Size();
+
+      outfile << nowners << "\n";
+
+      outfile << "(\n";
+
+      // Write the owners of the internal cells to file
+      for(int i = 1; i <= owner_celllist.Size(); i++)
+      {
+         outfile << owner_celllist.Elem(i) - 1 << "\n";
+      }
+
+      // Write the owners of the boundary cells to file
+      // (Written in order of ascending boundary condition numbers)
+      for(int i = 1; i <= surfelem_lists.Size(); i++)
+      {
+         outfile << surfelem_lists.Elem(i).I2() - 1 << "\n";
+      }
+      outfile << ")\n\n";
+      WriteOpenFOAM15xDividerEnd(outfile);
+   }
+
+
+
+   static void WriteFacesFile (ofstream & outfile, const Mesh & mesh)
+   {
+      const MeshTopology& meshtopo = mesh.GetTopology();
+
+      // Write the OpenFOAM standard banner and dividers, etc...
+      WriteOpenFOAM15xBanner(outfile);
+      outfile << "FoamFile \n"
+              << "{ \n"
+              << "    version     2.0; \n"
+              << "    format      ascii; \n"
+              << "    class       faceList; \n"
+              << "    note        \"Mesh generated and converted using NETGEN-" << PACKAGE_VERSION << "\"; \n"
+              << "    location    \"constant\\polyMesh\"; \n"
+              << "    object      faces; \n"
+              << "} \n";
+      WriteOpenFOAM15xDividerStart(outfile);
+
+      outfile << "\n\n";
+
+      int nfaces = owner_facelist.Size() + surfelem_lists.Size();
+
+      outfile << nfaces << "\n";
+
+      outfile << "(\n";
+
+      // Array to hold the indices of the points of each face to 
+      // flip if required 
+      Array<int> facepnts;
+
+      // Write the faces in the order specified in the owners lists of the 
+      // internal cells and the boundary cells
+      for(int i = 1; i <= owner_facelist.Size(); i++)
+      {
+         int face_w_orientation = owner_facelist.Elem(i);
+         int facenr = abs(face_w_orientation);
+
+         meshtopo.GetFaceVertices(facenr,facepnts);
+
+         // Get the orientation of the face, and invert it if required
+         // Since the faces already have the orientation "embedded" into 
+         // them by means of the prepended sign, only this needs to be 
+         // checked for...
+         if(face_w_orientation > 0)
+         {
+            int tmppnts = 0;
+
+            if(facepnts.Size() == 4)
+            {
+               tmppnts = facepnts.Elem(1);
+               facepnts.Elem(1) = facepnts.Elem(2);
+               facepnts.Elem(2) = tmppnts;
+               
+               tmppnts = facepnts.Elem(3);
+               facepnts.Elem(3) = facepnts.Elem(4);
+               facepnts.Elem(4) = tmppnts;
+            }
+            else if(facepnts.Size() == 3)
+            {
+               tmppnts = facepnts.Elem(1);
+               facepnts.Elem(1) = facepnts.Elem(3);
+               facepnts.Elem(3) = tmppnts;
+            }
+         }
+
+         outfile << facepnts.Size();
+         outfile << "(";
+         for(int j = 1; j <= facepnts.Size(); j++)
+         {
+            outfile << facepnts.Elem(j)-1;
+            if(j != facepnts.Size()) outfile << " ";
+         }
+         outfile << ")\n";
+      }
+
+      // Now append the faces of the surface elements (written in 
+      // ascending order of boundary condition number) also into 
+      // the faces file
+      for(int i = 1; i <= surfelem_lists.Size(); i++)
+      {
+         int face_w_orientation = surfelem_lists.Elem(i).I1();
+         int facenr = abs(face_w_orientation);
+
+         meshtopo.GetFaceVertices(facenr,facepnts);
+
+         // Get the orientation of the face, and invert it if required
+         if(face_w_orientation > 0)
+         {
+            int tmppnts = 0;
+
+            if(facepnts.Size() == 4)
+            {
+               tmppnts = facepnts.Elem(1);
+               facepnts.Elem(1) = facepnts.Elem(2);
+               facepnts.Elem(2) = tmppnts;
+               
+               tmppnts = facepnts.Elem(3);
+               facepnts.Elem(3) = facepnts.Elem(4);
+               facepnts.Elem(4) = tmppnts;
+            }
+            else if(facepnts.Size() == 3)
+            {
+               tmppnts = facepnts.Elem(1);
+               facepnts.Elem(1) = facepnts.Elem(3);
+               facepnts.Elem(3) = tmppnts;
+            }
+         }
+
+         outfile << facepnts.Size();
+         outfile << "(";
+         for(int j = 1; j <= facepnts.Size(); j++)
+         {
+            outfile << facepnts.Elem(j)-1;
+            if(j != facepnts.Size()) outfile << " ";
+         }
+         outfile << ")\n";
+      }
+
+      outfile << ")\n\n";
+      WriteOpenFOAM15xDividerEnd(outfile);
+   }
+
+
+ 
+   static void WritePointsFile (ofstream & outfile, const Mesh & mesh)
+   {
+      int np = mesh.GetNP();
+
+      // Write the OpenFOAM standard banner and dividers, etc...
+      WriteOpenFOAM15xBanner(outfile);
+      outfile << "FoamFile \n"
+              << "{ \n"
+              << "    version     2.0; \n"
+              << "    format      ascii; \n"
+              << "    class       vectorField; \n"
+              << "    note        \"Mesh generated and converted using NETGEN-" << PACKAGE_VERSION << "\"; \n"
+              << "    location    \"constant\\polyMesh\"; \n"
+              << "    object      points; \n"
+              << "} \n";
+      WriteOpenFOAM15xDividerStart(outfile);
+
+      outfile << "\n\n";
+
+      // Number of points in the following list
+      outfile << np << "\n";
+
+      outfile.precision(6);
+      outfile.setf (ios::fixed, ios::floatfield);
+      outfile.setf (ios::showpoint);
+
+      // Coordinate list starts here
+      outfile << "(\n";
+
+      for(int i = 1; i <= np; i++)
+      {
+         const Point3d & p = mesh.Point(i);
+
+         // Write coordinates to file
+         outfile << "(";
+         outfile << p.X() << " ";
+         outfile << p.Y() << " ";
+         outfile << p.Z();
+         outfile << ")\n";
+      }
+      outfile << ")\n\n";
+      WriteOpenFOAM15xDividerEnd(outfile);
+   }
+
+
+
+   static void WriteBoundaryFile (ofstream & outfile)
+   {
+      // Write the OpenFOAM standard banner and dividers, etc...
+      WriteOpenFOAM15xBanner(outfile);
+      outfile << "FoamFile \n"
+              << "{ \n"
+              << "    version     2.0; \n"
+              << "    format      ascii; \n"
+              << "    class       polyBoundaryMesh; \n"
+              << "    note        \"Mesh generated and converted using NETGEN-" << PACKAGE_VERSION << "\"; \n"
+              << "    location    \"constant\\polyMesh\"; \n"
+              << "    object      boundary; \n"
+              << "} \n";
+      WriteOpenFOAM15xDividerStart(outfile);
+
+      outfile << "\n";
+
+
+      Array<INDEX_3> bcarray;
+      int ind = 1;
+
+      // Since the boundary conditions are already sorted in ascending 
+      // order, the last element will give the maximum number of possible 
+      // boundary condition entries
+      int bcmax = surfelem_bclist.Elem(surfelem_bclist.Size());
+
+      bcarray.SetSize(bcmax+1);
+
+      bcarray.Elem(ind) = INDEX_3(surfelem_bclist.Elem(1),1,0);
+            
+      for(int i = 2; i <= surfelem_bclist.Size(); i++)
+      {
+         if(surfelem_bclist.Elem(i) == bcarray.Elem(ind).I1())
+         {
+            bcarray.Elem(ind).I2() = bcarray.Elem(ind).I2()+1;
+         }
+         else
+         {
+            ind++;
+            bcarray.Elem(ind) = INDEX_3(surfelem_bclist.Elem(i),1,i-1);
+         }
+      }
+
+      bcarray.SetSize(ind);
+
+      outfile << bcarray.Size() << "\n";
+      outfile << "(\n";
+
+      int startface = 0;
+
+      for(int i = 1; i <= bcarray.Size(); i++)
+      {
+         startface = owner_celllist.Size() + bcarray.Elem(i).I3();
+
+         outfile << "    patch" << bcarray.Elem(i).I1() << "\n"
+                 << "    {\n"
+                 << "        type            patch;\n"
+                 << "        physicalType    patch;\n"
+                 << "        nFaces          " << bcarray.Elem(i).I2() << ";\n"
+                 << "        startFace       " << startface << ";\n"
+                 << "    }\n";
+      }
+
+      outfile << ")\n\n";
+      WriteOpenFOAM15xDividerEnd(outfile);
+   }
+
+
+
+   void WriteOpenFOAM15xFormat (const Mesh & mesh, const string & casename)
+   {
+      bool error = false;
+      char casefiles[256];
+
+      // Make sure that the mesh data has been updated
+      const_cast<Mesh&> (mesh).Compress();
+      const_cast<Mesh&> (mesh).CalcSurfacesOfNode();
+      const_cast<Mesh&> (mesh).RebuildSurfaceElementLists();
+      const_cast<Mesh&> (mesh).BuildElementSearchTree();
+
+
+      int np = mesh.GetNP();
+      int nse = mesh.GetNSE();
+      int ne = mesh.GetNE();
+
+      cout << "Write OpenFOAM 1.5+ Mesh Files....\n";
+
+      // Abort if there are no points, surface elements or volume elements
+      if((np <= 0) || (ne <= 0) || (nse <= 0))
+      {
+         cout << "Export Error: Invalid mesh.... Aborting!\n";
+         return;
+      }
+
+      // OpenFOAM only supports linear meshes!
+      if(mparam.secondorder || mesh.GetCurvedElements().IsHighOrder())
+      {
+         cout << "Export Error: OpenFOAM 1.5+ does not support non-linear elements.... Aborting!\n";
+         return;
+      }
+
+      if(( (mesh.SurfaceElement(nse/2).GetType() != TRIG) 
+	   && (mesh.SurfaceElement(nse/2).GetType() != QUAD) )
+         || (mesh.VolumeElement(ne/2).GetType() == TET10)
+         || (mesh.VolumeElement(ne/2).GetType() == PRISM12))
+      {
+         cout << "Export Error: OpenFOAM 1.5+ does not support non-linear elements.... Aborting!\n";
+         return;
+      }
+
+
+      cout << "Writing OpenFOAM 1.5+ Mesh files to case: " << casename << "\n";
+
+      // Create the case directory if it does not already exist
+      // NOTE: This needs to be improved for the Linux variant....!!!
+   #ifdef WIN32
+      char casedir[256];
+      sprintf(casedir, "mkdir %s\\constant\\polyMesh", casename.c_str());
+      system(casedir);
+   #else
+      char casedir[256];
+      mkdir(casename.c_str(), S_IRWXU|S_IRWXG);
+      sprintf(casedir, "%s/constant", casename.c_str());
+      mkdir(casedir, S_IRWXU|S_IRWXG);
+      sprintf(casedir, "%s/constant/polyMesh", casename.c_str());
+      mkdir(casedir, S_IRWXU|S_IRWXG);
+   #endif
+
+      // Open handles to the five required mesh files
+      // points
+      // faces
+      // owner
+      // neighbour
+      // boundary
+      sprintf(casefiles, "%s/constant/polyMesh/points", casename.c_str());
+      ofstream outfile_pnts(casefiles);
+      sprintf(casefiles, "%s/constant/polyMesh/faces", casename.c_str()); 
+      ofstream outfile_faces(casefiles);
+      sprintf(casefiles, "%s/constant/polyMesh/owner", casename.c_str()); 
+      ofstream outfile_own(casefiles);
+      sprintf(casefiles, "%s/constant/polyMesh/neighbour", casename.c_str()); 
+      ofstream outfile_nei(casefiles);
+      sprintf(casefiles, "%s/constant/polyMesh/boundary", casename.c_str()); 
+      ofstream outfile_bnd(casefiles);
+
+      ResetTime();
+
+      // Build the owner, neighbour, faces and boundary lists 
+      // from the Netgen mesh
+      cout << "\nBuilding Owner, Neighbour and Face Lists: ";
+
+      error = BuildOwnerNeighbourLists(mesh);
+
+      cout << "Done! (Time Elapsed = " << GetTime() << " sec)\n";
+
+
+      // Write the "owner" file
+      if(outfile_own.good() && !error)
+      {
+         cout << "Writing the owner file: ";
+         WriteOwnerFile(outfile_own);
+         outfile_own.close();
+         cout << "Done! (Time Elapsed = " << GetTime() << " sec)\n";
+      }
+      else
+      {
+         cout << "Export Error: Error creating file: owner.... Aborting\n";
+         error = true;
+      }
+
+
+      // Write the "neighbour" file
+      if(outfile_nei.good() && !error)
+      {
+         cout << "Writing the neighbour file: ";
+         WriteNeighbourFile(outfile_nei);
+         outfile_nei.close();
+         cout << "Done! (Time Elapsed = " << GetTime() << " sec)\n";
+      }
+      else
+      {
+         cout << "Export Error: Error creating file: neighbour.... Aborting\n";
+         error = true;
+      }
+
+
+      // Write the "faces" file
+      if(outfile_faces.good() && !error)
+      {
+         cout << "Writing the faces file: ";
+         WriteFacesFile(outfile_faces, mesh);
+         outfile_faces.close();
+         cout << "Done! (Time Elapsed = " << GetTime() << " sec)\n";
+      }
+      else
+      {
+         cout << "Export Error: Error creating file: faces.... Aborting\n";
+         error = true;
+      }
+
+
+      // Write the "points" file
+      if(outfile_pnts.good() && !error)
+      {
+         cout << "Writing the points file: ";
+         WritePointsFile(outfile_pnts,mesh);
+         outfile_pnts.close();
+         cout << "Done! (Time Elapsed = " << GetTime() << " sec)\n";
+      }
+      else
+      {
+         cout << "Export Error: Error creating file: points.... Aborting\n";
+         error = true;
+      }
+
+
+      // Write the "boundary" file
+      if(outfile_bnd.good() && !error)
+      {
+         cout << "Writing the boundary file: ";
+         WriteBoundaryFile(outfile_bnd);
+         outfile_bnd.close();
+         cout << "Done! (Time Elapsed = " << GetTime() << " sec)\n";
+      }
+      else
+      {
+         cout << "Export Error: Error creating file: boundary.... Aborting\n";
+         error = true;
+      }
+
+      if(!error)
+      {
+         cout << "OpenFOAM 1.5+ Export successfully completed (Time elapsed = " << GetTime() << " sec) !\n";
+      }
+      else
+      {
+         cout << "Error in OpenFOAM 1.5+ Export.... Aborted!\n";
+      }
+   }
+}
+
diff --git a/contrib/Netgen/libsrc/interface/writeabaqus.cpp b/contrib/Netgen/libsrc/interface/writeabaqus.cpp
new file mode 100644
index 0000000000..6f2f165cb7
--- /dev/null
+++ b/contrib/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)(0) << ", ";
+      outfile << mesh.Point(i)(1) << ", ";
+      outfile << mesh.Point(i)(2) << "\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);
+      size_t 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(0);
+
+      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/contrib/Netgen/libsrc/interface/writediffpack.cpp b/contrib/Netgen/libsrc/interface/writediffpack.cpp
new file mode 100644
index 0000000000..82eb236dc0
--- /dev/null
+++ b/contrib/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[PointIndex(i)].Type() != 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[PointIndex(i)].Type() != 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/contrib/Netgen/libsrc/interface/writedolfin.cpp b/contrib/Netgen/libsrc/interface/writedolfin.cpp
new file mode 100644
index 0000000000..8fd9e7497a
--- /dev/null
+++ b/contrib/Netgen/libsrc/interface/writedolfin.cpp
@@ -0,0 +1,69 @@
+//
+//  Write dolfin file
+//
+//  by
+//  Kent-Andre Mardal <kent-and@simula.no>
+
+
+#include <mystdlib.h>
+
+#include <myadt.hpp>
+#include <linalg.hpp>
+#include <csg.hpp>
+#include <meshing.hpp>
+
+namespace netgen
+{
+
+#include "writeuser.hpp"
+
+
+
+  void WriteDolfinFormat (const Mesh & mesh, const string & filename)
+  {
+    cout << "start writing dolfin export" << endl;
+
+    int np = mesh.GetNP();
+    int ne = mesh.GetNE();
+    // int nse = mesh.GetNSE();
+    int nsd = mesh.GetDimension(); 
+    // int invertsurf = mparam.inverttrigs;
+    // int i, j;
+
+    ofstream outfile (filename.c_str());
+
+    // char str[100];
+    outfile.precision(8);
+    outfile.setf (ios::fixed, ios::floatfield);
+    outfile.setf (ios::showpoint);
+
+    if ( nsd == 3) {
+
+      outfile << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" <<endl; 
+      outfile << ""<<endl; 
+
+      outfile << "<dolfin xmlns:dolfin=\"http://www.phi.chalmers.se/dolfin/\">"<<endl;
+      outfile << "  <mesh celltype=\"tetrahedron\" dim=\"3\">" <<endl; 
+      outfile << "      <vertices size=\""<<np<<"\">"<<endl; 
+      for (int i = 1; i <= np; i++) { 
+        const Point3d & p = mesh.Point(i);
+        outfile << "      <vertex index=\""<<i-1<<"\" x=\""<<p.X()<<"\" y=\""<<p.Y()<<"\" z=\""<<p.Z()<<"\"/>"<<endl; 
+      }
+      outfile << "      </vertices>"<<endl; 
+
+
+
+      outfile << "      <cells size=\""<<ne<<"\">"<<endl; 
+      for (int i = 1; i <= ne; i++) {
+        const Element & el = mesh.VolumeElement(i);
+
+        outfile << "      <tetrahedron index=\""<<i-1<<"\" v0=\""<<el.PNum(1)-1<<"\" v1=\""<<el.PNum(2)-1<<"\" v2=\""<<el.PNum(3)-1<<"\" v3=\""<<el.PNum(4)-1<<"\"/>"<<endl; 
+      }
+      outfile << "      </cells>"<<endl; 
+    }
+    outfile << "   </mesh>"<<endl; 
+    outfile << "</dolfin>"<<endl; 
+
+    cout << "done writing dolfin export" << endl;
+  }
+}
diff --git a/contrib/Netgen/libsrc/interface/writeelmer.cpp b/contrib/Netgen/libsrc/interface/writeelmer.cpp
new file mode 100644
index 0000000000..664a6dadab
--- /dev/null
+++ b/contrib/Netgen/libsrc/interface/writeelmer.cpp
@@ -0,0 +1,132 @@
+
+//
+//  Write Elmer file
+//
+//
+
+#include <mystdlib.h>
+
+#include <myadt.hpp>
+#include <linalg.hpp>
+#include <csg.hpp>
+#include <meshing.hpp>
+#include <sys/stat.h>
+
+
+namespace netgen
+{
+#include "writeuser.hpp"
+
+
+
+void WriteElmerFormat (const Mesh &mesh,
+			 const string &filename)
+{
+  cout << "write elmer mesh files" << endl;
+  int np = mesh.GetNP();
+  int ne = mesh.GetNE();
+  int nse = mesh.GetNSE();
+  int i, j;
+  char str[200];
+  
+  int inverttets = mparam.inverttets;
+  int invertsurf = mparam.inverttrigs;
+
+#ifdef WIN32
+  char a[256];
+  sprintf( a, "mkdir %s", filename.c_str() );
+  system( a );
+#else
+  // int rc = 
+  mkdir(filename.c_str(), S_IRWXU|S_IRWXG);
+#endif
+
+  sprintf( str, "%s/mesh.header", filename.c_str() );
+  ofstream outfile_h(str);
+  sprintf( str, "%s/mesh.nodes", filename.c_str() );
+  ofstream outfile_n(str);
+  sprintf( str, "%s/mesh.elements", filename.c_str() );
+  ofstream outfile_e(str);
+  sprintf( str, "%s/mesh.boundary", filename.c_str() );
+  ofstream outfile_b(str);
+
+  // 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);
+	}
+    }
+
+//  outfile.precision(6);
+//  outfile.setf (ios::fixed, ios::floatfield);
+//  outfile.setf (ios::showpoint);
+  
+  outfile_h << np << " " << ne << " " << nse << "\n";
+  outfile_h << "2"     << "\n";
+  outfile_h << "303 " << nse << "\n";
+  outfile_h << "504 " << ne << "\n";
+  
+  for (i = 1; i <= np; i++)
+    {
+      const Point3d & p = mesh.Point(i);
+      
+      outfile_n << i << " -1 ";
+      outfile_n << p.X() << " ";
+      outfile_n << p.Y() << " ";
+      outfile_n << p.Z() << "\n";
+    }
+
+  for (i = 1; i <= ne; i++)
+    {
+      Element el = mesh.VolumeElement(i);
+      if (inverttets) el.Invert();
+      sprintf( str, "5%02d", (int)el.GetNP() );
+      outfile_e << i << " " << el.GetIndex() << " " << str <<  "  ";
+      for (j = 1; j <= el.GetNP(); j++)
+	{
+	  outfile_e << " ";
+	  outfile_e << el.PNum(j);
+	}
+      outfile_e << "\n";
+    }
+
+  for (i = 1; i <= nse; i++)
+    {
+      Element2d el = mesh.SurfaceElement(i);
+      if (invertsurf) el.Invert();
+      sprintf( str, "3%02d", (int)el.GetNP() );
+      {
+	  INDEX_3 i3;
+	  for (j = 1; j <= 3; j++) i3.I(j) = el.PNum(j);
+	  i3.Sort();
+	  
+	  int elind = face2volelement.Get(i3);
+          outfile_b << i << " " << mesh.GetFaceDescriptor(el.GetIndex()).BCProperty() << 
+         " " << elind << " 0 "  << str << "    ";
+      }
+      for (j = 1; j <= el.GetNP(); j++)
+	{
+	  outfile_b << " ";
+	  outfile_b << el.PNum(j);
+	}
+      outfile_b << "\n";
+    }
+}
+
+}
diff --git a/contrib/Netgen/libsrc/interface/writefeap.cpp b/contrib/Netgen/libsrc/interface/writefeap.cpp
new file mode 100644
index 0000000000..85681aa0cf
--- /dev/null
+++ b/contrib/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;
+
+  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)(0)/scale << "  ";
+      outfile.width(10);
+      outfile << mesh.Point(i)(1)/scale << "  ";
+      outfile.width(10);
+      outfile << mesh.Point(i)(2)/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/contrib/Netgen/libsrc/interface/writefluent.cpp b/contrib/Netgen/libsrc/interface/writefluent.cpp
new file mode 100644
index 0000000000..c5dac392f6
--- /dev/null
+++ b/contrib/Netgen/libsrc/interface/writefluent.cpp
@@ -0,0 +1,193 @@
+//
+//  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"
+
+
+
+void WriteFluentFormat (const Mesh & mesh,
+			const string & filename)
+
+{
+  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 \")" << 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 << hex << face.PNum(2) << " "
+		<< hex << face.PNum(1) << " "
+		<< hex << face.PNum(3) << " "
+		<< hex << i  << " "
+		<< hex << 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 << hex << surfaceelp.Get(i).I1() << " "
+	      << hex << surfaceelp.Get(i).I2() << " "
+	      << hex << surfaceelp.Get(i).I3() << " "
+	      << hex << 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/contrib/Netgen/libsrc/interface/writegmsh.cpp b/contrib/Netgen/libsrc/interface/writegmsh.cpp
new file mode 100644
index 0000000000..93def67783
--- /dev/null
+++ b/contrib/Netgen/libsrc/interface/writegmsh.cpp
@@ -0,0 +1,200 @@
+/*************************************
+ * Write Gmsh file
+ * First issue the 04/26/2004 by Paul CARRICO (paul.carrico@free.fr)
+ * At the moment, the GMSH format is available for
+ * linear tetrahedron elements i.e. in 3D
+ * (based on Neutral Format)
+ *
+ * Second issue the 05/05/2004 by Paul CARRICO
+ * Thanks to Joachim Schoeberl for the correction of a minor bug
+ * the 2 initial Gmsh Format (i.e. volume format and surface format) are group together)
+ * in only one file
+ **************************************/
+
+#include <mystdlib.h>
+
+#include <myadt.hpp>
+#include <linalg.hpp>
+#include <csg.hpp>
+#include <meshing.hpp>
+
+namespace netgen
+{
+#include "writeuser.hpp"
+
+
+
+/*
+ *  GMSH mesh format
+ *  points, elements, surface elements and physical entities
+ */
+
+void WriteGmshFormat (const Mesh & mesh,
+			 const CSGeometry & geom,
+			 const string & filename)
+{
+  ofstream outfile (filename.c_str());
+  outfile.precision(6);
+  outfile.setf (ios::fixed, ios::floatfield);
+  outfile.setf (ios::showpoint);
+
+  int np = mesh.GetNP();  /// number of point
+  int ne = mesh.GetNE();  /// number of element
+  int nse = mesh.GetNSE();  /// number of surface element (BC)
+  int i, j, k, l;
+
+
+  /*
+   * 3D section : Linear volume elements (only tetrahedra)
+   */
+
+   if (ne > 0 && mesh.VolumeElement(1).GetNP() == 4)
+      {
+      cout << "Write GMSH Format \n";
+      cout << "The GMSH format is available for linear tetrahedron elements only in 3D\n" << endl;
+
+      int inverttets = mparam.inverttets;
+      int invertsurf = mparam.inverttrigs;
+
+
+      /// Write nodes
+      outfile << "$NOD\n";
+      outfile << np << "\n";
+  
+      for (i = 1; i <= np; i++)
+          {
+          const Point3d & p = mesh.Point(i);
+          outfile << i << " "; /// node number
+          outfile << p.X() << " ";
+          outfile << p.Y() << " ";
+          outfile << p.Z() << "\n";
+          }
+      outfile << "$ENDNOD\n";
+
+      /// write elements
+      outfile << "$ELM\n";
+      outfile << ne + nse << "\n";  ////  number of elements + number of surfaces BC
+
+     for (i = 1; i <= nse; i++)
+         {
+         Element2d el = mesh.SurfaceElement(i);
+         if (invertsurf) el.Invert();
+         outfile << i;
+         outfile << " ";
+         outfile << "2";
+         outfile << " ";
+         outfile << mesh.GetFaceDescriptor (el.GetIndex()).BCProperty() << " ";
+         /// that means that physical entity = elementary entity (arbitrary approach)
+         outfile << mesh.GetFaceDescriptor (el.GetIndex()).BCProperty() << " ";
+         outfile << "3";
+         outfile << " ";
+                 for (j = 1; j <= el.GetNP(); j++)
+                     {
+                     outfile << " ";
+                     outfile << el.PNum(j);
+                     }
+                     outfile << "\n";
+         }
+
+
+         for (i = 1; i <= ne; i++)
+             {
+             Element el = mesh.VolumeElement(i);
+             if (inverttets) el.Invert();
+             outfile << nse + i; /// element number
+             outfile << " ";
+             outfile << "4"; /// element type i.e. Tetraedron == 4
+             outfile << " ";
+             outfile << 100000 + el.GetIndex();
+             /// that means that physical entity = elementary entity (arbitrary approach)
+             outfile << " ";
+             outfile << 100000 + el.GetIndex();   /// volume number
+             outfile << " ";
+             outfile << "4";  /// number of nodes i.e. 4 for a tetrahedron
+                                                                                                        
+             for (j = 1; j <= el.GetNP(); j++)
+                 {
+                 outfile << " ";
+                 outfile << el.PNum(j);
+                 }
+             outfile << "\n";
+             }
+
+
+             outfile << "$ENDELM\n";
+   }
+
+   /*
+    * End of 3D section
+    */
+
+
+
+
+
+  /*
+   * 2D section : available for triangles and quadrangles
+   */
+      else if (ne == 0)   /// means that there's no 3D element
+              {
+              cout << "\n Write Gmsh Surface Mesh (triangle and/or quadrangles)" << endl;
+
+              /// Write nodes
+              outfile << "$NOD\n";
+              outfile << np << "\n";
+
+              for (i = 1; i <= np; i++)
+              {
+              const Point3d & p = mesh.Point(i);
+              outfile << i << " "; /// node number
+              outfile << p.X() << " ";
+              outfile << p.Y() << " ";
+              outfile << p.Z() << "\n";
+              }
+              outfile << "$ENDNOD\n";
+
+
+              /// write triangles & quadrangles
+              outfile << "$ELM\n";
+              outfile << nse << "\n";
+
+              for (k = 1; k <= nse; k++)
+              {
+              const Element2d & el = mesh.SurfaceElement(k);
+
+
+              outfile << k;
+              outfile << " ";
+              outfile << (el.GetNP()-1);   // 2 for a triangle and 3 for a quadrangle
+              outfile << " ";
+              outfile << mesh.GetFaceDescriptor (el.GetIndex()).BCProperty() << " ";
+              /// that means that physical entity = elementary entity (arbitrary approach)
+              outfile << mesh.GetFaceDescriptor (el.GetIndex()).BCProperty() << " ";
+              outfile << (el.GetNP());    // number of node per surfacic element
+              outfile << " ";
+
+              for (l = 1; l <= el.GetNP(); l++)
+                  {
+                  outfile << " ";
+                  outfile << el.PNum(l);
+                  }
+	              outfile << "\n";
+		  
+               }
+               outfile << "$ENDELM$ \n";
+    }
+
+   /*
+    * End of 2D section
+    */
+
+     else
+    {
+    cout << " Invalide element type for Gmsh volume Format !\n";
+    }
+
+
+}
+}
+
+
diff --git a/contrib/Netgen/libsrc/interface/writegmsh2.cpp b/contrib/Netgen/libsrc/interface/writegmsh2.cpp
new file mode 100644
index 0000000000..5ec3dc8f0c
--- /dev/null
+++ b/contrib/Netgen/libsrc/interface/writegmsh2.cpp
@@ -0,0 +1,261 @@
+/*! \file writegmsh2.cpp
+*  \brief Export Netgen Mesh in the GMSH v2.xx File format
+*  \author Philippose Rajan
+*  \date 02 November 2008
+*
+*  This function extends the export capabilities of
+*  Netgen to include the GMSH v2.xx File Format.
+*
+*  Current features of this function include:
+*
+*  1. Exports Triangles, Quadrangles and Tetrahedra \n
+*  2. Supports upto second order elements of each type
+*
+*/
+
+
+#include <mystdlib.h>
+
+#include <myadt.hpp>
+#include <linalg.hpp>
+#include <csg.hpp>
+#include <meshing.hpp>
+
+namespace netgen
+{
+#include "writeuser.hpp"
+
+   // Mapping of entities from Netgen definitions to GMSH definitions
+   enum GMSH_ELEMENTS {GMSH_TRIG = 2, GMSH_TRIG6 = 9,
+      GMSH_QUAD = 3, GMSH_QUAD8 = 16,
+      GMSH_TET = 4, GMSH_TET10 = 11};
+   const int triGmsh[7] = {0,1,2,3,6,4,5};
+   const int quadGmsh[9] = {0,1,2,3,4,5,8,6,7};
+   const int tetGmsh[11] = {0,1,2,3,4,5,8,6,7,10,9};
+
+
+   /*! GMSH v2.xx mesh format export function
+   *
+   *  This function extends the export capabilities of
+   *  Netgen to include the GMSH v2.xx File Format.
+   *
+   *  Current features of this function include:
+   *
+   *  1. Exports Triangles, Quadrangles and Tetrahedra \n
+   *  2. Supports upto second order elements of each type
+   *
+   */
+   void WriteGmsh2Format (const Mesh & mesh,
+      const CSGeometry & geom,
+      const string & filename)
+   {
+      ofstream outfile (filename.c_str());
+      outfile.precision(6);
+      outfile.setf (ios::fixed, ios::floatfield);
+      outfile.setf (ios::showpoint);
+
+      int np = mesh.GetNP();  /// number of points in mesh
+      int ne = mesh.GetNE();  /// number of 3D elements in mesh
+      int nse = mesh.GetNSE();  /// number of surface elements (BC)
+      int i, j, k, l;
+
+
+      /*
+      * 3D section : Volume elements (currently only tetrahedra)
+      */
+
+      if ((ne > 0)
+         && (mesh.VolumeElement(1).GetNP() <= 10)
+         && (mesh.SurfaceElement(1).GetNP() <= 6))
+      {
+         cout << "Write GMSH v2.xx Format \n";
+         cout << "The GMSH v2.xx export is currently available for elements upto 2nd Order\n" << endl;
+
+         int inverttets = mparam.inverttets;
+         int invertsurf = mparam.inverttrigs;
+
+         /// Prepare GMSH 2.0 file (See GMSH 2.0 Documentation)
+         outfile << "$MeshFormat\n";
+         outfile << (float)2.0 << " "
+            << (int)0 << " "
+            << (int)sizeof(double) << "\n";
+         outfile << "$EndMeshFormat\n";
+
+         /// Write nodes
+         outfile << "$Nodes\n";
+         outfile << np << "\n";
+
+         for (i = 1; i <= np; i++)
+         {
+            const Point3d & p = mesh.Point(i);
+            outfile << i << " "; /// node number
+            outfile << p.X() << " ";
+            outfile << p.Y() << " ";
+            outfile << p.Z() << "\n";
+         }
+
+         outfile << "$EndNodes\n";
+
+         /// write elements (both, surface elements and volume elements)
+         outfile << "$Elements\n";
+         outfile << ne + nse << "\n";  ////  number of elements + number of surfaces BC
+
+         for (i = 1; i <= nse; i++)
+         {
+            int elType = 0;
+
+            Element2d el = mesh.SurfaceElement(i);
+            if(invertsurf) el.Invert();
+
+            if(el.GetNP() == 3) elType = GMSH_TRIG;	//// GMSH Type for a 3 node triangle
+            if(el.GetNP() == 6) elType = GMSH_TRIG6;  //// GMSH Type for a 6 node triangle
+            if(elType == 0)
+            {
+               cout << " Invalid surface element type for Gmsh 2.0 3D-Mesh Export Format !\n";
+               return;
+            }
+
+            outfile << i;
+            outfile << " ";
+            outfile << elType;
+            outfile << " ";
+            outfile << "2";                  //// Number of tags (2 => Physical and elementary entities)
+            outfile << " ";
+            outfile << mesh.GetFaceDescriptor (el.GetIndex()).BCProperty() << " ";
+            /// that means that physical entity = elementary entity (arbitrary approach)
+            outfile << mesh.GetFaceDescriptor (el.GetIndex()).BCProperty() << " ";
+            for (j = 1; j <= el.GetNP(); j++)
+            {
+               outfile << " ";
+               outfile << el.PNum(triGmsh[j]);
+            }
+            outfile << "\n";
+         }
+
+
+         for (i = 1; i <= ne; i++)
+         {
+            int elType = 0;
+
+            Element el = mesh.VolumeElement(i);
+            if (inverttets) el.Invert();
+
+            if(el.GetNP() == 4) elType = GMSH_TET;    //// GMSH Element type for 4 node tetrahedron
+            if(el.GetNP() == 10) elType = GMSH_TET10; //// GMSH Element type for 10 node tetrahedron
+            if(elType == 0)
+            {
+               cout << " Invalid volume element type for Gmsh 2.0 3D-Mesh Export Format !\n";
+               return;
+            }
+
+            outfile << nse + i;                       //// element number (Remember to add on surface elements)
+            outfile << " ";
+            outfile << elType;
+            outfile << " ";
+            outfile << "2";                   //// Number of tags (2 => Physical and elementary entities)
+            outfile << " ";
+            outfile << 100000 + el.GetIndex();
+            /// that means that physical entity = elementary entity (arbitrary approach)
+            outfile << " ";
+            outfile << 100000 + el.GetIndex();   /// volume number
+            outfile << " ";
+            for (j = 1; j <= el.GetNP(); j++)
+            {
+               outfile << " ";
+               outfile << el.PNum(tetGmsh[j]);
+            }
+            outfile << "\n";
+         }
+         outfile << "$EndElements\n";
+      }
+      /*
+      * End of 3D section
+      */
+
+
+      /*
+      * 2D section : available for triangles and quadrangles
+      *              upto 2nd Order
+      */
+      else if(ne == 0)   /// means that there's no 3D element
+      {
+         cout << "\n Write Gmsh v2.xx Surface Mesh (triangle and/or quadrangles upto 2nd Order)" << endl;
+
+         /// Prepare GMSH 2.0 file (See GMSH 2.0 Documentation)
+         outfile << "$MeshFormat\n";
+         outfile << (float)2.0 << " "
+            << (int)0 << " "
+            << (int)sizeof(double) << "\n";
+         outfile << "$EndMeshFormat\n";
+
+         /// Write nodes
+         outfile << "$Nodes\n";
+         outfile << np << "\n";
+
+         for (i = 1; i <= np; i++)
+         {
+            const Point3d & p = mesh.Point(i);
+            outfile << i << " "; /// node number
+            outfile << p.X() << " ";
+            outfile << p.Y() << " ";
+            outfile << p.Z() << "\n";
+         }
+         outfile << "$EndNodes\n";
+
+         /// write triangles & quadrangles
+         outfile << "$Elements\n";
+         outfile << nse << "\n";
+
+         for (k = 1; k <= nse; k++)
+         {
+            int elType = 0;
+
+            const Element2d & el = mesh.SurfaceElement(k);
+
+            if(el.GetNP() == 3) elType = GMSH_TRIG;   //// GMSH Type for a 3 node triangle
+            if(el.GetNP() == 6) elType = GMSH_TRIG6;  //// GMSH Type for a 6 node triangle
+            if(el.GetNP() == 4) elType = GMSH_QUAD;   //// GMSH Type for a 4 node quadrangle
+            if(el.GetNP() == 8) elType = GMSH_QUAD8;  //// GMSH Type for an 8 node quadrangle
+            if(elType == 0)
+            {
+               cout << " Invalid surface element type for Gmsh 2.0 2D-Mesh Export Format !\n";
+               return;
+            }
+
+            outfile << k;
+            outfile << " ";
+            outfile << elType;
+            outfile << " ";
+            outfile << "2";
+            outfile << " ";
+            outfile << mesh.GetFaceDescriptor (el.GetIndex()).BCProperty() << " ";
+            /// that means that physical entity = elementary entity (arbitrary approach)
+            outfile << mesh.GetFaceDescriptor (el.GetIndex()).BCProperty() << " ";
+            for (l = 1; l <= el.GetNP(); l++)
+            {
+               outfile << " ";
+               if((elType == GMSH_TRIG) || (elType == GMSH_TRIG6))
+               {
+                  outfile << el.PNum(triGmsh[l]);
+               }
+               else if((elType == GMSH_QUAD) || (elType == GMSH_QUAD8))
+               {
+                  outfile << el.PNum(quadGmsh[l]);
+               }
+            }
+            outfile << "\n";
+         }
+         outfile << "$EndElements\n";
+      }
+      /*
+      * End of 2D section
+      */
+
+      else
+      {
+         cout << " Invalid element type for Gmsh v2.xx Export Format !\n";
+      }
+   } // End: WriteGmsh2Format
+} // End: namespace netgen
+
+
diff --git a/contrib/Netgen/libsrc/interface/writejcm.cpp b/contrib/Netgen/libsrc/interface/writejcm.cpp
new file mode 100644
index 0000000000..fc00955d8f
--- /dev/null
+++ b/contrib/Netgen/libsrc/interface/writejcm.cpp
@@ -0,0 +1,430 @@
+//
+//  Write JCMwave file
+//  07.07.2005, Sven Burger, ZIB Berlin
+//
+
+
+#include <mystdlib.h>
+#include <myadt.hpp>
+#include <linalg.hpp>
+#include <csg.hpp>
+#include <meshing.hpp>
+#include <sys/stat.h>
+
+namespace netgen
+{
+#include "writeuser.hpp"
+
+void WriteJCMFormat (const Mesh & mesh,
+                     const CSGeometry & geom,
+                     const string & filename)
+{
+  if (mesh.GetDimension() != 3)
+  {
+    cout <<"\n Error: Dimension 3 only supported by this output format!"<<endl;
+    return;
+  }
+
+  int bc_at_infinity = 0;
+  int i, j, jj, ct(0), counter;
+  double dx1, dx2, dx3, dy1, dy2, dy3, dz1, dz2, dz3, vol;
+
+  // number of points
+  int np = mesh.GetNP();
+
+  // Identic points
+  Array<int,1> identmap1, identmap2, identmap3;
+  mesh.GetIdentifications().GetMap(1, identmap1);
+  mesh.GetIdentifications().GetMap(2, identmap2);
+  mesh.GetIdentifications().GetMap(3, identmap3);
+
+  // number of volume elements
+  int ne = mesh.GetNE();
+  int ntets = 0;
+  int nprisms = 0;
+  for (i = 1; i <= ne; i++)
+  {
+    Element el = mesh.VolumeElement(i);
+    if (el.GetNP() == 4)
+    {
+      ntets++;
+      // Check that no two points on a tetrahedron are identified with each other
+      for (j = 1; j <= 4; j++)
+        for (jj = 1; jj <=4; jj++)
+        {
+          if (identmap1.Elem(el.PNum(j)) == el.PNum(jj))
+          {
+            cout << "\n Error: two points on a tetrahedron identified (1) with each other"
+                 << "\n REFINE MESH !" << endl;
+            return;
+          }
+          if (identmap2.Elem(el.PNum(j)) == el.PNum(jj))
+          {
+            cout << "\n Error: two points on a tetrahedron identified (2) with each other"
+                 << "\n REFINE MESH !" << endl;
+            return;
+          }
+          if (identmap3.Elem(el.PNum(j)) == el.PNum(jj))
+          {
+            cout << "\n Error: two points on a tetrahedron identified (3) with each other"
+                 << "\n REFINE MESH !" << endl;
+            return;
+          }
+        }      
+      
+    }
+    else if (el.GetNP() == 6)
+      nprisms++;
+  }
+  if ( ne != (ntets+nprisms))
+  {
+    cout<< "\n Error in determining number of volume elements!\n"
+        << "\n Prisms and tetrahedra only implemented in the JCMwave format!\n"<<endl;
+    return;
+  }
+
+  if (nprisms > 0)
+    cout << " Please note: Boundaries at infinity have to carry the bc-attribute '-bc="
+         << bc_at_infinity <<"'."<<endl; 
+
+  // number of surface elements
+  int nse = mesh.GetNSE();
+  // number of boundary triangles
+  int nbtri = 0;
+  // number of boundary quadrilaterals
+  int nbquad = 0;
+  // array with 1 if point on any tetra, 0 else 
+  // this is needed in order to arrange the prism points in the right order
+  Array<int,1> pointsOnTetras;
+  pointsOnTetras.SetSize (mesh.GetNP());
+  pointsOnTetras = 0;
+  for (i = 1; i <= ne; i++)
+  {
+    Element el = mesh.VolumeElement(i);
+    if (el.GetNP() == 4)
+    {
+      for (j = 1; j <= 4; j++)
+        pointsOnTetras.Set(el.PNum(j).GetInt(),1);     
+    }
+  }
+
+  // number of boundary triangles and boundary quadrilaterals
+  for (i = 1; i <= nse; i++)
+  {
+    Element2d el = mesh.SurfaceElement(i);
+    if (el.GetNP() == 3 &&
+        ( mesh.GetFaceDescriptor (el.GetIndex()).DomainIn()==0  ||
+          mesh.GetFaceDescriptor (el.GetIndex()).DomainOut()==0 ) )
+      nbtri++;
+    else if (el.GetNP() == 4 &&
+             ( mesh.GetFaceDescriptor (el.GetIndex()).DomainIn()==0 ||
+               mesh.GetFaceDescriptor (el.GetIndex()).DomainOut()==0 ) )
+      nbquad++;
+  }
+  
+  ofstream outfile (filename.c_str());
+  outfile.precision(6);
+  outfile.setf (ios::fixed, ios::floatfield);
+  outfile.setf (ios::showpoint);
+  
+  outfile << "/* <BLOBHead>\n";
+  outfile << "__BLOBTYPE__=Grid\n";
+  outfile << "__OWNER__=JCMwave\n";
+  outfile << "<I>SpaceDim=3\n";
+  outfile << "<I>ManifoldDim=3\n";
+  outfile << "<I>NRefinementSteps=0\n";
+  outfile << "<I>NPoints="<<np<<"\n";
+  outfile << "<I>NTetrahedra="<<ntets<<"\n";
+  outfile << "<I>NPrisms="<<nprisms<<"\n";
+  outfile << "<I>NBoundaryTriangles="<<nbtri<<"\n";
+  outfile << "<I>NBoundaryQuadrilaterals="<<nbquad<<"\n";
+  outfile << "*/\n";
+  outfile << "\n";
+  outfile << "# output from Netgen\n\n";
+  int nDomains=mesh.GetNDomains();
+  for (i=1; i<=nDomains; i++)
+  {
+    if (mesh.GetMaterial(i))
+      outfile << "#" << mesh.GetMaterial(i) 
+              << ": Material ID = " 
+              << i << "\n";
+  }
+
+  outfile << "# Points\n";
+  cout << " Please note: The unit of length in the .geo file is assumed to be 'microns'."<<endl; 
+  for (i = 1; i <= np; i++)
+  {
+    const Point<3> & p = mesh.Point(i);
+    outfile << i << "\n";
+    outfile << p(0) << "e-6\n";
+    outfile << p(1) << "e-6\n";
+    outfile << p(2) << "e-6\n\n";
+  }
+
+  outfile << "\n";
+  outfile << "# Tetrahedra\n";
+  counter = 0;
+  for (i = 1; i <= ne; i++)
+  {
+    Element el = mesh.VolumeElement(i);
+    if (el.GetNP() == 4)
+    {
+      counter++;
+      dx1 = mesh.Point(el.PNum(2))(0) - mesh.Point(el.PNum(1))(0);
+      dx2 = mesh.Point(el.PNum(3))(0) - mesh.Point(el.PNum(1))(0);
+      dx3 = mesh.Point(el.PNum(4))(0) - mesh.Point(el.PNum(1))(0);
+      dy1 = mesh.Point(el.PNum(2))(1) - mesh.Point(el.PNum(1))(1);
+      dy2 = mesh.Point(el.PNum(3))(1) - mesh.Point(el.PNum(1))(1);
+      dy3 = mesh.Point(el.PNum(4))(1) - mesh.Point(el.PNum(1))(1);
+      dz1 = mesh.Point(el.PNum(2))(2) - mesh.Point(el.PNum(1))(2);
+      dz2 = mesh.Point(el.PNum(3))(2) - mesh.Point(el.PNum(1))(2);
+      dz3 = mesh.Point(el.PNum(4))(2) - mesh.Point(el.PNum(1))(2);
+      vol = (dy1*dz2-dz1*dy2)*dx3 + (dz1*dx2-dx1*dz2)*dy3 + (dx1*dy2-dy1*dx2)*dz3;
+
+      if ( vol > 0 )
+        for (j = 1; j <= 4; j++)
+          outfile << el.PNum(j)<<"\n";
+      else
+      {
+        for (j = 2; j >= 1; j--)
+          outfile << el.PNum(j)<<"\n";
+        for (j = 3; j <= 4; j++)
+          outfile << el.PNum(j)<<"\n";
+      }  
+      outfile << el.GetIndex() << "\n\n";
+    }
+  }
+  if ( counter != ntets)
+  {
+    cout<< "\n Error in determining number of tetras!\n"<<endl;
+    return;
+  }
+
+  outfile << "\n";
+  outfile << "# Prisms\n";
+  counter = 0;
+  for (i = 1; i <= ne; i++)
+  {
+    Element el = mesh.VolumeElement(i);
+    if (el.GetNP() == 6)
+    {
+      counter++;
+      dx1 = mesh.Point(el.PNum(2))(0) - mesh.Point(el.PNum(1))(0);
+      dx2 = mesh.Point(el.PNum(3))(0) - mesh.Point(el.PNum(1))(0);
+      dx3 = mesh.Point(el.PNum(4))(0) - mesh.Point(el.PNum(1))(0);
+      dy1 = mesh.Point(el.PNum(2))(1) - mesh.Point(el.PNum(1))(1);
+      dy2 = mesh.Point(el.PNum(3))(1) - mesh.Point(el.PNum(1))(1);
+      dy3 = mesh.Point(el.PNum(4))(1) - mesh.Point(el.PNum(1))(1);
+      dz1 = mesh.Point(el.PNum(2))(2) - mesh.Point(el.PNum(1))(2);
+      dz2 = mesh.Point(el.PNum(3))(2) - mesh.Point(el.PNum(1))(2);
+      dz3 = mesh.Point(el.PNum(4))(2) - mesh.Point(el.PNum(1))(2);
+      vol = (dy1*dz2-dz1*dy2)*dx3 + (dz1*dx2-dx1*dz2)*dy3 + (dx1*dy2-dy1*dx2)*dz3;
+
+      if (pointsOnTetras.Get(el.PNum(1)) &&
+          pointsOnTetras.Get(el.PNum(2)) &&
+          pointsOnTetras.Get(el.PNum(3)))
+      {
+        if (vol > 0)
+          for (j = 1; j <= 6; j++)
+            outfile << el.PNum(j)<<"\n";
+        else
+        {
+          for (j = 3; j >= 1; j--)
+            outfile << el.PNum(j)<<"\n";
+          for (j = 6; j >= 4; j--)
+            outfile << el.PNum(j)<<"\n";
+        }
+      }
+      else if ( pointsOnTetras.Get(el.PNum(4)) &&
+                pointsOnTetras.Get(el.PNum(5)) &&
+                pointsOnTetras.Get(el.PNum(6))    )
+      {
+        if ( vol < 0 )
+        {
+          for (j = 4; j <= 6; j++)
+            outfile << el.PNum(j)<<"\n";
+          for (j = 1; j <= 3; j++)
+            outfile << el.PNum(j)<<"\n";
+        }
+        else
+        {
+          for (j = 6; j >= 4; j--)
+            outfile << el.PNum(j)<<"\n";
+          for (j = 3; j >= 1; j--)
+            outfile << el.PNum(j)<<"\n";
+        }
+      }
+      else 
+      {
+        cout << "\n Error in determining prism point numbering!\n"<<endl;
+        return;
+      }
+      outfile << el.GetIndex() << "\n\n";
+    }
+  }
+  if ( counter != nprisms)
+  {
+    cout<< "\n Error in determining number of prisms!\n"<<endl;
+    return;
+  }
+
+  int npid1 = 0;
+  int npid2 = 0;
+  int npid3 = 0;
+  for (i=1; i<=np; i++)
+  {
+    if (identmap1.Elem(i))
+      npid1++;
+    if (identmap2.Elem(i))
+      npid2++;
+    if (identmap3.Elem(i))
+      npid3++;
+  }
+
+  outfile << "\n";
+  outfile << "# Boundary triangles\n";  
+  outfile << "# Number of identified points in 1-direction: " << npid1 << "\n";
+  outfile << "# Number of identified points in 2-direction: " << npid2 << "\n";
+  outfile << "# Number of identified points in 3-direction: " << npid3 << "\n";
+  for (i = 1; i <= nse; i++)
+  {
+    Element2d el = mesh.SurfaceElement(i);
+    if (el.GetNP() == 3
+        && (mesh.GetFaceDescriptor (el.GetIndex()).DomainIn()==0
+            || mesh.GetFaceDescriptor (el.GetIndex()).DomainOut()==0))
+    {
+      outfile <<"# T\n";
+      for (j = 1; j <= 3; j++)
+        outfile << el.PNum(j)<<"\n";
+      if (mesh.GetFaceDescriptor (el.GetIndex()).BCProperty()==bc_at_infinity)
+        outfile << 1000 << "\n";      
+      else
+        outfile << mesh.GetFaceDescriptor (el.GetIndex()).BCProperty() << "\n";      
+      if (mesh.GetFaceDescriptor (el.GetIndex()).BCProperty() == bc_at_infinity)
+        outfile << "-2\n\n";
+      else if (identmap1.Elem(el.PNum(1))
+               &&identmap1.Elem(el.PNum(2))
+               &&identmap1.Elem(el.PNum(3)))
+      {
+        outfile << "-1\n";
+        for (j = 1; j <= 3; j++)
+          outfile << identmap1.Elem(el.PNum(j))<<"\n";
+        outfile << "\n";
+      }
+      else if (identmap2.Elem(el.PNum(1))
+               &&identmap2.Elem(el.PNum(2))
+               &&identmap2.Elem(el.PNum(3)))
+      {
+        outfile << "-1\n";
+        for (j = 1; j <= 3; j++)
+          outfile << identmap2.Elem(el.PNum(j))<<"\n";
+        outfile << "\n";
+      }
+      else if (identmap3.Elem(el.PNum(1))
+               &&identmap3.Elem(el.PNum(2))
+               &&identmap3.Elem(el.PNum(3)))
+      {
+        outfile << "-1\n";
+        for (j = 1; j <= 3; j++)
+          outfile << identmap3.Elem(el.PNum(j))<<"\n";
+        outfile << "\n";
+      }
+      else
+        outfile << "1\n\n";
+        
+    }
+  }
+
+  outfile << "\n";
+  outfile << "# Boundary quadrilaterals\n";
+  for (i = 1; i <= nse; i++)
+  {
+    Element2d el = mesh.SurfaceElement(i);
+
+    if (el.GetNP() == 4
+        && (mesh.GetFaceDescriptor (el.GetIndex()).DomainIn()==0
+            || mesh.GetFaceDescriptor (el.GetIndex()).DomainOut()==0))
+    {
+      if      (pointsOnTetras.Get(el.PNum(1)) &&
+               pointsOnTetras.Get(el.PNum(2)))
+        ct = 0;
+      else if (pointsOnTetras.Get(el.PNum(2)) &&
+               pointsOnTetras.Get(el.PNum(3)))
+        ct = 1;
+      else if (pointsOnTetras.Get(el.PNum(3)) &&
+               pointsOnTetras.Get(el.PNum(4)))
+        ct = 2;
+      else if (pointsOnTetras.Get(el.PNum(4)) &&
+               pointsOnTetras.Get(el.PNum(1)))
+        ct = 3;
+      else
+        cout << "\nWarning: Quadrilateral with inconsistent points found!"<<endl;
+      
+      for (j = 1; j <= 4; j++)
+      {
+        jj = j + ct;
+        if ( jj >= 5 )
+          jj = jj - 4;
+        outfile << el.PNum(jj)<<"\n";
+      }
+      outfile << mesh.GetFaceDescriptor (el.GetIndex()).BCProperty() << "\n";      
+      if (mesh.GetFaceDescriptor (el.GetIndex()).BCProperty() == bc_at_infinity)
+      {
+        outfile << "-2\n\n";
+        cout << "\nWarning: Quadrilateral at infinity found (this should not occur)!"<<endl;
+      }
+      else if ( identmap1.Elem(el.PNum(1)) &&
+                identmap1.Elem(el.PNum(2)) &&
+                identmap1.Elem(el.PNum(3)) &&
+                identmap1.Elem(el.PNum(4))    )
+      {
+        outfile << "-1\n";
+        for (j = 1; j <= 4; j++)
+        {
+          jj = j + ct;
+          if ( jj >= 5 )
+            jj = jj - 4;
+          outfile << identmap1.Elem(el.PNum(jj))<<"\n";
+        }
+        outfile << "\n";
+      }
+      else if ( identmap2.Elem(el.PNum(1)) &&
+                identmap2.Elem(el.PNum(2)) &&
+                identmap2.Elem(el.PNum(3)) &&
+                identmap2.Elem(el.PNum(4))    )
+      {
+        outfile << "-1\n";
+        for (j = 1; j <= 4; j++)
+        {
+          jj = j + ct;
+          if ( jj >= 5 )
+            jj = jj - 4;
+          outfile << identmap2.Elem(el.PNum(jj))<<"\n";
+        }
+        outfile << "\n";
+      }
+      else if ( identmap3.Elem(el.PNum(1)) &&
+                identmap3.Elem(el.PNum(2)) &&
+                identmap3.Elem(el.PNum(3)) &&
+                identmap3.Elem(el.PNum(4))    )
+      {
+        outfile << "-1\n";
+        for (j = 1; j <= 4; j++)
+        {
+          jj = j + ct;
+          if ( jj >= 5 )
+            jj = jj - 4;
+          outfile << identmap3.Elem(el.PNum(jj))<<"\n";
+        }
+        outfile << "\n";
+      }
+      else
+        outfile << "1\n\n";
+    }
+  }
+
+  cout << " JCMwave grid file written." << endl;
+}
+
+}
+
diff --git a/contrib/Netgen/libsrc/interface/writepermas.cpp b/contrib/Netgen/libsrc/interface/writepermas.cpp
new file mode 100644
index 0000000000..fc46e87cd9
--- /dev/null
+++ b/contrib/Netgen/libsrc/interface/writepermas.cpp
@@ -0,0 +1,208 @@
+//
+// Write Permas file
+// for Intes GmbH, Stuttgart
+//
+
+#include <mystdlib.h>
+
+#include <myadt.hpp>
+#include <linalg.hpp>
+#include <csg.hpp>
+#include <meshing.hpp>
+
+#include <string>
+
+using namespace std;
+
+namespace netgen
+{
+#include "writeuser.hpp"
+    // Forward declarations (don't know, where to define them, sorry)
+    int addComponent(string &strComp, string &strSitu, ofstream &out);
+
+
+    // This should be the new function to export a PERMAS file
+    void WritePermasFormat (const Mesh &mesh, const string &filename, 
+                            string &strComp, string &strSitu) 
+    {
+        ofstream outfile (filename.c_str());
+        addComponent(strComp, strSitu, outfile);
+        WritePermasFormat ( mesh, filename);
+    }
+
+    void WritePermasFormat (const Mesh &mesh, const string &filename)
+    {
+        string strComp, strSitu;
+        ofstream outfile (filename.c_str());
+        
+        outfile.precision(8);
+
+        strSitu = strComp = "";
+        if (addComponent(strComp, strSitu, outfile) == 1) {
+            printf("Error while exporting PERMAS dat!\n");
+            return;
+        }
+    
+        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(0);
+                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;
+        
+        outfile.precision(6);
+        outfile.setf (ios::fixed, ios::floatfield);
+        outfile.setf (ios::showpoint);
+        
+        for (i = 1; i <= np; i++)
+        {
+            outfile << i << " ";
+            outfile << mesh.Point(i)(0) << " ";
+            outfile << mesh.Point(i)(1) << " ";
+            outfile << mesh.Point(i)(2) << "\n";
+        }
+    }
+    ////////////////////////////////////////////////////////////////////////////////// 
+    // \brief Writes PERMAS configuration header into export file
+    //        Returns >0 in case of errors
+    // \par string &strComp  : Reference to component description
+    // \par string &strComp  : Reference to situation description
+    ////////////////////////////////////////////////////////////////////////////////// 
+    int addComponent(string &strComp, string &strSitu, ofstream &out)
+    {
+        if (strComp.size() > 12 || strSitu > 12) 
+            return 1;
+
+        if (0 == strComp.size()) 
+            strComp = "KOMPO1";
+        
+        if (0 == strSitu.size())
+            strSitu = "SIT1";
+
+        // Writing description header of configuration
+        out << "$ENTER COMPONENT  NAME = " << strComp << "  DOFTYPE = DISP MATH" << endl << endl;
+        out << "   $SITUATION  NAME = " << strSitu << endl;
+        out << "   $END SITUATION" << endl << endl;
+        out << "   $STRUCTURE" << endl;
+        
+        return 0;
+    }
+    
+}
diff --git a/contrib/Netgen/libsrc/interface/writetecplot.cpp b/contrib/Netgen/libsrc/interface/writetecplot.cpp
new file mode 100644
index 0000000000..4730b983a5
--- /dev/null
+++ b/contrib/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 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)
+	  {
+	    n = geom.GetSurface(j) -> GetNormalVector ( mesh.Point(i) );
+		
+	    outfile << mesh.Point(i)(0) << " " /* Knoten Koordinaten */
+		    << mesh.Point(i)(1) << " "
+		    << mesh.Point(i)(2) << " "
+		    << 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 (k = 1; k <= nse; k++)
+		{
+		  const Element2d & sel = mesh.SurfaceElement(k);
+		  INDEX_3 i3;
+		  for (j = 1; j <= 3; j++)
+		    i3.I(j) = sel.PNum(j);
+		  i3.Sort();
+		  
+		  //int elind = face2volelement.Get(i3);
+		}
+	}
+    }
+}
+
+
+}
diff --git a/contrib/Netgen/libsrc/interface/writetet.cpp b/contrib/Netgen/libsrc/interface/writetet.cpp
new file mode 100644
index 0000000000..221f03013e
--- /dev/null
+++ b/contrib/Netgen/libsrc/interface/writetet.cpp
@@ -0,0 +1,1096 @@
+
+#include <mystdlib.h>
+
+#include <myadt.hpp>
+#include <linalg.hpp>
+#include <csg.hpp>
+#include <acisgeom.hpp>
+#include <meshing.hpp>
+
+namespace netgen
+{
+
+#include "writeuser.hpp"
+  
+  
+  void WriteTETFormat (const Mesh & mesh,
+		       const string & filename)//, const string& problemType )
+  {
+    string problemType = "";
+    if(!mesh.PureTetMesh())
+      throw NgException("Can only export pure tet mesh in this format");
+
+    cout << "starting .tet export to file " << filename << endl;
+
+
+    Array<int> point_ids,edge_ids,face_ids;
+    Array<int> elnum(mesh.GetNE());
+    elnum = -1;
+
+    
+    Array<int> userdata_int;
+    Array<double> userdata_double;
+    Array<int> ports;
+
+    Array<int> uid_to_group_3D, uid_to_group_2D, uid_to_group_1D, uid_to_group_0D;
+
+    int pos_int = 0;
+    int pos_double = 0;
+    
+    bool haveuserdata = 
+      (mesh.GetUserData("TETmesh:double",userdata_double) &&
+       mesh.GetUserData("TETmesh:int",userdata_int) && 
+       mesh.GetUserData("TETmesh:ports",ports) &&
+       mesh.GetUserData("TETmesh:point_id",point_ids,PointIndex::BASE) &&
+       mesh.GetUserData("TETmesh:uid_to_group_3D",uid_to_group_3D) &&
+       mesh.GetUserData("TETmesh:uid_to_group_2D",uid_to_group_2D) &&
+       mesh.GetUserData("TETmesh:uid_to_group_1D",uid_to_group_1D) &&
+       mesh.GetUserData("TETmesh:uid_to_group_0D",uid_to_group_0D));
+
+
+    int version,subversion;
+
+    if(haveuserdata)
+      {
+	version = int(userdata_double[0]);
+	subversion = int(10*(userdata_double[0] - version));
+	pos_double++;
+      }
+    else
+      {
+	version = 2;
+	subversion = 0;
+      }
+
+    
+    if(version >= 2)
+      {
+	// test if ids are disjunct, if not version 2.0 not possible
+	int maxbc(-1),mindomain(-1);
+	
+	for(ElementIndex i=0; i<mesh.GetNE(); i++)
+	  if(i==0 || mesh[i].GetIndex() < mindomain)
+	    mindomain = mesh[i].GetIndex();
+	for(int i=1; i<=mesh.GetNFD(); i++)
+	  if(i==1 || mesh.GetFaceDescriptor(i).BCProperty() > maxbc)
+	    maxbc = mesh.GetFaceDescriptor(i).BCProperty();
+	
+	if(maxbc >= mindomain)
+	  {
+	    cout << "WARNING: writing version " << version << "." << subversion << " tetfile not possible, ";
+	    version = 1; subversion = 1;
+	    cout << "using version " << version << "." << subversion << endl;
+	  }
+      }
+
+
+
+    int startsize = point_ids.Size();
+    point_ids.SetSize(mesh.GetNP()+1);
+    for(int i=startsize; i<point_ids.Size(); i++)
+      point_ids[i] = -1;
+
+
+    for(int i=0; i<PointIndex::BASE; i++)
+      point_ids[i] = -1;
+
+
+    INDEX_2_CLOSED_HASHTABLE<int> edgenumbers(6*mesh.GetNE()+3*mesh.GetNSE());;
+    INDEX_3_CLOSED_HASHTABLE<int> facenumbers(4*mesh.GetNE()+mesh.GetNSE());
+
+    Array<INDEX_2> edge2node;
+    Array<INDEX_3> face2edge;
+    Array<INDEX_4> element2face;
+
+    int numelems(0),numfaces(0),numedges(0),numnodes(0);
+
+    for(SegmentIndex si = 0; si < mesh.GetNSeg(); si++)
+      {
+	const Segment & seg = mesh[si];
+	INDEX_2 i2(seg[0],seg[1]);
+	i2.Sort();
+	if(edgenumbers.Used(i2))
+	  continue;
+
+	numedges++;
+	edgenumbers.Set(i2,numedges);
+	edge2node.Append(i2);
+
+	edge_ids.Append(seg.edgenr);
+
+	if(point_ids[seg[0]] == -1)
+	  point_ids[seg[0]] = (version >= 2) ? seg.edgenr : 0;
+	if(point_ids[seg[1]] == -1)
+	  point_ids[seg[1]] = (version >= 2) ? seg.edgenr : 0;
+      }
+
+    for(SurfaceElementIndex si = 0; si < mesh.GetNSE(); si++)
+      {
+	if(mesh[si].IsDeleted())
+	  continue;
+
+	const Element2d & elem = mesh[si];
+
+	numfaces++;
+	INDEX_3 i3(elem[0], elem[1], elem[2]);
+
+	int min = i3[0];
+	int minpos = 0;
+	for(int j=1; j<3; j++)
+	  if(i3[j] < min)
+	    {
+	      min = i3[j]; minpos = j;
+	    }
+	if(minpos == 1)
+	  {
+	    int aux = i3[0]; i3[0] = i3[1]; i3[1] = i3[2]; i3[2] = aux;
+	  }
+	else if(minpos == 2)
+	  {
+	    int aux = i3[0]; i3[0] = i3[2]; i3[2] = i3[1]; i3[1] = aux;
+	  }
+	facenumbers.Set(i3,numfaces);
+
+	int bc = mesh.GetFaceDescriptor(elem.GetIndex()).BCProperty();
+	face_ids.Append(bc);
+
+	for(int j=0; j<3; j++)
+	  if(point_ids[elem[j]] == -1)
+	    point_ids[elem[j]] = (version >= 2) ? bc : 0;
+
+	INDEX_2 i2a,i2b;
+	INDEX_3 f_to_n;
+	for(int j=0; j<3; j++)
+	  {
+	    i2a = INDEX_2(i3[j],i3[(j+1)%3]);
+	    i2b[0] = i2a[1]; i2b[1] = i2a[0];
+	    if(edgenumbers.Used(i2a))
+	      f_to_n[j] = edgenumbers.Get(i2a);
+	    else if(edgenumbers.Used(i2b))
+	      f_to_n[j] = -edgenumbers.Get(i2b);
+	    else
+	      {
+		numedges++;
+		edgenumbers.Set(i2a,numedges);
+		edge2node.Append(i2a);
+		f_to_n[j] = numedges;
+		if(version >= 2)
+		  edge_ids.Append(bc);
+		else
+		  edge_ids.Append(0);
+	      }
+	  }
+	face2edge.Append(f_to_n);
+      }
+    
+    for(ElementIndex ei = 0; ei < mesh.GetNE(); ei++)
+      {
+	const Element & el = mesh[ei];
+
+	if(el.IsDeleted())
+	  continue;
+
+	numelems++;
+	elnum[ei] = numelems;
+
+	static int tetfaces[4][3] =
+	  { { 0, 2, 1 },
+	    { 0, 1, 3 },
+	    { 1, 2, 3 },
+	    { 2, 0, 3 } };
+	
+	for(int j=0; j<4; j++)
+	  if(point_ids[el[j]] == -1)
+	    point_ids[el[j]] = (version >= 2) ? el.GetIndex() : 0;
+
+	INDEX_4 e_to_f;
+
+	for(int i = 0; i < 4; i++)
+	  {
+	    INDEX_3 i3a(el[tetfaces[i][0]],el[tetfaces[i][1]],el[tetfaces[i][2]]);
+	    
+	    int min = i3a[0];
+	    int minpos = 0;
+	    for(int j=1; j<3; j++)
+	      if(i3a[j] < min)
+		{
+		  min = i3a[j]; minpos = j;
+		}
+	    if(minpos == 1)
+	      {
+		int aux = i3a[0]; i3a[0] = i3a[1]; i3a[1] = i3a[2]; i3a[2] = aux;
+	      }
+	    else if(minpos == 2)
+	      {
+		int aux = i3a[0]; i3a[0] = i3a[2]; i3a[2] = i3a[1]; i3a[1] = aux;
+	      }
+	    INDEX_3 i3b(i3a[0],i3a[2],i3a[1]);
+	    
+
+	    if(facenumbers.Used(i3a))
+	      e_to_f[i] = facenumbers.Get(i3a);
+	    else if(facenumbers.Used(i3b))
+	      e_to_f[i] = -facenumbers.Get(i3b);
+	    else
+	      {
+		numfaces++;
+		facenumbers.Set(i3a,numfaces);
+		e_to_f[i] = numfaces;
+		if(version >= 2)
+		  face_ids.Append(el.GetIndex());
+		else
+		  face_ids.Append(0);
+
+		INDEX_2 i2a,i2b;
+		INDEX_3 f_to_n;
+		for(int j=0; j<3; j++)
+		  {
+		    i2a = INDEX_2(i3a[j],i3a[(j+1)%3]);
+		    i2b[0] = i2a[1]; i2b[1] = i2a[0];
+		    if(edgenumbers.Used(i2a))
+		      f_to_n[j] = edgenumbers.Get(i2a);
+		    else if(edgenumbers.Used(i2b))
+		      f_to_n[j] = -edgenumbers.Get(i2b);
+		    else
+		      {
+			numedges++;
+			edgenumbers.Set(i2a,numedges);
+			edge2node.Append(i2a);
+			f_to_n[j] = numedges;
+			if(version >= 2)
+			  edge_ids.Append(el.GetIndex());
+			else
+			  edge_ids.Append(0);
+		      }
+		  }
+		face2edge.Append(f_to_n);	  
+	      }
+	  }
+	element2face.Append(e_to_f);
+      }
+
+
+
+
+    ofstream outfile(filename.c_str());
+
+    outfile.precision(16);
+
+    int unitcode;
+    double tolerance;
+    double dS1,dS2, alphaDeg;
+    double x3D,y3D,z3D;
+    int modelverts(0), modeledges(0), modelfaces(0), modelcells(0);
+
+    int numObj0D,numObj1D,numObj2D,numObj3D;
+    int numports = ports.Size();
+
+    Array<int> nodenum(point_ids.Size()+1);
+
+    nodenum = -1;
+	    
+
+
+    numnodes = 0;
+    for(int i=0; i<point_ids.Size(); i++)
+      {
+	if(point_ids[i] != -1)
+	  {
+	    numnodes++;
+	    nodenum[i] = numnodes;
+	  }
+      }
+
+
+    if(haveuserdata)
+      {
+	unitcode = userdata_int[pos_int];
+	pos_int++;
+
+	tolerance = userdata_double[pos_double];
+	pos_double++;
+
+	dS1 = userdata_double[pos_double];
+	pos_double++;
+	dS2 = userdata_double[pos_double];
+	pos_double++;
+	alphaDeg = userdata_double[pos_double];
+	pos_double++;
+
+	x3D = userdata_double[pos_double];
+	pos_double++;
+	y3D = userdata_double[pos_double];
+	pos_double++;
+	z3D = userdata_double[pos_double];
+	pos_double++;
+
+	if(version == 2)
+	  {
+	    modelverts = userdata_int[pos_int];
+	    pos_int++;
+	    modeledges = userdata_int[pos_int];
+	    pos_int++;
+	    modelfaces = userdata_int[pos_int];
+	    pos_int++;
+	    modelcells = userdata_int[pos_int];
+	    pos_int++;
+	  }
+
+	numObj3D = userdata_int[pos_int];
+	pos_int++;
+	numObj2D = userdata_int[pos_int];
+	pos_int++;
+	numObj1D = userdata_int[pos_int];
+	pos_int++;
+	numObj0D = userdata_int[pos_int];
+	pos_int++;
+      }
+    else
+      {
+	unitcode = 3;
+
+	tolerance = 1e-5;
+
+	dS1 = dS2 = alphaDeg = 0;
+
+	x3D = y3D = z3D = 0;
+
+	modelverts = modeledges = modelfaces = modelcells = 0;
+	
+	numObj3D = numObj2D = numObj1D = numObj0D = 0;
+      }
+
+    string uidpid;
+    if(version == 1)
+      uidpid = "PID";
+    else if (version == 2)
+      uidpid = "UID";
+    
+
+    Array< Array<int,PointIndex::BASE>* > idmaps;
+    for(int i=1; i<=mesh.GetIdentifications().GetMaxNr(); i++)
+      {
+	if(mesh.GetIdentifications().GetType(i) == Identifications::PERIODIC)
+	  {
+	    idmaps.Append(new Array<int,PointIndex::BASE>);
+	    mesh.GetIdentifications().GetMap(i,*idmaps.Last(),true);
+	  }
+      }
+
+    Array<int> id_num,id_type;
+    Array< Array<int> *> id_groups;
+
+
+	// sst 2008-03-12: Write problem class...
+	{
+		std::string block;
+		block  = "// CST Tetrahedral ";
+		block += !problemType.empty() ? problemType : "High Frequency";
+		block += " Mesh, Version no.:\n";
+		
+		size_t size = block.size()-3;
+		block += "// ";
+		block.append( size, '^' );
+		block += "\n";
+
+		outfile
+			<< block
+			<< version << "." << subversion << "\n\n";
+	}
+
+	outfile 
+	    << "// User Units Code (1=CM 2=MM 3=M 4=MIC 5=NM 6=FT 7=IN 8=MIL):\n" \
+	    << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" \
+	    << unitcode << "\n\n"					\
+	    << "// Geometric coord \"zero\" tolerance threshold:\n" \
+	    << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" \
+	    << tolerance << "\n\n"				  \
+	    << "// Periodic UnitCell dS1 , dS2 , alphaDeg:\n" \
+	    << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" \
+	    << dS1 << " " << dS2 << " " << alphaDeg <<"\n\n"	\
+	    << "// Periodic UnitCell origin in global coords (x3D,y3D,z3D):\n" \
+	    << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" \
+	    << x3D << " " << y3D << " " << z3D << "\n" << endl;
+
+    if(version == 2)
+      {
+	outfile << "// Model entity count: Vertices, Edges, Faces, Cells:\n" \
+		<< "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" \
+		<< modelverts << " " << modeledges << " " << modelfaces << " " << modelcells << endl << endl;
+      }
+
+
+    outfile << "// Topological mesh-entity counts (#elements,#faces,#edges,#nodes):\n" \
+	    << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n";
+    outfile << numelems << " " 
+	    << numfaces << " "
+	    << numedges << " " 
+	    << numnodes << endl << endl;
+
+    outfile << "// NodeID, X, Y, Z, Type (0=Reg 1=PMaster 2=PSlave 3=CPMaster 4=CPSlave), "<< uidpid <<":\n" \
+	    << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n";
+       
+
+
+    id_num.SetSize(mesh.GetNP()+1);
+    id_type.SetSize(mesh.GetNP()+1);
+    id_num = 0;
+    id_type = 0;
+
+    int n2,n4,n8;
+    n2 = n4 = n8 = 0;
+
+ 
+    for(int i=PointIndex::BASE; i<mesh.GetNP()+PointIndex::BASE; i++)
+      {
+	if(id_num[i] != 0)
+	  continue;
+
+	if(nodenum[i] == -1)
+	  continue;
+
+	Array<int> group;
+	group.Append(i);
+	for(int j=0; j<idmaps.Size(); j++)
+	  {
+	    startsize = group.Size();
+	    for(int k=0; k<startsize; k++)
+	      {
+		int id = (*idmaps[j])[group[k]];
+		if(id != 0 && !group.Contains(id) && nodenum[id] != -1)
+		  {
+		    group.Append(id);
+		    id_num[id] = j+1+id_num[group[k]];
+		  }
+	      }
+	  }
+	if(group.Size() > 1)
+	  {
+	    id_groups.Append(new Array<int>(group));
+	    if(group.Size() == 2)
+	      {
+		id_type[i] = 1;
+		id_type[group[1]] = 2;
+		n2++;
+	      }
+	    else if(group.Size() == 4)
+	      {
+		id_type[i] = 3;
+		for(int j=1; j<group.Size(); j++)
+		  id_type[group[j]] = 4;
+		n4++;
+	      }
+	    else if(group.Size() == 8)
+	      {
+		id_type[i] = 5;
+		for(int j=1; j<group.Size(); j++)
+		  id_type[group[j]] = 6;
+		n8++;
+	      }
+	    else
+	      cerr << "ERROR: Identification group size = " << group.Size() << endl;
+	  }
+	
+      }
+
+
+    for(PointIndex i=PointIndex::BASE; i<mesh.GetNP()+PointIndex::BASE; i++)
+      {
+	if(nodenum[i] == -1)
+	  continue;
+	outfile << nodenum[i] << " "
+		<< mesh[i](0) << " "
+		<< mesh[i](1) << " "
+		<< mesh[i](2) << " " << id_type[i] << " ";
+	if(i-PointIndex::BASE < point_ids.Size())
+	  outfile << point_ids[i];
+	else
+	  outfile << "0";
+	outfile << "\n";
+      }
+    outfile << endl;
+
+    outfile << "\n// Number of Periodic Master Nodes:\n" \
+	    << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" \
+	    << n2 << "\n"			       \
+	    << "\n" \
+	    << "// MasterNodeID, SlaveNodeID, TranslCode (1=dS1 2=dS2 3=dS1+dS2):\n" \
+	    << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n";
+    for(int i=0; i<id_groups.Size(); i++)
+      {
+	if(id_groups[i]->Size() != 2)
+	  continue;
+
+	for(int j=0; j<id_groups[i]->Size(); j++)
+	  outfile << nodenum[(*id_groups[i])[j]] << " ";
+	for(int j=1; j<id_groups[i]->Size(); j++)
+	  outfile << id_num[(*id_groups[i])[j]] << " ";
+	outfile << "\n";
+
+	delete id_groups[i];
+	id_groups[i] = NULL;
+      }
+    outfile << endl;
+	
+	
+    outfile << "// Number of Corner Periodic Master Nodes:\n"	      \
+	    << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" \
+	    << n4 << "\n"				      \
+	    << "\n" \
+	    << "// MasterNodeID, 3-SlaveNodeID's, 3-TranslCodes (1=dS1 2=dS2 3=dS1+dS2):\n" \
+	    << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n";
+
+
+    for(int i=0; i<id_groups.Size(); i++)
+      {
+	if(!id_groups[i] || id_groups[i]->Size() != 4)
+	  continue;
+
+	for(int j=0; j<id_groups[i]->Size(); j++)
+	  outfile << nodenum[(*id_groups[i])[j]] << " ";
+	for(int j=1; j<id_groups[i]->Size(); j++)
+	  {
+	    outfile << id_num[(*id_groups[i])[j]] << " ";
+	  }
+	outfile << "\n";
+
+	delete id_groups[i];
+	id_groups[i] = NULL;
+      }
+    outfile << endl;
+
+
+    outfile << "// Number of Cubic Periodic Master Nodes:\n"	     \
+	    << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" \
+	    << n8 << "\n"				     \
+	    << "\n" \
+	    << "// MasterNodeID, 7-SlaveNodeID's, TranslCodes:\n" \
+	    << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n";
+    for(int i=0; i<id_groups.Size(); i++)
+      {
+	if(!id_groups[i] || id_groups[i]->Size() != 8)
+	  continue;
+
+	for(int j=0; j<id_groups[i]->Size(); j++)
+	  outfile << nodenum[(*id_groups[i])[j]] << " ";
+	for(int j=1; j<id_groups[i]->Size(); j++)
+	  outfile << id_num[(*id_groups[i])[j]] << " ";
+	outfile << "\n";
+
+	delete id_groups[i];
+	id_groups[i] = NULL;
+      }
+    outfile << endl;
+
+    
+
+
+    outfile << "// EdgeID, NodeID0, NodeID1, Type (0=Reg 1=PMaster 2=PSlave 3=CPMaster 4=CPSlave), "<<uidpid<<":\n" \
+	    << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n";
+
+    
+      
+    Array< Array<int>* > vertex_to_edge(mesh.GetNP()+1);
+    for(int i=0; i<=mesh.GetNP(); i++)
+      vertex_to_edge[i] = new Array<int>;
+
+    Array< Array<int,PointIndex::BASE>* > idmaps_edge(idmaps.Size());
+    for(int i=0; i<idmaps_edge.Size(); i++)
+      {
+	idmaps_edge[i] = new Array<int,PointIndex::BASE>(numedges);
+	(*idmaps_edge[i]) = 0;
+      }
+
+    Array<int> possible;
+    for(int i=0; i<edge2node.Size(); i++)
+      {
+	const INDEX_2 & v = edge2node[i];
+	for(int j=0; j<idmaps.Size(); j++)
+	  {
+	    INDEX_2 vid((*idmaps[j])[v[0]], (*idmaps[j])[v[1]]);
+	    if(vid[0] != 0 && vid[0] != v[0] && vid[1] != 0 && vid[1] != v[1])
+	      {
+		Intersection(*vertex_to_edge[vid[0]],*vertex_to_edge[vid[1]],possible);
+		if(possible.Size() == 1)
+		  {
+		    (*idmaps_edge[j])[possible[0]] = i+1;
+		    (*idmaps_edge[j])[i+1] = possible[0];
+		  }
+		else if(possible.Size() > 0)
+		  {
+		    cerr << "ERROR: too many possible edge identifications" << endl;
+		    (*testout) << "ERROR: too many possible edge identifications" << endl
+			       << "*vertex_to_edge["<<vid[0]<<"] " << *vertex_to_edge[vid[0]] << endl
+			       << "*vertex_to_edge["<<vid[1]<<"] " << *vertex_to_edge[vid[1]] << endl
+			       << "possible " << possible << endl;
+		  }
+	      }
+	  }
+	vertex_to_edge[v[0]]->Append(i+1);
+	vertex_to_edge[v[1]]->Append(i+1);
+      }
+
+
+    for(int i=0; i<vertex_to_edge.Size(); i++)
+      delete vertex_to_edge[i];
+
+
+    id_groups.SetSize(0);
+    id_num.SetSize(numedges+1);
+    id_num = 0;
+    id_type.SetSize(numedges+1);
+    id_type = 0;
+
+    n2 = n4 = n8 = 0;
+
+    for(int i=1; i<=edge2node.Size(); i++)
+      {
+	if(id_num[i] != 0)
+	  continue;
+
+
+	Array<int> group;
+	group.Append(i);
+	for(int j=0; j<idmaps_edge.Size(); j++)
+	  {
+	    startsize = group.Size();
+	    for(int k=0; k<startsize; k++)
+	      {
+		int id = (*idmaps_edge[j])[group[k]];
+		if(id != 0 && !group.Contains(id))
+		  {
+		    group.Append(id);
+		    id_num[id] = j+1+id_num[group[k]];
+		  }
+	      }
+	  }
+	if(group.Size() > 1)
+	  {
+	    id_num[i] = 1;
+	    id_groups.Append(new Array<int>(group));
+	    if(group.Size() == 2)
+	      {
+		id_type[i] = 1;
+		id_type[group[1]] = 2;
+		n2++;
+	      }
+	    else if(group.Size() == 4)
+	      {
+		id_type[i] = 3;
+		for(int j=1; j<group.Size(); j++)
+		  id_type[group[j]] = 4;
+		n4++;
+	      }
+	    else
+	      {
+		cerr << "ERROR: edge identification group size = " << group.Size() << endl;
+		(*testout) << "edge group " << group << endl;
+		for(int j=0; j<idmaps_edge.Size(); j++)
+		  {
+		    (*testout) << "edge id map " << j << endl << *idmaps_edge[j] << endl;
+		  }
+	      }
+	  }
+      }
+
+
+
+    for(int i=1; i<=edge2node.Size(); i++)
+      {
+	if(id_num[i] != 0)
+	  continue;
+
+
+	Array<int> group;
+	group.Append(i);
+	for(int j=0; j<idmaps_edge.Size(); j++)
+	  {
+	    startsize = group.Size();
+	    for(int k=0; k<startsize; k++)
+	      {
+		int id = (*idmaps_edge[j])[group[k]];
+		if(id != 0 && !group.Contains(id))
+		  {
+		    group.Append(id);
+		    id_num[id] = j+1+id_num[group[k]];
+		  }
+	      }
+	  }
+	if(group.Size() > 1)
+	  {
+	    id_num[i] = 1;
+	    id_groups.Append(new Array<int>(group));
+	    if(group.Size() == 2)
+	      {
+		id_type[i] = 1;
+		id_type[group[1]] = 2;
+		n2++;
+	      }
+	    else if(group.Size() == 4)
+	      {
+		id_type[i] = 3;
+		for(int j=1; j<group.Size(); j++)
+		  id_type[group[j]] = 4;
+		n4++;
+	      }
+	    else
+	      {
+		cerr << "ERROR: edge identification group size = " << group.Size() << endl;
+		(*testout) << "edge group " << group << endl;
+		for(int j=0; j<idmaps_edge.Size(); j++)
+		  {
+		    (*testout) << "edge id map " << j << endl << *idmaps_edge[j] << endl;
+		  }
+	      }
+	  }
+	
+      }
+
+    
+    for(int i=0; i<edge2node.Size(); i++)
+      outfile << i+1 << " " << nodenum[edge2node[i][0]] << " " << nodenum[edge2node[i][1]] 
+	      << " " << id_type[i+1] << " " << edge_ids[i] << "\n";
+
+    outfile << endl;
+
+    
+
+    outfile << "// Number of Periodic Master Edges:\n"\
+	    << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n"\
+	    << n2 << "\n"			      \
+	    << "\n"\
+	    << "// MasterEdgeID, SlaveEdgeID, TranslCode (1=dS1 2=dS2 3=dS1+dS2):\n"\
+	    << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n";
+    for(int i=0; i<id_groups.Size(); i++)
+      {
+	if(id_groups[i]->Size() != 2)
+	  continue;
+
+	for(int j=0; j<id_groups[i]->Size(); j++)
+	  outfile << (*id_groups[i])[j] << " ";
+	for(int j=1; j<id_groups[i]->Size(); j++)
+	  outfile << id_num[(*id_groups[i])[j]] << " ";
+	outfile << "\n";
+
+	delete id_groups[i];
+	id_groups[i] = NULL;
+      }
+    outfile << endl;
+
+    outfile << "// Number of Corner Periodic Master Edges:\n"		\
+	    << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n"\
+	    << n4 << "\n"				     \
+	    << "\n"\
+	    << "// MasterEdgeID, 3 SlaveEdgeID's, 3 TranslCode (1=dS1 2=dS2 3=dS1+dS2):\n"\
+	    << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n";
+    for(int i=0; i<id_groups.Size(); i++)
+      {
+	if(!id_groups[i] || id_groups[i]->Size() != 4)
+	  continue;
+
+	for(int j=0; j<id_groups[i]->Size(); j++)
+	  outfile << (*id_groups[i])[j] << " ";
+	for(int j=1; j<id_groups[i]->Size(); j++)
+	  outfile << id_num[(*id_groups[i])[j]] << " ";
+	outfile << "\n";
+
+	delete id_groups[i];
+	id_groups[i] = NULL;
+      }
+    outfile << endl;
+
+
+    outfile << "// FaceID, EdgeID0, EdgeID1, EdgeID2, FaceType (0=Reg 1=PMaster 2=PSlave), "<<uidpid<<":\n" \
+	    << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n";
+
+    
+    
+    Array< Array<int>* > edge_to_face(numedges+1);
+    for(int i=0; i<edge_to_face.Size(); i++)
+      edge_to_face[i] = new Array<int>;
+
+    
+    for(int i=0; i<idmaps.Size(); i++)
+      {
+	idmaps[i]->SetSize(numfaces);
+	(*idmaps[i]) = 0;
+      }
+
+    
+    for(int i=0; i<face2edge.Size(); i++)
+      {
+	for(int j=0; j<idmaps_edge.Size(); j++)
+	  {
+	    int e1id,e2id,e3id;
+	    e1id = (*idmaps_edge[j])[abs(face2edge[i][0])];
+	    e2id = (*idmaps_edge[j])[abs(face2edge[i][1])];
+	    e3id = (*idmaps_edge[j])[abs(face2edge[i][2])];
+	    if(e1id != 0 && e1id != abs(face2edge[i][0]) &&
+	       e2id != 0 && e2id != abs(face2edge[i][1]) &&
+	       e3id != 0 && e3id != abs(face2edge[i][2]))
+	      {
+		Intersection(*edge_to_face[e1id],*edge_to_face[e2id],*edge_to_face[e3id],possible);
+		if(possible.Size() == 1)
+		  {
+		    (*idmaps[j])[possible[0]] = i+1;
+		    (*idmaps[j])[i+1] = possible[0];
+		  }
+		else if(possible.Size() > 0)
+		  cerr << "ERROR: too many possible face identifications" << endl;
+	      }
+	  }
+
+	edge_to_face[abs(face2edge[i][0])]->Append(i+1);
+	edge_to_face[abs(face2edge[i][1])]->Append(i+1);
+	edge_to_face[abs(face2edge[i][2])]->Append(i+1);
+      }
+
+    for(int i=0; i<edge_to_face.Size(); i++)
+      delete edge_to_face[i];
+
+
+    for(int i=0; i<idmaps_edge.Size(); i++)
+      delete idmaps_edge[i];
+
+    
+    id_groups.SetSize(0);
+    id_num.SetSize(numfaces+1);
+    id_num = 0;
+
+    n2 = n4 = n8 = 0;
+
+    for(int i=1; i<=numfaces; i++)
+      {
+	if(id_num[i] != 0)
+	  continue;
+
+	Array<int> group;
+	group.Append(i);
+	for(int j=0; j<idmaps.Size(); j++)
+	  {
+	    startsize = group.Size();
+	    for(int k=0; k<startsize; k++)
+	      {
+		int id = (*idmaps[j])[group[k]];
+		if(id != 0 && !group.Contains(id))
+		  {
+		    group.Append(id);
+		    id_num[id] = j+1+id_num[group[k]];
+		  }
+	      }
+	  }
+	if(group.Size() > 1)
+	  {
+	    id_num[i] = -1;
+	    id_groups.Append(new Array<int>(group));
+	    if(group.Size() == 2)
+	      n2++;
+	    else
+	      cerr << "ERROR: face identification group size = " << group.Size() << endl;
+	  }
+	
+      }
+
+
+    for(int i=0; i<idmaps.Size(); i++)
+      delete idmaps[i];
+
+
+
+
+    for(int i=0; i<face2edge.Size(); i++)
+      {	
+	outfile << i+1 << " ";
+	for(int j=0; j<3; j++)
+	  outfile << face2edge[i][j] << " ";
+
+	if(id_num[i+1] == 0)
+	  outfile << 0;
+	else if(id_num[i+1] == -1)
+	  outfile << 1;
+	else
+	  outfile << 2;
+
+	outfile << " " << face_ids[i] <<"\n";
+      }
+    outfile << endl;
+
+
+    outfile << "// Number of Periodic Master Faces:\n"\
+	    << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n"\
+	    << n2 << "\n"			      \
+	    << "\n"\
+	    << "// MasterFaceID, SlaveFaceID, TranslCode (1=dS1 2=dS2):\n"\
+	    << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n";
+    for(int i=0; i<id_groups.Size(); i++)
+      {
+	if(id_groups[i]->Size() != 2)
+	  continue;
+
+	for(int j=0; j<id_groups[i]->Size(); j++)
+	  outfile << (*id_groups[i])[j] << " ";
+	for(int j=1; j<id_groups[i]->Size(); j++)
+	  outfile << id_num[(*id_groups[i])[j]] << " ";
+	outfile << "\n";
+
+	delete id_groups[i];
+      }
+    outfile << endl;
+
+    
+
+
+    outfile << "// ElemID, FaceID0, FaceID1, FaceID2, FaceID3, "<<uidpid<<":\n" \
+	    << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n";
+
+    for(ElementIndex i=0; i<mesh.GetNE(); i++)
+      {
+	if(elnum[i] >= 0)
+	  {
+	    outfile << elnum[i] << " ";
+	    for(int j=0; j<4; j++)
+	      outfile << element2face[elnum[i]-1][j] << " ";
+
+	    outfile << mesh[i].GetIndex() << "\n";
+	  }
+      }
+    outfile << endl;
+
+    outfile << "// ElemID, NodeID0, NodeID1, NodeID2, NodeID3:\n" \
+	    << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n";
+
+    
+    for(ElementIndex i=0; i<mesh.GetNE(); i++)
+      {
+	if(elnum[i] >= 0)
+	  outfile << elnum[i] << " "
+		  << nodenum[mesh[i][1]] << " " << nodenum[mesh[i][0]] << " " << nodenum[mesh[i][2]] << " " << nodenum[mesh[i][3]] << "\n";
+      }
+    outfile << endl;
+    
+
+    
+
+    outfile << "// Physical Object counts (#Obj3D,#Obj2D,#Obj1D,#Obj0D):\n"
+	    << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n"
+	    << " "<< numObj3D << " " << numObj2D << " " << numObj1D << " " << numObj0D << "\n" \
+	    << "\n" \
+	    << "// Number of Ports (Ports are a subset of Object2D list):\n" \
+	    << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" \
+	    << numports << "\n"						\
+	    << endl;
+
+
+    Array< Array<int> * > groups;
+
+    int maxg = -1;
+    for(int i = 0; i<uid_to_group_3D.Size(); i++)
+      if(uid_to_group_3D[i] > maxg)
+	maxg = uid_to_group_3D[i];
+    for(int i = 0; i<uid_to_group_2D.Size(); i++)
+      if(uid_to_group_2D[i] > maxg)
+	maxg = uid_to_group_2D[i];
+    for(int i = 0; i<uid_to_group_1D.Size(); i++)
+      if(uid_to_group_1D[i] > maxg)
+	maxg = uid_to_group_1D[i];
+    for(int i = 0; i<uid_to_group_0D.Size(); i++)
+      if(uid_to_group_0D[i] > maxg)
+	maxg = uid_to_group_0D[i];
+
+    groups.SetSize(maxg+1);
+    for(int i=0; i<groups.Size(); i++)
+      groups[i] = new Array<int>;
+
+    for(ElementIndex i=0; i<mesh.GetNE(); i++)
+      if(uid_to_group_3D[mesh[i].GetIndex()] >= 0)
+	groups[uid_to_group_3D[mesh[i].GetIndex()]]->Append(i+1);
+      
+    
+
+
+    outfile << "// Object3D GroupID, #Elems <immediately followed by> ElemID List:\n" \
+	    << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n";
+    for(int i=0; i<numObj3D; i++)
+      {
+	outfile << i << " " << groups[i]->Size() << "\n";
+	for(int j=0; j<groups[i]->Size(); j++)
+	  outfile << (*groups[i])[j] << "\n";
+      }
+
+    for(int i=0; i<groups.Size(); i++)
+      groups[i]->SetSize(0);
+
+    for(int i=0; i<face_ids.Size(); i++)
+      if(uid_to_group_2D[face_ids[i]] >= 0)
+	groups[uid_to_group_2D[face_ids[i]]]->Append(i+1);
+      
+
+    outfile << "// Object2D GroupID, #Faces <immediately followed by> FaceID List:\n" \
+	    << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n";
+    for(int i=0; i<numObj2D; i++)
+      {
+	outfile << i << " " << groups[i]->Size() << "\n";
+	for(int j=0; j<groups[i]->Size(); j++)
+	  {
+	    outfile << (*groups[i])[j];
+	    if(ports.Contains(face_ids[(*groups[i])[j]-1]))
+	      outfile << " P";
+	    outfile << "\n";
+	  }
+      }
+    outfile << endl;
+
+    
+    for(int i=0; i<groups.Size(); i++)
+      groups[i]->SetSize(0);
+
+    for(int i=0; i<edge_ids.Size(); i++)
+      if(uid_to_group_1D[edge_ids[i]] >= 0)
+	groups[uid_to_group_1D[edge_ids[i]]]->Append(i+1);
+
+
+
+    outfile << "// Object1D GroupID, #Edges <immediately followed by> EdgeID List:\n" \
+	    << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n";
+    for(int i=0; i<numObj1D; i++)
+      {
+	outfile << i << " " << groups[i]->Size() << "\n";
+	for(int j=0; j<groups[i]->Size(); j++)
+	  outfile << (*groups[i])[j] << "\n";
+      }
+    outfile << endl;
+
+    
+    for(int i=0; i<groups.Size(); i++)
+      groups[i]->SetSize(0);
+    for(PointIndex i=PointIndex::BASE; i<mesh.GetNP()+PointIndex::BASE; i++)
+      {
+	if(i-PointIndex::BASE < point_ids.Size())
+	  {
+	    if(uid_to_group_0D[point_ids[i]] >= 0)
+	      groups[uid_to_group_0D[point_ids[i]]]->Append(i+1-PointIndex::BASE);
+	  }
+	else
+	  groups[uid_to_group_0D[0]]->Append(i+1-PointIndex::BASE);
+      }
+
+
+    outfile << "// Object0D GroupID, #Nodes <immediately followed by> NodeID List:\n" \
+	    << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n";
+    for(int i=0; i<numObj0D; i++)
+      {
+	outfile << i << " " << groups[i]->Size() << "\n";
+	for(int j=0; j<groups[i]->Size(); j++)
+	  outfile << (*groups[i])[j] << "\n";
+      }
+    outfile << endl;
+
+    for(int i=0; i<groups.Size(); i++)
+      delete groups[i];
+
+
+    outfile.close();
+
+    cout << ".tet export done" << endl;
+  }
+}
diff --git a/contrib/Netgen/libsrc/interface/writetochnog.cpp b/contrib/Netgen/libsrc/interface/writetochnog.cpp
new file mode 100644
index 0000000000..c9ec6e3ce9
--- /dev/null
+++ b/contrib/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;
+
+  for (i = 1; i <= np; i++)
+    {
+      outfile << "node " << " " << i << " ";
+      outfile << mesh.Point(i)(0) << " ";
+      outfile << mesh.Point(i)(1) << " ";
+      outfile << mesh.Point(i)(2) << "\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/contrib/Netgen/libsrc/interface/writeuser.cpp b/contrib/Netgen/libsrc/interface/writeuser.cpp
new file mode 100644
index 0000000000..6e3f918566
--- /dev/null
+++ b/contrib/Netgen/libsrc/interface/writeuser.cpp
@@ -0,0 +1,1026 @@
+//
+//  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,
+			    Array<const char*> & extensions)
+			    
+{
+  const char *types[] =
+    {
+      "Neutral Format",  ".mesh",
+      "Surface Mesh Format", ".mesh" ,
+      "DIFFPACK Format", ".mesh",
+      "TecPlot Format", ".mesh",
+      "Tochnog Format", ".mesh",
+      "Abaqus Format", ".mesh",
+      "Fluent Format", ".mesh",
+      "Permas Format", ".mesh",
+      "FEAP Format", ".mesh",
+      "Elmer Format", "*",
+      "STL Format", ".stl",
+      "STL Extended Format", ".stl",
+      "VRML Format", ".*",
+      "Gmsh Format", ".gmsh",
+      "Gmsh2 Format", ".gmsh2",
+      "OpenFOAM 1.5+ Format", "*",
+      "JCMwave Format", ".jcm",
+      "TET Format", ".tet",
+      //      { "Chemnitz Format" },
+      0
+    };
+  
+  for (int i = 0; types[2*i]; i++)
+    {
+      names.Append (types[2*i]);
+      extensions.Append (types[2*i+1]);
+    }
+}
+  
+
+
+bool WriteUserFormat (const string & format,
+		      const Mesh & mesh,
+		      const NetgenGeometry & hgeom,
+		      const string & filename)
+{
+  const CSGeometry & geom = *dynamic_cast<const CSGeometry*> (&hgeom);
+
+  PrintMessage (1, "Export mesh to file ", filename,
+		", format is ", format);
+
+  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 == "Elmer Format")
+    WriteElmerFormat (mesh, filename);
+
+  else if (format == "STL Format")
+    WriteSTLFormat (mesh, filename);
+
+  // Philippose - 16 August 2010
+  // Added additional STL Export in which
+  // each face of the geometry is treated
+  // as a separate "solid" entity
+  else if (format == "STL Extended Format")
+	WriteSTLExtFormat (mesh, filename);
+
+  else if (format == "VRML Format")
+    WriteVRMLFormat (mesh, 1, filename);
+
+  else if (format == "Fepp Format")
+    WriteFEPPFormat (mesh, geom, filename);
+
+  else if (format ==  "EdgeElement Format")
+    WriteEdgeElementFormat (mesh, geom, filename);
+
+  else if (format == "Chemnitz Format")
+    WriteUserChemnitz (mesh, filename);
+
+  else if (format == "Gmsh Format")
+    WriteGmshFormat (mesh, geom, filename);
+
+  // Philippose - 29/01/2009
+  // Added Gmsh v2.xx Mesh export capability
+  else if (format == "Gmsh2 Format")
+    WriteGmsh2Format (mesh, geom, filename);
+
+  // Philippose - 25/10/2009
+  // Added OpenFOAM 1.5+ Mesh export capability
+  else if (format == "OpenFOAM 1.5+ Format")
+    WriteOpenFOAM15xFormat (mesh, filename);
+
+  else if (format == "JCMwave Format")
+    WriteJCMFormat (mesh, geom, filename);
+
+#ifdef OLIVER
+  else if (format == "TET Format")
+    WriteTETFormat( mesh, filename);//, "High Frequency" );
+#endif
+
+  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 nseg = mesh.GetNSeg();
+  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() << " ";
+      if (mesh.GetDimension() == 3)
+	{
+	  outfile.width(9);
+	  outfile << p.Z();
+	  }
+      outfile << "\n";
+    }
+
+  if (mesh.GetDimension() == 3)
+    {
+      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";
+    }
+
+
+  if (mesh.GetDimension() == 2)
+    {
+      outfile << nseg << "\n";
+      for (i = 1; i <= nseg; i++)
+	{
+	  const Segment & seg = mesh.LineSegment(i);
+	  outfile.width(4);
+	  outfile << seg.si << "    ";
+
+	  outfile << " ";
+	  outfile.width(8);
+	  outfile << seg[0];
+	  outfile << " ";
+	  outfile.width(8);
+	  outfile << seg[1];
+
+	  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 = 0; j < 3; j++)
+	{
+	  outfile.width(10);
+	  outfile << mesh.Point(i)(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;
+
+  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;
+}
+
+
+
+
+
+/*
+ *  Philippose - 16 August 2010
+ *  Save surface mesh as STL file
+ *  with a separate solid definition
+ *  for each face
+ *  - This helps in splitting up the
+ *    STL into named boundary faces
+ *    when using a third-party mesher
+ */
+void WriteSTLExtFormat (const Mesh & mesh,
+		     const string & filename)
+{
+  cout << "\nWrite STL Surface Mesh (with separated boundary faces)" << endl;
+
+  ofstream outfile (filename.c_str());
+
+  outfile.precision(10);
+
+  int numBCs = 0;
+
+  Array<int> faceBCs;
+  TABLE<int> faceBCMapping;
+
+  faceBCs.SetSize(mesh.GetNFD());
+  faceBCMapping.SetSize(mesh.GetNFD());
+
+  faceBCs = -1;
+
+  // Collect the BC numbers used in the mesh
+  for(int faceNr = 1; faceNr <= mesh.GetNFD(); faceNr++)
+  {
+	  int bcNum = mesh.GetFaceDescriptor(faceNr).BCProperty();
+
+	  if(faceBCs.Pos(bcNum) < 0)
+	  {
+        numBCs++;
+		  faceBCs.Set(numBCs,bcNum);
+        faceBCMapping.Add1(numBCs,faceNr);        
+	  }
+     else
+     {
+        faceBCMapping.Add1(faceBCs.Pos(bcNum)+1,faceNr);
+     }
+  }
+
+  faceBCs.SetSize(numBCs);
+  faceBCMapping.ChangeSize(numBCs);
+
+  // Now actually write the data to file
+  for(int bcInd = 1; bcInd <= faceBCs.Size(); bcInd++)
+  {
+      outfile << "solid Boundary_" << faceBCs.Elem(bcInd) << "\n";
+
+      for(int faceNr = 1;faceNr <= faceBCMapping.EntrySize(bcInd); faceNr++)
+      {
+          Array<SurfaceElementIndex> faceSei;
+          mesh.GetSurfaceElementsOfFace(faceBCMapping.Get(bcInd,faceNr),faceSei);
+
+          for (int i = 0; i < faceSei.Size(); i++)
+          {
+        	  outfile << "facet normal ";
+        	  const Point3d& p1 = mesh.Point(mesh.SurfaceElement(faceSei[i]).PNum(1));
+        	  const Point3d& p2 = mesh.Point(mesh.SurfaceElement(faceSei[i]).PNum(2));
+        	  const Point3d& p3 = mesh.Point(mesh.SurfaceElement(faceSei[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 Boundary_" << faceBCs.Elem(bcInd) << "\n";
+  }
+}
+
+
+
+
+/*
+ *
+ *  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;
+
+      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;
+
+      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);
+      */
+    }
+}
+
+
+
+
+
+
+/*
+ *  Edge element mesh format
+ *  points, elements, edges
+ */
+
+void WriteEdgeElementFormat (const Mesh & mesh,
+			     const CSGeometry & geom,
+			     const string & filename)
+{
+  cout << "write edge element format" << endl;
+
+  const MeshTopology * top = &mesh.GetTopology();
+  int npoints = mesh.GetNP();
+  int nelements = mesh.GetNE();
+  int nsurfelem = mesh.GetNSE();
+  int nedges = top->GetNEdges();
+  int i, j;
+
+  int inverttets = mparam.inverttets;
+  int invertsurf = mparam.inverttrigs;
+  Array<int> edges;
+
+  ofstream outfile (filename.c_str());
+
+  outfile.precision(6);
+  outfile.setf (ios::fixed, ios::floatfield);
+  outfile.setf (ios::showpoint);
+
+
+  // vertices with coordinates
+  outfile << npoints << "\n";
+  for (i = 1; i <= npoints; 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";
+    }
+
+  // element - edge - list
+  outfile << nelements << " " << nedges << "\n";
+  for (i = 1; i <= nelements; i++)
+    {
+      Element el = mesh.VolumeElement(i);
+      if (inverttets)
+      	el.Invert();
+      outfile.width(4);
+      outfile << el.GetIndex() << "  ";
+      outfile.width(8);
+      outfile << el.GetNP();
+      for (j = 1; j <= el.GetNP(); j++)
+	{
+	  outfile << " ";
+	  outfile.width(8);
+	  outfile << el.PNum(j);
+	}
+
+      top->GetElementEdges(i,edges);
+      outfile << endl << "      ";
+      outfile.width(8);
+      outfile << edges.Size();
+      for (j=1; j <= edges.Size(); j++)
+	{
+	  outfile << " ";
+	  outfile.width(8);
+	  outfile << edges[j-1];
+	}
+      outfile << "\n";
+
+      // orientation:
+      top->GetElementEdgeOrientations(i,edges);
+      outfile << "              ";
+      for (j=1; j <= edges.Size(); j++)
+	{
+	  outfile << " ";
+	  outfile.width(8);
+	  outfile << edges[j-1];
+	}
+      outfile << "\n";
+    }
+
+  // surface element - edge - list (with boundary conditions)
+  outfile << nsurfelem << "\n";
+  for (i = 1; i <= nsurfelem; i++)
+    {
+      Element2d el = mesh.SurfaceElement(i);
+      if (invertsurf)
+	el.Invert();
+      outfile.width(4);
+      outfile << mesh.GetFaceDescriptor (el.GetIndex()).BCProperty() << "  ";
+      outfile.width(8);
+      outfile << el.GetNP();
+      for (j = 1; j <= el.GetNP(); j++)
+	{
+	  outfile << " ";
+	  outfile.width(8);
+	  outfile << el.PNum(j);
+	}
+
+      top->GetSurfaceElementEdges(i,edges);
+      outfile << endl << "      ";
+      outfile.width(8);
+      outfile << edges.Size();
+      for (j=1; j <= edges.Size(); j++)
+	{
+	  outfile << " ";
+	  outfile.width(8);
+	  outfile << edges[j-1];
+	}
+      outfile << "\n";
+    }
+
+
+  int v1, v2;
+  // edge - vertex - list
+  outfile << nedges << "\n";
+  for (i=1; i <= nedges; i++)
+    {
+      top->GetEdgeVertices(i,v1,v2);
+      outfile.width(4);
+      outfile << v1;
+      outfile << " ";
+      outfile.width(8);
+      outfile << v2 << endl;
+    }
+}
+
+
+
+
+
+
+
+
+
+#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/contrib/Netgen/libsrc/interface/writeuser.hpp b/contrib/Netgen/libsrc/interface/writeuser.hpp
new file mode 100644
index 0000000000..e5745713cb
--- /dev/null
+++ b/contrib/Netgen/libsrc/interface/writeuser.hpp
@@ -0,0 +1,165 @@
+#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 string & 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);
+
+
+// Philippose - 16 August 2010
+// Added the STL Extended format in which
+// each face of the geometry is treated as
+// a separate "solid" entity in the STL file
+extern
+void WriteSTLExtFormat (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 WriteGmshFormat (const Mesh & mesh,
+                      const CSGeometry & geom,
+                      const string & filename);
+
+
+// Philippose - 29/01/2009
+// Added GMSH v2.xx Mesh Export support
+void WriteGmsh2Format (const Mesh & mesh,
+                       const CSGeometry & geom,
+                       const string & filename);
+
+
+// Philippose - 25/10/2009
+// Added OpenFOAM 1.5+ Mesh Export support
+extern 
+void WriteOpenFOAM15xFormat (const Mesh & mesh, 
+                             const string & casename);
+
+
+extern
+void WriteUserChemnitz (const Mesh & mesh,
+                        const string & filename);
+
+extern
+void WriteJCMFormat (const Mesh & mesh,
+                     const CSGeometry & geom,
+                     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 WriteElmerFormat (const Mesh & mesh,
+                       const string & filename);
+
+
+extern
+void WriteEdgeElementFormat (const Mesh & mesh,
+                             const CSGeometry & geom,
+                             const string & filename);
+
+
+
+#ifdef OLIVER
+extern
+void WriteTETFormat (const Mesh & mesh,
+                     const string & filename);
+
+#endif
+
+extern void ReadTETFormat (Mesh & mesh,
+                           const string & filename);
+
+
+extern void ReadFNFFormat (Mesh & mesh,
+                           const string & filename);
+
+
+
+void WriteDolfinFormat (const Mesh & mesh,
+                        const string & filename);
+
+
+extern void RegisterUserFormats (Array<const char*> & names,
+                                 Array<const char*> & extensions);
+
+
+extern bool WriteUserFormat (const string & format,
+                             const Mesh & mesh,
+                             const NetgenGeometry & geom,
+                             const string & filename);
+
+#endif
+
diff --git a/contrib/Netgen/libsrc/interface/wuchemnitz.cpp b/contrib/Netgen/libsrc/interface/wuchemnitz.cpp
new file mode 100644
index 0000000000..8641a8cde9
--- /dev/null
+++ b/contrib/Netgen/libsrc/interface/wuchemnitz.cpp
@@ -0,0 +1,317 @@
+// 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:
+    int domnr, p1, p2, p3, p4;
+    int faces[4];
+
+    VOLELEMENT () 
+    { for (int i = 0; i < 4; i++) faces[i] = 0; }
+  };
+  
+  class SURFELEMENT
+  {
+  public:
+    SURFELEMENT () { };
+    int snr, p1, p2, p3;
+  };
+  
+
+  class FACE
+  {
+  public:
+    int p1, p2, p3;
+    int edges[3];
+
+    FACE () 
+    { for (int i = 0; i < 3; i++) edges[i] = 0; }
+  };
+
+  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;
+              default:
+                i3.I1()=i3.I2()=i3.I3()=0;
+              }
+            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;
+              default:
+                i2.I1()=i2.I2()=0;
+              }
+            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/contrib/Netgen/libsrc/linalg/Makefile.am b/contrib/Netgen/libsrc/linalg/Makefile.am
new file mode 100644
index 0000000000..9503b31ed7
--- /dev/null
+++ b/contrib/Netgen/libsrc/linalg/Makefile.am
@@ -0,0 +1,9 @@
+noinst_HEADERS = densemat.hpp linalg.hpp polynomial.hpp vector.hpp opti.hpp
+AM_CPPFLAGS = -I$(top_srcdir)/libsrc/include
+METASOURCES = AUTO
+noinst_LTLIBRARIES = libla.la
+libla_la_SOURCES = densemat.cpp polynomial.cpp bfgs.cpp linopt.cpp linsearch.cpp
+
+#  vector.cpp
+
+libla_la_LDFLAGS = -rdynamic
diff --git a/contrib/Netgen/libsrc/linalg/bfgs.cpp b/contrib/Netgen/libsrc/linalg/bfgs.cpp
new file mode 100644
index 0000000000..e0f40d687e
--- /dev/null
+++ b/contrib/Netgen/libsrc/linalg/bfgs.cpp
@@ -0,0 +1,407 @@
+/***************************************************************************/
+/*                                                                         */
+/* 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 n = a.Height();
+  
+  //  (*testout) << "a = " << a << endl;
+
+  l = a;
+
+  for (int i = 1; i <= n; i++)
+    {
+      for (int j = i; j <= n; j++)
+	{
+	  x = l.Get(i, j);
+
+	  for (int k = 1; k < i; k++)
+	    x -= l.Get(i, k) * l.Get(j, k) * d(k-1); 
+          
+	  if (i == j)
+	    {
+	      d(i-1) = x;
+	    }
+	  else
+	    {
+	      l.Elem(j, i) = x / d(i-1);
+	    }
+	}
+    }
+
+  for (int i = 1; i <= n; i++)
+    {
+      l.Elem(i, i) = 1;
+      for (int 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);
+    }
+  */
+
+
+
+  double val;
+
+  int n = l.Height();
+  p = g;
+  
+  for (int i = 0; i < n; i++)
+    {
+      val = 0;
+      for (int j = i; j < n; j++)
+	val += p(j) * l(j, i);
+      p(i) = val;
+    }
+
+  for (int i = 0; i < n; i++)
+    p(i) *= d(i);
+
+  for (int i = n-1; i >= 0; i--)
+    {
+      val = 0;
+      for (int j = 0; j <= i; j++)
+	val += p(j) * l(i, j);
+      p(i) = val;
+    }
+}
+
+void SolveLDLt (const DenseMatrix & l, const Vector & d, const Vector & g, Vector & p)
+{
+  double val;
+
+  int n = l.Height();
+  p = g;
+
+  for (int i = 0; i < n; i++)
+    {
+      val = 0;
+      for (int j = 0; j < i; j++)
+	val += p(j) * l(i,j);
+      p(i) -= val;
+    }
+
+  for (int i = 0; i < n; i++)
+    p(i) /= d(i);
+  
+  for (int i = n-1; i >= 0; i--)
+    {
+      val = 0;
+      for (int j = i+1; j < n; j++)
+	val += p(j) * l(j, i);
+      p(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 n = l.Height();
+
+  Vector v(n);
+  double t, told, xi;
+
+  told = 1;
+  v = u;
+
+  for (int j = 1; j <= n; j++)
+    {
+      t = told + a * sqr (v(j-1)) / d(j-1);
+
+      if (t <= 0) 
+	{
+	  (*testout) << "update err, t = " << t << endl;
+	  return 1;
+	}
+
+      xi = a * v(j-1) / (d(j-1) * t);
+
+      d(j-1) *= t / told;
+
+      for (int i = j + 1; i <= n; i++)
+	{
+	  v(i-1) -= v(j-1) * l.Elem(i, j);
+	  l.Elem(i, j) += xi * v(i-1);
+	}
+
+      told = t;
+    }
+
+  return 0;
+}
+
+
+double BFGS (
+	     Vector & x,         // i: Startwert
+	     // o: Loesung, falls IFAIL = 0
+	     const MinFunction & fun,
+	     const OptiParameters & par,
+	     double eps
+	     )
+
+
+{
+  int 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 (int 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 (int i = 1; i <= n; i++)
+	    d(i-1) = typf/ sqr (typx(i-1));   // 1;
+	  for (int i = 2; i <= n; i++)
+	    for (int 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);
+
+ //      (*testout) << "l " << l << endl
+// 		 << "d " << d << endl
+// 		 << "g " << g << endl
+// 		 << "p " << p << endl;
+
+
+      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(ifail == 1)
+	(*testout) << "no success with linesearch" << endl;
+
+       /*
+      // 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 << "BFGS update error1" << endl;
+	      (*testout) << "BFGS update error1" << endl;
+	      (*testout) << "l " << endl << l << endl
+			 << "d " << d << endl;
+	      ifail = 1;
+	      break;
+	    }
+
+	  if (LDLtUpdate (l, d, -1 / a2, bs) != 0)
+	    {
+              cerr << "BFGS update error2" << endl;
+	      (*testout) << "BFGS update error2" << endl;
+	      (*testout) << "l " << endl << l << endl
+			 << "d " << d << endl;
+	      ifail = 1;
+	      break;
+	    }
+	}
+
+      // Calculate stop conditions
+
+      hd = eps * max2 (typf, fabs (f));
+      a1crit = 1;
+      for (int i = 1; i <= n; i++)
+	if ( fabs (g(i-1)) * max2 (typx(i-1), fabs (x(i-1))) > 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/contrib/Netgen/libsrc/linalg/densemat.cpp b/contrib/Netgen/libsrc/linalg/densemat.cpp
new file mode 100644
index 0000000000..a0066e8ffd
--- /dev/null
+++ b/contrib/Netgen/libsrc/linalg/densemat.cpp
@@ -0,0 +1,1384 @@
+#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; height = width = 0;
+    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;
+  }
+
+  DenseMatrix & DenseMatrix :: operator= (double v)
+  {
+    double * p = data;
+
+    if (data)
+      for (int i = width*height; i > 0; i--, p++)
+        *p = v;
+
+    return *this;
+  }
+
+
+
+  DenseMatrix & DenseMatrix :: operator*= (double v)
+  {
+    double * p = data;
+
+    if (data)
+      for (int 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 data[0];
+      case 2: return data[0] * data[3] - data[1] * data[2];
+      case 3: return data[0] * data[4] * data[8]
+          + data[1] * data[5] * data[6]
+          + data[2] * data[3] * data[7] 
+          - data[0] * data[5] * data[7]
+          - data[1] * data[3] * data[8]
+          - data[2] * data[4] * data[6];
+      default:
+        {
+          (*myerr) << "Matrix :: Det:  general size not implemented (size=" << width << ")" << endl;
+          return 0;
+        }
+      }
+  }
+
+
+  void CalcInverse (const DenseMatrix & m1, DenseMatrix & m2)
+  {
+    double det;
+
+    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;
+            (*testout) << "CalcInverse: Matrix singular" << endl;
+            return;
+          }
+
+        det = 1.0 / det;
+        switch (m1.Width())
+          {
+          case 1:
+            {
+              m2(0,0) = det;
+              return;
+            }
+          case 2:
+            {
+              m2(0,0) = det * m1(3);
+              m2(1,1) = det * m1(0);  
+              m2(0,1) = -det * m1(1);
+              m2(1,0) = - det * m1(2);
+              return;
+            }
+          case 3:
+            {
+              m2(0, 0) =  det * (m1(4) * m1(8) - m1(5) * m1(7));
+              m2(1, 0) = -det * (m1(3) * m1(8) - m1(5) * m1(6));
+              m2(2, 0) =  det * (m1(3) * m1(7) - m1(4) * m1(6));
+
+              m2(0, 1) = -det * (m1(1) * m1(8) - m1(2) * m1(7));
+              m2(1, 1) =  det * (m1(0) * m1(8) - m1(2) * m1(6));
+              m2(2, 1) = -det * (m1(0) * m1(7) - m1(1) * m1(6));
+
+              m2(0, 2) =  det * (m1(1) * m1(5) - m1(2) * m1(4));
+              m2(1, 2) = -det * (m1(0) * m1(5) - m1(2) * m1(3));
+              m2(2, 2) =  det * (m1(0) * m1(4) - m1(1) * m1(3));
+              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;
+                *testout << "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(p.Get(k)-1) = m2.Get(i, k);
+            for (k = 1; k <= n; k++)
+              m2.Elem(i, k) = hv(k-1);
+          }
+
+
+
+        /*
+          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);
+          }
+      }
+  }
+
+
+
+  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(0);
+
+      prod = 0;
+
+      for (i = 1; i <= h; i++)
+	{
+	  double val = *pv;
+	  ++pv;
+
+	  double * pprod = &prod(0);
+
+	  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 h = Height(); 
+        int w = Width();
+        const double * mp = &Get(1, 1);
+
+        for (int i = 1; i <= h; i++)
+          {
+            sum = b(i-1);
+            const double * xp = &x(0);
+
+            for (int j = 1; j <= w; ++j, ++mp, ++xp)
+              sum -= *mp * *xp;
+	  
+            res(i-1) = 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(i-1) = 1 / sqrt(x);
+                  }
+                else
+                  {
+                    Elem(j, i) = x * p(i-1);
+                  }
+              }
+          }
+
+        for (int i = 1; i <= n; i++)
+          Elem(i, i) = 1 / p(i-1);
+
+        // A = L L^t 
+        // L stored in left-lower triangle
+
+
+        sol = v;
+
+        // Solve L sol = sol
+
+        for (int i = 1; i <= n; i++)
+          {
+            double val = sol(i-1);
+
+            const double * pij = &Get(i, 1);
+            const double * solj = &sol(0);
+
+            for (int j = 1; j < i; j++, ++pij, ++solj)
+              val -= *pij * *solj;
+            //	  for (j = 1; j < i; j++)
+            //	    val -= Get(i, j) * sol.Get(j);
+
+            sol(i-1) = val / Get(i, i);
+          }
+
+        // Solve L^t sol = sol
+
+        for (int i = n; i >= 1; i--)
+          {
+            double val = sol(i-1) / Get(i, i);
+            sol(i-1) = val;
+
+            double * solj = &sol(0);
+            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 n = Height();
+        for (int i = 1; i <= n; i++)
+          {
+            for (int 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 (int 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(j-1) -= q * sol(i-1);
+                  }
+              }
+          }
+      
+        for (int i = n; i >= 1; i--)
+          {
+            q = sol(i-1);
+            for (int j = i+1; j <= n; j++)
+	      q -= Get(i,j) * sol(j-1);
+
+            sol(i-1) = 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/contrib/Netgen/libsrc/linalg/densemat.hpp b/contrib/Netgen/libsrc/linalg/densemat.hpp
new file mode 100644
index 0000000000..5d721b5a98
--- /dev/null
+++ b/contrib/Netgen/libsrc/linalg/densemat.hpp
@@ -0,0 +1,277 @@
+#ifndef FILE_DENSEMAT
+#define FILE_DENSEMAT
+
+/**************************************************************************/
+/* File:   densemat.hpp                                                    */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   01. Oct. 94                                                    */
+/**************************************************************************/
+
+/** 
+    Data type dense matrix
+*/
+
+
+class DenseMatrix
+{
+protected:
+  int height;
+  int width;
+  double * data;
+
+public:
+  ///
+  DLL_HEADER DenseMatrix ();
+  ///
+  DLL_HEADER DenseMatrix (int h, int w = 0);
+  ///
+  DLL_HEADER DenseMatrix (const DenseMatrix & m2);
+  ///
+  DLL_HEADER ~DenseMatrix ();
+
+  ///
+  DLL_HEADER 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]; }
+  double & operator() (int i) { return data[i]; }
+  double operator() (int i) const { return data[i]; }
+
+  ///
+  DLL_HEADER DenseMatrix & operator= (const DenseMatrix & m2);
+  ///
+  DLL_HEADER DenseMatrix & operator+= (const DenseMatrix & m2);
+  ///
+  DLL_HEADER DenseMatrix & operator-= (const DenseMatrix & m2);
+
+  ///
+  DLL_HEADER DenseMatrix & operator= (double v);
+  ///
+  DLL_HEADER DenseMatrix & operator*= (double v);
+
+  ///
+  DLL_HEADER void Mult (const FlatVector & v, FlatVector & prod) const
+  {
+    double sum;
+    const double * mp, * sp;
+    double * dp;
+    
+#ifdef DEBUG
+    if (prod.Size() != height)
+      {
+	(*myerr) << "Mult: wrong vector size " << endl;
+      }
+    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(0);
+        for (int i = 0; i < height; i++)
+	  {
+	    sum = 0;
+	    sp = &v(0);
+	    
+	    for (int j = 0; j < width; j++)
+	      {
+		//        sum += Get(i,j) * v.Get(j);
+		sum += *mp * *sp;
+		mp++;
+		sp++;
+	      }
+	    
+	    *dp = sum;
+	    dp++;
+	  }
+      }
+  }
+
+  ///
+  DLL_HEADER void MultTrans (const Vector & v, Vector & prod) const;
+  ///
+  DLL_HEADER void Residuum (const Vector & x, const Vector & b, Vector & res) const;
+  ///
+  DLL_HEADER 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);
+  ///
+  DLL_HEADER void Solve (const Vector & b, Vector & x) const;
+  ///
+  void SolveDestroy (const Vector & b, Vector & x);
+  ///
+  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]; }
+};
+
+
+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; }
+
+  ///
+  MatrixFixWidth & operator= (double v)
+  {
+    for (int i = 0; i < height*WIDTH; i++)
+      data[i] = v; 
+    return *this;
+  }
+
+  ///
+  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]; }
+
+
+  MatrixFixWidth & operator*= (double v)
+  {
+    if (data)
+      for (int i = 0; i < height*WIDTH; i++)
+        data[i] *= v;
+    return *this;
+  }
+
+
+
+  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]; }
+};
+
+
+template <int WIDTH>
+extern ostream & operator<< (ostream & ost, const MatrixFixWidth<WIDTH> & 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;
+};
+
+
+extern DLL_HEADER void CalcAtA (const DenseMatrix & a, DenseMatrix & m2);
+extern DLL_HEADER void CalcInverse (const DenseMatrix & m1, DenseMatrix & m2);
+
+
+#endif
diff --git a/contrib/Netgen/libsrc/linalg/linalg.hpp b/contrib/Netgen/libsrc/linalg/linalg.hpp
new file mode 100644
index 0000000000..95d0c823c1
--- /dev/null
+++ b/contrib/Netgen/libsrc/linalg/linalg.hpp
@@ -0,0 +1,32 @@
+#ifndef FILE_LINALG
+#define FILE_LINALG
+
+/* *************************************************************************/
+/* File:   linalg.hpp                                                      */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   01. Oct. 94                                                    */
+/* *************************************************************************/
+
+/* 
+
+   Data types for basic linear algebra
+   
+   The basic concepts include the data types 
+   
+    Vector
+    SparseMatrix
+    DenseMatrix
+
+*/
+
+
+#include "../include/myadt.hpp"
+namespace netgen
+{
+#include "vector.hpp"
+#include "densemat.hpp"
+#include "polynomial.hpp"
+}
+#endif
+
+
diff --git a/contrib/Netgen/libsrc/linalg/linopt.cpp b/contrib/Netgen/libsrc/linalg/linopt.cpp
new file mode 100644
index 0000000000..dc5b53fa47
--- /dev/null
+++ b/contrib/Netgen/libsrc/linalg/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(0) = b(i1-1);
+        rs(1) = b(i2-1);
+        rs(2) = b(i3-1);
+        
+        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(0);
+	for (int hi = 1; hi < res.Size(); hi++)
+	  if (res(hi) < rmin) rmin = res(hi);
+        
+        if ( (f < fmin) && rmin >= -1e-8)
+          {
+          fmin = f;
+          x = hx;
+          }
+        }
+  }
+}
diff --git a/contrib/Netgen/libsrc/linalg/linsearch.cpp b/contrib/Netgen/libsrc/linalg/linsearch.cpp
new file mode 100644
index 0000000000..a2dd38aabf
--- /dev/null
+++ b/contrib/Netgen/libsrc/linalg/linsearch.cpp
@@ -0,0 +1,349 @@
+/***************************************************************************/
+/*                                                                         */
+/* 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
+{
+  cerr << "Grad of MinFunction called" << endl;
+  return 0;
+  /*
+  int n = x.Size();
+
+  Vector xr(n);
+  Vector xl(n);
+
+  double eps = 1e-6;
+  double fl, fr;
+  
+  for (int i = 1; i <= n; i++)
+    {
+      xr.Set (1, x);
+      xl.Set (1, x);
+
+      xr.Elem(i) += eps;
+      fr = Func (xr);
+
+      xl.Elem(i) -= eps;
+      fl = Func (xl);
+
+      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 = 0; i < n; i++)
+    {
+      for (j = 0; j < i; j++)
+	{
+	  hx = x;
+	  hx(i) = x(i) + eps;
+	  hx(j) = x(j) + eps;
+	  f11 = Func(hx);
+	  hx(i) = x(i) + eps;
+	  hx(j) = x(j) - eps;
+	  f12 = Func(hx);
+	  hx(i) = x(i) - eps;
+	  hx(j) = x(j) + eps;
+	  f21 = Func(hx);
+	  hx(i) = x(i) - eps;
+	  hx(j) = x(j) - eps;
+	  f22 = Func(hx);
+
+	  hesse(i, j) = hesse(j, i) =
+	    (f11 + f22 - f12 - f21) / (2 * eps * eps);
+	}
+
+      hx = x;
+      f = Func(x);
+      hx(i) = x(i) + eps;
+      f11 = Func(hx);
+      hx(i) = x(i) - eps;
+      f22 = Func(hx);
+
+      hesse(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;
+    }
+
+  ifail = 1;  // Markus
+
+  phi1prime = phi0prime;
+
+  //  (*testout) << "phi0prime = " << phi0prime << endl;
+
+  //  it = 100000l;
+  it = 0;
+
+  while (it++ <= par.maxit_linsearch)
+    {
+
+      xneu.Set2 (1, x, alphahat, p);
+
+
+      //    f = fun.FuncGrad (xneu, g);
+      //      f = fun.Func (xneu);
+      f = fun.FuncDeriv (xneu, p, phihatprime);
+
+      // (*testout) << "lines, 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/contrib/Netgen/libsrc/linalg/opti.hpp b/contrib/Netgen/libsrc/linalg/opti.hpp
new file mode 100644
index 0000000000..9875786900
--- /dev/null
+++ b/contrib/Netgen/libsrc/linalg/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
+
+
+
+
+  /**  
+       Solver for 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/contrib/Netgen/libsrc/linalg/polynomial.cpp b/contrib/Netgen/libsrc/linalg/polynomial.cpp
new file mode 100644
index 0000000000..cc515aac0a
--- /dev/null
+++ b/contrib/Netgen/libsrc/linalg/polynomial.cpp
@@ -0,0 +1,198 @@
+#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;
+};
+
+
+
+
+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/contrib/Netgen/libsrc/linalg/polynomial.hpp b/contrib/Netgen/libsrc/linalg/polynomial.hpp
new file mode 100644
index 0000000000..3108d4dd72
--- /dev/null
+++ b/contrib/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/contrib/Netgen/libsrc/linalg/vector.hpp b/contrib/Netgen/libsrc/linalg/vector.hpp
new file mode 100644
index 0000000000..e7c52e812b
--- /dev/null
+++ b/contrib/Netgen/libsrc/linalg/vector.hpp
@@ -0,0 +1,161 @@
+#ifndef FILE_VECTOR
+#define FILE_VECTOR
+
+/* *************************************************************************/
+/* File:   vector.hpp                                                      */
+/* 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[i];
+    return *this;
+  }
+
+  FlatVector & Set (double scal, const FlatVector & v2)
+  {
+    for (int i = 0; i < s; i++) 
+      data[i] = scal * v2[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[i] + scal2 * v2[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
+{
+  bool ownmem;
+public:
+  Vector () 
+  { s = 0; data = 0; ownmem = false; }
+  Vector (int as)
+  { s = as; data = new double[s]; ownmem = true; }
+  Vector (int as, double * mem)
+  { s = as; data = mem; ownmem = false; }
+  ~Vector ()
+  { if (ownmem) delete [] data; }
+
+  Vector & operator= (const FlatVector & v) 
+  { memcpy (data, &v(0), 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;
+	if (ownmem) delete [] data;
+	data = new double [s];
+        ownmem = true;
+      }
+  }
+
+};
+
+template <int S>
+class VectorMem : public Vector
+{
+  double mem[S];
+public:
+  VectorMem () : Vector(S, &mem[0]) { ; }
+
+  VectorMem & operator= (const FlatVector & v) 
+  { memcpy (data, &v(0), S*sizeof(double)); return *this; }
+
+  VectorMem & operator= (double scal) 
+  {
+    for (int i = 0; i < S; i++) data[i] = scal; 
+    return *this;
+  }
+};
+
+
+
+
+
+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;
+}
+
+
+
+#endif
+
+
diff --git a/contrib/Netgen/libsrc/meshing/Makefile.am b/contrib/Netgen/libsrc/meshing/Makefile.am
new file mode 100644
index 0000000000..2ff94a9525
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/Makefile.am
@@ -0,0 +1,31 @@
+AM_CPPFLAGS = $(MPI_INCLUDES) -I$(top_srcdir)/libsrc/include 
+
+
+noinst_HEADERS = adfront2.hpp hpref_quad.hpp meshfunc.hpp ruler3.hpp  \
+adfront3.hpp findip.hpp findip2.hpp hpref_segm.hpp meshing2.hpp	      \
+specials.hpp bisect.hpp geomsearch.hpp hpref_tet.hpp meshing3.hpp     \
+topology.hpp boundarylayer.hpp global.hpp hpref_trig.hpp meshing.hpp  \
+validate.hpp classifyhpel.hpp hpref_hex.hpp improve2.hpp meshtool.hpp \
+clusters.hpp hprefinement.hpp improve3.hpp meshtype.hpp		      \
+ hpref_prism.hpp localh.hpp msghandler.hpp curvedelems.hpp	      \
+ hpref_pyramid.hpp meshclass.hpp ruler2.hpp bcfunctions.hpp	      \
+ basegeom.hpp 
+
+
+
+METASOURCES = AUTO
+
+lib_LTLIBRARIES = libmesh.la
+
+libmesh_la_SOURCES = adfront2.cpp adfront3.cpp bisect.cpp boundarylayer.cpp \
+	clusters.cpp curvedelems.cpp delaunay.cpp delaunay2d.cpp	    \
+	geomsearch.cpp global.cpp hprefinement.cpp improve2.cpp		    \
+	improve2gen.cpp improve3.cpp localh.cpp meshclass.cpp		    \
+	meshfunc.cpp meshfunc2d.cpp meshing2.cpp meshing3.cpp		    \
+	meshtool.cpp meshtype.cpp msghandler.cpp netrule2.cpp		    \
+	netrule3.cpp parser2.cpp parser3.cpp prism2rls.cpp		    \
+	pyramid2rls.cpp pyramidrls.cpp quadrls.cpp refine.cpp		    \
+	ruler2.cpp ruler3.cpp secondorder.cpp smoothing2.5.cpp		    \
+	smoothing2.cpp smoothing3.cpp specials.cpp tetrarls.cpp		    \
+	topology.cpp triarls.cpp validate.cpp zrefine.cpp bcfunctions.cpp   \
+	parallelmesh.cpp  paralleltop.cpp  paralleltop.hpp basegeom.cpp 
diff --git a/contrib/Netgen/libsrc/meshing/adfront2.cpp b/contrib/Netgen/libsrc/meshing/adfront2.cpp
new file mode 100644
index 0000000000..81bef640be
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/adfront2.cpp
@@ -0,0 +1,508 @@
+/*
+  Advancing front class for surfaces
+*/
+
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+
+namespace netgen
+{
+  FrontPoint2 :: FrontPoint2 (const Point<3> & ap, PointIndex agi,
+			      MultiPointGeomInfo * amgi, bool aonsurface)
+  {
+    p = ap;
+    globalindex = agi;
+    nlinetopoint = 0;
+    frontnr = INT_MAX-10;
+    onsurface = aonsurface;
+
+    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 :: AdFront2 (const Box3d & aboundingbox)
+    : boundingbox(aboundingbox), 
+      linesearchtree(boundingbox.PMin(), boundingbox.PMax()),
+      pointsearchtree(boundingbox.PMin(), boundingbox.PMax()),
+      cpointsearchtree(boundingbox.PMin(), boundingbox.PMax())
+  {
+    nfl = 0;
+    allflines = 0;
+
+    minval = 0;
+    starti = lines.Begin();
+  }
+
+  AdFront2 :: ~AdFront2 ()
+  {
+    delete allflines;
+  }
+
+
+  void AdFront2 :: PrintOpenSegments (ostream & ost) const
+  {
+    if (nfl > 0)
+      {
+	ost << nfl << " open front segments left:" << endl;
+	for (int i = lines.Begin(); i < lines.End(); i++)
+	  if (lines[i].Valid())
+	    ost << i << ": " 
+                << GetGlobalIndex (lines[i].L().I1()) << "-"
+		<< GetGlobalIndex (lines[i].L().I2()) << endl;
+      }
+  }
+
+  /*
+  void AdFront2 :: GetPoints (Array<Point<3> > & apoints) const
+  {
+    apoints.Append (points);
+    // for (int i = 0; i < points.Size(); i++)
+    // apoints.Append (points[i].P());
+  }
+  */
+
+
+
+  int AdFront2 :: AddPoint (const Point<3> & p, PointIndex globind, 
+                            MultiPointGeomInfo * mgi,
+                            bool pointonsurface)
+  {
+    // inserts at empty position or resizes array
+    int pi;
+
+    if (delpointl.Size() != 0)
+      {
+	pi = delpointl.Last();
+	delpointl.DeleteLast ();
+
+	points[pi] = FrontPoint2 (p, globind, mgi, pointonsurface);
+      }
+    else
+      {
+	pi = points.Append (FrontPoint2 (p, globind, mgi, pointonsurface)) - 1;
+      }
+
+    if (mgi)
+      cpointsearchtree.Insert (p, pi);
+
+    if (pointonsurface)
+      pointsearchtree.Insert (p, pi);
+    
+    return pi;
+  }
+
+
+  int AdFront2 :: AddLine (int pi1, int pi2,
+                           const PointGeomInfo & gi1, const PointGeomInfo & gi2)
+  {
+    int minfn;
+    int li;
+
+    FrontPoint2 & p1 = points[pi1];
+    FrontPoint2 & p2 = points[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[li] = FrontLine (INDEX_2(pi1, pi2));
+      }
+    else
+      {
+	li = lines.Append(FrontLine (INDEX_2(pi1, pi2))) - 1;
+      }
+
+  
+    if (!gi1.trignum || !gi2.trignum)
+      {
+	cout << "ERROR: in AdFront::AddLine, illegal geominfo" << endl;
+      }
+  
+    lines[li].SetGeomInfo (gi1, gi2);
+
+    Box3d lbox;
+    lbox.SetPoint(p1.P());
+    lbox.AddPoint(p2.P());
+
+    linesearchtree.Insert (lbox.PMin(), lbox.PMax(), li);
+
+    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 (int li)
+  {
+    int pi;
+
+    nfl--;
+
+    for (int i = 1; i <= 2; i++)
+      {
+	pi = lines[li].L().I(i);
+	points[pi].RemoveLine();
+
+	if (!points[pi].Valid())
+	  {
+	    delpointl.Append (pi);
+	    if (points[pi].mgi)
+	      {
+		cpointsearchtree.DeleteElement (pi);
+		delete points[pi].mgi;
+		points[pi].mgi = NULL;
+	      }
+
+            pointsearchtree.DeleteElement (pi);
+	  }
+      }
+
+    if (allflines)
+      {
+	allflines->Set (INDEX_2 (GetGlobalIndex (lines[li].L().I1()),
+				 GetGlobalIndex (lines[li].L().I2())), 2);
+      }
+
+    lines[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 (int li)
+  {
+    lines[li].IncrementClass();
+  }
+
+
+  void AdFront2 :: ResetClass (int li)
+  {
+    lines[li].ResetClass();
+  }
+  */
+
+  int AdFront2 :: SelectBaseLine (Point<3>  & p1, Point<3>  & p2, 
+				  const PointGeomInfo *& geominfo1,
+				  const PointGeomInfo *& geominfo2,
+				  int & qualclass)
+  {
+    int baselineindex = -1; 
+
+    for (int i = starti; i < lines.End(); i++)
+      {
+	if (lines[i].Valid())
+	  {
+	    int hi = lines[i].LineClass() +
+	      points[lines[i].L().I1()].FrontNr() +
+	      points[lines[i].L().I2()].FrontNr();
+	  
+	    if (hi <= minval)
+	      {
+		minval = hi;
+		baselineindex = i;
+		break;
+	      }
+	  }
+      }
+  
+    if (baselineindex == -1)
+      {
+	minval = INT_MAX;
+	for (int i = lines.Begin(); i < lines.End(); i++)
+	  if (lines[i].Valid())
+	    {
+	      int hi = lines[i].LineClass() +
+		points[lines[i].L().I1()].FrontNr() +
+		points[lines[i].L().I2()].FrontNr();
+	    
+	      if (hi < minval)
+		{
+		  minval = hi;
+		  baselineindex = i;
+		}
+	    }
+      }
+    starti = baselineindex+1;
+
+    p1 = points[lines[baselineindex].L().I1()].P();
+    p2 = points[lines[baselineindex].L().I2()].P();
+    geominfo1 = &lines[baselineindex].GetGeomInfo(1);
+    geominfo2 = &lines[baselineindex].GetGeomInfo(2);
+
+    qualclass = lines[baselineindex].LineClass();
+
+    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)
+  {
+    static int timer = NgProfiler::CreateTimer ("adfront2::GetLocals");
+    NgProfiler::RegionTimer reg (timer);
+
+
+    int pstind;
+    Point<3>  midp, p0;
+
+    pstind = lines[baselineindex].L().I1();
+    p0 = points[pstind].P();
+
+    loclines.Append(lines[baselineindex].L());
+    lindex.Append(baselineindex);  
+
+    ArrayMem<int, 1000> nearlines(0);
+    ArrayMem<int, 1000> nearpoints(0);
+
+    // dominating costs !!
+    linesearchtree.GetIntersecting (p0 - Vec3d(xh, xh, xh),
+				    p0 + Vec3d(xh, xh, xh),
+				    nearlines);
+
+    pointsearchtree.GetIntersecting (p0 - Vec3d(xh, xh, xh),
+                                     p0 + Vec3d(xh, xh, xh),
+                                     nearpoints);
+    
+    for (int ii = 0; ii < nearlines.Size(); ii++)
+      {
+	int i = nearlines[ii];
+	if (lines[i].Valid() && i != baselineindex) 
+	  {
+            loclines.Append(lines[i].L());
+            lindex.Append(i);
+	  }
+      }
+
+    // static Array<int> invpindex;
+    invpindex.SetSize (points.Size()); 
+    // invpindex = -1;
+    for (int i = 0; i < nearpoints.Size(); i++)
+      invpindex[nearpoints[i]] = -1;
+
+    for (int i = 0; i < loclines.Size(); i++)
+      {
+	invpindex[loclines[i].I1()] = 0;
+	invpindex[loclines[i].I2()] = 0;
+      }
+
+
+    for (int i = 0; i < loclines.Size(); i++)
+      {
+	for (int j = 0; j < 2; j++)
+	  {
+	    int pi = loclines[i][j];
+	    if (invpindex[pi] == 0)
+	      {
+		pindex.Append (pi);
+		invpindex[pi] = pindex.Size();
+		loclines[i][j] = locpoints.Append (points[pi].P());
+	      }
+	    else
+	      loclines[i][j] = invpindex[pi];
+	  }
+      }
+
+
+    // double xh2 = xh*xh;
+    for (int ii = 0; ii < nearpoints.Size(); ii++)
+      {
+        int i = nearpoints[ii];
+	if (points[i].Valid() && 
+	    points[i].OnSurface() &&
+	    // Dist2 (points.Get(i).P(), p0) <= xh2 &&
+	    invpindex[i] <= 0)
+	  {
+	    invpindex[i] = locpoints.Append (points[i].P());
+	    pindex.Append(i);
+	  }
+      }
+    /*
+    double xh2 = xh*xh;
+    for (i = 1; i <= points.Size(); i++)
+      {
+	if (points.Get(i).Valid() && 
+	    points.Get(i).OnSurface() &&
+	    Dist2 (points.Get(i).P(), p0) <= xh2 &&
+	    invpindex.Get(i) <= 0)
+	  {
+	    invpindex.Elem(i) =
+	      locpoints.Append (points.Get(i).P());
+	    pindex.Append(i);
+	  }
+      }
+    */
+
+    pgeominfo.SetSize (locpoints.Size());
+    for (int i = 0; i < pgeominfo.Size(); i++)
+      pgeominfo[i].Init();
+
+
+    for (int i = 0; i < loclines.Size(); i++)
+      for (int j = 0; j < 2; j++)
+	{
+	  int lpi = loclines[i][j];
+	
+	  const PointGeomInfo & gi = 
+	    lines[lindex[i]].GetGeomInfo (j+1);
+	  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 (int i = 0; i < locpoints.Size(); i++)
+      {
+	int pi = pindex[i];
+      
+	if (points[pi].mgi)
+	  for (int j = 1; j <= points[pi].mgi->GetNPGI(); j++)
+	    pgeominfo[i].AddPointGeomInfo (points[pi].mgi->GetPGI(j));
+      }
+   
+    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[baselineindex].LineClass();
+  }
+
+
+
+  void AdFront2 :: SetStartFront ()
+  {
+    for (int i = lines.Begin(); i < lines.End(); i++)
+      if (lines[i].Valid())
+	for (int j = 1; j <= 2; j++)
+	  points[lines[i].L().I(j)].DecFrontNr(0);
+  }
+
+
+  void AdFront2 :: Print (ostream & ost) const
+  {
+    ost << points.Size() << " Points: " << endl;
+    for (int i = points.Begin(); i < points.End(); i++)
+      if (points[i].Valid())
+	ost << i << "  " << points[i].P() << endl;
+
+    ost << nfl << " Lines: " << endl;
+    for (int i = lines.Begin(); i < lines.End(); i++)
+      if (lines[i].Valid())
+	ost << lines[i].L().I1() << " - " << lines[i].L().I2() << endl;
+
+    ost << flush;
+  }
+
+
+  bool AdFront2 :: Inside (const Point<2> & p) const
+  {
+    int cnt;
+    Vec<2> n;
+    Vec<3> v1;
+    DenseMatrix a(2), ainv(2);
+    Vector b(2), u(2);
+    
+    // random numbers:
+    n(0) = 0.123871;
+    n(1) = 0.15432;
+    
+    cnt = 0;
+    for (int i = 0; i < lines.Size(); i++)
+      if (lines[i].Valid())
+	{
+	  const Point<3> & p1 = points[lines[i].L().I1()].P();
+	  const Point<3> & p2 = points[lines[i].L().I2()].P();
+	  
+	  v1 = p2 - p1;
+	  
+	  a(0, 0) = v1(0);
+	  a(1, 0) = v1(1);
+	  
+	  a(0, 1) = -n(0);
+	  a(1, 1) = -n(1);
+
+	  b(0) = p(0) - p1(0);
+	  b(1) = p(1) - p1(1);
+	  
+	  CalcInverse (a, ainv);
+	  ainv.Mult (b, u);
+	  
+	  if (u(0) >= 0 && u(0) <= 1 && u(1) > 0)
+	    cnt++;
+	}
+    
+    return ((cnt % 2) != 0);
+  }
+}
diff --git a/contrib/Netgen/libsrc/meshing/adfront2.hpp b/contrib/Netgen/libsrc/meshing/adfront2.hpp
new file mode 100644
index 0000000000..6a8158b974
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/adfront2.hpp
@@ -0,0 +1,282 @@
+#ifndef FILE_ADFRONT2
+#define FILE_ADFRONT2
+
+/**************************************************************************/
+/* File:   adfront2.hpp                                                   */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   01. Okt. 95                                                    */
+/**************************************************************************/
+
+
+/**
+
+    Advancing front class for surfaces
+
+*/
+
+  ///
+  class FrontPoint2
+  {
+    /// coordinates
+    Point<3> p;            
+    /// global node index
+    PointIndex globalindex;   
+    /// number of front lines connected to point 
+    int nlinetopoint;    
+    /// distance to original boundary
+    int frontnr;          
+
+    bool onsurface;
+
+  public:
+    ///
+    MultiPointGeomInfo * mgi;
+
+    ///
+    FrontPoint2 ()
+    {
+      globalindex = -1;
+      nlinetopoint = 0;
+      frontnr = INT_MAX-10;    // attention: overflow on calculating  INT_MAX + 1
+      mgi = NULL;
+      onsurface = true;
+    }
+
+    ///
+    FrontPoint2 (const Point<3> & ap, PointIndex agi,
+		 MultiPointGeomInfo * amgi, bool aonsurface = true);
+    ///
+    ~FrontPoint2 () { ; }
+
+    ///
+    const Point<3> & P () const { return p; }
+    ///
+    operator const Point<3> & () 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; }
+
+    ///
+    bool OnSurface() const
+    { return onsurface; }
+
+    ///
+    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
+    PointGeomInfo geominfo[2];
+  public:
+
+    FrontLine ()
+    {
+      lineclass = 1;
+    }
+
+    ///
+    FrontLine (const INDEX_2 & al)
+    {
+      l = al;
+      lineclass = 1;
+    }
+
+
+    ///
+    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;
+  };
+
+
+class AdFront2
+{
+
+  ///
+  Array<FrontPoint2> points;  /// front points
+  Array<FrontLine> lines;     /// front lines
+
+  Box3d boundingbox;
+  Box3dTree linesearchtree;       /// search tree for lines
+  Point3dTree pointsearchtree;    /// search tree for points
+  Point3dTree cpointsearchtree;   /// search tree for cone points (not used ???)
+
+  Array<int> delpointl;     /// list of deleted front points
+  Array<int> dellinel;      /// list of deleted front lines
+
+  int nfl;                  /// number of front lines;
+  INDEX_2_HASHTABLE<int> * allflines; /// all front lines ever have been
+
+  Array<int> invpindex;
+
+  int minval;
+  int starti;
+
+public:
+  ///
+  //  AdFront2 ();
+  AdFront2 (const Box3d & aboundingbox);
+  ///
+  ~AdFront2 ();
+
+  ///
+  // void GetPoints (Array<Point<3> > & apoints) const;
+  ///
+  void Print (ostream & ost) const;
+
+  ///
+  bool Empty () const
+  {
+    return nfl == 0;
+  }
+  ///
+  int GetNFL () const { return nfl; }
+
+  const FrontLine & GetLine (int nr) { return lines[nr]; }
+  const FrontPoint2 & GetPoint (int nr) { return points[nr]; }
+
+
+  ///
+  int SelectBaseLine (Point<3> & p1, Point<3> & p2, 
+		      const PointGeomInfo *& geominfo1,
+		      const PointGeomInfo *& geominfo2,
+		      int & qualclass);
+
+  ///
+  int GetLocals (int baseline, 
+		 Array<Point3d> & locpoints,
+		 Array<MultiPointGeomInfo> & pgeominfo,
+                 Array<INDEX_2> & loclines,   // local index
+                 Array<int> & pindex,
+                 Array<int> & lindex,
+                 double xh);
+
+  ///
+  void DeleteLine (int li);
+  ///
+  int AddPoint (const Point<3> & p, PointIndex globind, 
+                MultiPointGeomInfo * mgi = NULL,
+                bool pointonsurface = true);
+  ///
+  int AddLine (int pi1, int pi2, 
+               const PointGeomInfo & gi1, const PointGeomInfo & gi2);
+  ///
+  int ExistsLine (int gpi1, int gpi2);
+
+  ///
+  void IncrementClass (int li)
+  {
+    lines[li].IncrementClass();
+  }
+
+  ///
+  void ResetClass (int li)
+  {
+    lines[li].ResetClass();
+  }
+
+  ///
+  const PointGeomInfo & GetLineGeomInfo (int li, int lend) const
+    { return lines[li].GetGeomInfo (lend); }
+  ///
+
+  PointIndex GetGlobalIndex (int pi) const
+  {
+    return points[pi].GlobalIndex();
+  }
+
+
+  /// is Point p inside Surface (flat geometry only)
+  bool Inside (const Point<2> & p) const;
+
+  bool SameSide (const Point<2> & lp1, const Point<2> & lp2, 
+                 const Array<int> * /* testfaces */ = NULL) const
+  {
+    return Inside (lp1) == Inside (lp2);
+  }
+
+
+  ///
+  void SetStartFront ();
+  ///
+  void PrintOpenSegments (ostream & ost) const;
+};
+
+
+
+#endif
+
+
+
diff --git a/contrib/Netgen/libsrc/meshing/adfront3.cpp b/contrib/Netgen/libsrc/meshing/adfront3.cpp
new file mode 100644
index 0000000000..e8863d9f42
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/adfront3.cpp
@@ -0,0 +1,868 @@
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+
+/* ********************** FrontPoint ********************** */
+
+namespace netgen
+{
+
+FrontPoint3 :: FrontPoint3 () 
+{ 
+  globalindex = -1;
+  nfacetopoint = 0; 
+  frontnr = 1000; 
+  cluster = 0;
+}
+
+
+FrontPoint3 :: FrontPoint3 (const Point<3> & 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 MiniElement2d & af)
+{ 
+  f = af; 
+  oldfront = 0; 
+  qualclass = 1; 
+  hashvalue = 0;
+}
+
+void FrontFace :: Invalidate ()
+{ 
+  f.Delete(); 
+  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 ()
+{
+  delete facetree;
+  delete connectedpairs;
+}
+
+void AdFront3 :: GetPoints (Array<Point<3> > & apoints) const
+{
+  for (PointIndex pi = PointIndex::BASE; 
+       pi < points.Size()+PointIndex::BASE; pi++)
+    
+    apoints.Append (points[pi].P());
+}
+
+
+PointIndex AdFront3 :: AddPoint (const Point<3> & 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 MiniElement2d & 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)
+{
+  nff--;
+
+  for (int i = 1; i <= faces.Get(fi).Face().GetNP(); i++)
+    {
+      PointIndex pi = faces.Get(fi).Face().PNum(i);
+      points[pi].RemoveFace();
+      if (!points[pi].Valid())
+	delpointl.Append (pi);
+    }
+
+  const MiniElement2d & face = faces.Get(fi).Face();
+  const Point3d & p1 = points[face.PNum(1)].P();
+  const Point3d & p2 = points[face.PNum(2)].P();
+  const Point3d & p3 = points[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[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, PointIndex::BASE> (GetNP());
+
+  connectedpairs->Add (apair.I1(), apair.I2());
+  connectedpairs->Add (apair.I2(), apair.I1());
+
+  return 0;
+}
+
+
+void AdFront3 :: CreateTrees ()
+{
+  int i, j;
+  PointIndex pi;
+  Point3d pmin, pmax;
+
+  for (pi = PointIndex::BASE; 
+       pi < GetNP()+PointIndex::BASE; pi++)
+    {
+      const Point<3> & 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);
+
+  delete facetree;
+  facetree = new Box3dTree (pmin, pmax);
+  
+  for (i = 1; i <= GetNF(); i++)
+    {
+      const MiniElement2d & el = GetFace(i);
+      pmin = GetPoint (el[0]);
+      pmax = pmin;
+      for (j = 1; j < 3; j++)
+	{
+	  const Point<3> & 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 Point<3> & pmin, const Point<3> & 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 ()
+{
+  static int timer_a = NgProfiler::CreateTimer ("Adfront3::RebuildInternal A");
+  static int timer_b = NgProfiler::CreateTimer ("Adfront3::RebuildInternal B");
+  static int timer_c = NgProfiler::CreateTimer ("Adfront3::RebuildInternal C");
+  static int timer_d = NgProfiler::CreateTimer ("Adfront3::RebuildInternal D");
+
+
+  NgProfiler::StartTimer (timer_a);	  
+  int hi = 0;
+  for (int i = 1; i <= faces.Size(); i++)
+    if (faces.Get(i).Valid())
+      {
+	hi++;
+	if (hi < i)
+	  faces.Elem(hi) = faces.Get(i);
+      }
+  
+  faces.SetSize (nff);
+
+  int np = points.Size();
+
+  for (int i = PointIndex::BASE; 
+       i < np+PointIndex::BASE; i++)
+    points[i].cluster = i;
+  
+  NgProfiler::StopTimer (timer_a);	  
+  NgProfiler::StartTimer (timer_b);	  
+
+  int change;
+  do
+    {
+      change = 0;
+      for (int i = 1; i <= faces.Size(); i++)
+	{
+	  const MiniElement2d & el = faces.Get(i).Face();
+
+	  int mini = points[el.PNum(1)].cluster;
+	  int maxi = mini;
+	  
+	  for (int j = 2; j <= 3; j++)
+	    {
+	      int ci = points[el.PNum(j)].cluster;
+	      if (ci < mini) mini = ci;
+	      if (ci > maxi) maxi = ci;
+	    }
+
+	  if (mini < maxi)
+	    {
+	      change = 1;
+	      for (int j = 1; j <= 3; j++)
+		points[el.PNum(j)].cluster = mini;
+	    }
+	}
+    }
+  while (change);
+
+
+  NgProfiler::StopTimer (timer_b);	  
+  NgProfiler::StartTimer (timer_c);	  
+
+
+
+
+  BitArrayChar<PointIndex::BASE> usecl(np);
+  usecl.Clear();
+  for (int i = 1; i <= faces.Size(); i++)
+    {
+      usecl.Set (points[faces.Get(i).Face().PNum(1)].cluster);
+      faces.Elem(i).cluster =
+	points[faces.Get(i).Face().PNum(1)].cluster;
+    }
+  int cntcl = 0;
+  for (int i = PointIndex::BASE; 
+       i < np+PointIndex::BASE; i++)
+    if (usecl.Test(i))
+      cntcl++;
+
+  Array<double, PointIndex::BASE> clvol (np);
+  clvol = 0.0;
+
+  for (int i = 1; i <= faces.Size(); i++)
+    {
+      const MiniElement2d & face = faces.Get(i).Face();
+
+      const Point3d p1 = points[face.PNum(1)].P();      
+      const Point3d p2 = points[face.PNum(2)].P();      
+      const Point3d p3 = points[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[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[faces.Get(i).cluster] += vi;
+    }
+
+  NgProfiler::StopTimer (timer_c);	  
+  NgProfiler::StartTimer (timer_d);	  
+
+
+
+  int negvol = 0;
+  for (int i = PointIndex::BASE; 
+       i < clvol.Size()+PointIndex::BASE; i++)
+    {
+      if (clvol[i] < 0)
+	negvol = 1;
+    }
+
+  if (negvol)
+    {
+      for (int i = 1; i <= faces.Size(); i++)
+	faces.Elem(i).cluster = 1;
+      for (int i = PointIndex::BASE; 
+	   i < points.Size()+PointIndex::BASE; i++)
+	points[i].cluster = 1;
+    }
+
+  if (hashon) 
+    hashtable.Create();
+
+  NgProfiler::StopTimer (timer_d);	  
+}
+
+
+
+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[faces.Get(i).Face().PNum(1)].FrontNr() +
+	  points[faces.Get(i).Face().PNum(2)].FrontNr() +
+	  points[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[faces.Get(i).Face().PNum(1)].FrontNr() +
+	      points[faces.Get(i).Face().PNum(2)].FrontNr() +
+	      points[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<MiniElement2d> & locfaces,   // local index
+			   Array<PointIndex> & pindex,
+			   Array<INDEX> & findex,
+			   INDEX_2_HASHTABLE<int> & getconnectedpairs,
+			   float xh,
+			   float relh,
+			   INDEX& facesplit)
+{
+  static int timer = NgProfiler::CreateTimer ("AdFront3::GetLocals");
+  NgProfiler::RegionTimer reg (timer);
+
+
+  if (hashon && faces.Size() < 500) { hashon=0; }
+  if (hashon && !hashcreated) 
+    {
+      hashtable.Create(); 
+      hashcreated=1;
+    }
+
+  INDEX i, j;
+  PointIndex pstind;
+  INDEX pi;
+  Point3d midp, p0;
+
+  //  static Array<int, PointIndex::BASE> invpindex;
+  
+  Array<MiniElement2d> locfaces2;           //all local faces in radius xh
+  Array<int> locfaces3;           // all faces in outer radius relh
+  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[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 MiniElement2d & face = faces.Get(i).Face();
+	  if (faces.Get(i).cluster == cluster && faces.Get(i).Valid() && i != fstind)
+	    {
+	      Box3d b2;
+	      b2.SetPoint (points[face[0]].P());
+	      b2.AddPoint (points[face[1]].P());
+	      b2.AddPoint (points[face[2]].P());
+
+	      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 MiniElement2d & face = locfaces2.Get(i);
+      const Point3d & p1 = points[face[0]].P();
+      const Point3d & p2 = points[face[1]].P();
+      const Point3d & p3 = points[face[2]].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[pi] = -1;
+      }
+
+  for (i = 1; i <= locfaces.Size(); i++)
+    {
+      for (j = 1; j <= locfaces.Get(i).GetNP(); j++)
+	{
+	  pi = locfaces.Get(i).PNum(j);
+	  if (invpindex[pi] == -1)
+	    {
+	      pindex.Append (pi);
+	      invpindex[pi] = pindex.Size();  // -1+PointIndex::BASE;
+	      locfaces.Elem(i).PNum(j) = locpoints.Append (points[pi].P());
+	    }
+	  else
+	    locfaces.Elem(i).PNum(j) = invpindex[pi];
+
+	}
+    }
+
+
+
+  if (connectedpairs)
+    {
+      for (i = 1; i <= locpoints.Size(); i++)
+	{
+	  int pind = pindex.Get(i);
+	  if (pind >= 1 && pind <= connectedpairs->Size ())
+	    {
+	      for (j = 1; j <= connectedpairs->EntrySize(pind); j++)
+		{
+		  int oi = connectedpairs->Get(pind, 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 (INDEX_2::Sort (i, other), 1);
+		    }
+		}
+	    }
+	}
+    }
+  
+
+  /*
+    // add isolated points
+  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<MiniElement2d> & groupelements,
+			   Array<PointIndex> & pindex,
+			   Array<INDEX> & findex) 
+{
+  // static Array<char> pingroup;
+  int i, j, changed;
+
+  pingroup.SetSize(points.Size());
+
+  pingroup = 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 MiniElement2d & face = faces.Get(i).Face();
+
+	    int 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())
+      {
+	int 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 MiniElement2d & face = faces.Get(i).Face();
+	for (j = 1; j <= 3; j++)
+	  points[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;
+    }
+    */
+}
+
+
+bool AdFront3 :: Inside (const Point<3> & p) const
+{
+  int 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 (int i = 1; i <= faces.Size(); i++)
+    if (faces.Get(i).Valid())
+      {
+	const Point<3> & p1 = points[faces.Get(i).Face().PNum(1)].P();
+	const Point<3> & p2 = points[faces.Get(i).Face().PNum(2)].P();
+	const Point<3> & p3 = points[faces.Get(i).Face().PNum(3)].P();
+
+	v1 = p2 - p1;
+	v2 = p3 - p1;
+
+	a(0, 0) = v1.X();
+	a(1, 0) = v1.Y();
+	a(2, 0) = v1.Z();
+	a(0, 1) = v2.X();
+	a(1, 1) = v2.Y();
+	a(2, 1) = v2.Z();
+	a(0, 2) = -n.X();
+	a(1, 2) = -n.Y();
+	a(2, 2) = -n.Z();
+
+	b(0) = p(0) - p1(0);
+	b(1) = p(1) - p1(1);
+	b(2) = p(2) - p1(2);
+
+	CalcInverse (a, ainv);
+	ainv.Mult (b, u);
+
+	if (u(0) >= 0 && u(1) >= 0 && u(0)+u(1) <= 1 &&
+	    u(2) > 0)
+	  {
+	    cnt++;
+	  }
+      }
+
+  return ((cnt % 2) != 0);
+}
+
+
+
+
+
+int AdFront3 :: SameSide (const Point<3> & lp1, const Point<3> & lp2,
+			  const Array<int> * testfaces) const
+{
+  const Point<3> *line[2];
+  line[0] = &lp1;
+  line[1] = &lp2;
+
+
+  Point3d pmin(lp1);
+  Point3d pmax(lp1);
+  pmin.SetToMin (lp2);
+  pmax.SetToMax (lp2);
+  
+  ArrayMem<int, 100> aprif;
+  aprif.SetSize(0);
+  
+  if (!testfaces)
+    facetree->GetIntersecting (pmin, pmax, aprif);
+  else
+    for (int i = 1; i <= testfaces->Size(); i++)
+      aprif.Append (testfaces->Get(i));
+
+  int cnt = 0;
+  for (int ii = 1; ii <= aprif.Size(); ii++)
+    {
+      int i = aprif.Get(ii);
+      
+      if (faces.Get(i).Valid())
+	{
+	  const Point<3> *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/contrib/Netgen/libsrc/meshing/adfront3.hpp b/contrib/Netgen/libsrc/meshing/adfront3.hpp
new file mode 100644
index 0000000000..60c6aa108a
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/adfront3.hpp
@@ -0,0 +1,320 @@
+#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
+Point<3> 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 Point<3> & ap, PointIndex agi);
+  
+  ///
+  const Point<3> & 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;
+};
+
+
+
+class MiniElement2d
+{
+protected:
+  int np;
+  PointIndex pnum[4];
+  bool deleted;
+public:
+  MiniElement2d ()
+  { np = 3; deleted = 0; }
+  MiniElement2d (int anp)
+  { np = anp; deleted = 0; }
+
+  int GetNP() const { return np; }
+  PointIndex & operator[] (int i) { return pnum[i]; }
+  const PointIndex operator[] (int i) const { return pnum[i]; }
+
+  const PointIndex PNum (int i) const { return pnum[i-1]; }
+  PointIndex & PNum (int i) { return pnum[i-1]; }
+  const PointIndex PNumMod (int i) const { return pnum[(i-1)%np]; }
+
+  void Delete () { deleted = 1; pnum[0] = pnum[1] = pnum[2] = pnum[3] = PointIndex::BASE-1; }
+  bool IsDeleted () const { return deleted; }
+};
+
+
+inline ostream & operator<<(ostream  & s, const MiniElement2d & el)
+{
+  s << "np = " << el.GetNP();
+  for (int j = 0; j < el.GetNP(); j++)
+    s << " " << el[j];
+  return s;
+}
+
+
+
+
+/// Face in advancing front
+class FrontFace
+{
+private:
+  ///
+  MiniElement2d f;
+  ///
+  int qualclass;
+  ///
+  char oldfront;
+  ///
+  int hashvalue;
+  ///
+  int cluster;
+
+public:
+  ///
+  FrontFace ();
+  ///
+  FrontFace (const MiniElement2d & af);
+  ///
+  const MiniElement2d & Face () const
+  { return f; }
+  
+  ///
+  int QualClass () const
+  { return qualclass; }
+
+  ///
+  void IncrementQualClass ()
+  { qualclass++; }
+
+  ///
+  void ResetQualClass ()
+  {
+    if (qualclass > 1)
+      {
+	qualclass = 1;
+	oldfront = 0;
+      }
+  }
+  
+  ///
+  bool Valid () const
+  { return !f.IsDeleted(); }
+
+  ///
+  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, PointIndex::BASE> * 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;
+  Array<int, PointIndex::BASE> invpindex;
+  Array<char> pingroup;
+  
+  ///
+class Box3dTree * facetree;
+public:
+
+  ///
+  AdFront3 ();
+  ///
+  ~AdFront3 ();
+  ///
+  void GetPoints (Array<Point<3> > & apoints) const;
+  ///
+  int GetNP() const 
+  { return points.Size(); }
+  ///
+  const Point<3> & GetPoint (PointIndex pi) const
+  { return points[pi].P(); }
+  ///
+  int GetNF() const
+  { return nff; }
+  ///
+  const MiniElement2d & GetFace (int i) const
+  { return faces.Get(i).Face(); }
+  ///
+  void Print () const;
+  ///
+  bool Empty () const
+  { return nff == 0; }
+  ///
+  bool Empty (int elnp) const
+  {
+    if (elnp == 4)
+      return (nff4 == 0);
+    return (nff - nff4 == 0);
+  }
+  ///
+  int SelectBaseElement ();
+
+  ///
+  void CreateTrees ();
+
+  ///
+  void GetIntersectingFaces (const Point<3> & pmin, const Point<3> & pmax, 
+			     Array<int> & ifaces) const;
+
+  ///
+  void GetFaceBoundingBox (int i, Box3d & box) const;
+
+  ///
+  int GetLocals (int baseelement,
+		 Array<Point3d > & locpoints,
+                 Array<MiniElement2d> & 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<MiniElement2d> & groupelements,
+                 Array<PointIndex> & pindex,
+                 Array<INDEX> & findex);
+
+  ///
+  void DeleteFace (INDEX fi);
+  ///
+  PointIndex AddPoint (const Point<3> & p, PointIndex globind);
+  ///
+  INDEX AddFace (const MiniElement2d & e);
+  ///
+  INDEX AddConnectedPair (const INDEX_2 & pair);
+  ///
+  void IncrementClass (INDEX fi)
+  { faces.Elem(fi).IncrementQualClass(); }
+
+  ///
+  void ResetClass (INDEX fi)
+  { faces.Elem(fi).ResetQualClass(); }
+
+  ///
+  void SetStartFront (int baseelnp = 0);
+
+  /// is Point p inside Surface ?
+  bool Inside (const Point<3> & p) const;
+  /// both points on same side ?
+  int SameSide (const Point<3> & lp1, const Point<3> & 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/contrib/Netgen/libsrc/meshing/basegeom.cpp b/contrib/Netgen/libsrc/meshing/basegeom.cpp
new file mode 100644
index 0000000000..c8d642e29d
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/basegeom.cpp
@@ -0,0 +1,66 @@
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+namespace netgen
+{
+
+  DLL_HEADER Array<GeometryRegister*> geometryregister;
+
+  GeometryRegister :: ~GeometryRegister()
+  { ; }
+
+
+
+
+  
+  int NetgenGeometry :: GenerateMesh (Mesh*& mesh, MeshingParameters & mparam,
+				      int perfstepsstart, int perfstepsend)
+  {
+    if (!mesh) return 1;
+
+    if (perfstepsstart <= MESHCONST_MESHVOLUME)
+      {
+	multithread.task = "Volume meshing";
+	
+	MESHING3_RESULT res =
+	  MeshVolume (mparam, *mesh);
+	
+	if (res != MESHING3_OK) return 1;
+	
+	if (multithread.terminate) return 0;
+	
+	RemoveIllegalElements (*mesh);
+	if (multithread.terminate) return 0;
+
+	MeshQuality3d (*mesh);
+      }
+
+    
+    if (multithread.terminate || perfstepsend <= MESHCONST_MESHVOLUME)
+      return 0;
+
+
+    if (perfstepsstart <= MESHCONST_OPTVOLUME)
+      {
+	multithread.task = "Volume optimization";
+	
+	OptimizeVolume (mparam, *mesh);
+	if (multithread.terminate) return 0;
+      }
+    
+    return 0;
+  }    
+  
+
+  const Refinement & NetgenGeometry :: GetRefinement () const
+  {
+    return *new Refinement;;
+  }
+
+
+  void NetgenGeometry :: Save (string filename) const
+  {
+    throw NgException("Cannot save geometry - no geometry available");
+  }
+
+}
diff --git a/contrib/Netgen/libsrc/meshing/basegeom.hpp b/contrib/Netgen/libsrc/meshing/basegeom.hpp
new file mode 100644
index 0000000000..5f866d0738
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/basegeom.hpp
@@ -0,0 +1,50 @@
+#ifndef FILE_BASEGEOM
+#define FILE_BASEGEOM
+
+/**************************************************************************/
+/* File:   basegeom.hpp                                                   */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   23. Aug. 09                                                    */
+/**************************************************************************/
+
+
+struct Tcl_Interp;
+
+namespace netgen
+{
+
+  class DLL_HEADER NetgenGeometry
+  {
+  public:
+    virtual ~NetgenGeometry () { ; }
+
+    virtual int GenerateMesh (Mesh*& mesh, MeshingParameters & mparam, 
+			      int perfstepsstart, int perfstepsend);
+
+    virtual const Refinement & GetRefinement () const;
+
+    virtual void Save (string filename) const;
+    virtual void SaveToMeshFile (ostream & /* ost */) const { ; }
+  };
+
+
+
+
+
+  class DLL_HEADER GeometryRegister
+  {
+  public:
+    virtual ~GeometryRegister();
+    virtual NetgenGeometry * Load (string filename) const = 0;
+    virtual NetgenGeometry * LoadFromMeshFile (istream & /* ist */) const { return NULL; }
+    virtual class VisualScene * GetVisualScene (const NetgenGeometry * /* geom */) const
+    { return NULL; }
+    virtual void SetParameters (Tcl_Interp * /* interp */) { ; }
+  };
+
+  extern DLL_HEADER Array<GeometryRegister*> geometryregister; 
+}
+
+
+
+#endif
diff --git a/contrib/Netgen/libsrc/meshing/bcfunctions.cpp b/contrib/Netgen/libsrc/meshing/bcfunctions.cpp
new file mode 100644
index 0000000000..1bab1b75cc
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/bcfunctions.cpp
@@ -0,0 +1,468 @@
+
+#include <mystdlib.h>
+#include <meshing.hpp>
+
+
+namespace netgen
+{
+   // Default colour to be used for boundary condition number "0"
+   #define DEFAULT_R       0.0
+   #define DEFAULT_G       1.0
+   #define DEFAULT_B       0.0
+
+   // Boundary condition number to use if a face does not have a 
+   // colour assigned to it, or if the colour is the above defined 
+   // default colour
+   #define DEFAULT_BCNUM   1
+
+   // Default tolerance for colour matching (using Euclidean distance)
+   #define DEFAULT_EPS     2.5e-05
+
+
+
+
+   /*! Philippose - 11/07/2009
+       Function to check if two RGB colours are equal
+
+       Note#1: Currently uses unweighted Euclidean Distance 
+       for colour matching.
+
+       Note#2: The tolerance used for deciding whether two 
+       colours match is defined as "eps" and is currently 
+       2.5e-5 (for square of distance)
+   */
+   bool ColourMatch(Vec3d col1, Vec3d col2, double eps = DEFAULT_EPS)
+   {
+      if(eps <= 0.0) eps = DEFAULT_EPS;
+      
+      bool colmatch = false;
+
+      if(Dist2(col1,col2) < eps) colmatch = true;
+
+      return colmatch;
+   }
+      
+
+
+
+
+   /*! Philippose - 11/07/2009
+       Function to create a list of all the unique colours 
+       available in a given mesh
+   */
+   void GetFaceColours(Mesh & mesh, Array<Vec3d> & face_colours)
+   {
+      face_colours.SetSize(1);
+      face_colours.Elem(1) = mesh.GetFaceDescriptor(1).SurfColour();
+      
+      for(int i = 1; i <= mesh.GetNFD(); i++)
+      {
+         Vec3d face_colour = mesh.GetFaceDescriptor(i).SurfColour();
+         bool col_found = false;
+         
+         for(int j = 1; j <= face_colours.Size(); j++)
+         {
+            if(ColourMatch(face_colours.Elem(j),face_colour))
+            {
+               col_found = true;
+               break;
+            }
+         }
+         
+         if(!col_found) face_colours.Append(face_colour);
+      }
+
+      if(printmessage_importance >= 3)
+      {
+         cout << endl << "-------- Face Colours --------" << endl;
+         for( int i = 1; i <= face_colours.Size(); i++)
+         {
+            cout << face_colours.Elem(i) << endl;
+         }
+         cout << "------------------------------" << endl;
+      }
+   }
+
+
+
+
+
+
+   /*! Philippose - 11/07/2009
+       Assign boundary condition numbers based on a user defined 
+       colour profile file.
+
+       The default profile file is "netgen.ocf"
+
+       If the mesh contains colours not defined in the profile,
+       netgen automatically starts assigning each new colour a 
+       new boundary condition number starting from the highest 
+       boundary condition number specified in the profile file.
+   */
+   void AutoColourAlg_UserProfile(Mesh & mesh, ifstream & ocf)
+   {
+      char ocf_inp[100];
+      bool header_found = false;
+
+      // Number of colour specifications in the 
+      // user profile file
+      int numentries = 0;
+      while((ocf.good()) && (!header_found))
+      {
+         ocf >> ocf_inp;
+         if(strcmp(ocf_inp,"boundary_colours") == 0) header_found = true;
+      }
+
+      if(!header_found)
+      {
+         ocf.close();
+         throw NgException("AutoColourAlg_UserProfile: Invalid or empty Boundary Colour Profile file\n");
+         return;
+      }
+
+      // Read in the number of entries from file
+      ocf >> numentries;
+      if(numentries > 0)
+      {
+         if(!ocf.good())
+         {
+            ocf.close();
+            throw NgException("AutoColourAlg_UserProfile: Invalid or empty Boundary Colour Profile file\n");
+            return;
+         }
+
+         PrintMessage(3, "Number of colour entries: ", numentries);
+      }
+      else
+      {
+         ocf.close();
+         PrintMessage(3, "AutoColourAlg_UserProfile: No Boundary Colour entries found.... no changes made!");
+         return;
+      }
+
+      // Arrays to hold the specified RGB colour triplets as well 
+      // as the associated boundary condition number
+      Array<Vec3d> bc_colours(numentries);
+      Array<int> bc_num(numentries);
+      Array<bool> bc_used(numentries);
+      
+      // Actually read in the data from the file
+      for(int i = 1; i <= numentries; i++)
+      {
+         int bcnum;
+         // double col_red, col_green, col_blue;
+
+         ocf >> bcnum;
+         // Boundary condition number DEFAULT_BCNUM is reserved for 
+         // faces which have the default colour Green (0.0,1.0,0.0)
+         // To prevent confusion, no boundary numbery below this default 
+         // are permitted
+         if(bcnum < (DEFAULT_BCNUM + 1)) bcnum = DEFAULT_BCNUM+1;
+
+         bc_num.Elem(i) = bcnum;
+         bc_used.Elem(i) = false;
+         ocf >> bc_colours.Elem(i).X() 
+             >> bc_colours.Elem(i).Y() 
+             >> bc_colours.Elem(i).Z();
+
+         if(!ocf.good())
+         {
+            ocf.close();
+            throw NgException("Boundary Colour file error: Number of entries do not match specified list size!!\n");
+            return;
+         }
+
+         // Bound checking of the values
+         // The RGB values should be between 0.0 and 1.0
+         if(bc_colours.Elem(bcnum).X() < 0.0) bc_colours.Elem(bcnum).X() = 0.0;
+         if(bc_colours.Elem(bcnum).X() > 1.0) bc_colours.Elem(bcnum).X() = 1.0;
+         if(bc_colours.Elem(bcnum).Y() < 0.0) bc_colours.Elem(bcnum).X() = 0.0;
+         if(bc_colours.Elem(bcnum).Y() > 1.0) bc_colours.Elem(bcnum).X() = 1.0;
+         if(bc_colours.Elem(bcnum).Z() < 0.0) bc_colours.Elem(bcnum).X() = 0.0;
+         if(bc_colours.Elem(bcnum).Z() > 1.0) bc_colours.Elem(bcnum).X() = 1.0;
+      }
+
+      PrintMessage(3, "Successfully loaded Boundary Colour Profile file....");
+      ocf.close();
+
+      // Find the highest boundary condition number in the list
+      // All colours in the geometry which are not specified in the 
+      // list will be given boundary condition numbers higher than this 
+      // number
+      int max_bcnum = DEFAULT_BCNUM;
+      for(int i = 1; i <= bc_num.Size();i++)
+      {
+         if(bc_num.Elem(i) > max_bcnum) max_bcnum = bc_num.Elem(i);
+      }
+
+      PrintMessage(3, "Highest boundary number in list = ",max_bcnum);
+
+      Array<Vec3d> all_colours;
+      
+      // Extract all the colours to see how many there are
+      GetFaceColours(mesh,all_colours);
+      PrintMessage(3,"\nNumber of colours defined in Mesh: ", all_colours.Size());
+
+      if(all_colours.Size() == 0)
+      {
+         PrintMessage(3,"No colour data detected in Mesh... no changes made!");
+         return;
+      }
+
+      int nfd = mesh.GetNFD();
+
+      for(int face_index = 1; face_index <= nfd; face_index++)
+      {
+         // Temporary container for individual face colours
+         Vec3d face_colour;
+
+         // Get the colour of the face being currently processed
+         face_colour = mesh.GetFaceDescriptor(face_index).SurfColour();
+         if(!ColourMatch(face_colour,Vec3d(DEFAULT_R,DEFAULT_G,DEFAULT_B)))
+         {
+            // Boolean variable to check if the boundary condition was applied 
+            // or not... not applied would imply that the colour of the face 
+            // does not exist in the list of colours in the profile file
+            bool bc_assigned = false;
+
+            for(int col_index = 1; col_index <= bc_colours.Size(); col_index++)
+            {
+               if((ColourMatch(face_colour,bc_colours.Elem(col_index))) && (!bc_assigned))
+               {
+                  mesh.GetFaceDescriptor(face_index).SetBCProperty(bc_num.Elem(col_index));
+                  bc_used.Elem(col_index) = true;
+                  bc_assigned = true;
+                  break;
+               }
+            }
+
+            // If the colour was not found in the list, add it to the list, and assign 
+            // the next free boundary condition number to it
+            if(!bc_assigned)
+            {
+               max_bcnum++;
+               bc_num.Append(max_bcnum);
+               bc_colours.Append(face_colour);
+               bc_used.Append(true);
+
+               mesh.GetFaceDescriptor(face_index).SetBCProperty(max_bcnum);
+            }
+         }
+         else
+         {
+            // Set the boundary condition number to the default one
+            mesh.GetFaceDescriptor(face_index).SetBCProperty(DEFAULT_BCNUM);
+         }
+      }
+
+      // User Information of the results of the operation
+      Vec3d ref_colour(0.0,1.0,0.0);
+      PrintMessage(3,"Colour based Boundary Condition Property details:");
+      for(int bc_index = 0; bc_index <= bc_num.Size(); bc_index++)
+      {
+         if(bc_index > 0) ref_colour = bc_colours.Elem(bc_index);
+
+         if(bc_index == 0) 
+         {
+            PrintMessage(3, "BC Property: ",DEFAULT_BCNUM);
+            PrintMessage(3, "   RGB Face Colour = ",ref_colour,"","\n");
+         }
+         else if(bc_used.Elem(bc_index))
+         {
+            PrintMessage(3, "BC Property: ",bc_num.Elem(bc_index));
+            PrintMessage(3, "   RGB Face Colour = ",ref_colour,"","\n");
+         }
+      }
+   }
+
+
+
+
+   
+   /*! Philippose - 11/07/2009
+       Assign boundary condition numbers based on the colours 
+       assigned to each face in the mesh using an automated 
+       algorithm.
+
+       The particular algorithm used has been briefly explained 
+       in the header file "occauxfunctions.hpp"
+   */
+   void AutoColourAlg_Sorted(Mesh & mesh)
+   {
+      Array<Vec3d> all_colours;
+      Array<int> faces_sorted;
+      Array<int> colours_sorted;
+
+      // Extract all the colours to see how many there are
+      GetFaceColours(mesh,all_colours);
+
+      // Delete the default colour from the list since it will be accounted 
+      // for automatically
+      for(int i = 1; i <= all_colours.Size(); i++)
+      {
+         if(ColourMatch(all_colours.Elem(i),Vec3d(DEFAULT_R,DEFAULT_G,DEFAULT_B)))
+         {
+            all_colours.DeleteElement(i);
+            break;
+         }
+      }
+      PrintMessage(3,"\nNumber of colours defined in Mesh: ", all_colours.Size());
+
+      if(all_colours.Size() == 0)
+      {
+         PrintMessage(3,"No colour data detected in Mesh... no changes made!");
+         return;
+      }
+
+      // One more slot than the number of colours are required, to 
+      // account for individual faces which have no colour data 
+      // assigned to them in the CAD software
+      faces_sorted.SetSize(all_colours.Size()+1);
+      colours_sorted.SetSize(all_colours.Size()+1);
+      faces_sorted = 0;
+      
+      // Slave Array to identify the colours the faces were assigned to, 
+      // after the bubble sort routine to sort the automatic boundary 
+      // identifiers according to the number of surface mesh elements 
+      // of a given colour
+      for(int i = 0; i <= all_colours.Size(); i++) colours_sorted[i] = i;
+
+      // Used to hold the number of surface elements without any OCC 
+      // colour definition
+      int no_colour_faces = 0;
+
+      // Index in the faces array assigned to faces without any 
+      // or the default colour definition
+      int no_colour_index = 0;
+
+      int nfd = mesh.GetNFD();
+
+      // Extract the number of surface elements having a given colour
+      // And save this number into an array for later sorting
+      for(int face_index = 1; face_index <= nfd; face_index++)
+      {
+         Array<SurfaceElementIndex> se_face;
+
+         mesh.GetSurfaceElementsOfFace(face_index, se_face);
+
+         Vec3d face_colour;
+
+         face_colour = mesh.GetFaceDescriptor(face_index).SurfColour();
+         if(!ColourMatch(face_colour,Vec3d(DEFAULT_R,DEFAULT_G,DEFAULT_B)))
+         {
+            for(int i = 1; i <= all_colours.Size(); i++)
+            {
+               if(ColourMatch(face_colour, all_colours.Elem(i)))
+               {
+                  faces_sorted[i] = faces_sorted[i] + se_face.Size();
+               }
+            }
+         }
+         else
+         {
+            // Add the number of surface elements without any colour 
+            // definition separately
+            no_colour_faces = no_colour_faces + se_face.Size();
+         }
+      }
+
+      // Sort the face colour indices according to the number of surface 
+      // mesh elements which have a specific colour
+      BubbleSort(faces_sorted,colours_sorted);
+
+      // Now update the array position assigned for surface elements 
+      // without any colour definition with the number of elements
+      faces_sorted[no_colour_index] = no_colour_faces;
+
+      // Now actually assign the BC Property to the respective faces
+      for(int face_index = 1; face_index <= nfd; face_index++)
+      {
+         Vec3d face_colour;
+
+         face_colour = mesh.GetFaceDescriptor(face_index).SurfColour();
+         if(!ColourMatch(face_colour,Vec3d(DEFAULT_R,DEFAULT_G,DEFAULT_B)))
+         {
+            for(int i = 0; i < colours_sorted.Size(); i++)
+            {
+               Vec3d ref_colour;
+               if(i != no_colour_index) ref_colour = all_colours.Elem(colours_sorted[i]);
+
+               if(ColourMatch(face_colour, ref_colour))
+               {
+                  mesh.GetFaceDescriptor(face_index).SetBCProperty(i + DEFAULT_BCNUM);
+               }
+            }
+         }
+         else
+         {
+            mesh.GetFaceDescriptor(face_index).SetBCProperty(DEFAULT_BCNUM);
+         }
+
+         PrintMessage(4,"Face number: ",face_index," ; BC Property = ",mesh.GetFaceDescriptor(face_index).BCProperty());
+      }
+
+      // User Information of the results of the operation
+      Vec3d ref_colour(0.0,1.0,0.0);
+      PrintMessage(3,"Colour based Boundary Condition Property details:");
+      for(int i = 0; i < faces_sorted.Size(); i++)
+      {
+         if(colours_sorted[i] > 0) ref_colour = all_colours.Elem(colours_sorted[i]);
+
+         PrintMessage(3, "BC Property: ",i + DEFAULT_BCNUM);
+         PrintMessage(3, "   Nr. of Surface Elements = ", faces_sorted[i]);
+         PrintMessage(3, "   Colour Index = ", colours_sorted[i]);
+         PrintMessage(3, "   RGB Face Colour = ",ref_colour,"","\n");
+      }
+   }
+
+
+
+
+
+   /*! Philippose - 13/07/2009
+       Main function implementing automated assignment of 
+       Boundary Condition numbers based on face colours
+
+       This functionality is currently implemtented at the mesh 
+       level, and hence allows colour based assignment of boundary 
+       conditions for any geometry type within netgen which 
+       supports face colours
+   */
+   void AutoColourBcProps(Mesh & mesh, const char * bccolourfile)
+   {
+      // Go directly to the alternate algorithm if no colour profile file was specified
+      if(!bccolourfile)
+      {
+         PrintMessage(1,"AutoColourBcProps: Using Automatic Colour based boundary property assignment algorithm");
+         AutoColourAlg_Sorted(mesh);
+      }
+      else
+      {
+         ifstream ocf(bccolourfile);
+
+         // If there was an error opening the Colour profile file, jump to the alternate 
+         // algorithm after printing a message
+         if(!ocf)
+         {
+            PrintMessage(1,"AutoColourBcProps: Error loading Boundary Colour Profile file ", 
+                         bccolourfile, " ....","Switching to Automatic Assignment algorithm!");
+
+            AutoColourAlg_Sorted(mesh);
+         }
+         // If the file opens successfully, call the function which assigns boundary conditions 
+         // based on the colour profile file
+         else
+         {
+            PrintMessage(1, "AutoColourBcProps: Using Boundary Colour Profile file: ");
+            PrintMessage(1, "  ", bccolourfile);
+            AutoColourAlg_UserProfile(mesh, ocf);
+
+            // Make sure the file is closed before exiting the function
+            if(ocf.is_open())
+            {
+               ocf.close();
+            }
+         }
+      }
+   }
+}
diff --git a/contrib/Netgen/libsrc/meshing/bcfunctions.hpp b/contrib/Netgen/libsrc/meshing/bcfunctions.hpp
new file mode 100644
index 0000000000..593838afe8
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/bcfunctions.hpp
@@ -0,0 +1,53 @@
+#ifndef FILE_BCFUNCTIONS
+#define FILE_BCFUNCTIONS
+
+// Philippose - 14/03/2009
+// Auxiliary functions for OCC Geometry
+// Use this file and the corresponding ".cpp" 
+// file to add miscellaneous functionality 
+// to the OpenCascade Geometry support in Netgen
+namespace netgen
+{
+   /*! \brief Automatically assign boundary conditions for meshes
+
+       This function allows the boundary condition numbers of a 
+       mesh created in Netgen to be automatically assigned based on 
+       the colours of each face.
+
+       Currently, two algorithms are utilised to assign the BC Properties:
+       1. Automatic assignment using a user defined colour profile file 
+          which defines which RGB colours are to be assigned to which 
+          BC Property number
+          - A default profile file exists in the Netgen folder called 
+            "netgen.ocf"
+       
+       2. The second algorithm uses the following automated algorithm:
+          - Extract all the colours present in the mesh
+          - Use colour index 0 (zero) for all faces with no colour defined
+          - Calculate the number of faces of the surface mesh for each colour
+          - Sort the number of surface elements in ascending order, with the 
+            colour indices as a slave
+          - Use the indices of the sorted array as the BC property number
+
+          Example: If there are 3 colours, present in the mesh and the number 
+          of surface elements for each colour are:
+          - Colour 0: 8500
+          - Colour 1: 120
+          - Colour 2: 2200
+          - Colour 3: 575
+
+          The above is sorted in ascending order and assigned as BC Properties:
+          - BC Prop 0: 120  : Colour 1
+          - BC Prop 1: 575  : Colour 3
+          - BC Prop 2: 2200 : Colour 2
+          - BC Prop 3: 8500 : Colour 0 (no colour defined)
+   */
+   //extern void OCCAutoColourBcProps(Mesh & mesh, OCCGeometry & occgeometry, const char *occcolourfile);
+   extern void AutoColourBcProps(Mesh & mesh, const char *bccolourfile);
+
+   extern void GetFaceColours(Mesh & mesh, Array<Vec3d> & face_colours);
+
+   extern bool ColourMatch(Vec3d col1, Vec3d col2, double eps = 2.5e-05);
+}
+#endif
+
diff --git a/contrib/Netgen/libsrc/meshing/bisect.cpp b/contrib/Netgen/libsrc/meshing/bisect.cpp
new file mode 100644
index 0000000000..afa3400dac
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/bisect.cpp
@@ -0,0 +1,4071 @@
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+#define noDEBUG
+
+
+namespace netgen
+{
+  //#include "../interface/writeuser.hpp"
+  class MarkedTet;
+  class MarkedPrism;
+  class MarkedIdentification;
+  class MarkedTri;
+  class MarkedQuad;
+  
+  typedef MoveableArray<MarkedTet> T_MTETS;
+  typedef MoveableArray<MarkedPrism> T_MPRISMS;
+  typedef MoveableArray<MarkedIdentification> T_MIDS;
+  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
+    
+    char faceedges[4];
+    // unsigned char faceedges[4];
+    bool incorder;
+    unsigned int order:6;
+
+    MarkedTet()
+    { 
+      for (int i = 0; i < 4; i++) { faceedges[i] = 255; }
+    }
+  };
+
+  ostream & operator<< (ostream & ost, const MarkedTet & mt)
+  {
+    for(int i=0; i<4; i++)
+      ost << mt.pnums[i] << " ";
+
+    ost << mt.matindex << " " << int(mt.marked) << " " << int(mt.flagged) << " " << int(mt.tetedge1) << " " << int(mt.tetedge2) << " ";
+    
+    ost << "faceedges = ";
+    for(int i=0; i<4; i++)
+      ost << int(mt.faceedges[i]) << " ";
+
+    ost << " order = ";
+    ost << mt.incorder << " " << int(mt.order) << "\n";
+    return ost;
+  }
+  istream & operator>> (istream & ost, MarkedTet & mt)
+  {
+    for(int i=0; i<4; i++)
+      ost >> mt.pnums[i];
+
+    ost >> mt.matindex;
+
+    int auxint;
+    ost >> auxint;
+    mt.marked = auxint;
+    ost >> auxint;
+    mt.flagged = auxint;
+    ost >> auxint;
+    mt.tetedge1 = auxint;
+    ost >> auxint;
+    mt.tetedge2 = auxint;
+    
+    char auxchar;
+
+    for(int i=0; i<4; i++)
+      {
+	ost >> auxchar;
+	mt.faceedges[i] = auxchar;
+      }
+
+    ost >> mt.incorder;
+    ost >> auxint;
+    mt.order = auxint;
+    return ost;
+  }
+
+  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;
+  };
+
+  
+  ostream & operator<< (ostream & ost, const MarkedPrism & mp)
+  {
+    for(int i=0; i<6; i++)
+      ost << mp.pnums[i] << " ";
+
+    ost << mp.matindex << " " << mp.marked << " " << mp.markededge << " " << mp.incorder << " " << int(mp.order) << "\n";
+    return ost;
+  }
+  istream & operator>> (istream & ist, MarkedPrism & mp)
+  {
+    for(int i=0; i<6; i++)
+      ist >> mp.pnums[i];
+
+    ist >> mp.matindex >> mp.marked >> mp.markededge >> mp.incorder;
+    int auxint;
+    ist >> auxint;
+    mp.order = auxint;
+    return ist;
+  }
+
+
+  class MarkedIdentification
+  {
+  public:
+    // number of points of one face (3 or 4)
+    int np;
+    /// 6 or 8 point numbers
+    PointIndex pnums[8];
+    /// marked for refinement
+    int marked;
+    /// edge starting with node k (0,1,2, or 3)
+    int markededge;
+
+    bool incorder;
+    unsigned int order:6;
+  };
+    
+  
+  ostream & operator<< (ostream & ost, const MarkedIdentification & mi)
+  {
+    ost << mi.np << " ";
+    for(int i=0; i<2*mi.np; i++)
+      ost << mi.pnums[i] << " ";
+    ost << mi.marked << " " << mi.markededge << " " << mi.incorder << " " << int(mi.order) << "\n";
+    return ost;
+  }
+  istream & operator>> (istream & ist, MarkedIdentification & mi)
+  {
+    ist >> mi.np;
+    for(int i=0; i<2*mi.np; i++)
+      ist >> mi.pnums[i];
+    ist >> mi.marked >> mi.markededge >> mi.incorder;
+    int auxint;
+    ist >> auxint;
+    mi.order = auxint;
+    return ist;
+  }
+  
+
+
+
+
+  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;
+  };
+  
+  ostream & operator<< (ostream & ost, const MarkedTri & mt)
+  {
+    for(int i=0; i<3; i++)
+      ost << mt.pnums[i] << " ";
+    for(int i=0; i<3; i++)
+      ost << mt.pgeominfo[i] << " ";
+    ost << mt.marked << " " << mt.markededge << " " << mt.surfid << " " << mt.incorder << " " << int(mt.order) << "\n";
+    return ost;
+  } 
+  istream & operator>> (istream & ist, MarkedTri & mt)
+  {
+    for(int i=0; i<3; i++)
+      ist >> mt.pnums[i];
+    for(int i=0; i<3; i++)
+      ist >> mt.pgeominfo[i];
+    ist >> mt.marked >> mt.markededge >> mt.surfid >> mt.incorder;
+    int auxint;
+    ist >> auxint;
+    mt.order = auxint;
+    return ist;
+  }
+    
+
+
+  class MarkedQuad
+  {
+  public:
+    /// point numbers
+    PointIndex pnums[4];
+    ///
+    PointGeomInfo pgeominfo[4];
+    /// marked for refinement
+    int marked;
+    /// marked edge: 0/2 = vertical, 1/3 = horizontal
+    int markededge;
+    /// surface id
+    int surfid;
+
+    bool incorder;
+    unsigned int order:6;
+  };
+
+  ostream & operator<< (ostream & ost, const MarkedQuad & mt)
+  {
+    for(int i=0; i<4; i++)
+      ost << mt.pnums[i] << " ";
+    for(int i=0; i<4; i++)
+      ost << mt.pgeominfo[i] << " ";
+    ost << mt.marked << " " << mt.markededge << " " << mt.surfid << " " << mt.incorder << " " << int(mt.order) << "\n";
+    return ost;
+  } 
+  istream & operator>> (istream & ist, MarkedQuad & mt)
+  {
+    for(int i=0; i<4; i++)
+      ist >> mt.pnums[i];
+    for(int i=0; i<4; i++)
+      ist >> mt.pgeominfo[i];
+    ist >> mt.marked >> mt.markededge >> mt.surfid >> mt.incorder;
+    int auxint;
+    ist >> auxint;
+    mt.order = auxint;
+    return ist;
+  }
+
+
+
+
+  void PrettyPrint(ostream & ost, const MarkedTet & mt)
+  {
+    int te1 = mt.tetedge1;
+    int te2 = mt.tetedge2;
+    int order = mt.order;
+
+    ost << "MT: " << mt.pnums[0] << " - " << mt.pnums[1] << " - " 
+	<< mt.pnums[2] << " - " << mt.pnums[3] << endl
+	<< "marked edge: " << te1 << " - " << te2
+	<< ", order = " << order << endl;
+    //for (int k = 0; k < 4; k++)
+    //  ost << int(mt.faceedges[k]) << "  ";
+    for (int k = 0; k < 4; k++)
+      {
+	ost << "face";
+	for (int j=0; j<4; j++)
+	  if(j != k)
+	    ost << " " << mt.pnums[j];
+	for(int i=0; i<3; i++)
+	  for(int j=i+1; j<4; j++)
+	    if(i != k && j != k && int(mt.faceedges[k]) == 6-k-i-j)
+	      ost << " marked edge " << mt.pnums[i] << " " << mt.pnums[j] << endl;
+      }
+    ost << endl;
+  }
+
+
+
+
+  int BTSortEdges (const Mesh & mesh,
+		   const Array< Array<int,PointIndex::BASE>* > & idmaps,
+		   INDEX_2_CLOSED_HASHTABLE<int> & edgenumber)
+  {
+    PrintMessage(4,"sorting ... ");
+
+    //  if (mesh.PureTetMesh())
+    if (1)
+      {
+	// new, fast version
+      
+	Array<INDEX_2> edges;
+	Array<int> eclasses;
+      
+	int i, j, k;
+	int cntedges = 0;
+	int go_on;
+	int ned(0);
+      
+	// 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] = NULL;
+	  
+	    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;
+		}
+              default:
+                throw NgException("Bisect, element type not handled in switch");
+	      }
+	      
+	    for (j = 0; j < ned; j++)
+	      {
+		INDEX_2 i2(el.PNum(tip[j][0]), el.PNum(tip[j][1]));
+		i2.Sort();
+		//(*testout) << "edge " << i2 << endl;
+		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] = NULL;
+	  
+	    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
+	  {
+	    go_on = 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] = NULL;
+		switch (el.GetType())
+		  {
+		  case PRISM:
+		  case PRISM12:
+		    {
+		      pairs = prismpairs;
+		      break;
+		    }
+		  case PYRAMID:
+		    {
+		      pairs = pyramidpairs;
+		      break;
+		    }
+                  default:
+                    throw NgException("Bisect, element type not handled in switch, 2");
+		  }
+
+		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);
+			go_on = 1;
+		      }
+		    else if (eclasses.Get(eclass2) >
+			     eclasses.Get(eclass1))
+		      {
+			eclasses.Elem(eclass2) = 
+			  eclasses.Get(eclass1);
+			go_on = 1;
+		      }
+		  }
+	      }
+
+	    for(SurfaceElementIndex sei = 0; sei < mesh.GetNSE(); sei++)
+	      {
+		const Element2d & el2d = mesh[sei];
+
+		for(i = 0; i < el2d.GetNP(); i++)
+		  {
+		    INDEX_2 e1(el2d[i], el2d[(i+1) % el2d.GetNP()]);
+		    e1.Sort();
+		    INDEX_2 e2;
+		    
+		    for(k = 0; k < idmaps.Size(); k++)
+		      {
+			e2.I1() = (*idmaps[k])[e1.I1()];
+			e2.I2() = (*idmaps[k])[e1.I2()];
+			
+			if(e2.I1() == 0 || e2.I2() == 0 ||
+			   e1.I1() == e2.I1() || e1.I2() == e2.I2())
+			  continue;
+			
+			e2.Sort();
+			if(!edgenumber.Used(e2))
+			  continue;
+			
+
+			int eclass1 = edgenumber.Get (e1);
+			int eclass2 = edgenumber.Get (e2);
+			
+			if (eclasses.Get(eclass1) >
+			    eclasses.Get(eclass2))
+			  {
+			    eclasses.Elem(eclass1) = 
+			      eclasses.Get(eclass2);
+
+
+			    go_on = 1;
+			  }
+			else if (eclasses.Get(eclass2) >
+				 eclasses.Get(eclass1))
+			  {
+			    eclasses.Elem(eclass2) = 
+			      eclasses.Get(eclass1);
+			    go_on = 1;
+			  }
+		      }		      
+		  }
+		
+	      }
+
+	  }
+	while (go_on);
+
+// 	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);
+      
+	QuickSort (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); 
+	      }
+	  }
+	return cnt;
+      }
+
+    else
+    
+      {
+	// old version
+      
+	int i, j;
+	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;
+		    }
+                  default:
+                    throw NgException("Bisect, element type not handled in switch, 3");
+		  }
+	      
+		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 go_on = 0;
+		do
+		  {
+		    go_on = 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;
+			    }
+                          default:
+                            throw NgException("Bisect, element type not handled in switch, 3a");
+			  }
+
+			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);
+				go_on = 1;
+			      }
+			    if (used2 && !used1)
+			      {
+				cnt++;
+				edgenumber.Set (e1, cnt);
+				go_on = 1;
+			      }
+			  }
+		      }
+		  }
+		while (go_on);
+	      }
+	  }
+	while (found);
+
+	return cnt;
+      }
+  }
+
+
+
+
+  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;
+                    int hi = 6 - k - i - j;
+                    mt.faceedges[k] = char(hi);
+		  }
+	      }
+      }
+  }
+
+
+
+
+  void BTDefineMarkedPrism (const Element & el,
+			    INDEX_2_CLOSED_HASHTABLE<int> & edgenumber,
+			    MarkedPrism & mp)
+  {
+    int i, j;
+
+    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;
+	    }
+	}
+  }
+
+
+
+  bool BTDefineMarkedId(const Element2d & el, 
+			INDEX_2_CLOSED_HASHTABLE<int> & edgenumber, 
+			const Array<int,PointIndex::BASE> & idmap,
+			MarkedIdentification & mi)
+  {
+
+    bool identified = true;
+    mi.np = el.GetNP();
+    int min1(0),min2(0);
+    for(int j = 0; identified && j < mi.np; j++)
+      {
+	mi.pnums[j] = el[j];
+	mi.pnums[j+mi.np] = idmap[el[j]];
+
+	if(j == 0 || el[j] < min1)
+	  min1 = el[j];
+	if(j == 0 || mi.pnums[j+mi.np] < min2)
+	  min2 = mi.pnums[j+mi.np];
+
+	identified = (mi.pnums[j+mi.np] != 0 && mi.pnums[j+mi.np] != mi.pnums[j]);
+      }
+
+    identified = identified && (min1 < min2);
+
+    if(identified)
+      {
+	mi.marked = 0;
+	
+	mi.incorder = 0;
+	mi.order = 1;
+
+	int val = 0;
+	for (int i = 0; i < mi.np; i++)
+	  {
+	    INDEX_2 i2(mi.pnums[i], mi.pnums[(i+1)%mi.np]);
+	    i2.Sort();
+	    int hval = edgenumber.Get(i2);
+	    if (hval > val)
+	      {
+		val = hval;
+		mi.markededge = i;
+	      }
+	  }
+      }
+
+    return identified;
+  }
+
+
+  void BTDefineMarkedTri (const Element2d & el,
+			  INDEX_2_CLOSED_HASHTABLE<int> & edgenumber,
+			  MarkedTri & mt)
+  {
+    int i, j;
+    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 PrettyPrint(ostream & ost, const MarkedTri & mt)
+  {
+    ost << "MarkedTrig: " << endl;
+    ost << "  pnums = "; for (int i=0; i<3; i++) ost << mt.pnums[i] << " "; ost << endl; 
+    ost << "  marked = " << mt.marked << ", markededge=" << mt.markededge << endl;
+    for(int i=0; i<2; i++)
+      for(int j=i+1; j<3; j++)
+	if(mt.markededge == 3-i-j)
+	  ost << "  marked edge pnums = " << mt.pnums[i] << " " << mt.pnums[j] << endl;
+  }
+
+
+  void PrettyPrint(ostream & ost, const MarkedQuad & mq)
+  {
+    ost << "MarkedQuad: " << endl;
+    ost << "  pnums = "; for (int i=0; i<4; i++) ost << mq.pnums[i] << " "; ost << endl; 
+    ost << "  marked = " << mq.marked << ", markededge=" << mq.markededge << endl;
+  }
+
+
+
+
+
+  void BTDefineMarkedQuad (const Element2d & el,
+			   INDEX_2_CLOSED_HASHTABLE<int> & edgenumber,
+			   MarkedQuad & mq)
+  {
+    int i;
+    for (i = 0; i < 4; i++)
+      mq.pnums[i] = el[i];
+    Swap (mq.pnums[2], mq.pnums[3]);  
+
+    mq.marked = 0;
+    mq.markededge = 0;
+    mq.surfid = el.GetIndex();
+  }
+
+
+
+
+  // mark elements due to local h
+  int BTMarkTets (T_MTETS & mtets,
+		  T_MPRISMS & mprisms,
+		  const Mesh & mesh)
+  {
+    int marked = 0;
+
+    int np = mesh.GetNP();
+    Vector hv(np);
+    for (int i = 0; i < np; i++)
+      hv(i) = mesh.GetH (mesh.Point(i+1));
+
+    double hfac = 1;
+  
+    for (int step = 1; step <= 2; step++)
+      {
+	for (int i = 1; i <= mtets.Size(); i++)
+	  {
+	    double h = 0;
+	  
+	    for (int j = 0; j < 3; j++)
+	      for (int k = j+1; k < 4; k++)
+		{
+		  const Point<3> & p1 = mesh.Point (mtets.Get(i).pnums[j]);
+		  const Point<3> & 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 (int j = 0; j < 4; j++)
+	      {
+		double hi = hv (mtets.Get(i).pnums[j]-1);
+		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 (int i = 1; i <= mprisms.Size(); i++)
+	  {
+	    double h = 0;
+	  
+	    for (int j = 0; j < 2; j++)
+	      for (int k = j+1; k < 3; k++)
+		{
+		  const Point<3> & p1 = mesh.Point (mprisms.Get(i).pnums[j]);
+		  const Point<3> & 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 (int j = 0; j < 6; j++)
+	      {
+		double hi = hv (mprisms.Get(i).pnums[j]-1);
+		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)
+  {
+#ifdef DEBUG
+    *testout << "bisect tet " << oldtet << endl;
+#endif    
+    
+    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;
+
+#ifdef DEBUG
+    *testout << "newtet1,before = " << newtet1 << endl;
+    *testout << "newtet2,before = " << newtet2 << endl;
+#endif
+
+    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)
+              {
+                int hi = 6 - oldtet.tetedge1 - j - k;
+                newtet2.faceedges[oldtet.tetedge2] = char(hi);
+              }
+	    else
+	      newtet2.faceedges[oldtet.tetedge2] = oldtet.tetedge1;
+            
+#ifdef DEBUG
+            *testout << "i = " << i << ", j = " << j << " k = " << k 
+                     << " oldtet.tetedge1 = " << oldtet.tetedge1 
+                     << " oldtet.tetedge2 = " << oldtet.tetedge2
+                     << "   6-oldtet.tetedge1-j-k = " <<  6 - oldtet.tetedge1 - j - k 
+                     << "   6-oldtet.tetedge1-j-k = " <<  short(6 - oldtet.tetedge1 - j - k)
+                     << endl;
+            *testout << "vis1 = " << vis1 << ", vis2 = " << vis2 << endl;
+            for (int j = 0; j < 4; j++)
+              if (newtet2.faceedges[j] > 3)
+                {
+                  *testout << "ERROR1" << endl;
+                }
+#endif
+	  }
+
+	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)
+              {
+                int hi = 6 - oldtet.tetedge2 - j - k;
+                newtet1.faceedges[oldtet.tetedge1] = char(hi);
+              }
+	    else
+	      newtet1.faceedges[oldtet.tetedge1] = oldtet.tetedge2;
+
+#ifdef DEBUG
+            for (int j = 0; j < 4; j++)
+              if (newtet2.faceedges[j] > 3)
+                {
+                  *testout << "ERROR2" << endl;
+                }
+#endif
+	  }
+      }
+
+    newtet1.matindex = oldtet.matindex;
+    newtet2.matindex = oldtet.matindex;
+    newtet1.incorder = 0;
+    newtet1.order = oldtet.order;
+    newtet2.incorder = 0;
+    newtet2.order = oldtet.order;
+
+    *testout << "newtet1 =  " << newtet1 << endl;
+    *testout << "newtet2 =  " << newtet2 << endl;
+  }
+
+
+  
+
+  void BTBisectPrism (const MarkedPrism & oldprism, int newp1, int newp2,
+		      MarkedPrism & newprism1, MarkedPrism & newprism2)
+  {
+    int i;
+
+    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 BTBisectIdentification (const MarkedIdentification & oldid,
+			       Array<int> & newp,
+			       MarkedIdentification & newid1,
+			       MarkedIdentification & newid2)
+  {
+    for(int i=0; i<2*oldid.np; i++)
+      {
+	newid1.pnums[i] = oldid.pnums[i];
+	newid2.pnums[i] = oldid.pnums[i];
+      }
+    newid1.np = newid2.np = oldid.np;
+
+    if(oldid.np == 3)
+      {
+	newid1.pnums[(oldid.markededge+1)%3] = newp[0];
+	newid1.pnums[(oldid.markededge+1)%3+3] = newp[1];
+	newid1.markededge = (oldid.markededge+2)%3;
+
+	newid2.pnums[oldid.markededge] = newp[0];
+	newid2.pnums[oldid.markededge+3] = newp[1];
+	newid2.markededge = (oldid.markededge+1)%3;
+      }
+    else if(oldid.np == 4)
+      {
+	newid1.pnums[(oldid.markededge+1)%4] = newp[0];
+	newid1.pnums[(oldid.markededge+2)%4] = newp[2];
+	newid1.pnums[(oldid.markededge+1)%4+4] = newp[1];
+	newid1.pnums[(oldid.markededge+2)%4+4] = newp[3];
+	newid1.markededge = (oldid.markededge+3)%4;
+
+	newid2.pnums[oldid.markededge] = newp[0];
+	newid2.pnums[(oldid.markededge+3)%4] = newp[2];
+	newid2.pnums[oldid.markededge+4] = newp[1];
+	newid2.pnums[(oldid.markededge+3)%4+4] = newp[3];
+	newid2.markededge = (oldid.markededge+1)%4;
+      }
+
+    
+    int nm = oldid.marked - 1;
+    if (nm < 0) nm = 0;
+    newid1.marked = newid2.marked = nm;
+
+    newid1.incorder = newid2.incorder = 0;
+    newid1.order = newid2.order = oldid.order;
+  }
+
+
+
+  void BTBisectTri (const MarkedTri & oldtri, int newp, const PointGeomInfo & newpgi,
+		    MarkedTri & newtri1, MarkedTri & newtri2)
+  {
+    int i;
+
+    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;
+
+    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];
+      }  
+
+/*    if (oldquad.marked==1) // he/sz: 2d quads or 3d prism
+    {   
+      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;
+    }
+      
+    else if (oldquad.marked==2) // he/sz: 2d quads only
+    {
+      newquad1.pnums[0] = newp1;
+      newquad1.pnums[1] = newp2;
+      newquad1.pnums[3] = oldquad.pnums[2];  
+      newquad1.pnums[2] = oldquad.pnums[0]; 
+      newquad1.pgeominfo[0] = npgi1;
+      newquad1.pgeominfo[1] = npgi2;
+      newquad1.pgeominfo[3] = oldquad.pgeominfo[2]; 
+      newquad1.pgeominfo[2] = oldquad.pgeominfo[0];
+
+      newquad2.pnums[0] = newp2;
+      newquad2.pnums[1] = newp1;
+      newquad2.pnums[3] = oldquad.pnums[1];  
+      newquad2.pnums[2] = oldquad.pnums[3]; 
+      newquad2.pgeominfo[0] = npgi2;
+      newquad2.pgeominfo[1] = npgi1;
+      newquad2.pgeominfo[3] = oldquad.pgeominfo[1]; 
+      newquad2.pgeominfo[2] = oldquad.pgeominfo[3];
+    }
+      
+    */
+      
+    if (oldquad.markededge==0 || oldquad.markededge==2)
+    {
+      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;
+    }
+    else // 1 || 3 
+    {
+      newquad1.pnums[2] = newp1;
+      newquad1.pgeominfo[2] = npgi1;
+      newquad1.pnums[3] = newp2;
+      newquad1.pgeominfo[3] = npgi2;
+
+      newquad2.pnums[0] = newp1;
+      newquad2.pgeominfo[0] = npgi1;
+      newquad2.pnums[1] = newp2;
+      newquad2.pgeominfo[1] = 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;
+    
+    if (nm==1)
+    {
+      newquad1.markededge=1;
+      newquad2.markededge=1;
+    }
+    else
+    {
+      newquad1.markededge=0;
+      newquad2.markededge=0;
+    }
+    
+  }
+
+
+  int MarkHangingIdentifications(T_MIDS & mids, 
+				 const INDEX_2_CLOSED_HASHTABLE<int> & cutedges)
+  {
+    int i, j;
+    
+    int hanging = 0;
+    for (i = 1; i <= mids.Size(); i++)
+      {
+	if (mids.Elem(i).marked)
+	  {
+	    hanging = 1;
+	    continue;
+	  }
+
+	const int np = mids.Get(i).np;
+
+	for(j = 0; j < np; j++)
+	  {
+	    INDEX_2 edge1(mids.Get(i).pnums[j],
+			  mids.Get(i).pnums[(j+1) % np]);
+	    INDEX_2 edge2(mids.Get(i).pnums[j+np],
+			  mids.Get(i).pnums[((j+1) % np) + np]);
+
+	    edge1.Sort();
+	    edge2.Sort();
+	    if (cutedges.Used (edge1) ||
+		cutedges.Used (edge2))
+	      {
+		mids.Elem(i).marked = 1;
+		hanging = 1;
+	      }
+	  }
+      }
+
+    return hanging;
+  }
+
+
+  /*
+  void IdentifyCutEdges(Mesh & mesh,
+			INDEX_2_CLOSED_HASHTABLE<int> & cutedges)
+  {
+    int i,j,k;
+
+    Array< Array<int,PointIndex::BASE>* > idmaps;
+    for(i=1; i<=mesh.GetIdentifications().GetMaxNr(); i++)
+      {
+	idmaps.Append(new Array<int,PointIndex::BASE>);
+	mesh.GetIdentifications().GetMap(i,*idmaps.Last());
+      }
+
+
+    
+    for(SurfaceElementIndex sei = 0; sei < mesh.GetNSE(); sei++)
+      {
+	const Element2d & el2d = mesh[sei];
+	
+	for(i = 0; i < el2d.GetNP(); i++)
+	  {
+	    INDEX_2 e1(el2d[i], el2d[(i+1) % el2d.GetNP()]);
+	    e1.Sort();
+
+	    if(!cutedges.Used(e1))
+	      continue;
+
+	    
+	    for(k = 0; k < idmaps.Size(); k++)
+	      {
+		INDEX_2 e2((*idmaps[k])[e1.I1()],
+			   (*idmaps[k])[e1.I2()]);
+		
+		if(e2.I1() == 0 || e2.I2() == 0 ||
+		   e1.I1() == e2.I1() || e1.I2() == e2.I2())
+		  continue;
+		
+		e2.Sort();
+
+		if(cutedges.Used(e2))
+		  continue;
+
+		Point3d np = Center(mesh.Point(e2.I1()),
+				    mesh.Point(e2.I2()));
+		int newp = mesh.AddPoint(np);
+		cutedges.Set(e2,newp);
+		(*testout) << "DAAA" << endl;
+	      }
+	  }
+      }
+
+    
+    for(i=0; i<idmaps.Size(); i++)
+      delete idmaps[i];
+    idmaps.DeleteAll();
+  }
+  */
+
+
+  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;
+            mquads.Elem(i).markededge = 0;
+	    hanging = 1;
+            continue;
+	  }
+          
+        // he/sz: second case: split horizontally
+        INDEX_2 edge3(mquads.Get(i).pnums[1],
+                      mquads.Get(i).pnums[3]);
+        INDEX_2 edge4(mquads.Get(i).pnums[2],
+                      mquads.Get(i).pnums[0]);
+
+        edge3.Sort();
+        edge4.Sort();
+        if (cutedges.Used (edge3) ||
+            cutedges.Used (edge4))
+        {
+          mquads.Elem(i).marked = 1;
+          mquads.Elem(i).markededge = 1;
+          hanging = 1; 
+          continue; 
+        }
+    
+      }
+    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_MIDS mids;
+  T_MTRIS mtris;
+  T_MQUADS mquads;
+
+
+  void WriteMarkedElements(ostream & ost)
+  {
+    ost << "Marked Elements\n";
+
+    ost << mtets.Size() << "\n";
+    for(int i=0; i<mtets.Size(); i++)
+      ost << mtets[i];
+
+    ost << mprisms.Size() << "\n";
+    for(int i=0; i<mprisms.Size(); i++)
+      ost << mprisms[i];
+
+    ost << mids.Size() << "\n";
+    for(int i=0; i<mids.Size(); i++)
+      ost << mids[i];
+
+    ost << mtris.Size() << "\n";
+    for(int i=0; i<mtris.Size(); i++)
+      ost << mtris[i];
+
+    ost << mquads.Size() << "\n";
+    for(int i=0; i<mquads.Size(); i++)
+      ost << mquads[i];
+    ost << endl;
+  }
+
+  bool ReadMarkedElements(istream & ist, const Mesh & mesh)
+  {
+    string auxstring("");
+    if(ist)
+      ist >> auxstring;
+
+    if(auxstring != "Marked")
+      return false;
+
+    if(ist)
+      ist >> auxstring;
+
+    if(auxstring != "Elements")
+      return false;
+
+    int size;
+
+    ist >> size;
+    mtets.SetSize(size);
+    for(int i=0; i<size; i++)
+      {
+        ist >> mtets[i];
+        if(mtets[i].pnums[0] > mesh.GetNV() || 
+           mtets[i].pnums[1] > mesh.GetNV() || 
+           mtets[i].pnums[2] > mesh.GetNV() || 
+           mtets[i].pnums[3] > mesh.GetNV())
+          return false;
+      }
+
+    ist >> size;
+    mprisms.SetSize(size);
+    for(int i=0; i<size; i++)
+      ist >> mprisms[i];
+
+    ist >> size;
+    mids.SetSize(size);
+    for(int i=0; i<size; i++)
+      ist >> mids[i];
+
+    ist >> size;
+    mtris.SetSize(size);
+    for(int i=0; i<size; i++)
+      ist >> mtris[i];
+
+    ist >> size;
+    mquads.SetSize(size);
+    for(int i=0; i<size; i++)
+      ist >> mquads[i];
+
+    return true;
+  }
+
+
+
+
+
+  void BisectTetsCopyMesh (Mesh & mesh, const class CSGeometry *,
+			   BisectionOptions & opt,
+			   const Array< Array<int,PointIndex::BASE>* > & idmaps,
+			   const string & refinfofile)
+  {
+    mtets.SetName ("bisection, tets");
+    mprisms.SetName ("bisection, prisms");
+    mtris.SetName ("bisection, trigs");
+    mquads.SetName ("bisection, quads");
+    mids.SetName ("bisection, identifications");
+
+    //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;
+    */
+
+    bool readok = false;
+
+    if(refinfofile != "")
+      {
+	PrintMessage(3,"Reading marked-element information from \"",refinfofile,"\"");
+	ifstream ist(refinfofile.c_str());
+
+	readok = ReadMarkedElements(ist,mesh);
+
+	ist.close();
+      }
+
+    if(!readok)
+      {
+	PrintMessage(3,"resetting marked-element information");
+	mtets.SetSize(0);
+	mprisms.SetSize(0);
+	mids.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, idmaps, 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;
+		}
+              default:
+                throw NgException("Bisect, element type not handled in switch, 4");
+	      }
+	  }
+	
+	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);
+	      }
+	    
+	    MarkedIdentification mi;
+	    for(j=0; j<idmaps.Size(); j++)
+	      if(BTDefineMarkedId(el, edgenumber, *idmaps[j], mi))
+		mids.Append(mi);
+	  }
+      }
+	
+
+
+
+    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;
+  
+    if (printmessage_importance>0)
+    {
+      ostringstream str1,str2;
+      str1 << "copied " << mtets.Size() << " tets, " << mprisms.Size() << " prisms";
+      str2 << "       " << mtris.Size() << " trigs, " << mquads.Size() << " quads";
+
+      PrintMessage(4,str1.str());
+      PrintMessage(4,str2.str());
+    }
+  }
+
+
+  /*
+  void UpdateEdgeMarks2(Mesh & mesh,
+			const Array< Array<int,PointIndex::BASE>* > & idmaps)
+  {
+    Array< Array<MarkedTet>*,PointIndex::BASE > mtets_old(mesh.GetNP());
+    Array< Array<MarkedPrism>*,PointIndex::BASE > mprisms_old(mesh.GetNP());
+    Array< Array<MarkedIdentification>*,PointIndex::BASE > mids_old(mesh.GetNP());
+    Array< Array<MarkedTri>*,PointIndex::BASE > mtris_old(mesh.GetNP());
+    Array< Array<MarkedQuad>*,PointIndex::BASE > mquads_old(mesh.GetNP());
+
+    for(int i=PointIndex::BASE; i<mesh.GetNP()+PointIndex::BASE; i++)
+      mtets_old[i] = new Array<MarkedTet>;
+    for(int i=PointIndex::BASE; i<mesh.GetNP()+PointIndex::BASE; i++)
+      mprisms_old[i] = new Array<MarkedPrism>;
+    for(int i=PointIndex::BASE; i<mesh.GetNP()+PointIndex::BASE; i++)
+      mids_old[i] = new Array<MarkedIdentification>;
+    for(int i=PointIndex::BASE; i<mesh.GetNP()+PointIndex::BASE; i++)
+      mtris_old[i] = new Array<MarkedTri>;
+    for(int i=PointIndex::BASE; i<mesh.GetNP()+PointIndex::BASE; i++)
+      mquads_old[i] = new Array<MarkedQuad>;
+
+    for(int i=0; i<mtets.Size(); i++)
+      mtets_old[mtets[i].pnums[0]]->Append(mtets[i]);
+    for(int i=0; i<mprisms.Size(); i++)
+      mprisms_old[mprisms[i].pnums[0]]->Append(mprisms[i]);
+    for(int i=0; i<mids.Size(); i++)
+      mids_old[mids[i].pnums[0]]->Append(mids[i]);
+    for(int i=0; i<mtris.Size(); i++)
+      {
+	(*testout) << "i " << i << endl;
+	(*testout) << "mtris[i] " << mtris[i].pnums[0] << " " << mtris[i].pnums[1] << " " << mtris[i].pnums[2] << endl; 
+	mtris_old[mtris[i].pnums[0]]->Append(mtris[i]);
+      }
+    for(int i=0; i<mquads.Size(); i++)
+      mquads_old[mquads[i].pnums[0]]->Append(mquads[i]);
+
+   
+    
+    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);
+    mids.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, idmaps, 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;
+		  
+		  int oldind = -1;
+		  for(l = 0; oldind < 0 && l<mtets_old[el[0]]->Size(); l++)
+		    if(el[1] == (*mtets_old[el[0]])[l].pnums[1] &&
+		       el[2] == (*mtets_old[el[0]])[l].pnums[2] &&
+		       el[3] == (*mtets_old[el[0]])[l].pnums[3])
+		      oldind = l;
+
+		  if(oldind >= 0)
+		    mtets.Append((*mtets_old[el[0]])[oldind]);
+		  else
+		    {
+		      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);
+	  }
+	
+	MarkedIdentification mi;
+
+	
+
+	for(j=0; j<idmaps.Size(); j++)
+	  if(BTDefineMarkedId(el, edgenumber, *idmaps[j], mi))
+	    {
+	      mids.Append(mi);
+		
+	      int oldind = -1;
+	      for(l = 0; oldind < 0 && l<mids_old[mi.pnums[0]]->Size(); l++)
+		{
+		  bool equal = true;
+		  for(int m = 1; equal && m < mi.np; m++)
+		    equal = (mi.pnums[m] == (*mids_old[el[0]])[l].pnums[m]);
+		  if(equal)
+		    oldind = l;
+		}
+
+	      if(oldind >= 0)
+		mids.Last() = (*mids_old[mi.pnums[0]])[oldind];
+	    }
+
+      }
+
+
+
+    for(int i=PointIndex::BASE; i<mesh.GetNP()+PointIndex::BASE; i++)
+      delete mtets_old[i];
+    for(int i=PointIndex::BASE; i<mesh.GetNP()+PointIndex::BASE; i++)
+      delete mprisms_old[i];
+    for(int i=PointIndex::BASE; i<mesh.GetNP()+PointIndex::BASE; i++)
+      delete mids_old[i];
+    for(int i=PointIndex::BASE; i<mesh.GetNP()+PointIndex::BASE; i++)
+      delete mtris_old[i];
+    for(int i=PointIndex::BASE; i<mesh.GetNP()+PointIndex::BASE; i++)
+      delete mquads_old[i];
+  }
+*/
+
+  
+  void UpdateEdgeMarks (Mesh & mesh,
+			const Array< Array<int,PointIndex::BASE>* > & idmaps)
+  //const Array < Array<Element>* > & elements_before,
+  //const Array < Array<int>* > & markedelts_num,
+  //		const Array < Array<Element2d>* > & surfelements_before,
+  //		const Array < Array<int>* > & markedsurfelts_num)
+  {
+    T_MTETS mtets_old; mtets_old.Copy(mtets);
+    T_MPRISMS mprisms_old; mprisms_old.Copy(mprisms);
+    T_MIDS mids_old; mids_old.Copy(mids);
+    T_MTRIS mtris_old; mtris_old.Copy(mtris);
+    T_MQUADS mquads_old; mquads_old.Copy(mquads);
+
+
+
+    
+    mtets.SetSize(0);
+    mprisms.SetSize(0);
+    mids.SetSize(0);
+    mtris.SetSize(0);
+    mquads.SetSize(0);
+
+    //int nv = mesh.GetNV();
+
+
+    INDEX_2_CLOSED_HASHTABLE<int> edgenumber(9*mesh.GetNE()+4*mesh.GetNSE());  
+    
+    int maxnum = BTSortEdges (mesh, idmaps, edgenumber);
+
+    for(int m = 0; m < mtets_old.Size(); m++)
+      {
+	MarkedTet & mt = mtets_old[m];
+
+	//(*testout) << "old mt " << mt;
+	
+	INDEX_2 edge (mt.pnums[mt.tetedge1],mt.pnums[mt.tetedge2]);
+	edge.Sort();
+	if(edgenumber.Used(edge))
+	  {
+	    int val = edgenumber.Get(edge);
+	    //(*testout) << "set voledge " << edge << " from " << val;
+	    if(val <= maxnum)
+	      {
+		val += 2*maxnum;
+		edgenumber.Set(edge,val);
+	      }
+	    else if(val <= 2*maxnum)
+	      {
+		val += maxnum;
+		edgenumber.Set(edge,val);
+	      }
+	    //(*testout) << " to " << val << endl;
+	  }
+	
+	for(int k=0; k<4; k++)
+	  for(int i=0; i<3; i++)
+	    for(int j=i+1; i != k && j<4; j++)
+	      if(j != k && int(mt.faceedges[k]) == 6-k-i-j)
+		{
+		  edge[0] = mt.pnums[i];
+		  edge[1] = mt.pnums[j];
+		  edge.Sort();
+		  if(edgenumber.Used(edge))
+		    {
+		      int val = edgenumber.Get(edge);
+		      //(*testout) << "set faceedge " << edge << " from " << val;
+		      if(val <= maxnum)
+			{
+			  val += maxnum;
+			  edgenumber.Set(edge,val);
+			}
+		      //(*testout) << " to " << val << endl;
+		    }		      
+		}
+      }
+
+	
+    
+    
+    for(ElementIndex ei = 0; ei < mesh.GetNE(); ei++)
+      {
+	const Element & el = mesh[ei];
+	
+	//int pos = elements_before[el[0]]->Pos(el);
+	//int elnum = (pos >= 0) ? (*markedelts_num[el[0]])[pos] : -1;
+	 
+	switch (el.GetType())
+	  {
+	  case TET:
+	  case TET10:
+	    {
+	      //if(elnum >= 0)
+	      // {
+	      //   mtets.Append(mtets_old[elnum]);
+	      // } 
+	      //else
+	      // {
+	      MarkedTet mt;
+	      BTDefineMarkedTet (el, edgenumber, mt);
+	      mt.matindex = el.GetIndex();
+	      
+	      mtets.Append (mt);
+	    
+	      //(*testout) << "mtet " << mtets.Last() << endl;
+	      break;
+	    }
+	  case PYRAMID:
+	    {
+	      cerr << "Refinement :: UpdateEdgeMarks not yet implemented for pyramids"
+		   << endl;
+	      break;
+	    }
+	    
+	  case PRISM:
+	  case PRISM12:
+	    {
+	      cerr << "Refinement :: UpdateEdgeMarks not yet implemented for prisms"
+		   << endl;
+	      break;
+	    }
+          default:
+            throw NgException("Bisect, element type not handled in switch, 6");
+	  }
+	
+      }
+    
+
+    
+     for(SurfaceElementIndex sei = 0; sei < mesh.GetNSE(); sei++)
+       {
+	 const Element2d & el = mesh[sei];
+
+	 /*
+	 for(int k=0; k<3; k++)
+	   auxind3[k] = el[k];
+
+	 auxind3.Sort();
+	 
+	 int pos = oldfaces[auxind3[0]]->Pos(auxind3);
+	 if(pos < 0)
+	   cout << "UIUIUI" << endl;
+	 */	 
+	 
+	 switch (el.GetType())
+	   {
+	   case TRIG:
+	   case TRIG6:
+	     {
+	       MarkedTri mt;
+	       BTDefineMarkedTri (el, edgenumber, mt);
+	       mtris.Append (mt);
+	       break;
+	     }
+	     
+	   case QUAD:
+	   case QUAD6:
+	     {
+	       MarkedQuad mt;
+	       BTDefineMarkedQuad (el, edgenumber, mt);
+	       mquads.Append (mt);
+	       break;
+	     }
+           default:
+             throw NgException("Bisect, element type not handled in switch, 5");
+	   }
+
+	 
+	MarkedIdentification mi;
+	for(int j=0; j<idmaps.Size(); j++)
+	  if(BTDefineMarkedId(el, edgenumber, *idmaps[j], mi))
+	    mids.Append(mi);
+
+
+	 /*
+	 int pos = surfelements_before[el[0]]->Pos(el);
+	 int elnum = (pos >= 0) ? (*markedsurfelts_num[el[0]])[pos] : -1;
+	 
+	 
+	 switch (el.GetType())
+	   {
+	   case TRIG:
+	   case TRIG6:
+	     {
+	       if(elnum >= 0)
+		 mtris.Append(mtris_old[elnum]);
+	       else
+		 {
+		   MarkedTri mt;
+		   BTDefineMarkedTri (el, edgenumber, mt);
+		   mtris.Append (mt);
+		   (*testout) << "(new) ";
+		 }
+	       (*testout) << "mtri " << mtris.Last();
+	       break;
+	     }
+	     
+	   case QUAD:
+	   case QUAD6:
+	     {
+	       if(elnum >= 0)
+		 mquads.Append(mquads_old[elnum]);
+	       else
+		 {
+		   MarkedQuad mt;
+		   BTDefineMarkedQuad (el, edgenumber, mt);
+		   mquads.Append (mt);
+		 }
+	       break;
+	     }
+	   }
+	 */
+       }
+     
+     /*
+     for(int i=0; i<oldfaces.Size(); i++)
+       {
+	 delete oldfaces[i];
+	 delete oldmarkededges[i];
+       }
+     */
+     
+  }
+				      
+
+
+
+  void Refinement :: Bisect (Mesh & mesh, 
+			     BisectionOptions & opt,
+			     Array<double> * quality_loss) const
+  {
+    PrintMessage(1,"Mesh bisection");
+    PushStatus("Mesh bisection");
+
+    static int timer = NgProfiler::CreateTimer ("Bisect");
+    NgProfiler::RegionTimer reg1 (timer);
+    
+    
+
+    static int localizetimer = NgProfiler::CreateTimer("localize edgepoints");
+    NgProfiler::RegionTimer * loct = new NgProfiler::RegionTimer(localizetimer);   
+    LocalizeEdgePoints(mesh);
+    delete loct;
+
+    Array< Array<int,PointIndex::BASE>* > idmaps;
+    for(int i=1; i<=mesh.GetIdentifications().GetMaxNr(); i++)
+      {
+	if(mesh.GetIdentifications().GetType(i) == Identifications::PERIODIC)
+	  {
+	    idmaps.Append(new Array<int,PointIndex::BASE>);
+	    mesh.GetIdentifications().GetMap(i,*idmaps.Last(),true);
+	  }
+      }
+
+    
+    string refelementinfofileread = "";
+    string refelementinfofilewrite = "";
+
+    if(opt.refinementfilename)
+      {
+	ifstream inf(opt.refinementfilename);
+	string st;
+	inf >> st;
+	if(st == "refinementinfo")
+	  {
+	    while(inf)
+	      {
+		while(inf && st != "markedelementsfile")
+		  inf >> st;
+		
+		if(inf)
+		  inf >> st;
+		
+		if(st == "read" && inf)
+		  ReadEnclString(inf,refelementinfofileread,'\"');
+		else if(st == "write" && inf)
+		  ReadEnclString(inf,refelementinfofilewrite,'\"');
+	      }
+	  }
+	inf.close();
+      }
+	
+
+
+    if (mesh.mglevels == 1 || idmaps.Size() > 0)
+      BisectTetsCopyMesh(mesh, NULL, opt, idmaps, refelementinfofileread);
+
+
+    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;
+    */
+
+
+    if (opt.refine_p)   
+      {
+	int ne = mesh.GetNE();
+	int nse = mesh.GetNSE();
+	int ox,oy,oz; 
+	for (ElementIndex ei = 0; ei < ne; ei++)
+	  if (mesh[ei].TestRefinementFlag())
+	    {
+	      mesh[ei].GetOrder(ox,oy,oz);
+	      mesh[ei].SetOrder (ox+1,oy+1,oz+1);
+	      if (mesh[ei].TestStrongRefinementFlag())
+		mesh[ei].SetOrder (ox+2,oy+2,oz+2);
+	    }
+	for (SurfaceElementIndex sei = 0; sei < nse; sei++)
+	  if (mesh[sei].TestRefinementFlag())
+	    {
+	      mesh[sei].GetOrder(ox,oy);
+	      mesh[sei].SetOrder(ox+1,oy+1);
+	      if (mesh[sei].TestStrongRefinementFlag())
+		mesh[sei].SetOrder(ox+2,oy+2);
+	    }
+
+	  #ifndef SABINE //Nachbarelemente mit ordx,ordy,ordz 
+      
+	  Array<int,PointIndex::BASE> v_order (mesh.GetNP());
+	  v_order = 0;
+
+	  for (ElementIndex ei = 0; ei < ne; ei++)
+	  for (j = 0; j < mesh[ei].GetNP(); j++)
+	  if (mesh[ei].GetOrder() > v_order[mesh[ei][j]])
+	  v_order[mesh[ei][j]] = mesh[ei].GetOrder();
+
+	  for (SurfaceElementIndex sei = 0; sei < nse; sei++)
+	  for (j = 0; j < mesh[sei].GetNP(); j++)
+	  if (mesh[sei].GetOrder() > v_order[mesh[sei][j]])
+	  v_order[mesh[sei][j]] = mesh[sei].GetOrder();
+
+	  for (ElementIndex ei = 0; ei < ne; ei++)
+	  for (j = 0; j < mesh[ei].GetNP(); j++)
+	  if (mesh[ei].GetOrder() < v_order[mesh[ei][j]]-1)
+	  mesh[ei].SetOrder(v_order[mesh[ei][j]]-1);
+
+	  for (SurfaceElementIndex sei = 0; sei < nse; sei++)
+	  for (j = 0; j < mesh[sei].GetNP(); j++)
+	  if (mesh[sei].GetOrder() < v_order[mesh[sei][j]]-1)
+	  mesh[sei].SetOrder(v_order[mesh[sei][j]]-1);
+	    
+	  #endif
+
+	PopStatus();
+	return;
+      }
+
+
+
+    // 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()));
+
+    bool noprojection = false;
+
+    for (l = 1; l <= 1; l++)
+      {
+	int marked = 0;
+	if (opt.refinementfilename)
+	  {
+	    ifstream inf(opt.refinementfilename);
+	    PrintMessage(3,"load refinementinfo from file ",opt.refinementfilename);
+
+	    string st;
+	    inf >> st;
+	    if(st == "refinementinfo")
+	      // new version
+	      {
+		for(i=1; i<=mtets.Size(); i++)
+		  mtets.Elem(i).marked = 0;
+		for(i=1; i<=mprisms.Size(); i++)
+		  mprisms.Elem(i).marked = 0;
+		for(i=1; i<=mtris.Size(); i++)
+		  mtris.Elem(i).marked = 0;
+		for(i=1; i<=mquads.Size(); i++)
+		  mquads.Elem(i).marked = 0;
+		for(i=1; i<=mprisms.Size(); i++)
+		  mids.Elem(i).marked = 0;
+
+		inf >> st;
+		while(inf)
+		  {
+		    if(st[0] == '#')
+		      {
+			inf.ignore(10000,'\n');
+			inf >> st;
+		      }
+		    else if(st == "markedelementsfile")
+		      {
+			inf >> st;
+			ReadEnclString(inf,st,'\"');
+			inf >> st;
+		      }
+		    else if(st == "noprojection")
+		      {
+			noprojection = true;
+			inf >> st;
+		      }
+		    else if(st == "refine")
+		      {
+			inf >> st;
+			if(st == "elements")
+			  {
+			    inf >> st;
+			    bool isint = true;
+				for(string::size_type ii=0; isint && ii<st.size(); ii++)
+			      isint = (isdigit(st[ii]) != 0);
+			    
+			    while(inf && isint)
+			      {
+				mtets.Elem(atoi(st.c_str())).marked = 3;
+				marked = 1;
+
+				inf >> st;
+				isint = true;
+				for(string::size_type ii=0; isint && ii<st.size(); ii++)
+				  isint = (isdigit(st[ii]) != 0);
+			      }
+			  }
+			else if(st == "orthobrick")
+			  {
+			    double bounds[6];
+			    for(i=0; i<6; i++)
+			      inf >> bounds[i];
+			    
+			    int cnt = 0;
+
+			    for(ElementIndex ei = 0; ei < mesh.GetNE(); ei++)
+			      {
+				const Element & el = mesh[ei];
+				
+				//
+				Point<3> center(0,0,0);
+				for(i=0; i<el.GetNP(); i++)
+				  {
+				    const MeshPoint & point = mesh[el[i]];
+				    center(0) += point(0);
+				    center(1) += point(1);
+				    center(2) += point(2);
+				  }
+				for(i=0; i<3; i++)
+				  center(i) *= 1./double(el.GetNP());
+				if(bounds[0] <= center(0) && center(0) <= bounds[3] &&
+				   bounds[1] <= center(1) && center(1) <= bounds[4] &&
+				   bounds[2] <= center(2) && center(2) <= bounds[5])
+				  {
+				    mtets[ei].marked = 3;
+				    cnt++;
+				  }
+				
+				  
+// 				bool contained = false;
+// 				for(int i=0; !contained && i<el.GetNP(); i++)
+// 				  {
+// 				    const MeshPoint & point = mesh[el[i]];
+// 				    contained = (bounds[0] <= point.X() && point.X() <= bounds[3] &&
+// 						 bounds[1] <= point.Y() && point.Y() <= bounds[4] &&
+// 						 bounds[2] <= point.Z() && point.Z() <= bounds[5]);
+// 				  }
+// 				if(contained)
+// 				  {
+// 				    mtets[ei].marked = 3;
+// 				    cnt++;
+// 				  }
+			      }
+
+
+			    ostringstream strstr;
+			    strstr.precision(2);
+			    strstr << "marked " << float(cnt)/float(mesh.GetNE())*100. 
+#ifdef WIN32
+				   << "%%"
+#else
+				   << "%"
+#endif
+				   <<" of the elements";
+			    PrintMessage(4,strstr.str());
+
+			    if(cnt > 0)
+			      marked = 1;
+
+
+			    inf >> st;
+			  }
+			else
+			  {
+			    throw NgException("something wrong with refinementinfo file");
+			  }
+		      }
+		  }		
+	      }
+	    else
+	      {
+		inf.close();
+		inf.open(opt.refinementfilename);
+
+		char ch;
+		for (i = 1; i <= mtets.Size(); i++)
+		  {
+		    inf >> ch;
+		    if(!inf)
+		      throw NgException("something wrong with refinementinfo file (old format)");
+		    mtets.Elem(i).marked = (ch == '1');
+		  }
+		marked = 1;
+	      }
+	    inf.close();
+	  }
+
+	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;
+	    */
+
+	    if (printmessage_importance>0)
+	      {
+		ostringstream str;
+		str << "marked elements: " << cntm;
+		PrintMessage(4,str.str());
+	      }
+
+	    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 =
+		      mesh.SurfaceElement(i).TestRefinementFlag() ? 2 : 0;
+		    // mtris.Elem(cnttrig).marked = 0;
+		    if (mtris.Elem(cnttrig).marked)
+		      cntm++;
+		  }
+		else
+		  {
+		    cntquad++;
+                    // 2d: marked=2, 3d prisms: marked=1
+		    mquads.Elem(cntquad).marked =
+                        mesh.SurfaceElement(i).TestRefinementFlag() ? 4-mesh.GetDimension() : 0 ;
+		    // mquads.Elem(cntquad).marked = 0;
+		    if (mquads.Elem(cntquad).marked)
+		      cntm++;
+		  }
+	      }
+
+              if (printmessage_importance>0)
+		{
+		  ostringstream str;
+		  str << "with surface-elements: " << cntm;
+		  PrintMessage(4,str.str());
+		}
+
+            // he/sz: das wird oben schon richtig gemacht.
+            // hier sind die quads vergessen!
+            /*
+	    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;
+        
+
+	//(*testout) << "mtets " << mtets << endl;
+
+	if (opt.refine_p)
+	  {
+	    PrintMessage(3,"refine p");
+
+	    for (i = 1; i <= mtets.Size(); i++)
+	      mtets.Elem(i).incorder = mtets.Elem(i).marked ? 1 : 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 = mprisms.Elem(i).marked ? 1 : 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 = mtris.Elem(i).marked ? 1 : 0;
+
+	    for (i = 1; i <= mtris.Size(); i++)
+	      {
+		if (mtris.Elem(i).incorder)
+		  mtris.Elem(i).marked = 0;
+	      }
+	  }
+
+	if (opt.refine_hp)
+	  {
+	    PrintMessage(3,"refine hp");
+	    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[0]);
+		    singv.Set (seg[1]);
+		  }
+		/*
+		  for ( i=1; i<= mesh.GetNSE(); i++)
+		  {
+		  const Element2d & sel = mesh.SurfaceElement(i);
+		  for(int j=1; j<=sel.GetNP(); j++)
+		  singv.Set(sel.PNum(j));
+		  }
+		*/
+	      }
+	    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 (j = 0; j < 2; j++)
+		      {
+			int pi = (j == 0) ? seg[0] : seg[1];
+			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;
+
+	//cout << "write?" << endl;
+	//string yn;
+	//cin >> yn;
+
+	(*testout) << "refine volume elements" << endl;
+	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);
+		  //if(yn == "y")
+		  //  (*testout) << "bisected tet " << oldtet;
+		  INDEX_2 edge(oldtet.pnums[oldtet.tetedge1],
+			       oldtet.pnums[oldtet.tetedge2]);
+		  edge.Sort();
+		  if (cutedges.Used (edge))
+		    {
+		      newp = cutedges.Get(edge);
+		    }
+		  else
+		    {
+		      Point<3> npt = Center (mesh.Point (edge.I1()),
+					   mesh.Point (edge.I2()));
+		      newp = mesh.AddPoint (npt);
+		      cutedges.Set (edge, newp);
+		    }
+
+		  BTBisectTet (oldtet, newp, newtet1, newtet2);
+
+		  mtets.Elem(i) = newtet1;
+		  mtets.Append (newtet2);
+
+#ifdef DEBUG
+                  *testout << "tet1 has elnr = " << i << ", tet2 has elnr = " << mtets.Size() << endl;
+#endif
+		  //if(yn == "y")
+		  //  (*testout) << "and got " << newtet1 << "and " << newtet2 << endl;
+
+		  mesh.mlparentelement.Append (i);
+		}
+
+	    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
+		    {
+		      Point<3> npt = Center (mesh.Point (edge1.I1()),
+					    mesh.Point (edge1.I2()));
+		      newp1 = mesh.AddPoint (npt);
+		      cutedges.Set (edge1, newp1);
+		    }
+		  if (cutedges.Used (edge2))
+		    newp2 = cutedges.Get(edge2);
+		  else
+		    {
+		      Point<3> npt = Center (mesh.Point (edge2.I1()),
+					    mesh.Point (edge2.I2()));
+		      newp2 = mesh.AddPoint (npt);
+		      cutedges.Set (edge2, newp2);
+		    }
+		
+
+		  BTBisectPrism (oldprism, newp1, newp2, newprism1, newprism2);
+		  //if(yn == "y")
+		  //  (*testout) << "bisected prism " << oldprism << "and got " << newprism1 << "and " << newprism2 << endl;
+		  mprisms.Elem(i) = newprism1;
+		  mprisms.Append (newprism2);
+		}
+
+	    int nid = mids.Size();
+	    for (i = 1; i <= nid; i++)
+	      if (mids.Elem(i).marked)
+		{
+		  MarkedIdentification oldid,newid1,newid2;
+		  Array<int> newp;
+
+		  oldid = mids.Get(i);
+		  
+		  Array<INDEX_2> edges;
+		  edges.Append(INDEX_2(oldid.pnums[oldid.markededge],
+				       oldid.pnums[(oldid.markededge+1)%oldid.np]));
+		  edges.Append(INDEX_2(oldid.pnums[oldid.markededge + oldid.np],
+				       oldid.pnums[(oldid.markededge+1)%oldid.np + oldid.np]));
+
+		  if(oldid.np == 4)
+		    {
+		      edges.Append(INDEX_2(oldid.pnums[(oldid.markededge+2)%oldid.np],
+					   oldid.pnums[(oldid.markededge+3)%oldid.np]));
+		      edges.Append(INDEX_2(oldid.pnums[(oldid.markededge+2)%oldid.np + oldid.np],
+					   oldid.pnums[(oldid.markededge+3)%oldid.np + oldid.np]));
+		    }
+		  for (j = 0; j < edges.Size(); j++)
+		    {
+		      edges[j].Sort();
+
+		      if(cutedges.Used(edges[j]))
+			newp.Append(cutedges.Get(edges[j]));
+		      else
+			{
+			  Point<3> npt = Center (mesh.Point (edges[j].I1()),
+						mesh.Point (edges[j].I2()));
+			  newp.Append(mesh.AddPoint(npt));
+			  cutedges.Set(edges[j],newp[j]);
+			}			 
+		    }
+		  
+		  BTBisectIdentification(oldid,newp,newid1,newid2);
+		  mids.Elem(i) = newid1;
+		  mids.Append(newid2);		  
+		}
+
+	    
+	    //IdentifyCutEdges(mesh, cutedges);
+
+
+	    hangingvol = 
+	      MarkHangingTets (mtets, cutedges) +
+	      MarkHangingPrisms (mprisms, cutedges) +
+	      MarkHangingIdentifications (mids, cutedges);
+
+
+	    int nsel = mtris.Size();
+
+	    for (i = 1; i <= nsel; i++)
+	      if (mtris.Elem(i).marked)
+		{
+		  MarkedTri oldtri;
+		  MarkedTri newtri1, newtri2;
+		  PointIndex 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
+		    {
+		      Point<3> npt = Center (mesh.Point (edge.I1()),
+					    mesh.Point (edge.I2()));
+		      newp = mesh.AddPoint (npt);
+                      cutedges.Set (edge, newp);
+		    }
+		  //		newp = cutedges.Get(edge);
+		
+		  int si = mesh.GetFaceDescriptor (oldtri.surfid).SurfNr();
+		  //  geom->GetSurface(si)->Project (mesh.Point(newp));
+		  PointGeomInfo npgi;
+		
+//                   cerr << "project point " << newp << " old: " << mesh.Point(newp);
+                  if (mesh[newp].Type() != 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);
+//                   cerr << " new: " << mesh.Point(newp) << endl;
+		
+		  BTBisectTri (oldtri, newp, npgi, newtri1, newtri2);
+		  //if(yn == "y")
+		  //  (*testout) << "bisected tri " << oldtri << "and got " << newtri1 << "and " << newtri2 << endl;
+		
+		
+		  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]);
+                  */
+                  INDEX_2 edge1, edge2;
+                  PointGeomInfo pgi11, pgi12, pgi21, pgi22;
+                  if (oldquad.markededge==0 || oldquad.markededge==2)
+                  {
+                    edge1.I1()=oldquad.pnums[0]; pgi11=oldquad.pgeominfo[0];
+                    edge1.I2()=oldquad.pnums[1]; pgi12=oldquad.pgeominfo[1];
+                    edge2.I1()=oldquad.pnums[2]; pgi21=oldquad.pgeominfo[2];
+                    edge2.I2()=oldquad.pnums[3]; pgi22=oldquad.pgeominfo[3];
+                  }
+                  else // 3 || 1
+                  {
+                    edge1.I1()=oldquad.pnums[0]; pgi11=oldquad.pgeominfo[0];
+                    edge1.I2()=oldquad.pnums[2]; pgi12=oldquad.pgeominfo[2];
+                    edge2.I1()=oldquad.pnums[1]; pgi21=oldquad.pgeominfo[1];
+                    edge2.I2()=oldquad.pnums[3]; pgi22=oldquad.pgeominfo[3];
+                  }
+                  
+                  edge1.Sort();
+		  edge2.Sort();
+
+		  if (cutedges.Used (edge1))
+		    {
+		      newp1 = cutedges.Get(edge1);
+		    }
+		  else
+		    {
+		      Point<3> np1 = Center (mesh.Point (edge1.I1()),
+					   mesh.Point (edge1.I2()));
+		      newp1 = mesh.AddPoint (np1);
+		      cutedges.Set (edge1, newp1);
+                    }
+
+		  if (cutedges.Used (edge2))
+		    {
+		      newp2 = cutedges.Get(edge2);
+		    }
+		  else
+		    {
+		      Point<3> np2 = Center (mesh.Point (edge2.I1()),
+					   mesh.Point (edge2.I2()));
+		      newp2 = mesh.AddPoint (np2);
+		      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)
+//                   cerr << "project point 1 " << newp1 << " old: " << mesh.Point(newp1);
+                  PointBetween (mesh.Point (edge1.I1()), mesh.Point (edge1.I2()),
+				0.5, si,
+				pgi11,
+				pgi12,
+				mesh.Point (newp1), npgi1);
+// 		  (*testout)
+//                   cerr << " new: " << mesh.Point(newp1) << endl;
+
+		
+//                   cerr << "project point 2 " << newp2 << " old: " << mesh.Point(newp2);
+                  PointBetween (mesh.Point (edge2.I1()), mesh.Point (edge2.I2()),
+				0.5, si,
+				pgi21,
+				pgi22,
+				mesh.Point (newp2), npgi2);
+//                   cerr << " new: " << mesh.Point(newp2) << endl;
+		
+
+		  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[0], seg[1]);
+		edge.Sort();
+		if (cutedges.Used (edge))
+		  {
+		    hangingedge = 1;
+		    Segment nseg1 = seg;
+		    Segment nseg2 = seg;
+		  
+		    int newpi = cutedges.Get(edge);
+		  
+		    nseg1[1] = newpi;
+		    nseg2[0] = newpi;
+		  
+		    EdgePointGeomInfo newepgi;
+		  
+ 
+//                     
+//                     cerr << "move edgepoint " << newpi << " from " << mesh.Point(newpi);
+		    PointBetween (mesh.Point (seg[0]), mesh.Point (seg[1]),
+				  0.5, seg.surfnr1, seg.surfnr2, 
+				  seg.epgeominfo[0], seg.epgeominfo[1],
+				  mesh.Point (newpi), newepgi);
+// 		    cerr << " to " << mesh.Point (newpi) << endl;
+
+		    
+		    nseg1.epgeominfo[1] = newepgi;
+		    nseg2.epgeominfo[0] = newepgi;
+		  
+		    mesh.LineSegment (i) = nseg1;
+		    mesh.AddSegment (nseg2);
+		  }
+	      }
+	  }
+	while (hangingvol || hangingsurf || hangingedge);
+        
+	/*
+        if (printmessage_importance>0)
+	  {
+	    ostringstream strstr;
+	    strstr << mtets.Size() << " tets" << endl
+		   << mtris.Size() << " trigs" << endl;
+	    if (mprisms.Size())
+	      {
+		strstr << mprisms.Size() << " prisms" << endl
+		       << mquads.Size() << " quads" << endl;
+	      }
+	    strstr << mesh.GetNP() << " points";
+	    PrintMessage(4,strstr.str());
+	  }
+	*/
+	PrintMessage (4, mtets.Size(), " tets");
+	PrintMessage (4, mtris.Size(), " trigs");
+	if (mprisms.Size())
+	  {
+	    PrintMessage (4, mprisms.Size(), " prisms");
+	    PrintMessage (4, mquads.Size(), " quads");
+	  }
+	PrintMessage (4, mesh.GetNP(), " points");
+      }
+
+
+    // (*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 (int(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 (int(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 (int(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 (int(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());
+    mids.SetAllocSize (mids.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)
+      {
+	PrintMessage(4,"RESETTING mlbetweennodes");
+	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;
+      }
+    */
+
+    BitArray isnewpoint(np);
+    isnewpoint.Clear();
+
+    for (i = 1; i <= cutedges.Size(); i++)
+      if (cutedges.UsedPos(i))
+	{
+	  INDEX_2 edge;
+	  int newpi;
+	  cutedges.GetData (i, edge, newpi);
+	  isnewpoint.Set(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.RebuildSurfaceElementLists();
+  
+    
+    // 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);
+		}
+	    }
+      }
+
+
+    // Repair works only for tets!
+    bool do_repair = mesh.PureTetMesh ();
+
+    do_repair = false;   // JS, March 2009: multigrid crashes
+
+    //if(mesh.mglevels == 3)
+    //  noprojection = true;
+
+    //noprojection = true;
+
+    if(noprojection)
+      {
+	do_repair = false;
+	for(int ii=1; ii<=mesh.GetNP(); ii++)
+	  {
+	    if(isnewpoint.Test(ii) && mesh.mlbetweennodes[ii][0] > 0)
+	      {
+		mesh.Point(ii) = Center(mesh.Point(mesh.mlbetweennodes[ii][0]),
+                                        mesh.Point(mesh.mlbetweennodes[ii][1]));
+	      }
+	  }
+      }
+
+
+    // Check/Repair
+
+    static bool repaired_once;
+    if(mesh.mglevels == 1)
+      repaired_once = false;
+
+    //mesh.Save("before.vol");
+
+    static int reptimer = NgProfiler::CreateTimer("check/repair");
+	NgProfiler::RegionTimer * regt(NULL);
+    regt = new NgProfiler::RegionTimer(reptimer); 
+
+    Array<ElementIndex> bad_elts;
+    Array<double> pure_badness;
+   
+    if(do_repair || quality_loss != NULL)
+      {
+	pure_badness.SetSize(mesh.GetNP()+2);
+	GetPureBadness(mesh,pure_badness,isnewpoint);
+      }
+
+
+    if(do_repair)  // by Markus W
+      {
+	const double max_worsening = 1;
+	
+	const bool uselocalworsening = false;
+	
+	bool repaired = false;
+	
+	Validate(mesh,bad_elts,pure_badness,max_worsening,uselocalworsening);
+	
+        if (printmessage_importance>0)
+	  {
+	    ostringstream strstr;
+	    for(int ii=0; ii<bad_elts.Size(); ii++)
+	      strstr << "bad element " << bad_elts[ii] << "\n";
+	    PrintMessage(1,strstr.str());
+	  }
+	if(repaired_once || bad_elts.Size() > 0)
+	  {
+	    clock_t t1(clock());
+	    
+	    
+	    // update id-maps
+	    j=0;
+	    for(i=1; i<=mesh.GetIdentifications().GetMaxNr(); i++)
+	      {
+		if(mesh.GetIdentifications().GetType(i) == Identifications::PERIODIC)
+		  {
+		    mesh.GetIdentifications().GetMap(i,*idmaps[j],true);
+		    j++;
+		  }
+	      }
+
+    
+	    // do the repair
+	    try
+	      {
+		RepairBisection(mesh,bad_elts,isnewpoint,*this,
+				pure_badness,
+				max_worsening,uselocalworsening,
+				idmaps);
+		repaired = true;
+		repaired_once = true;
+	      }
+	    catch(NgException & ex)
+	      {
+		PrintMessage(1,string("Problem: ") + ex.What());
+	      }
+
+
+            if (printmessage_importance>0)
+            {
+	      ostringstream strstr;
+              strstr << "Time for Repair: " << double(clock() - t1)/double(CLOCKS_PER_SEC) << endl
+		     << "bad elements after repair: " << bad_elts << endl;
+	      PrintMessage(1,strstr.str());
+            }
+	    
+	    if(quality_loss != NULL)
+	      Validate(mesh,bad_elts,pure_badness,1e100,uselocalworsening,quality_loss);
+
+	    if(idmaps.Size() == 0)
+	      UpdateEdgeMarks(mesh,idmaps);
+	    
+	    /*
+	    if(1==1)
+	      UpdateEdgeMarks(mesh,idmaps);
+	    else
+	      mesh.mglevels = 1;
+	    */
+	    
+	    //mesh.ImproveMesh();
+	    
+	  }
+      }
+    delete regt;
+
+
+    
+    for(i=0; i<idmaps.Size(); i++)
+      delete idmaps[i];
+    idmaps.DeleteAll();
+
+    mesh.UpdateTopology();
+
+
+
+
+    if(refelementinfofilewrite != "")
+      {
+	PrintMessage(3,"writing marked-elements information to \"",refelementinfofilewrite,"\"");
+	ofstream ofst(refelementinfofilewrite.c_str());
+
+	WriteMarkedElements(ofst);
+
+	ofst.close();
+      }
+
+
+    mesh.CalcSurfacesOfNode();
+
+    PrintMessage (1, "Bisection done");
+
+    PopStatus();
+  }
+
+
+
+
+  BisectionOptions :: BisectionOptions ()
+  {
+    outfilename = NULL;
+    mlfilename = NULL;
+    refinementfilename = NULL;
+    femcode = NULL;
+    maxlevel = 50;
+    usemarkedelements = 0;
+    refine_hp = 0;
+    refine_p = 0;
+  }
+
+
+  Refinement :: Refinement ()
+  {
+    optimizer2d = NULL;
+  }
+
+  Refinement :: ~Refinement ()
+  {
+    ;
+  }
+
+
+  void Refinement :: PointBetween (const Point<3> & p1, const Point<3> & p2, double secpoint,
+				   int surfi, 
+				   const PointGeomInfo & gi1, 
+				   const PointGeomInfo & gi2,
+				   Point<3> & newp, PointGeomInfo & newgi) const
+  {
+    newp = p1+secpoint*(p2-p1);
+  }
+
+  void Refinement :: PointBetween (const Point<3> & p1, const Point<3> & p2, double secpoint,
+				   int surfi1, int surfi2, 
+				   const EdgePointGeomInfo & ap1, 
+				   const EdgePointGeomInfo & ap2,
+				   Point<3> & newp, EdgePointGeomInfo & newgi) const
+  {
+    cout << "base class edge point between" << endl;
+    newp = p1+secpoint*(p2-p1);
+  }
+
+
+  Vec<3> Refinement :: GetTangent (const Point<3> & p, int surfi1, int surfi2,
+                                   const EdgePointGeomInfo & ap1) const
+  {
+    cerr << "Refinement::GetTangent not overloaded" << endl;
+    return Vec<3> (0,0,0);
+  }
+
+  Vec<3> Refinement :: GetNormal (const Point<3> & p, int surfi1, 
+                                  const PointGeomInfo & gi) const
+  {
+    cerr << "Refinement::GetNormal not overloaded" << endl;
+    return Vec<3> (0,0,0);
+  }
+
+
+  void Refinement :: ProjectToSurface (Point<3> & p, int surfi) const
+  {
+    if (printmessage_importance>0)
+      cerr << "Refinement :: ProjectToSurface    ERROR: no geometry set" << endl;
+  };
+
+  void Refinement :: ProjectToEdge (Point<3> & p, int surfi1, int surfi2, const EdgePointGeomInfo & egi) const
+  {
+    cerr << "Refinement::ProjectToEdge not overloaded" << endl;
+  }
+}
diff --git a/contrib/Netgen/libsrc/meshing/bisect.hpp b/contrib/Netgen/libsrc/meshing/bisect.hpp
new file mode 100644
index 0000000000..2da9b97e8d
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/bisect.hpp
@@ -0,0 +1,102 @@
+#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;
+  bool refine_p;
+  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 class NetgenGeometry *,
+			 ZRefinementOptions & opt);
+
+
+
+
+
+class DLL_HEADER Refinement
+{
+  MeshOptimize2d * optimizer2d;
+
+public:
+  Refinement ();
+  virtual ~Refinement ();
+  
+  void Refine (Mesh & mesh) const;
+  void Refine (Mesh & mesh);
+  void Bisect (Mesh & mesh, class BisectionOptions & opt, Array<double> * quality_loss = NULL) const;
+
+  void MakeSecondOrder (Mesh & mesh) const;
+  void MakeSecondOrder (Mesh & mesh);
+
+  virtual void PointBetween (const Point<3> & p1, const Point<3> & p2, double secpoint, 
+			     int surfi, 
+			     const PointGeomInfo & gi1, 
+			     const PointGeomInfo & gi2,
+			     Point<3> & newp, PointGeomInfo & newgi) const;
+
+  virtual void PointBetween (const Point<3> & p1, const Point<3> & p2, double secpoint,
+			     int surfi1, int surfi2, 
+			     const EdgePointGeomInfo & ap1, 
+			     const EdgePointGeomInfo & ap2,
+			     Point<3> & newp, EdgePointGeomInfo & newgi) const;
+
+  virtual Vec<3> GetTangent (const Point<3> & p, int surfi1, int surfi2,
+                             const EdgePointGeomInfo & egi) const;
+
+  virtual Vec<3> GetNormal (const Point<3> & p, int surfi1, 
+                            const PointGeomInfo & gi) const;
+
+
+  virtual void ProjectToSurface (Point<3> & p, int surfi) const;
+
+  virtual void ProjectToSurface (Point<3> & p, int surfi, const PointGeomInfo & /* gi */) const
+  {
+    ProjectToSurface (p, surfi);
+  }
+
+  virtual void ProjectToEdge (Point<3> & p, int surfi1, int surfi2, const EdgePointGeomInfo & egi) const;
+
+
+  void ValidateSecondOrder (Mesh & mesh);
+  void ValidateRefinedMesh (Mesh & mesh, 
+			    Array<INDEX_2> & parents);
+
+  MeshOptimize2d * Get2dOptimizer(void) const
+  {
+    return optimizer2d;
+  }
+  void Set2dOptimizer(MeshOptimize2d * opti)
+  {
+    optimizer2d = opti;
+  }
+
+  
+  virtual void LocalizeEdgePoints(Mesh & /* mesh */) const {;}
+};
+
+#endif
diff --git a/contrib/Netgen/libsrc/meshing/boundarylayer.cpp b/contrib/Netgen/libsrc/meshing/boundarylayer.cpp
new file mode 100644
index 0000000000..94bfcbe0d0
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/boundarylayer.cpp
@@ -0,0 +1,610 @@
+#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)[0]);
+            bndnodes.Set (mesh.LineSegment(i)[1]);
+         }
+      }
+      for (i = 1; i <= mesh.GetNSeg(); i++)
+      {
+         int snr = mesh.LineSegment(i).edgenr;
+         if (snr != surfid)
+         {
+            bndnodes.Clear (mesh.LineSegment(i)[0]);
+            bndnodes.Clear (mesh.LineSegment(i)[1]);
+         }
+      }
+
+      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)[0];
+            int p2 = mesh.LineSegment(i)[1];
+            int p3 = mapto.Get (p1);
+            if (!p3) p3 = p1;
+            int p4 = mapto.Get (p2);
+            if (!p4) p4 = p2;
+
+            Element2d el(QUAD);
+            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;
+   }
+
+
+
+
+
+/*
+   Philippose Rajan - 11 June 2009
+
+   Function to calculate the surface normal at a given 
+   vertex of a surface element, with respect to that 
+   surface element.
+
+   This function is used by the boundary layer generation 
+   function, in order to calculate the effective direction 
+   in which the prismatic layer should grow
+*/
+   void GetSurfaceNormal(Mesh & mesh, Element2d & el, int Vertex, Vec3d & SurfaceNormal)
+   {
+      int Vertex_A;
+      int Vertex_B;
+
+      Vertex_A = Vertex + 1;
+      if(Vertex_A > el.GetNP()) Vertex_A = 1;
+
+      Vertex_B = Vertex - 1;
+      if(Vertex_B <= 0) Vertex_B = el.GetNP();
+
+      Vec3d Vect_A,Vect_B;
+      
+      Vect_A = mesh.Point(el.PNum(Vertex_A)) - mesh.Point(el.PNum(Vertex));
+      Vect_B = mesh.Point(el.PNum(Vertex_B)) - mesh.Point(el.PNum(Vertex));
+
+      SurfaceNormal = Cross(Vect_A,Vect_B);
+      SurfaceNormal.Normalize();
+   }
+
+
+
+
+
+/*
+    Philippose Rajan - 11 June 2009
+    
+    Added an initial experimental function for 
+    generating prismatic boundary layers on 
+    a given set of surfaces.
+    
+    The number of layers, height of the first layer 
+    and the growth / shrink factor can be specified 
+    by the user
+
+    Currently, the layer height is calculated using:
+    height = h_first_layer * (growth_factor^(num_layers - 1))
+*/
+   void GenerateBoundaryLayer (Mesh & mesh, MeshingParameters & mp)
+   {
+      int i, j;
+
+      ofstream dbg("BndLayerDebug.log");
+
+      // Angle between a surface element and a growth-vector below which 
+      // a prism is project onto that surface as a quad
+      // (in degrees)
+      double angleThreshold = 5.0;
+      
+      cout << "Generate Prismatic Boundary Layers (Experimental)...." << endl;
+
+      // Use an array to support creation of boundary 
+      // layers for multiple surfaces in the future...
+      Array<int> surfid;
+      int surfinp = 0;
+      int prismlayers = 1;
+      double hfirst = 0.01;
+      double growthfactor = 1.0;
+
+      // Monitor and print out the number of prism and quad elements 
+      // added to the mesh
+      int numprisms = 0;
+      int numquads = 0;
+
+      while(surfinp >= 0)
+      {
+         cout << "Enter Surface ID (-1 to end list): ";
+         cin >> surfinp;
+         if(surfinp >= 0) surfid.Append(surfinp);
+      }
+
+      cout << "Number of surfaces entered = " << surfid.Size() << endl; 
+      cout << "Selected surfaces are:" << endl;
+
+      for(i = 1; i <= surfid.Size(); i++)
+      {
+         cout << "Surface " << i << ": " << surfid.Elem(i) << endl;
+      }
+      
+      cout << endl << "Enter number of prism layers: ";
+      cin >> prismlayers;
+      if(prismlayers < 1) prismlayers = 1;
+
+      cout << "Enter height of first layer: ";
+      cin >> hfirst;
+      if(hfirst <= 0.0) hfirst = 0.01;
+
+      cout << "Enter layer growth / shrink factor: ";
+      cin >> growthfactor;
+      if(growthfactor <= 0.0) growthfactor = 0.5;
+
+      cout << "Old NP: " << mesh.GetNP() << endl;
+      cout << "Old NSE: " << mesh.GetNSE() << endl;
+      
+      for(int layer = prismlayers; layer >= 1; layer--)
+      {
+         cout << "Generating layer: " << layer << endl;
+
+         const MeshTopology& meshtopo = mesh.GetTopology();
+         const_cast<MeshTopology &> (meshtopo).SetBuildEdges(true);
+         const_cast<MeshTopology &> (meshtopo).SetBuildFaces(true);
+         const_cast<MeshTopology &> (meshtopo).Update();
+
+         double layerht = hfirst;
+
+         if(growthfactor == 1)
+         {
+            layerht = layer * hfirst;
+         }
+         else
+         {
+            layerht = hfirst*(pow(growthfactor,(layer+1)) - 1)/(growthfactor - 1);
+         }
+
+         cout << "Layer Height = " << layerht << endl;
+
+         // Need to store the old number of points and 
+         // surface elements because there are new points and 
+         // surface elements being added during the process
+         int np = mesh.GetNP();
+         int nse = mesh.GetNSE();
+
+         // Safety measure to ensure no issues with mesh 
+         // consistency
+         int nseg = mesh.GetNSeg();
+
+         // Indicate which points need to be remapped
+         BitArray bndnodes(np);
+
+         // Map of the old points to the new points
+         Array<int> mapto(np);
+
+         // Growth vectors for the prismatic layer based on 
+         // the effective surface normal at a given point
+         Array<Vec3d> growthvectors(np);
+
+         // Bit array to identify all the points belonging 
+         // to the surface of interest
+         bndnodes.Clear();
+
+         // Run through all the surface elements and mark the points 
+         // belonging to those where a boundary layer has to be created.
+         // In addition, also calculate the effective surface normal 
+         // vectors at each of those points to determine the mesh motion 
+         // direction
+         cout << "Marking points for remapping...." << endl;
+
+         for (i = 1; i <= nse; i++)
+         {
+            int snr = mesh.SurfaceElement(i).GetIndex();
+            // cout << "snr = " << snr << endl;
+            if (surfid.Contains(snr))
+            {
+               Element2d & sel = mesh.SurfaceElement(i);
+               int selNP = sel.GetNP();
+               for(j = 1; j <= selNP; j++)
+               {
+                  // Set the bitarray to indicate that the 
+                  // point is part of the required set
+                  bndnodes.Set(sel.PNum(j));
+		  
+                  // Vec3d& surfacenormal = Vec3d();   ????
+                  Vec3d surfacenormal;
+
+                  // Calculate the surface normal at the current point 
+                  // with respect to the current surface element
+                  GetSurfaceNormal(mesh,sel,j,surfacenormal);
+                  
+                  // Add the surface normal to the already existent one 
+                  // (This gives the effective normal direction at corners 
+                  //  and curved areas)
+                  growthvectors.Elem(sel.PNum(j)) = growthvectors.Elem(sel.PNum(j)) 
+                                                    + surfacenormal;
+               }
+            }
+         }
+
+         // Add additional points into the mesh structure in order to 
+         // clone the surface elements.
+         // Also invert the growth vectors so that they point inwards, 
+         // and normalize them
+         cout << "Cloning points and calculating growth vectors...." << endl;
+
+         for (i = 1; i <= np; i++)
+         {
+            if (bndnodes.Test(i))
+            {
+               mapto.Elem(i) = mesh.AddPoint (mesh.Point (i));
+
+               growthvectors.Elem(i).Normalize();
+               growthvectors.Elem(i) *= -1.0;
+            }
+            else
+            {
+               mapto.Elem(i) = 0;
+               growthvectors.Elem(i) = Vec3d(0,0,0);
+            }
+         }
+
+
+         // Add quad surface elements at edges for surfaces which 
+         // dont have boundary layers
+
+         // Bit array to keep track of segments already processed
+         BitArray segsel(nseg);
+
+         // Set them all to "1" to initially activate all segments
+         segsel.Set();
+
+         cout << "Adding 2D Quad elements on required surfaces...." << endl;
+
+         for (i = 1; i <= nseg; i++)
+         {
+            int seg_p1 = mesh.LineSegment(i)[0];
+            int seg_p2 = mesh.LineSegment(i)[1];
+
+            // Only go in if the segment is still active, and if both its 
+            // surface index is part of the "hit-list"
+            if(segsel.Test(i) && surfid.Contains(mesh.LineSegment(i).si))
+            {
+               // clear the bit to indicate that this segment has been processed
+               segsel.Clear(i);
+
+               // Find matching segment pair on other surface
+               for(j = 1; j <= nseg; j++)
+               {
+                  int segpair_p1 = mesh.LineSegment(j)[1];
+                  int segpair_p2 = mesh.LineSegment(j)[0];
+
+                  // Find the segment pair on the neighbouring surface element
+                  // Identified by: seg1[0] = seg_pair[1] and seg1[1] = seg_pair[0]
+                  if(segsel.Test(j) && ((segpair_p1 == seg_p1) && (segpair_p2 == seg_p2)))
+                  {
+                     // clear bit to indicate that processing of this segment is done
+                     segsel.Clear(j);
+
+                     // Only worry about those surfaces which are not in the 
+                     // boundary layer list
+                     if(!surfid.Contains(mesh.LineSegment(j).si))
+                     {
+                        int pnt_commelem = 0;
+                        int pnum_commelem = 0;
+                        Array<int> pnt1_elems;
+                        Array<int> pnt2_elems;
+                       
+                            
+                        meshtopo.GetVertexSurfaceElements(segpair_p1,pnt1_elems);
+                        meshtopo.GetVertexSurfaceElements(segpair_p2,pnt2_elems);
+                        for(int k = 1; k <= pnt1_elems.Size(); k++)
+                        {
+                           Element2d pnt1_sel = mesh.SurfaceElement(pnt1_elems.Elem(k));
+                           for(int l = 1; l <= pnt2_elems.Size(); l++)
+                           {
+                              Element2d pnt2_sel = mesh.SurfaceElement(pnt2_elems.Elem(l));
+                              if((pnt1_sel.GetIndex() == mesh.LineSegment(j).si) 
+                                 && (pnt2_sel.GetIndex() == mesh.LineSegment(j).si)
+                                 && (pnt1_elems.Elem(k) == pnt2_elems.Elem(l)))
+                              {
+                                 pnt_commelem = pnt1_elems.Elem(k);
+                              }
+                           }
+                        }
+
+                        for(int k = 1; k <= mesh.SurfaceElement(pnt_commelem).GetNP(); k++)
+                        {
+                           if((mesh.SurfaceElement(pnt_commelem).PNum(k) != segpair_p1)
+                              && (mesh.SurfaceElement(pnt_commelem).PNum(k) != segpair_p2))
+                           {
+                              pnum_commelem = mesh.SurfaceElement(pnt_commelem).PNum(k);
+                           }
+                        }
+
+                        Vec3d surfelem_vect, surfelem_vect1;
+                        
+                        Element2d & commsel = mesh.SurfaceElement(pnt_commelem);
+
+                        dbg << "NP= " << commsel.GetNP() << " : ";
+
+                        for(int k = 1; k <= commsel.GetNP(); k++)
+                        {
+                           GetSurfaceNormal(mesh,commsel,k,surfelem_vect1);
+                           surfelem_vect += surfelem_vect1;
+                        }
+
+                        surfelem_vect.Normalize();
+
+                        double surfangle = Angle(growthvectors.Elem(segpair_p1),surfelem_vect);
+
+                        dbg << "V1= " << surfelem_vect1 
+                            << " : V2= " << surfelem_vect1
+                            << " : V= " << surfelem_vect
+                            << " : GV= " << growthvectors.Elem(segpair_p1)
+                            << " : Angle= " << surfangle * 180 / 3.141592;
+
+                  
+                        // remap the segments to the new points
+                        mesh.LineSegment(i)[0] = mapto.Get(seg_p1);
+                        mesh.LineSegment(i)[1] = mapto.Get(seg_p2);
+                        mesh.LineSegment(j)[1] = mapto.Get(seg_p1);
+                        mesh.LineSegment(j)[0] = mapto.Get(seg_p2);
+
+                        if((surfangle < (90 + angleThreshold) * 3.141592 / 180.0)
+                           && (surfangle > (90 - angleThreshold) * 3.141592 / 180.0))
+                        {
+                           dbg << " : quad\n";
+                           // Since the surface is lower than the threshold, change the effective 
+                           // prism growth vector to match with the surface vector, so that 
+                           // the Quad which is created lies on the original surface
+                           //growthvectors.Elem(segpair_p1) = surfelem_vect;
+
+                           // Add a quad element to account for the prism volume
+                           // element which is going to be added 
+                           Element2d sel(QUAD);
+                           sel.PNum(4) = mapto.Get(seg_p1);
+                           sel.PNum(3) = mapto.Get(seg_p2);
+                           sel.PNum(2) = segpair_p2;
+                           sel.PNum(1) = segpair_p1;
+                           sel.SetIndex(mesh.LineSegment(j).si);
+                           mesh.AddSurfaceElement(sel);
+                           numquads++;
+                        }
+                        else
+                        {
+                           dbg << "\n";
+                           for (int k = 1; k <= pnt1_elems.Size(); k++)
+                           {
+                              Element2d & pnt_sel = mesh.SurfaceElement(pnt1_elems.Elem(k));
+                              if(pnt_sel.GetIndex() == mesh.LineSegment(j).si)
+                              {
+                                 for(int l = 1; l <= pnt_sel.GetNP(); l++)
+                                 {
+                                    if(pnt_sel.PNum(l) == segpair_p1)
+                                    {
+                                       pnt_sel.PNum(l) = mapto.Get(seg_p1);
+                                    }
+                                    else if(pnt_sel.PNum(l) == segpair_p2)
+                                    {
+                                       pnt_sel.PNum(l) = mapto.Get(seg_p2);
+                                    }
+                                 }
+                              }
+                           }
+
+                           for (int k = 1; k <= pnt2_elems.Size(); k++)
+                           {
+                              Element2d & pnt_sel = mesh.SurfaceElement(pnt2_elems.Elem(k));
+                              if(pnt_sel.GetIndex() == mesh.LineSegment(j).si)
+                              {
+                                 for(int l = 1; l <= pnt_sel.GetNP(); l++)
+                                 {
+                                    if(pnt_sel.PNum(l) == segpair_p1)
+                                    {
+                                       pnt_sel.PNum(l) = mapto.Get(seg_p1);
+                                    }
+                                    else if(pnt_sel.PNum(l) == segpair_p2)
+                                    {
+                                       pnt_sel.PNum(l) = mapto.Get(seg_p2);
+                                    }
+                                 }
+                              }
+                           }
+                        }
+                     }
+                     else
+                     {
+                        // If the code comes here, it indicates that we are at 
+                        // a line segment pair which is at the intersection 
+                        // of two surfaces, both of which have to grow boundary 
+                        // layers.... here too, remapping the segments to the 
+                        // new points is required
+                        mesh.LineSegment(i)[0] = mapto.Get(seg_p1);
+                        mesh.LineSegment(i)[1] = mapto.Get(seg_p2);
+                        mesh.LineSegment(j)[1] = mapto.Get(seg_p1);
+                        mesh.LineSegment(j)[0] = mapto.Get(seg_p2);
+                     }
+                  }
+               }
+            }
+         }
+
+         // Add prismatic cells at the boundaries
+         cout << "Generating prism boundary layer volume elements...." << endl;
+
+         for (i = 1; i <= nse; i++)
+         {
+            Element2d & sel = mesh.SurfaceElement(i);
+            if(surfid.Contains(sel.GetIndex()))
+            {
+               Element el(PRISM);
+               for (j = 1; j <= sel.GetNP(); j++)
+               {
+                  // Check (Doublecheck) if the corresponding point has a 
+                  // copy available for remapping
+                  if (mapto.Get(sel.PNum(j)))
+                  {
+                     // Define the points of the newly added Prism cell
+                     el.PNum(j+3) = mapto.Get(sel.PNum(j));
+                     el.PNum(j) = sel.PNum(j);
+                  }
+               }
+
+               el.SetIndex(1);
+               el.Invert();
+               mesh.AddVolumeElement(el);
+               numprisms++;
+            }
+         }
+
+         // Finally switch the point indices of the surface elements 
+         // to the newly added ones
+         cout << "Transferring boundary layer surface elements to new vertex references...." << endl;
+
+         for (i = 1; i <= nse; i++)
+         {
+            Element2d & sel = mesh.SurfaceElement(i);
+            if(surfid.Contains(sel.GetIndex()))
+            {
+               for (j = 1; j <= sel.GetNP(); j++)
+               {
+                  // Check (Doublecheck) if the corresponding point has a 
+                  // copy available for remapping
+                  if (mapto.Get(sel.PNum(j)))
+                  {
+                     // Map the surface elements to the new points
+                     sel.PNum(j) = mapto.Get(sel.PNum(j));
+                  }
+               }
+            }
+         }
+
+         // Lock all the prism points so that the rest of the mesh can be 
+         // optimised without invalidating the entire mesh
+         for (i = 1; i <= np; i++)
+         {
+            if(bndnodes.Test(i)) mesh.AddLockedPoint(i);
+         }
+
+         // Now, actually pull back the old surface points to create 
+         // the actual boundary layers
+         cout << "Moving and optimising boundary layer points...." << endl;
+         
+         for (i = 1; i <= np; i++)
+         {
+            Array<int> vertelems;
+
+            if(bndnodes.Test(i))
+            {
+               MeshPoint pointtomove;
+
+               pointtomove = mesh.Point(i);
+
+               if(layer == prismlayers)
+               {
+                  mesh.Point(i).SetPoint(pointtomove + layerht * growthvectors.Elem(i));
+
+                  meshtopo.GetVertexElements(i,vertelems);
+
+                  for(j = 1; j <= vertelems.Size(); j++)
+                  {
+		    // double sfact = 0.9;
+                     Element volel = mesh.VolumeElement(vertelems.Elem(j));
+                     if(((volel.GetType() == TET) || (volel.GetType() == TET10)) && (!volel.IsDeleted()))
+                     {
+                        //while((volel.Volume(mesh.Points()) <= 0.0) && (sfact >= 0.0))
+                        //{
+                        //   mesh.Point(i).SetPoint(pointtomove + (sfact * layerht * growthvectors.Elem(i)));
+                        //   mesh.ImproveMesh();
+
+                        //   // Try to move the point back by one step but 
+                        //   // if the volume drops to below zero, double back
+                        //   mesh.Point(i).SetPoint(pointtomove + ((sfact + 0.1) * layerht * growthvectors.Elem(i)));
+                        //   if(volel.Volume(mesh.Points()) <= 0.0)
+                        //   {
+                        //      mesh.Point(i).SetPoint(pointtomove + (sfact * layerht * growthvectors.Elem(i)));
+                        //   }
+                        //   sfact -= 0.1;
+                        //}
+                        volel.Delete();
+                     }
+                  }
+
+                  mesh.Compress();
+               }
+               else
+               {
+                  mesh.Point(i).SetPoint(pointtomove + layerht * growthvectors.Elem(i));
+               }
+            }
+         }
+      }
+
+      // Optimise the tet part of the volume mesh after all the modifications 
+      // to the system are completed
+      //OptimizeVolume(mparam,mesh);
+
+      cout << "New NP: " << mesh.GetNP() << endl;
+      cout << "Num of Quads: " << numquads << endl;
+      cout << "Num of Prisms: " << numprisms << endl;
+      cout << "Boundary Layer Generation....Done!" << endl;
+
+      dbg.close();
+   }
+
+}
+
diff --git a/contrib/Netgen/libsrc/meshing/boundarylayer.hpp b/contrib/Netgen/libsrc/meshing/boundarylayer.hpp
new file mode 100644
index 0000000000..4bd469848f
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/boundarylayer.hpp
@@ -0,0 +1,13 @@
+#ifndef FILE_BOUNDARYLAYER
+#define FILE_BOUNDARYLAYER
+
+
+///
+extern void InsertVirtualBoundaryLayer (Mesh & mesh);
+
+/// Create a typical prismatic boundary layer on the given 
+/// surfaces
+extern void GenerateBoundaryLayer (Mesh & mesh, MeshingParameters & mp);
+
+
+#endif
diff --git a/contrib/Netgen/libsrc/meshing/classifyhpel.hpp b/contrib/Netgen/libsrc/meshing/classifyhpel.hpp
new file mode 100644
index 0000000000..c155537199
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/classifyhpel.hpp
@@ -0,0 +1,1728 @@
+HPREF_ELEMENT_TYPE ClassifyTet(HPRefElement & el, INDEX_2_HASHTABLE<int> & edges, INDEX_2_HASHTABLE<int> & edgepoint_dom, 
+                               BitArray & cornerpoint, BitArray & edgepoint, INDEX_3_HASHTABLE<int> & faces, INDEX_2_HASHTABLE<int> & face_edges, 
+                               INDEX_2_HASHTABLE<int> & surf_edges, Array<int, PointIndex::BASE> & facepoint)
+{
+  int ep1(0), ep2(0), ep3(0), ep4(0), cp1(0), cp2(0), cp3(0), cp4(0), fp1, fp2, fp3, fp4;
+  int isedge1(0), isedge2(0), isedge3(0), isedge4(0), isedge5(0), isedge6(0);
+  int isfedge1, isfedge2, isfedge3, isfedge4, isfedge5, isfedge6;
+  int isface1(0), isface2(0), isface3(0), isface4(0);
+
+  HPREF_ELEMENT_TYPE type = HP_NONE; 
+  
+
+  int debug = 0;
+  for (int j = 0;j < 4; j++)
+    {
+      if (el.pnums[j] == 444) debug++;
+      if (el.pnums[j] == 115) debug++;
+      if (el.pnums[j] == 382) debug++;
+      if (el.pnums[j] == 281) debug++;
+    }
+  if (debug < 4) debug = 0;
+  
+
+
+  for (int j = 0; j < 4; j++)
+    for (int k = 0; k < 4; k++)
+      {
+	if (j == k) continue;
+	if (type) break;
+	
+	int pi3 = 0;
+	while (pi3 == j || pi3 == k) pi3++;
+	int pi4 = 6 - 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.pnums[j]);
+	ep2 = edgepoint.Test (el.pnums[k]);
+	ep3 = edgepoint.Test (el.pnums[pi3]);
+	ep4 = edgepoint.Test (el.pnums[pi4]);
+	
+	cp1 = cornerpoint.Test (el.pnums[j]);
+	cp2 = cornerpoint.Test (el.pnums[k]);
+	cp3 = cornerpoint.Test (el.pnums[pi3]);
+	cp4 = cornerpoint.Test (el.pnums[pi4]);
+	
+	isedge1 = edges.Used (INDEX_2::Sort (el.pnums[j], el.pnums[k]));
+	isedge2 = edges.Used (INDEX_2::Sort (el.pnums[j], el.pnums[pi3]));
+	isedge3 = edges.Used (INDEX_2::Sort (el.pnums[j], el.pnums[pi4]));
+	isedge4 = edges.Used (INDEX_2::Sort (el.pnums[k], el.pnums[pi3]));
+	isedge5 = edges.Used (INDEX_2::Sort (el.pnums[k], el.pnums[pi4]));
+	isedge6 = edges.Used (INDEX_2::Sort (el.pnums[pi3], el.pnums[pi4]));
+	
+	if (debug)
+	  {
+	    cout << "debug" << endl;
+	    *testout  << "debug" << endl;
+	    *testout << "ep = " << ep1 << ep2 << ep3 << ep4 << endl;
+	    *testout << "cp = " << cp1 << cp2 << cp3 << cp4 << endl;
+	    *testout << "edge = " << isedge1 << isedge2 << isedge3 << isedge4 << isedge5 << isedge6 << endl;
+	  }
+
+
+	isface1 = isface2 = isface3 = isface4 = 0;
+	for (int l = 0; l < 4; l++)
+	  {
+	    INDEX_3 i3(0,0,0);
+	    switch (l)
+	      {
+              case 0: i3.I1() = el.pnums[k]; i3.I1() = el.pnums[pi3]; i3.I1() = el.pnums[pi4]; break;
+              case 1: i3.I1() = el.pnums[j]; i3.I1() = el.pnums[pi3]; i3.I1() = el.pnums[pi4]; break;
+              case 2: i3.I1() = el.pnums[j]; i3.I1() = el.pnums[k]; i3.I1() = el.pnums[pi4]; break;
+              case 3: i3.I1() = el.pnums[j]; i3.I1() = el.pnums[k]; i3.I1() = el.pnums[pi3]; break;
+	      }
+	    i3.Sort();
+	    if (faces.Used (i3))
+	      {
+		int domnr = faces.Get(i3);
+		if (domnr == -1 || domnr == el.GetIndex())
+		  {
+		    switch (l)
+		      {
+		      case 0: isface1 = 1; break;
+		      case 1: isface2 = 1; break;
+		      case 2: isface3 = 1; break;
+		      case 3: isface4 = 1; break;
+		      }
+		  }
+	      }
+	  }
+	/*
+	  isface1 = faces.Used (INDEX_3::Sort (el.pnums[k], el.pnums[pi3], el.pnums[pi4]));
+	  isface2 = faces.Used (INDEX_3::Sort (el.pnums[j], el.pnums[pi3], el.pnums[pi4]));
+	  isface3 = faces.Used (INDEX_3::Sort (el.pnums[j], el.pnums[k], el.pnums[pi4]));
+	  isface4 = faces.Used (INDEX_3::Sort (el.pnums[j], el.pnums[k], el.pnums[pi3]));
+	*/
+	
+	isfedge1 = isfedge2 = isfedge3 = isfedge4 = isfedge5 = isfedge6 = 0;
+	for (int l = 0; l < 6; l++)
+	  {
+	    INDEX_2 i2(0,0);
+	    switch (l)
+	      {
+              case 0: i2.I1() = el.pnums[j]; i2.I2() = el[k]; break;
+              case 1: i2.I1() = el.pnums[j]; i2.I2() = el.pnums[pi3]; break;
+              case 2: i2.I1() = el.pnums[j]; i2.I2() = el.pnums[pi4]; break;
+              case 3: i2.I1() = el.pnums[k]; i2.I2() = el.pnums[pi3]; break;
+              case 4: i2.I1() = el.pnums[k]; i2.I2() = el.pnums[pi4]; break;
+              case 5: i2.I1() = el.pnums[pi3]; i2.I2() = el.pnums[pi4]; break;
+	      }
+	    i2.Sort();
+	    if (face_edges.Used (i2))
+	      {
+		int domnr = face_edges.Get(i2);
+		if (domnr == -1 || domnr == el.GetIndex())
+		  {
+		    switch (l)
+		      {
+		      case 0: isfedge1 = 1; break;
+		      case 1: isfedge2 = 1; break;
+		      case 2: isfedge3 = 1; break;
+		      case 3: isfedge4 = 1; break;
+		      case 4: isfedge5 = 1; break;
+		      case 5: isfedge6 = 1; break;
+		      }
+		  }
+	      }
+	  }
+	/*
+	  isfedge1 = face_edges.Used (INDEX_2::Sort (el.pnums[j], el.pnums[k]));
+	  isfedge2 = face_edges.Used (INDEX_2::Sort (el.pnums[j], el.pnums[pi3]));
+	  isfedge3 = face_edges.Used (INDEX_2::Sort (el.pnums[j], el.pnums[pi4]));
+	  isfedge4 = face_edges.Used (INDEX_2::Sort (el.pnums[k], el.pnums[pi3]));
+	  isfedge5 = face_edges.Used (INDEX_2::Sort (el.pnums[k], el.pnums[pi4]));
+	  isfedge6 = face_edges.Used (INDEX_2::Sort (el.pnums[pi3], el.pnums[pi4]));
+	*/
+	
+	fp1 = fp2 = fp3 = fp4 = 0;
+	for (int l = 0; l < 4; l++)
+	  {
+	    int pti(0);
+	    switch (l)
+	      {
+	      case 0: pti = el.pnums[j]; break;
+	      case 1: pti = el.pnums[k]; break;
+	      case 2: pti = el.pnums[pi3]; break;
+	      case 3: pti = el.pnums[pi4]; break;
+	      }
+	    int domnr = facepoint[pti];
+	    if (domnr == -1 || domnr == el.GetIndex())
+	      {
+		switch (l)
+		  {
+		  case 0: fp1 = 1; break;
+		  case 1: fp2 = 1; break;
+		  case 2: fp3 = 1; break;
+		  case 3: fp4 = 1; break;
+		  }
+	      }
+	  }
+	
+	/*
+	  fp1 = facepoint[el.pnums[j]] != 0;
+	  fp2 = facepoint[el.pnums[k]] != 0;
+	  fp3 = facepoint[el.pnums[pi3]] != 0;
+	  fp4 = facepoint[el.pnums[pi4]] != 0;
+	*/
+	
+	
+	switch (isface1+isface2+isface3+isface4)
+	  {
+	  case 0:
+	    {
+	      isedge1 |= isfedge1;
+	      isedge2 |= isfedge2;
+	      isedge3 |= isfedge3;
+	      isedge4 |= isfedge4;
+	      isedge5 |= isfedge5;
+	      isedge6 |= isfedge6;
+	      
+	      ep1 |= fp1;
+	      ep2 |= fp2;
+	      ep3 |= fp3;
+	      ep4 |= fp4;
+	      
+	      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;
+		      }
+		    break;
+		  }
+		case 3:
+		  {
+		    if (isedge1 && isedge2 && isedge3)
+		      {
+			if (!cp2 && !cp3 && !cp4)
+			  type = HP_TET_3EA_0V;
+			if (cp2 && !cp3 && !cp4)
+			  type = HP_TET_3EA_1V;
+			if (cp2 && cp3 && !cp4)
+			  type = HP_TET_3EA_2V;
+			if (cp2 && cp3 && cp4)
+			  type = HP_TET_3EA_3V;
+		      }
+		    if (isedge1 && isedge3 && isedge4)
+		      {
+			if (!cp3 && !cp4)
+			  type = HP_TET_3EB_0V;
+			if (cp3 && !cp4)
+                          type = HP_TET_3EB_1V;
+			if (cp3 && cp4)
+			  type = HP_TET_3EB_2V;
+		      }
+		    if (isedge1 && isedge2 && isedge5)
+		      {
+			if (!cp3 && !cp4)
+			  type = HP_TET_3EC_0V;
+			if (cp3 && !cp4)
+			  type = HP_TET_3EC_1V;
+			if (cp3 && cp4)
+			  type = HP_TET_3EC_2V;
+		      }
+		    break;
+		  }
+		}
+	      break;
+	    }
+	    
+	    
+	    
+	  case 1:  // one singular face
+	    {
+	      if (!isface1) break;
+	      
+	      switch (isfedge1+isfedge2+isfedge3+isedge4+isedge5+isedge6)
+		{
+		case 0:
+		  {
+		    if (!fp1 && !ep2 && !ep3 && !ep4)
+		      type = HP_TET_1F_0E_0V;
+		    if (fp1 && !ep2 && !ep3 && !ep4)
+		      type = HP_TET_1F_0E_1VB;
+		    if (!fp1 && ep2 && !ep3 & !ep4)
+		      type = HP_TET_1F_0E_1VA;
+		    break;
+		  }
+		case 1:
+		  {
+		    if (isfedge1)
+		      {
+			if (!ep1 && !ep3 && !ep4)
+			  type = HP_TET_1F_1EA_0V;
+		      }
+		    if (isedge4) // V1-V3
+		      {
+			if (!ep1 && !cp2 && !cp3 && !ep4)
+			  type = HP_TET_1F_1EB_0V;
+		      }
+		    break;
+		  }
+		}
+	      break;
+	    }
+	    
+	    
+	  case 2:  // two singular faces
+	    {
+	      if (!isface1 || !isface2) break;
+	      
+	      switch (isfedge1+isedge2+isedge3+isedge4+isedge5)
+		{
+		case 0:
+		  {
+		    if (!ep1 && !ep2 && !cp3 && !cp4)
+		      type = HP_TET_2F_0E_0V;
+		    break;
+		  }
+		}
+	      break;
+	    }
+	    
+	    
+	  }
+	
+	if (type != HP_NONE)
+	  {
+	    int pnums[4]; 
+	    pnums[0] = el.pnums[j];
+	    pnums[1] = el.pnums[k];
+	    pnums[2] = el.pnums[pi3];
+	    pnums[3] = el.pnums[pi4];
+	    for(k=0;k<4;k++) el.pnums[k] = pnums[k]; 
+	    break;
+	  }
+      }
+  
+  
+  if (debug) cout << "type = " << type << endl;
+
+  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
+		 << "isface = " << isface1 << isface2 << isface3 << isface4 << endl;
+      cout << "undefined element !!! " << endl;
+
+      
+    }
+  return(type); 
+}
+
+
+
+HPREF_ELEMENT_TYPE ClassifyPrism(HPRefElement & el, INDEX_2_HASHTABLE<int> & edges, INDEX_2_HASHTABLE<int> & edgepoint_dom, 
+                                 BitArray & cornerpoint, BitArray & edgepoint, INDEX_3_HASHTABLE<int> & faces, INDEX_2_HASHTABLE<int> & face_edges, 
+                                 INDEX_2_HASHTABLE<int> & surf_edges, Array<int, PointIndex::BASE> & facepoint)
+{
+
+  HPREF_ELEMENT_TYPE type = HP_NONE;
+  
+  int p[6];
+  for(int m=1;m<=6;m++)
+    {
+      int point_sing[6]={0,0,0,0,0,0}; 
+      int face_sing[5]={0,0,0,0,0};
+      int edge_sing[9]={0,0,0,0,0,0,0,0,0}; 
+      
+      if(m<4)
+	{ 
+	  p[0]= m; p[1]=m%3+1; p[2]=(m%3+1)%3+1;
+	  for(int l=3;l<6;l++) p[l]=p[l-3]+3;  
+	}
+      else
+	{
+	  p[0] = m; p[1]=(m%3+1)%3+4; p[2]=m%3+4;
+	  for(int l=3;l<6;l++) p[l]=p[l-3]-3; 
+	}
+      
+      for(int j=0;j<6;j++) 
+	{ 
+	  if(cornerpoint.Test(el.PNum(p[j])))  { point_sing[p[j]-1]=3;}
+	  else if(edgepoint.Test(el.PNum(p[j]))) point_sing[p[j]-1]=2;
+	  else if (facepoint[el.PNum(p[j])] == -1 || facepoint[el.PNum(p[j])] == el.GetIndex())
+	    point_sing[p[j]-1] = 1;  
+	}
+      
+      const ELEMENT_EDGE * eledges = MeshTopology::GetEdges1 (PRISM);
+      for(int k=0;k<9;k++)
+	{
+	  INDEX_2 i2 = INDEX_2 :: Sort(el.PNum(p[eledges[k][0]-1]),el.PNum(p[eledges[k][1]-1])); 
+	  if (edges.Used(i2)) edge_sing[k] = 2;
+	  else edge_sing[k] = face_edges.Used(i2);
+	}
+      
+      const ELEMENT_FACE * elfaces  = MeshTopology::GetFaces1 (PRISM);
+      for (int k=0;k<5;k++)
+	{
+	  INDEX_3 i3; 
+	  
+	  if(k<2) 
+	    i3 = INDEX_3::Sort(el.pnums[p[elfaces[k][0]-1]-1], el.pnums[p[elfaces[k][1]-1]-1], 
+			       el.pnums[p[elfaces[k][2]-1]-1]); 
+	  else 
+	    { 
+	      INDEX_4  i4 = INDEX_4(el.pnums[p[elfaces[k][0]-1]-1], el.pnums[p[elfaces[k][1]-1]-1], el.pnums[p[elfaces[k][2]-1]-1],el.pnums[p[elfaces[k][3]-1]-1]); 
+	      i4.Sort();
+	      i3 = INDEX_3(i4.I1(), i4.I2(), i4.I3()); 
+	    }
+	  
+	  if (faces.Used (i3))
+	    {
+	      int domnr = faces.Get(i3); 
+	      if (domnr == -1 || domnr == el.GetIndex())
+		face_sing[k] = 1; 
+	      
+	    } 
+	} 
+      if (face_sing[1] > face_sing[0]) {m=m+2; continue;}  
+      
+      
+      //int cp = 0;  
+      
+      int qfsing = face_sing[2] + face_sing[3] + face_sing[4];
+      int tfsing = face_sing[0] + face_sing[1]; 
+      int evsing = edge_sing[6] + edge_sing[7] + edge_sing[8];
+      int ehsing = edge_sing[0] + edge_sing[1] + edge_sing[2] + edge_sing[3] + edge_sing[4] + edge_sing[5];
+      
+      if (qfsing + tfsing + evsing + ehsing == 0)  
+	{ type = HP_PRISM;  break;}
+      
+      HPREF_ELEMENT_TYPE types[] = {HP_NONE,HP_NONE,HP_NONE};   
+      
+      int fb = (1-face_sing[4])* face_sing[3] * (face_sing[2] + face_sing[3]) + 3*face_sing[4]*face_sing[3]*face_sing[2];  
+      int sve[3] = {edge_sing[7] , edge_sing[8], edge_sing[6]}; 
+      
+            
+      if(fb!=qfsing) continue; 
+      
+      
+      switch(fb)
+	{ 
+	case 0: 
+	  if (evsing == 0 && ehsing==3*tfsing) 
+	    {
+	      types[0] = HP_PRISM; 
+	      types[1] = HP_PRISM_1FA_0E_0V;   
+	      types[2] = HP_PRISM_2FA_0E_0V; 
+	    } 
+	  if(evsing > 0 &&  sve[0] == evsing) // 1 vertical edge 1-4 
+	    { 
+	      types[0] = HP_PRISM_SINGEDGE;
+	      types[1] = HP_PRISM_1FA_1E_0V;
+	      types[2] = HP_PRISM_2FA_1E_0V;   
+	    }
+	  
+	  if(sve[0] > 0 && sve[1] > 0 && sve[2] == 0)
+	    {
+	      types[0] = HP_PRISM_SINGEDGE_V12;
+	      types[1] = HP_PRISM_1FA_2E_0V; 
+	      types[2] = HP_PRISM_2FA_2E_0V; 
+	    }
+	  if(sve[0] > 0 && sve[1] > 0 && sve[2] > 0) 
+	    {
+	      types[0] = HP_PRISM_3E_0V;
+	      types[1] = HP_PRISM_1FA_3E_0V;
+	      types[2] = HP_PRISM_2FA_3E_0V;
+	      
+	      if ( edge_sing[0] > 1 && edge_sing[2] > 1 &&  
+		   edge_sing[4] > 1 && edge_sing[5] > 1 && tfsing==0)
+		types[0] = HP_PRISM_3E_4EH; 
+	    }
+	  
+	  break;
+	case 1:
+	  if(sve[0] <= 1 && sve[1] <= 1)  
+            {
+              if(sve[2]==0)
+                { 
+                  types[0] = HP_PRISM_1FB_0E_0V;
+                  types[1] = HP_PRISM_1FA_1FB_0E_0V;
+                  types[2] = HP_PRISM_2FA_1FB_0E_0V;  
+                }
+              else
+                { 
+                  types[0] = HP_PRISM_1FB_1EC_0V;
+                  types[1] = HP_PRISM_1FA_1FB_1EC_0V;
+                  types[2] = HP_PRISM_2FA_1FB_1EC_0V; 
+                }
+            }
+
+	  if(sve[0] > 1 && sve[2] >= 1 && sve[1] <= 1)
+	    { 
+	      types[0] = HP_PRISM_1FB_2EB_0V;  
+	      types[1] = HP_PRISM_1FA_1FB_2EB_0V;
+	      types[2] = HP_PRISM_2FA_1FB_2EB_0V; 
+	    }
+	  
+	  if(sve[0] > 1 && sve[1] <= 1 && sve[2] == 0) // ea && !eb  
+	    {
+	      types[0] = HP_PRISM_1FB_1EA_0V;
+	      types[1] = HP_PRISM_1FA_1FB_1EA_0V;
+	      types[2] = HP_PRISM_2FA_1FB_1EA_0V; 
+	    } 
+	  
+	  if(sve[0] <= 1 && sve[1] > 1 && sve[2] == 0)
+	    types[1] = HP_PRISM_1FA_1FB_1EB_0V; 
+	  
+	  if(sve[0] > 1 && sve[1]>1) 
+	    if(sve[2] == 0)  // ea && eb 
+	      {
+		types[0] = HP_PRISM_1FB_2EA_0V;
+		types[1] = HP_PRISM_1FA_1FB_2EA_0V;
+		types[2] = HP_PRISM_2FA_1FB_2EA_0V; 
+	      }
+	  if(sve[0] <= 1 && sve[1] > 1 && sve[2] >0)
+	    types[1] = HP_PRISM_1FA_1FB_2EC_0V; 
+	  
+	  if(sve[0] > 1 && sve[1] > 1 && sve[2] >= 1) //sve[2] can also be a face-edge  
+	    {
+	      types[0] = HP_PRISM_1FB_3E_0V;  
+	      types[1] = HP_PRISM_1FA_1FB_3E_0V; 
+	      types[2] = HP_PRISM_2FA_1FB_3E_0V; 
+	    } 
+	  
+	  break;  
+	  
+	case 2:
+	  if(sve[0] <= 1) 
+	    cout << " **** WARNING: Edge between to different singular faces should be marked singular " << endl; 
+		      
+	  if(sve[1] <= 1)   
+	    if(sve[2] <=1) 
+	      { 
+		types[0] = HP_PRISM_2FB_0E_0V; 
+		types[1] = HP_PRISM_1FA_2FB_0E_0V;
+		types[2] = HP_PRISM_2FA_2FB_0E_0V;
+	      }
+	    else
+	      { 
+		types[0] = HP_PRISM_2FB_1EC_0V; 
+		types[1] = HP_PRISM_1FA_2FB_1EC_0V; 
+		types[2] = HP_PRISM_2FA_2FB_1EC_0V;   
+	      }
+	  else
+	    if(sve[2] <= 1) 
+	      types[1] = HP_PRISM_1FA_2FB_1EB_0V; 
+	    else
+	      { 
+		types[0] = HP_PRISM_2FB_3E_0V; 
+		types[1] = HP_PRISM_1FA_2FB_3E_0V; 
+		types[2] = HP_PRISM_2FA_2FB_3E_0V; 
+	      }
+	  
+	  break;
+	  
+	case 3: 
+	  types[0] = HP_PRISM_3FB_0V; 
+	  types[1] = HP_PRISM_1FA_3FB_0V; 
+	  types[2] = HP_PRISM_2FA_3FB_0V; 
+	  break;
+	}
+      type = types[tfsing];
+      
+         
+      if(type != HP_NONE)  
+	break;
+    }
+	 
+  /*
+   *testout << " Prism with pnums " << endl; 
+   for(int j=0;j<6;j++) *testout << el.pnums[j] << "\t"; 
+   *testout << endl; 
+   */
+  
+  if(type != HP_NONE) 
+    {
+      int pnums[6]; 
+      for(int j=0;j<6;j++) pnums[j] = el.PNum (p[j]);
+      for(int k=0;k<6;k++) el.pnums[k] = pnums[k]; 
+    }
+
+  /* *testout << " Classified Prism with pnums " << endl; 
+     for(int j=0;j<6;j++) *testout << el.pnums[j] << "\t"; 
+     *testout << endl; 
+     */ 
+  return(type); 
+}
+
+
+// #ifdef SABINE 
+HPREF_ELEMENT_TYPE ClassifyTrig(HPRefElement & el, INDEX_2_HASHTABLE<int> & edges, INDEX_2_HASHTABLE<int> & edgepoint_dom, 
+                                BitArray & cornerpoint, BitArray & edgepoint, INDEX_3_HASHTABLE<int> & faces, INDEX_2_HASHTABLE<int>  & face_edges, 
+				INDEX_2_HASHTABLE<int> & surf_edges, Array<int, PointIndex::BASE> & facepoint, int dim, const FaceDescriptor & fd)
+
+{
+  HPREF_ELEMENT_TYPE type = HP_NONE; 
+  
+  int pnums[3]; 
+  int p[3];   
+  
+  INDEX_3 i3 (el.pnums[0], el.pnums[1], el.pnums[2]);
+  i3.Sort();
+  bool sing_face = faces.Used (i3);
+  
+  // *testout << " facepoint " << facepoint << endl;  
+      
+
+  // Try all rotations of the trig 
+  for (int j=0;j<3;j++) 
+    {
+      int point_sing[3] = {0,0,0}; 
+      int edge_sing[3] = {0,0,0}; 
+      // *testout << " actual rotation of trig points " ;  
+      for(int m=0;m<3;m++) 
+	{ 
+	  p[m] = (j+m)%3 +1; // local vertex number
+	  pnums[m] = el.PNum(p[m]); // global vertex number 
+	  // *testout << pnums[m] << " \t "; 
+	}
+      // *testout << endl ; 
+      
+      if(dim == 3) 
+	{
+	  // face point 
+	  for(int k=0;k<3;k++)
+	    if(!sing_face)
+	      { 
+		//	*testout << " fp [" << k << "] = " << facepoint[pnums[k]] << endl;   
+		//	*testout << " fd.DomainIn()" <<  fd.DomainIn() << endl; 
+		//	*testout  << " fd.DomainOut()" <<  fd.DomainOut() << endl; 
+		if( facepoint[pnums[k]]  && (facepoint[pnums[k]] ==-1 || 
+					     facepoint[pnums[k]] == fd.DomainIn() ||   facepoint[pnums[k]] == fd.DomainOut()))
+		  point_sing[p[k]-1] = 1; 
+	      } 
+	  // if point is on face_edge in next step sing = 2 
+
+	  /*	  *testout << " pointsing NACH FACEPOints ... FALLS EDGEPOINT UMSETZEN" ; 
+            for (int k=0;k<3;k++) *testout << "\t" << point_sing[p[k]-1] ;
+            *testout << endl; */
+	}
+      
+      const ELEMENT_EDGE * eledges = MeshTopology::GetEdges1(TRIG); 
+      
+      if(dim==3)
+	{
+	  for(int k=0;k<3;k++) 
+	    { 
+	      int ep1=p[eledges[k][0]-1];  
+	      int ep2=p[eledges[k][1]-1];  
+	      INDEX_2 i2(el.PNum(ep1),el.PNum(ep2)); 
+	      
+	      if(edges.Used(i2)) 
+		{
+		  
+		  edge_sing[k]=2;
+		  point_sing[ep1-1] = 2; 
+		  point_sing[ep2-1] = 2; 
+		}
+	      else // face_edge? 
+		{	  
+		  i2.Sort();  
+		  if(surf_edges.Used(i2) && surf_edges.Get(i2) != fd.SurfNr()+1)  // edge not face_edge acc. to surface in which trig lies
+		    {
+		      if(face_edges.Get(i2)==-1 ||face_edges.Get(i2) == fd.DomainIn() || face_edges.Get(i2) == fd.DomainOut() )
+			{ 
+			  edge_sing[k]=1;
+			} 
+		      else
+			{ 
+			  point_sing[ep1-1] = 0; // set to edge_point 
+			  point_sing[ep2-1] = 0; // set to edge_point
+			} 
+		    }
+		}
+	      
+	      /*  *testout << " pointsing NACH edges UND FACEEDGES UMSETZEN ... " ; 
+                  for (int k=0;k<3;k++) *testout << "\t" << point_sing[p[k]-1] ; 
+                  *testout << endl;          
+                  */
+	    }
+	}
+      /*
+       *testout << " dim " << dim << endl; 
+       *testout << " edgepoint_dom " << edgepoint_dom << endl; 
+       */
+      if(dim==2)
+	{
+	  for(int k=0;k<3;k++) 
+	    { 
+	      int ep1=p[eledges[k][0]-1];  
+	      int ep2=p[eledges[k][1]-1];  
+	     
+	      INDEX_2 i2(el.PNum(ep1),el.PNum(ep2));  
+	     
+	      if(edges.Used(i2)) 
+		{
+		  
+		  if(edgepoint_dom.Used(INDEX_2(fd.SurfNr(),pnums[ep1-1])) || 
+		     edgepoint_dom.Used(INDEX_2(-1,pnums[ep1-1])) || 
+		     edgepoint_dom.Used(INDEX_2(fd.SurfNr(),pnums[ep2-1])) || 
+		     edgepoint_dom.Used(INDEX_2(-1,pnums[ep2-1]))) 
+		    {
+		      edge_sing[k]=2;
+		      point_sing[ep1-1] = 2;
+		      point_sing[ep2-1] = 2; 
+		    }
+		}
+	     
+	    }
+	}
+
+     
+	 
+      for(int k=0;k<3;k++) 
+	if(edgepoint.Test(pnums[k])) //edgepoint, but not member of sing_edge on trig -> cp 
+	  {
+	    INDEX_2 i2a=INDEX_2::Sort(el.PNum(p[k]), el.PNum(p[(k+1)%3])); 
+	    INDEX_2 i2b=INDEX_2::Sort(el.PNum(p[k]), el.PNum(p[(k+2)%3])); 
+	    
+	    if(!edges.Used(i2a) && !edges.Used(i2b)) 
+	      point_sing[p[k]-1] = 3; 	
+	  } 
+      
+      for(int k=0;k<3;k++) 
+	if(cornerpoint.Test(el.PNum(p[k]))) 
+	  point_sing[p[k]-1] = 3; 
+      
+      *testout << "point_sing = " << point_sing[0] << point_sing[1] << point_sing[2] << endl;
+
+      if(edge_sing[0] + edge_sing[1] + edge_sing[2] == 0) 
+        { 
+          int ps = point_sing[0] + point_sing[1] + point_sing[2]; 
+	 
+          if(ps==0) 
+            type = HP_TRIG; 
+          else if(point_sing[p[0]-1]  && !point_sing[p[1]-1] && !point_sing[p[2]-1])
+            type = HP_TRIG_SINGCORNER;
+          else if(point_sing[p[0]-1] && point_sing[p[1]-1] && !point_sing[p[2]-1]) 
+            type = HP_TRIG_SINGCORNER12; 
+          else if(point_sing[p[0]-1] && point_sing[p[1]-1] && point_sing[p[2]-1]) 
+            { 
+              if(dim==2) type = HP_TRIG_SINGCORNER123_2D; 
+              else type = HP_TRIG_SINGCORNER123; 
+            } 
+        } 
+      else
+        if (edge_sing[2] && !edge_sing[0] && !edge_sing[1]) //E[2]=(1,2) 
+          { 
+            int code = 0; 
+            if(point_sing[p[0]-1] > edge_sing[2]) code+=1; 
+            if(point_sing[p[1]-1] > edge_sing[2]) code+=2; 
+            if(point_sing[p[2]-1]) 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]; 
+	
+          }  // E[0] = [0,2], E[1] =[1,2], E[2] = [0,1]
+        else 
+          if(edge_sing[2] && !edge_sing[1] && edge_sing[0])
+            {
+              if(point_sing[p[2]-1] <= edge_sing[0] ) 
+                { 
+                  if(point_sing[p[1]-1]<= edge_sing[2]) type = HP_TRIG_SINGEDGES; 
+                  else type = HP_TRIG_SINGEDGES2; 
+                } 
+              else 
+                {
+                  if(point_sing[p[1]-1]<= edge_sing[2]) 
+                    type = HP_TRIG_SINGEDGES3; 
+                  else type = HP_TRIG_SINGEDGES23; 
+                }
+            }
+          else if (edge_sing[2] && edge_sing[1] && edge_sing[0])
+            type = HP_TRIG_3SINGEDGES; 
+     
+      //  cout << " run for " <<  j << " gives type " << type << endl; 
+      //*testout << " run for " <<  j << " gives type " << type << endl; 
+
+      if(type!=HP_NONE) break;
+    }
+
+  *testout << "type = " << type << endl;
+    
+  for(int k=0;k<3;k++) el[k] = pnums[k]; 
+  /*if(type != HP_NONE) 
+    {
+     
+    cout << " TRIG with pnums " << pnums[0] << "\t"  << 
+    pnums[1] << "\t"  << pnums[2] << endl; 
+    cout << " type "  << type << endl; 
+    }
+  */
+      return(type);
+}
+#ifdef HPREF_OLD 
+HPREF_ELEMENT_TYPE ClassifyTrig(HPRefElement & el, INDEX_2_HASHTABLE<int> & edges, INDEX_2_HASHTABLE<int> & edgepoint_dom, 
+				BitArray & cornerpoint, BitArray & edgepoint, INDEX_3_HASHTABLE<int> & faces, INDEX_2_HASHTABLE<int> & face_edges, 
+				INDEX_2_HASHTABLE<int> & surf_edges, Array<int, PointIndex::BASE> & facepoint, int dim, const FaceDescriptor & fd)
+{
+  HPREF_ELEMENT_TYPE type = HP_NONE; 
+  
+  int pnums[3]; 
+	      
+  INDEX_3 i3 (el.pnums[0], el.pnums[1], el.pnums[2]);
+  i3.Sort();
+  bool sing_face = faces.Used (i3);
+   
+  
+  for (int 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));
+      
+      if (dim == 2)
+	{
+	  // JS, Dec 11
+	  ep1 = edgepoint_dom.Used (INDEX_2 (fd.SurfNr(), el.PNumMod(j))) ||
+	    edgepoint_dom.Used (INDEX_2 (-1, el.PNumMod(j)));
+	  ep2 = edgepoint_dom.Used (INDEX_2 (fd.SurfNr(), el.PNumMod(j+1))) ||
+	    edgepoint_dom.Used (INDEX_2 (-1, el.PNumMod(j+1)));
+	  ep3 = edgepoint_dom.Used (INDEX_2 (fd.SurfNr(), el.PNumMod(j+2))) ||
+	    edgepoint_dom.Used (INDEX_2 (-1, el.PNumMod(j+2)));
+	  /*
+            ep1 = edgepoint_dom.Used (INDEX_2 (el.index, el.PNumMod(j)));
+            ep2 = edgepoint_dom.Used (INDEX_2 (el.index, el.PNumMod(j+1)));
+            ep3 = edgepoint_dom.Used (INDEX_2 (el.index, el.PNumMod(j+2)));
+	  */
+	  // ep3 = edgepoint_dom.Used (INDEX_2 (mesh.SurfaceElement(i).GetIndex(), 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));
+      
+      ep1 |= cp1;
+      ep2 |= cp2;
+      ep3 |= cp3;
+      
+      
+      // (*testout) << "cp = " << cp1 << cp2 << cp3 << ", ep = " << ep1 << ep2 << ep3 << endl;
+
+      int p[3] = { el.PNumMod (j), el.PNumMod (j+1), el.PNumMod (j+2)};
+      if(ep1)
+	{
+	  INDEX_2 i2a=INDEX_2::Sort(p[0], p[1]); 
+	  INDEX_2 i2b=INDEX_2::Sort(p[0], p[2]); 
+	  if(!edges.Used(i2a) && !edges.Used(i2b)) 
+	    cp1 = 1; 
+	}
+      if(ep2)
+	{
+	  INDEX_2 i2a=INDEX_2::Sort(p[1], p[0]); 
+	  INDEX_2 i2b=INDEX_2::Sort(p[1], p[2]); 
+	  if(!edges.Used(i2a) && !edges.Used(i2b)) 
+	    cp2 = 1; 
+	}
+      if(ep3)
+	{
+	  INDEX_2 i2a=INDEX_2::Sort(p[2], p[0]); 
+	  INDEX_2 i2b=INDEX_2::Sort(p[2], p[1]); 
+	  if(!edges.Used(i2a) && !edges.Used(i2b)) 
+	    cp3= 1; 
+	}		      
+      
+      
+      int isedge1=0, isedge2=0, isedge3=0; 
+      if(dim == 3 )
+	{
+	  INDEX_2 i2;
+	  i2 = INDEX_2(el.PNumMod (j), el.PNumMod (j+1));
+	  isedge1 = edges.Used (i2);
+	  i2.Sort();
+	  if(surf_edges.Used(i2) &&  surf_edges.Get(i2)   != fd.SurfNr()+1 && 
+	     (face_edges.Get(i2) == -1 || face_edges.Get(i2) == fd.DomainIn() || face_edges.Get(i2) == fd.DomainOut()) ) 
+	    {
+	      isedge1=1;
+	      ep1 = 1; ep2=1;
+	    }
+	  
+	  i2 = INDEX_2(el.PNumMod (j+1), el.PNumMod (j+2));
+	  isedge2 = edges.Used (i2);
+	  i2.Sort();
+	  if(surf_edges.Used(i2) &&  surf_edges.Get(i2)   != fd.SurfNr()+1 &&
+	     (face_edges.Get(i2) == -1 || face_edges.Get(i2) == fd.DomainIn() || face_edges.Get(i2) == fd.DomainOut()) ) 
+	    {
+	      isedge2=1;
+	      ep2 = 1; ep3=1;
+	    }
+	  i2 = INDEX_2(el.PNumMod (j+2), el.PNumMod (j+3));
+	  isedge3 = edges.Used (i2);
+	  i2.Sort();
+	  if(surf_edges.Used(i2) &&  surf_edges.Get(i2)   != fd.SurfNr()+1 && 
+	     (face_edges.Get(i2) == -1 || face_edges.Get(i2) == fd.DomainIn() || face_edges.Get(i2) == fd.DomainOut()) ) 
+	    {
+	      isedge3=1;
+	      ep1 = 1; ep3=1;
+	    }
+	  
+	  // cout << " isedge " << isedge1 << " \t " << isedge2 << " \t " << isedge3 << endl;  
+	
+	  if (!sing_face)
+            {
+              /*
+                if (!isedge1)  { cp1 |= ep1; cp2 |= ep2; }
+                if (!isedge2)  { cp2 |= ep2; cp3 |= ep3; }
+                if (!isedge3)  { cp3 |= ep3; cp1 |= ep1; }
+              */
+              ep1 |= facepoint [el.PNumMod(j)] != 0;
+              ep2 |= facepoint [el.PNumMod(j+1)] != 0;
+              ep3 |= facepoint [el.PNumMod(j+2)] != 0;
+	  
+	  
+              isedge1 |= face_edges.Used (INDEX_2::Sort (el.PNumMod(j), el.PNumMod(j+1)));
+              isedge2 |= face_edges.Used (INDEX_2::Sort (el.PNumMod(j+1), el.PNumMod(j+2)));
+              isedge3 |= face_edges.Used (INDEX_2::Sort (el.PNumMod(j+2), el.PNumMod(j+3)));
+            }
+	}
+      
+      if(dim ==2) 
+	{ 
+	  INDEX_2 i2;
+	  i2 = INDEX_2(el.PNumMod (j), el.PNumMod (j+1));
+	  i2.Sort();
+	  isedge1 = edges.Used (i2);
+	  if(isedge1)
+	    {
+	      ep1 = 1; ep2=1;
+	    }
+	  
+	  i2 = INDEX_2(el.PNumMod (j+1), el.PNumMod (j+2));
+	  i2.Sort();
+	  isedge2 = edges.Used (i2);
+	  if(isedge2)
+	    {
+	      ep2 = 1; ep3=1;
+	    }
+	  i2 = INDEX_2(el.PNumMod (j+2), el.PNumMod (j+3));
+	  i2.Sort();
+	  isedge3 = edges.Used (i2);
+	  if(isedge3)
+	    {
+	      ep1 = 1; ep3=1;
+	    }
+	  
+	  
+	}
+      
+		  
+      /*
+        cout << " used " << face_edges.Used (INDEX_2::Sort (el.PNumMod(j), el.PNumMod(j+1))) << endl; 
+
+        cout << " isedge " << isedge1 << " \t " << isedge2 << " \t " << isedge3 << endl; 
+        cout << " ep " << ep1 << "\t" << ep2 << " \t " << ep3 << endl; 
+        cout << " cp " << cp1 << "\t" << cp2 << " \t " << cp3 << endl; 
+      */
+		  
+
+      
+      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)
+	    {
+	      if (dim == 2)
+                type = HP_TRIG_SINGCORNER123_2D;
+	      else
+		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;
+	}
+    }
+  
+  for(int k=0;k<3;k++) el[k] = pnums[k]; 
+  /*if(type != HP_NONE) 
+    {
+     
+    cout << " TRIG with pnums " << pnums[0] << "\t"  << 
+    pnums[1] << "\t"  << pnums[2] << endl; 
+    cout << " type "  << type << endl; 
+    }
+  */
+  return(type);
+}
+#endif
+HPREF_ELEMENT_TYPE ClassifyQuad(HPRefElement & el, INDEX_2_HASHTABLE<int> & edges, INDEX_2_HASHTABLE<int> & edgepoint_dom, 
+                                BitArray & cornerpoint, BitArray & edgepoint, INDEX_3_HASHTABLE<int> & faces, INDEX_2_HASHTABLE<int>  & face_edges, 
+				INDEX_2_HASHTABLE<int> & surf_edges, Array<int, PointIndex::BASE> & facepoint, int dim, const FaceDescriptor & fd)
+{
+  HPREF_ELEMENT_TYPE type = HP_NONE; 
+  
+  int ep1(-1), ep2(-1), ep3(-1), ep4(-1), cp1(-1), cp2(-1), cp3(-1), cp4(-1);
+  int isedge1, isedge2, isedge3, isedge4;
+
+  *testout << "edges = " << edges << endl;
+  
+  for (int j = 1; j <= 4; j++)
+    {
+      ep1 = edgepoint.Test (el.PNumMod (j));
+      ep2 = edgepoint.Test (el.PNumMod (j+1));
+      ep3 = edgepoint.Test (el.PNumMod (j+2));
+      ep4 = edgepoint.Test (el.PNumMod (j+3));
+
+      if (dim == 2)
+        {
+          ep1 = edgepoint_dom.Used (INDEX_2 (el.GetIndex(), el.PNumMod(j)));
+          ep2 = edgepoint_dom.Used (INDEX_2 (el.GetIndex(), el.PNumMod(j+1)));
+          ep3 = edgepoint_dom.Used (INDEX_2 (el.GetIndex(), el.PNumMod(j+2)));
+          ep4 = edgepoint_dom.Used (INDEX_2 (el.GetIndex(), el.PNumMod(j+3)));
+        }
+
+      cp1 = cornerpoint.Test (el.PNumMod (j));
+      cp2 = cornerpoint.Test (el.PNumMod (j+1));
+      cp3 = cornerpoint.Test (el.PNumMod (j+2));
+      cp4 = cornerpoint.Test (el.PNumMod (j+3));
+
+      ep1 |= cp1;
+      ep2 |= cp2;
+      ep3 |= cp3;
+      ep4 |= cp4;
+		
+      int p[4] = { el.PNumMod (j), el.PNumMod (j+1), el.PNumMod (j+2), el.PNumMod(j+4)};
+      //int epp[4] = { ep1, ep2, ep3, ep4}; 
+      int cpp[4] = { cp1, cp2, cp3, cp4};
+      for(int k=0;k<0;k++)
+        {
+          INDEX_2 i2a=INDEX_2::Sort(p[k], p[(k+1)%4]); 
+          INDEX_2 i2b=INDEX_2::Sort(p[k], p[(k-1)%4]); 
+          if(!edges.Used(i2a) && !edges.Used(i2b)) 
+            cpp[k] = 1; 
+        }
+      cp1= cpp[0]; cp2=cpp[1]; cp3=cpp[2]; cp4=cpp[3];
+		  
+
+      if(dim ==3) 
+        { 
+          INDEX_2 i2;
+          i2 = INDEX_2(el.PNumMod (j), el.PNumMod (j+1));
+          // i2.Sort();
+          isedge1 = edges.Used (i2);
+          i2.Sort();
+          if(surf_edges.Used(i2)  &&  surf_edges.Get(i2)   != fd.SurfNr()+1 && 
+             (face_edges.Get(i2) == -1 || face_edges.Get(i2) == fd.DomainIn() || face_edges.Get(i2) == fd.DomainOut()) ) 
+            {
+              isedge1=1;
+              ep1 = 1; ep2=1;
+            }
+          i2 = INDEX_2(el.PNumMod (j+1), el.PNumMod (j+2));
+          // i2.Sort();
+          isedge2 = edges.Used (i2);
+          i2.Sort();
+          if(surf_edges.Used(i2)  &&  surf_edges.Get(i2)   != fd.SurfNr()+1 && 
+             (face_edges.Get(i2) == -1 || face_edges.Get(i2) == fd.DomainIn() || face_edges.Get(i2) == fd.DomainOut()) ) 
+            {  
+              isedge2=1;
+              ep2=1; ep3=1;
+            }
+          i2 = INDEX_2(el.PNumMod (j+2), el.PNumMod (j+3));
+          // i2.Sort();
+          isedge3 = edges.Used (i2); 
+          i2.Sort();
+          if(surf_edges.Used(i2)   &&  surf_edges.Get(i2)   != fd.SurfNr()+1 && (face_edges.Get(i2) == -1 || face_edges.Get(i2) == fd.DomainIn() || face_edges.Get(i2) == fd.DomainOut()) ) 
+            {
+              isedge3=1;
+              ep3=1; ep4=1;
+            }
+          i2 = INDEX_2(el.PNumMod (j+3), el.PNumMod (j+4));
+          // i2.Sort();
+          isedge4 = edges.Used (i2);
+          i2.Sort();
+          if(surf_edges.Used(i2)  &&  surf_edges.Get(i2)   != fd.SurfNr()+1 && 
+             (face_edges.Get(i2) == -1 || face_edges.Get(i2) == fd.DomainIn() || face_edges.Get(i2) == fd.DomainOut()) ) 
+            { 
+              isedge4=1;
+              ep4=1; ep1=1;
+            } 
+		    
+
+          //MH***********************************************************************************************************
+          if(ep1)
+            if(edgepoint.Test(p[0]))
+              {
+                INDEX_2 i2a=INDEX_2::Sort(p[0], p[1]); 
+                INDEX_2 i2b=INDEX_2::Sort(p[0], p[3]); 
+                if(!edges.Used(i2a) && !edges.Used(i2b)) 
+                  cp1 = 1; 
+              }
+          if(ep2)
+            if(edgepoint.Test(p[1]))
+              {
+                INDEX_2 i2a=INDEX_2::Sort(p[0], p[1]); 
+                INDEX_2 i2b=INDEX_2::Sort(p[1], p[2]); 
+                if(!edges.Used(i2a) && !edges.Used(i2b)) 
+                  cp2 = 1; 
+              }
+          if(ep3)
+            if(edgepoint.Test(p[2]))
+              {
+                INDEX_2 i2a=INDEX_2::Sort(p[2], p[1]); 
+                INDEX_2 i2b=INDEX_2::Sort(p[3], p[2]); 
+                if(!edges.Used(i2a) && !edges.Used(i2b)) 
+                  cp3 = 1; 
+              }
+          if(ep4)
+            if(edgepoint.Test(p[3]))
+              {
+                INDEX_2 i2a=INDEX_2::Sort(p[0], p[3]); 
+                INDEX_2 i2b=INDEX_2::Sort(p[3], p[2]); 
+                if(!edges.Used(i2a) && !edges.Used(i2b)) 
+                  cp4 = 1; 
+              }
+          //MH*****************************************************************************************************************************
+        }
+      else
+        { 
+          INDEX_2 i2;
+          i2 = INDEX_2(el.PNumMod (j), el.PNumMod (j+1));
+          i2.Sort();
+          isedge1 = edges.Used (i2);
+          if(isedge1)
+            {
+              ep1 = 1; ep2=1;
+            }
+          i2 = INDEX_2(el.PNumMod (j+1), el.PNumMod (j+2));
+          i2.Sort();
+          isedge2 = edges.Used (i2);
+          if(isedge2)
+            {  
+              ep2=1; ep3=1;
+            }
+          i2 = INDEX_2(el.PNumMod (j+2), el.PNumMod (j+3));
+          i2.Sort();
+          isedge3 = edges.Used (i2); 
+		      
+          if(isedge3)
+            {
+              ep3=1; ep4=1;
+            }
+          i2 = INDEX_2(el.PNumMod (j+3), el.PNumMod (j+4));
+          i2.Sort();
+          isedge4 = edges.Used (i2);
+          if(isedge4)
+            { 
+              ep4=1; ep1=1;
+            } 
+        }
+
+      int sumcp = cp1 + cp2 + cp3 + cp4;
+      int sumep = ep1 + ep2 + ep3 + ep4;
+      int sumedge = isedge1 + isedge2 + isedge3 + isedge4;
+
+      *testout << "isedge = " << isedge1 << isedge2 << isedge3 << isedge4 << endl;
+      *testout << "iscp = " << cp1 << cp2 << cp3 << cp4 << endl;
+      *testout << "isep = " << ep1 << ep2 << ep3 << ep4 << endl;
+
+      switch (sumedge)
+        {
+        case 0:
+          {
+            switch (sumep)
+              {
+              case 0: 
+                type = HP_QUAD; 
+                break;
+              case 1: 
+                if (ep1) type = HP_QUAD_SINGCORNER;
+                break; 
+              case 2:
+                {
+                  if (ep1 && ep2) type = HP_QUAD_0E_2VA;
+                  if (ep1 && ep3) type = HP_QUAD_0E_2VB;
+                  break;
+                }
+              case 3: 
+                if (!ep4) type = HP_QUAD_0E_3V; 
+                break; 
+              case 4: 
+                type = HP_QUAD_0E_4V; 
+                break; 
+              }
+            break;
+          }
+        case 1:
+          {
+            if (isedge1)
+              {
+                switch (cp1+cp2+ep3+ep4)
+                  {
+                  case 0: 
+                    type = HP_QUAD_SINGEDGE; 
+                    break;
+                  case 1:
+                    {
+                      if (cp1) type = HP_QUAD_1E_1VA;
+                      if (cp2) type = HP_QUAD_1E_1VB;
+                      if (ep3) type = HP_QUAD_1E_1VC;
+                      if (ep4) type = HP_QUAD_1E_1VD; 
+                      break; 
+                    }
+                  case 2:
+                    {
+                      if (cp1 && cp2) type = HP_QUAD_1E_2VA; 
+                      if (cp1 && ep3) type = HP_QUAD_1E_2VB; 
+                      if (cp1 && ep4) type = HP_QUAD_1E_2VC; 
+                      if (cp2 && ep3) type = HP_QUAD_1E_2VD; 
+                      if (cp2 && ep4) type = HP_QUAD_1E_2VE; 
+                      if (ep3 && ep4) type = HP_QUAD_1E_2VF; 
+                      break; 
+                    }
+                  case 3:
+                    {
+                      if (cp1 && cp2 && ep3) type = HP_QUAD_1E_3VA;
+                      if (cp1 && cp2 && ep4) type = HP_QUAD_1E_3VB;
+                      if (cp1 && ep3 && ep4) type = HP_QUAD_1E_3VC;
+                      if (cp2 && ep3 && ep4) type = HP_QUAD_1E_3VD;
+                      break;
+                    }
+                  case 4:
+                    {
+                      type = HP_QUAD_1E_4V; 
+                      break;
+                    }
+                  }
+              }
+            break;
+          }
+        case 2:
+          {
+            if (isedge1 && isedge4)
+              {
+                if (!cp2 && !ep3 && !cp4)
+                  type = HP_QUAD_2E;
+			  
+                if (cp2 && !ep3 && !cp4)
+                  type = HP_QUAD_2E_1VA;
+                if (!cp2 && ep3 && !cp4)
+                  type = HP_QUAD_2E_1VB;
+                if (!cp2 && !ep3 && cp4)
+                  type = HP_QUAD_2E_1VC;
+
+                if (cp2 && ep3 && !cp4)
+                  type = HP_QUAD_2E_2VA;
+                if (cp2 && !ep3 && cp4)
+                  type = HP_QUAD_2E_2VB;
+                if (!cp2 && ep3 && cp4)
+                  type = HP_QUAD_2E_2VC;
+
+                if (cp2 && ep3 && cp4)
+                  type = HP_QUAD_2E_3V;
+              }
+            if (isedge1 && isedge3)
+              {
+                switch (sumcp)
+                  {
+                  case 0: 
+                    type = HP_QUAD_2EB_0V; break;
+                  case 1:
+                    {
+                      if (cp1) type = HP_QUAD_2EB_1VA; 
+                      if (cp2) type = HP_QUAD_2EB_1VB; 
+                      break;
+                    }
+                  case 2:
+                    {
+                      if (cp1 && cp2) { type = HP_QUAD_2EB_2VA; }
+                      if (cp1 && cp3) { type = HP_QUAD_2EB_2VB; }
+                      if (cp1 && cp4) { type = HP_QUAD_2EB_2VC; }
+                      if (cp2 && cp4) { type = HP_QUAD_2EB_2VD; }
+                      break;
+                    }
+                  case 3:
+                    {
+                      if (cp1 && cp2 && cp3) { type = HP_QUAD_2EB_3VA; }
+                      if (cp1 && cp2 && cp4) { type = HP_QUAD_2EB_3VB; }
+                      break;
+                    }
+                  case 4:
+                    {
+                      type = HP_QUAD_2EB_4V; break;
+                    }
+                  }
+              }
+            break;
+          }
+
+        case 3:
+          {
+            if (isedge1 && isedge2 && isedge4)
+              {
+                if (!cp3 && !cp4) type = HP_QUAD_3E;
+                if (cp3 && !cp4) type = HP_QUAD_3E_3VA;
+                if (!cp3 && cp4) type = HP_QUAD_3E_3VB;
+                if (cp3 && cp4) type = HP_QUAD_3E_4V;
+              }
+            break;
+          }
+
+        case 4:
+          {
+            type = HP_QUAD_4E;
+            break;
+          }
+        }
+
+      if (type != HP_NONE)
+        {
+          int pnums[4]; 
+          pnums[0] = el.PNumMod (j); 
+          pnums[1] = el.PNumMod (j+1);
+          pnums[2] = el.PNumMod (j+2); 
+          pnums[3] = el.PNumMod (j+3);
+          for (int k=0;k<4;k++) el[k] = pnums[k]; 
+	
+          /*  cout << " QUAD with pnums " << pnums[0] << "\t"  << 
+              pnums[1] << "\t"  << pnums[2] << "\t"  << pnums[3] 
+              << endl << " of type " << type << endl; */
+		   		      
+          break;
+        }
+    }
+  if (type == HP_NONE)
+    {
+      (*testout) << "undefined element" << endl
+                 << "cp = " << cp1 << cp2 << cp3 << cp4 << endl
+                 << "ep = " << ep1 << ep2 << ep3 << ep4 << endl
+                 << "isedge = " << isedge1 << isedge2 << isedge3 
+                 << isedge4 << endl;
+    }
+	    
+  *testout << "quad type = " << type << endl;
+
+  return type;  
+}	    
+
+
+HPREF_ELEMENT_TYPE ClassifyHex(HPRefElement & el, INDEX_2_HASHTABLE<int> & edges, INDEX_2_HASHTABLE<int> & edgepoint_dom, 
+                               BitArray & cornerpoint, BitArray & edgepoint, INDEX_3_HASHTABLE<int> & faces, INDEX_2_HASHTABLE<int> & face_edges, 
+                               INDEX_2_HASHTABLE<int> & surf_edges, Array<int, PointIndex::BASE> & facepoint)
+{
+  HPREF_ELEMENT_TYPE type = HP_NONE;
+  
+  // implementation only for HP_HEX_1F_0E_0V
+  //                         HP_HEX_1FA_1FB_0E_0V
+  //                         HP_HEX 
+  // up to now other cases are refine dummies 
+  
+  // indices of bot,top-faces combinations
+  int index[6][2] = {{0,1},{1,0},{2,4},{4,2},{3,5},{5,3}}; 
+  int p[8]; 
+  const ELEMENT_FACE * elfaces  = MeshTopology::GetFaces1 (HEX);
+  const ELEMENT_EDGE * eledges = MeshTopology::GetEdges1 (HEX);
+  
+  for(int m=0;m<6 && type == HP_NONE;m++) 
+    for(int j=0;j<4 && type == HP_NONE;j++) 
+      { 
+	int point_sing[8]={0,0,0,0,0,0,0,0}; 
+	int face_sing[6] = {0,0,0,0,0,0};
+	int edge_sing[12] = {0,0,0,0,0,0,0,0,0,0,0,0};
+	int spoint=0, sface=0, sedge=0; 
+	for(int l=0;l<4;l++) 
+	  {
+	    p[l] = elfaces[index[m][0]][(4-j-l)%4]; 
+	    p[l+4] = elfaces[index[m][1]][(j+l)%4];
+	  }
+	
+	for(int l=0;l<8;l++) 
+	  if(cornerpoint.Test(el.PNum(p[l])))  
+	    { 
+	      point_sing[p[l]-1]=3;
+	      spoint++; 
+	    }
+	  else if(edgepoint.Test(el.PNum(p[l]))) point_sing[p[l]-1]=2;
+	  else if (facepoint[el.PNum(p[l])] == -1 || facepoint[el.PNum(p[l])] == el.GetIndex())
+	    point_sing[p[l]-1] = 1;   
+	
+	for(int k=0;k<12;k++)
+          {
+            INDEX_2 i2 = INDEX_2 :: Sort(el.PNum(p[eledges[k][0]-1]),el.PNum(p[eledges[k][1]-1])); 
+            if (edges.Used(i2)) 
+              { 
+                edge_sing[k] = 2;
+                sedge++; 
+              }
+            else edge_sing[k] = face_edges.Used(i2);
+          }
+	
+	for (int k=0;k<6;k++)
+          {
+            INDEX_3 i3; 
+	  
+	
+            INDEX_4  i4 = INDEX_4(el.pnums[p[elfaces[k][0]-1]-1], el.pnums[p[elfaces[k][1]-1]-1], el.pnums[p[elfaces[k][2]-1]-1],el.pnums[p[elfaces[k][3]-1]-1]); 
+            i4.Sort();
+            i3 = INDEX_3(i4.I1(), i4.I2(), i4.I3()); 
+	  
+            if (faces.Used (i3))
+              {
+	      
+                int domnr = faces.Get(i3); 
+                if (domnr == -1 || domnr == el.GetIndex())
+                  {
+                    face_sing[k] = 1;
+                    sface++;
+                  }
+	      
+              } 
+          } 
+	
+	if(!sface && !sedge && !spoint) type = HP_HEX; 
+	if(!sedge && !spoint) 
+	  {
+	    if(face_sing[0] && face_sing[2] && sface==2) 
+	      type = HP_HEX_1FA_1FB_0E_0V; 
+	    if (face_sing[0] && sface==1)  
+	      type = HP_HEX_1F_0E_0V; 
+	  }
+	
+	el.type=type; 
+
+	if(type != HP_NONE) 
+	  {
+	    int pnums[8]; 
+	    for(int l=0;l<8;l++) pnums[l] = el[p[l]-1];
+	    for(int l=0;l<8;l++) el[l] = pnums[l];
+	    /* cout << " HEX with pnums " << pnums[0] << "\t"  << 
+               pnums[1] << "\t"  << pnums[2] << "\t"  << pnums[3] << "\t"  << 
+               pnums[4] << "\t"  <<  pnums[5] << endl << " of type " << type << endl; */
+	    break; 
+	  }
+      }
+  
+  return (type); 
+
+}
+
+HPREF_ELEMENT_TYPE ClassifySegm(HPRefElement & hpel, INDEX_2_HASHTABLE<int> & edges, INDEX_2_HASHTABLE<int> & edgepoint_dom, 
+                                BitArray & cornerpoint, BitArray & edgepoint, INDEX_3_HASHTABLE<int> & faces, INDEX_2_HASHTABLE<int> & face_edges, 
+                                INDEX_2_HASHTABLE<int> & surf_edges, Array<int, PointIndex::BASE> & facepoint)
+{
+  
+  int cp1 = cornerpoint.Test (hpel[0]);
+  int cp2 = cornerpoint.Test (hpel[1]);
+  
+  INDEX_2 i2;
+  i2 = INDEX_2(hpel[0], hpel[1]);
+  i2.Sort();
+  if (!edges.Used (i2))
+    {
+      cp1 = edgepoint.Test (hpel[0]);
+      cp2 = edgepoint.Test (hpel[1]);
+    }
+  
+  if(!edges.Used(i2) && !face_edges.Used(i2))
+    {
+      if(facepoint[hpel[0]]!=0) cp1=1; 
+      if(facepoint[hpel[1]]!=0) cp2=1; 
+    }
+  
+  if(edges.Used(i2) && !face_edges.Used(i2))
+    {
+      if(facepoint[hpel[0]]) cp1 = 1; 
+      if(facepoint[hpel[1]]) cp2 = 1; 
+    }
+  
+  if (!cp1 && !cp2)
+    hpel.type = HP_SEGM;
+  else if (cp1 && !cp2)
+    hpel.type = HP_SEGM_SINGCORNERL;
+  else if (!cp1 && cp2)
+    hpel.type = HP_SEGM_SINGCORNERR;
+  else
+    hpel.type = HP_SEGM_SINGCORNERS;
+  
+  // cout << " SEGM found with " << hpel[0] << " \t" << hpel[1] << endl << " of type " << hpel.type << endl; 
+  return(hpel.type) ; 
+} 
+
+
+HPREF_ELEMENT_TYPE ClassifyPyramid(HPRefElement & el, INDEX_2_HASHTABLE<int> & edges, INDEX_2_HASHTABLE<int> & edgepoint_dom, 
+                                   BitArray & cornerpoint, BitArray & edgepoint, INDEX_3_HASHTABLE<int> & faces, INDEX_2_HASHTABLE<int> & face_edges, 
+                                   INDEX_2_HASHTABLE<int> & surf_edges, Array<int, PointIndex::BASE> & facepoint)
+{
+  HPREF_ELEMENT_TYPE type = HP_NONE;
+  
+  // implementation only for HP_PYRAMID
+  //                         HP_PYRAMID_0E_1V
+  //                         HP_PYRAMID_EDGES
+  //                         HP_PYRAMID_1FB_0E_1VA
+  // up to now other cases are refine dummies 
+  
+  // indices of bot,top-faces combinations
+  // int index[6][2] = {{0,1},{1,0},{2,4},{4,2},{3,5},{5,3}}; 
+
+  const ELEMENT_FACE * elfaces  = MeshTopology::GetFaces1 (PYRAMID);
+  const ELEMENT_EDGE * eledges = MeshTopology::GetEdges1 (PYRAMID);
+  
+  int point_sing[5]={0,0,0,0,0}; 
+  int face_sing[5] = {0,0,0,0,0};
+  int edge_sing[8] = {0,0,0,0,0,0,0,0};
+  
+  int spoint=0, sedge=0, sface=0; 
+   
+  for(int m=0;m<4 && type == HP_NONE;m++) 
+    {
+      int p[5] = {m%4, m%4+1, m%4+2, m%4+3, 4}; 
+
+      for(int l=0;l<5;l++) 
+	{
+	  if(cornerpoint.Test(el.pnums[p[l]]))  
+	    point_sing[l]=3;
+	  
+          else if(edgepoint.Test(el.pnums[p[l]]))
+	    point_sing[l]=2;
+	  
+	  else if (facepoint[el.pnums[p[l]]] == -1 || facepoint[el.pnums[p[l]]] == el.GetIndex())
+	    point_sing[l] = 1;   
+	  
+	  spoint += point_sing[l]; 
+	}
+      
+      for(int k=0;k<8;k++)
+	{
+	  INDEX_2 i2 = INDEX_2 :: Sort(el.pnums[p[eledges[k][0]-1]],
+				       el.pnums[p[eledges[k][1]-1]]); 
+	  if (edges.Used(i2)) 
+	    edge_sing[k] = 2;
+	  else 
+	    edge_sing[k] = face_edges.Used(i2);
+	  
+	  sedge += edge_sing[k]; 
+	}
+  
+      for (int k=0;k<5;k++)
+	{
+	  INDEX_3 i3; 
+	  INDEX_4  i4 = INDEX_4(el.pnums[p[elfaces[k][0]-1]], el.pnums[p[elfaces[k][1]-1]], el.pnums[p[elfaces[k][2]-1]],
+				el.pnums[p[elfaces[k][3]-1]]); 
+	  i4.Sort();
+	  i3 = INDEX_3(i4.I1(), i4.I2(), i4.I3()); 
+	  
+	  if (faces.Used (i3))
+	    {
+	      
+	      int domnr = faces.Get(i3); 
+	      if (domnr == -1 || domnr == el.GetIndex())
+		face_sing[k] = 1;
+	    } 
+	  sface +=face_sing[k]; 
+	} 
+  
+      if(!sface && !spoint && !sedge) return(HP_PYRAMID); 
+      
+      if(!sface && !sedge && point_sing[p[0]] == spoint) 
+	type = HP_PYRAMID_0E_1V; 
+      
+      if(!sface && edge_sing[0] + edge_sing[2] == sedge && 
+	 spoint == point_sing[0] + point_sing[1] + point_sing[3]) 
+	type = HP_PYRAMID_EDGES; 
+      
+      if(sface && sface == face_sing[0] && spoint == point_sing[4] + 2)
+	type = HP_PYRAMID_1FB_0E_1VA; 
+      
+      
+      if(type != HP_NONE) 
+	{ 
+	  int pnums[8]; 
+	  for(int l=0;l<5;l++) pnums[l] = el[p[l]];
+	  for(int l=0;l<5;l++) el[l] = pnums[l];
+	  el.type=type; 
+	  break; 
+	} 
+    }
+  
+  return (type); 
+  
+}
diff --git a/contrib/Netgen/libsrc/meshing/clusters.cpp b/contrib/Netgen/libsrc/meshing/clusters.cpp
new file mode 100644
index 0000000000..e89def6a85
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/clusters.cpp
@@ -0,0 +1,267 @@
+#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();
+
+    bool hasedges = top.HasEdges();
+    bool hasfaces = top.HasFaces();
+
+    if (!hasedges || !hasfaces) return;
+
+    if (id == 0)
+      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) = -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 hex_cluster[] =
+      { 
+	1, 2, 3, 4, 1, 2, 3, 4, 
+	5, 6, 7, 8, 5, 6, 7, 8, 1, 2, 3, 4, 
+	9, 9, 5, 8, 6, 7, 
+	9
+      };
+
+    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 HEX: 
+		clustertab = hex_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/contrib/Netgen/libsrc/meshing/clusters.hpp b/contrib/Netgen/libsrc/meshing/clusters.hpp
new file mode 100644
index 0000000000..fa0de93a4a
--- /dev/null
+++ b/contrib/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/contrib/Netgen/libsrc/meshing/curvedelems.cpp b/contrib/Netgen/libsrc/meshing/curvedelems.cpp
new file mode 100644
index 0000000000..df17cf1917
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/curvedelems.cpp
@@ -0,0 +1,3581 @@
+#include <mystdlib.h>
+
+#include "meshing.hpp"
+
+#include "../general/autodiff.hpp"
+
+
+namespace netgen
+{
+  
+  //   bool rational = true;
+
+
+  
+  static 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);
+      }
+  }
+  
+  
+
+  // compute edge bubbles up to order n, x \in (-1, 1)
+  static void CalcEdgeShape (int n, double x, double * shape)
+  {
+    double p1 = x, p2 = -1, p3 = 0;
+    for (int j=2; j<=n; j++)
+      {
+	p3=p2; p2=p1;
+	p1=( (2*j-3) * x * p2 - (j-3) * p3) / j;
+	shape[j-2] = p1;
+      } 
+  }
+
+  static void CalcEdgeDx (int n, double x, double * dshape)
+  {
+    double p1 = x, p2 = -1, p3 = 0;
+    double p1dx = 1, p2dx = 0, p3dx = 0;
+
+    for (int j=2; j<=n; j++)
+      {
+	p3=p2; p2=p1;
+	p3dx = p2dx; p2dx = p1dx;
+
+	p1=( (2*j-3) * x * p2 - (j-3) * p3) / j;
+	p1dx = ( (2*j-3) * (x * p2dx + p2) - (j-3) * p3dx) / j;
+
+	dshape[j-2] = p1dx;
+      }    
+  }
+
+  static void CalcEdgeShapeDx (int n, double x, double * shape, double * dshape)
+  {
+    double p1 = x, p2 = -1, p3 = 0;
+    double p1dx = 1, p2dx = 0, p3dx = 0;
+
+    for (int j=2; j<=n; j++)
+      {
+	p3=p2; p2=p1;
+	p3dx = p2dx; p2dx = p1dx;
+
+	p1=( (2*j-3) * x * p2 - (j-3) * p3) / j;
+	p1dx = ( (2*j-3) * (x * p2dx + p2) - (j-3) * p3dx) / j;
+
+	shape[j-2] = p1;
+	dshape[j-2] = p1dx;
+      }    
+  }
+
+  // compute L_i(x/t) * t^i
+  static void CalcScaledEdgeShape (int n, double x, double t, double * shape)
+  {
+    static bool init = false;
+    static double coefs[100][2];
+    if (!init)
+      {
+        for (int j = 0; j < 100; j++)
+          {
+            coefs[j][0] = double(2*j+1)/(j+2);
+            coefs[j][1] = -double(j-1)/(j+2);
+          }
+        init = true;
+      }
+
+    double p1 = x, p2 = -1, p3 = 0;
+    double tt = t*t;
+    for (int j=0; j<=n-2; j++)
+      {
+	p3=p2; p2=p1;
+        p1= coefs[j][0] * x * p2 + coefs[j][1] * tt*p3;
+	// p1=( (2*j+1) * x * p2 - t*t*(j-1) * p3) / (j+2);
+	shape[j] = p1;
+      }    
+  }
+
+  template <int DIST>
+  static void CalcScaledEdgeShapeDxDt (int n, double x, double t, double * dshape)
+  {
+    double p1 = x, p2 = -1, p3 = 0;
+    double p1dx = 1, p1dt = 0;
+    double p2dx = 0, p2dt = 0;
+    double p3dx = 0, p3dt = 0;
+     
+    for (int j=0; j<=n-2; j++)
+      {
+	p3=p2; p3dx=p2dx; p3dt = p2dt;
+	p2=p1; p2dx=p1dx; p2dt = p1dt;
+
+	p1   = ( (2*j+1) * x * p2 - t*t*(j-1) * p3) / (j+2);
+	p1dx = ( (2*j+1) * (x * p2dx + p2) - t*t*(j-1) * p3dx) / (j+2);
+	p1dt = ( (2*j+1) * x * p2dt - (j-1)* (t*t*p3dt+2*t*p3)) / (j+2);
+
+	// shape[j] = p1;
+	dshape[DIST*j  ] = p1dx;
+	dshape[DIST*j+1] = p1dt;
+      }    
+  }
+
+
+  template <class Tx, class Tres>
+  static void LegendrePolynomial (int n, Tx x, Tres * values)
+  {
+    switch (n)
+      {
+      case 0:
+	values[0] = 1;
+	break;
+      case 1:
+	values[0] = 1;
+	values[1] = x;
+	break;
+
+      default:
+
+	if (n < 0) return;
+
+	Tx p1 = 1.0, p2 = 0.0, p3;
+	
+	values[0] = 1.0;
+	for (int j=1; j<=n; j++)
+	  {
+	    p3 = p2; p2 = p1;
+	    p1 = ((2.0*j-1.0)*x*p2 - (j-1.0)*p3) / j;
+	    values[j] = p1;
+	  }
+      }
+  }
+
+  template <class Tx, class Tt, class Tres>
+  static void ScaledLegendrePolynomial (int n, Tx x, Tt t, Tres * values)
+  {
+    switch (n)
+      {
+      case 0:
+	values[0] = 1.0;
+	break;
+
+      case 1:
+	values[0] = 1.0;
+	values[1] = x;
+	break;
+
+      default:
+
+	if (n < 0) return;
+
+	Tx p1 = 1.0, p2 = 0.0, p3;
+	values[0] = 1.0;
+	for (int j=1; j<=n; j++)
+	  {
+	    p3 = p2; p2 = p1;
+	    p1 = ((2.0*j-1.0)*x*p2 - t*t*(j-1.0)*p3) / j;
+	    values[j] = p1;
+	  }
+      }
+  }
+
+
+
+  template <class S, class T>
+  inline void JacobiPolynomial (int n, S x, double alpha, double beta, T * values)
+  {
+    S p1 = 1.0, p2 = 0.0, p3;
+
+    if (n >= 0) 
+      p2 = values[0] = 1.0;
+    if (n >= 1) 
+      p1 = values[1] = 0.5 * (2*(alpha+1)+(alpha+beta+2)*(x-1));
+
+    for (int i  = 1; i < n; i++)
+      {
+        p3 = p2; p2=p1;
+        p1 =
+          1.0 / ( 2 * (i+1) * (i+alpha+beta+1) * (2*i+alpha+beta) ) *
+          ( 
+           ( (2*i+alpha+beta+1)*(alpha*alpha-beta*beta) + 
+             (2*i+alpha+beta)*(2*i+alpha+beta+1)*(2*i+alpha+beta+2) * x) 
+           * p2
+           - 2*(i+alpha)*(i+beta) * (2*i+alpha+beta+2) * p3
+           );
+        values[i+1] = p1;
+      }
+  }
+
+
+
+
+  template <class S, class St, class T>
+  inline void ScaledJacobiPolynomial (int n, S x, St t, double alpha, double beta, T * values)
+  {
+    /*
+      S p1 = 1.0, p2 = 0.0, p3;
+
+      if (n >= 0) values[0] = 1.0;
+    */
+
+    S p1 = 1.0, p2 = 0.0, p3;
+
+    if (n >= 0) 
+      p2 = values[0] = 1.0;
+    if (n >= 1) 
+      p1 = values[1] = 0.5 * (2*(alpha+1)*t+(alpha+beta+2)*(x-t));
+
+    for (int i=1; i < n; i++)
+      {
+        p3 = p2; p2=p1;
+        p1 =
+          1.0 / ( 2 * (i+1) * (i+alpha+beta+1) * (2*i+alpha+beta) ) *
+          ( 
+           ( (2*i+alpha+beta+1)*(alpha*alpha-beta*beta) * t + 
+             (2*i+alpha+beta)*(2*i+alpha+beta+1)*(2*i+alpha+beta+2) * x) 
+           * p2
+           - 2*(i+alpha)*(i+beta) * (2*i+alpha+beta+2) * t * t * p3
+           );
+        values[i+1] = p1;
+      }
+  }
+
+
+
+
+
+  // compute face bubbles up to order n, 0 < y, y-x < 1, x+y < 1
+  template <class Tx, class Ty, class Ts>
+  static void CalcTrigShape (int n, Tx x, Ty y, Ts * shape)
+  { 
+    if (n < 3) return;
+    Tx hx[50], hy[50*50];
+    // ScaledLegendrePolynomial (n-3, 2*x-1, 1-y, hx);
+    ScaledJacobiPolynomial (n-3, x, 1-y, 2, 2, hx);
+
+
+    // LegendrePolynomial (n-3, 2*y-1, hy);
+    for (int ix = 0; ix <= n-3; ix++)
+      //  JacobiPolynomial (n-3, 2*y-1, 0, 0, hy+50*ix);
+      JacobiPolynomial (n-3, 2*y-1, 2*ix+5, 2, hy+50*ix);
+
+    int ii = 0;
+    Tx bub = (1+x-y)*y*(1-x-y);
+    for (int iy = 0; iy <= n-3; iy++)
+      for (int ix = 0; ix <= n-3-iy; ix++)
+	shape[ii++] = bub * hx[ix]*hy[iy+50*ix];
+  }
+
+
+
+  static void CalcTrigShapeDxDy (int n, double x, double y, double * dshape)
+  { 
+    if (n < 3) return;
+
+    AutoDiff<2> adx(x, 0);
+    AutoDiff<2> ady(y, 1);
+    AutoDiff<2> res[2000];
+    CalcTrigShape (n, adx, ady, &res[0]);
+    int ndof = (n-1)*(n-2)/2;
+    for (int i = 0; i < ndof; i++)
+      {
+	dshape[2*i] = res[i].DValue(0);
+	dshape[2*i+1] = res[i].DValue(1);
+      }
+
+    /*    
+	  if (n < 3) return;
+    
+          int ndof = (n-1)*(n-2)/2;
+          double h1[1000], h2[1000];
+          double eps = 1e-4;
+  
+          CalcTrigShape (n, x+eps, y, h1);
+          CalcTrigShape (n, x-eps, y, h2);
+
+          for (int i = 0; i < ndof; i++)
+          dshape[2*i] = (h1[i]-h2[i])/(2*eps);
+
+          CalcTrigShape (n, x, y+eps, h1);
+          CalcTrigShape (n, x, y-eps, h2);
+
+          for (int i = 0; i < ndof; i++)
+          dshape[2*i+1] = (h1[i]-h2[i])/(2*eps);
+    */
+  }
+
+
+
+
+
+
+
+
+  // compute face bubbles up to order n, 0 < y, y-x < 1, x+y < 1
+  template <class Tx, class Ty, class Tt, class Tr>
+  static void CalcScaledTrigShape (int n, Tx x, Ty y, Tt t, Tr * shape)
+  {
+    if (n < 3) return;
+
+    Tx hx[50], hy[50*50];
+    // ScaledLegendrePolynomial (n-3, (2*x-1), t-y, hx);
+    ScaledJacobiPolynomial (n-3, x, t-y, 2, 2, hx);
+
+    // ScaledLegendrePolynomial (n-3, (2*y-1), t, hy);
+    for (int ix = 0; ix <= n-3; ix++)
+      ScaledJacobiPolynomial (n-3, 2*y-1, t, 2*ix+5, 2, hy+50*ix);
+
+
+    int ii = 0;
+    Tx bub = (t+x-y)*y*(t-x-y);
+    for (int iy = 0; iy <= n-3; iy++)
+      for (int ix = 0; ix <= n-3-iy; ix++)
+	shape[ii++] = bub * hx[ix]*hy[iy+50*ix];
+  }
+
+
+  // compute face bubbles up to order n, 0 < y, y-x < 1, x+y < 1
+  static void CalcScaledTrigShapeDxDyDt (int n, double x, double y, double t, double * dshape)
+  {
+    if (n < 3) return;
+    AutoDiff<3> adx(x, 0);
+    AutoDiff<3> ady(y, 1);
+    AutoDiff<3> adt(t, 2);
+    AutoDiff<3> res[2000];
+    CalcScaledTrigShape (n, adx, ady, adt, &res[0]);
+    int ndof = (n-1)*(n-2)/2;
+    for (int i = 0; i < ndof; i++)
+      {
+	dshape[3*i] = res[i].DValue(0);
+	dshape[3*i+1] = res[i].DValue(1);
+	dshape[3*i+2] = res[i].DValue(2);
+      }
+
+    /*
+      double dshape1[6000];
+      if (n < 3) return;
+      double hvl[1000], hvr[1000];
+      int nd = (n-1)*(n-2)/2;
+    
+      double eps = 1e-6;
+
+      CalcScaledTrigShape (n, x-eps, y, t, hvl);
+      CalcScaledTrigShape (n, x+eps, y, t, hvr);
+      for (int i = 0; i < nd; i++)
+      dshape[3*i] = (hvr[i]-hvl[i])/(2*eps);
+
+      CalcScaledTrigShape (n, x, y-eps, t, hvl);
+      CalcScaledTrigShape (n, x, y+eps, t, hvr);
+      for (int i = 0; i < nd; i++)
+      dshape[3*i+1] = (hvr[i]-hvl[i])/(2*eps);
+
+      CalcScaledTrigShape (n, x, y, t-eps, hvl);
+      CalcScaledTrigShape (n, x, y, t+eps, hvr);
+      for (int i = 0; i < nd; i++)
+      dshape[3*i+2] = (hvr[i]-hvl[i])/(2*eps);
+    */
+
+    /*
+      for (int i = 0; i < 3*nd; i++)
+      if (fabs (dshape[i]-dshape1[i]) > 1e-8 * fabs(dshape[i]) + 1e-6)
+      {
+      cerr
+      cerr << "big difference: " << dshape1[i] << " != " << dshape[i] << endl;
+      }
+    */
+  }
+
+    
+
+  
+
+  CurvedElements :: CurvedElements (const Mesh & amesh)
+    : mesh (amesh)
+  {
+    order = 1;
+    rational = 0;
+    ishighorder = 0;
+  }
+
+
+  CurvedElements :: ~CurvedElements()
+  {
+    ;
+  }
+
+
+  void CurvedElements :: BuildCurvedElements(const Refinement * ref, int aorder,
+                                             bool arational)
+  {
+    order = aorder;
+    ishighorder = 0;
+
+    if (mesh.coarsemesh)
+      {
+	mesh.coarsemesh->GetCurvedElements().BuildCurvedElements (ref, aorder, arational);
+        order = aorder;
+        rational = arational;
+        ishighorder = (order > 1);
+	return;
+      }
+
+
+#ifdef PARALLEL
+    if (id > 0)
+      {
+	Array<int> master_edgeorder;
+	Array<int> master_edgecoeffsindex;
+	Array<Vec<3> > master_edgecoeffs;
+	Array<int> master_faceorder;
+	Array<int> master_facecoeffsindex;
+	Array<Vec<3> > master_facecoeffs;
+	    
+	MyMPI_Bcast (master_edgeorder, 0, mesh_comm);
+	MyMPI_Bcast (master_edgecoeffsindex, 0, mesh_comm);
+	MyMPI_Bcast (master_edgecoeffs, 0, mesh_comm);
+
+	if (mesh.GetDimension() == 3)
+	  {
+	    MyMPI_Bcast (master_faceorder, 0, mesh_comm);
+	    MyMPI_Bcast (master_facecoeffsindex, 0, mesh_comm);
+	    MyMPI_Bcast (master_facecoeffs, 0, mesh_comm);
+	  }
+
+
+	const MeshTopology & top = mesh.GetTopology();
+	const ParallelMeshTopology & partop = mesh.GetParallelTopology ();
+	
+	edgeorder.SetSize (top.GetNEdges());
+	edgecoeffsindex.SetSize (top.GetNEdges()+1);
+	edgecoeffsindex[0] = 0;
+	for (int i = 0; i < top.GetNEdges(); i++)
+	  {
+	    int glob = partop.GetDistantEdgeNum (0, i+1);
+	    edgeorder[i] = master_edgeorder[glob-1];
+	    int ncoefs = master_edgecoeffsindex[glob]-master_edgecoeffsindex[glob-1];
+	    edgecoeffsindex[i+1] = edgecoeffsindex[i] + ncoefs;
+	  }
+	edgecoeffs.SetSize (edgecoeffsindex[top.GetNEdges()]);
+	
+	for (int i = 0; i < top.GetNEdges(); i++)
+	  {
+	    int glob = partop.GetDistantEdgeNum (0, i+1);
+	    int ncoefs = master_edgecoeffsindex[glob]-master_edgecoeffsindex[glob-1];
+	    for (int j = 0; j < ncoefs; j++)
+	      edgecoeffs[edgecoeffsindex[i]+j] = master_edgecoeffs[master_edgecoeffsindex[glob-1]+j];
+	  }
+
+	if (mesh.GetDimension() == 3)
+	  {
+	    faceorder.SetSize (top.GetNFaces());
+	    facecoeffsindex.SetSize (top.GetNFaces()+1);
+	    facecoeffsindex[0] = 0;
+	    for (int i = 0; i < top.GetNFaces(); i++)
+	      {
+		int glob = partop.GetDistantFaceNum (0, i+1);
+		faceorder[i] = master_faceorder[glob-1];
+		int ncoefs = master_facecoeffsindex[glob]-master_facecoeffsindex[glob-1];
+		facecoeffsindex[i+1] = facecoeffsindex[i] + ncoefs;
+	      }
+	    facecoeffs.SetSize (facecoeffsindex[top.GetNFaces()]);
+	    
+	    for (int i = 0; i < top.GetNFaces(); i++)
+	      {
+		int glob = partop.GetDistantFaceNum (0, i+1);
+		int ncoefs = master_facecoeffsindex[glob]-master_facecoeffsindex[glob-1];
+		for (int j = 0; j < ncoefs; j++)
+		  facecoeffs[facecoeffsindex[i]+j] = master_facecoeffs[master_facecoeffsindex[glob-1]+j];
+	      }
+	  }
+	else
+	  {
+	    faceorder.SetSize (top.GetNFaces());
+	    faceorder = 1;
+	    facecoeffsindex.SetSize (top.GetNFaces()+1);
+	    facecoeffsindex = 0;
+	  }
+
+	ishighorder = 1;
+	return;
+      }
+#endif
+
+    
+    PrintMessage (1, "Curve elements, order = ", aorder);
+    if (rational) PrintMessage (1, "curved elements with rational splines");
+
+    const_cast<Mesh&> (mesh).UpdateTopology();
+    const MeshTopology & top = mesh.GetTopology();
+
+    rational = arational;
+
+    Array<int> edgenrs;
+
+    edgeorder.SetSize (top.GetNEdges());
+    faceorder.SetSize (top.GetNFaces());
+
+    edgeorder = 1;
+    faceorder = 1;
+
+    if (rational)
+      {
+        edgeweight.SetSize (top.GetNEdges());
+        edgeweight = 1.0;
+      }
+
+    
+    if (aorder <= 1) 
+      {
+	for (ElementIndex ei = 0; ei < mesh.GetNE(); ei++)
+	  if (mesh[ei].GetType() == TET10)
+	    ishighorder = 1;
+	return;
+      }
+
+
+    if (rational) aorder = 2;
+
+
+    if (mesh.GetDimension() == 3)
+      for (SurfaceElementIndex i = 0; i < mesh.GetNSE(); i++)
+	{
+	  top.GetSurfaceElementEdges (i+1, edgenrs);
+	  for (int j = 0; j < edgenrs.Size(); j++)
+	    edgeorder[edgenrs[j]-1] = aorder;
+	  faceorder[top.GetSurfaceElementFace (i+1)-1] = aorder;
+	}
+    for (SegmentIndex i = 0; i < mesh.GetNSeg(); i++)
+      edgeorder[top.GetSegmentEdge (i+1)-1] = aorder;
+
+    if (rational)
+      {
+        edgeorder = 2;
+        faceorder = 1;
+      }
+
+
+    edgecoeffsindex.SetSize (top.GetNEdges()+1);
+    int nd = 0;
+    for (int i = 0; i < top.GetNEdges(); i++)
+      {
+	edgecoeffsindex[i] = nd;
+	nd += max (0, edgeorder[i]-1);
+      }
+    edgecoeffsindex[top.GetNEdges()] = nd;
+
+    edgecoeffs.SetSize (nd);
+    edgecoeffs = Vec<3> (0,0,0);
+    
+
+    facecoeffsindex.SetSize (top.GetNFaces()+1);
+    nd = 0;
+    for (int i = 0; i < top.GetNFaces(); i++)
+      {
+	facecoeffsindex[i] = nd;
+	if (top.GetFaceType(i+1) == TRIG)
+	  nd += max (0, (faceorder[i]-1)*(faceorder[i]-2)/2);
+	else
+	  nd += max (0, sqr(faceorder[i]-1));
+      }
+    facecoeffsindex[top.GetNFaces()] = nd;
+
+    facecoeffs.SetSize (nd);
+    facecoeffs = Vec<3> (0,0,0);
+
+
+    if (!ref || aorder <= 1) 
+      {
+        order = aorder;
+        return;
+      }
+    
+    Array<double> xi, weight;
+
+    ComputeGaussRule (aorder+4, xi, weight);  // on (0,1)
+
+    PrintMessage (3, "Curving edges");
+
+    if (mesh.GetDimension() == 3 || rational)
+      for (SurfaceElementIndex i = 0; i < mesh.GetNSE(); i++)
+        {
+	  SetThreadPercent(double(i)/mesh.GetNSE()*100.);
+          const Element2d & el = mesh[i];
+          top.GetSurfaceElementEdges (i+1, edgenrs);
+          for (int j = 0; j < edgenrs.Size(); j++)
+            edgenrs[j]--;
+          const ELEMENT_EDGE * edges = MeshTopology::GetEdges1 (el.GetType());
+
+          for (int i2 = 0; i2 < edgenrs.Size(); i2++)
+            {
+              PointIndex pi1 = edges[i2][0]-1;
+              PointIndex pi2 = edges[i2][1]-1;
+
+              bool swap = el[pi1] > el[pi2];
+
+              Point<3> p1 = mesh[el[pi1]];
+              Point<3> p2 = mesh[el[pi2]];
+
+              int order1 = edgeorder[edgenrs[i2]];
+              int ndof = max (0, order1-1);
+
+              if (rational && order1 >= 2)
+                {
+                  Point<3> pm = Center (p1, p2);
+
+                  int surfnr = mesh.GetFaceDescriptor(el.GetIndex()).SurfNr();
+
+                  Vec<3> n1 = ref -> GetNormal (p1, surfnr, el.GeomInfoPi(edges[i2][0]));
+                  Vec<3> n2 = ref -> GetNormal (p2, surfnr, el.GeomInfoPi(edges[i2][1]));
+
+                  // p3 = pm + alpha1 n1 + alpha2 n2
+                  
+                  Mat<2> mat, inv;
+                  Vec<2> rhs, sol;
+
+                  mat(0,0) = n1*n1;
+                  mat(0,1) = mat(1,0) = n1*n2;
+                  mat(1,1) = n2*n2;
+                  
+                  rhs(0) = n1 * (p1-pm);
+                  rhs(1) = n2 * (p2-pm);
+                  
+
+                  Point<3> p3;
+
+                  if (fabs (Det (mat)) > 1e-10)
+                    {
+                      CalcInverse (mat, inv);
+                      sol = inv * rhs;
+
+                      p3 = pm + sol(0) * n1 + sol(1) * n2;
+                    }
+                  else
+                    p3 = pm;
+
+                  edgecoeffs[edgecoeffsindex[edgenrs[i2]]] = Vec<3> (p3);
+
+
+                  double wold = 1, w = 1, dw = 0.1;
+                  double dold = 1e99;
+                  while (fabs (dw) > 1e-12)
+                    {
+                      Vec<3> v05 = 0.25 * Vec<3> (p1) + 0.5*w* Vec<3>(p3) + 0.25 * Vec<3> (p2);
+                      v05 /= 1 + (w-1) * 0.5;
+                      Point<3> p05 (v05), pp05(v05);
+                      ref -> ProjectToSurface (pp05, surfnr,  el.GeomInfoPi(edges[i2][0]));
+                      double d = Dist (pp05, p05);
+                      
+                      if (d < dold)
+                        {
+                          dold = d;
+                          wold = w;
+                          w += dw;
+                        }
+                      else
+                        {
+                          dw *= -0.7;
+                          w = wold + dw;
+                        }
+                    }
+                  
+                  edgeweight[edgenrs[i2]] = w;
+                  continue;
+                }
+	    
+              Vector shape(ndof);
+              DenseMatrix mat(ndof, ndof), inv(ndof, ndof),
+                rhs(ndof, 3), sol(ndof, 3);
+	    
+              rhs = 0.0;
+              mat = 0.0;
+              for (int j = 0; j < xi.Size(); j++)
+                {
+                  Point<3> p;
+                  Point<3> pp;
+                  PointGeomInfo ppgi;
+		
+                  if (swap)
+                    {
+                      p = p1 + xi[j] * (p2-p1);
+                      ref -> PointBetween (p1, p2, xi[j], 
+                                           mesh.GetFaceDescriptor(el.GetIndex()).SurfNr(),
+                                           el.GeomInfoPi(edges[i2][0]),
+                                           el.GeomInfoPi(edges[i2][1]),
+                                           pp, ppgi);
+                    }
+                  else
+                    {
+                      p = p2 + xi[j] * (p1-p2);
+                      ref -> PointBetween (p2, p1, xi[j], 
+                                           mesh.GetFaceDescriptor(el.GetIndex()).SurfNr(),
+                                           el.GeomInfoPi(edges[i2][1]),
+                                           el.GeomInfoPi(edges[i2][0]),
+                                           pp, ppgi);
+                    }
+		
+                  Vec<3> dist = pp - p;
+		
+                  CalcEdgeShape (order1, 2*xi[j]-1, &shape(0));
+		
+                  for (int k = 0; k < ndof; k++)
+                    for (int l = 0; l < ndof; l++)
+                      mat(k,l) += weight[j] * shape(k) * shape(l);
+		
+                  for (int k = 0; k < ndof; k++)
+                    for (int l = 0; l < 3; l++)
+                      rhs(k,l) += weight[j] * shape(k) * dist(l);
+                }
+	    
+              CalcInverse (mat, inv);
+              Mult (inv, rhs, sol);
+
+	      
+	    
+              int first = edgecoeffsindex[edgenrs[i2]];
+              for (int j = 0; j < ndof; j++)
+                for (int k = 0; k < 3; k++)
+                  edgecoeffs[first+j](k) = sol(j,k);
+            }
+        }
+
+
+    
+    for (SegmentIndex i = 0; i < mesh.GetNSeg(); i++)
+      {
+	SetThreadPercent(double(i)/mesh.GetNSeg()*100.);
+	const Segment & seg = mesh[i];
+	PointIndex pi1 = mesh[i][0];
+	PointIndex pi2 = mesh[i][1];
+
+	bool swap = (pi1 > pi2);
+
+	Point<3> p1 = mesh[pi1];
+	Point<3> p2 = mesh[pi2];
+
+	int segnr = top.GetSegmentEdge (i+1)-1;
+
+	int order1 = edgeorder[segnr];
+	int ndof = max (0, order1-1);
+
+
+        if (rational)
+          {
+            Vec<3> tau1 = ref -> GetTangent (p1, seg.surfnr2, seg.surfnr1, seg.epgeominfo[0]);
+            Vec<3> tau2 = ref -> GetTangent (p2, seg.surfnr2, seg.surfnr1, seg.epgeominfo[1]);
+            // p1 + alpha1 tau1 = p2 + alpha2 tau2;
+
+            Mat<3,2> mat;
+            Mat<2,3> inv;
+            Vec<3> rhs;
+            Vec<2> sol;
+            for (int j = 0; j < 3; j++)
+              {
+                mat(j,0) = tau1(j); 
+                mat(j,1) = -tau2(j); 
+                rhs(j) = p2(j)-p1(j); 
+              }
+            CalcInverse (mat, inv);
+            sol = inv * rhs;
+
+            Point<3> p3 = p1+sol(0) * tau1;
+            edgecoeffs[edgecoeffsindex[segnr]] = Vec<3> (p3);
+
+            
+            //             double dopt = 1e99;
+            //             double wopt = 0;
+            //             for (double w = 0; w <= 2; w += 0.0001)
+            //               {
+            //                 Vec<3> v05 = 0.25 * Vec<3> (p1) + 0.5*w* Vec<3>(p3) + 0.25 * Vec<3> (p2);
+            //                 v05 /= 1 + (w-1) * 0.5;
+            //                 Point<3> p05 (v05), pp05(v05);
+            //                 ref -> ProjectToEdge (pp05, seg.surfnr1, seg.surfnr2, seg.epgeominfo[0]);
+            //                 double d = Dist (pp05, p05);
+            //                 if (d < dopt)
+            //                   {
+            //                     wopt = w;
+            //                     dopt = d;
+            //                   }
+            //               }
+            
+            double wold = 1, w = 1, dw = 0.1;
+            double dold = 1e99;
+            while (fabs (dw) > 1e-12)
+              {
+                Vec<3> v05 = 0.25 * Vec<3> (p1) + 0.5*w* Vec<3>(p3) + 0.25 * Vec<3> (p2);
+                v05 /= 1 + (w-1) * 0.5;
+                Point<3> p05 (v05), pp05(v05);
+                ref -> ProjectToEdge (pp05, seg.surfnr1, seg.surfnr2, seg.epgeominfo[0]);
+                double d = Dist (pp05, p05);
+
+                if (d < dold)
+                  {
+                    dold = d;
+                    wold = w;
+                    w += dw;
+                  }
+                else
+                  {
+                    dw *= -0.7;
+                    w = wold + dw;
+                  }
+                // *testout << "w = " << w << ", dw = " << dw << endl;
+              }
+
+            // cout << "wopt = " << w << ", dopt = " << dold << endl;
+            edgeweight[segnr] = w;
+            
+            //             cout << "p1 = " << p1 << ", tau1 = " << tau1 << ", alpha1 = " << sol(0) << endl;
+            //             cout << "p2 = " << p2 << ", tau2 = " << tau2 << ", alpha2 = " << -sol(1) << endl;
+            //             cout << "p+alpha tau = " << p1 + sol(0) * tau1 
+            //                  << " =?= " << p2 +sol(1) * tau2 << endl;
+            
+          }
+
+        else
+          
+          {
+
+            Vector shape(ndof);
+            DenseMatrix mat(ndof, ndof), inv(ndof, ndof),
+              rhs(ndof, 3), sol(ndof, 3);
+
+            rhs = 0.0;
+            mat = 0.0;
+            for (int j = 0; j < xi.Size(); j++)
+              {
+                Point<3> p;
+
+                Point<3> pp;
+                EdgePointGeomInfo ppgi;
+	    
+                if (swap)
+                  {
+                    p = p1 + xi[j] * (p2-p1);
+                    ref -> PointBetween (p1, p2, xi[j], 
+                                         seg.surfnr2, seg.surfnr1, 
+                                         seg.epgeominfo[0], seg.epgeominfo[1],
+                                         pp, ppgi);
+                  }
+                else
+                  {
+                    p = p2 + xi[j] * (p1-p2);
+                    ref -> PointBetween (p2, p1, xi[j], 
+                                         seg.surfnr2, seg.surfnr1, 
+                                         seg.epgeominfo[1], seg.epgeominfo[0],
+                                         pp, ppgi);
+                  }
+	    
+                Vec<3> dist = pp - p;
+
+                CalcEdgeShape (order1, 2*xi[j]-1, &shape(0));
+
+                for (int k = 0; k < ndof; k++)
+                  for (int l = 0; l < ndof; l++)
+                    mat(k,l) += weight[j] * shape(k) * shape(l);
+
+                for (int k = 0; k < ndof; k++)
+                  for (int l = 0; l < 3; l++)
+                    rhs(k,l) += weight[j] * shape(k) * dist(l);
+              }
+
+
+            CalcInverse (mat, inv);
+            Mult (inv, rhs, sol);
+
+            int first = edgecoeffsindex[segnr];
+            for (int j = 0; j < ndof; j++)
+              for (int k = 0; k < 3; k++)
+                edgecoeffs[first+j](k) = sol(j,k);
+          }
+      }
+
+   
+
+    
+    PrintMessage (3, "Curving faces");
+
+    if (mesh.GetDimension() == 3)
+      for (SurfaceElementIndex i = 0; i < mesh.GetNSE(); i++)
+        {
+          SetThreadPercent(double(i)/mesh.GetNSE()*100.);
+          const Element2d & el = mesh[i];
+          int facenr = top.GetSurfaceElementFace (i+1)-1;
+
+          if (el.GetType() == TRIG && order >= 3)
+            {
+              int fnums[] = { 0, 1, 2 };
+              if (el[fnums[0]] > el[fnums[1]]) swap (fnums[0], fnums[1]);
+              if (el[fnums[1]] > el[fnums[2]]) swap (fnums[1], fnums[2]);
+              if (el[fnums[0]] > el[fnums[1]]) swap (fnums[0], fnums[1]);
+
+              int order1 = faceorder[facenr];
+              int ndof = max (0, (order1-1)*(order1-2)/2);
+	    
+              Vector shape(ndof);
+              DenseMatrix mat(ndof, ndof), inv(ndof, ndof),
+                rhs(ndof, 3), sol(ndof, 3);
+	    
+              rhs = 0.0;
+              mat = 0.0;
+
+              for (int jx = 0; jx < xi.Size(); jx++)
+                for (int jy = 0; jy < xi.Size(); jy++)
+                  {
+                    double y = xi[jy];
+                    double x = (1-y) * xi[jx];
+                    double lami[] = { x, y, 1-x-y };
+                    double wi = weight[jx]*weight[jy]*(1-y);
+
+                    Point<2> xii (x, y);
+                    Point<3> p1, p2;
+                    CalcSurfaceTransformation (xii, i, p1);
+                    p2 = p1;
+                    ref -> ProjectToSurface (p2, mesh.GetFaceDescriptor(el.GetIndex()).SurfNr());
+
+                    Vec<3> dist = p2-p1;
+		
+                    CalcTrigShape (order1, lami[fnums[1]]-lami[fnums[0]],
+                                   1-lami[fnums[1]]-lami[fnums[0]], &shape(0));
+
+                    for (int k = 0; k < ndof; k++)
+                      for (int l = 0; l < ndof; l++)
+                        mat(k,l) += wi * shape(k) * shape(l);
+		  
+                    for (int k = 0; k < ndof; k++)
+                      for (int l = 0; l < 3; l++)
+                        rhs(k,l) += wi * shape(k) * dist(l);
+                  }
+
+              // *testout << "mat = " << endl << mat << endl;
+              // CalcInverse (mat, inv);
+              // Mult (inv, rhs, sol);
+
+              for (int i = 0; i < ndof; i++)
+                for (int j = 0; j < 3; j++)
+                  sol(i,j) = rhs(i,j) / mat(i,i);   // Orthogonal basis !
+
+              int first = facecoeffsindex[facenr];
+              for (int j = 0; j < ndof; j++)
+                for (int k = 0; k < 3; k++)
+                  facecoeffs[first+j](k) = sol(j,k);
+            }
+        }
+    
+    PrintMessage (3, "Complete");
+
+
+    // compress edge and face tables
+    int newbase = 0;
+    for (int i = 0; i < edgeorder.Size(); i++)
+      {
+	bool curved = 0;
+	int oldbase = edgecoeffsindex[i];
+	nd = edgecoeffsindex[i+1] - edgecoeffsindex[i];
+
+	for (int j = 0; j < nd; j++)
+	  if (edgecoeffs[oldbase+j].Length() > 1e-12)
+	    curved = 1;
+        if (rational) curved = 1;
+
+	if (curved && newbase != oldbase)
+	  for (int j = 0; j < nd; j++)
+	    edgecoeffs[newbase+j] = edgecoeffs[oldbase+j];
+
+	edgecoeffsindex[i] = newbase;
+	if (!curved) edgeorder[i] = 1;
+	if (curved) newbase += nd;
+      }
+    edgecoeffsindex.Last() = newbase;
+
+
+    newbase = 0;
+    for (int i = 0; i < faceorder.Size(); i++)
+      {
+	bool curved = 0;
+	int oldbase = facecoeffsindex[i];
+	nd = facecoeffsindex[i+1] - facecoeffsindex[i];
+
+	for (int j = 0; j < nd; j++)
+	  if (facecoeffs[oldbase+j].Length() > 1e-12)
+	    curved = 1;
+
+	if (curved && newbase != oldbase)
+	  for (int j = 0; j < nd; j++)
+	    facecoeffs[newbase+j] = facecoeffs[oldbase+j];
+
+	facecoeffsindex[i] = newbase;
+	if (!curved) faceorder[i] = 1;
+	if (curved) newbase += nd;
+      }
+    facecoeffsindex.Last() = newbase;
+
+    ishighorder = (order > 1);
+    // (*testout) << "edgecoeffs = " << endl << edgecoeffs << endl;
+    // (*testout) << "facecoeffs = " << endl << facecoeffs << endl;
+
+
+#ifdef PARALLEL
+    if (ntasks > 1)
+      {
+	MyMPI_Bcast (edgeorder, 0, mesh_comm);
+	MyMPI_Bcast (edgecoeffsindex, 0, mesh_comm);
+	MyMPI_Bcast (edgecoeffs, 0, mesh_comm);
+	
+	if (mesh.GetDimension() == 3)
+	  {
+	    MyMPI_Bcast (faceorder, 0, mesh_comm);
+	    MyMPI_Bcast (facecoeffsindex, 0, mesh_comm);
+	    MyMPI_Bcast (facecoeffs, 0, mesh_comm);
+	  }
+      }
+#endif
+
+
+  }
+
+
+
+
+
+
+
+
+
+
+  // ***********************  Transform edges *****************************
+
+  
+  bool CurvedElements ::  IsSegmentCurved (SegmentIndex elnr) const
+  {
+    if (mesh.coarsemesh)
+      {
+	const HPRefElement & hpref_el =
+	  (*mesh.hpelements) [mesh[elnr].hp_elnr];
+	
+	return mesh.coarsemesh->GetCurvedElements().IsSegmentCurved (hpref_el.coarse_elnr);
+      }
+
+    SegmentInfo info;
+    info.elnr = elnr;
+    info.order = order;
+    info.ndof = info.nv = 2;
+    if (info.order > 1)
+      {
+	const MeshTopology & top = mesh.GetTopology();
+	info.edgenr = top.GetSegmentEdge (elnr+1)-1;	
+	info.ndof += edgeorder[info.edgenr]-1;
+      }
+
+    return (info.ndof > info.nv);
+  }
+
+
+ 
+  
+
+  void CurvedElements :: 
+  CalcSegmentTransformation (double xi, SegmentIndex elnr,
+			     Point<3> * x, Vec<3> * dxdxi, bool * curved)
+  {
+    if (mesh.coarsemesh)
+      {
+	const HPRefElement & hpref_el =
+	  (*mesh.hpelements) [mesh[elnr].hp_elnr];
+	
+	// xi umrechnen
+	double lami[2] = { xi, 1-xi };
+	double dlami[2] = { 1, -1 };
+
+	double coarse_xi = 0;
+	double trans = 0;
+	for (int i = 0; i < 2; i++)
+	  {
+	    coarse_xi += hpref_el.param[i][0] * lami[i];
+	    trans += hpref_el.param[i][0] * dlami[i];
+	  }
+
+	mesh.coarsemesh->GetCurvedElements().CalcSegmentTransformation (coarse_xi, hpref_el.coarse_elnr, x, dxdxi, curved);
+	if (dxdxi) *dxdxi *= trans;
+	
+	return;
+      }
+    
+
+    Vector shapes, dshapes;
+    Array<Vec<3> > coefs;
+
+    SegmentInfo info;
+    info.elnr = elnr;
+    info.order = order;
+    info.ndof = info.nv = 2;
+
+    if (info.order > 1)
+      {
+	const MeshTopology & top = mesh.GetTopology();
+	info.edgenr = top.GetSegmentEdge (elnr+1)-1;	
+	info.ndof += edgeorder[info.edgenr]-1;
+      }
+
+    CalcElementShapes (info, xi, shapes);
+    GetCoefficients (info, coefs);
+
+    *x = 0;
+    for (int i = 0; i < shapes.Size(); i++)
+      *x += shapes(i) * coefs[i];
+
+
+    if (dxdxi)
+      {
+	CalcElementDShapes (info, xi, dshapes);
+	
+	*dxdxi = 0;
+	for (int i = 0; i < shapes.Size(); i++)
+	  for (int j = 0; j < 3; j++)
+	    (*dxdxi)(j) += dshapes(i) * coefs[i](j);
+      }
+
+    if (curved)
+      *curved = (info.order > 1);
+
+    // cout << "Segment, |x| = " << Abs2(Vec<3> (*x) ) << endl;
+  }
+
+
+
+
+  void CurvedElements :: 
+  CalcElementShapes (SegmentInfo & info, double xi, Vector & shapes) const
+  {
+    if (rational && info.order == 2)
+      {
+        shapes.SetSize(3);
+        double w = edgeweight[info.edgenr];
+        shapes(0) = xi*xi;
+        shapes(1) = (1-xi)*(1-xi);
+        shapes(2) = 2*w*xi*(1-xi);
+        shapes *= 1.0 / (1 + (w-1) *2*xi*(1-xi));
+        return;
+      }
+
+
+    shapes.SetSize(info.ndof);
+    shapes(0) = xi;
+    shapes(1) = 1-xi;
+
+    if (info.order >= 2)
+      {
+	if (mesh[info.elnr][0] > mesh[info.elnr][1])
+	  xi = 1-xi;
+	CalcEdgeShape (edgeorder[info.edgenr], 2*xi-1, &shapes(2));
+      }
+  }
+
+  void CurvedElements :: 
+  CalcElementDShapes (SegmentInfo & info, double xi, Vector & dshapes) const
+  {
+    if (rational && info.order == 2)
+      {
+        dshapes.SetSize(3);
+        double wi = edgeweight[info.edgenr];
+        double shapes[3];
+        shapes[0] = xi*xi;
+        shapes[1] = (1-xi)*(1-xi);
+        shapes[2] = 2*wi*xi*(1-xi);
+        double w = 1 + (wi-1) *2*xi*(1-xi);
+        double dw = (wi-1) * (2 - 4*xi);
+        
+        dshapes(0) = 2*xi;
+        dshapes(1) = 2*(xi-1);
+        dshapes(2) = 2*wi*(1-2*xi);
+
+        for (int j = 0;j < 3; j++)
+          dshapes(j) = dshapes(j) / w - shapes[j] * dw / (w*w);
+        return;
+      }
+
+
+
+
+
+
+    dshapes.SetSize(info.ndof);
+    dshapes = 0;
+    dshapes(0) = 1;
+    dshapes(1) = -1;
+
+    // int order = edgeorder[info.edgenr];
+
+    if (info.order >= 2)
+      {
+        double fac = 2;
+	if (mesh[info.elnr][0] > mesh[info.elnr][1])
+          {
+            xi = 1-xi; 
+            fac *= -1;
+          }
+	CalcEdgeDx (edgeorder[info.edgenr], 2*xi-1, &dshapes(2));
+        for (int i = 2; i < dshapes.Size(); i++)
+          dshapes(i) *= fac;
+      }
+
+    // ??? not implemented ????
+  }
+
+  void CurvedElements :: 
+  GetCoefficients (SegmentInfo & info, Array<Vec<3> > & coefs) const
+  {
+    const Segment & el = mesh[info.elnr];
+
+    coefs.SetSize(info.ndof);
+
+    coefs[0] = Vec<3> (mesh[el[0]]);
+    coefs[1] = Vec<3> (mesh[el[1]]);
+
+    if (info.order >= 2)
+      {
+	int first = edgecoeffsindex[info.edgenr]; 
+	int next = edgecoeffsindex[info.edgenr+1]; 
+	for (int i = 0; i < next-first; i++)
+	  coefs[i+2] = edgecoeffs[first+i];
+      }
+  }
+
+
+
+
+
+
+
+
+
+
+
+
+
+  // ********************** Transform surface elements *******************
+
+
+  bool CurvedElements :: IsSurfaceElementCurved (SurfaceElementIndex elnr) const
+  {
+    if (!IsHighOrder()) return false;
+
+    if (mesh.coarsemesh)
+      {
+	const HPRefElement & hpref_el =
+	  (*mesh.hpelements) [mesh[elnr].hp_elnr];
+	
+	return mesh.coarsemesh->GetCurvedElements().IsSurfaceElementCurved (hpref_el.coarse_elnr);
+      }
+
+    const Element2d & el = mesh[elnr];
+    ELEMENT_TYPE type = el.GetType();
+    
+    SurfaceElementInfo info;
+    info.elnr = elnr;
+    info.order = order;
+
+    switch (type)
+      {
+      case TRIG : info.nv = 3; break;
+      case QUAD : info.nv = 4; break;
+      case TRIG6: return true;
+      default:
+	cerr << "undef element in CalcSurfaceTrafo" << endl;
+      }
+    info.ndof = info.nv;
+
+    // info.ndof = info.nv = ( (type == TRIG) || (type == TRIG6) ) ? 3 : 4;
+    if (info.order > 1)
+      {
+	const MeshTopology & top = mesh.GetTopology();
+	
+	top.GetSurfaceElementEdges (elnr+1, info.edgenrs);
+	for (int i = 0; i < info.edgenrs.Size(); i++)
+	  info.edgenrs[i]--;
+	info.facenr = top.GetSurfaceElementFace (elnr+1)-1;
+
+	for (int i = 0; i < info.edgenrs.Size(); i++)
+	  info.ndof += edgecoeffsindex[info.edgenrs[i]+1] - edgecoeffsindex[info.edgenrs[i]];
+	info.ndof += facecoeffsindex[info.facenr+1] - facecoeffsindex[info.facenr];
+      }
+
+    return (info.ndof > info.nv);
+  }
+  
+  void CurvedElements :: 
+  CalcSurfaceTransformation (Point<2> xi, SurfaceElementIndex elnr,
+			     Point<3> * x, Mat<3,2> * dxdxi, bool * curved)
+  {
+    if (mesh.coarsemesh)
+      {
+	const HPRefElement & hpref_el =
+	  (*mesh.hpelements) [mesh[elnr].hp_elnr];
+	
+        // xi umrechnen
+	double lami[4];
+	FlatVector vlami(4, lami);
+	vlami = 0;
+	mesh[elnr].GetShapeNew (xi, vlami);
+	
+	Mat<2,2> trans;
+	Mat<3,2> dxdxic;
+	if (dxdxi)
+	  {
+	    MatrixFixWidth<2> dlami(4);
+	    dlami = 0;
+	    mesh[elnr].GetDShapeNew (xi, dlami);	  
+	    
+	    trans = 0;
+	    for (int k = 0; k < 2; k++)
+	      for (int l = 0; l < 2; l++)
+		for (int i = 0; i < hpref_el.np; i++)
+		  trans(l,k) += hpref_el.param[i][l] * dlami(i, k);
+          }
+	
+	Point<2> coarse_xi(0,0);
+	for (int i = 0; i < hpref_el.np; i++)
+	  for (int j = 0; j < 2; j++)
+	    coarse_xi(j) += hpref_el.param[i][j] * lami[i];
+	
+	mesh.coarsemesh->GetCurvedElements().CalcSurfaceTransformation (coarse_xi, hpref_el.coarse_elnr, x, &dxdxic, curved);
+	
+	if (dxdxi)
+	  *dxdxi = dxdxic * trans;
+	
+	return;
+      }
+    
+
+
+    Vector shapes;
+    MatrixFixWidth<2> dshapes;
+    Array<Vec<3> > coefs;
+
+    const Element2d & el = mesh[elnr];
+    ELEMENT_TYPE type = el.GetType();
+
+    SurfaceElementInfo info;
+    info.elnr = elnr;
+    info.order = order;
+
+    switch (type)
+      {
+      case TRIG : info.nv = 3; break;
+      case QUAD : info.nv = 4; break;
+      case TRIG6: info.nv = 6; break;
+      default:
+	cerr << "undef element in CalcSurfaceTrafo" << endl;
+      }
+    info.ndof = info.nv;
+
+    if (info.order > 1)
+      {
+	const MeshTopology & top = mesh.GetTopology();
+	
+	top.GetSurfaceElementEdges (elnr+1, info.edgenrs);
+	for (int i = 0; i < info.edgenrs.Size(); i++)
+	  info.edgenrs[i]--;
+	info.facenr = top.GetSurfaceElementFace (elnr+1)-1;
+
+
+	bool firsttry = true;
+	bool problem = false;
+
+	while(firsttry || problem)
+	  {
+	    problem = false;
+
+	    for (int i = 0; !problem && i < info.edgenrs.Size(); i++)
+	      {
+		if(info.edgenrs[i]+1 >= edgecoeffsindex.Size())
+		  problem = true;
+		else
+		  info.ndof += edgecoeffsindex[info.edgenrs[i]+1] - edgecoeffsindex[info.edgenrs[i]];
+	      }
+	    if(info.facenr+1 >= facecoeffsindex.Size())
+	      problem = true;
+	    else
+	      info.ndof += facecoeffsindex[info.facenr+1] - facecoeffsindex[info.facenr];
+
+	    if(problem && !firsttry)
+	      throw NgException("something wrong with curved elements");
+	    
+	    if(problem)
+	      BuildCurvedElements(NULL,order,rational);
+
+	    firsttry = false;
+	  }
+      }
+
+    CalcElementShapes (info, xi, shapes);
+    GetCoefficients (info, coefs);
+
+    *x = 0;
+    for (int i = 0; i < coefs.Size(); i++)
+      *x += shapes(i) * coefs[i];
+
+    if (dxdxi)
+      {
+	CalcElementDShapes (info, xi, dshapes);
+	
+	*dxdxi = 0;
+	for (int i = 0; i < coefs.Size(); i++)
+	  for (int j = 0; j < 3; j++)
+	    for (int k = 0; k < 2; k++)
+	      (*dxdxi)(j,k) += dshapes(i,k) * coefs[i](j);
+      }
+
+    if (curved)
+      *curved = (info.ndof > info.nv);
+  }
+
+
+
+
+  void CurvedElements :: 
+  CalcElementShapes (SurfaceElementInfo & info, const Point<2> & xi, Vector & shapes) const
+  {
+    const Element2d & el = mesh[info.elnr];
+
+    shapes.SetSize(info.ndof);
+    // shapes = 0;	  
+
+    if (rational && info.order >= 2)
+      {
+        shapes.SetSize(6);
+        double w = 1;
+        double lami[3] = { xi(0), xi(1), 1-xi(0)-xi(1) };
+        for (int j = 0; j < 3; j++)
+          shapes(j) = lami[j] * lami[j];
+
+        const ELEMENT_EDGE * edges = MeshTopology::GetEdges1 (TRIG);
+        for (int j = 0; j < 3; j++)
+          {
+            double wi = edgeweight[info.edgenrs[j]];
+            shapes(j+3) = 2 * wi * lami[edges[j][0]-1] * lami[edges[j][1]-1];
+            w += (wi-1) * 2 * lami[edges[j][0]-1] * lami[edges[j][1]-1];
+          }
+
+        shapes *= 1.0 / w;
+        return;
+      }
+
+    switch (el.GetType())
+      {
+      case TRIG:
+	{
+	  shapes(0) = xi(0);
+	  shapes(1) = xi(1);
+	  shapes(2) = 1-xi(0)-xi(1);
+
+	  if (info.order == 1) return;
+
+	  int ii = 3;
+	  const ELEMENT_EDGE * edges = MeshTopology::GetEdges1 (TRIG);
+	  
+	  for (int i = 0; i < 3; i++)
+	    {
+	      int eorder = edgeorder[info.edgenrs[i]];
+	      if (eorder >= 2)
+		{
+		  int vi1 = edges[i][0]-1, vi2 = edges[i][1]-1;
+		  if (el[vi1] > el[vi2]) swap (vi1, vi2);
+
+		  CalcScaledEdgeShape (eorder, shapes(vi1)-shapes(vi2), shapes(vi1)+shapes(vi2), &shapes(ii));
+		  ii += eorder-1;
+		}
+	    }
+
+	  int forder = faceorder[info.facenr];
+	  if (forder >= 3)
+	    {
+	      int fnums[] = { 0, 1, 2 };
+	      if (el[fnums[0]] > el[fnums[1]]) swap (fnums[0], fnums[1]);
+	      if (el[fnums[1]] > el[fnums[2]]) swap (fnums[1], fnums[2]);
+	      if (el[fnums[0]] > el[fnums[1]]) swap (fnums[0], fnums[1]);
+	      
+	      CalcTrigShape (forder, 
+			     shapes(fnums[1])-shapes(fnums[0]),
+			     1-shapes(fnums[1])-shapes(fnums[0]), &shapes(ii));
+	    }
+	  break;
+	}
+
+      case TRIG6:
+	{
+	  if (shapes.Size() == 3)
+	    {
+	      shapes(0) = xi(0);
+	      shapes(1) = xi(1);
+	      shapes(2) = 1-xi(0)-xi(1);
+	    }
+	  else
+	    {
+	      double x = xi(0);
+	      double y = xi(1);
+	      double lam3 = 1-x-y;
+	      
+	      shapes(0) = x * (2*x-1);
+	      shapes(1) = y * (2*y-1);
+	      shapes(2) = lam3 * (2*lam3-1);
+	      shapes(3) = 4 * y * lam3;
+	      shapes(4) = 4 * x * lam3;
+	      shapes(5) = 4 * x * y;
+	    }
+          break;
+        }
+
+      case QUAD:
+	{
+	  shapes(0) = (1-xi(0))*(1-xi(1));
+	  shapes(1) =    xi(0) *(1-xi(1));
+	  shapes(2) =    xi(0) *   xi(1) ;
+	  shapes(3) = (1-xi(0))*   xi(1) ;
+
+	  if (info.order == 1) return;
+	  
+	  double mu[4] = { 
+	    1 - xi(0) + 1 - xi(1), 
+            xi(0) + 1 - xi(1), 
+            xi(0) +     xi(1), 
+	    1 - xi(0) +     xi(1), 
+	  };
+	    
+	  int ii = 4;
+	  const ELEMENT_EDGE * edges = MeshTopology::GetEdges1 (QUAD);
+	  
+	  for (int i = 0; i < 4; i++)
+	    {
+	      int eorder = edgeorder[info.edgenrs[i]];
+	      if (eorder >= 2)
+		{
+		  int vi1 = edges[i][0]-1, vi2 = edges[i][1]-1;
+		  if (el[vi1] > el[vi2]) swap (vi1, vi2);
+
+		  CalcEdgeShape (eorder, mu[vi1]-mu[vi2], &shapes(ii));
+		  double lame = shapes(vi1)+shapes(vi2);
+		  for (int j = 0; j < order-1; j++)
+		    shapes(ii+j) *= lame;
+		  ii += eorder-1;
+		}
+	    }
+	  
+	  for (int i = ii; i < info.ndof; i++)
+	    shapes(i) = 0;
+
+	  break;
+	}
+        
+      default:
+        throw NgException("CurvedElements::CalcShape 2d, element type not handled");
+      };
+  }
+
+
+  void CurvedElements :: 
+  CalcElementDShapes (SurfaceElementInfo & info, const Point<2> & xi, MatrixFixWidth<2> & dshapes) const
+  {
+    const Element2d & el = mesh[info.elnr];
+    ELEMENT_TYPE type = el.GetType();
+
+    double lami[4];
+
+    dshapes.SetSize(info.ndof);
+    // dshapes = 0;	  
+
+    // *testout << "calcelementdshapes, info.ndof = " << info.ndof << endl;
+
+    if (rational && info.order >= 2)
+      {
+        double w = 1;
+        double dw[2] = { 0, 0 };
+
+
+        lami[0] = xi(0); lami[1] = xi(1); lami[2] = 1-xi(0)-xi(1);
+        double dlami[3][2] = { { 1, 0 }, { 0, 1 }, { -1, -1 }};
+        double shapes[6];
+
+        for (int j = 0; j < 3; j++)
+          {
+            shapes[j] = lami[j] * lami[j];
+            dshapes(j,0) = 2 * lami[j] * dlami[j][0];
+            dshapes(j,1) = 2 * lami[j] * dlami[j][1];
+          }
+
+        const ELEMENT_EDGE * edges = MeshTopology::GetEdges1 (TRIG);
+        for (int j = 0; j < 3; j++)
+          {
+            double wi = edgeweight[info.edgenrs[j]];
+
+            shapes[j+3] = 2 * wi * lami[edges[j][0]-1] * lami[edges[j][1]-1];
+            for (int k = 0; k < 2; k++)
+              dshapes(j+3,k) = 2*wi* (lami[edges[j][0]-1] * dlami[edges[j][1]-1][k] +
+                                      lami[edges[j][1]-1] * dlami[edges[j][0]-1][k]);
+
+            w += (wi-1) * 2 * lami[edges[j][0]-1] * lami[edges[j][1]-1];
+            for (int k = 0; k < 2; k++)
+              dw[k] += 2*(wi-1) * (lami[edges[j][0]-1] * dlami[edges[j][1]-1][k] +
+                                   lami[edges[j][1]-1] * dlami[edges[j][0]-1][k]);
+          }
+        // shapes *= 1.0 / w;
+        dshapes *= 1.0 / w;
+        for (int i = 0; i < 6; i++)
+          for (int j = 0; j < 2; j++)
+            dshapes(i,j) -= shapes[i] * dw[j] / (w*w);
+        return;
+      }
+
+
+
+
+
+    switch (type)
+      {
+      case TRIG:
+	{
+	  dshapes(0,0) = 1;
+          dshapes(0,1) = 0.0;
+          dshapes(1,0) = 0.0;
+	  dshapes(1,1) = 1;
+	  dshapes(2,0) = -1;
+	  dshapes(2,1) = -1;
+	  
+	  if (info.order == 1) return;
+
+          // *testout << "info.order = " << info.order << endl;
+
+
+	  lami[0] = xi(0);
+	  lami[1] = xi(1);
+	  lami[2] = 1-xi(0)-xi(1);
+
+	  int ii = 3;
+	  const ELEMENT_EDGE * edges = MeshTopology::GetEdges1 (TRIG);
+	  
+	  for (int i = 0; i < 3; i++)
+	    {
+	      int eorder = edgeorder[info.edgenrs[i]];
+	      if (eorder >= 2)
+		{
+		  int vi1 = edges[i][0]-1, vi2 = edges[i][1]-1;
+		  if (el[vi1] > el[vi2]) swap (vi1, vi2);
+
+		  CalcScaledEdgeShapeDxDt<2> (eorder, lami[vi1]-lami[vi2], lami[vi1]+lami[vi2], &dshapes(ii,0));
+
+		  Mat<2,2> trans;
+		  for (int j = 0; j < 2; j++)
+		    {
+		      trans(0,j) = dshapes(vi1,j)-dshapes(vi2,j);
+		      trans(1,j) = dshapes(vi1,j)+dshapes(vi2,j);
+		    }
+		  
+		  for (int j = 0; j < eorder-1; j++)
+		    {
+		      double ddx = dshapes(ii+j,0);
+		      double ddt = dshapes(ii+j,1);
+		      dshapes(ii+j,0) = ddx * trans(0,0) + ddt * trans(1,0);
+		      dshapes(ii+j,1) = ddx * trans(0,1) + ddt * trans(1,1);
+		    }
+
+		  ii += eorder-1;
+		}
+	    }
+
+	  int forder = faceorder[info.facenr];
+          // *testout << "forder = " << forder << endl;
+	  if (forder >= 3)
+	    {
+	      int fnums[] = { 0, 1, 2 };
+	      if (el[fnums[0]] > el[fnums[1]]) swap (fnums[0], fnums[1]);
+	      if (el[fnums[1]] > el[fnums[2]]) swap (fnums[1], fnums[2]);
+	      if (el[fnums[0]] > el[fnums[1]]) swap (fnums[0], fnums[1]);
+	      
+	      CalcTrigShapeDxDy (forder, 
+				 lami[fnums[1]]-lami[fnums[0]],
+				 1-lami[fnums[1]]-lami[fnums[0]], &dshapes(ii,0));
+
+	      int nd = (forder-1)*(forder-2)/2;
+	      Mat<2,2> trans;
+	      for (int j = 0; j < 2; j++)
+		{
+		  trans(0,j) = dshapes(fnums[1],j)-dshapes(fnums[0],j);
+		  trans(1,j) = -dshapes(fnums[1],j)-dshapes(fnums[0],j);
+		}
+
+	      for (int j = 0; j < nd; j++)
+		{
+		  double ddx = dshapes(ii+j,0);
+		  double ddt = dshapes(ii+j,1);
+		  dshapes(ii+j,0) = ddx * trans(0,0) + ddt * trans(1,0);
+		  dshapes(ii+j,1) = ddx * trans(0,1) + ddt * trans(1,1);
+		}
+	    }
+
+	  break;
+	}
+
+      case TRIG6:
+	{
+	  if (dshapes.Height() == 3)
+	    {
+	      dshapes = 0.0;
+	      dshapes(0,0) = 1;
+	      dshapes(1,1) = 1;
+	      dshapes(2,0) = -1;
+	      dshapes(2,1) = -1;	    
+	    }
+	  else
+	    {
+	      AutoDiff<2> x(xi(0), 0);
+	      AutoDiff<2> y(xi(1), 1);
+	      AutoDiff<2> lam3 = 1-x-y;
+	      AutoDiff<2> shapes[6];
+	      shapes[0] = x * (2*x-1);
+	      shapes[1] = y * (2*y-1);
+	      shapes[2] = lam3 * (2*lam3-1);
+	      shapes[3] = 4 * y * lam3;
+	      shapes[4] = 4 * x * lam3;
+	      shapes[5] = 4 * x * y;
+
+	      for (int i = 0; i < 6; i++)
+		{
+		  dshapes(i,0) = shapes[i].DValue(0);
+		  dshapes(i,1) = shapes[i].DValue(1);
+		}
+	      
+	    }
+          break;
+        }
+
+      case QUAD:
+	{
+	  dshapes(0,0) = -(1-xi(1));
+	  dshapes(0,1) = -(1-xi(0));
+	  dshapes(1,0) =  (1-xi(1));
+	  dshapes(1,1) =    -xi(0);
+	  dshapes(2,0) =     xi(1);
+	  dshapes(2,1) =     xi(0);
+	  dshapes(3,0) =    -xi(1);
+	  dshapes(3,1) =  (1-xi(0));
+
+	  if (info.order == 1) return;
+
+	  double shapes[4] = {
+	    (1-xi(0))*(1-xi(1)),
+            xi(0) *(1-xi(1)),
+            xi(0) *   xi(1) ,
+	    (1-xi(0))*   xi(1) 
+	  };
+
+	  double mu[4] = { 
+	    1 - xi(0) + 1 - xi(1), 
+            xi(0) + 1 - xi(1), 
+            xi(0) +     xi(1), 
+	    1 - xi(0) +     xi(1), 
+	  };
+
+	  double dmu[4][2] = {
+	    { -1, -1 },
+	    { 1, -1 },
+	    { 1, 1 },
+	    { -1, 1 } };
+	    
+	  // double hshapes[20], hdshapes[20];
+          ArrayMem<double, 20> hshapes(order+1), hdshapes(order+1);
+
+	  int ii = 4;
+	  const ELEMENT_EDGE * edges = MeshTopology::GetEdges1 (QUAD);
+	  
+	  for (int i = 0; i < 4; i++)
+	    {
+	      int eorder = edgeorder[info.edgenrs[i]];
+	      if (eorder >= 2)
+		{
+		  int vi1 = edges[i][0]-1, vi2 = edges[i][1]-1;
+		  if (el[vi1] > el[vi2]) swap (vi1, vi2);
+
+		  CalcEdgeShapeDx (eorder, mu[vi1]-mu[vi2], &hshapes[0], &hdshapes[0]);
+
+		  double lame = shapes[vi1]+shapes[vi2];
+		  double dlame[2] = {
+		    dshapes(vi1, 0) + dshapes(vi2, 0),
+		    dshapes(vi1, 1) + dshapes(vi2, 1) };
+		    
+		  for (int j = 0; j < eorder-1; j++)
+		    for (int k = 0; k < 2; k++)
+		      dshapes(ii+j, k) = 
+			lame * hdshapes[j] * (dmu[vi1][k]-dmu[vi2][k])
+			+ dlame[k] * hshapes[j];
+
+		  ii += eorder-1;
+		}
+	    }
+
+	  /*	  
+           *testout << "quad, dshape = " << endl << dshapes << endl;
+           for (int i = 0; i < 2; i++)
+           {
+           Point<2> xil = xi, xir = xi;
+           Vector shapesl(dshapes.Height()), shapesr(dshapes.Height());
+           xil(i) -= 1e-6;
+           xir(i) += 1e-6;
+           CalcElementShapes (info, xil, shapesl);
+           CalcElementShapes (info, xir, shapesr);
+	      
+           for (int j = 0; j < dshapes.Height(); j++)
+           dshapes(j,i) = 1.0 / 2e-6 * (shapesr(j)-shapesl(j));
+           }
+	  
+           *testout << "quad, num dshape = " << endl << dshapes << endl;
+           */
+	  break;
+	}
+      default:
+        throw NgException("CurvedElements::CalcDShape 2d, element type not handled");
+
+      };
+  }
+
+
+  template <int DIM_SPACE>
+  void CurvedElements :: 
+  GetCoefficients (SurfaceElementInfo & info, Array<Vec<DIM_SPACE> > & coefs) const
+  {
+    const Element2d & el = mesh[info.elnr];
+    coefs.SetSize (info.ndof);
+    // coefs = Vec<3> (0,0,0);
+    
+    for (int i = 0; i < info.nv; i++)
+      {
+        Vec<3> hv(mesh[el[i]]);
+        for (int j = 0; j < DIM_SPACE; j++)
+          coefs[i](j) = hv(j);
+      }
+    
+    if (info.order == 1) return;
+
+    int ii = info.nv;
+	  
+    for (int i = 0; i < info.edgenrs.Size(); i++)
+      {
+	int first = edgecoeffsindex[info.edgenrs[i]];
+	int next = edgecoeffsindex[info.edgenrs[i]+1];
+	for (int j = first; j < next; j++, ii++)
+          for (int k = 0; k < DIM_SPACE; k++)
+            coefs[ii](k) = edgecoeffs[j](k);
+      }
+    
+    int first = facecoeffsindex[info.facenr];
+    int next = facecoeffsindex[info.facenr+1];
+    for (int j = first; j < next; j++, ii++)
+      for (int k = 0; k < DIM_SPACE; k++)
+        coefs[ii](k) = facecoeffs[j](k);
+  }
+
+
+  template void CurvedElements :: 
+  GetCoefficients<2> (SurfaceElementInfo & info, Array<Vec<2> > & coefs) const;
+
+  template void CurvedElements :: 
+  GetCoefficients<3> (SurfaceElementInfo & info, Array<Vec<3> > & coefs) const;
+
+
+
+
+
+  // ********************** Transform volume elements *******************
+
+
+  bool CurvedElements :: IsElementCurved (ElementIndex elnr) const
+  {
+    if (mesh.coarsemesh)
+      {
+	const HPRefElement & hpref_el =
+	  (*mesh.hpelements) [mesh[elnr].hp_elnr];
+	
+	return mesh.coarsemesh->GetCurvedElements().IsElementCurved (hpref_el.coarse_elnr);
+      }
+
+    const Element & el = mesh[elnr];
+    ELEMENT_TYPE type = el.GetType();
+    
+    int nfaces = MeshTopology::GetNFaces (type);
+    if (nfaces > 4)
+      { // not a tet
+	const ELEMENT_FACE * faces = MeshTopology::GetFaces0 (type);
+	for (int j = 0; j < nfaces; j++)
+	  {
+	    if (faces[j][3] != -1)
+	      {  // a quad face
+		Point<3> pts[4];
+		for (int k = 0; k < 4; k++)
+		  pts[k] = mesh.Point(el[faces[j][k]]);
+		Vec<3> twist = (pts[1] - pts[0]) - (pts[2]-pts[3]);
+		if (twist.Length() > 1e-8 * (pts[1]-pts[0]).Length())
+		  return true;
+	      }
+	  }
+      }
+      
+    
+
+    ElementInfo info;
+    info.elnr = elnr;
+    info.order = order;
+    info.ndof = info.nv = MeshTopology::GetNPoints (type);
+    if (info.order > 1)
+      {
+	const MeshTopology & top = mesh.GetTopology();
+	
+	info.nedges = top.GetElementEdges (elnr+1, info.edgenrs, 0);
+	for (int i = 0; i < info.nedges; i++)
+	  info.edgenrs[i]--;
+
+	info.nfaces = top.GetElementFaces (elnr+1, info.facenrs, 0);
+	for (int i = 0; i < info.nfaces; i++)
+	  info.facenrs[i]--;
+
+	for (int i = 0; i < info.nedges; i++)
+	  info.ndof += edgecoeffsindex[info.edgenrs[i]+1] - edgecoeffsindex[info.edgenrs[i]];
+	for (int i = 0; i < info.nfaces; i++)
+	  info.ndof += facecoeffsindex[info.facenrs[i]+1] - facecoeffsindex[info.facenrs[i]];
+      }
+
+    return (info.ndof > info.nv);
+  }
+
+
+
+
+
+
+  void CurvedElements :: 
+  CalcElementTransformation (Point<3> xi, ElementIndex elnr,
+			     Point<3> * x, Mat<3,3> * dxdxi, //  bool * curved,
+                             void * buffer, bool valid)
+  {
+    if (mesh.coarsemesh)
+      {
+        const HPRefElement & hpref_el =
+          (*mesh.hpelements) [mesh[elnr].hp_elnr];
+	  
+        // xi umrechnen
+        double lami[8];
+        FlatVector vlami(8, lami);
+        vlami = 0;
+        mesh[elnr].GetShapeNew (xi, vlami);
+
+        Mat<3,3> trans, dxdxic;
+        if (dxdxi)
+          {
+            MatrixFixWidth<3> dlami(8);
+            dlami = 0;
+            mesh[elnr].GetDShapeNew (xi, dlami);	  
+	      
+            trans = 0;
+            for (int k = 0; k < 3; k++)
+              for (int l = 0; l < 3; l++)
+                for (int i = 0; i < hpref_el.np; i++)
+                  trans(l,k) += hpref_el.param[i][l] * dlami(i, k);
+          }
+
+        Point<3> coarse_xi(0,0,0);
+        for (int i = 0; i < hpref_el.np; i++)
+          for (int j = 0; j < 3; j++)
+            coarse_xi(j) += hpref_el.param[i][j] * lami[i];
+
+        mesh.coarsemesh->GetCurvedElements().CalcElementTransformation (coarse_xi, hpref_el.coarse_elnr, x, &dxdxic /* , curved */);
+
+        if (dxdxi)
+          *dxdxi = dxdxic * trans;
+
+        return;
+      }
+
+
+    Vector shapes;
+    MatrixFixWidth<3> dshapes;
+
+    const Element & el = mesh[elnr];
+    ELEMENT_TYPE type = el.GetType();
+
+    ElementInfo hinfo;
+    ElementInfo & info = (buffer) ? *static_cast<ElementInfo*> (buffer) : hinfo;
+    
+
+    if (!valid)
+      {
+        info.elnr = elnr;
+        info.order = order;
+        info.ndof = info.nv = MeshTopology::GetNPoints (type);
+        if (info.order > 1)
+          {
+            const MeshTopology & top = mesh.GetTopology();
+            
+            info.nedges = top.GetElementEdges (elnr+1, info.edgenrs, 0);
+            for (int i = 0; i < info.nedges; i++)
+              info.edgenrs[i]--;
+            
+            info.nfaces = top.GetElementFaces (elnr+1, info.facenrs, 0);
+            for (int i = 0; i < info.nfaces; i++)
+              info.facenrs[i]--;
+            
+            for (int i = 0; i < info.nedges; i++)
+              info.ndof += edgecoeffsindex[info.edgenrs[i]+1] - edgecoeffsindex[info.edgenrs[i]];
+            for (int i = 0; i < info.nfaces; i++)
+              info.ndof += facecoeffsindex[info.facenrs[i]+1] - facecoeffsindex[info.facenrs[i]];
+          }
+      }
+
+    CalcElementShapes (info, xi, shapes);
+
+    Vec<3> * coefs =  (info.ndof <= 10) ? 
+      &info.hcoefs[0] : new Vec<3> [info.ndof];
+
+    if (info.ndof > 10 || !valid)
+      GetCoefficients (info, coefs);
+
+    if (x)
+      {
+        *x = 0;
+        for (int i = 0; i < shapes.Size(); i++)
+          *x += shapes(i) * coefs[i];
+      }
+
+    if (dxdxi)
+      {
+        if (valid && info.order == 1 && info.nv == 4)   // a linear tet
+          {
+            *dxdxi = info.hdxdxi;
+          }
+        else
+          {
+            CalcElementDShapes (info, xi, dshapes);
+            
+            *dxdxi = 0;
+            for (int i = 0; i < shapes.Size(); i++)
+              for (int j = 0; j < 3; j++)
+                for (int k = 0; k < 3; k++)
+                  (*dxdxi)(j,k) += dshapes(i,k) * coefs[i](j);
+            
+            info.hdxdxi = *dxdxi;
+          }
+      }
+
+    // *testout << "curved_elements, dshapes = " << endl << dshapes << endl;
+
+    //    if (curved) *curved = (info.ndof > info.nv);
+
+    if (info.ndof > 10) delete [] coefs;
+  }
+
+
+
+
+  void CurvedElements ::   CalcElementShapes (ElementInfo & info, const Point<3> & xi, Vector & shapes) const
+  {
+    const Element & el = mesh[info.elnr];
+
+    if (rational && info.order >= 2)
+      {
+        shapes.SetSize(10);
+        double w = 1;
+        double lami[4] = { xi(0), xi(1), xi(2), 1-xi(0)-xi(1)-xi(2) };
+        for (int j = 0; j < 4; j++)
+          shapes(j) = lami[j] * lami[j];
+
+        const ELEMENT_EDGE * edges = MeshTopology::GetEdges1 (TET);
+        for (int j = 0; j < 6; j++)
+          {
+            double wi = edgeweight[info.edgenrs[j]];
+            shapes(j+4) = 2 * wi * lami[edges[j][0]-1] * lami[edges[j][1]-1];
+            w += (wi-1) * 2 * lami[edges[j][0]-1] * lami[edges[j][1]-1];
+          }
+
+        shapes *= 1.0 / w;
+        return;
+      }
+
+    shapes.SetSize(info.ndof);
+    
+    switch (el.GetType())
+      {
+      case TET:
+	{
+	  shapes(0) = xi(0);
+	  shapes(1) = xi(1);
+	  shapes(2) = xi(2);
+	  shapes(3) = 1-xi(0)-xi(1)-xi(2);
+
+	  if (info.order == 1) return;
+
+	  int ii = 4;
+	  const ELEMENT_EDGE * edges = MeshTopology::GetEdges1 (TET);
+	  for (int i = 0; i < 6; i++)
+	    {
+	      int eorder = edgeorder[info.edgenrs[i]];
+	      if (eorder >= 2)
+		{
+		  int vi1 = edges[i][0]-1, vi2 = edges[i][1]-1;
+		  if (el[vi1] > el[vi2]) swap (vi1, vi2);
+
+		  CalcScaledEdgeShape (eorder, shapes(vi1)-shapes(vi2), shapes(vi1)+shapes(vi2), &shapes(ii));
+		  ii += eorder-1;
+		}
+	    }
+	  const ELEMENT_FACE * faces = MeshTopology::GetFaces1 (TET);
+	  for (int i = 0; i < 4; i++)
+	    {
+	      int forder = faceorder[info.facenrs[i]];
+	      if (forder >= 3)
+		{
+		  int fnums[] = { faces[i][0]-1, faces[i][1]-1, faces[i][2]-1 }; 
+		  if (el[fnums[0]] > el[fnums[1]]) swap (fnums[0], fnums[1]);
+		  if (el[fnums[1]] > el[fnums[2]]) swap (fnums[1], fnums[2]);
+		  if (el[fnums[0]] > el[fnums[1]]) swap (fnums[0], fnums[1]);
+
+		  CalcScaledTrigShape (forder, 
+				       shapes(fnums[1])-shapes(fnums[0]), shapes(fnums[2]), 
+				       shapes(fnums[0])+shapes(fnums[1])+shapes(fnums[2]), &shapes(ii));
+		  ii += (forder-1)*(forder-2)/2;
+		}
+	    }
+
+	  break;
+	}
+        
+      case TET10:
+        {
+          double x = xi(0);
+          double y = xi(1);
+          double z = xi(2);
+          double lam4 = 1 - x - y - z;
+          /*
+            shapes(0) = xi(0);
+            shapes(1) = xi(1);
+            shapes(2) = xi(2);
+            shapes(3) = 1-xi(0)-xi(1)-xi(2);
+          */
+          
+          shapes(0) = 2 * x * x - x;  
+          shapes(1) = 2 * y * y - y;
+          shapes(2) = 2 * z * z - z;
+          shapes(3) = 2 * lam4 * lam4 - lam4;
+          
+          shapes(4) = 4 * x * y;
+          shapes(5) = 4 * x * z;
+          shapes(6) = 4 * x * lam4;
+          shapes(7) = 4 * y * z;
+          shapes(8) = 4 * y * lam4;
+          shapes(9) = 4 * z * lam4;
+
+          break;
+        }
+
+      case PRISM:
+	{
+	  double lami[6] = { xi(0), xi(1), 1-xi(0)-xi(1), xi(0), xi(1), 1-xi(0)-xi(1) };
+	  double lamiz[6] = { 1-xi(2), 1-xi(2), 1-xi(2), xi(2), xi(2), xi(2) };
+	  for (int i = 0; i < 6; i++)
+	    shapes(i) = lami[i] * lamiz[i]; 
+	  for (int i = 6; i < info.ndof; i++)
+	    shapes(i) = 0;
+
+          if (info.order == 1) return;
+
+
+	  int ii = 6;
+ 	  const ELEMENT_EDGE * edges = MeshTopology::GetEdges1 (PRISM);
+	  for (int i = 0; i < 6; i++)    // horizontal edges
+	    {
+	      int eorder = edgeorder[info.edgenrs[i]];
+	      if (eorder >= 2)
+		{
+		  int vi1 = edges[i][0]-1, vi2 = edges[i][1]-1;
+		  if (el[vi1] > el[vi2]) swap (vi1, vi2);
+
+		  CalcScaledEdgeShape (eorder, lami[vi1]-lami[vi2], lami[vi1]+lami[vi2], &shapes(ii));
+		  double facz = (i < 3) ? (1-xi(2)) : xi(2);
+		  for (int j = 0; j < eorder-1; j++)
+		    shapes(ii+j) *= facz;
+
+		  ii += eorder-1;
+		}
+	    }
+
+	  for (int i = 6; i < 9; i++)    // vertical edges
+	    {
+	      int eorder = edgeorder[info.edgenrs[i]];
+	      if (eorder >= 2)
+		{
+		  int vi1 = edges[i][0]-1, vi2 = edges[i][1]-1;
+		  if (el[vi1] > el[vi2]) swap (vi1, vi2);
+
+		  double bubz = lamiz[vi1]*lamiz[vi2];
+		  double polyz = lamiz[vi1] - lamiz[vi2];
+		  double bubxy = lami[vi1];
+
+		  for (int j = 0; j < eorder-1; j++)
+		    {
+		      shapes(ii+j) = bubxy * bubz;
+		      bubz *= polyz;
+		    }
+		  ii += eorder-1;
+		}
+	    }
+
+	  // FACE SHAPES
+	  const ELEMENT_FACE * faces = MeshTopology::GetFaces1 (PRISM);
+	  for (int i = 0; i < 2; i++)
+	    {
+	      int forder = faceorder[info.facenrs[i]];
+	      if ( forder < 3 ) continue;
+	      int fav[3] = { faces[i][0]-1, faces[i][1]-1, faces[i][2]-1 };
+	      if(el[fav[0]] > el[fav[1]]) swap(fav[0],fav[1]); 
+	      if(el[fav[1]] > el[fav[2]]) swap(fav[1],fav[2]);
+	      if(el[fav[0]] > el[fav[1]]) swap(fav[0],fav[1]); 	
+
+	      CalcTrigShape (forder, 
+			     lami[fav[2]]-lami[fav[1]], lami[fav[0]],
+			     &shapes(ii));
+	      
+	      int ndf = (forder+1)*(forder+2)/2 - 3 - 3*(forder-1);
+	      for ( int j = 0; j < ndf; j++ )
+		shapes(ii+j) *= lamiz[fav[1]];
+	      ii += ndf;
+	    }
+	  break;
+	}
+
+      case PYRAMID:
+	{
+	  shapes = 0.0;
+	  double x = xi(0);
+	  double y = xi(1);
+	  double z = xi(2);
+	  
+	  if (z == 1.) z = 1-1e-10;
+	  shapes[0] = (1-z-x)*(1-z-y) / (1-z);
+	  shapes[1] = x*(1-z-y) / (1-z);
+	  shapes[2] = x*y / (1-z);
+	  shapes[3] = (1-z-x)*y / (1-z);
+	  shapes[4] = z;
+          
+          if (info.order == 1) return;
+
+	  int ii = 5;
+	  const ELEMENT_EDGE * edges = MeshTopology::GetEdges1 (PYRAMID);
+	  for (int i = 0; i < 4; i++)    // horizontal edges
+	    {
+	      int eorder = edgeorder[info.edgenrs[i]];
+	      if (eorder >= 2)
+		{
+		  int vi1 = (edges[i][0]-1), vi2 = (edges[i][1]-1);
+		  if (el[vi1] > el[vi2]) swap (vi1, vi2);
+
+		  CalcScaledEdgeShape (eorder, shapes[vi1]-shapes[vi2], shapes[vi1]+shapes[vi2], &shapes(ii));
+		  double fac = (shapes[vi1]+shapes[vi2]) / (1-z);
+		  for (int j = 0; j < eorder-1; j++)
+		    shapes(ii+j) *= fac;
+
+		  ii += eorder-1;
+		}
+	    }
+
+
+
+	  break;
+	}
+
+      case HEX:
+        {
+	  shapes = 0.0;
+	  double x = xi(0);
+	  double y = xi(1);
+	  double z = xi(2);
+	  
+	  shapes[0] = (1-x)*(1-y)*(1-z);
+	  shapes[1] =    x *(1-y)*(1-z);
+	  shapes[2] =    x *   y *(1-z);
+	  shapes[3] = (1-x)*   y *(1-z);
+	  shapes[4] = (1-x)*(1-y)*(z);
+	  shapes[5] =    x *(1-y)*(z);
+	  shapes[6] =    x *   y *(z);
+	  shapes[7] = (1-x)*   y *(z);
+          break;
+        }
+
+      default:
+        throw NgException("CurvedElements::CalcShape 3d, element type not handled");
+
+      };
+  }
+
+
+  void CurvedElements :: 
+  CalcElementDShapes (ElementInfo & info, const Point<3> & xi, MatrixFixWidth<3> & dshapes) const
+  {
+    const Element & el = mesh[info.elnr];
+
+    dshapes.SetSize(info.ndof);
+    dshapes = 0.0;
+
+
+
+    if (rational && info.order >= 2)
+      {
+        double w = 1;
+        double dw[3] = { 0, 0, 0 };
+
+        double lami[4] = { xi(0), xi(1), xi(2), 1-xi(0)-xi(1)-xi(2) };
+        double dlami[4][3] = { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 }, { -1, -1, -1 }};
+        double shapes[10];
+
+        for (int j = 0; j < 4; j++)
+          {
+            shapes[j] = lami[j] * lami[j];
+            dshapes(j,0) = 2 * lami[j] * dlami[j][0];
+            dshapes(j,1) = 2 * lami[j] * dlami[j][1];
+            dshapes(j,2) = 2 * lami[j] * dlami[j][2];
+          }
+
+        const ELEMENT_EDGE * edges = MeshTopology::GetEdges1 (TET);
+        for (int j = 0; j < 6; j++)
+          {
+            double wi = edgeweight[info.edgenrs[j]];
+
+            shapes[j+4] = 2 * wi * lami[edges[j][0]-1] * lami[edges[j][1]-1];
+            for (int k = 0; k < 3; k++)
+              dshapes(j+4,k) = 2*wi* (lami[edges[j][0]-1] * dlami[edges[j][1]-1][k] +
+                                      lami[edges[j][1]-1] * dlami[edges[j][0]-1][k]);
+
+            w += (wi-1) * 2 * lami[edges[j][0]-1] * lami[edges[j][1]-1];
+            for (int k = 0; k < 3; k++)
+              dw[k] += 2*(wi-1) * (lami[edges[j][0]-1] * dlami[edges[j][1]-1][k] +
+                                   lami[edges[j][1]-1] * dlami[edges[j][0]-1][k]);
+          }
+        // shapes *= 1.0 / w;
+        dshapes *= 1.0 / w;
+        for (int i = 0; i < 10; i++)
+          for (int j = 0; j < 3; j++)
+            dshapes(i,j) -= shapes[i] * dw[j] / (w*w);
+        return;
+      }
+
+    switch (el.GetType())
+      {
+      case TET:
+	{
+	  dshapes(0,0) = 1;
+	  dshapes(1,1) = 1;
+	  dshapes(2,2) = 1;
+	  dshapes(3,0) = -1;
+	  dshapes(3,1) = -1;
+	  dshapes(3,2) = -1;
+
+	  if (info.order == 1) return;
+
+	  double lami[] = { xi(0), xi(1), xi(2), 1-xi(0)-xi(1)-xi(2) };
+	  int ii = 4;
+	  const ELEMENT_EDGE * edges = MeshTopology::GetEdges1 (TET);
+	  for (int i = 0; i < 6; i++)
+	    {
+	      int eorder = edgeorder[info.edgenrs[i]];
+	      if (eorder >= 2)
+		{
+		  int vi1 = edges[i][0]-1, vi2 = edges[i][1]-1;
+		  if (el[vi1] > el[vi2]) swap (vi1, vi2);
+
+		  CalcScaledEdgeShapeDxDt<3> (eorder, lami[vi1]-lami[vi2], lami[vi1]+lami[vi2], &dshapes(ii,0));
+
+		  Mat<2,3> trans;
+		  for (int j = 0; j < 3; j++)
+		    {
+		      trans(0,j) = dshapes(vi1,j)-dshapes(vi2,j);
+		      trans(1,j) = dshapes(vi1,j)+dshapes(vi2,j);
+		    }
+		  
+		  for (int j = 0; j < order-1; j++)
+		    {
+		      double ddx = dshapes(ii+j,0);
+		      double ddt = dshapes(ii+j,1);
+		      dshapes(ii+j,0) = ddx * trans(0,0) + ddt * trans(1,0);
+		      dshapes(ii+j,1) = ddx * trans(0,1) + ddt * trans(1,1);
+		      dshapes(ii+j,2) = ddx * trans(0,2) + ddt * trans(1,2);
+		    }
+
+		  ii += eorder-1;
+		}
+	    }
+
+	  const ELEMENT_FACE * faces = MeshTopology::GetFaces1 (TET);
+	  for (int i = 0; i < 4; i++)
+	    {
+	      int forder = faceorder[info.facenrs[i]];
+	      if (forder >= 3)
+		{
+		  int fnums[] = { faces[i][0]-1, faces[i][1]-1, faces[i][2]-1 }; 
+		  if (el[fnums[0]] > el[fnums[1]]) swap (fnums[0], fnums[1]);
+		  if (el[fnums[1]] > el[fnums[2]]) swap (fnums[1], fnums[2]);
+		  if (el[fnums[0]] > el[fnums[1]]) swap (fnums[0], fnums[1]);
+
+		  CalcScaledTrigShapeDxDyDt (forder, 
+					     lami[fnums[1]]-lami[fnums[0]], 
+					     lami[fnums[2]], lami[fnums[0]]+lami[fnums[1]]+lami[fnums[2]],
+					     &dshapes(ii,0));
+
+		  Mat<3,3> trans;
+		  for (int j = 0; j < 3; j++)
+		    {
+		      trans(0,j) = dshapes(fnums[1],j)-dshapes(fnums[0],j);
+		      trans(1,j) = dshapes(fnums[2],j);
+		      trans(2,j) = dshapes(fnums[0],j)+dshapes(fnums[1],j)+dshapes(fnums[2],j);
+		    }
+		  
+		  int nfd = (forder-1)*(forder-2)/2;
+		  for (int j = 0; j < nfd; j++)
+		    {
+		      double ddx = dshapes(ii+j,0);
+		      double ddy = dshapes(ii+j,1);
+		      double ddt = dshapes(ii+j,2);
+		      dshapes(ii+j,0) = ddx * trans(0,0) + ddy * trans(1,0) + ddt * trans(2,0);
+		      dshapes(ii+j,1) = ddx * trans(0,1) + ddy * trans(1,1) + ddt * trans(2,1);
+		      dshapes(ii+j,2) = ddx * trans(0,2) + ddy * trans(1,2) + ddt * trans(2,2);
+		    }
+
+		  ii += nfd;
+		}
+	    }
+
+	  break;
+	}
+
+      case TET10:
+	{
+	  if (dshapes.Height() == 4)
+	    {
+	      dshapes = 0.0;
+
+              dshapes(0,0) = 1;
+              dshapes(1,1) = 1;
+              dshapes(2,2) = 1;
+              dshapes(3,0) = -1;
+              dshapes(3,1) = -1;
+              dshapes(3,2) = -1;
+	    }
+	  else
+	    {
+	      AutoDiff<3> x(xi(0), 0);
+	      AutoDiff<3> y(xi(1), 1);
+	      AutoDiff<3> z(xi(2), 2);
+	      AutoDiff<3> lam4 = 1-x-y-z;
+	      AutoDiff<3> shapes[10];
+              
+              shapes[0] = 2 * x * x - x;  
+              shapes[1] = 2 * y * y - y;
+              shapes[2] = 2 * z * z - z;
+              shapes[3] = 2 * lam4 * lam4 - lam4;
+              
+              shapes[4] = 4 * x * y;
+              shapes[5] = 4 * x * z;
+              shapes[6] = 4 * x * lam4;
+              shapes[7] = 4 * y * z;
+              shapes[8] = 4 * y * lam4;
+              shapes[9] = 4 * z * lam4;
+
+	      for (int i = 0; i < 10; i++)
+		{
+		  dshapes(i,0) = shapes[i].DValue(0);
+		  dshapes(i,1) = shapes[i].DValue(1);
+		  dshapes(i,2) = shapes[i].DValue(2);
+		}
+	      
+	    }
+          break;
+
+          break;
+        }
+
+
+      case PRISM:
+	{
+	  double lami[6] = { xi(0), xi(1), 1-xi(0)-xi(1), xi(0), xi(1), 1-xi(0)-xi(1)  };
+	  double lamiz[6] = { 1-xi(2), 1-xi(2), 1-xi(2), xi(2), xi(2), xi(2) };
+	  double dlamiz[6] = { -1, -1, -1, 1, 1, 1 };
+	  double dlami[6][2] = 
+	    { { 1, 0, },
+	      { 0, 1, },
+	      { -1, -1 },
+	      { 1, 0, },
+	      { 0, 1, },
+	      { -1, -1 } };
+	  for (int i = 0; i < 6; i++)
+	    {
+	      // shapes(i) = lami[i%3] * ( (i < 3) ? (1-xi(2)) : xi(2) );
+	      dshapes(i,0) = dlami[i%3][0] * ( (i < 3) ? (1-xi(2)) : xi(2) );
+	      dshapes(i,1) = dlami[i%3][1] * ( (i < 3) ? (1-xi(2)) : xi(2) );
+	      dshapes(i,2) = lami[i%3] * ( (i < 3) ? -1 : 1 );
+	    }
+
+	  int ii = 6;
+
+	  if (info.order == 1) return;
+
+
+	  const ELEMENT_EDGE * edges = MeshTopology::GetEdges1 (PRISM);
+	  for (int i = 0; i < 6; i++)    // horizontal edges
+	    {
+	      int order = edgeorder[info.edgenrs[i]];
+	      if (order >= 2)
+		{
+		  int vi1 = (edges[i][0]-1), vi2 = (edges[i][1]-1);
+		  if (el[vi1] > el[vi2]) swap (vi1, vi2);
+		  vi1 = vi1 % 3;
+		  vi2 = vi2 % 3;
+
+		  Vector shapei(order+1);
+		  CalcScaledEdgeShapeDxDt<3> (order, lami[vi1]-lami[vi2], lami[vi1]+lami[vi2], &dshapes(ii,0) );
+		  CalcScaledEdgeShape(order, lami[vi1]-lami[vi2], lami[vi1]+lami[vi2], &shapei(0) );
+
+		  Mat<2,2> trans;
+		  for (int j = 0; j < 2; j++)
+		    {
+		      trans(0,j) = dlami[vi1][j]-dlami[vi2][j];
+		      trans(1,j) = dlami[vi1][j]+dlami[vi2][j];
+		    }
+		  
+		  for (int j = 0; j < order-1; j++)
+		    {
+		      double ddx = dshapes(ii+j,0);
+		      double ddt = dshapes(ii+j,1);
+		      dshapes(ii+j,0) = ddx * trans(0,0) + ddt * trans(1,0);
+		      dshapes(ii+j,1) = ddx * trans(0,1) + ddt * trans(1,1);
+		    }
+
+
+
+		  double facz = (i < 3) ? (1-xi(2)) : xi(2);
+		  double dfacz = (i < 3) ? (-1) : 1;
+		  for (int j = 0; j < order-1; j++)
+		    {
+		      dshapes(ii+j,0) *= facz;
+		      dshapes(ii+j,1) *= facz;
+		      dshapes(ii+j,2) = shapei(j) * dfacz;
+		    }
+
+		  ii += order-1;
+		}
+	    }
+
+	  for (int i = 6; i < 9; i++)    // vertical edges
+	    {
+	      int eorder = edgeorder[info.edgenrs[i]];
+	      if (eorder >= 2)
+		{
+		  int vi1 = (edges[i][0]-1), vi2 = (edges[i][1]-1);
+		  if (el[vi1] > el[vi2]) swap (vi1, vi2);
+
+		  double bubz = lamiz[vi1] * lamiz[vi2];
+		  double dbubz = dlamiz[vi1]*lamiz[vi2] + lamiz[vi1]*dlamiz[vi2];
+		  double polyz = lamiz[vi1] - lamiz[vi2];
+		  double dpolyz = dlamiz[vi1] - dlamiz[vi2];
+		  double bubxy = lami[(vi1)%3];
+		  double dbubxydx = dlami[(vi1)%3][0];
+		  double dbubxydy = dlami[(vi1)%3][1];
+
+		  for (int j = 0; j < eorder-1; j++)
+		    {
+		      dshapes(ii+j,0) = dbubxydx * bubz;
+		      dshapes(ii+j,1) = dbubxydy * bubz;
+		      dshapes(ii+j,2) = bubxy * dbubz;
+
+		      dbubz = bubz * dpolyz + dbubz * polyz;
+		      bubz *= polyz;
+		    }
+		  ii += eorder-1;
+		}
+	    }
+
+
+	  if (info.order == 2) return;
+	  // FACE SHAPES
+	  const ELEMENT_FACE * faces = MeshTopology::GetFaces1 (PRISM);
+	  for (int i = 0; i < 2; i++)
+	    {
+	      int forder = faceorder[info.facenrs[i]];
+
+	      if ( forder < 3 ) continue;
+	      int ndf = (forder+1)*(forder+2)/2 - 3 - 3*(forder-1);
+
+	      int fav[3] = { faces[i][0]-1, faces[i][1]-1, faces[i][2]-1 };
+	      if(el[fav[0]] > el[fav[1]]) swap(fav[0],fav[1]); 
+	      if(el[fav[1]] > el[fav[2]]) swap(fav[1],fav[2]);
+	      if(el[fav[0]] > el[fav[1]]) swap(fav[0],fav[1]); 	
+
+	      MatrixFixWidth<2> dshapei(ndf);
+	      Vector shapei(ndf);
+
+	      CalcTrigShapeDxDy (forder, 
+				 lami[fav[2]]-lami[fav[1]], lami[fav[0]],
+				 &dshapei(0,0));
+	      CalcTrigShape (forder, lami[fav[2]]-lami[fav[1]], lami[fav[0]],
+                             &shapei(0));
+	      
+	      Mat<2,2> trans;
+	      for (int j = 0; j < 2; j++)
+		{
+		  trans(0,j) = dlami[fav[2]][j]-dlami[fav[1]][j];
+		  trans(1,j) = dlami[fav[0]][j];
+		}
+		  
+	      for (int j = 0; j < ndf; j++)
+		{
+		  // double ddx = dshapes(ii+j,0);
+		  // double ddt = dshapes(ii+j,1);
+		  double ddx = dshapei(j,0);
+		  double ddt = dshapei(j,1);
+		  dshapes(ii+j,0) = ddx * trans(0,0) + ddt * trans(1,0);
+		  dshapes(ii+j,1) = ddx * trans(0,1) + ddt * trans(1,1);
+		}
+
+	      for ( int j = 0; j < ndf; j++ )
+		{
+		  dshapes(ii+j,0) *= lamiz[fav[1]];
+		  dshapes(ii+j,1) *= lamiz[fav[1]];
+		  dshapes(ii+j,2) = shapei(j) * dlamiz[fav[1]];
+		}
+	      ii += ndf;
+	    }
+
+	  break;
+
+	}
+
+      case PYRAMID:
+	{
+	  dshapes = 0.0;
+	  double x = xi(0);
+	  double y = xi(1);
+	  double z = xi(2);
+	  
+	  if (z == 1.) z = 1-1e-10;
+	  double z1 = 1-z;
+	  double z2 = z1*z1;
+	  
+	  dshapes(0,0) = -(z1-y)/z1;
+	  dshapes(0,1) = -(z1-x)/z1;
+	  dshapes(0,2) = ((x+y+2*z-2)*z1+(z1-y)*(z1-x))/z2;
+
+	  dshapes(1,0) = (z1-y)/z1;
+	  dshapes(1,1) = -x/z1;
+	  dshapes(1,2) = (-x*z1+x*(z1-y))/z2;
+
+	  dshapes(2,0) = y/z1;
+	  dshapes(2,1) = x/z1;
+	  dshapes(2,2) = x*y/z2;
+
+	  dshapes(3,0) = -y/z1;
+	  dshapes(3,1) = (z1-x)/z1;
+	  dshapes(3,2) = (-y*z1+y*(z1-x))/z2;
+
+	  dshapes(4,0) = 0;
+	  dshapes(4,1) = 0;
+	  dshapes(4,2) = 1;
+          /* old:
+             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 );
+          */
+	  break;
+	}
+
+      case HEX:
+        {
+          dshapes = 0.0;
+
+	  double x = xi(0);
+	  double y = xi(1);
+	  double z = xi(2);
+
+	  // shapes[0] = (1-x)*(1-y)*(1-z);
+          dshapes(0,0) = - (1-y)*(1-z);
+          dshapes(0,1) = (1-x) * (-1) * (1-z);
+          dshapes(0,2) = (1-x) * (1-y) * (-1);
+
+	  // shapes[1] =    x *(1-y)*(1-z);
+          dshapes(1,0) = (1-y)*(1-z);
+          dshapes(1,1) = -x * (1-z);
+          dshapes(1,2) = -x * (1-y);
+
+	  // shapes[2] =    x *   y *(1-z);
+          dshapes(2,0) = y * (1-z);
+          dshapes(2,1) = x * (1-z);
+          dshapes(2,2) = -x * y;
+
+	  // shapes[3] = (1-x)*   y *(1-z);
+          dshapes(3,0) = -y * (1-z);
+          dshapes(3,1) = (1-x) * (1-z);
+          dshapes(3,2) = -(1-x) * y;
+
+	  // shapes[4] = (1-x)*(1-y)*z;
+          dshapes(4,0) = - (1-y)*z;
+          dshapes(4,1) = (1-x) * (-1) * z;
+          dshapes(4,2) = (1-x) * (1-y) * 1;
+
+	  // shapes[5] =    x *(1-y)*z;
+          dshapes(5,0) = (1-y)*z;
+          dshapes(5,1) = -x * z;
+          dshapes(5,2) = x * (1-y);
+
+	  // shapes[6] =    x *   y *z;
+          dshapes(6,0) = y * z;
+          dshapes(6,1) = x * z;
+          dshapes(6,2) = x * y;
+
+	  // shapes[7] = (1-x)*   y *z;
+          dshapes(7,0) = -y * z;
+          dshapes(7,1) = (1-x) * z;
+          dshapes(7,2) = (1-x) * y;
+
+          break;
+        }
+
+      default:
+        throw NgException("CurvedElements::CalcDShape 3d, element type not handled");
+      }
+    
+    /*
+      DenseMatrix dshapes2 (info.ndof, 3);
+      Vector shapesl(info.ndof); 
+      Vector shapesr(info.ndof); 
+    
+      double eps = 1e-6;
+      for (int i = 0; i < 3; i++)
+      {
+      Point<3> xl = xi;
+      Point<3> xr = xi;
+	
+      xl(i) -= eps;
+      xr(i) += eps;
+      CalcElementShapes (info, xl, shapesl);
+      CalcElementShapes (info, xr, shapesr);
+	
+      for (int j = 0; j < info.ndof; j++)
+      dshapes2(j,i) = (shapesr(j)-shapesl(j)) / (2*eps);
+      }
+      (*testout) << "dshapes = " << endl << dshapes << endl;
+      (*testout) << "dshapes2 = " << endl << dshapes2 << endl;
+      dshapes2 -= dshapes;
+      (*testout) << "diff = " << endl << dshapes2 << endl;
+    */
+  }
+
+
+
+  void CurvedElements :: 
+  GetCoefficients (ElementInfo & info, Vec<3> * coefs) const
+  {
+    const Element & el = mesh[info.elnr];
+
+    for (int i = 0; i < info.nv; i++)
+      coefs[i] = Vec<3> (mesh[el[i]]);
+
+    if (info.order == 1) return;
+
+    int ii = info.nv;
+	  
+    for (int i = 0; i < info.nedges; i++)
+      {
+	int first = edgecoeffsindex[info.edgenrs[i]];
+	int next = edgecoeffsindex[info.edgenrs[i]+1];
+	for (int j = first; j < next; j++, ii++)
+	  coefs[ii] = edgecoeffs[j];
+      }
+    for (int i = 0; i < info.nfaces; i++)
+      {
+	int first = facecoeffsindex[info.facenrs[i]];
+	int next = facecoeffsindex[info.facenrs[i]+1];
+	for (int j = first; j < next; j++, ii++)
+	  coefs[ii] = facecoeffs[j];
+      }
+  }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+  void CurvedElements :: 
+  CalcMultiPointSegmentTransformation (Array<double> * xi, SegmentIndex segnr,
+				       Array<Point<3> > * x,
+				       Array<Vec<3> > * dxdxi)
+  {
+    ;
+  }
+
+
+  template <int DIM_SPACE>
+  void CurvedElements :: 
+  CalcMultiPointSegmentTransformation (SegmentIndex elnr, int n,
+				       const double * xi, size_t sxi,
+				       double * x, size_t sx,
+				       double * dxdxi, size_t sdxdxi)
+  {
+    for (int ip = 0; ip < n; ip++)
+      {
+        Point<3> xg;
+        Vec<3> dx;
+
+        // mesh->GetCurvedElements().
+	CalcSegmentTransformation (xi[ip*sxi], elnr, xg, dx);
+      
+        if (x)
+          for (int i = 0; i < DIM_SPACE; i++)
+            x[ip*sx+i] = xg(i);
+	  
+        if (dxdxi)
+          for (int i=0; i<DIM_SPACE; i++)
+            dxdxi[ip*sdxdxi+i] = dx(i);
+      }
+  }
+
+  template void CurvedElements :: 
+  CalcMultiPointSegmentTransformation<2> (SegmentIndex elnr, int npts,
+                                          const double * xi, size_t sxi,
+                                          double * x, size_t sx,
+                                          double * dxdxi, size_t sdxdxi);
+
+  template void CurvedElements :: 
+  CalcMultiPointSegmentTransformation<3> (SegmentIndex elnr, int npts,
+                                          const double * xi, size_t sxi,
+                                          double * x, size_t sx,
+                                          double * dxdxi, size_t sdxdxi);
+
+
+
+  void CurvedElements :: 
+  CalcMultiPointSurfaceTransformation (Array< Point<2> > * xi, SurfaceElementIndex elnr,
+				       Array< Point<3> > * x,
+				       Array< Mat<3,2> > * dxdxi)
+  {
+    double * px = (x) ? &(*x)[0](0) : NULL;
+    double * pdxdxi = (dxdxi) ? &(*dxdxi)[0](0) : NULL;
+
+    CalcMultiPointSurfaceTransformation <3> (elnr, xi->Size(),
+					     &(*xi)[0](0), 2, 
+					     px, 3,
+					     pdxdxi, 6);
+					    
+    return;
+#ifdef OLD
+    if (mesh.coarsemesh)
+      {
+	const HPRefElement & hpref_el =
+	  (*mesh.hpelements) [mesh[elnr].hp_elnr];
+	
+        // xi umrechnen
+	double lami[4];
+	FlatVector vlami(4, lami);
+
+	ArrayMem<Point<2>, 50> coarse_xi (xi->Size());
+	
+	for (int pi = 0; pi < xi->Size(); pi++)
+	  {
+	    vlami = 0;
+	    mesh[elnr].GetShapeNew ( (*xi)[pi], vlami);
+	    
+	    Point<2> cxi(0,0);
+	    for (int i = 0; i < hpref_el.np; i++)
+	      for (int j = 0; j < 2; j++)
+		cxi(j) += hpref_el.param[i][j] * lami[i];
+
+	    coarse_xi[pi] = cxi;
+	  }
+
+	mesh.coarsemesh->GetCurvedElements().
+	  CalcMultiPointSurfaceTransformation (&coarse_xi, hpref_el.coarse_elnr, x, dxdxi);
+
+
+	Mat<2,2> trans;
+        Mat<3,2> dxdxic;
+	if (dxdxi)
+	  {
+	    MatrixFixWidth<2> dlami(4);
+	    dlami = 0;
+
+	    for (int pi = 0; pi < xi->Size(); pi++)
+	      {
+		mesh[elnr].GetDShapeNew ( (*xi)[pi], dlami);	  
+		
+		trans = 0;
+		for (int k = 0; k < 2; k++)
+		  for (int l = 0; l < 2; l++)
+		    for (int i = 0; i < hpref_el.np; i++)
+		      trans(l,k) += hpref_el.param[i][l] * dlami(i, k);
+		
+		dxdxic = (*dxdxi)[pi];
+		(*dxdxi)[pi] = dxdxic * trans;
+	      }
+	  }	
+
+	return;
+      }
+
+
+
+
+
+    Vector shapes;
+    MatrixFixWidth<2> dshapes;
+    Array<Vec<3> > coefs;
+
+
+    const Element2d & el = mesh[elnr];
+    ELEMENT_TYPE type = el.GetType();
+
+    SurfaceElementInfo info;
+    info.elnr = elnr;
+    info.order = order;
+    switch (type)
+      {
+      case TRIG : info.nv = 3; break;
+      case QUAD : info.nv = 4; break;
+      case TRIG6: info.nv = 6; break;
+      default:
+	cerr << "undef element in CalcMultPointSurfaceTrao" << endl;
+      }
+    info.ndof = info.nv;
+
+    if (info.order > 1)
+      {
+	const MeshTopology & top = mesh.GetTopology();
+	
+	top.GetSurfaceElementEdges (elnr+1, info.edgenrs);
+	for (int i = 0; i < info.edgenrs.Size(); i++)
+	  info.edgenrs[i]--;
+	info.facenr = top.GetSurfaceElementFace (elnr+1)-1;
+
+	for (int i = 0; i < info.edgenrs.Size(); i++)
+	  info.ndof += edgecoeffsindex[info.edgenrs[i]+1] - edgecoeffsindex[info.edgenrs[i]];
+	info.ndof += facecoeffsindex[info.facenr+1] - facecoeffsindex[info.facenr];
+      }
+
+    GetCoefficients (info, coefs);
+    if (x)
+      {
+	for (int j = 0; j < xi->Size(); j++)
+	  {
+	    CalcElementShapes (info, (*xi)[j], shapes);
+	    Point<3> val(0,0,0);
+	    for (int i = 0; i < coefs.Size(); i++)
+	      val += shapes(i) * coefs[i];
+            (*x)[j] = val;
+	  }
+      }
+
+    if (dxdxi)
+      {
+	for (int ip = 0; ip < xi->Size(); ip++)
+	  {
+	    CalcElementDShapes (info, (*xi)[ip], dshapes);
+
+            /*
+              (*dxdxi)[ip] = 0;
+              for (int i = 0; i < coefs.Size(); i++)
+	      for (int j = 0; j < 3; j++)
+              for (int k = 0; k < 2; k++)
+              (*dxdxi)[ip](j,k) += dshapes(i,k) * coefs[i](j);
+            */
+
+	    Mat<3,2> ds;
+            ds = 0.0;
+	    for (int i = 0; i < coefs.Size(); i++)
+	      for (int j = 0; j < 3; j++)
+		for (int k = 0; k < 2; k++)
+                  ds(j,k) += dshapes(i,k) * coefs[i](j);
+            (*dxdxi)[ip] = ds;
+	  }
+      }
+#endif
+  }
+
+
+
+
+  template <int DIM_SPACE>
+  void CurvedElements :: 
+  CalcMultiPointSurfaceTransformation (SurfaceElementIndex elnr, int npts,
+				       const double * xi, size_t sxi,
+                                       double * x, size_t sx,
+                                       double * dxdxi, size_t sdxdxi)
+  {
+    if (mesh.coarsemesh)
+      {
+	const HPRefElement & hpref_el =
+	  (*mesh.hpelements) [mesh[elnr].hp_elnr];
+	
+        // xi umrechnen
+	double lami[4];
+	FlatVector vlami(4, lami);
+
+	ArrayMem<Point<2>, 50> coarse_xi (npts);
+	
+	for (int pi = 0; pi < npts; pi++)
+	  {
+	    vlami = 0;
+            Point<2> hxi(xi[pi*sxi], xi[pi*sxi+1]);
+	    mesh[elnr].GetShapeNew ( hxi, vlami);
+	    
+	    Point<2> cxi(0,0);
+	    for (int i = 0; i < hpref_el.np; i++)
+	      for (int j = 0; j < 2; j++)
+		cxi(j) += hpref_el.param[i][j] * lami[i];
+
+	    coarse_xi[pi] = cxi;
+	  }
+
+        mesh.coarsemesh->GetCurvedElements().
+          CalcMultiPointSurfaceTransformation<DIM_SPACE> (hpref_el.coarse_elnr, npts,
+                                                          &coarse_xi[0](0), &coarse_xi[1](0)-&coarse_xi[0](0), 
+                                                          x, sx, dxdxi, sdxdxi);
+
+        // Mat<3,2> dxdxic;
+	if (dxdxi)
+	  {
+	    MatrixFixWidth<2> dlami(4);
+	    dlami = 0;
+
+	    for (int pi = 0; pi < npts; pi++)
+	      {
+                Point<2> hxi(xi[pi*sxi], xi[pi*sxi+1]);
+		mesh[elnr].GetDShapeNew ( hxi, dlami);	  
+		
+		Mat<2,2> trans;
+		trans = 0;
+		for (int k = 0; k < 2; k++)
+		  for (int l = 0; l < 2; l++)
+		    for (int i = 0; i < hpref_el.np; i++)
+		      trans(l,k) += hpref_el.param[i][l] * dlami(i, k);
+		
+                Mat<DIM_SPACE,2> hdxdxic, hdxdxi;
+                for (int k = 0; k < 2*DIM_SPACE; k++)
+                  hdxdxic(k) = dxdxi[pi*sdxdxi+k];
+
+                hdxdxi = hdxdxic * trans;
+
+                for (int k = 0; k < 2*DIM_SPACE; k++)
+                  dxdxi[pi*sdxdxi+k] = hdxdxi(k);
+                    
+                // dxdxic = (*dxdxi)[pi];
+                // (*dxdxi)[pi] = dxdxic * trans;
+	      }
+	  }	
+
+	return;
+      }
+
+    Vector shapes;
+    MatrixFixWidth<2> dshapes;
+    Array<Vec<DIM_SPACE> > coefs;
+
+
+    const Element2d & el = mesh[elnr];
+    ELEMENT_TYPE type = el.GetType();
+
+    SurfaceElementInfo info;
+    info.elnr = elnr;
+    info.order = order;
+    switch (type)
+      {
+      case TRIG : info.nv = 3; break;
+      case QUAD : info.nv = 4; break;
+      case TRIG6: info.nv = 6; break;
+      default:
+	cerr << "undef element in CalcMultPointSurfaceTrao" << endl;
+      }
+    info.ndof = info.nv;
+
+    if (info.order > 1)
+      {
+	const MeshTopology & top = mesh.GetTopology();
+	
+	top.GetSurfaceElementEdges (elnr+1, info.edgenrs);
+	for (int i = 0; i < info.edgenrs.Size(); i++)
+	  info.edgenrs[i]--;
+	info.facenr = top.GetSurfaceElementFace (elnr+1)-1;
+
+	for (int i = 0; i < info.edgenrs.Size(); i++)
+	  info.ndof += edgecoeffsindex[info.edgenrs[i]+1] - edgecoeffsindex[info.edgenrs[i]];
+	info.ndof += facecoeffsindex[info.facenr+1] - facecoeffsindex[info.facenr];
+      }
+
+    GetCoefficients (info, coefs);
+
+    if (x)
+      {
+	for (int j = 0; j < npts; j++)
+	  {
+            Point<2> vxi(xi[j*sxi], xi[j*sxi+1]);
+	    CalcElementShapes (info, vxi, shapes);
+
+	    Point<DIM_SPACE> val = 0.0;
+	    for (int i = 0; i < coefs.Size(); i++)
+	      val += shapes(i) * coefs[i];
+            
+            for (int k = 0; k < DIM_SPACE; k++)
+              x[j*sx+k] = val(k);
+	  }
+      }
+
+    if (dxdxi)
+      {
+	for (int j = 0; j < npts; j++)
+	  {
+            Point<2> vxi(xi[j*sxi], xi[j*sxi+1]);
+	    CalcElementDShapes (info, vxi, dshapes);
+
+	    Mat<DIM_SPACE,2> ds;
+            ds = 0.0;
+	    for (int i = 0; i < coefs.Size(); i++)
+	      for (int j = 0; j < DIM_SPACE; j++)
+		for (int k = 0; k < 2; k++)
+                  ds(j,k) += dshapes(i,k) * coefs[i](j);
+            // (*dxdxi)[ip] = ds;
+
+            for (int k = 0; k < 2*DIM_SPACE; k++)
+              dxdxi[j*sdxdxi+k] = ds(k);
+	  }
+      }
+  }
+
+
+
+  template void CurvedElements :: 
+  CalcMultiPointSurfaceTransformation<2> (SurfaceElementIndex elnr, int npts,
+                                          const double * xi, size_t sxi,
+                                          double * x, size_t sx,
+                                          double * dxdxi, size_t sdxdxi);
+
+  template void CurvedElements :: 
+  CalcMultiPointSurfaceTransformation<3> (SurfaceElementIndex elnr, int npts,
+                                          const double * xi, size_t sxi,
+                                          double * x, size_t sx,
+                                          double * dxdxi, size_t sdxdxi);
+
+
+
+
+
+
+
+
+
+
+
+
+  void CurvedElements :: 
+  CalcMultiPointElementTransformation (Array< Point<3> > * xi, ElementIndex elnr,
+				       Array< Point<3> > * x,
+				       Array< Mat<3,3> > * dxdxi)
+  {
+    double * px = (x) ? &(*x)[0](0) : NULL;
+    double * pdxdxi = (dxdxi) ? &(*dxdxi)[0](0) : NULL;
+
+    CalcMultiPointElementTransformation (elnr, xi->Size(),
+					 &(*xi)[0](0), 3, 
+					 px, 3,
+					 pdxdxi, 9);
+    
+    return;
+#ifdef OLD
+
+    if (mesh.coarsemesh)
+      {
+	const HPRefElement & hpref_el =
+	  (*mesh.hpelements) [mesh[elnr].hp_elnr];
+	
+        // xi umrechnen
+	double lami[8];
+	FlatVector vlami(8, lami);
+
+
+	ArrayMem<Point<3>, 50> coarse_xi (xi->Size());
+	
+	for (int pi = 0; pi < xi->Size(); pi++)
+	  {
+	    vlami = 0;
+	    mesh[elnr].GetShapeNew ( (*xi)[pi], vlami);
+	    
+	    Point<3> cxi(0,0,0);
+	    for (int i = 0; i < hpref_el.np; i++)
+	      for (int j = 0; j < 3; j++)
+		cxi(j) += hpref_el.param[i][j] * lami[i];
+
+	    coarse_xi[pi] = cxi;
+	  }
+
+	mesh.coarsemesh->GetCurvedElements().
+	  CalcMultiPointElementTransformation (&coarse_xi, hpref_el.coarse_elnr, x, dxdxi);
+
+
+	Mat<3,3> trans, dxdxic;
+	if (dxdxi)
+	  {
+	    MatrixFixWidth<3> dlami(8);
+	    dlami = 0;
+
+	    for (int pi = 0; pi < xi->Size(); pi++)
+	      {
+		mesh[elnr].GetDShapeNew ( (*xi)[pi], dlami);	  
+		
+		trans = 0;
+		for (int k = 0; k < 3; k++)
+		  for (int l = 0; l < 3; l++)
+		    for (int i = 0; i < hpref_el.np; i++)
+		      trans(l,k) += hpref_el.param[i][l] * dlami(i, k);
+		
+		dxdxic = (*dxdxi)[pi];
+		(*dxdxi)[pi] = dxdxic * trans;
+	      }
+	  }	
+
+	return;
+      }
+
+
+
+
+
+
+
+
+    Vector shapes;
+    MatrixFixWidth<3> dshapes;
+
+
+    const Element & el = mesh[elnr];
+    ELEMENT_TYPE type = el.GetType();
+
+    ElementInfo info;
+    info.elnr = elnr;
+    info.order = order;
+    info.ndof = info.nv = MeshTopology::GetNPoints (type);
+    if (info.order > 1)
+      {
+	const MeshTopology & top = mesh.GetTopology();
+	
+	info.nedges = top.GetElementEdges (elnr+1, info.edgenrs, 0);
+	for (int i = 0; i < info.nedges; i++)
+	  info.edgenrs[i]--;
+
+	info.nfaces = top.GetElementFaces (elnr+1, info.facenrs, 0);
+	for (int i = 0; i < info.nfaces; i++)
+	  info.facenrs[i]--;
+
+	for (int i = 0; i < info.nedges; i++)
+	  info.ndof += edgecoeffsindex[info.edgenrs[i]+1] - edgecoeffsindex[info.edgenrs[i]];
+	for (int i = 0; i < info.nfaces; i++)
+	  info.ndof += facecoeffsindex[info.facenrs[i]+1] - facecoeffsindex[info.facenrs[i]];
+	// info.ndof += facecoeffsindex[info.facenr+1] - facecoeffsindex[info.facenr];
+      }
+
+    Array<Vec<3> > coefs(info.ndof);
+    GetCoefficients (info, &coefs[0]);
+    if (x)
+      {
+	for (int j = 0; j < xi->Size(); j++)
+	  {
+	    CalcElementShapes (info, (*xi)[j], shapes);
+	    (*x)[j] = 0;
+	    for (int i = 0; i < coefs.Size(); i++)
+	      (*x)[j] += shapes(i) * coefs[i];
+	  }
+      }
+
+    if (dxdxi)
+      {
+	if (info.order == 1 && type == TET)
+	  {
+	    if (xi->Size() > 0)
+	      {
+		CalcElementDShapes (info, (*xi)[0], dshapes);
+		Mat<3,3> ds;
+		ds = 0;
+		for (int i = 0; i < coefs.Size(); i++)
+		  for (int j = 0; j < 3; j++)
+		    for (int k = 0; k < 3; k++)
+		      ds(j,k) += dshapes(i,k) * coefs[i](j);
+	    
+		for (int ip = 0; ip < xi->Size(); ip++)
+		  (*dxdxi)[ip] = ds;
+	      }
+	  }
+	else
+	  for (int ip = 0; ip < xi->Size(); ip++)
+	    {
+	      CalcElementDShapes (info, (*xi)[ip], dshapes);
+	      
+	      Mat<3,3> ds;
+	      ds = 0;
+	      for (int i = 0; i < coefs.Size(); i++)
+		for (int j = 0; j < 3; j++)
+		  for (int k = 0; k < 3; k++)
+		    ds(j,k) += dshapes(i,k) * coefs[i](j);
+	      (*dxdxi)[ip] = ds;
+	    }
+      }
+#endif
+  }
+
+
+
+  void  CurvedElements :: 
+  CalcMultiPointElementTransformation (ElementIndex elnr, int n,
+                                       const double * xi, size_t sxi,
+                                       double * x, size_t sx,
+                                       double * dxdxi, size_t sdxdxi)
+  {
+    if (mesh.coarsemesh)
+      {
+	const HPRefElement & hpref_el =
+	  (*mesh.hpelements) [mesh[elnr].hp_elnr];
+	
+        // xi umrechnen
+	double lami[8];
+	FlatVector vlami(8, lami);
+
+
+	ArrayMem<double, 100> coarse_xi (3*n);
+	
+	for (int pi = 0; pi < n; pi++)
+	  {
+	    vlami = 0;
+            Point<3> pxi;
+            for (int j = 0; j < 3; j++)
+              pxi(j) = xi[pi*sxi+j];
+
+	    mesh[elnr].GetShapeNew ( pxi, vlami);
+	    
+	    Point<3> cxi(0,0,0);
+	    for (int i = 0; i < hpref_el.np; i++)
+	      for (int j = 0; j < 3; j++)
+		cxi(j) += hpref_el.param[i][j] * lami[i];
+
+            for (int j = 0; j < 3; j++)
+              coarse_xi[3*pi+j] = cxi(j);
+	  }
+
+	mesh.coarsemesh->GetCurvedElements().
+	  CalcMultiPointElementTransformation (hpref_el.coarse_elnr, n, 
+                                               &coarse_xi[0], 3, 
+                                               x, sx, 
+                                               dxdxi, sdxdxi);
+
+	Mat<3,3> trans, dxdxic;
+	if (dxdxi)
+	  {
+	    MatrixFixWidth<3> dlami(8);
+	    dlami = 0;
+
+	    for (int pi = 0; pi < n; pi++)
+	      {
+                Point<3> pxi;
+                for (int j = 0; j < 3; j++)
+                  pxi(j) = xi[pi*sxi+j];
+
+		mesh[elnr].GetDShapeNew (pxi, dlami);	  
+		
+		trans = 0;
+		for (int k = 0; k < 3; k++)
+		  for (int l = 0; l < 3; l++)
+		    for (int i = 0; i < hpref_el.np; i++)
+		      trans(l,k) += hpref_el.param[i][l] * dlami(i, k);
+
+                Mat<3> mat_dxdxic, mat_dxdxi;
+                for (int j = 0; j < 3; j++)
+                  for (int k = 0; k < 3; k++)
+                    mat_dxdxic(j,k) = dxdxi[pi*sdxdxi+3*j+k];
+		
+                mat_dxdxi = mat_dxdxic * trans;
+
+                for (int j = 0; j < 3; j++)
+                  for (int k = 0; k < 3; k++)
+                    dxdxi[pi*sdxdxi+3*j+k] = mat_dxdxi(j,k);
+
+		// dxdxic = (*dxdxi)[pi];
+		// (*dxdxi)[pi] = dxdxic * trans;
+	      }
+	  }	
+	return;
+      }
+
+
+
+
+
+
+    Vector shapes;
+    MatrixFixWidth<3> dshapes;
+
+
+    const Element & el = mesh[elnr];
+    ELEMENT_TYPE type = el.GetType();
+
+    ElementInfo info;
+    info.elnr = elnr;
+    info.order = order;
+    info.ndof = info.nv = MeshTopology::GetNPoints (type);
+    if (info.order > 1)
+      {
+	const MeshTopology & top = mesh.GetTopology();
+	
+	info.nedges = top.GetElementEdges (elnr+1, info.edgenrs, 0);
+	for (int i = 0; i < info.nedges; i++)
+	  info.edgenrs[i]--;
+
+	info.nfaces = top.GetElementFaces (elnr+1, info.facenrs, 0);
+	for (int i = 0; i < info.nfaces; i++)
+	  info.facenrs[i]--;
+
+	for (int i = 0; i < info.nedges; i++)
+	  info.ndof += edgecoeffsindex[info.edgenrs[i]+1] - edgecoeffsindex[info.edgenrs[i]];
+	for (int i = 0; i < info.nfaces; i++)
+	  info.ndof += facecoeffsindex[info.facenrs[i]+1] - facecoeffsindex[info.facenrs[i]];
+	// info.ndof += facecoeffsindex[info.facenr+1] - facecoeffsindex[info.facenr];
+      }
+
+    Array<Vec<3> > coefs(info.ndof);
+    GetCoefficients (info, &coefs[0]);
+    if (x)
+      {
+	for (int j = 0; j < n; j++)
+	  {
+            Point<3> xij, xj;
+            for (int k = 0; k < 3; k++)
+              xij(k) = xi[j*sxi+k];
+
+	    CalcElementShapes (info, xij, shapes);
+	    xj = 0;
+	    for (int i = 0; i < coefs.Size(); i++)
+	      xj += shapes(i) * coefs[i];
+
+            for (int k = 0; k < 3; k++)
+              x[j*sx+k] = xj(k);
+	  }
+      }
+
+    if (dxdxi)
+      {
+	if (info.order == 1 && type == TET)
+	  {
+	    if (n > 0)
+	      {
+
+		Point<3> xij;
+		for (int k = 0; k < 3; k++)
+		  xij(k) = xi[k];
+		
+		CalcElementDShapes (info, xij, dshapes);
+		
+		Mat<3> dxdxij;
+		dxdxij = 0.0;
+		for (int i = 0; i < coefs.Size(); i++)
+		  for (int j = 0; j < 3; j++)
+		    for (int k = 0; k < 3; k++)
+		      dxdxij(j,k) += dshapes(i,k) * coefs[i](j);
+		
+		
+		for (int ip = 0; ip < n; ip++)
+		  for (int j = 0; j < 3; j++)
+		    for (int k = 0; k < 3; k++)
+		      dxdxi[ip*sdxdxi+3*j+k] = dxdxij(j,k);
+	      }
+	  }
+	else
+	  {
+	    for (int ip = 0; ip < n; ip++)
+	      {
+		Point<3> xij;
+		for (int k = 0; k < 3; k++)
+		  xij(k) = xi[ip*sxi+k];
+		
+		CalcElementDShapes (info, xij, dshapes);
+		
+		Mat<3> dxdxij;
+		dxdxij = 0.0;
+		for (int i = 0; i < coefs.Size(); i++)
+		  for (int j = 0; j < 3; j++)
+		    for (int k = 0; k < 3; k++)
+		      dxdxij(j,k) += dshapes(i,k) * coefs[i](j);
+		
+		
+		for (int j = 0; j < 3; j++)
+		  for (int k = 0; k < 3; k++)
+		    dxdxi[ip*sdxdxi+3*j+k] = dxdxij(j,k);
+	      }
+	  }
+      }
+  }
+
+
+
+
+
+
+
+
+
+};
+
+
diff --git a/contrib/Netgen/libsrc/meshing/curvedelems.hpp b/contrib/Netgen/libsrc/meshing/curvedelems.hpp
new file mode 100644
index 0000000000..945f20c886
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/curvedelems.hpp
@@ -0,0 +1,223 @@
+#ifndef CURVEDELEMS
+#define CURVEDELEMS
+
+/**************************************************************************/
+/* File:   curvedelems.hpp                                                */
+/* Author: Robert Gaisbauer (first version)                               */
+/*         redesign by Joachim Schoeberl                                  */
+/* Date:   27. Sep. 02, Feb 2006                                          */
+/**************************************************************************/
+
+
+
+
+class Refinement;
+
+
+class CurvedElements
+{
+  const Mesh & mesh;
+
+  Array<int> edgeorder;
+  Array<int> faceorder;
+
+  Array<int> edgecoeffsindex;
+  Array<int> facecoeffsindex;
+
+  Array< Vec<3> > edgecoeffs;
+  Array< Vec<3> > facecoeffs;
+
+  Array< double > edgeweight;  // for rational 2nd order splines
+
+  int order;
+  bool rational;
+
+  bool ishighorder;
+
+public:
+  CurvedElements (const Mesh & amesh);
+  ~CurvedElements();
+
+  // bool IsHighOrder() const { return order > 1; }
+  bool IsHighOrder() const { return ishighorder; }
+
+  // void SetHighOrder (int aorder) { order=aorder; }
+  void SetIsHighOrder (bool ho) { ishighorder = ho; }
+  
+  void BuildCurvedElements(const Refinement * ref, int aorder, bool arational = false);
+
+  int GetOrder () { return order; }
+
+
+  bool IsSegmentCurved (SegmentIndex segnr) const;
+  bool IsSurfaceElementCurved (SurfaceElementIndex sei) const;
+  bool IsElementCurved (ElementIndex ei) const;
+
+
+  void CalcSegmentTransformation (double xi, SegmentIndex segnr,
+				  Point<3> & x)
+  { CalcSegmentTransformation (xi, segnr, &x, NULL); };
+
+  void CalcSegmentTransformation (double xi, SegmentIndex segnr,
+				  Vec<3> & dxdxi)
+  { CalcSegmentTransformation (xi, segnr, NULL, &dxdxi); };
+
+  void CalcSegmentTransformation (double xi, SegmentIndex segnr,
+				  Point<3> & x, Vec<3> & dxdxi)
+  { CalcSegmentTransformation (xi, segnr, &x, &dxdxi, NULL); };
+
+  void CalcSegmentTransformation (double xi, SegmentIndex segnr,
+				  Point<3> & x, Vec<3> & dxdxi, bool & curved)
+  { CalcSegmentTransformation (xi, segnr, &x, &dxdxi, &curved); };
+
+
+
+  void CalcSurfaceTransformation (const Point<2> & xi, SurfaceElementIndex elnr,
+				  Point<3> & x)
+  { CalcSurfaceTransformation (xi, elnr, &x, NULL); };
+
+  void CalcSurfaceTransformation (const Point<2> & xi, SurfaceElementIndex elnr,
+				  Mat<3,2> & dxdxi)
+  { CalcSurfaceTransformation (xi, elnr, NULL, &dxdxi); };
+
+  void CalcSurfaceTransformation (const Point<2> & xi, SurfaceElementIndex elnr,
+				  Point<3> & x, Mat<3,2> & dxdxi)
+  { CalcSurfaceTransformation (xi, elnr, &x, &dxdxi, NULL); };
+
+  void CalcSurfaceTransformation (const Point<2> & xi, SurfaceElementIndex elnr,
+				  Point<3> & x, Mat<3,2> & dxdxi, bool & curved)
+  { CalcSurfaceTransformation (xi, elnr, &x, &dxdxi, &curved); };
+
+
+
+
+
+  void CalcElementTransformation (const Point<3> & xi, ElementIndex elnr,
+				  Point<3> & x)
+  { CalcElementTransformation (xi, elnr, &x, NULL); };
+
+  void CalcElementTransformation (const Point<3> & xi, ElementIndex elnr,
+				  Mat<3,3> & dxdxi)
+  { CalcElementTransformation (xi, elnr, NULL, &dxdxi); };
+
+  void CalcElementTransformation (const Point<3> & xi, ElementIndex elnr,
+				  Point<3> & x, Mat<3,3> & dxdxi)
+  { CalcElementTransformation (xi, elnr, &x, &dxdxi /* , NULL */ ); };
+
+  void CalcElementTransformation (const Point<3> & xi, ElementIndex elnr,
+				  Point<3> & x, Mat<3,3> & dxdxi,
+                                  void * buffer, bool valid)
+  { CalcElementTransformation (xi, elnr, &x, &dxdxi, /* NULL, */ buffer, valid ); };
+
+  // void CalcElementTransformation (const Point<3> & xi, ElementIndex elnr,
+  // 				  Point<3> & x, Mat<3,3> & dxdxi) // , bool & curved)
+  //   { CalcElementTransformation (xi, elnr, &x, &dxdxi /* , &curved * ); }
+
+
+
+  void CalcMultiPointSegmentTransformation (Array<double> * xi, SegmentIndex segnr,
+					    Array<Point<3> > * x,
+					    Array<Vec<3> > * dxdxi);
+
+  template <int DIM_SPACE>
+  void CalcMultiPointSegmentTransformation (SegmentIndex elnr, int n,
+                                            const double * xi, size_t sxi,
+                                            double * x, size_t sx,
+                                            double * dxdxi, size_t sdxdxi);
+
+
+  void CalcMultiPointSurfaceTransformation (Array< Point<2> > * xi, SurfaceElementIndex elnr,
+					    Array< Point<3> > * x,
+					    Array< Mat<3,2> > * dxdxi);
+
+  template <int DIM_SPACE>
+  void CalcMultiPointSurfaceTransformation (SurfaceElementIndex elnr, int n,
+                                            const double * xi, size_t sxi,
+                                            double * x, size_t sx,
+                                            double * dxdxi, size_t sdxdxi);
+
+  void CalcMultiPointElementTransformation (Array< Point<3> > * xi, ElementIndex elnr,
+					    Array< Point<3> > * x,
+					    Array< Mat<3,3> > * dxdxi);
+
+  void CalcMultiPointElementTransformation (ElementIndex elnr, int n,
+                                            const double * xi, size_t sxi,
+                                            double * x, size_t sx,
+                                            double * dxdxi, size_t sdxdxi);
+
+
+
+
+private:
+  
+  void CalcSegmentTransformation (double xi, SegmentIndex segnr,
+				  Point<3> * x = NULL, Vec<3> * dxdxi = NULL, bool * curved = NULL);
+
+  void CalcSurfaceTransformation (Point<2> xi, SurfaceElementIndex elnr,
+				  Point<3> * x = NULL, Mat<3,2> * dxdxi = NULL, bool * curved = NULL);
+
+  void CalcElementTransformation (Point<3> xi, ElementIndex elnr,
+				  Point<3> * x = NULL, Mat<3,3> * dxdxi = NULL, // bool * curved = NULL,
+                                  void * buffer = NULL, bool valid = 0);
+
+
+
+
+
+
+  class SegmentInfo
+  {
+  public:
+    SegmentIndex elnr;
+    int order;
+    int nv;
+    int ndof;
+    int edgenr;
+  };
+
+  void CalcElementShapes (SegmentInfo &  elnr, double xi, Vector & shapes) const;
+  void GetCoefficients (SegmentInfo & elnr, Array<Vec<3> > & coefs) const;
+  void CalcElementDShapes (SegmentInfo & elnr, double xi, Vector & dshapes) const;
+
+
+  class ElementInfo
+  {
+  public:
+    ElementIndex elnr;
+    int order;
+    int nv;
+    int ndof;
+    int nedges;
+    int nfaces;
+    int edgenrs[12];
+    int facenrs[6];
+    Mat<3> hdxdxi;
+    Vec<3> hcoefs[10]; // enough for second order tets
+  };
+
+
+  void CalcElementShapes (ElementInfo & info, const Point<3> & xi, Vector & shapes) const;
+  void GetCoefficients (ElementInfo & info, Vec<3> * coefs) const;
+  void CalcElementDShapes (ElementInfo & info, const Point<3> & xi, MatrixFixWidth<3> & dshapes) const;
+
+  
+  class SurfaceElementInfo
+  {
+  public:
+    SurfaceElementIndex elnr;
+    int order;
+    int nv;
+    int ndof;
+    ArrayMem<int,4> edgenrs;
+    int facenr;
+  };
+
+  void CalcElementShapes (SurfaceElementInfo & elinfo, const Point<2> & xi, Vector & shapes) const;
+  template <int DIM_SPACE>
+  void GetCoefficients (SurfaceElementInfo & elinfo, Array<Vec<DIM_SPACE> > & coefs) const;
+  void CalcElementDShapes (SurfaceElementInfo & elinfo, const Point<2> & xi, MatrixFixWidth<2> & dshapes) const;
+};
+
+
+
+#endif
diff --git a/contrib/Netgen/libsrc/meshing/delaunay.cpp b/contrib/Netgen/libsrc/meshing/delaunay.cpp
new file mode 100644
index 0000000000..90dbb62150
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/delaunay.cpp
@@ -0,0 +1,1676 @@
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+
+
+namespace netgen
+{
+
+
+  static const int deltetfaces[][3] = 
+    { { 1, 2, 3 },
+      { 2, 0, 3 },
+      { 0, 1, 3 },
+      { 1, 0, 2 } };
+
+
+
+
+
+
+  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 & operator[] (int i) { return pnums[i]; }
+    PointIndex operator[] (int i) const { return pnums[i]; }
+
+    int & NB1(int i) { return nb[i-1]; }
+    int NB1(int i) const { return nb[i-1]; }
+
+    int & NB(int i) { return nb[i]; }
+    int NB(int i) const { return nb[i]; }
+
+
+    int FaceNr (INDEX_3 & face) const  // which face nr is it ?
+    {
+      for (int i = 0; i < 3; i++)
+	if (pnums[i] != face.I1() && 
+	    pnums[i] != face.I2() && 
+	    pnums[i] != face.I3())
+	  return i;
+      return 3;
+    }
+    
+    void GetFace1 (int i, INDEX_3 & face) const
+    {
+      face.I(1) = pnums[deltetfaces[i-1][0]];
+      face.I(2) = pnums[deltetfaces[i-1][1]];
+      face.I(3) = pnums[deltetfaces[i-1][2]];
+    }
+
+    void GetFace (int i, INDEX_3 & face) const
+    {
+      face.I(1) = pnums[deltetfaces[i][0]];
+      face.I(2) = pnums[deltetfaces[i][1]];
+      face.I(3) = pnums[deltetfaces[i][2]];
+    }
+      
+    INDEX_3 GetFace1 (int i) const
+    {
+      return INDEX_3 (pnums[deltetfaces[i-1][0]],
+		      pnums[deltetfaces[i-1][1]],
+		      pnums[deltetfaces[i-1][2]]);
+    }
+
+    INDEX_3 GetFace (int i) const
+    {
+      return INDEX_3 (pnums[deltetfaces[i][0]],
+		      pnums[deltetfaces[i][1]],
+		      pnums[deltetfaces[i][2]]);
+    }
+     
+    void GetFace1 (int i, Element2d & face) const
+    {
+      // face.SetType(TRIG);
+      face[0] = pnums[deltetfaces[i-1][0]];
+      face[1] = pnums[deltetfaces[i-1][1]];
+      face[2] = pnums[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)
+    {
+      DelaunayTet & el = tets.Elem(elnr);
+      for (int i = 0; i < 4; i++)
+	faces.Set (el.GetFace(i).Sort(), el.NB(i));
+    }
+
+    // get neighbour of element elnr in direction fnr 
+    int GetNB (int elnr, int fnr)
+    { 
+      return tets.Get(elnr).NB1(fnr); 
+    }
+
+    //
+    void ResetFaceHT (int size)
+    {
+      faces.SetSize (size);
+    }
+  };
+
+
+
+  void MeshNB :: Add (int elnr)
+  {
+    DelaunayTet & el = tets.Elem(elnr);
+
+    for (int i = 0; i < 4; i++)
+      {
+	INDEX_3 i3 = INDEX_3::Sort (el.GetFace(i));
+
+	int posnr;
+	
+	if (!faces.PositionCreate (i3, posnr))
+	  {
+	    // face already in use
+	    int othertet = faces.GetData (posnr);
+
+	    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;
+	  }
+      }
+  }
+
+
+
+
+
+
+  /*
+    connected lists of cosphereical elements
+  */
+  class SphereList 
+  {
+    Array<int> links;
+  public:
+    SphereList () 
+    { ; }
+
+    void AddElement (int elnr)
+    {
+      if (elnr > links.Size())
+	links.Append (1);
+      links.Elem(elnr) = elnr;
+    }
+
+    void DeleteElement (int elnr)
+    {
+      links.Elem(elnr) = 0;
+    }    
+  
+    void ConnectElement (int eli, int toi)
+    {
+      links.Elem (eli) = links.Get (toi);
+      links.Elem (toi) = eli;
+    }
+      
+    void GetList (int eli, Array<int> & linked) const;
+  };
+
+
+  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<Point<3> > & centers, Array<double> & radi2,
+			 Array<int> & connected, Array<int> & treesearch, 
+			 Array<int> & freelist, SphereList & list,
+			 IndexSet & insphere, IndexSet & closesphere)
+  {
+    /*
+      find any sphere, such that newp is contained in
+    */
+  
+    DelaunayTet el;
+    int cfelind = -1;
+
+    const Point<3> * pp[4];
+    Point<3> pc;
+    double r2;
+    Point3d tpmin, tpmax;
+
+    tettree.GetIntersecting (newp, newp, treesearch);
+    
+    double quot,minquot(1e20);
+
+    for (int j = 0; j < treesearch.Size(); j++)
+      {
+	int jjj = treesearch[j];
+	quot = Dist2 (centers.Get(jjj), newp) / radi2.Get(jjj);
+	
+	if((cfelind == -1 || quot < 0.99*minquot) && quot < 1)
+	  {
+	    minquot = quot;
+	    el = tempels.Get(jjj);
+	    cfelind = jjj;
+	    if(minquot < 0.917632)
+	      break;
+	  }
+      }
+
+
+    /*
+      int i, j, k, l;
+      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.GetArray().Size()+1;
+
+
+	// if point in sphere, then it is also closesphere
+	for (int j = starti; j < nstarti; j++)
+	  {
+	    int helind = insphere.GetArray().Get(j);
+	    if (!closesphere.IsIn (helind))
+	      closesphere.Add (helind);
+	  }
+
+	// add connected spheres to insphere - list
+	for (int j = starti; j < nstarti; j++)
+	  {
+	    list.GetList (insphere.GetArray().Get(j), connected);
+	    for (int k = 0; k < connected.Size(); k++)
+	      {
+		int celind = connected[k];
+
+		if (tempels.Get(celind)[0] != -1 && 
+		    !insphere.IsIn (celind))
+		  {
+		    changed = 1;
+		    insphere.Add (celind);
+		  }
+	      }
+	  }
+	
+	// check neighbour-tets
+	for (int j = starti; j < nstarti; j++)
+	  for (int k = 1; k <= 4; k++)
+	    {
+	      int helind = insphere.GetArray().Get(j);
+	      int nbind = meshnb.GetNB (helind, k);
+
+	      if (nbind && !insphere.IsIn (nbind) )
+		{
+		  //changed
+		  //int prec = testout->precision();
+		  //testout->precision(12);
+		  //(*testout) << "val1 " << Dist2 (centers.Get(nbind), newp)
+		  //	     << " val2 " << radi2.Get(nbind) * (1+1e-8)
+		  //	     << " val3 " << radi2.Get(nbind)
+		  //	     << " val1 / val3 " << Dist2 (centers.Get(nbind), newp)/radi2.Get(nbind) << endl;
+		  //testout->precision(prec);
+		  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[1]);
+		      const Point3d & p3 = mesh.Point (face[2]);
+		      */
+
+		      INDEX_3 i3 = tempels.Get(helind).GetFace (k-1);
+
+		      const Point3d & p1 = mesh.Point ( PointIndex (i3.I1()));
+		      const Point3d & p2 = mesh.Point ( PointIndex (i3.I2()));
+		      const Point3d & p3 = mesh.Point ( PointIndex (i3.I3()));
+
+
+		      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)[k-1])) > 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;
+
+    Element2d face(TRIG);
+
+    for (int j = 1; j <= insphere.GetArray().Size(); j++)
+      for (int k = 1; k <= 4; k++)
+	{
+	  //	    int elind = insphere.GetArray().Get(j);
+	  int celind = insphere.GetArray().Get(j);
+	  int nbind = meshnb.GetNB (celind, k);
+
+	  if (!nbind || !insphere.IsIn (nbind))
+	    {
+	      tempels.Get (celind).GetFace1 (k, face);
+		
+	      Element newel(TET);
+	      for (int l = 0; l < 3; l++)
+                newel[l] = face[l];
+              newel[3] = newpi;
+
+	      newels.Append (newel);
+
+              Vec<3> v1 = mesh[face[1]] - mesh[face[0]];
+              Vec<3> v2 = mesh[face[2]] - mesh[face[0]];
+	      Vec<3> n = Cross (v1, v2);
+
+	      n.Normalize();
+	      if (n * Vec3d(mesh.Point (face[0]), 
+			    mesh.Point (tempels.Get(insphere.GetArray().Get(j))[k-1]))
+		  > 0)
+		n *= -1;
+
+              double hval = n *  ( newp - mesh[face[0]]);
+		
+	      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[0]) << " "
+			     << mesh.Point (face[1]) << " "
+			     << mesh.Point (face[2]) << endl;
+		}
+	    }
+	}
+
+    meshnb.ResetFaceHT (10*insphere.GetArray().Size()+1);
+
+    for (int j = 1; j <= insphere.GetArray().Size(); j++)
+      {
+	//	  int elind = 
+	int celind = insphere.GetArray().Get(j);
+
+	meshnb.Delete (celind); 
+	list.DeleteElement (celind);
+	  
+	for (int k = 0; k < 4; k++)
+	  tempels.Elem(celind)[k] = -1;
+
+	((ADTree6&)tettree.Tree()).DeleteElement (celind);
+	freelist.Append (celind);
+      }
+
+
+    int hasclose = 0;
+    for (int j = 1; j <= closesphere.GetArray().Size(); j++)
+      {
+	int ind = closesphere.GetArray().Get(j);
+	if (!insphere.IsIn(ind) &&
+	    fabs (Dist2 (centers.Get (ind), newp) - radi2.Get(ind)) < 1e-8 )
+	  hasclose = 1;
+      }
+
+    for (int 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 (int k = 0; k < 4; k++)
+	  pp[k] = &mesh.Point (newels.Get(j)[k]);
+
+	if (CalcSphereCenter (&pp[0], pc) )
+	  {
+	    PrintSysError ("Delaunay: New tet is flat");
+
+	    (*testout) << "new tet is flat" << endl;
+	    for (int k = 1; k <= 4; k++)
+	      (*testout) << newels.Get(j).PNum(k) << " ";
+	    (*testout) << endl;
+	    for (int k = 1; k <= 4; k++)
+	      (*testout) << *pp[k-1] << " ";
+	    (*testout) << endl;
+	  }
+
+	r2 = Dist2 (*pp[0], pc);
+	if (hasclose)
+	  for (int k = 1; k <= closesphere.GetArray().Size(); k++)
+	    {
+	      int csameind = closesphere.GetArray().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 (int 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;
+    const Point<3> * pp[4];
+
+    Array<Point<3> > centers;
+    Array<double> radi2;
+  
+    Point3d tpmin, tpmax;
+
+
+    // new: local box
+    mesh.GetBox (pmax, pmin);   // lower bound for pmax, upper for pmin
+    for (i = 1; i <= adfront->GetNF(); i++)
+      {
+	const MiniElement2d & face = adfront->GetFace(i);
+	for (j = 0; j < face.GetNP(); j++)
+	  {
+	    pmin.SetToMin  (mesh.Point (face[j]));
+	    pmax.SetToMax  (mesh.Point (face[j]));
+	  }
+      }
+  
+    for (i = 0; i < mesh.LockedPoints().Size(); i++)
+      {
+	pmin.SetToMin (mesh.Point (mesh.LockedPoints()[i]));
+	pmax.SetToMax (mesh.Point (mesh.LockedPoints()[i]));
+      }
+  
+
+
+    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[0] = mesh.AddPoint (cp1);
+    startel[1] = mesh.AddPoint (cp2);
+    startel[2] = mesh.AddPoint (cp3);
+    startel[3] = mesh.AddPoint (cp4);
+
+    // flag points to use for Delaunay:
+    BitArrayChar<PointIndex::BASE> usep(np);
+    usep.Clear();
+    for (i = 1; i <= adfront->GetNF(); i++)
+      {
+	const MiniElement2d & 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[0]);
+    for (k = 1; k < 4; k++)
+      {
+	tpmin.SetToMin (mesh.Point (startel[k]));
+	tpmax.SetToMax (mesh.Point (startel[k]));
+      }
+    tpmax = tpmax + 0.01 * (tpmax - tpmin);
+    tettree.Insert (tpmin, tpmax, 1);
+
+
+    Point<3> pc;
+	  
+    for (k = 0; k < 4; k++)
+      {
+	pp[k] = &mesh.Point (startel[k]);
+      }
+  
+    CalcSphereCenter (&pp[0], pc);
+    
+    centers.Append (pc);
+    radi2.Append (Dist2 (*pp[0], pc));
+
+
+    IndexSet insphere(mesh.GetNP());
+    IndexSet closesphere(mesh.GetNP());
+
+
+
+    // "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 % 1000 == 0)
+	  {
+	    if (i % 10000 == 0)
+	      PrintDot ('+');
+	    else
+	      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);
+      }
+
+    for (i = tempels.Size(); i >= 1; i--)
+      if (tempels.Get(i)[0] <= 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, int domainnr, const MeshingParameters & mp)
+  {
+    int np, ne;
+
+    PrintMessage (1, "Delaunay meshing");
+    PrintMessage (3, "number of points: ", mesh.GetNP());
+    PushStatus ("Delaunay meshing");
+
+
+    Array<DelaunayTet> tempels;
+    Point3d pmin, pmax;
+
+    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 (PointIndex pi = PointIndex::BASE; pi < mesh.GetNP()+PointIndex::BASE; pi++)
+	tempmesh.AddPoint (mesh[pi]);
+      
+      for (int i = 1; i <= tempels.Size(); i++)
+	{   
+	  Element el(4);
+	  for (int j = 0; j < 4; j++)
+	    el[j] = tempels.Elem(i)[j];
+
+	  el.SetIndex (1);
+
+	  const Point3d & lp1 = mesh.Point (el[0]);
+	  const Point3d & lp2 = mesh.Point (el[1]);
+	  const Point3d & lp3 = mesh.Point (el[2]);
+	  const Point3d & lp4 = mesh.Point (el[3]);
+	  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[2], el[3]);
+
+	  tempmesh.AddVolumeElement (el);
+	}
+
+
+      MeshQuality3d (tempmesh);
+
+      tempmesh.AddFaceDescriptor (FaceDescriptor (1, 1, 0, 0));
+      tempmesh.AddFaceDescriptor (FaceDescriptor (2, 1, 0, 0));
+
+
+    
+      for (int i = 1; i <= mesh.GetNOpenElements(); i++)
+	{
+	  Element2d sel = mesh.OpenElement(i);
+	  sel.SetIndex(1);
+	  tempmesh.AddSurfaceElement (sel);
+	  swap (sel[1], sel[2]);
+	  tempmesh.AddSurfaceElement (sel);
+	}
+
+
+      for (int i = 1; i <= 4; i++)
+	{
+	  Element2d self(TRIG);
+	  self.SetIndex (1);
+	  startel.GetFace1 (i, self);
+	  tempmesh.AddSurfaceElement (self);
+	}
+
+      
+      //  for (i = mesh.GetNP() - 3; i <= mesh.GetNP(); i++)
+      //    tempmesh.AddLockedPoint (i);
+      for (PointIndex pi = PointIndex::BASE; 
+	   pi < tempmesh.GetNP() + PointIndex::BASE; pi++)
+	tempmesh.AddLockedPoint (pi);
+      
+      //    tempmesh.PrintMemInfo(cout);
+      // tempmesh.Save ("tempmesh.vol");
+
+      for (int i = 1; i <= 2; i++)
+	{ 
+	  tempmesh.FindOpenElements ();
+
+	  PrintMessage (5, "Num open: ", tempmesh.GetNOpenElements());
+	  tempmesh.CalcSurfacesOfNode ();
+
+	  tempmesh.FreeOpenElementsEnvironment (1);
+
+	  MeshOptimize3d meshopt(mp);
+	  // tempmesh.CalcSurfacesOfNode();
+	  meshopt.SwapImprove(tempmesh, OPT_CONFORM);
+	}
+    
+      MeshQuality3d (tempmesh);
+    
+      tempels.SetSize(0);
+      for (int i = 1; i <= tempmesh.GetNE(); i++)
+	tempels.Append (tempmesh.VolumeElement(i));
+    }
+
+
+
+    // remove degenerated
+
+    BitArray badnode(mesh.GetNP());
+    badnode.Clear();
+    int ndeg = 0;
+    for (int i = 1; i <= tempels.Size(); i++)
+      {
+	Element el(4);
+	for (int j = 0; j < 4; j++)
+	  el[j] = tempels.Elem(i)[j];
+	//      Element & el = tempels.Elem(i);
+	const Point3d & lp1 = mesh.Point (el[0]);
+	const Point3d & lp2 = mesh.Point (el[1]);
+	const Point3d & lp3 = mesh.Point (el[2]);
+	const Point3d & lp4 = mesh.Point (el[3]);
+	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[0] <= np && el[1] <= np &&
+	     el[2] <= np && el[3] <= np) )   // old: 1e-12
+	  {
+	    badnode.Set(el[0]);
+	    badnode.Set(el[1]);
+	    badnode.Set(el[2]);
+	    badnode.Set(el[3]);
+	    ndeg++;
+	    (*testout) << "vol = " << vol << " h = " << h << endl;
+	  }
+
+	if (vol > 0)
+	  Swap (el[2], el[3]);
+      }
+
+    ne = tempels.Size();
+    for (int i = ne; i >= 1; i--)
+      {
+	const DelaunayTet & el = tempels.Get(i);
+	if (badnode.Test(el[0]) ||
+	    badnode.Test(el[1]) ||
+	    badnode.Test(el[2]) ||
+	    badnode.Test(el[3]) )
+	  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 (int i = 1; i <= mesh.GetNOpenElements(); i++)
+      {
+	const Element2d & tri = mesh.OpenElement(i);
+	INDEX_3 i3(tri[0], tri[1], tri[2]);
+	i3.Sort();
+	openeltab.Set (i3, i);
+      }
+
+    for (int i = 1; i <= tempels.Size(); i++)
+      {
+	for (int j = 0; j < 4; j++)
+	  {
+	    INDEX_3 i3 = tempels.Get(i).GetFace (j);
+	    i3.Sort();
+	    if (openeltab.Used(i3))
+	      openeltab.Set (i3, 0);
+	  }
+      }
+  
+    // and store them in openels
+    for (int i = 1; i <= openeltab.GetNBags(); i++)
+      for (int 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 (int ii = 1; ii <= openels.Size(); ii++)
+      {
+	int i = openels.Get(ii);
+	const Element2d & el = mesh.OpenElement(i);
+	for (int 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 (int i = 1; i <= tempels.Size(); i++)
+      {
+	const DelaunayTet & el = tempels.Get(i);
+	INDEX_2 i2;
+	for (int j = 1; j <= 6; j++)
+	  {
+	    switch (j)
+	      {
+	      case 1: i2.I1()=el[0]; i2.I2()=el[1]; break;
+	      case 2: i2.I1()=el[0]; i2.I2()=el[2]; break;
+	      case 3: i2.I1()=el[0]; i2.I2()=el[3]; break;
+	      case 4: i2.I1()=el[1]; i2.I2()=el[2]; break;
+	      case 5: i2.I1()=el[1]; i2.I2()=el[3]; break;
+	      case 6: i2.I1()=el[2]; i2.I2()=el[3]; break;
+		  default: i2.I1()=i2.I2()=0; break;
+	      }
+	    i2.Sort();
+	    tetedges.Set (i2, 1);
+	  }
+      }
+    //  cout << "tetedges:";
+    //  tetedges.PrintMemInfo (cout);
+
+
+    for (INDEX_2_HASHTABLE<INDEX_2>::Iterator it = twotrias.Begin();
+	 it != twotrias.End(); it++)
+      {
+	INDEX_2 hi2, hi3;
+	twotrias.GetData (it, hi2, hi3);
+	hi3.Sort();
+	if (tetedges.Used (hi3))
+	  {
+	    const Point3d & p1 = mesh.Point ( PointIndex (hi2.I1()));
+	    const Point3d & p2 = mesh.Point ( PointIndex (hi2.I2()));
+	    const Point3d & p3 = mesh.Point ( PointIndex (hi3.I1()));
+	    const Point3d & p4 = mesh.Point ( PointIndex (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());	
+	      }
+	  }
+      }
+
+    /*
+    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 (int i = ne; i >= 1; i--)
+      {
+	const DelaunayTet & el = tempels.Get(i);
+	if (badnode.Test(el[0]) ||
+	    badnode.Test(el[1]) ||
+	    badnode.Test(el[2]) ||
+	    badnode.Test(el[3]) )
+	  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 (int 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[0]));
+		Point3d ltpmax (ltpmin);
+	      
+		for (int 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 (int i = 1; i <= tempels.Size(); i++)
+	  {
+	    const Point<3> *pp[4];
+	    int tetpi[4];
+	    DelaunayTet & el = tempels.Elem(i);
+	  
+	    int intersect = 0;
+	  
+	    for (int j = 0; j < 4; j++)
+	      {
+		pp[j] = &mesh.Point(el[j]);
+		tetpi[j] = el[j];
+	      }
+	  
+	    Point3d tetpmin(*pp[0]);
+	    Point3d tetpmax(tetpmin);
+	    for (int 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++)
+	      {
+		int j = neartrias.Get(jj);
+	      
+		const Element2d & tri = mesh.OpenElement(j);
+		const Point<3> *tripp[3];
+		int tripi[3];
+	      
+		for (int 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--;
+	      }
+	  }
+      }
+  
+
+
+
+    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 (int i = 1; i <= mesh.GetNOpenElements(); i++)
+      {
+	const Element2d & tri = mesh.OpenElement(i);
+	INDEX_3 i3 (tri[0], tri[1], tri[2]);
+	i3.Sort();
+	boundaryfaces.PrepareSet (i3);
+      }
+    boundaryfaces.AllocateElements();
+    for (int i = 1; i <= mesh.GetNOpenElements(); i++)
+      {
+	const Element2d & tri = mesh.OpenElement(i);
+	INDEX_3 i3 (tri[0], tri[1], tri[2]);
+	i3.Sort();
+	boundaryfaces.Set (i3, 1);
+      }
+
+    for (int i = 0; i < tempels.Size(); i++)
+      for (int j = 0; j < 4; j++)
+	tempels[i].NB(j) = 0;
+  
+    TABLE<int,PointIndex::BASE> elsonpoint(mesh.GetNP());
+    for (int 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 (int 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(TRIG);
+    for (PointIndex pi = PointIndex::BASE; 
+	 pi < mesh.GetNP()+PointIndex::BASE; pi++)
+      {
+	faceht.SetSize (4 * elsonpoint[pi].Size());
+	for (int ii = 0; ii < elsonpoint[pi].Size(); ii++)
+	  {
+	    int i = elsonpoint[pi][ii];
+	    const DelaunayTet & el = tempels.Get(i);
+
+	    for (int j = 1; j <= 4; j++)
+	      {
+		el.GetFace1 (j, hel);
+		hel.Invert();
+		hel.NormalizeNumbering();
+	      
+		if (hel[0] == pi)
+		  {
+		    INDEX_3 i3(hel[0], hel[1], hel[2]);
+		  
+		    if (!boundaryfaces.Used (i3))
+		      {
+			if (faceht.Used (i3))
+			  {
+			    INDEX_2 i2 = faceht.Get(i3);
+			  
+			    tempels.Elem(i).NB1(j) = i2.I1();
+			    tempels.Elem(i2.I1()).NB1(i2.I2()) = i;
+			  }
+			else
+			  {
+			    hel.Invert();
+			    hel.NormalizeNumbering();
+			    INDEX_3 i3i(hel[0], hel[1], hel[2]);
+			    INDEX_2 i2(i, j);
+			    faceht.Set (i3i, 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.GetFace1 (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).NB1(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;
+
+	int i;
+	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[0]);
+	const Point3d & p2 = mesh.Point (el[1]);
+	const Point3d & p3 = mesh.Point (el[2]);
+	const Point3d & p4 = mesh.Point (el[3]);
+      
+	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 (int j = 1; j <= 4; j++)
+		  {
+		    INDEX_3 i3 = tempels.Get(ei).GetFace1(j);
+		    /*
+		    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).NB1(j))
+		      elstack.Append (tempels.Get(ei).NB1(j));
+
+		    /*
+		      if (innerfaces.Used(i3))
+		      {
+		      INDEX_2 i2 = innerfaces.Get(i3);
+		      int other = i2.I1() + i2.I2() - ei;
+
+		      if (other != tempels.Get(ei).NB1(j))
+		      cerr << "different1 !!" << endl;
+
+		      if (other)
+		      {
+		      elstack.Append (other);
+		      }
+		      }
+		      else
+		      if (tempels.Get(ei).NB1(j))
+		      cerr << "different2 !!" << endl;
+		    */
+
+		  }
+	      }
+	  }
+      }
+
+
+
+    // check outer elements
+    if (debugparam.slowchecks)
+      {
+	for (int i = 1; i <= ne; i++)
+	  {
+	    const DelaunayTet & el = tempels.Get(i);
+	    const Point3d & p1 = mesh.Point (el[0]);
+	    const Point3d & p2 = mesh.Point (el[1]);
+	    const Point3d & p3 = mesh.Point (el[2]);
+	    const Point3d & p4 = mesh.Point (el[3]);
+	  
+	    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 (int 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 (int i = ne; i >= 1; i--)
+      {
+	if (outer.Test(i))
+	  tempels.DeleteElement(i);
+      }
+
+
+    // mesh.points.SetSize(mesh.points.Size()-4);
+
+    for (int i = 0; i < tempels.Size(); i++)
+      {
+	Element el(4);
+	for (int j = 0; j < 4; j++)
+	  el[j] = tempels[i][j];
+	mesh.AddVolumeElement (el);
+      }
+
+    PrintMessage (5, "outer removed");
+
+    mesh.FindOpenElements(domainnr);
+
+    mesh.Compress();
+
+    PopStatus ();
+  }
+}
diff --git a/contrib/Netgen/libsrc/meshing/delaunay2d.cpp b/contrib/Netgen/libsrc/meshing/delaunay2d.cpp
new file mode 100644
index 0000000000..2b1119f190
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/delaunay2d.cpp
@@ -0,0 +1,174 @@
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+// not yet working ....
+
+namespace netgen
+{
+
+  void Meshing2 :: BlockFillLocalH (Mesh & mesh, const MeshingParameters & mp)
+  {
+    double filldist = mp.filldist;
+    
+    cout << "blockfill local h" << endl;
+    cout << "rel filldist = " << filldist << endl;
+    PrintMessage (3, "blockfill local h");
+
+    Array<Point<3> > npoints;
+  
+    // adfront -> CreateTrees();
+
+    Box<3> bbox ( Box<3>::EMPTY_BOX );
+    double maxh = 0;
+    
+    for (int i = 0; i < adfront->GetNFL(); i++)
+      {
+	const FrontLine & line = adfront->GetLine (i);
+
+	const Point<3> & p1 = adfront->GetPoint(line.L().I1());
+	const Point<3> & p2 = adfront->GetPoint(line.L().I2());
+	
+	double hi = Dist (p1, p2);
+	if (hi > maxh) maxh = hi;
+	
+	bbox.Add (p1);
+	bbox.Add (p2);
+      }
+
+    
+    cout << "bbox = " << bbox << endl;
+
+
+    // Point<3> mpc = bbox.Center();
+    bbox.Increase (bbox.Diam()/2);
+    Box<3> meshbox = bbox;
+    
+    LocalH loch2 (bbox, 1);
+    
+    if (mp.maxh < maxh) maxh = mp.maxh;
+    
+    bool changed;
+    do 
+      {
+	mesh.LocalHFunction().ClearFlags();
+	
+	for (int i = 0; i < adfront->GetNFL(); i++)
+	  {
+	    const FrontLine & line = adfront->GetLine(i);
+	    
+	    Box<3> bbox (adfront->GetPoint (line.L().I1()));
+	    bbox.Add (adfront->GetPoint (line.L().I2()));
+
+	    
+	    double filld = filldist * bbox.Diam();
+	    bbox.Increase (filld);
+	    
+	    mesh.LocalHFunction().CutBoundary (bbox); 
+	  }
+	
+
+	mesh.LocalHFunction().FindInnerBoxes (adfront, NULL);
+	
+	npoints.SetSize(0);
+	mesh.LocalHFunction().GetInnerPoints (npoints);
+
+	changed = false;
+	for (int i = 0; i < npoints.Size(); i++)
+	  {
+	    if (mesh.LocalHFunction().GetH(npoints[i]) > 1.5 * maxh)
+	      {
+		mesh.LocalHFunction().SetH (npoints[i], maxh);
+		changed = true;
+	      }
+	  }
+      }
+    while (changed);
+
+    if (debugparam.slowchecks)
+      (*testout) << "Blockfill with points: " << endl;
+    *testout << "loch = " << mesh.LocalHFunction() << endl;
+    
+    *testout << "npoints = " << endl << npoints << endl;
+
+    for (int 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;
+
+		Point<2> p2d (npoints.Get(i)(0), npoints.Get(i)(1));
+		if (!adfront->Inside(p2d))
+		  {
+		    cout << "add outside point" << endl;
+		    (*testout) << "outside" << endl;
+		  }
+	      }
+	    
+	  }
+      }
+    
+  
+
+  // find outer points
+  
+    loch2.ClearFlags();
+
+    for (int i = 0; i < adfront->GetNFL(); i++)
+      {
+	const FrontLine & line = adfront->GetLine(i);
+	
+	Box<3> bbox (adfront->GetPoint (line.L().I1()));
+	bbox.Add (adfront->GetPoint (line.L().I2()));
+	
+	loch2.SetH (bbox.Center(), bbox.Diam());
+      }
+
+
+    for (int i = 0; i < adfront->GetNFL(); i++)
+      {
+	const FrontLine & line = adfront->GetLine(i);
+	
+	Box<3> bbox (adfront->GetPoint (line.L().I1()));
+	bbox.Add (adfront->GetPoint (line.L().I2()));
+
+	bbox.Increase (filldist * bbox.Diam());
+	loch2.CutBoundary (bbox);
+      }
+    
+    loch2.FindInnerBoxes (adfront, NULL);
+    
+    npoints.SetSize(0);
+    loch2.GetOuterPoints (npoints);
+    
+    for (int 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);
+	  }
+      }  
+
+  }
+  
+  void Meshing2 :: Delaunay (Mesh & mesh, int domainnr, const MeshingParameters & mp)
+  {
+    cout << "2D Delaunay meshing (in progress)" << endl;
+
+    // int oldnp = mesh.GetNP();
+
+    cout << "np, old = " << mesh.GetNP() << endl;
+
+    BlockFillLocalH (mesh, mp);
+
+
+    cout << "np, now = " << mesh.GetNP() << endl;
+    
+  }
+
+}
diff --git a/contrib/Netgen/libsrc/meshing/findip.hpp b/contrib/Netgen/libsrc/meshing/findip.hpp
new file mode 100644
index 0000000000..f5d8e4249f
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/findip.hpp
@@ -0,0 +1,192 @@
+// find inner point
+
+
+
+inline void Minimize (const Array<Vec3d> & a,
+		      const Array<double> & c,
+		      int * act, 
+		      Vec<3> & x, double & f,
+		      int * sol)
+{
+  int act1[4];
+  Mat<3> m, inv;
+  Vec<3> rs, xmax, center;
+
+  f = 1e99;
+
+  for (int j = 0; j < 5; j++)
+    {
+      for (int hk = 0, k = 0; hk < 4; hk++)
+	{
+	  if (hk == j) k++;
+	  act1[hk] = act[k];
+	  k++;
+	}
+
+      for (int k = 0; k < 3; k++)
+	{
+	  m(k, 0) = a[act1[0]].X() - a[act1[k+1]].X();
+	  m(k, 1) = a[act1[0]].Y() - a[act1[k+1]].Y();
+	  m(k, 2) = a[act1[0]].Z() - a[act1[k+1]].Z();
+	  rs(k) = c[act1[k+1]] - c[act1[0]];
+	}
+
+      /*
+      (*testout) << "act1 = "
+		 << act1[0] << " "
+		 << act1[1] << " "
+		 << act1[2] << " "
+		 << act1[3] << endl;
+      (*testout) << "Det = " << Det(m) << endl;
+      */
+
+      if (fabs (Det (m)) > 1e-10)
+	{
+	  CalcInverse (m, inv);
+	  xmax = inv * rs;
+	  
+	  double fmax = -1e10;
+	  for (int k = 0; k < 5; k++)
+	    {
+	      double hd = 
+		xmax(0) * a[act[k]].X() + xmax(1) * a[act[k]].Y() + xmax(2) * a[act[k]].Z() + c[act[k]];
+	      if (hd > fmax) fmax = hd;
+	    }
+
+	  if (fmax < f)
+	    {
+	      f = fmax;
+	      x = xmax;
+	      for (int k = 0; k < 4; k++)
+		sol[k] = act1[k];
+	    }
+	}
+    }
+}
+
+
+
+
+template <typename POINTArray, typename FACEArray>
+inline int FindInnerPoint (POINTArray & points,
+			   FACEArray & faces,
+			   Point3d & p)
+{
+  static int timer = NgProfiler::CreateTimer ("FindInnerPoint");
+  NgProfiler::RegionTimer reg (timer);
+
+  Array<Vec3d> a;
+  Array<double> c;
+  Mat<3> m, inv;
+  Vec<3> rs, x = 0.0, center;
+  double f;
+
+  int nf = faces.Size();
+
+  // minimize_x  max_i  a_i x + c_i
+
+  a.SetSize (nf+4);
+  c.SetSize (nf+4);
+
+  for (int i = 0; i < nf; i++)
+    {
+      Point3d p1 = points.Get(faces[i][0]);
+      a[i] = Cross (points.Get(faces[i][1]) - p1,
+		    points.Get(faces[i][2]) - p1);
+      a[i] /= a[i].Length();
+      c[i] = - (a[i].X() * p1.X() + a[i].Y() * p1.Y() + a[i].Z() * p1.Z());
+    }
+
+  /*
+  center = 0;
+  for (int i = 0; i < points.Size(); i++)
+    center += Vec<3> (points[i]);
+  center /= points.Size();
+  */
+
+  center = 0;
+  for (int i = 0; i < faces.Size(); i++)
+    for (int j = 0; j < 3; j++)
+      center += Vec<3> (points.Get(faces[i][j]));
+  center /= (3*faces.Size());
+
+
+  // (*testout) << "center = " << center << endl;
+
+  double hmax = 0;
+  for (int i = 0; i < nf; i++)
+    {
+      // const Element2d & el = faces[i];
+      // (*testout) << "el[" << i << "] = " << el << endl;
+      for (int j = 1; j <= 3; j++)
+	{
+	  double hi = Dist (points.Get(faces[i].PNumMod(j)),
+			    points.Get(faces[i].PNumMod(j+1)));
+	  if (hi > hmax) hmax = hi;
+	}
+    }
+  
+  // (*testout) << "hmax = " << hmax << endl;
+  
+  a[nf] = Vec<3> (1, 0, 0);
+  c[nf] = -center(0) - hmax;
+  a[nf+1] = Vec<3> (0, 1, 0);
+  c[nf+1] = -center(1) - hmax;
+  a[nf+2] = Vec<3> (0, 0, 1);
+  c[nf+2] = -center(2) - hmax;
+  a[nf+3] = Vec<3> (-1, -1, -1);
+  c[nf+3] = center(0)+center(1)+center(2)-3*hmax;
+
+  /*
+  (*testout) << "findip, a now = " << endl << a << endl;
+  (*testout) << "findip, c now = " << endl << c << endl;
+  */
+
+  int act[5] = { 0, nf, nf+1, nf+2, nf+3 };
+  int sol[4];
+
+  while (1)
+    {
+      /*
+      (*testout) << "try ";
+      for (int j = 0; j < 5; j++)
+	(*testout)  << act[j] << " ";
+      */
+
+      Minimize (a, c, act, x, f, sol);
+
+      /*
+      (*testout) << endl << "sol = ";
+      for (int j = 0; j < 4; j++)
+	(*testout)  << sol[j] << " ";
+
+      (*testout) << " fmin = " << f << endl;
+      */
+      for (int j = 0; j < 4; j++) act[j] = sol[j];
+      
+      bool found = 0;
+      double maxval = f;
+      for (int j = 0; j < nf; j++)
+	{
+	  double val = x(0) * a[j].X() + x(1) * a[j].Y() + x(2) * a[j].Z() + c[j];
+	  if (val > maxval + hmax * 1e-6)
+	    {
+	      found = 1;
+	      maxval = val;
+	      act[4] = j;
+	    }
+	}
+      
+      // (*testout) << "maxval = " << maxval << endl;
+      if (!found) break;
+    }
+  
+  // cout << "converged, f = " << f << endl;
+  
+  p = Point3d (x(0), x(1), x(2));
+  // (*testout) << "findip, f = " << f << ", hmax = " << hmax << endl;
+  return (f < -1e-5 * hmax);
+}
+
+
+
diff --git a/contrib/Netgen/libsrc/meshing/findip2.hpp b/contrib/Netgen/libsrc/meshing/findip2.hpp
new file mode 100644
index 0000000000..9538553485
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/findip2.hpp
@@ -0,0 +1,95 @@
+// find inner point
+
+template <typename POINTArray, typename FACEArray>
+inline int FindInnerPoint2 (POINTArray & points,
+			    FACEArray & faces,
+			    Point3d & p)
+{
+  static int timer = NgProfiler::CreateTimer ("FindInnerPoint2");
+  NgProfiler::RegionTimer reg (timer);
+
+  Array<Vec3d> a;
+  Array<double> c;
+  Mat<3> m, inv;
+  Vec<3> rs, x, pmin;
+
+  int nf = faces.Size();
+
+  a.SetSize (nf);
+  c.SetSize (nf);
+
+  for (int i = 0; i < nf; i++)
+    {
+      Point3d p1 = points.Get(faces[i][0]);
+      a[i] = Cross (points.Get(faces[i][1]) - p1,
+		    points.Get(faces[i][2]) - p1);
+      a[i] /= a[i].Length();
+      c[i] = - (a[i].X() * p1.X() + a[i].Y() * p1.Y() + a[i].Z() * p1.Z());
+    }
+
+
+  x = 0;
+  
+  
+  double hmax = 0;
+  for (int i = 0; i < nf; i++)
+    {
+      const Element2d & el = faces[i];
+      for (int j = 1; j <= 3; j++)
+	{
+	  double hi = Dist (points.Get(el.PNumMod(j)),
+			    points.Get(el.PNumMod(j+1)));
+	  if (hi > hmax) hmax = hi;
+	}
+    }
+
+  double fmin = 0;
+
+  for (int i1 = 1; i1 <= nf; i1++)
+    for (int i2 = i1+1; i2 <= nf; i2++)
+      for (int i3 = i2+1; i3 <= nf; i3++)
+        for (int i4 = i3+1; i4 <= nf; i4++)
+          {
+	    m(0, 0) = a.Get(i1).X() - a.Get(i2).X();
+	    m(0, 1) = a.Get(i1).Y() - a.Get(i2).Y();
+	    m(0, 2) = a.Get(i1).Z() - a.Get(i2).Z();
+	    rs(0) = c.Get(i2) - c.Get(i1);
+
+	    m(1, 0) = a.Get(i1).X() - a.Get(i3).X();
+	    m(1, 1) = a.Get(i1).Y() - a.Get(i3).Y();
+	    m(1, 2) = a.Get(i1).Z() - a.Get(i3).Z();
+	    rs(1) = c.Get(i3) - c.Get(i1);
+
+	    m(2, 0) = a.Get(i1).X() - a.Get(i4).X();
+	    m(2, 1) = a.Get(i1).Y() - a.Get(i4).Y();
+	    m(2, 2) = a.Get(i1).Z() - a.Get(i4).Z();
+	    rs(2) = c.Get(i4) - c.Get(i1);
+
+
+	    if (fabs (Det (m)) > 1e-10)
+	      {
+		CalcInverse (m, inv);
+		x = inv * rs;
+
+		double f = -1e10;
+		for (int i = 0; i < nf; i++)
+		  {
+		    double hd = 
+		      x(0) * a[i].X() + x(1) * a[i].Y() + x(2) * a[i].Z() + c[i];
+		    if (hd > f) f = hd;
+		    if (hd > fmin) break;
+		  }
+
+		if (f < fmin)
+		  {
+		    fmin = f;
+		    pmin = x;
+		  }
+	      }
+          }
+
+  p = Point3d (pmin(0), pmin(1), pmin(2));
+  (*testout) << "fmin = " << fmin << endl;
+  return (fmin < -1e-3 * hmax);
+}
+
diff --git a/contrib/Netgen/libsrc/meshing/geomsearch.cpp b/contrib/Netgen/libsrc/meshing/geomsearch.cpp
new file mode 100644
index 0000000000..dc217a4809
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/geomsearch.cpp
@@ -0,0 +1,263 @@
+#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 = 0; i < size.i1*size.i2*size.i3; i++)
+	  delete hashtable[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 MiniElement2d& elem)
+  {
+    maxp.X()=(*points)[elem.PNum(1)].P()(0);
+    maxp.Y()=(*points)[elem.PNum(1)].P()(1);
+    maxp.Z()=(*points)[elem.PNum(1)].P()(2);
+    minp.X()=(*points)[elem.PNum(1)].P()(0);
+    minp.Y()=(*points)[elem.PNum(1)].P()(1);
+    minp.Z()=(*points)[elem.PNum(1)].P()(2);
+  
+    for (int i=2; i <= 3; i++)
+      {
+	maxp.X()=max2((*points)[elem.PNum(i)].P()(0),maxp.X());
+	maxp.Y()=max2((*points)[elem.PNum(i)].P()(1),maxp.Y());
+	maxp.Z()=max2((*points)[elem.PNum(i)].P()(2),maxp.Z());
+	minp.X()=min2((*points)[elem.PNum(i)].P()(0),minp.X());
+	minp.Y()=min2((*points)[elem.PNum(i)].P()(1),minp.Y());
+	minp.Z()=min2((*points)[elem.PNum(i)].P()(2),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 MiniElement2d& 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.);
+  
+    for (int ix = sx; ix <= ex; ix++)
+      for (int iy = sy; iy <= ey; iy++)
+        for (int 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;
+		    throw NgException ("Illegal position in Geomsearch");
+              }
+            hashtable.Elem(ind)->Append(elemnum);		      
+          }
+  }
+
+  void GeomSearch3d :: GetLocals(Array<MiniElement2d> & 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 MiniElement2d & face = faces->Get(i).Face();
+		      
+			const Point3d & p1 = (*points)[face.PNum(1)].P();
+			const Point3d & p2 = (*points)[face.PNum(2)].P();
+			const Point3d & p3 = (*points)[face.PNum(3)].P();
+		      
+			midp = Center (p1, p2, p3);
+		      
+			// if (Dist2 (midp, p0) <= xh*xh)  
+                        if((Dist2 (p1, p0) <= xh*xh) ||
+                           (Dist2 (p2, p0) <= xh*xh) ||
+                           (Dist2 (p3, p0) <= xh*xh) ||
+                           (Dist2 (midp, p0) <= xh*xh) )  // by Jochen Wild
+			  {
+			    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/contrib/Netgen/libsrc/meshing/geomsearch.hpp b/contrib/Netgen/libsrc/meshing/geomsearch.hpp
new file mode 100644
index 0000000000..052073de59
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/geomsearch.hpp
@@ -0,0 +1,117 @@
+#ifndef FILE_GEOMSEARCH
+#define FILE_GEOMSEARCH
+
+/**************************************************************************/
+/* File:   geomsearch.hh                                                  */
+/* Author: Johannes Gerstmayr                                             */
+/* Date:   19. Nov. 97                                                    */
+/**************************************************************************/
+
+class FrontPoint3;
+class FrontFace;
+class MiniElement2d;
+
+  /// 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 MiniElement2d& 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 MiniElement2d& elem, INDEX elemnum);
+
+  ///GetLocal faces in sphere with radius xh and middlepoint p
+  void GetLocals(Array<MiniElement2d> & 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/contrib/Netgen/libsrc/meshing/global.cpp b/contrib/Netgen/libsrc/meshing/global.cpp
new file mode 100644
index 0000000000..b0f0108a7c
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/global.cpp
@@ -0,0 +1,59 @@
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+
+namespace netgen
+{
+  // stringstream emptystr;
+  // ostream * testout = &emptystr;
+  // testout -> clear(ios::failbit);
+
+  // ostream * testout = &cout;
+  ostream * testout = new ostream(0);
+
+  // NetgenOutStream * testout = new NetgenOutStream;
+
+  ostream * mycout = &cout;
+  ostream * myerr = &cerr;
+
+
+  //  Flags parameters;
+
+
+  int silentflag = 0;
+  int testmode = 0;
+
+  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/contrib/Netgen/libsrc/meshing/global.hpp b/contrib/Netgen/libsrc/meshing/global.hpp
new file mode 100644
index 0000000000..43a204930f
--- /dev/null
+++ b/contrib/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
+*/
+
+namespace netgen
+{
+
+  ///
+  DLL_HEADER extern double GetTime ();
+  extern void ResetTime ();
+
+  ///
+  extern int testmode;
+
+  /// calling parameters
+  // extern Flags parameters;
+
+  // extern DLL_HEADER 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;
+    const char * task;
+    bool demorunning;
+    multithreadt();
+  };
+
+  extern volatile multithreadt multithread;
+
+  extern string ngdir;
+  extern DebugParameters debugparam;
+  extern bool verbose;  
+}
+
+#endif
diff --git a/contrib/Netgen/libsrc/meshing/hpref_hex.hpp b/contrib/Netgen/libsrc/meshing/hpref_hex.hpp
new file mode 100644
index 0000000000..11e3f86e49
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/hpref_hex.hpp
@@ -0,0 +1,236 @@
+// SZ 
+
+// HP_HEX  ... no refinement
+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_1F  ... face (1 - 4 - 3 -2) singular 
+int refhex_1f_0e_0v_splitedges[][3] =
+  {
+    { 1, 5, 9 },
+    { 2, 6, 10 },
+    { 3, 7, 11 },
+    { 4, 8, 12 }, 
+    { 0, 0, 0 }
+  };
+HPREF_ELEMENT_TYPE refhex_1f_0e_0v_newelstypes[] =
+  {
+    HP_HEX,
+    HP_HEX_1F_0E_0V,
+    HP_NONE,
+  };
+int  refhex_1f_0e_0v_newels[][8] =
+  {
+    { 9, 10, 11, 12, 5, 6, 7, 8 }, 
+    { 1, 2, 3, 4, 9, 10, 11, 12}  
+ }; 
+HPRef_Struct refhex_1f_0e_0v =
+  {
+    HP_HEX,
+    refhex_1f_0e_0v_splitedges, 
+    0, 0,
+    refhex_1f_0e_0v_newelstypes, 
+    refhex_1f_0e_0v_newels
+  };
+
+
+
+// HP_HEX_1FA_1FB  ... face (1 - 4 - 3 -2) and face (1-2-6-5) singular 
+int refhex_1fa_1fb_0e_0v_splitedges[][3] =
+  {
+    { 1, 5, 9 },
+    { 2, 6, 10 },
+    { 3, 7, 11 },
+    { 4, 8, 12 },
+    { 1, 4, 13 },
+    { 2, 3, 14 },  
+    { 6, 7, 15 }, 
+    { 5, 8, 16 }, 
+    { 0, 0, 0 }
+  };
+
+int refhex_1fa_1fb_0e_0v_splitfaces[][4] =
+  {
+    { 2, 3, 6, 17 },
+    { 1, 4, 5, 18 },
+    { 0, 0, 0, 0 },
+  };
+HPREF_ELEMENT_TYPE refhex_1fa_1fb_0e_0v_newelstypes[] =
+  {
+    HP_HEX,
+    HP_HEX_1F_0E_0V,
+    HP_HEX_1F_0E_0V, 
+    HP_HEX_1FA_1FB_0E_0V, 
+    HP_NONE,
+  };
+int  refhex_1fa_1fb_0e_0v_newels[][8] =
+  {
+    {18, 17, 11, 12, 16, 15, 7, 8}, 
+    {13, 14, 3, 4, 18, 17, 11, 12},
+    { 5, 6, 10, 9, 16, 15, 17, 18}, 
+    { 1, 2, 14, 13, 9, 10, 17, 18} 
+  }; 
+HPRef_Struct refhex_1fa_1fb_0e_0v =
+  {
+    HP_HEX,
+    refhex_1fa_1fb_0e_0v_splitedges, 
+    refhex_1fa_1fb_0e_0v_splitfaces, 0,
+    refhex_1fa_1fb_0e_0v_newelstypes, 
+    refhex_1fa_1fb_0e_0v_newels
+  };
+
+
+
+// Refine Dummies 
+  // 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
+    };
+
+
+
+// Refine Dummies 
+  // HP_HEX_1E_1V
+  int refhex_1e_1v_splitedges[][3] =
+    {
+      { 0, 0, 0 }
+    };
+  HPREF_ELEMENT_TYPE refhex_1e_1v_newelstypes[] =
+    {
+      HP_TET_1E_1VA,
+      HP_TET,
+      HP_TET_0E_1V,
+      HP_TET_0E_1V,
+      HP_TET_0E_1V,
+      HP_TET_0E_1V,
+      HP_NONE,
+    };
+  int refhex_1e_1v_newels[][8] =
+    {
+      // { 1, 5, 2, 4 }, 
+      { 1, 2, 4, 5 },
+      { 7, 3, 6, 8 },
+      { 2, 8, 5, 6 },
+      { 2, 8, 6, 3 },
+      { 2, 8, 3, 4 },
+      { 2, 8, 4, 5 },
+    };
+  HPRef_Struct refhex_1e_1v =
+    {
+      HP_HEX,
+      refhex_1e_1v_splitedges, 
+      0, 0,
+      refhex_1e_1v_newelstypes, 
+      refhex_1e_1v_newels
+    };
+
+
+// Refine Dummies 
+  // 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
+    };
+
+
+
+// Refine Dummies 
+  // 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_SINGEDGE_H1,
+      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
+    };
+
+
diff --git a/contrib/Netgen/libsrc/meshing/hpref_prism.hpp b/contrib/Netgen/libsrc/meshing/hpref_prism.hpp
new file mode 100644
index 0000000000..3cceb44a57
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/hpref_prism.hpp
@@ -0,0 +1,3405 @@
+
+  // HP_PRISM  ... no refinement
+  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  ... vertical edge 1-4 is singular
+  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_PRISM_SINGEDGE_V12  vertical edges 1-4 and 2-5 are singular 
+  int refprism_singedge_v12_splitedges[][3] =
+    {
+      { 1, 2, 7 },
+      { 1, 3, 8 },
+      { 2, 1, 9 },
+      { 2, 3, 10 },
+      { 4, 5, 11 },
+      { 4, 6, 12 },
+      { 5, 4, 13 },
+      { 5, 6, 14},
+      { 0, 0, 0 }
+    };
+  HPREF_ELEMENT_TYPE refprism_singedge_v12_newelstypes[] =
+    {
+      HP_HEX,
+      HP_PRISM_SINGEDGE,
+      HP_PRISM_SINGEDGE,
+      HP_PRISM,
+      HP_NONE,
+    };
+  int refprism_singedge_v12_newels[][8] =
+    {
+      { 7, 9, 10, 8, 11, 13, 14, 12 },
+      { 1, 7, 8, 4, 11, 12 },
+      { 2, 10, 9, 5, 14, 13 },
+      { 3, 8, 10, 6, 12, 14 },
+    };
+  HPRef_Struct refprism_singedge_v12 =
+    {
+      HP_PRISM,
+      refprism_singedge_v12_splitedges, 
+      0, 0,
+      refprism_singedge_v12_newelstypes, 
+      refprism_singedge_v12_newels
+    };
+
+
+
+
+
+
+  // HP_PRISM_SINGEDGE_H12
+  int refprism_singedge_h12_splitedges[][3] =
+    {
+      { 1, 3, 7 },
+      { 2, 1, 8 },
+      { 2, 3, 9 },
+      { 3, 1, 10 },
+
+      { 4, 6, 12 },
+      { 5, 4, 13 },
+      { 5, 6, 14 },
+      { 6, 4, 15 },
+
+      { 0, 0, 0 }
+    };
+
+  int refprism_singedge_h12_splitfaces[][4] =
+    {
+      { 2, 1, 3, 11 },
+      { 5, 4, 6, 16 },
+      { 0, 0, 0, 0 },
+    };
+
+  HPREF_ELEMENT_TYPE refprism_singedge_h12_newelstypes[] =
+    {
+      HP_HEX,
+      HP_HEX,
+      HP_PRISM,
+      HP_PRISM,
+      HP_PRISM,
+      HP_NONE,
+    };
+  int refprism_singedge_h12_newels[][8] =
+    {
+      { 1, 8, 11, 7, 4, 13, 16, 12 },
+      { 9, 3, 10, 11, 14, 6, 15, 16 },
+      { 7, 11, 10, 12, 16, 15 },
+      { 2, 9, 11, 5, 14, 16 },
+      { 8, 2, 11, 13, 5, 16 }
+    };
+  HPRef_Struct refprism_singedge_h12 =
+    {
+      HP_PRISM,
+      refprism_singedge_h12_splitedges, 
+      refprism_singedge_h12_splitfaces, 
+      0,
+      refprism_singedge_h12_newelstypes, 
+      refprism_singedge_h12_newels
+    };
+
+
+
+
+
+
+  // HP_PRISM_SINGEDGE_H1
+  int refprism_singedge_h1_splitedges[][3] =
+    {
+      { 1, 3, 7 },
+      { 2, 3, 8 },
+      { 4, 6, 9 },
+      { 5, 6, 10 },
+      { 0, 0, 0 }
+    };
+  HPREF_ELEMENT_TYPE refprism_singedge_h1_newelstypes[] =
+    {
+      HP_HEX,
+      HP_PRISM,
+      HP_NONE,
+    };
+  int refprism_singedge_h1_newels[][8] =
+    {
+      { 1, 2, 8, 7, 4, 5, 10, 9 },
+      { 3, 7, 8, 6, 9, 10 }
+    };
+  HPRef_Struct refprism_singedge_h1 =
+    {
+      HP_PRISM,
+      refprism_singedge_h1_splitedges, 
+      0, 0,
+      refprism_singedge_h1_newelstypes, 
+      refprism_singedge_h1_newels
+    };
+
+
+
+//  HP_PRISM_1FA_0E_0V
+  int refprism_1fa_0e_0v_splitedges[][3] =
+    {
+      { 1, 4, 16 },
+      { 2, 5, 17 },
+      { 3, 6, 18 },
+      { 0, 0, 0 }
+    };
+  HPREF_ELEMENT_TYPE refprism_1fa_0e_0v_newelstypes[] =
+    {
+      HP_PRISM,
+      HP_PRISM_1FA_0E_0V,
+      HP_NONE,
+    };
+  int refprism_1fa_0e_0v_newels[][8] =
+    {
+      { 16, 17, 18, 4, 5, 6 },      
+      { 1, 2, 3, 16, 17, 18 }
+    };
+  HPRef_Struct refprism_1fa_0e_0v =
+    {
+      HP_PRISM,
+      refprism_1fa_0e_0v_splitedges, 
+      0, 0,
+      refprism_1fa_0e_0v_newelstypes, 
+      refprism_1fa_0e_0v_newels
+    };
+
+//  HP_PRISM_1FA_1E_0V
+  int refprism_1fa_1e_0v_splitedges[][3] =
+    {
+      { 1, 4, 16 },
+      { 2, 5, 17 },
+      { 3, 6, 18 },
+      { 1, 2, 7},
+      { 1, 3, 12},
+      { 4, 6, 45},
+      { 4, 5, 40},
+      { 0, 0, 0 }
+    };
+  int refprism_1fa_1e_0v_splitfaces[][4] =
+    {
+      {1,2,4,19},
+      {1,3,4,24},
+      {0,0,0,0}
+    }; 
+
+  HPREF_ELEMENT_TYPE refprism_1fa_1e_0v_newelstypes[] =
+    {
+      HP_PRISM_SINGEDGE,
+      HP_HEX,
+      HP_PRISM_1FA_1E_0V,
+      HP_HEX_1F_0E_0V,
+      HP_NONE,
+    };
+  int refprism_1fa_1e_0v_newels[][8] =
+    {
+      { 16, 19, 24, 4, 40, 45 }, 
+      { 24, 19,  17, 18, 45 , 40, 5, 6 }, 
+      { 1, 7 , 12 , 16, 19, 24 }, 
+      { 7, 2, 3, 12,  19, 17, 18, 24 }
+    };
+  HPRef_Struct refprism_1fa_1e_0v =
+    {
+      HP_PRISM,
+      refprism_1fa_1e_0v_splitedges, 
+      refprism_1fa_1e_0v_splitfaces, 
+      0,
+      refprism_1fa_1e_0v_newelstypes, 
+      refprism_1fa_1e_0v_newels
+    };
+
+//  HP_PRISM_2FA_1E_0V
+  int refprism_2fa_1e_0v_splitedges[][3] =
+    {
+      { 1, 4, 16 },
+      { 2, 5, 17 },
+      { 3, 6, 18 },
+      { 1, 2, 7}, 
+      { 1, 3, 12},
+      { 4, 6, 45},
+      { 4, 5, 40},
+      { 4, 1, 28},
+      { 5, 2, 29},
+      { 6, 3, 30},
+      { 0, 0, 0 }
+    };
+  int refprism_2fa_1e_0v_splitfaces[][4] =
+    {
+      {1,2,4,19},
+      {1,3,4,24},
+      {4,1,5,31},
+      {4,1,6,36},
+      {0,0,0,0}
+    }; 
+
+  HPREF_ELEMENT_TYPE refprism_2fa_1e_0v_newelstypes[] =
+    {
+      HP_PRISM_SINGEDGE,
+      HP_HEX,
+      HP_PRISM_1FA_1E_0V,
+      HP_HEX_1F_0E_0V,
+      HP_PRISM_1FA_1E_0V, 
+      HP_HEX_1F_0E_0V, 
+      HP_NONE,
+    };
+  int refprism_2fa_1e_0v_newels[][8] =
+    {
+      { 16, 19, 24, 28, 31, 36 }, 
+      { 24, 19,  17, 18, 36, 31, 29, 30 }, 
+      { 1, 7 , 12 , 16, 19, 24 }, 
+      { 12, 7, 2, 3, 24, 19, 17, 18 },
+      { 4, 45, 40, 28, 36, 31 }, 
+      { 40, 45, 6, 5, 31, 36, 30, 29,}
+    };
+  HPRef_Struct refprism_2fa_1e_0v =
+    {
+      HP_PRISM,
+      refprism_2fa_1e_0v_splitedges, 
+      refprism_2fa_1e_0v_splitfaces,
+      0,
+      refprism_2fa_1e_0v_newelstypes, 
+      refprism_2fa_1e_0v_newels
+    };
+
+//  HP_PRISM_1FB_0E_0V   ... quad face 1-2-4-5
+  int refprism_1fb_0e_0v_splitedges[][3] =
+    {
+      { 1, 3, 7 },
+      { 2, 3, 8 },
+      { 4, 6, 9 },
+      { 5, 6, 10 },
+      { 0, 0, 0 }
+    };
+  HPREF_ELEMENT_TYPE refprism_1fb_0e_0v_newelstypes[] =
+    {
+      HP_HEX_1F_0E_0V,
+      HP_PRISM,
+      HP_NONE,
+    };
+  int refprism_1fb_0e_0v_newels[][8] =
+    {
+      { 1, 4, 5, 2, 7, 9, 10, 8  },
+      { 7, 8, 3, 9, 10, 6 }
+    };
+  HPRef_Struct refprism_1fb_0e_0v =
+    {
+      HP_PRISM,
+      refprism_1fb_0e_0v_splitedges, 
+
+      0, 0,
+      refprism_1fb_0e_0v_newelstypes, 
+      refprism_1fb_0e_0v_newels
+    };
+
+
+//  HP_PRISM_1FB_1EA_0V   ... quad face 1-2-4-5
+  int refprism_1fb_1ea_0v_splitedges[][3] =
+    {
+      { 1, 3, 7 },
+      { 2, 3, 8 },
+      { 4, 6, 9 },
+      { 5, 6, 10 },
+      { 1, 2, 11 },
+      { 4, 5, 12 },
+      { 0, 0, 0 }
+    };
+  HPREF_ELEMENT_TYPE refprism_1fb_1ea_0v_newelstypes[] =
+    {
+      HP_HEX_1F_0E_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM,
+      HP_NONE,
+    };
+  int refprism_1fb_1ea_0v_newels[][8] =
+    {
+      { 11, 12, 5, 2, 7, 9, 10, 8  },
+      { 1, 11, 7, 4, 12, 9 },
+      { 7, 8, 3, 9, 10, 6 }
+    };
+  HPRef_Struct refprism_1fb_1ea_0v =
+    {
+      HP_PRISM,
+      refprism_1fb_1ea_0v_splitedges, 
+      0, 0,
+      refprism_1fb_1ea_0v_newelstypes, 
+      refprism_1fb_1ea_0v_newels
+    };
+
+//  HP_PRISM_1FB_1EC_0V   ... quad face 1-2-4-5 with singular edge 3-6 
+  int refprism_1fb_1ec_0v_splitedges[][3] =
+    {
+      {2,3,9},
+      {1,3,12},
+      {3,2,10},
+      {3,1,11},
+      {5,6,42},
+      {4,6,45},
+      {6,5,43},
+      {6,4,44},
+      { 0, 0, 0 }
+    };
+  HPREF_ELEMENT_TYPE refprism_1fb_1ec_0v_newelstypes[] =
+    {
+      HP_PRISM_SINGEDGE, 
+      HP_HEX, 
+      HP_HEX_1F_0E_0V,
+      HP_NONE,
+    };
+  int refprism_1fb_1ec_0v_newels[][8] =
+    {
+      { 3, 11, 10, 6, 44, 43},
+      { 12, 9, 10, 11, 45, 42, 43, 44}, 
+      { 4, 5, 2, 1, 45, 42, 9, 12 } 
+    };
+  HPRef_Struct refprism_1fb_1ec_0v =
+    {
+      HP_PRISM,
+      refprism_1fb_1ec_0v_splitedges, 
+      0, 0,
+      refprism_1fb_1ec_0v_newelstypes, 
+      refprism_1fb_1ec_0v_newels
+    };
+
+//  HP_PRISM_1FA_1FB_1EC_0V   ... bot-trig face, quad face 1-2-4-5 with singular edge 3-6 
+  int refprism_1fa_1fb_1ec_0v_splitedges[][3] =
+    {
+      {2,3,9},
+      {1,3,12},
+      {3,2,10},
+      {3,1,11},
+      {5,6,42},
+      {4,6,45},
+      {6,5,43},
+      {6,4,44},
+      {1,4,16}, 
+      {2,5,17},
+      {3,6,18},
+      { 0, 0, 0 }
+    };
+
+ int refprism_1fa_1fb_1ec_0v_splitfaces[][4] =
+   {
+     {2,3,5,21},
+     {3,2,6,22},
+     {3,1,6,23},
+     {1,3,4,24},
+     {0,0,0,0}
+   }; 
+  HPREF_ELEMENT_TYPE refprism_1fa_1fb_1ec_0v_newelstypes[] =
+    {
+      HP_PRISM_SINGEDGE, 
+      HP_HEX, 
+      HP_HEX_1F_0E_0V,
+      HP_PRISM_1FA_1E_0V, 
+      HP_HEX_1F_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V,
+      HP_NONE,
+    };
+  int refprism_1fa_1fb_1ec_0v_newels[][8] =
+    {
+      { 18, 23, 22, 6, 44, 43},
+      { 24, 21, 22, 23, 45, 42, 43, 44}, 
+      { 4, 5, 17, 16, 45, 42, 21, 24}, 
+      { 3, 11, 10, 18, 23, 22}, 
+      { 12, 9, 10, 11, 24, 21, 22, 23},
+      { 1, 2, 9, 12, 16, 17, 21, 24}
+    };
+  HPRef_Struct refprism_1fa_1fb_1ec_0v =
+    {
+      HP_PRISM,
+      refprism_1fa_1fb_1ec_0v_splitedges,
+      refprism_1fa_1fb_1ec_0v_splitfaces, 0,
+      refprism_1fa_1fb_1ec_0v_newelstypes, 
+      refprism_1fa_1fb_1ec_0v_newels
+    };
+
+
+//  HP_PRISM_1FA_1FB_2EB_0V  
+  int refprism_1fa_1fb_2eb_0v_splitedges[][3] =
+    {
+      {2,3,9},
+      {1,3,12},
+      {3,2,10},
+      {3,1,11},
+      {5,6,42},
+      {4,6,45},
+      {6,5,43},
+      {6,4,44},
+      {1,4,16}, 
+      {2,5,17},
+      {3,6,18},
+      { 4, 5, 40},
+      { 4, 6, 45},
+      { 1, 2, 7},
+      { 0, 0, 0 }
+    };
+
+ int refprism_1fa_1fb_2eb_0v_splitfaces[][4] =
+   {
+     {2,3,5,21},
+     {3,2,6,22},
+     {3,1,6,23},
+     {1,3,4,24},
+     {1,2,4,19},
+     {0,0,0,0}
+   }; 
+  HPREF_ELEMENT_TYPE refprism_1fa_1fb_2eb_0v_newelstypes[] =
+    {
+      HP_PRISM_SINGEDGE, 
+      HP_HEX, 
+      HP_HEX_1F_0E_0V,
+      HP_PRISM_1FA_1E_0V, 
+      HP_HEX_1F_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V,
+      HP_PRISM_1FB_1EA_0V, 
+      HP_PRISM_1FA_1FB_1EA_0V, 
+      HP_NONE,
+    };
+  int refprism_1fa_1fb_2eb_0v_newels[][8] =
+    {
+      { 18, 23, 22, 6, 44, 43},
+      { 24, 21, 22, 23, 45, 42, 43, 44}, 
+      { 40, 5, 17, 19, 45, 42, 21, 24}, 
+      { 3, 11, 10, 18, 23, 22}, 
+      { 12, 9, 10, 11, 24, 21, 22, 23},
+      { 7, 2, 9, 12, 19, 17, 21, 24},
+      {16,19,24,4,40,45},
+      {1,7,12,16,19,24}
+    };
+  HPRef_Struct refprism_1fa_1fb_2eb_0v =
+    {
+      HP_PRISM,
+      refprism_1fa_1fb_2eb_0v_splitedges, 
+      refprism_1fa_1fb_2eb_0v_splitfaces, 0,
+      refprism_1fa_1fb_2eb_0v_newelstypes, 
+      refprism_1fa_1fb_2eb_0v_newels
+    };
+
+ //  HP_PRISM_1FA_1FB_2EC_0V 
+  int refprism_1fa_1fb_2ec_0v_splitedges[][3] =
+    {
+      {2,3,9},
+      {1,3,12},
+      {3,2,10},
+      {3,1,11},
+      {5,6,42},
+      {4,6,45},
+      {6,5,43},
+      {6,4,44},
+      {1,4,16}, 
+      {2,5,17},
+      {3,6,18},
+      {5,4,41},
+      {2,1,8},
+      { 0, 0, 0 }
+    };
+
+ int refprism_1fa_1fb_2ec_0v_splitfaces[][4] =
+   {
+     {2,3,5,21},
+     {3,2,6,22},
+     {3,1,6,23},
+     {1,3,4,24},
+     {2,1,5,20},
+     {0,0,0,0}
+   }; 
+  HPREF_ELEMENT_TYPE refprism_1fa_1fb_2ec_0v_newelstypes[] =
+    {
+      HP_PRISM_SINGEDGE, 
+      HP_HEX, 
+      HP_HEX_1F_0E_0V,
+      HP_PRISM_1FA_1E_0V, 
+      HP_HEX_1F_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V,
+      HP_PRISM_1FA_1FB_1EB_0V, 
+      HP_PRISM_1FB_1EA_0V,
+      HP_NONE,
+    };
+  int refprism_1fa_1fb_2ec_0v_newels[][8] =
+    {
+      { 18, 23, 22, 6, 44, 43},
+      { 24, 21, 22, 23, 45, 42, 43, 44}, 
+      { 4, 41, 20, 16, 45, 42, 21, 24}, 
+      { 3, 11, 10, 18, 23, 22}, 
+      { 12, 9, 10, 11, 24, 21, 22, 23},
+      { 1, 8, 9, 12, 16, 20, 21, 24}, 
+      {8,2,9,20,17,21}, 
+      {5,41,42,17,20,21}
+    };
+  HPRef_Struct refprism_1fa_1fb_2ec_0v =
+    {
+      HP_PRISM,
+      refprism_1fa_1fb_2ec_0v_splitedges, 
+      refprism_1fa_1fb_2ec_0v_splitfaces,
+      0,
+      refprism_1fa_1fb_2ec_0v_newelstypes, 
+      refprism_1fa_1fb_2ec_0v_newels
+    };
+
+
+
+
+
+
+
+//  HP_PRISM_2FA_1FB_1EC_0V   ... trig faces, quad face 1-2-4-5 with singular edge 3-6 
+  int refprism_2fa_1fb_1ec_0v_splitedges[][3] =
+    {
+      {2,3,9},
+      {1,3,12},
+      {3,2,10},
+      {3,1,11},
+      {5,6,42},
+      {4,6,45},
+      {6,5,43},
+      {6,4,44},
+      {1,4,16}, 
+      {2,5,17},
+      {3,6,18},
+      { 4, 1, 28},
+      { 5, 2, 29},
+      { 6, 3, 30},
+      { 0, 0, 0 }
+    };
+
+ int refprism_2fa_1fb_1ec_0v_splitfaces[][4] =
+   {
+     {2,3,5,21},
+     {3,2,6,22},
+     {3,1,6,23},
+     {1,3,4,24},
+     {5,2,6,33},
+     {6,5,3,34},
+     {6,4,3,35},
+     {4,1,6,36},
+     {0,0,0,0}
+   }; 
+  HPREF_ELEMENT_TYPE refprism_2fa_1fb_1ec_0v_newelstypes[] =
+    {
+      HP_PRISM_SINGEDGE, 
+      HP_HEX, 
+      HP_HEX_1F_0E_0V,
+      HP_PRISM_1FA_1E_0V, 
+      HP_HEX_1F_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V,
+      HP_PRISM_1FA_1E_0V, 
+      HP_HEX_1F_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V,
+      HP_NONE,
+    };
+  int refprism_2fa_1fb_1ec_0v_newels[][8] =
+    {
+      { 18, 23, 22, 30, 35, 34},
+      { 24, 21, 22, 23, 36, 33, 34, 35}, 
+      { 28, 29, 17, 16, 36, 33, 21, 24}, 
+      { 3, 11, 10, 18, 23, 22}, 
+      { 12, 9, 10, 11, 24, 21, 22, 23},
+      { 1, 2, 9, 12, 16, 17, 21, 24},
+      { 6, 43, 44, 30, 34, 35},
+      { 44, 43, 42, 45, 35, 34, 33, 36}, 
+      { 5, 4, 45, 42, 29, 28, 36, 33 }, 
+    };
+  HPRef_Struct refprism_2fa_1fb_1ec_0v =
+    {
+      HP_PRISM,
+      refprism_2fa_1fb_1ec_0v_splitedges, 
+      refprism_2fa_1fb_1ec_0v_splitfaces,
+      0,
+      refprism_2fa_1fb_1ec_0v_newelstypes, 
+      refprism_2fa_1fb_1ec_0v_newels
+    };
+
+//  HP_PRISM_2FA_1FB_2EB_0V  
+  int refprism_2fa_1fb_2eb_0v_splitedges[][3] =
+    {
+      {2,3,9},
+      {1,3,12},
+      {3,2,10},
+      {3,1,11},
+      {5,6,42},
+      {4,6,45},
+      {6,5,43},
+      {6,4,44},
+      {1,4,16}, 
+      {2,5,17},
+      {3,6,18},
+      { 4, 1, 28},
+      { 5, 2, 29},
+      { 6, 3, 30},
+      {4,5,40},
+      {1,2,7},
+      { 0, 0, 0 }
+    };
+
+ int refprism_2fa_1fb_2eb_0v_splitfaces[][4] =
+   {
+     {2,3,5,21},
+     {3,2,6,22},
+     {3,1,6,23},
+     {1,3,4,24},
+     {5,6,2,33},
+     {6,5,3,34},
+     {6,4,3,35},
+     {4,1,6,36},
+     {4,1,5,31},
+     {1,2,4,19},
+     {0,0,0,0}
+   }; 
+  HPREF_ELEMENT_TYPE refprism_2fa_1fb_2eb_0v_newelstypes[] =
+    {
+      HP_PRISM_SINGEDGE, 
+      HP_HEX, 
+      HP_HEX_1F_0E_0V,
+      HP_PRISM_1FA_1E_0V, 
+      HP_HEX_1F_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V,
+      HP_PRISM_1FA_1E_0V, 
+      HP_HEX_1F_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V,
+      HP_PRISM_1FA_1FB_1EA_0V, 
+      HP_PRISM_1FB_1EA_0V, 
+      HP_PRISM_1FA_1FB_1EB_0V, 
+      HP_NONE,
+    };
+  int refprism_2fa_1fb_2eb_0v_newels[][8] =
+    {
+      { 18, 23, 22, 30, 35, 34},
+      { 24, 21, 22, 23, 36, 33, 34, 35}, 
+      { 31, 29, 17, 19, 36, 33, 21, 24}, 
+      { 3, 11, 10, 18, 23, 22}, 
+      { 12, 9, 10, 11, 24, 21, 22, 23},
+      { 7, 2, 9, 12, 19, 17, 21, 24},
+      { 6, 43, 44, 30, 34, 35},
+      { 44, 43, 42, 45, 35, 34, 33, 36}, 
+      { 5, 40, 45, 42, 29, 31, 36, 33 }, 
+      { 1, 7, 12, 16, 19, 24 }, 
+      { 16, 19, 24, 28, 31, 36 }, 
+      { 40, 4, 45, 31, 28, 36 }, 
+    };
+  HPRef_Struct refprism_2fa_1fb_2eb_0v =
+    {
+      HP_PRISM,
+      refprism_2fa_1fb_2eb_0v_splitedges, 
+      refprism_2fa_1fb_2eb_0v_splitfaces, 0,
+      refprism_2fa_1fb_2eb_0v_newelstypes, 
+      refprism_2fa_1fb_2eb_0v_newels
+    };
+
+//  HP_PRISM_1FB_2EA_0V   ... quad face 1-2-4-5 with singular edges 1-4, 2-5
+  int refprism_1fb_2ea_0v_splitedges[][3] =
+    {
+      { 1, 3, 7 },
+      { 2, 3, 8 },
+      { 1, 2, 9 }, 
+      { 2, 1, 10 }, 
+      { 4, 6, 11 }, 
+      { 5, 6, 12 }, 
+      { 4, 5, 13 }, 
+      { 5, 4, 14 }, 
+      { 0, 0, 0 }
+    };
+  HPREF_ELEMENT_TYPE refprism_1fb_2ea_0v_newelstypes[] =
+    {
+      HP_PRISM, 
+      HP_PRISM_1FB_1EA_0V,
+      HP_HEX_1F_0E_0V, 
+      HP_PRISM_1FB_1EA_0V, 
+      HP_NONE,
+    };
+  int refprism_1fb_2ea_0v_newels[][8] =
+    {
+      { 7, 8, 3, 11, 12, 6 }, 
+      { 1, 9, 7, 4, 13, 11 }, 
+      { 13, 14, 10, 9, 11, 12, 8, 7 }, 
+      { 5, 14, 12, 2, 10, 8 }, 
+    };
+  HPRef_Struct refprism_1fb_2ea_0v =
+    {
+      HP_PRISM,
+      refprism_1fb_2ea_0v_splitedges, 
+      0, 0,
+      refprism_1fb_2ea_0v_newelstypes, 
+      refprism_1fb_2ea_0v_newels
+    };
+
+//  HP_PRISM_1FB_2EB_0V   ... quad face 1-2-4-5 with singular edges 1-4, 3-6 
+  int refprism_1fb_2eb_0v_splitedges[][3] =
+    {
+      { 1, 2, 7},
+      { 2, 3, 9},
+      { 3, 2, 10},
+      { 3, 1, 11},
+      { 1, 3, 12},
+      { 4, 5, 40},
+      { 5, 6, 42},
+      { 6, 5, 43},
+      { 6, 4, 44},
+      { 4, 6, 45},
+      { 0, 0, 0 }
+    };
+HPREF_ELEMENT_TYPE refprism_1fb_2eb_0v_newelstypes[] =
+    {
+      HP_PRISM_SINGEDGE,
+      HP_HEX, 
+      HP_PRISM_1FB_1EA_0V, 
+      HP_HEX_1F_0E_0V, 
+      HP_NONE,
+    };
+  int refprism_1fb_2eb_0v_newels[][8] =
+    {
+      { 3, 11, 10, 6, 44, 43 },  
+      { 12, 9, 10, 11, 45, 42, 43, 44}, 
+      { 1, 7, 12, 4, 40, 45}, 
+      { 40, 5, 2, 7, 45, 42, 9, 12}
+    };
+  HPRef_Struct refprism_1fb_2eb_0v =
+    {
+      HP_PRISM,
+      refprism_1fb_2eb_0v_splitedges, 
+      0, 0,
+      refprism_1fb_2eb_0v_newelstypes, 
+      refprism_1fb_2eb_0v_newels
+    };
+
+//  HP_PRISM_1FB_3E_0V   ... quad face 1-2-4-5 with singular edges 1-4, 3-6
+  int refprism_1fb_3e_0v_splitedges[][3] =
+    {
+      { 1, 2, 7},
+      { 2, 1, 8},
+      { 2, 3, 9},
+      { 3, 2, 10},
+      { 3, 1, 11},
+      { 1, 3, 12},
+      { 4, 5, 40},
+      { 5, 4, 41},
+      { 5, 6, 42},
+      { 6, 5, 43},
+      { 6, 4, 44},
+      { 4, 6, 45},
+      { 0, 0, 0 }
+    };
+  HPREF_ELEMENT_TYPE refprism_1fb_3e_0v_newelstypes[] =
+    { 
+      HP_PRISM_SINGEDGE,
+      HP_HEX, 
+      HP_PRISM_1FB_1EA_0V, 
+      HP_HEX_1F_0E_0V, 
+      HP_PRISM_1FB_1EA_0V, 
+      HP_NONE,
+    };
+  int refprism_1fb_3e_0v_newels[][8] =
+    {
+      { 3, 11, 10, 6, 44, 43 }, 
+      { 12, 9, 10, 11, 45, 42, 43, 44}, 
+      { 1, 7, 12, 4, 40, 45 }, 
+      { 40, 41, 8, 7, 45, 42, 9, 12}, 
+      { 5, 41, 42, 2, 8, 9}, 
+    };
+  HPRef_Struct refprism_1fb_3e_0v =
+    {
+      HP_PRISM,
+      refprism_1fb_3e_0v_splitedges, 
+      0, 0,
+      refprism_1fb_3e_0v_newelstypes, 
+      refprism_1fb_3e_0v_newels
+    };
+
+
+
+//  HP_PRISM_2FB    ... quad face 1-2-4-5 and quad face 1-4-6-3
+  int refprism_2fb_0e_0v_splitedges[][3] =
+    {
+      { 1, 3, 7 },
+      { 2, 3, 8 },
+      { 1, 2, 9 }, 
+      { 3, 2, 10 }, 
+      { 4, 6, 11 },
+      { 5, 6, 12 },
+      { 4, 5, 13 },
+      { 6, 5, 14 },
+      { 0, 0, 0 }
+    };
+ int refprism_2fb_0e_0v_splitfaces[][4] =
+    {
+      { 1, 2, 3, 15 },
+      { 4, 5, 6, 16 },
+      { 0, 0, 0, 0 },
+    };
+  HPREF_ELEMENT_TYPE refprism_2fb_0e_0v_newelstypes[] =
+    {
+      HP_PRISM,
+      HP_HEX_1F_0E_0V, 
+      HP_HEX_1F_0E_0V, 
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_NONE,
+    };
+  int refprism_2fb_0e_0v_newels[][8] =
+    {
+      { 15, 8, 10, 16, 12, 14 }, 
+      { 13, 5, 2, 9, 16, 12, 8, 15}, 
+      { 11, 7, 3, 6, 16, 15, 10, 14 }, 
+      { 1, 9, 15, 4, 13, 16 }, 
+      { 4, 11, 16, 1,7, 15 }
+    };
+  HPRef_Struct refprism_2fb_0e_0v =
+    {
+      HP_PRISM,
+      refprism_2fb_0e_0v_splitedges, 
+      refprism_2fb_0e_0v_splitfaces,
+      0,
+      refprism_2fb_0e_0v_newelstypes, 
+      refprism_2fb_0e_0v_newels
+    };
+
+//  HP_PRISM_2FB    ... quad face 1-2-4-5 and quad face 1-4-6-3 and sing edge 3-6
+  int refprism_2fb_1ec_0v_splitedges[][3] =
+    {
+      { 1, 3, 7 },
+      { 2, 3, 8 },
+      { 1, 2, 9 }, 
+      { 3, 2, 10 }, 
+      { 4, 6, 11 },
+      { 5, 6, 12 },
+      { 4, 5, 13 },
+      { 6, 5, 14 },
+      { 3, 1, 17},
+      { 6, 4, 18}, 
+      { 0, 0, 0 }
+    };
+ int refprism_2fb_1ec_0v_splitfaces[][4] =
+    {
+      { 1, 2, 3, 15 },
+      { 4, 5, 6, 16 },
+      { 0, 0, 0, 0 },
+    };
+  HPREF_ELEMENT_TYPE refprism_2fb_1ec_0v_newelstypes[] =
+    {
+      HP_PRISM,
+      HP_HEX_1F_0E_0V, 
+      HP_HEX_1F_0E_0V, 
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_NONE,
+    };
+  int refprism_2fb_1ec_0v_newels[][8] =
+    {
+      { 15, 8, 10, 16, 12, 14 }, 
+      { 13, 5, 2, 9, 16, 12, 8, 15}, 
+      { 11, 7, 17, 18, 16, 15, 10, 14 }, 
+      { 1, 9, 15, 4, 13, 16 }, 
+      { 4, 11, 16, 1,7, 15 }, 
+      { 3, 17, 10, 6, 18, 14 } 
+    };
+  HPRef_Struct refprism_2fb_1ec_0v =
+    {
+      HP_PRISM,
+      refprism_2fb_1ec_0v_splitedges, 
+      refprism_2fb_1ec_0v_splitfaces,
+      0,
+      refprism_2fb_1ec_0v_newelstypes, 
+      refprism_2fb_1ec_0v_newels
+    };
+
+
+
+//  HP_PRISM_2FB    ... quad face 1-2-4-5 and quad face 1-4-6-3 and 3 sing edges
+  int refprism_2fb_3e_0v_splitedges[][3] =
+    {
+      { 1, 3, 7 },
+      { 2, 3, 8 },
+      { 1, 2, 9 }, 
+      { 3, 2, 10 }, 
+      { 4, 6, 11 },
+      { 5, 6, 12 },
+      { 4, 5, 13 },
+      { 6, 5, 14 },
+      { 3, 1, 17},
+      { 6, 4, 18}, 
+      { 2, 1, 19},
+      { 5, 4, 20}, 
+      { 0, 0, 0 }
+    };
+ int refprism_2fb_3e_0v_splitfaces[][4] =
+    {
+      { 1, 2, 3, 15 },
+      { 4, 5, 6, 16 },
+      { 0, 0, 0, 0 },
+    };
+  HPREF_ELEMENT_TYPE refprism_2fb_3e_0v_newelstypes[] =
+    {
+      HP_PRISM,
+      HP_HEX_1F_0E_0V, 
+      HP_HEX_1F_0E_0V, 
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_NONE,
+    };
+  int refprism_2fb_3e_0v_newels[][8] =
+    {
+      { 15, 8, 10, 16, 12, 14 }, 
+      { 13, 20, 19, 9, 16, 12, 8, 15}, 
+      { 11, 7, 17, 18, 16, 15, 10, 14 }, 
+      { 1, 9, 15, 4, 13, 16 }, 
+      { 4, 11, 16, 1,7, 15 }, 
+      { 3, 17, 10, 6, 18, 14 }, 
+      { 5, 20, 12, 2, 19, 8 }
+    };
+  HPRef_Struct refprism_2fb_3e_0v =
+    {
+      HP_PRISM,
+      refprism_2fb_3e_0v_splitedges, 
+      refprism_2fb_3e_0v_splitfaces, 0,
+      refprism_2fb_3e_0v_newelstypes, 
+      refprism_2fb_3e_0v_newels
+    };
+
+
+
+//  HP_PRISM_1FA_1FB_0E_0V   ... quad face 1-2-4-5 and trig face 1-2-3
+  int refprism_1fa_1fb_0e_0v_splitedges[][3] = 
+    {
+      {1,4,16}, 
+      {2,5,17},
+      {3,6,18},
+      {2,3,9},
+      {1,3,12},
+      {5,6,42},
+      {4,6,45},
+      {0,0,0}
+    };
+  int refprism_1fa_1fb_0e_0v_splitfaces[][4] = 
+    {
+      {2,3,5,21},
+      {1,3,4,24},
+      { 0, 0, 0, 0 }
+    };
+
+HPREF_ELEMENT_TYPE refprism_1fa_1fb_0e_0v_newelstypes[] =
+    {
+      HP_PRISM, 
+      HP_HEX_1F_0E_0V,
+      HP_PRISM_1FA_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V,
+      HP_NONE,
+    };
+  int refprism_1fa_1fb_0e_0v_newels[][8] =
+    {
+      { 24, 21, 18, 45, 42, 6 }, 
+      { 4, 5, 17, 16, 45, 42, 21, 24 },
+      { 12, 9, 3, 24, 21, 18 }, 
+      { 1, 2, 9, 12, 16, 17, 21, 24 } 
+    };
+  HPRef_Struct refprism_1fa_1fb_0e_0v =
+    {
+      HP_PRISM,
+      refprism_1fa_1fb_0e_0v_splitedges, 
+
+      refprism_1fa_1fb_0e_0v_splitfaces, 0,
+      refprism_1fa_1fb_0e_0v_newelstypes, 
+      refprism_1fa_1fb_0e_0v_newels
+    };
+
+/*
+//  HP_PRISM_1FA_1FB_1EC_0V   ... quad face 1-2-4-5 and trig face 1-2-3
+int refprism_1fa_1fb_1ec_0v_splitedges[][3] =
+    {
+      {1,4,16}, 
+      {2,5,17},
+      {3,6,18},
+      {2,3,9},
+      {1,3,12},
+      {5,6,42},
+      {4,6,45},
+      {6,5,43},
+      {6,4,44},
+      {3,2,10},
+      {3,1,11},
+      {0,0,0}
+    };
+  int refprism_1fa_1fb_1ec_0v_splitfaces[][4] = 
+    {
+      {2,3,5,21},
+      {1,3,4,24},
+      { 0, 0, 0, 0 }
+    };
+
+  HPREF_ELEMENT_TYPE refprism_1fa_1fb_1ec_0v_newelstypes[] =
+    {
+      HP_PRISM, 
+      HP_HEX_1F_0E_0V,
+      HP_PRISM_1FA_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V,
+      HP_PRISM_SINGEDGE,
+      HP_PRISM_1FA_1E_0V, 
+      HP_PRISM_
+      HP_NONE,
+    };
+  int refprism_1fa_1fb_0e_0v_newels[][8] =
+    {
+      { 24, 21, 18, 45, 42, 6 }, 
+      { 4, 5, 17, 16, 45, 42, 21, 24 },
+      { 12, 9, 3, 24, 21, 18 }, 
+      { 1, 2, 9, 12, 16, 17, 21, 24 } 
+    };
+  HPRef_Struct refprism_1fa_1fb_0e_0v =
+    {
+      HP_PRISM,
+      refprism_1fa_1fb_1ec_0v_splitedges, 
+
+      refprism_1fa_1fb_1ec_0v_splitfaces, 0,
+      refprism_1fa_1fb_1ec_0v_newelstypes, 
+      refprism_1fa_1fb_1ec_0v_newels
+    };
+
+
+*/
+
+
+
+
+//  HP_PRISM_2FA_1FB_0E_0V   ... quad face 1-2-4-5 and trig face 1-2-3 
+  int refprism_2fa_1fb_0e_0v_splitedges[][3] =
+    {
+      {2,3,9},
+      {1,3,12},
+      {1,4,16}, 
+      {2,5,17},
+      {3,6,18},
+      {5,6,42},
+      {4,6,45},
+      {4,1,28},
+      {5,2,29},
+      {6,3,30},
+      {0,0,0}
+      
+    };
+  int refprism_2fa_1fb_0e_0v_splitfaces[][4] = 
+    {
+      {2,3,5,21},
+      {1,3,4,24},
+      {5,6,2,33},
+      {4,1,6,36},
+      {0,0,0,0}
+    };
+
+  HPREF_ELEMENT_TYPE refprism_2fa_1fb_0e_0v_newelstypes[] =
+    {  
+      HP_HEX_1F_0E_0V,
+      HP_PRISM,
+      HP_PRISM_1FA_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V, 
+      HP_PRISM_1FA_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V,
+      HP_NONE,
+    };
+  int refprism_2fa_1fb_0e_0v_newels[][8] =
+    {
+      {28,29,17,16,36,33,21,24}, 
+      {24,21,18, 36, 33, 30}, 
+      {12,9,3,24,21,18},
+      {1,2,9,12,16,17,21,24}, 
+      {6,42,45,30,33,36},
+      {4,5,29,28,45,42,33,36}
+    };
+  HPRef_Struct refprism_2fa_1fb_0e_0v =
+    {
+      HP_PRISM,
+      refprism_2fa_1fb_0e_0v_splitedges, 
+
+      refprism_2fa_1fb_0e_0v_splitfaces, 0,
+      refprism_2fa_1fb_0e_0v_newelstypes, 
+      refprism_2fa_1fb_0e_0v_newels
+    };
+
+
+//  HP_PRISM_1FA_1FB_1EA_0V   ... quad face 1-2-4-5 and trig face 1-2-3 
+  int refprism_1fa_1fb_1ea_0v_splitedges[][3] =
+    {
+      {2,3,9},
+      {1,3,12},
+      {1,4,16}, 
+      {2,5,17},
+      {3,6,18},
+      {5,6,42},
+      {4,6,45},
+      {4,5,40},
+      {1,2,7},
+      {0,0,0}, 
+    };
+  int refprism_1fa_1fb_1ea_0v_splitfaces[][4] = 
+    {
+      {2,3,5,21},
+      {1,3,4,24},
+      {1,2,4,19},
+      {0,0,0,0}, 
+    };
+
+  HPREF_ELEMENT_TYPE refprism_1fa_1fb_1ea_0v_newelstypes[] =
+    {
+      HP_HEX_1F_0E_0V,
+      HP_PRISM,
+      HP_PRISM_1FA_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V, 
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FA_1FB_1EA_0V,
+      HP_NONE
+    };
+  int refprism_1fa_1fb_1ea_0v_newels[][8] =
+    {
+      {40,5,17,19,45,42,21,24}, 
+      {24,21,18,45,42,6},
+      {12,9,3,24,21,18},
+      {7,2,9,12,19,17,21,24}, 
+      {16,19,24,4,40,45},
+      {1,7,12,16,19,24}
+      
+    };
+  HPRef_Struct refprism_1fa_1fb_1ea_0v =
+    {
+      HP_PRISM,
+      refprism_1fa_1fb_1ea_0v_splitedges, 
+      refprism_1fa_1fb_1ea_0v_splitfaces, 0,
+      refprism_1fa_1fb_1ea_0v_newelstypes, 
+      refprism_1fa_1fb_1ea_0v_newels
+    };
+
+//  HP_PRISM_2FA_1FB_1EA_0V   
+  int refprism_2fa_1fb_1ea_0v_splitedges[][3] =
+    {
+      {2,3,9},
+      {1,3,12},
+      {1,4,16}, 
+      {2,5,17},
+      {3,6,18},
+      {5,6,42},
+      {4,6,45},
+      {4,1,28},
+      {5,2,29},
+      {6,3,30},
+      {4,5,40},
+      {1,2,7},
+      {0,0,0}, 
+    };
+  int refprism_2fa_1fb_1ea_0v_splitfaces[][4] = 
+    {
+      {2,3,5,21},
+      {1,3,4,24},
+      {1,2,4,19},
+      {4,1,6,36},
+      {4,1,5,31},
+      {5,6,2,33},
+      {0,0,0,0}, 
+    };
+
+  HPREF_ELEMENT_TYPE refprism_2fa_1fb_1ea_0v_newelstypes[] =
+    {
+      HP_PRISM, 
+      HP_HEX_1F_0E_0V, 
+      HP_PRISM_1FB_1EA_0V, 
+      HP_PRISM_1FA_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V, 
+      HP_PRISM_1FA_1FB_1EA_0V, 
+      HP_PRISM_1FA_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V, 
+      HP_PRISM_1FA_1FB_1EB_0V, 
+      HP_NONE
+    };
+  int refprism_2fa_1fb_1ea_0v_newels[][8] =
+    {
+      { 18, 24, 21, 30, 36, 33}, 
+      { 31, 29, 17, 19, 36, 33, 21, 24}, 
+      { 16,19, 24, 28, 31, 36 }, 
+      { 3, 12, 9, 18, 24, 21 }, 
+      { 7, 2, 9, 12, 19, 17, 21, 24},  
+      { 1, 7, 12, 16, 19, 24 }, 
+      { 6, 42, 45, 30, 33, 36 }, 
+      { 40, 5, 29, 31, 45, 42, 33, 36 },
+      { 40, 4, 45, 31, 28, 36} 
+    };
+  HPRef_Struct refprism_2fa_1fb_1ea_0v =
+    {
+      HP_PRISM,
+      refprism_2fa_1fb_1ea_0v_splitedges, 
+      refprism_2fa_1fb_1ea_0v_splitfaces, 0,
+      refprism_2fa_1fb_1ea_0v_newelstypes, 
+      refprism_2fa_1fb_1ea_0v_newels
+    };
+
+
+//  HP_PRISM_2FA_1FB_2EA_0V   
+  int refprism_2fa_1fb_2ea_0v_splitedges[][3] =
+    {
+      {2,3,9},
+      {1,3,12},
+      {1,4,16}, 
+      {2,5,17},
+      {3,6,18},
+      {5,6,42},
+      {4,6,45},
+      {4,1,28},
+      {5,2,29},
+      {6,3,30},
+      {4,5,40},
+      {1,2,7},
+      { 5, 4, 41},
+      { 2, 1, 8},
+      {0,0,0}, 
+    };
+  int refprism_2fa_1fb_2ea_0v_splitfaces[][4] = 
+    {
+      {2,3,5,21},
+      {1,3,4,24},
+      {1,2,4,19},
+      {4,1,6,36},
+      {4,1,5,31},
+      {5,6,2,33},
+      {5,4,2,32},
+      {2,1,5,20},
+      {0,0,0,0}, 
+    };
+
+  HPREF_ELEMENT_TYPE refprism_2fa_1fb_2ea_0v_newelstypes[] =
+    {
+      HP_PRISM, 
+      HP_HEX_1F_0E_0V, 
+      HP_PRISM_1FB_1EA_0V, 
+      HP_PRISM_1FA_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V, 
+      HP_PRISM_1FA_1FB_1EA_0V, 
+      HP_PRISM_1FA_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V, 
+      HP_PRISM_1FA_1FB_1EB_0V, 
+      HP_PRISM_1FA_1FB_1EB_0V, 
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FA_1FB_1EA_0V, 
+      HP_NONE
+    };
+  int refprism_2fa_1fb_2ea_0v_newels[][8] =
+    {
+      { 18, 24, 21, 30, 36, 33}, 
+      { 31, 32, 20, 19, 36, 33, 21, 24}, 
+      { 16,19, 24, 28, 31, 36 }, 
+      { 3, 12, 9, 18, 24, 21 }, 
+      {7,8,9,12,19,20,21,24},
+      { 1, 7, 12, 16, 19, 24 }, 
+      { 6, 42, 45, 30, 33, 36 }, 
+      { 40, 41, 32, 31, 45, 42, 33, 36}, 
+      { 40, 4, 45, 31, 28, 36}, 
+      { 8, 2, 9, 20, 17, 21 },  
+      { 29, 32, 33, 17, 20, 21 }, 
+      { 5, 41, 42, 29, 32, 33 }, 
+    };
+  HPRef_Struct refprism_2fa_1fb_2ea_0v =
+    {
+      HP_PRISM,
+      refprism_2fa_1fb_2ea_0v_splitedges, 
+      refprism_2fa_1fb_2ea_0v_splitfaces, 0,
+      refprism_2fa_1fb_2ea_0v_newelstypes, 
+      refprism_2fa_1fb_2ea_0v_newels
+    };
+
+//  HP_PRISM_2FA_1FB_3E_0V   
+  int refprism_2fa_1fb_3e_0v_splitedges[][3] =
+    {
+      { 1, 2, 7},
+      { 2, 1, 8},
+      { 2, 3, 9},
+      { 3, 2, 10},
+      { 3, 1, 11},
+      { 1, 3, 12},
+      { 1, 4, 16}, 
+      { 2, 5, 17},
+      { 3, 6, 18},
+      { 4, 1, 28},
+      { 5, 2, 29},
+      { 6, 3, 30},
+      { 4, 5, 40},
+      { 5, 4, 41},
+      { 5, 6, 42},
+      { 6, 5, 43},
+      { 6, 4, 44},
+      { 4, 6, 45},
+      {0,0,0}, 
+    };
+  int refprism_2fa_1fb_3e_0v_splitfaces[][4] = 
+    {
+      {1,2,4,19},
+      {2,1,5,20},
+      {2,3,5,21},
+      {3,2,6,22},
+      {3,1,6,23},
+      {1,3,4,24},
+      {4,1,5,31},
+      {5,4,2,32},
+      {5,6,2,33},
+      {6,5,3,34},
+      {6,4,3,35},
+      {4,1,6,36},
+      {0,0,0,0}, 
+    };
+
+  HPREF_ELEMENT_TYPE refprism_2fa_1fb_3e_0v_newelstypes[] =
+    {
+      HP_HEX,
+      HP_PRISM_SINGEDGE,
+      HP_HEX_1F_0E_0V, 
+      HP_PRISM_1FB_1EA_0V, 
+      HP_PRISM_1FB_1EA_0V, 
+
+      HP_HEX_1F_0E_0V,
+      HP_PRISM_1FA_1E_0V,
+      HP_PRISM_1FA_1FB_1EA_0V, 
+      HP_PRISM_1FA_1FB_1EB_0V, 
+      HP_HEX_1FA_1FB_0E_0V,
+      
+      HP_HEX_1F_0E_0V,
+      HP_PRISM_1FA_1E_0V,
+      HP_PRISM_1FA_1FB_1EB_0V,
+      HP_PRISM_1FA_1FB_1EA_0V,
+      HP_HEX_1FA_1FB_0E_0V,
+      
+      HP_NONE
+    };
+  int refprism_2fa_1fb_3e_0v_newels[][8] =
+    {
+      {24, 21, 22, 23, 36, 33, 34, 35},
+      {18, 23, 22, 30, 35, 34}, 
+      { 31, 32, 20, 19, 36, 33, 21, 24}, 
+      { 16,19, 24, 28, 31, 36 }, 
+      { 29, 32, 33, 17, 20, 21},
+      
+      
+      { 12, 9,10,11, 24, 21, 22, 23 }, 
+      { 3, 11, 10, 18,23,22}, 
+      { 1, 7, 12 , 16, 19, 24}, 
+      { 8,2,9, 20, 17,21}, 
+      { 7,8,9,12,19, 20, 21, 24}, 
+      
+      { 44, 43, 42, 45, 35, 34, 33, 36}, 
+      { 6, 43, 44, 30, 34, 35}, 
+      { 40, 4, 45, 31,28, 36}, 
+      { 5, 41,42, 29, 32, 33},  
+      { 40, 41, 32, 31, 45, 42, 33, 36}, 
+    };
+  HPRef_Struct refprism_2fa_1fb_3e_0v =
+    {
+      HP_PRISM,
+      refprism_2fa_1fb_3e_0v_splitedges, 
+
+      refprism_2fa_1fb_3e_0v_splitfaces, 0,
+      refprism_2fa_1fb_3e_0v_newelstypes, 
+      refprism_2fa_1fb_3e_0v_newels
+    };
+
+
+
+
+//  HP_PRISM_1FA_1FB_1EB_0V   ... quad face 1-2-4-5 and trig face 1-2-3 
+  int refprism_1fa_1fb_1eb_0v_splitedges[][3] =
+    {
+      {2,3,9},
+      {1,3,12},
+      {1,4,16}, 
+      {2,5,17},
+      {3,6,18},
+      {5,6,42},
+      {4,6,45},
+      {5,4,41},
+      {2,1,8},
+      {0,0,0}, 
+    };
+  int refprism_1fa_1fb_1eb_0v_splitfaces[][4] = 
+    {
+      {2,3,5,21},
+      {1,3,4,24},
+      {2,1,5,20},
+      {0,0,0,0}, 
+    };
+
+  HPREF_ELEMENT_TYPE refprism_1fa_1fb_1eb_0v_newelstypes[] =
+    {
+      HP_HEX_1F_0E_0V,
+      HP_PRISM,
+      HP_PRISM_1FA_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FA_1FB_1EB_0V ,
+      HP_NONE
+    };
+  int refprism_1fa_1fb_1eb_0v_newels[][8] =
+    {
+      {4,41,20,16,45,42,21,24}, 
+      {24,21,18,45,42,6},
+      {12,9,3,24,21,18},
+      {1,8,9,12,16,20,21,24},
+      {5,41,42,17,20,21},
+      {8,2,9,20,17,21}
+    };
+  HPRef_Struct refprism_1fa_1fb_1eb_0v =
+    {
+      HP_PRISM,
+      refprism_1fa_1fb_1eb_0v_splitedges, 
+
+       refprism_1fa_1fb_1eb_0v_splitfaces, 0,
+      refprism_1fa_1fb_1eb_0v_newelstypes, 
+      refprism_1fa_1fb_1eb_0v_newels
+    };
+
+
+//  HP_PRISM_1FA_1FB_2EA_0V   ... quad face 1-2-4-5 and trig face 1-2-3 
+  int refprism_1fa_1fb_2ea_0v_splitedges[][3] =
+    {
+      {2,3,9},
+      {1,3,12},
+      {1,4,16}, 
+      {2,5,17},
+      {3,6,18},
+      {5,6,42},
+      {4,6,45},
+      {5,4,41},
+      {2,1,8},
+      {4,5,40},
+      {1,2,7},
+      {0,0,0},
+
+    };
+  int refprism_1fa_1fb_2ea_0v_splitfaces[][4] = 
+    {
+      {2,3,5,21},
+      {1,3,4,24},
+      {2,1,5,20},
+      {1,2,4,19},
+      {0,0,0,0},
+    };
+
+  HPREF_ELEMENT_TYPE refprism_1fa_1fb_2ea_0v_newelstypes[] =
+    {
+      HP_HEX_1F_0E_0V,
+      HP_PRISM,
+      HP_PRISM_1FA_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FA_1FB_1EB_0V ,
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FA_1FB_1EA_0V,
+      HP_NONE
+    };
+  int refprism_1fa_1fb_2ea_0v_newels[][8] =
+    {
+      {40,41,20,19,45,42,21,24}, 
+      {24,21,18,45,42,6},
+      {12,9,3,24,21,18},
+      {7,8,9,12,19,20,21,24},
+      {5,41,42,17,20,21},
+      {8,2,9,20,17,21},
+      {16,19,24,4,40,45},
+      {1,7,12,16,19,24}
+    };
+  HPRef_Struct refprism_1fa_1fb_2ea_0v =
+    {
+      HP_PRISM,
+      refprism_1fa_1fb_2ea_0v_splitedges, 
+
+      refprism_1fa_1fb_2ea_0v_splitfaces, 0,
+      refprism_1fa_1fb_2ea_0v_newelstypes, 
+      refprism_1fa_1fb_2ea_0v_newels
+    };
+
+
+//  HP_PRISM_1FA_1FB_3E_0V   
+  int refprism_1fa_1fb_3e_0v_splitedges[][3] =
+    {
+      {2,3,9},
+      {1,3,12},
+      {1,4,16}, 
+      {2,5,17},
+      {3,6,18},
+      {5,6,42},
+      {4,6,45},
+      {5,4,41},
+      {2,1,8},
+      {4,5,40},
+      {1,2,7},
+      { 3, 2, 10},
+      { 3, 1, 11},
+      { 6, 5, 43},
+      { 6, 4, 44},
+      {0,0,0},
+
+    };
+  int refprism_1fa_1fb_3e_0v_splitfaces[][4] = 
+    {
+      {2,3,5,21},
+      {1,3,4,24},
+      {2,1,5,20},
+      {1,2,4,19},
+      {3,2,6,22},
+      {3,1,6,23},
+      {0,0,0,0},
+    };
+
+  HPREF_ELEMENT_TYPE refprism_1fa_1fb_3e_0v_newelstypes[] =
+    {
+      HP_HEX_1F_0E_0V,
+      HP_HEX,
+      HP_PRISM_SINGEDGE,
+      HP_HEX_1F_0E_0V,
+      HP_PRISM_1FA_1E_0V,
+      HP_HEX_1FA_1FB_0E_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FA_1FB_1EB_0V ,
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FA_1FB_1EA_0V,
+      HP_NONE
+    };
+  int refprism_1fa_1fb_3e_0v_newels[][8] =
+    {
+      {40,41,20,19,45,42,21,24}, 
+      {24, 21, 22, 23, 45, 42, 43, 44},
+      {18, 23, 22, 6, 44, 43}, 
+      {12, 9, 10, 11, 24, 21, 22, 23}, 
+      {3, 11, 10, 18, 23, 22}, 
+      {7,8,9,12,19,20,21,24},
+      {5,41,42,17,20,21},
+      {8,2,9,20,17,21},
+      {16,19,24,4,40,45},
+      {1,7,12,16,19,24}
+    };
+  HPRef_Struct refprism_1fa_1fb_3e_0v =
+    {
+      HP_PRISM,
+      refprism_1fa_1fb_3e_0v_splitedges, 
+
+      refprism_1fa_1fb_3e_0v_splitfaces, 0,
+      refprism_1fa_1fb_3e_0v_newelstypes, 
+      refprism_1fa_1fb_3e_0v_newels
+    };
+
+
+
+
+
+
+
+
+//  HP_PRISM_2FA_0E_0V  singular trig faces
+  int refprism_2fa_0e_0v_splitedges[][3] =
+    {
+      {1,4,16}, 
+      {2,5,17},
+      {3,6,18},
+      {4,1,28},
+      {5,2,29},
+      {6,3,30},
+      {0,0,0}
+    };
+  
+HPREF_ELEMENT_TYPE refprism_2fa_0e_0v_newelstypes[] =
+    {
+      HP_PRISM,
+      HP_PRISM_1FA_0E_0V,
+      HP_PRISM_1FA_0E_0V,
+      HP_NONE
+    };
+  int refprism_2fa_0e_0v_newels[][8] =
+    {
+      {16,17,18,28,29,30},
+      {1,2,3,16,17,18},
+      {4,6,5,28,30,29}, 
+    };
+
+HPRef_Struct refprism_2fa_0e_0v = 
+
+    {
+      HP_PRISM,
+      refprism_2fa_0e_0v_splitedges, 
+      0, 0,
+      refprism_2fa_0e_0v_newelstypes, 
+      refprism_2fa_0e_0v_newels
+    };
+
+
+
+
+
+//  HP_PRISM_1FA_2FB    ... quad face 1-2-4-5 and quad face 1-4-6-3
+int refprism_1fa_2fb_0e_0v_splitedges[][3] =
+    {
+      { 1, 2, 7},
+      { 2, 3, 9},
+      { 3, 2, 10},
+      { 1, 3, 12},
+      { 1, 4, 16}, 
+      { 2, 5, 17},
+      { 3, 6, 18},
+      { 4, 5, 40},
+      { 5, 6, 42},
+      { 6, 5, 43},
+      { 4, 6, 45},
+      { 0, 0, 0 }
+    };
+int refprism_1fa_2fb_0e_0v_splitfaces[][4] =
+    {
+      {1,2,3,13},
+      {1,2,4,19},
+      {2,3,5,21},
+      {3,2,6,22},
+      {1,3,4,24},
+      {4,5,6,46},
+      { 0, 0, 0, 0 }
+    };
+int refprism_1fa_2fb_0e_0v_splitelement[][5] = 
+  {
+    {1,2,3,4,25}, 
+    {0,0,0,0,0} 
+  };
+  
+HPREF_ELEMENT_TYPE refprism_1fa_2fb_0e_0v_newelstypes[] =
+    {
+      HP_PRISM,
+      HP_HEX_1F_0E_0V, 
+      HP_HEX_1F_0E_0V, 
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FA_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V,
+      HP_HEX_1FA_1FB_0E_0V, 
+      HP_PRISM_1FA_1FB_1EA_0V,
+      HP_PRISM_1FA_1FB_1EB_0V,
+      HP_NONE,
+    };
+  int refprism_1fa_2fb_0e_0v_newels[][8] =
+    {
+      { 25, 21, 22, 46, 42, 43 }, 
+      { 40, 5, 17, 19, 46, 42, 21, 25 }, 
+      { 24, 18, 6, 45, 25, 22, 43, 46}, 
+      { 16, 19, 25, 4, 40, 46 }, 
+      { 4, 45, 46, 16, 24, 25 }, 
+      { 13, 9, 10, 25, 21, 22 }, 
+      { 7, 2, 9, 13, 19, 17, 21, 25 }, 
+      { 3, 12, 13, 10, 18, 24, 25, 22 }, 
+      { 1, 7, 13, 16, 19, 25 }, 
+      { 12, 1, 13, 24, 16, 25 }
+      
+    };
+  HPRef_Struct refprism_1fa_2fb_0e_0v =
+    {
+      HP_PRISM,
+      refprism_1fa_2fb_0e_0v_splitedges, 
+      refprism_1fa_2fb_0e_0v_splitfaces, 
+      refprism_1fa_2fb_0e_0v_splitelement, 
+      refprism_1fa_2fb_0e_0v_newelstypes, 
+      refprism_1fa_2fb_0e_0v_newels
+    };
+
+//  HP_PRISM_1FA_2FB_1EC    ... quad face 1-2-4-5 and quad face 1-4-6-3
+int refprism_1fa_2fb_1ec_0v_splitedges[][3] =
+    {
+      { 1, 2, 7},
+      { 2, 3, 9},
+      { 3, 2, 10},
+      { 3, 1, 11},
+      { 1, 3, 12},
+      { 1, 4, 16}, 
+      { 2, 5, 17},
+      { 3, 6, 18},
+      { 4, 5, 40},
+      { 5, 6, 42},
+      { 6, 5, 43},
+      { 6, 4, 44},
+      { 4, 6, 45},
+      { 0, 0, 0 }
+    };
+int refprism_1fa_2fb_1ec_0v_splitfaces[][4] =
+    {
+      {1,2,3,13},
+      {1,2,4,19},
+      {2,3,5,21},
+      {3,2,6,22},
+      {3,1,6,23},
+      {1,3,4,24},
+      {4,5,6,46},
+      { 0, 0, 0, 0 }
+    };
+int refprism_1fa_2fb_1ec_0v_splitelement[][5] = 
+  {
+    {1,2,3,4,25}, 
+    {0,0,0,0,0} 
+  };
+  
+HPREF_ELEMENT_TYPE refprism_1fa_2fb_1ec_0v_newelstypes[] =
+    {
+      HP_PRISM,
+      HP_HEX_1F_0E_0V, 
+      HP_HEX_1F_0E_0V, 
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V, 
+      
+      HP_PRISM_1FA_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V,
+      HP_HEX_1FA_1FB_0E_0V, 
+      HP_PRISM_1FA_1FB_1EA_0V,
+      HP_PRISM_1FA_1FB_1EB_0V,
+      HP_PRISM_1FA_1FB_1EA_0V, 
+      
+      HP_NONE,
+    };
+  int refprism_1fa_2fb_1ec_0v_newels[][8] =
+    {
+      { 25, 21, 22, 46, 42, 43 }, 
+      { 40, 5, 17, 19, 46, 42, 21, 25 }, 
+      { 24, 23, 44, 45, 25, 22, 43, 46}, 
+      { 16, 19, 25, 4, 40, 46 }, 
+      { 4, 45, 46, 16, 24, 25 }, 
+      { 18, 23, 22, 6, 44, 43}, 
+
+
+      { 13, 9, 10, 25, 21, 22 }, 
+      { 7, 2, 9, 13, 19, 17, 21, 25 }, 
+      { 11, 12, 13, 10, 23, 24, 25, 22 }, 
+      { 1, 7, 13, 16, 19, 25 }, 
+      { 12, 1, 13, 24, 16, 25 }, 
+      { 3, 11, 10, 18, 23, 22},
+      
+    };
+  HPRef_Struct refprism_1fa_2fb_1ec_0v =
+    {
+      HP_PRISM,
+      refprism_1fa_2fb_1ec_0v_splitedges, 
+      refprism_1fa_2fb_1ec_0v_splitfaces, 
+      refprism_1fa_2fb_1ec_0v_splitelement, 
+      refprism_1fa_2fb_1ec_0v_newelstypes, 
+      refprism_1fa_2fb_1ec_0v_newels
+    };
+
+
+//  HP_PRISM_1FA_2FB_3E    ... quad face 1-2-4-5 and quad face 1-4-6-3
+int refprism_1fa_2fb_3e_0v_splitedges[][3] =
+    {
+      { 1, 2, 7},
+      { 2, 1, 8},
+      { 2, 3, 9},
+      { 3, 2, 10},
+      { 3, 1, 11},
+      { 1, 3, 12},
+      { 1, 4, 16}, 
+      { 2, 5, 17},
+      { 3, 6, 18},
+      { 4, 5, 40},
+      { 5, 4, 41},
+      { 5, 6, 42},
+      { 6, 5, 43},
+      { 6, 4, 44},
+      { 4, 6, 45},
+      { 0, 0, 0 }
+    };
+int refprism_1fa_2fb_3e_0v_splitfaces[][4] =
+    {
+      {1,2,3,13},
+      {1,2,4,19},
+      {2,1,5,20},
+      {2,3,5,21},
+      {3,2,6,22},
+      {3,1,6,23},
+      {1,3,4,24},
+      {4,5,6,46},
+      { 0, 0, 0, 0 }
+    };
+int refprism_1fa_2fb_3e_0v_splitelement[][5] = 
+  {
+    {1,2,3,4,25}, 
+    {0,0,0,0,0} 
+  };
+  
+HPREF_ELEMENT_TYPE refprism_1fa_2fb_3e_0v_newelstypes[] =
+    {
+      HP_PRISM,
+      HP_HEX_1F_0E_0V, 
+      HP_HEX_1F_0E_0V, 
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V, 
+      HP_PRISM_1FB_1EA_0V,
+      
+      
+      HP_PRISM_1FA_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V,
+      HP_HEX_1FA_1FB_0E_0V, 
+      HP_PRISM_1FA_1FB_1EA_0V,
+      HP_PRISM_1FA_1FB_1EB_0V,
+      HP_PRISM_1FA_1FB_1EA_0V, 
+      HP_PRISM_1FA_1FB_1EB_0V,
+      
+      HP_NONE,
+    };
+  int refprism_1fa_2fb_3e_0v_newels[][8] =
+    {
+      { 25, 21, 22, 46, 42, 43 }, 
+      { 40, 41, 20, 19, 46, 42, 21, 25 }, 
+      { 24, 23, 44, 45, 25, 22, 43, 46}, 
+      { 16, 19, 25, 4, 40, 46 }, 
+      { 4, 45, 46, 16, 24, 25 }, 
+      { 18, 23, 22, 6, 44, 43}, 
+      { 5, 41, 42, 17, 20, 21}, 
+      
+
+      { 13, 9, 10, 25, 21, 22 }, 
+      { 7, 8, 9, 13, 19, 20, 21, 25 }, 
+      { 11, 12, 13, 10, 23, 24, 25, 22 }, 
+      { 1, 7, 13, 16, 19, 25 }, 
+      
+      { 12, 1, 13, 24, 16, 25 }, 
+      { 3, 11, 10, 18, 23, 22},
+      { 8, 2, 9, 20, 17, 21}, 
+      
+    };
+  HPRef_Struct refprism_1fa_2fb_3e_0v =
+    {
+      HP_PRISM,
+      refprism_1fa_2fb_3e_0v_splitedges, 
+      refprism_1fa_2fb_3e_0v_splitfaces, 
+      refprism_1fa_2fb_3e_0v_splitelement, 
+      refprism_1fa_2fb_3e_0v_newelstypes, 
+      refprism_1fa_2fb_3e_0v_newels
+    };
+
+
+
+
+
+
+
+
+
+//  HP_PRISM_1FA_2FB_1eb    ... quad face 1-2-4-5 and quad face 1-4-6-3
+int refprism_1fa_2fb_1eb_0v_splitedges[][3] =
+    {
+      { 1, 2, 7},
+      { 2, 1, 8},
+      { 2, 3, 9},
+      { 3, 2, 10},
+      { 1, 3, 12},
+      { 1, 4, 16}, 
+      { 2, 5, 17},
+      { 3, 6, 18},
+      { 4, 5, 40},
+      { 5, 4, 41},
+      { 5, 6, 42},
+      { 6, 5, 43},
+      { 4, 6, 45},
+      { 0, 0, 0 }
+    };
+int refprism_1fa_2fb_1eb_0v_splitfaces[][4] =
+    {
+      {1,2,3,13},
+      {1,2,4,19},
+      {2,1,5,20},
+      {2,3,5,21},
+      {3,2,6,22},
+      {1,3,4,24},
+      {4,5,6,46},
+      { 0, 0, 0, 0 }
+    };
+int refprism_1fa_2fb_1eb_0v_splitelement[][5] = 
+  {
+    {1,2,3,4,25}, 
+    {0,0,0,0,0} 
+  };
+
+
+HPREF_ELEMENT_TYPE refprism_1fa_2fb_1eb_0v_newelstypes[] =
+    {
+      HP_PRISM,
+      HP_HEX_1F_0E_0V, 
+      HP_HEX_1F_0E_0V, 
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V, 
+      HP_PRISM_1FB_1EA_0V,
+      
+      HP_PRISM_1FA_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V,
+      HP_HEX_1FA_1FB_0E_0V, 
+      HP_PRISM_1FA_1FB_1EA_0V,
+      HP_PRISM_1FA_1FB_1EB_0V, 
+      HP_PRISM_1FA_1FB_1EB_0V,
+      
+      HP_NONE,
+    };
+
+  int refprism_1fa_2fb_1eb_0v_newels[][8] =
+    {
+      { 25, 21, 22, 46, 42, 43 }, 
+      { 40, 41, 20, 19, 46, 42, 21, 25 }, 
+      { 24, 18, 6, 45, 25, 22, 43, 46}, 
+      { 16, 19, 25, 4, 40, 46 },
+      { 4, 45, 46, 16, 24, 25 }, 
+      { 5, 41, 42, 17, 20, 21 },
+
+
+      { 13, 9, 10, 25, 21, 22 }, 
+      { 7, 8, 9, 13, 19, 20, 21, 25 }, 
+      { 3, 12, 13, 10, 18, 24, 25, 22 }, 
+      { 1, 7, 13, 16, 19, 25 },  
+      { 12, 1, 13, 24, 16, 25 }, 
+      { 8, 2, 9, 20, 17, 21}, 
+      
+    };
+  HPRef_Struct refprism_1fa_2fb_1eb_0v =
+    {
+      HP_PRISM,
+      refprism_1fa_2fb_1eb_0v_splitedges, 
+      refprism_1fa_2fb_1eb_0v_splitfaces, 
+      refprism_1fa_2fb_1eb_0v_splitelement, 
+      refprism_1fa_2fb_1eb_0v_newelstypes, 
+      refprism_1fa_2fb_1eb_0v_newels
+    };
+
+
+
+
+
+
+//  HP_PRISM_2FA_2FB 
+int refprism_2fa_2fb_0e_0v_splitedges[][3] =
+    {
+      { 1, 2, 7},
+      { 2, 3, 9},
+      { 3, 2, 10},
+      { 1, 3, 12},
+      { 1, 4, 16}, 
+      { 2, 5, 17},
+      { 3, 6, 18},
+      { 4, 5, 40},
+      { 5, 6, 42},
+      { 6, 5, 43},
+      { 4, 6, 45},
+      { 4, 1, 28},
+      { 5, 2, 29},
+      { 6, 3, 30},
+      { 0, 0, 0 }
+    };
+int refprism_2fa_2fb_0e_0v_splitfaces[][4] =
+    {
+      {1,2,3,13},
+      {1,2,4,19},
+      {2,3,5,21},
+      {3,2,6,22},
+      {1,3,4,24},
+      {4,5,6,46},  
+      {4,1,5,31},
+      {5,6,2,33},
+      {6,5,3,34},
+      {4,1,6,36},
+      { 0, 0, 0, 0 }
+    };
+int refprism_2fa_2fb_0e_0v_splitelement[][5] = 
+  {
+    {1,2,3,4,25}, 
+    {4,1,6,5,37},
+    {0,0,0,0,0} 
+  };
+  
+HPREF_ELEMENT_TYPE refprism_2fa_2fb_0e_0v_newelstypes[] =
+    {
+      HP_PRISM,
+      HP_HEX_1F_0E_0V, 
+      HP_HEX_1F_0E_0V, 
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V,
+      
+      HP_PRISM_1FA_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V,
+      HP_HEX_1FA_1FB_0E_0V, 
+      HP_PRISM_1FA_1FB_1EA_0V,
+      HP_PRISM_1FA_1FB_1EB_0V,
+      
+      HP_PRISM_1FA_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V,
+      HP_HEX_1FA_1FB_0E_0V, 
+      HP_PRISM_1FA_1FB_1EB_0V,
+      HP_PRISM_1FA_1FB_1EA_0V,
+      
+      HP_NONE,
+    };
+  int refprism_2fa_2fb_0e_0v_newels[][8] =
+    {
+      { 25, 21, 22, 37, 33, 34}, 
+      { 31, 29, 17, 19, 37, 33, 21, 25}, 
+      { 36, 24, 18, 30, 37, 25, 22, 34}, 
+      { 16, 19, 25, 28, 31, 37}, 
+      { 28, 36, 37, 16, 24, 25},
+      
+      { 13, 9, 10, 25, 21, 22 }, 
+      { 7, 2, 9, 13, 19, 17, 21, 25 }, 
+      { 3, 12, 13, 10, 18, 24, 25, 22 }, 
+      { 1, 7, 13, 16, 19, 25 }, 
+      { 12, 1, 13, 24, 16, 25 }, 
+
+      {  46, 43, 42 ,37, 34, 33},
+      { 40, 5, 29, 31, 46, 42, 33, 37 }, 
+      { 6, 45, 36, 30, 43, 46, 37, 34 }, 
+      { 40, 4, 46, 31, 28, 37 }, 
+      { 4, 45, 46, 28, 36, 37},  
+      
+    };
+  HPRef_Struct refprism_2fa_2fb_0e_0v =
+    {
+      HP_PRISM,
+      refprism_2fa_2fb_0e_0v_splitedges, 
+      refprism_2fa_2fb_0e_0v_splitfaces, 
+      refprism_2fa_2fb_0e_0v_splitelement, 
+      refprism_2fa_2fb_0e_0v_newelstypes, 
+      refprism_2fa_2fb_0e_0v_newels
+    };
+
+
+//  HP_PRISM_2FA_2FB_1EC 
+int refprism_2fa_2fb_1ec_0v_splitedges[][3] =
+    {
+      { 1, 2, 7},
+      { 2, 3, 9},
+      { 3, 2, 10},
+      { 3, 1, 11},
+      { 1, 3, 12},
+      { 1, 4, 16}, 
+      { 2, 5, 17},
+      { 3, 6, 18},
+      { 4, 1, 28},
+      { 5, 2, 29},
+      { 6, 3, 30},
+      { 4, 5, 40},
+      { 5, 6, 42},
+      { 6, 5, 43},
+      { 6, 4, 44},
+      { 4, 6, 45},
+      { 0, 0, 0 }
+    };
+int refprism_2fa_2fb_1ec_0v_splitfaces[][4] =
+    {
+      {1,2,3,13},
+      {1,2,4,19},
+      {2,3,5,21},
+      {3,2,6,22},
+      {3,1,6,23},
+      {1,3,4,24},
+      {4,5,6,46},  
+      {4,1,5,31},
+      {5,6,2,33},
+      {6,5,3,34},
+      {6,4,3,35},
+      {4,1,6,36},
+      { 0, 0, 0, 0 }
+    };
+int refprism_2fa_2fb_1ec_0v_splitelement[][5] = 
+  {
+    {1,2,3,4,25}, 
+    {4,1,6,5,37},
+    {0,0,0,0,0} 
+  };
+  
+HPREF_ELEMENT_TYPE refprism_2fa_2fb_1ec_0v_newelstypes[] =
+    {
+      HP_PRISM,
+      HP_HEX_1F_0E_0V, 
+      HP_HEX_1F_0E_0V, 
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V,
+      
+      HP_PRISM_1FA_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V,
+      HP_HEX_1FA_1FB_0E_0V, 
+      HP_PRISM_1FA_1FB_1EA_0V,
+      HP_PRISM_1FA_1FB_1EB_0V,
+      HP_PRISM_1FA_1FB_1EA_0V, 
+      
+      HP_PRISM_1FA_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V,
+      HP_HEX_1FA_1FB_0E_0V, 
+      HP_PRISM_1FA_1FB_1EB_0V,
+      HP_PRISM_1FA_1FB_1EA_0V,
+      HP_PRISM_1FA_1FB_1EB_0V, 
+      
+      HP_NONE,
+    };
+  int refprism_2fa_2fb_1ec_0v_newels[][8] =
+    {
+      { 25, 21, 22, 37, 33, 34}, 
+      { 31, 29, 17, 19, 37, 33, 21, 25}, 
+      { 36, 24, 23, 35, 37, 25, 22, 34}, 
+      { 16, 19, 25, 28, 31, 37}, 
+      { 28, 36, 37, 16, 24, 25},
+      { 18, 23, 22, 30, 35, 34}, 
+            
+      { 13, 9, 10, 25, 21, 22 }, 
+      { 7, 2, 9, 13, 19, 17, 21, 25 }, 
+      { 11, 12, 13, 10, 23, 24, 25, 22 }, 
+      { 1, 7, 13, 16, 19, 25 }, 
+      { 12, 1, 13, 24, 16, 25 }, 
+      { 3, 11, 10, 18, 23, 22 }, 
+
+      { 46, 43, 42 ,37, 34, 33},
+      { 40, 5, 29, 31, 46, 42, 33, 37 }, 
+      { 44, 45, 36, 35, 43, 46, 37, 34 }, 
+      { 40, 4, 46, 31, 28, 37 }, 
+      { 4, 45, 46, 28, 36, 37},  
+      { 44, 6, 43, 35, 30, 34}, 
+      
+    };
+  HPRef_Struct refprism_2fa_2fb_1ec_0v =
+    {
+      HP_PRISM,
+      refprism_2fa_2fb_1ec_0v_splitedges, 
+      refprism_2fa_2fb_1ec_0v_splitfaces, 
+      refprism_2fa_2fb_1ec_0v_splitelement, 
+      refprism_2fa_2fb_1ec_0v_newelstypes, 
+      refprism_2fa_2fb_1ec_0v_newels
+    };
+
+
+
+//  HP_PRISM_2FA_2FB_3E 
+int refprism_2fa_2fb_3e_0v_splitedges[][3] =
+    {
+      { 1, 2, 7},
+      { 2, 1, 8},
+      { 2, 3, 9},
+      { 3, 2, 10},
+      { 3, 1, 11},
+      { 1, 3, 12},
+      { 1, 4, 16}, 
+      { 2, 5, 17},
+      { 3, 6, 18},
+      { 4, 1, 28},
+      { 5, 2, 29},
+      { 6, 3, 30},
+      { 4, 5, 40},
+      { 5, 4, 41},
+      { 5, 6, 42},
+      { 6, 5, 43},
+      { 6, 4, 44},
+      { 4, 6, 45},
+      { 0, 0, 0 }
+    };
+int refprism_2fa_2fb_3e_0v_splitfaces[][4] =
+    {
+      {1,2,3,13},
+      {1,2,4,19},
+      {2,1,5,20},
+      {2,3,5,21},
+      {3,2,6,22},
+      {3,1,6,23},
+      {1,3,4,24},
+      {4,5,6,46},  
+      {4,1,5,31},
+      {5,4,2,32},
+      {5,6,2,33},
+      {6,5,3,34},
+      {6,4,3,35},
+      {4,1,6,36},
+      { 0, 0, 0, 0 }
+    };
+int refprism_2fa_2fb_3e_0v_splitelement[][5] = 
+  {
+    {1,2,3,4,25}, 
+    {4,1,6,5,37},
+    {0,0,0,0,0} 
+  };
+  
+HPREF_ELEMENT_TYPE refprism_2fa_2fb_3e_0v_newelstypes[] =
+    {
+      HP_PRISM,
+      HP_HEX_1F_0E_0V, 
+      HP_HEX_1F_0E_0V, 
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V, 
+      
+      HP_PRISM_1FA_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V,
+      HP_HEX_1FA_1FB_0E_0V, 
+      HP_PRISM_1FA_1FB_1EA_0V,
+      HP_PRISM_1FA_1FB_1EB_0V,
+      HP_PRISM_1FA_1FB_1EA_0V, 
+      HP_PRISM_1FA_1FB_1EB_0V, 
+      
+      HP_PRISM_1FA_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V,
+      HP_HEX_1FA_1FB_0E_0V, 
+      HP_PRISM_1FA_1FB_1EB_0V,
+      HP_PRISM_1FA_1FB_1EA_0V,
+      HP_PRISM_1FA_1FB_1EB_0V, 
+      HP_PRISM_1FA_1FB_1EA_0V, 
+      
+      HP_NONE,
+    };
+  int refprism_2fa_2fb_3e_0v_newels[][8] =
+    {
+      { 25, 21, 22, 37, 33, 34}, 
+      { 31, 32, 20, 19, 37, 33, 21, 25}, 
+      { 36, 24, 23, 35, 37, 25, 22, 34}, 
+      { 16, 19, 25, 28, 31, 37}, 
+      { 28, 36, 37, 16, 24, 25},
+      { 18, 23, 22, 30, 35, 34}, 
+      { 29, 32, 33, 17, 20, 21}, 
+            
+      { 13, 9, 10, 25, 21, 22 }, 
+      { 7, 8, 9, 13, 19, 20, 21, 25 }, 
+      { 11, 12, 13, 10, 23, 24, 25, 22 }, 
+      { 1, 7, 13, 16, 19, 25 }, 
+      { 12, 1, 13, 24, 16, 25 }, 
+      { 3, 11, 10, 18, 23, 22 }, 
+      { 8, 2, 9, 20, 17, 21 }, 
+
+      { 46, 43, 42 ,37, 34, 33},
+      { 40, 41, 32, 31, 46, 42, 33, 37 }, 
+      { 44, 45, 36, 35, 43, 46, 37, 34 }, 
+      { 40, 4, 46, 31, 28, 37 }, 
+      { 4, 45, 46, 28, 36, 37},  
+      { 44, 6, 43, 35, 30, 34},
+      { 5, 41, 42, 29, 32, 33}, 
+      
+    };
+  HPRef_Struct refprism_2fa_2fb_3e_0v =
+    {
+      HP_PRISM,
+      refprism_2fa_2fb_3e_0v_splitedges, 
+      refprism_2fa_2fb_3e_0v_splitfaces, 
+      refprism_2fa_2fb_3e_0v_splitelement, 
+      refprism_2fa_2fb_3e_0v_newelstypes, 
+      refprism_2fa_2fb_3e_0v_newels
+    };
+
+
+
+
+//  HP_PRISM_1FA_2E_0V  
+  int refprism_1fa_2e_0v_splitedges[][3] =
+    {
+      {2,3,9},
+      {1,3,12},
+      {1,4,16}, 
+      {2,5,17},
+      {3,6,18},
+      {5,6,42},
+      {4,6,45},
+      {5,4,41},
+      {2,1,8},
+      {4,5,40},
+      {1,2,7},
+      {0,0,0},
+
+    };
+  int refprism_1fa_2e_0v_splitfaces[][4] = 
+    {
+      {2,3,5,21},
+      {1,3,4,24},
+      {2,1,5,20},
+      {1,2,4,19},
+      {0,0,0,0},
+    };
+
+  HPREF_ELEMENT_TYPE refprism_1fa_2e_0v_newelstypes[] =
+    {
+      HP_HEX,
+      HP_PRISM,
+      HP_PRISM_1FA_0E_0V, 
+      HP_HEX_1F_0E_0V,
+      HP_PRISM_SINGEDGE, 
+      HP_PRISM_1FA_1E_0V,
+      HP_PRISM_SINGEDGE,
+      HP_PRISM_1FA_1E_0V,
+      HP_NONE
+    };
+  int refprism_1fa_2e_0v_newels[][8] =
+    {
+      {40,41,20,19,45,42,21,24}, 
+      {24,21,18,45,42,6},
+      {12,9,3,24,21,18},
+      {9, 12, 7, 8, 21, 24, 19, 20}, 
+      { 17, 21, 20, 5, 42, 41},
+      {2, 9, 8, 17, 21, 20},
+      {16,19,24,4,40,45},
+      {1,7,12,16,19,24}
+    };
+  HPRef_Struct refprism_1fa_2e_0v =
+    {
+      HP_PRISM,
+      refprism_1fa_2e_0v_splitedges, 
+
+      refprism_1fa_2e_0v_splitfaces, 0,
+      refprism_1fa_2e_0v_newelstypes, 
+      refprism_1fa_2e_0v_newels
+    };
+    
+//  HP_PRISM_2FA_2E_0V   
+  int refprism_2fa_2e_0v_splitedges[][3] =
+    {
+      {2,3,9},
+      {1,3,12},
+      {1,4,16}, 
+      {2,5,17},
+      {3,6,18},
+      {5,6,42},
+      {4,6,45},
+      {4,1,28},
+      {5,2,29},
+      {6,3,30},
+      {4,5,40},
+      {1,2,7},
+      { 5, 4, 41},
+      { 2, 1, 8},
+      {0,0,0}, 
+    };
+  int refprism_2fa_2e_0v_splitfaces[][4] = 
+    {
+      {2,3,5,21},
+      {1,3,4,24},
+      {1,2,4,19},
+      {4,1,6,36},
+      {4,1,5,31},
+      {5,6,2,33},
+      {5,4,2,32},
+      {2,1,5,20},
+      {0,0,0,0}, 
+    };
+
+  HPREF_ELEMENT_TYPE refprism_2fa_2e_0v_newelstypes[] =
+    {
+      HP_PRISM, 
+      HP_HEX, 
+      HP_PRISM_SINGEDGE,
+      HP_PRISM_SINGEDGE, 
+      
+      HP_PRISM_1FA_0E_0V,
+      HP_HEX_1F_0E_0V, 
+      HP_PRISM_1FA_1E_0V, 
+      HP_PRISM_1FA_1E_0V, 
+
+      HP_PRISM_1FA_0E_0V,
+      HP_HEX_1F_0E_0V, 
+      HP_PRISM_1FA_1E_0V, 
+      HP_PRISM_1FA_1E_0V, 
+      HP_NONE,
+      
+    };
+  int refprism_2fa_2e_0v_newels[][8] =
+    {
+      { 24, 21, 18, 36, 33, 30}, 
+      { 19, 20, 21, 24, 31, 32, 33, 36}, 
+      { 16, 19, 24, 28, 31, 36}, 
+      { 17, 21, 20, 29, 33, 32}, 
+      
+      { 12, 9, 3, 24, 21, 18}, 
+      { 7, 8, 9, 12, 19, 20, 21, 24}, 
+      { 1, 7, 12, 16, 19, 24},
+      { 2, 9, 8, 17, 21, 20}, 
+      
+      { 45, 6, 42, 36, 30, 33}, 
+      { 40, 45, 42, 41, 31, 36, 33, 32}, 
+      { 4, 45, 40, 28, 36, 31 }, 
+      { 5, 41, 42, 29, 32, 33 },
+    };
+  HPRef_Struct refprism_2fa_2e_0v =
+    {
+      HP_PRISM,
+      refprism_2fa_2e_0v_splitedges, 
+      refprism_2fa_2e_0v_splitfaces, 0,
+      refprism_2fa_2e_0v_newelstypes, 
+      refprism_2fa_2e_0v_newels
+    };
+
+
+ 
+//  HP_PRISM_3E_0V   
+  int refprism_3e_0v_splitedges[][3] =
+    {
+      { 1, 2, 7},
+      { 2, 1, 8},
+      { 2, 3, 9},
+      { 3, 2, 10},
+      { 3, 1, 11},
+      { 1, 3, 12},
+      { 4, 5, 40},
+      { 5, 4, 41},
+      { 5, 6, 42},
+      { 6, 5, 43},
+      { 6, 4, 44},
+      { 4, 6, 45},
+      { 0, 0, 0}, 
+    };
+  int refprism_3e_0v_splitfaces[][4] = 
+    {
+      {1,2,3,13},
+      {2,3,1,14},
+      {3,1,2,15},
+      {4,5,6,46},
+      {5,4,6,47},
+      {6,4,5,48},
+      {0,0,0,0}, 
+    };
+
+  HPREF_ELEMENT_TYPE refprism_3e_0v_newelstypes[] =
+    {
+      HP_PRISM,
+      HP_HEX,
+      HP_HEX,
+      HP_HEX,
+      HP_PRISM,
+      HP_PRISM,
+      HP_PRISM,
+      HP_PRISM_SINGEDGE,
+      HP_PRISM_SINGEDGE,
+      HP_PRISM_SINGEDGE,
+      HP_NONE
+    };
+  int refprism_3e_0v_newels[][8] =
+    {
+      { 13, 14, 15, 46, 47, 48}, 
+      { 7, 8, 14, 13, 40, 41, 47, 46}, 
+      { 15, 14, 9, 10, 48, 47, 42, 43}, 
+      { 12, 13, 15, 11, 45, 46, 48, 44}, 
+      { 14, 8, 9, 47, 41, 42 }, 
+      { 11, 15, 10, 44, 48, 43 }, 
+      { 7, 13, 12, 40, 46, 45}, 
+      { 1, 7, 12, 4, 40, 45}, 
+      { 2, 9, 8, 5, 42, 41 }, 
+      { 3, 11, 10, 6, 44, 43 }
+    };
+  HPRef_Struct refprism_3e_0v =
+    {
+      HP_PRISM,
+      refprism_3e_0v_splitedges, 
+      refprism_3e_0v_splitfaces, 0,
+      refprism_3e_0v_newelstypes, 
+      refprism_3e_0v_newels
+    };
+
+
+//  HP_PRISM_3E_0V   
+int refprism_1fa_3e_0v_splitedges[][3] =
+    {
+      { 1, 2, 7},
+      { 2, 1, 8},
+      { 2, 3, 9},
+      { 3, 2, 10},
+      { 3, 1, 11},
+      { 1, 3, 12},
+      { 1, 4, 16}, 
+      { 2, 5, 17},
+      { 3, 6, 18},
+      { 4, 5, 40},
+      { 5, 4, 41},
+      { 5, 6, 42},
+      { 6, 5, 43},
+      { 6, 4, 44},
+      { 4, 6, 45},
+      
+      { 0, 0, 0}, 
+    };
+int refprism_1fa_3e_0v_splitfaces[][4] = 
+    {
+      {1,2,3,13},
+      {2,3,1,14},
+      {3,1,2,15},
+      {1,2,4,19},
+      {2,1,5,20},
+      {2,3,5,21},
+      {3,2,6,22},
+      {3,1,6,23},
+      {1,3,4,24},
+      {4,5,6,46},
+      {5,4,6,47},
+      {6,4,5,48}, 
+      {0,0,0,0}, 
+    };
+
+int refprism_1fa_3e_0v_splitelements[][5] = 
+  {
+      {1,2,3,4,25},
+      {2,1,3,5,26},
+      {3,1,2,6,27}, 
+      {0,0,0,0,0},
+  };
+
+  HPREF_ELEMENT_TYPE refprism_1fa_3e_0v_newelstypes[] =
+    {
+      HP_PRISM,
+      HP_HEX,
+      HP_HEX,
+      HP_HEX,
+      HP_PRISM,
+      HP_PRISM,
+      HP_PRISM,
+      HP_PRISM_SINGEDGE,
+      HP_PRISM_SINGEDGE,
+      HP_PRISM_SINGEDGE,
+
+      HP_PRISM_1FA_0E_0V,
+      HP_HEX_1F_0E_0V, 
+      HP_HEX_1F_0E_0V, 
+      HP_HEX_1F_0E_0V, 
+      HP_PRISM_1FA_0E_0V,
+      HP_PRISM_1FA_0E_0V,
+      HP_PRISM_1FA_0E_0V,
+      HP_PRISM_1FA_1E_0V,
+      HP_PRISM_1FA_1E_0V,
+      HP_PRISM_1FA_1E_0V,
+      HP_NONE
+    };
+int refprism_1fa_3e_0v_newels[][8] =
+    {
+      { 25, 26, 27, 46, 47, 48}, 
+      { 19, 20, 26, 25, 40, 41, 47, 46},  
+      { 27, 26, 21, 22, 48, 47, 42, 43}, 
+      { 23, 24, 25, 27, 44, 45, 46, 48}, 
+      { 19, 25, 24, 40, 46, 45}, 
+      { 26, 20, 21, 47, 41, 42},
+      { 23, 27, 22, 44, 48, 43}, 
+      { 16, 19, 24, 4, 40, 45}, 
+      { 17, 21, 20, 5, 42, 41}, 
+      { 18, 23, 22, 6, 44, 43}, 
+
+      { 13, 14, 15, 25, 26, 27}, 
+      { 7, 8, 14, 13, 19, 20, 26, 25},
+      { 15, 14, 9, 10, 27, 26, 21, 22}, 
+      { 12, 13, 15, 11, 24, 25, 27, 23}, 
+      { 14, 8, 9, 26, 20, 21}, 
+      { 11, 15, 10, 23, 27, 22}, 
+      { 7, 13 , 12, 19, 25, 24}, 
+      { 2, 9, 8, 17, 21, 20}, 
+      { 3, 11, 10, 18, 23, 22}, 
+      { 1, 7, 12, 16, 19, 24}, 
+    };
+  HPRef_Struct refprism_1fa_3e_0v =
+    {
+      HP_PRISM,
+      refprism_1fa_3e_0v_splitedges, 
+      refprism_1fa_3e_0v_splitfaces, 
+      refprism_1fa_3e_0v_splitelements, 
+      refprism_1fa_3e_0v_newelstypes, 
+      refprism_1fa_3e_0v_newels
+    };
+
+
+
+//  HP_PRISM_2FA_3E_0V   
+int refprism_2fa_3e_0v_splitedges[][3] =
+    {
+      { 1, 2, 7},
+      { 2, 1, 8},
+      { 2, 3, 9},
+      { 3, 2, 10},
+      { 3, 1, 11},
+      { 1, 3, 12},
+      { 1, 4, 16}, 
+      { 2, 5, 17},
+      { 3, 6, 18},
+      { 4, 1, 28},
+      { 5, 2, 29},
+      { 6, 3, 30},
+      { 4, 5, 40},
+      { 5, 4, 41},
+      { 5, 6, 42},
+      { 6, 5, 43},
+      { 6, 4, 44},
+      { 4, 6, 45},
+      { 0, 0, 0}, 
+    };
+int refprism_2fa_3e_0v_splitfaces[][4] = 
+    {
+      {1,2,3,13},
+      {2,3,1,14},
+      {3,1,2,15},
+      {1,2,4,19},
+      {2,1,5,20},
+      {2,3,5,21},
+      {3,2,6,22},
+      {3,1,6,23},
+      {1,3,4,24},
+      {4,1,5,31},
+      {5,4,2,32},
+      {5,6,2,33},
+      {6,5,3,34},
+      {6,4,3,35},
+      {4,1,6,36},
+      {4,5,6,46},
+      {5,4,6,47},
+      {6,4,5,48}, 
+      {0,0,0,0}, 
+    };
+
+int refprism_2fa_3e_0v_splitelements[][5] = 
+  {
+      {1,2,3,4,25},
+      {2,1,3,5,26},
+      {3,1,2,6,27}, 
+      {4,1,6,5,37},
+      {5,2,4,6,38},
+      {6,4,5,3,39}, 
+      {0,0,0,0,0},
+  };
+
+  HPREF_ELEMENT_TYPE refprism_2fa_3e_0v_newelstypes[] =
+    {
+      HP_PRISM,
+      HP_HEX,
+      HP_HEX,
+      HP_HEX,
+      HP_PRISM,
+      HP_PRISM,
+      HP_PRISM,
+      HP_PRISM_SINGEDGE,
+      HP_PRISM_SINGEDGE,
+      HP_PRISM_SINGEDGE,
+
+      HP_PRISM_1FA_0E_0V,
+      HP_HEX_1F_0E_0V, 
+      HP_HEX_1F_0E_0V, 
+      HP_HEX_1F_0E_0V, 
+      HP_PRISM_1FA_0E_0V,
+      HP_PRISM_1FA_0E_0V,
+      HP_PRISM_1FA_0E_0V,
+      HP_PRISM_1FA_1E_0V,
+      HP_PRISM_1FA_1E_0V,
+      HP_PRISM_1FA_1E_0V,
+
+      HP_PRISM_1FA_0E_0V,
+      HP_HEX_1F_0E_0V, 
+      HP_HEX_1F_0E_0V, 
+      HP_HEX_1F_0E_0V, 
+      HP_PRISM_1FA_0E_0V,
+      HP_PRISM_1FA_0E_0V,
+      HP_PRISM_1FA_0E_0V,
+      HP_PRISM_1FA_1E_0V,
+      HP_PRISM_1FA_1E_0V,
+      HP_PRISM_1FA_1E_0V,
+
+      HP_NONE
+    };
+
+  int refprism_2fa_3e_0v_newels[][8] =
+    {
+      { 25, 26, 27, 37, 38, 39}, 
+      { 19, 20, 26, 25, 31, 32, 38, 37},  
+      { 27, 26, 21, 22, 39, 38, 33, 34}, 
+      { 23, 24, 25, 27, 35, 36, 37, 39}, 
+      { 19, 25, 24, 31, 37, 36}, 
+      { 26, 20, 21, 38, 32, 33},
+      { 23, 27, 22, 35, 39, 34}, 
+      { 16, 19, 24, 28, 31, 36}, 
+      { 17, 21, 20, 29, 33, 32}, 
+      { 18, 23, 22, 30, 35, 34}, 
+
+      { 13, 14, 15, 25, 26, 27}, 
+      { 7, 8, 14, 13, 19, 20, 26, 25},
+      { 15, 14, 9, 10, 27, 26, 21, 22}, 
+      { 12, 13, 15, 11, 24, 25, 27, 23}, 
+      { 14, 8, 9, 26, 20, 21}, 
+      { 11, 15, 10, 23, 27, 22}, 
+      { 7, 13 , 12, 19, 25, 24}, 
+      { 2, 9, 8, 17, 21, 20}, 
+      { 3, 11, 10, 18, 23, 22}, 
+      { 1, 7, 12, 16, 19, 24}, 
+
+      { 48, 47, 46, 39, 38, 37 }, 
+      { 48, 43, 42, 47, 39, 34, 33, 38}, 
+      { 45, 44, 48, 46, 36, 35, 39, 37},
+      { 46, 47, 41, 40, 37, 38, 32, 31}, 
+      { 47, 42, 41, 38, 33, 32}, 
+      { 45, 46, 40, 36, 37, 31}, 
+      { 44, 43, 48, 35, 34, 39},
+      { 6, 43, 44, 30, 34, 35}, 
+      { 5, 41, 42, 29, 32, 33}, 
+      { 4, 45, 40, 28, 36, 31},
+    };
+
+HPRef_Struct refprism_2fa_3e_0v =
+  {
+    HP_PRISM,
+    refprism_2fa_3e_0v_splitedges, 
+    refprism_2fa_3e_0v_splitfaces, 
+    refprism_2fa_3e_0v_splitelements, 
+    refprism_2fa_3e_0v_newelstypes, 
+    refprism_2fa_3e_0v_newels
+  };
+
+
+
+//  HP_PRISM_3FB_0V   
+  int refprism_3fb_0v_splitedges[][3] =
+    {
+      { 1, 2, 7},
+      { 2, 1, 8},
+      { 2, 3, 9},
+      { 3, 2, 10},
+      { 3, 1, 11},
+      { 1, 3, 12},
+      { 4, 5, 40},
+      { 5, 4, 41},
+      { 5, 6, 42},
+      { 6, 5, 43},
+      { 6, 4, 44},
+      { 4, 6, 45},
+      { 0, 0, 0}, 
+    };
+  int refprism_3fb_0v_splitfaces[][4] = 
+    {
+      {1,2,3,13},
+      {2,3,1,14},
+      {3,1,2,15},
+      {4,5,6,46},
+      {5,4,6,47},
+      {6,4,5,48},
+      {0,0,0,0}, 
+    };
+
+  HPREF_ELEMENT_TYPE refprism_3fb_0v_newelstypes[] =
+    {
+      HP_PRISM,
+      HP_HEX_1F_0E_0V,
+      HP_HEX_1F_0E_0V,
+      HP_HEX_1F_0E_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_NONE
+    };
+  int refprism_3fb_0v_newels[][8] =
+    {
+      { 13, 14, 15, 46, 47, 48}, 
+      { 8, 7, 40, 41, 14,13, 46, 47 }, 
+      { 10, 9, 42, 43, 15, 14, 47, 48 }, 
+      { 44, 45, 12, 11, 48, 46, 13, 15}, 
+      { 1, 7, 13, 4, 40, 46 }, 
+      { 4, 45, 46, 1, 12, 13}, 
+      { 2, 9, 14, 5, 42, 47 }, 
+      { 5, 41, 47, 2, 8, 14 }, 
+      { 3, 11, 15, 6, 44, 48}, 
+      { 6, 43, 48, 3, 10, 15},
+
+    };
+  HPRef_Struct refprism_3fb_0v =
+    {
+      HP_PRISM,
+      refprism_3fb_0v_splitedges, 
+      refprism_3fb_0v_splitfaces, 0,
+      refprism_3fb_0v_newelstypes, 
+      refprism_3fb_0v_newels
+    };
+
+
+//  HP_PRISM_3FB_0V   
+int refprism_1fa_3fb_0v_splitedges[][3] =
+    {
+      { 1, 2, 7},
+      { 2, 1, 8},
+      { 2, 3, 9},
+      { 3, 2, 10},
+      { 3, 1, 11},
+      { 1, 3, 12},
+      { 1, 4, 16}, 
+      { 2, 5, 17},
+      { 3, 6, 18},
+      { 4, 5, 40},
+      { 5, 4, 41},
+      { 5, 6, 42},
+      { 6, 5, 43},
+      { 6, 4, 44},
+      { 4, 6, 45},
+      { 0, 0, 0}, 
+    };
+int refprism_1fa_3fb_0v_splitfaces[][4] = 
+    {
+      {1,2,3,13},
+      {2,3,1,14},
+      {3,1,2,15},
+      {1,2,4,19},
+      {2,1,5,20},
+      {2,3,5,21},
+      {3,2,6,22},
+      {3,1,6,23},
+      {1,3,4,24},
+      {4,5,6,46},
+      {5,4,6,47},
+      {6,4,5,48}, 
+      {0,0,0,0}, 
+    };
+
+int refprism_1fa_3fb_0v_splitelements[][5] = 
+  {
+      {1,2,3,4,25},
+      {2,1,3,5,26},
+      {3,1,2,6,27}, 
+      {0,0,0,0,0},
+  };
+
+  HPREF_ELEMENT_TYPE refprism_1fa_3fb_0v_newelstypes[] =
+    {
+      HP_PRISM,
+      HP_HEX_1F_0E_0V,
+      HP_HEX_1F_0E_0V,
+      HP_HEX_1F_0E_0V,
+      
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V,
+
+      HP_PRISM_1FA_0E_0V,
+      HP_HEX_1FA_1FB_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V, 
+      HP_PRISM_1FA_1FB_1EA_0V, 
+      HP_PRISM_1FA_1FB_1EB_0V, 
+      HP_PRISM_1FA_1FB_1EA_0V, 
+      HP_PRISM_1FA_1FB_1EB_0V, 
+      HP_PRISM_1FA_1FB_1EA_0V, 
+      HP_PRISM_1FA_1FB_1EB_0V, 
+      
+      HP_NONE
+    };
+  int refprism_1fa_3fb_0v_newels[][8] =
+    {
+      { 25, 26, 27, 46, 47, 48}, 
+      { 19, 40, 41, 20, 25, 46, 47, 26}, 
+      { 22, 21, 42, 43, 27, 26, 47, 48}, 
+      { 24, 23, 44, 45, 25, 27, 48, 46},
+      
+      { 16, 19, 25, 4, 40, 46 }, 
+      { 4, 45, 46, 16, 24, 25 }, 
+      { 17, 21, 26, 5, 42, 47 }, 
+      { 5, 41, 47, 17, 20, 26}, 
+      { 18, 23, 27, 6, 44, 48}, 
+      { 6, 43, 48, 18, 22, 27},
+
+      { 13, 14, 15, 25, 26, 27}, 
+      { 7, 8, 14, 13, 19, 20, 26, 25}, 
+      { 9, 10, 15, 14, 21, 22, 27, 26},
+      { 11, 12, 13, 15, 23, 24, 25, 27},
+
+      { 2, 9, 14, 17, 21, 26}, 
+      { 8, 2, 14, 20, 17, 26}, 
+      { 1, 7, 13, 16, 19, 25}, 
+      { 12, 1, 13, 24, 16, 25 }, 
+      { 3, 11, 15, 18, 23, 27 },
+      { 10, 3, 15, 22, 18, 27}, 
+      
+      };
+  HPRef_Struct refprism_1fa_3fb_0v =
+    {
+      HP_PRISM,
+      refprism_1fa_3fb_0v_splitedges, 
+      refprism_1fa_3fb_0v_splitfaces, 
+      refprism_1fa_3fb_0v_splitelements, 
+      refprism_1fa_3fb_0v_newelstypes, 
+      refprism_1fa_3fb_0v_newels
+    };
+     
+
+
+//  HP_PRISM_2FA_3E_0V   
+int refprism_2fa_3fb_0v_splitedges[][3] =
+    {
+      { 1, 2, 7},
+      { 2, 1, 8},
+      { 2, 3, 9},
+      { 3, 2, 10},
+      { 3, 1, 11},
+      { 1, 3, 12},
+      { 1, 4, 16}, 
+      { 2, 5, 17},
+      { 3, 6, 18},
+      { 4, 1, 28},
+      { 5, 2, 29},
+      { 6, 3, 30},
+      { 4, 5, 40},
+      { 5, 4, 41},
+      { 5, 6, 42},
+      { 6, 5, 43},
+      { 6, 4, 44},
+      { 4, 6, 45},
+      { 0, 0, 0}, 
+    };
+int refprism_2fa_3fb_0v_splitfaces[][4] = 
+    {
+      {1,2,3,13},
+      {2,3,1,14},
+      {3,1,2,15},
+      {1,2,4,19},
+      {2,1,5,20},
+      {2,3,5,21},
+      {3,2,6,22},
+      {3,1,6,23},
+      {1,3,4,24},
+      {4,1,5,31},
+      {5,4,2,32},
+      {5,6,2,33},
+      {6,5,3,34},
+      {6,4,3,35},
+      {4,1,6,36},
+      {4,5,6,46},
+      {5,4,6,47},
+      {6,4,5,48}, 
+      {0,0,0,0}, 
+    };
+
+int refprism_2fa_3fb_0v_splitelements[][5] = 
+  {
+      {1,2,3,4,25},
+      {2,1,3,5,26},
+      {3,1,2,6,27}, 
+      {4,1,6,5,37},
+      {5,2,4,6,38},
+      {6,4,5,3,39}, 
+      {0,0,0,0,0},
+  };
+
+  HPREF_ELEMENT_TYPE refprism_2fa_3fb_0v_newelstypes[] =
+    {
+
+      HP_PRISM,
+      HP_HEX_1F_0E_0V,
+      HP_HEX_1F_0E_0V,
+      HP_HEX_1F_0E_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V,
+
+      HP_PRISM_1FA_0E_0V,
+      HP_HEX_1FA_1FB_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V,
+      HP_PRISM_1FA_1FB_1EA_0V, 
+      HP_PRISM_1FA_1FB_1EB_0V, 
+      HP_PRISM_1FA_1FB_1EA_0V, 
+      HP_PRISM_1FA_1FB_1EB_0V, 
+      HP_PRISM_1FA_1FB_1EA_0V, 
+      HP_PRISM_1FA_1FB_1EB_0V, 
+
+      HP_PRISM_1FA_0E_0V,
+      HP_HEX_1FA_1FB_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V,
+      HP_PRISM_1FA_1FB_1EA_0V, 
+      HP_PRISM_1FA_1FB_1EB_0V, 
+      HP_PRISM_1FA_1FB_1EA_0V, 
+      HP_PRISM_1FA_1FB_1EB_0V, 
+      HP_PRISM_1FA_1FB_1EA_0V, 
+      HP_PRISM_1FA_1FB_1EB_0V, 
+
+      HP_NONE
+    };
+  int refprism_2fa_3fb_0v_newels[][8] =
+    {
+      { 25, 26, 27, 37, 38, 39}, 
+      { 19, 31, 32, 20, 25, 37, 38, 26}, 
+      { 33, 34, 22, 21, 38, 39, 27, 26}, 
+      { 35, 36, 24, 23, 39, 37, 25, 27}, 
+
+      { 16, 19, 25, 28, 31, 37}, 
+      { 28, 36, 37, 16, 24, 25 }, 
+      { 17, 21, 26, 29, 33, 38 }, 
+      { 29, 32, 38, 17, 20, 26}, 
+      { 18, 23, 27, 30, 35, 39}, 
+      { 30, 34, 39, 18, 22, 27},
+
+ 
+      { 13, 14, 15, 25, 26, 27}, 
+      { 7, 8, 14, 13, 19, 20, 26, 25}, 
+      { 9, 10, 15, 14, 21, 22, 27, 26},
+      { 11, 12, 13, 15, 23, 24, 25, 27},
+
+      { 2, 9, 14, 17, 21, 26}, 
+      { 8, 2, 14, 20, 17, 26}, 
+      { 1, 7, 13, 16, 19, 25}, 
+      { 12, 1, 13, 24, 16, 25 }, 
+      { 3, 11, 15, 18, 23, 27 },
+      { 10, 3, 15, 22, 18, 27}, 
+
+      
+      { 48, 47, 46, 39, 38, 37 }, 
+      { 44, 45, 36, 35, 48, 46, 37, 39}, 
+      { 40, 41, 32, 31, 46, 47, 38, 37}, 
+      { 42, 43, 34, 33, 47, 48, 39, 38}, 
+      
+      { 6, 43, 48, 30, 34, 39}, 
+      { 44, 6, 48, 35, 30, 39}, 
+      { 4, 45, 46, 28, 36, 37}, 
+      { 40, 4, 46, 31, 28, 37}, 
+      { 5, 41, 47, 29, 32, 38}, 
+      { 42, 5, 47, 33, 29, 38},
+    };
+
+HPRef_Struct refprism_2fa_3fb_0v =
+  {
+    HP_PRISM,
+    refprism_2fa_3fb_0v_splitedges, 
+    refprism_2fa_3fb_0v_splitfaces, 
+    refprism_2fa_3fb_0v_splitelements, 
+    refprism_2fa_3fb_0v_newelstypes, 
+    refprism_2fa_3fb_0v_newels
+  };
+
+
+/* 
+
+
+//  HP_PRISM_3E_4EH
+int refprism_3e_4eh_splitedges[][3] =
+    {
+      { 1, 2, 7},
+      { 2, 1, 8},
+      { 2, 3, 9},
+      { 3, 2, 10},
+      { 3, 1, 11},
+      { 1, 3, 12},
+      { 4, 5, 40},
+      { 5, 4, 41},
+      { 5, 6, 42},
+      { 6, 5, 43},
+      { 6, 4, 44},
+      { 4, 6, 45},
+      { 0, 0, 0},
+
+    };
+int refprism_3e_4eh_splitfaces[][4] = 
+    {
+      {3,1,2,15},
+      {6,4,5,48}, 
+      {0,0,0,0}, 
+    };
+
+HPREF_ELEMENT_TYPE refprism_2fa_3fb_0v_newelstypes[] =
+  {
+    HP_PRISM, 
+    HP_HEX_2EH_0V,
+    HP_HEX_2EH_0V,
+    HP_TET_2E,
+    HP_TET_2E,
+    HP_PRISM_1E_2EH_0V, 
+    HP_PRISM_1E_2EH_0V, 
+    HP_NONE
+    };
+  int refprism_2fa_3fb_0v_newels[][8] =
+    {
+      {15, 7, 8, 48, 40, 41 }, 
+      
+    };
+
+HPRef_Struct refprism_2fa_3fb_0v =
+  {
+    HP_PRISM,
+    refprism_2fa_3fb_0v_splitedges, 
+    refprism_2fa_3fb_0v_splitfaces, 
+    refprism_2fa_3fb_0v_splitelements, 
+    refprism_2fa_3fb_0v_newelstypes, 
+    refprism_2fa_3fb_0v_newels
+  };
+*/ 
+
+/*
+//  HP_PRISM_2FA_3E_0V   
+int refprism_3e_4_0v_splitedges[][3] =
+    {
+      { 1, 2, 7},
+      { 2, 1, 8},
+      { 2, 3, 9},
+      { 3, 2, 10},
+      { 3, 1, 11},
+      { 1, 3, 12},
+      { 1, 4, 16}, 
+      { 2, 5, 17},
+      { 3, 6, 18},
+      { 4, 1, 28},
+      { 5, 2, 29},
+      { 6, 3, 30},
+      { 4, 5, 40},
+      { 5, 4, 41},
+      { 5, 6, 42},
+      { 6, 5, 43},
+      { 6, 4, 44},
+      { 4, 6, 45},
+      { 0, 0, 0}, 
+    };
+int refprism_2fa_3e_0v_splitfaces[][4] = 
+    {
+      {1,2,3,13},
+      {2,3,1,14},
+      {3,1,2,15},
+      {1,2,4,19},
+      {2,1,5,20},
+      {2,3,5,21},
+      {3,2,6,22},
+      {3,1,6,23},
+      {1,3,4,24},
+      {4,1,5,31},
+      {5,4,2,32},
+      {5,6,2,33},
+      {6,5,3,34},
+      {6,4,3,35},
+      {4,1,6,36},
+      {4,5,6,46},
+      {5,4,6,47},
+      {6,4,5,48}, 
+      {0,0,0,0}, 
+    };
+
+int refprism_2fa_3e_0v_splitelements[][5] = 
+  {
+      {1,2,3,4,25},
+      {2,1,3,5,26},
+      {3,1,2,6,27}, 
+      {4,1,6,5,37},
+      {5,2,4,6,38},
+      {6,4,5,3,39}, 
+      {0,0,0,0,0},
+  };
+
+  HPREF_ELEMENT_TYPE refprism_2fa_3e_0v_newelstypes[] =
+    {
+      HP_PRISM,
+      HP_HEX,
+      HP_HEX,
+      HP_HEX,
+      HP_PRISM,
+      HP_PRISM,
+      HP_PRISM,
+      HP_PRISM_SINGEDGE,
+      HP_PRISM_SINGEDGE,
+      HP_PRISM_SINGEDGE,
+
+      HP_PRISM_1FA_0E_0V,
+      HP_HEX_1F_0E_0V, 
+      HP_HEX_1F_0E_0V, 
+      HP_HEX_1F_0E_0V, 
+      HP_PRISM_1FA_0E_0V,
+      HP_PRISM_1FA_0E_0V,
+      HP_PRISM_1FA_0E_0V,
+      HP_PRISM_1FA_1E_0V,
+      HP_PRISM_1FA_1E_0V,
+      HP_PRISM_1FA_1E_0V,
+
+      HP_PRISM_1FA_0E_0V,
+      HP_HEX_1F_0E_0V, 
+      HP_HEX_1F_0E_0V, 
+      HP_HEX_1F_0E_0V, 
+      HP_PRISM_1FA_0E_0V,
+      HP_PRISM_1FA_0E_0V,
+      HP_PRISM_1FA_0E_0V,
+      HP_PRISM_1FA_1E_0V,
+      HP_PRISM_1FA_1E_0V,
+      HP_PRISM_1FA_1E_0V,
+
+      HP_NONE
+    };
+
+  int refprism_2fa_3e_0v_newels[][8] =
+    {
+      { 25, 26, 27, 37, 38, 39}, 
+      { 19, 20, 26, 25, 31, 32, 38, 37},  
+      { 27, 26, 21, 22, 39, 38, 33, 34}, 
+      { 23, 24, 25, 27, 35, 36, 37, 39}, 
+      { 19, 25, 24, 31, 37, 36}, 
+      { 26, 20, 21, 38, 32, 33},
+      { 23, 27, 22, 35, 39, 34}, 
+      { 16, 19, 24, 28, 31, 36}, 
+      { 17, 21, 20, 29, 33, 32}, 
+      { 18, 23, 22, 30, 35, 34}, 
+
+      { 13, 14, 15, 25, 26, 27}, 
+      { 7, 8, 14, 13, 19, 20, 26, 25},
+      { 15, 14, 9, 10, 27, 26, 21, 22}, 
+      { 12, 13, 15, 11, 24, 25, 27, 23}, 
+      { 14, 8, 9, 26, 20, 21}, 
+      { 11, 15, 10, 23, 27, 22}, 
+      { 7, 13 , 12, 19, 25, 24}, 
+      { 2, 9, 8, 17, 21, 20}, 
+      { 3, 11, 10, 18, 23, 22}, 
+      { 1, 7, 12, 16, 19, 24}, 
+
+      { 48, 47, 46, 39, 38, 37 }, 
+      { 48, 43, 42, 47, 39, 34, 33, 38}, 
+      { 45, 44, 48, 46, 36, 35, 39, 37},
+      { 46, 47, 41, 40, 37, 38, 32, 31}, 
+      { 47, 42, 41, 38, 33, 32}, 
+      { 45, 46, 40, 36, 37, 31}, 
+      { 44, 43, 48, 35, 34, 39},
+      { 6, 43, 44, 30, 34, 35}, 
+      { 5, 41, 42, 29, 32, 33}, 
+      { 4, 45, 40, 28, 36, 31},
+    };
+
+HPRef_Struct refprism_2fa_3e_0v =
+  {
+    HP_PRISM,
+    refprism_2fa_3e_0v_splitedges, 
+    refprism_2fa_3e_0v_splitfaces, 
+    refprism_2fa_3e_0v_splitelements, 
+    refprism_2fa_3e_0v_newelstypes, 
+    refprism_2fa_3e_0v_newels
+  };
+
+*/
+/*
+
+//  HP_PRISM_1FB_1EB_0V   ... quad face 1-2-4-5
+  int refprism_1fb_1eb_0v_splitedges[][3] =
+    {
+      { 1, 3, 7 },
+      { 2, 3, 8 },
+      { 4, 6, 9 },
+      { 5, 6, 10 },
+      { 2, 1, 11 },
+      { 5, 4, 12 },
+      { 0, 0, 0 }
+    };
+  HPREF_ELEMENT_TYPE refprism_1fb_1eb_0v_newelstypes[] =
+    {
+      HP_HEX_1F_0E_0V,
+      HP_PRISM_1FB_1EB_0V,
+      HP_PRISM,
+      HP_NONE,
+    };
+  int refprism_1fb_1eb_0v_newels[][8] =
+    {
+      { 1, 4, 12, 11, 7, 9, 10, 8  },
+      { 11, 2, 8, 12, 5, 10 },
+      { 7, 8, 3, 9, 10, 6 }
+    };
+  HPRef_Struct refprism_1fb_1eb_0v =
+    {
+      HP_PRISM,
+      refprism_1fb_1eb_0v_splitedges, 
+      0, 0,
+      refprism_1fb_1eb_0v_newelstypes, 
+      refprism_1fb_1eb_0v_newels
+    };
+
+
+
+
+
+
+
+
+
+
+  // HP_PRISM_2F_0E_0V
+  int refprism_2f_0e_0v_splitedges[][3] =
+    {
+      { 1, 3, 7 },
+      { 2, 1, 8 },
+      { 2, 3, 9 },
+      { 3, 1, 10 },
+
+      { 4, 6, 12 },
+      { 5, 4, 13 },
+      { 5, 6, 14 },
+      { 6, 4, 15 },
+
+      { 0, 0, 0 }
+    };
+
+  int refprism_2f_0e_0v_splitfaces[][4] =
+    {
+      { 2, 1, 3, 11 },
+      { 5, 4, 6, 16 },
+      { 0, 0, 0, 0 },
+    };
+
+  HPREF_ELEMENT_TYPE refprism_2f_0e_0v_newelstypes[] =
+    {
+      HP_HEX_1F_0E_0V,
+      HP_HEX_1F_0E_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM,
+      HP_NONE,
+    };
+  int refprism_2f_0e_0v_newels[][8] =
+    {
+      //{ 1, 8, 11, 7, 4, 13, 16, 12 },
+      // { 9, 3, 10, 11, 14, 6, 15, 16 },
+      { 1, 4, 13, 8, 7, 12, 16, 11 },
+      { 9, 14, 6, 3, 11, 16, 15, 10 },
+      { 2, 9, 11, 5, 14, 16 },
+      // { 8, 2, 11, 13, 5, 16 },
+      { 5, 13, 16, 2, 8, 11 },
+      { 7, 11, 10, 12, 16, 15 }
+    };
+  HPRef_Struct refprism_2f_0e_0v =
+    {
+      HP_PRISM,
+      refprism_2f_0e_0v_splitedges, 
+      refprism_2f_0e_0v_splitfaces, 
+      0,
+      refprism_2f_0e_0v_newelstypes, 
+      refprism_2f_0e_0v_newels
+    };
+
+*/
diff --git a/contrib/Netgen/libsrc/meshing/hpref_pyramid.hpp b/contrib/Netgen/libsrc/meshing/hpref_pyramid.hpp
new file mode 100644
index 0000000000..521daf5081
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/hpref_pyramid.hpp
@@ -0,0 +1,118 @@
+
+  // 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 }
+    };
+  HPRef_Struct refpyramid =
+    {
+      HP_PYRAMID,
+      refpyramid_splitedges, 
+      0, 0,
+      refpyramid_newelstypes, 
+      refpyramid_newels
+    };
+
+
+// singular point 1      
+  // 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
+    };
+
+
+// singular edges 1-2 1-4 singular point 1 
+  // 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
+    };
+
+
+
+// singular face 1-2-5 singular point 5
+  // HP_PYRAMID_1FB_0E_1VA
+  int refpyramid_1fb_0e_1va_splitedges[][3] =
+    {
+      { 1, 4, 6 },
+      { 2, 3, 7 },
+      { 5, 1, 8 },
+      { 5, 2, 9 },
+      { 5, 3, 10 },
+      { 5, 4, 11 },
+      { 0, 0, 0 },
+    };
+
+  HPREF_ELEMENT_TYPE refpyramid_1fb_0e_1va_newelstypes[] =
+    {
+      HP_HEX_1F_0E_0V,
+      HP_PYRAMID_1FB_0E_1VA,
+      HP_PRISM,
+      HP_NONE,
+    };
+  int refpyramid_1fb_0e_1va_newels[][8] =
+    {
+      { 1, 8, 9, 2, 6, 11, 10, 7 },
+      { 8, 9, 10, 11, 5 },
+      { 3, 7, 10, 4, 6, 11 }
+    };
+  HPRef_Struct refpyramid_1fb_0e_1va =
+    {
+      HP_PYRAMID,
+      refpyramid_1fb_0e_1va_splitedges, 
+      0, 0,
+      refpyramid_1fb_0e_1va_newelstypes, 
+      refpyramid_1fb_0e_1va_newels
+    };
+
+
+
+
diff --git a/contrib/Netgen/libsrc/meshing/hpref_quad.hpp b/contrib/Netgen/libsrc/meshing/hpref_quad.hpp
new file mode 100644
index 0000000000..2a23156d1c
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/hpref_quad.hpp
@@ -0,0 +1,2082 @@
+// 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_0E_2VA
+int refquad_0e_2va_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 4, 6 },
+  { 2, 1, 7 },
+  { 2, 3, 8 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE refquad_0e_2va_newelstypes[] =
+{
+  HP_TRIG_SINGCORNER,
+  HP_TRIG_SINGCORNER,
+  HP_QUAD,
+  HP_QUAD,
+  HP_NONE,
+};
+int refquad_0e_2va_newels[][8] =
+{
+  { 1, 5, 6 },
+  { 2, 8, 7 },
+  { 5, 7, 8, 6 },
+  { 6, 8, 3, 4 },
+};
+HPRef_Struct refquad_0e_2va =
+{
+  HP_QUAD,
+  refquad_0e_2va_splitedges, 
+  0, 0,
+  refquad_0e_2va_newelstypes, 
+  refquad_0e_2va_newels
+};
+
+
+
+// HP_QUAD_0E_2VB
+int refquad_0e_2vb_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 4, 6 },
+  { 3, 4, 7 },
+  { 3, 2, 8 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE refquad_0e_2vb_newelstypes[] =
+{
+  HP_TRIG_SINGCORNER,
+  HP_TRIG_SINGCORNER,
+  HP_QUAD,
+  HP_QUAD,
+  HP_NONE,
+};
+int refquad_0e_2vb_newels[][8] =
+{
+  { 1, 5, 6 },
+  { 3, 7, 8 },
+  { 5, 2, 4, 6 },
+  { 2, 8, 7, 4 },
+};
+HPRef_Struct refquad_0e_2vb =
+{
+  HP_QUAD,
+  refquad_0e_2vb_splitedges, 
+  0, 0,
+  refquad_0e_2vb_newelstypes, 
+  refquad_0e_2vb_newels
+};
+
+
+
+
+// HP_QUAD_0E_3V
+int refquad_0e_3v_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 4, 6 },
+  { 2, 1, 7 },
+  { 2, 3, 8 },
+  { 3, 2, 9 },
+  { 3, 4, 10 },
+  { 0, 0, 0 }
+};
+
+int refquad_0e_3v_splitfaces[][4] =
+{
+  { 2, 3, 1, 14 },
+  { 0, 0, 0, 0 },
+};
+
+HPREF_ELEMENT_TYPE refquad_0e_3v_newelstypes[] =
+{
+  HP_TRIG_SINGCORNER,
+  HP_DUMMY_QUAD_SINGCORNER,
+  HP_TRIG_SINGCORNER,
+  HP_QUAD,
+  HP_QUAD,
+  HP_QUAD,
+  HP_NONE,
+};
+int refquad_0e_3v_newels[][8] =
+{
+  { 1, 5, 6 },
+  { 2, 8, 14, 7 },
+  { 3, 10, 9 },
+  { 5, 7, 14, 6 },
+  { 8, 9, 10, 14 },
+  { 6, 14, 10, 4 },
+};
+HPRef_Struct refquad_0e_3v =
+{
+  HP_QUAD,
+  refquad_0e_3v_splitedges, 
+  refquad_0e_3v_splitfaces, 
+  0,
+  refquad_0e_3v_newelstypes, 
+  refquad_0e_3v_newels
+};
+
+
+
+
+// HP_QUAD_0E_4V
+int refquad_0e_4v_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 4, 6 },
+  { 2, 1, 7 },
+  { 2, 3, 8 },
+  { 3, 2, 9 },
+  { 3, 4, 10 },
+  { 4, 1, 11 },
+  { 4, 3, 12 },
+  { 0, 0, 0 }
+};
+
+int refquad_0e_4v_splitfaces[][4] =
+{
+  { 1, 2, 4, 13 },
+  { 2, 3, 1, 14 },
+  { 3, 4, 2, 15 },
+  { 4, 1, 3, 16 },
+  { 0, 0, 0, 0 },
+};
+
+HPREF_ELEMENT_TYPE refquad_0e_4v_newelstypes[] =
+{
+  HP_DUMMY_QUAD_SINGCORNER,
+  HP_DUMMY_QUAD_SINGCORNER,
+  HP_DUMMY_QUAD_SINGCORNER,
+  HP_DUMMY_QUAD_SINGCORNER,
+
+  HP_QUAD,
+  HP_QUAD,
+  HP_QUAD,
+  HP_QUAD,
+
+  HP_QUAD,
+  HP_NONE,
+};
+int refquad_0e_4v_newels[][8] =
+{
+  { 1, 5, 13, 6 },
+  { 2, 8, 14, 7 },
+  { 3, 10, 15, 9 },
+  { 4, 11, 16, 12 },
+  { 5, 7, 14, 13 },
+  { 8, 9, 15, 14 },
+  { 10, 12, 16, 15 },
+  { 11, 6, 13, 16 },
+  { 13, 14, 15, 16 }
+};
+HPRef_Struct refquad_0e_4v =
+{
+  HP_QUAD,
+  refquad_0e_4v_splitedges, 
+  refquad_0e_4v_splitfaces, 
+  0,
+  refquad_0e_4v_newelstypes, 
+  refquad_0e_4v_newels
+};
+
+
+
+
+
+
+
+
+// HP_QUAD_1E_1VA
+int refquad_1e_1va_splitedges[][3] =
+{
+  { 1, 4, 5 },
+  { 2, 3, 6 },
+  { 1, 2, 7 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE refquad_1e_1va_newelstypes[] =
+{
+  HP_QUAD_SINGEDGE,
+  HP_QUAD,
+  HP_TRIG_SINGEDGECORNER1,
+  HP_NONE,
+};
+int refquad_1e_1va_newels[][8] =
+{
+  { 7, 2, 6, 5 },
+  { 5, 6, 3, 4 },
+  { 1, 7, 5 },
+};
+HPRef_Struct refquad_1e_1va =
+{
+  HP_QUAD,
+  refquad_1e_1va_splitedges, 
+  0, 0,
+  refquad_1e_1va_newelstypes, 
+  refquad_1e_1va_newels
+};
+
+
+
+
+// HP_QUAD_1E_1VB
+int refquad_1e_1vb_splitedges[][3] =
+{
+  { 1, 4, 5 },
+  { 2, 3, 6 },
+  { 2, 1, 7 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE refquad_1e_1vb_newelstypes[] =
+{
+  HP_QUAD_SINGEDGE,
+  HP_QUAD,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_NONE,
+};
+int refquad_1e_1vb_newels[][8] =
+{
+  { 1, 7, 6, 5 },
+  { 5, 6, 3, 4 },
+  { 7, 2, 6 },
+};
+HPRef_Struct refquad_1e_1vb =
+{
+  HP_QUAD,
+  refquad_1e_1vb_splitedges, 
+  0, 0,
+  refquad_1e_1vb_newelstypes, 
+  refquad_1e_1vb_newels
+};
+
+
+
+// HP_QUAD_1E_1VC
+int refquad_1e_1vc_splitedges[][3] =
+{
+  { 1, 4, 5 },
+  { 2, 3, 6 },
+  { 3, 2, 7 },
+  { 3, 4, 8 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE refquad_1e_1vc_newelstypes[] =
+{
+  HP_QUAD_SINGEDGE,
+  HP_TRIG,
+  HP_QUAD,
+  HP_TRIG_SINGCORNER,
+  HP_NONE,
+};
+int refquad_1e_1vc_newels[][8] =
+{
+  { 1, 2, 6, 5 },
+  { 5, 6, 4 },
+  { 4, 6, 7, 8 },
+  { 3, 8, 7 }
+};
+HPRef_Struct refquad_1e_1vc =
+{
+  HP_QUAD,
+  refquad_1e_1vc_splitedges, 
+  0, 0,
+  refquad_1e_1vc_newelstypes, 
+  refquad_1e_1vc_newels
+};
+
+
+
+// HP_QUAD_1E_1VD
+int refquad_1e_1vd_splitedges[][3] =
+{
+  { 1, 4, 5 },
+  { 2, 3, 6 },
+  { 4, 1, 7 },
+  { 4, 3, 8 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE refquad_1e_1vd_newelstypes[] =
+{
+  HP_QUAD_SINGEDGE,
+  HP_TRIG,
+  HP_QUAD,
+  HP_TRIG_SINGCORNER,
+  HP_NONE,
+};
+int refquad_1e_1vd_newels[][8] =
+{
+  { 1, 2, 6, 5 },
+  { 5, 6, 3 },
+  { 5, 3, 8, 7 },
+  { 4, 7, 8 }
+};
+HPRef_Struct refquad_1e_1vd =
+{
+  HP_QUAD,
+  refquad_1e_1vd_splitedges, 
+  0, 0,
+  refquad_1e_1vd_newelstypes, 
+  refquad_1e_1vd_newels
+};
+
+
+
+
+
+
+
+// HP_QUAD_1E_2VA
+int refquad_1e_2va_splitedges[][3] =
+{
+  { 1, 4, 5 },
+  { 2, 3, 6 },
+  { 1, 2, 7 },
+  { 2, 1, 8 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE refquad_1e_2va_newelstypes[] =
+{
+  HP_QUAD_SINGEDGE,
+  HP_QUAD,
+  HP_TRIG_SINGEDGECORNER1,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_NONE,
+};
+int refquad_1e_2va_newels[][8] =
+{
+  { 7, 8, 6, 5 },
+  { 5, 6, 3, 4 },
+  { 1, 7, 5 },
+  { 8, 2, 6 }
+};
+HPRef_Struct refquad_1e_2va =
+{
+  HP_QUAD,
+  refquad_1e_2va_splitedges, 
+  0, 0,
+  refquad_1e_2va_newelstypes, 
+  refquad_1e_2va_newels
+};
+
+
+
+
+// HP_QUAD_1E_2VB
+int refquad_1e_2vb_splitedges[][3] =
+{
+  { 1, 4, 5 },
+  { 2, 3, 6 },
+  { 1, 2, 7 },
+  { 3, 2, 8 },
+  { 3, 4, 9 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE refquad_1e_2vb_newelstypes[] =
+{
+  HP_QUAD_SINGEDGE,
+  HP_TRIG_SINGEDGECORNER1,
+  HP_TRIG,
+  HP_QUAD,
+  HP_TRIG_SINGCORNER,
+  HP_NONE,
+};
+int refquad_1e_2vb_newels[][8] =
+{
+  { 7, 2, 6, 5 },
+  { 1, 7, 5 },
+  { 5, 6, 4 },
+  { 4, 6, 8, 9 },
+  { 3, 9, 8 }
+};
+HPRef_Struct refquad_1e_2vb =
+{
+  HP_QUAD,
+  refquad_1e_2vb_splitedges, 
+  0, 0,
+  refquad_1e_2vb_newelstypes, 
+  refquad_1e_2vb_newels
+};
+
+
+
+
+// HP_QUAD_1E_2VC
+int refquad_1e_2vc_splitedges[][3] =
+{
+  { 1, 4, 5 },
+  { 2, 3, 6 },
+  { 1, 2, 7 },
+  { 4, 1, 8 },
+  { 4, 3, 9 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE refquad_1e_2vc_newelstypes[] =
+{
+  HP_QUAD_SINGEDGE,
+  HP_TRIG_SINGEDGECORNER1,
+  HP_TRIG,
+  HP_QUAD,
+  HP_TRIG_SINGCORNER,
+  HP_NONE,
+};
+int refquad_1e_2vc_newels[][8] =
+{
+  { 7, 2, 6, 5 },
+  { 1, 7, 5 },
+  { 5, 6, 3 },
+  { 5, 3, 9, 8 },
+  { 4, 8, 9 }
+};
+HPRef_Struct refquad_1e_2vc =
+{
+  HP_QUAD,
+  refquad_1e_2vc_splitedges, 
+  0, 0,
+  refquad_1e_2vc_newelstypes, 
+  refquad_1e_2vc_newels
+};
+
+
+
+
+// HP_QUAD_1E_2VD
+int refquad_1e_2vd_splitedges[][3] =
+{
+  { 1, 4, 5 },
+  { 2, 3, 6 },
+  { 2, 1, 7 },
+  { 3, 2, 8 },
+  { 3, 4, 9 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE refquad_1e_2vd_newelstypes[] =
+{
+  HP_QUAD_SINGEDGE,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_TRIG,
+  HP_QUAD,
+  HP_TRIG_SINGCORNER,
+  HP_NONE,
+};
+int refquad_1e_2vd_newels[][8] =
+{
+  { 1, 7, 6, 5 },
+  { 7, 2, 6 },
+  { 5, 6, 4 },
+  { 4, 6, 8, 9 },
+  { 3, 9, 8 }
+};
+HPRef_Struct refquad_1e_2vd =
+{
+  HP_QUAD,
+  refquad_1e_2vd_splitedges, 
+  0, 0,
+  refquad_1e_2vd_newelstypes, 
+  refquad_1e_2vd_newels
+};
+
+
+
+
+
+// HP_QUAD_1E_2VE
+int refquad_1e_2ve_splitedges[][3] =
+{
+  { 1, 4, 5 },
+  { 2, 3, 6 },
+  { 2, 1, 7 },
+  { 4, 1, 8 },
+  { 4, 3, 9 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE refquad_1e_2ve_newelstypes[] =
+{
+  HP_QUAD_SINGEDGE,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_TRIG,
+  HP_QUAD,
+  HP_TRIG_SINGCORNER,
+  HP_NONE,
+};
+int refquad_1e_2ve_newels[][8] =
+{
+  { 1, 7, 6, 5 },
+  { 7, 2, 6 },
+  { 5, 6, 3 },
+  { 5, 3, 9, 8 },
+  { 4, 8, 9 }
+};
+HPRef_Struct refquad_1e_2ve =
+{
+  HP_QUAD,
+  refquad_1e_2ve_splitedges, 
+  0, 0,
+  refquad_1e_2ve_newelstypes, 
+  refquad_1e_2ve_newels
+};
+
+
+
+
+
+
+// HP_QUAD_1E_2VF
+int refquad_1e_2vf_splitedges[][3] =
+{
+  { 1, 4, 5 },
+  { 2, 3, 6 },
+  { 4, 1, 7 },
+  { 4, 3, 8 },
+  { 3, 2, 9 },
+  { 3, 4, 10 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE refquad_1e_2vf_newelstypes[] =
+{
+  HP_QUAD_SINGEDGE,
+  HP_QUAD,
+  HP_QUAD,
+  HP_TRIG_SINGCORNER,
+  HP_TRIG_SINGCORNER,
+  HP_NONE,
+};
+int refquad_1e_2vf_newels[][8] =
+{
+  { 1, 2, 6, 5 },
+  { 5, 6, 9, 7 },
+  { 7, 9, 10, 8 },
+  { 4, 7, 8 },
+  { 3, 10, 9 },
+};
+HPRef_Struct refquad_1e_2vf =
+{
+  HP_QUAD,
+  refquad_1e_2vf_splitedges, 
+  0, 0,
+  refquad_1e_2vf_newelstypes, 
+  refquad_1e_2vf_newels
+};
+
+
+
+
+
+// HP_QUAD_1E_3VA
+int refquad_1e_3va_splitedges[][3] =
+{
+  { 1, 4, 5 },
+  { 2, 3, 6 },
+  { 1, 2, 7 },
+  { 2, 1, 8 },
+  { 3, 2, 9 },
+  { 3, 4, 10 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE refquad_1e_3va_newelstypes[] =
+{
+  HP_TRIG_SINGEDGECORNER1,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_TRIG_SINGCORNER,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD,
+  HP_TRIG,
+  HP_NONE,
+};
+int refquad_1e_3va_newels[][8] =
+{
+  { 1, 7, 5 },
+  { 8, 2, 6 },
+  { 3, 10, 9 },
+  { 7, 8, 6, 5 },
+  { 4, 6, 9, 10 },
+  { 5, 6, 4 }
+};
+HPRef_Struct refquad_1e_3va =
+{
+  HP_QUAD,
+  refquad_1e_3va_splitedges, 
+  0, 0,
+  refquad_1e_3va_newelstypes, 
+  refquad_1e_3va_newels
+};
+
+
+
+
+
+// HP_QUAD_1E_3VB
+int refquad_1e_3vb_splitedges[][3] =
+{
+  { 1, 4, 5 },
+  { 2, 3, 6 },
+  { 1, 2, 7 },
+  { 2, 1, 8 },
+  { 4, 1, 9 },
+  { 4, 3, 10 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE refquad_1e_3vb_newelstypes[] =
+{
+  HP_TRIG_SINGEDGECORNER1,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_TRIG_SINGCORNER,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD,
+  HP_TRIG,
+  HP_NONE,
+};
+int refquad_1e_3vb_newels[][8] =
+{
+  { 1, 7, 5 },
+  { 8, 2, 6 },
+  { 4, 9, 10 },
+  { 7, 8, 6, 5 },
+  { 5, 3, 10, 9 },
+  { 5, 6, 3 }
+};
+HPRef_Struct refquad_1e_3vb =
+{
+  HP_QUAD,
+  refquad_1e_3vb_splitedges, 
+  0, 0,
+  refquad_1e_3vb_newelstypes, 
+  refquad_1e_3vb_newels
+};
+
+
+
+
+
+// HP_QUAD_1E_3VC
+int refquad_1e_3vc_splitedges[][3] =
+{
+  { 1, 4, 5 },
+  { 2, 3, 6 },
+  { 1, 2, 7 },
+  { 3, 2, 8 },
+  { 3, 4, 9 },
+  { 4, 3, 10 },
+  { 4, 1, 11 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE refquad_1e_3vc_newelstypes[] =
+{
+  HP_TRIG_SINGEDGECORNER1,
+  HP_TRIG_SINGCORNER,
+  HP_TRIG_SINGCORNER,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD,
+  HP_QUAD,
+  HP_NONE,
+};
+int refquad_1e_3vc_newels[][8] =
+{
+  { 1, 7, 5 },
+  { 3, 9, 8 },
+  { 4, 11, 10 },
+  { 7, 2, 6, 5 },
+  { 5, 6, 8, 11 },
+  { 11, 8, 9, 10 }
+};
+HPRef_Struct refquad_1e_3vc =
+{
+  HP_QUAD,
+  refquad_1e_3vc_splitedges, 
+  0, 0,
+  refquad_1e_3vc_newelstypes, 
+  refquad_1e_3vc_newels
+};
+
+
+
+
+// HP_QUAD_1E_3VD
+int refquad_1e_3vd_splitedges[][3] =
+{
+  { 1, 4, 5 },
+  { 2, 3, 6 },
+  { 2, 1, 7 },
+  { 3, 2, 8 },
+  { 3, 4, 9 },
+  { 4, 3, 10 },
+  { 4, 1, 11 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE refquad_1e_3vd_newelstypes[] =
+{
+  HP_TRIG_SINGEDGECORNER2,
+  HP_TRIG_SINGCORNER,
+  HP_TRIG_SINGCORNER,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD,
+  HP_QUAD,
+  HP_NONE,
+};
+int refquad_1e_3vd_newels[][8] =
+{
+  { 7, 2, 6 },
+  { 3, 9, 8 },
+  { 4, 11, 10 },
+  { 1, 7, 6, 5 },
+  { 5, 6, 8, 11 },
+  { 11, 8, 9, 10 }
+};
+HPRef_Struct refquad_1e_3vd =
+{
+  HP_QUAD,
+  refquad_1e_3vd_splitedges, 
+  0, 0,
+  refquad_1e_3vd_newelstypes, 
+  refquad_1e_3vd_newels
+};
+
+
+
+
+
+
+// HP_QUAD_1E_4V
+int refquad_1e_4v_splitedges[][3] =
+{
+  { 1, 4, 5 },
+  { 2, 3, 6 },
+  { 1, 2, 7 },
+  { 2, 1, 8 },
+  { 4, 1, 9 },
+  { 3, 2, 10 },
+  { 4, 3, 11 },
+  { 3, 4, 12 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE refquad_1e_4v_newelstypes[] =
+{
+  HP_TRIG_SINGEDGECORNER1,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_TRIG_SINGCORNER,
+  HP_TRIG_SINGCORNER,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD,
+  HP_QUAD,
+  HP_NONE,
+};
+int refquad_1e_4v_newels[][8] =
+{
+  { 1, 7, 5 },
+  { 8, 2, 6 },
+  { 3, 12, 10 },
+  { 4, 9, 11 },
+  { 7, 8, 6, 5 },
+  { 5, 6, 10, 9 },
+  { 9, 10, 12, 11 }
+};
+HPRef_Struct refquad_1e_4v =
+{
+  HP_QUAD,
+  refquad_1e_4v_splitedges, 
+  0, 0,
+  refquad_1e_4v_newelstypes, 
+  refquad_1e_4v_newels
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+// HP_QUAD_2E
+int refquad_2e_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 4, 6 },
+  { 2, 3, 7 },
+  { 4, 3, 8 },
+  { 0, 0, 0 }
+};
+int refquad_2e_splitfaces[][4] =
+{
+  { 1, 2, 4, 9 },
+  { 0, 0, 0, 0 },
+};
+
+
+/* 
+   HPREF_ELEMENT_TYPE refquad_2e_newelstypes[] =
+{
+  HP_TRIG_SINGEDGECORNER1,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD,
+  HP_NONE,
+};
+int refquad_2e_newels[][8] =
+{
+  { 1, 5, 9 },
+  { 6, 1, 9 },
+  { 5, 2, 7, 9 },
+  { 4, 6, 9, 8 },
+  { 9, 7, 3, 8 },
+};
+*/ 
+
+// SZ refine to 4 quads 
+HPREF_ELEMENT_TYPE refquad_2e_newelstypes[] =
+{
+  HP_QUAD_2E,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD,
+  HP_NONE,
+};
+int refquad_2e_newels[][8] =
+{
+  { 1, 5, 9, 6 },
+  { 5, 2, 7, 9 },
+  { 4, 6, 9, 8 },
+  { 9, 7, 3, 8 },
+};
+
+HPRef_Struct refquad_2e =
+{
+  HP_QUAD,
+  refquad_2e_splitedges, 
+  refquad_2e_splitfaces, 
+  0,
+  refquad_2e_newelstypes, 
+  refquad_2e_newels
+};
+
+
+// HP_QUAD_2E_1VA
+int refquad_2e_1va_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 4, 6 },
+  { 2, 3, 7 },
+  { 4, 3, 8 },
+  { 2, 1, 10 },
+  { 0, 0, 0 }
+};
+int refquad_2e_1va_splitfaces[][4] =
+{
+  { 1, 2, 4, 9 },
+  { 0, 0, 0, 0 },
+};
+
+/* 
+HPREF_ELEMENT_TYPE refquad_2e_1va_newelstypes[] =
+{
+  HP_TRIG_SINGEDGECORNER1,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_NONE,
+};
+int refquad_2e_1va_newels[][8] =
+{
+  { 1, 5, 9 },
+  { 6, 1, 9 },
+  { 5, 10, 7, 9 },
+  { 4, 6, 9, 8 },
+  { 9, 7, 3, 8 },
+  { 10, 2, 7 },
+};
+*/ 
+// SZ Quad_2e refinement 
+HPREF_ELEMENT_TYPE refquad_2e_1va_newelstypes[] =
+{
+  HP_QUAD_2E,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_NONE,
+};
+int refquad_2e_1va_newels[][8] =
+{
+  { 1, 5, 9, 6 },
+  { 5, 10, 7, 9 },
+  { 4, 6, 9, 8 },
+  { 9, 7, 3, 8 },
+  { 10, 2, 7 },
+};
+
+HPRef_Struct refquad_2e_1va =
+{
+  HP_QUAD,
+  refquad_2e_1va_splitedges, 
+  refquad_2e_1va_splitfaces, 
+  0,
+  refquad_2e_1va_newelstypes, 
+  refquad_2e_1va_newels
+};
+
+
+
+// HP_QUAD_2E_1VB
+int refquad_2e_1vb_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 4, 6 },
+  { 2, 3, 7 },
+  { 4, 3, 8 },
+  { 3, 2, 10 },
+  { 3, 4, 11 },
+  { 0, 0, 0 }
+};
+int refquad_2e_1vb_splitfaces[][4] =
+{
+  { 1, 2, 4, 9 },
+  { 0, 0, 0, 0 },
+};
+HPREF_ELEMENT_TYPE refquad_2e_1vb_newelstypes[] =
+{
+  // HP_TRIG_SINGEDGECORNER1,
+  // HP_TRIG_SINGEDGECORNER2,
+  // SZ QUAD_2E 
+  HP_QUAD_2E,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+  HP_TRIG,
+  HP_QUAD,
+  HP_TRIG_SINGCORNER,
+  HP_NONE,
+};
+int refquad_2e_1vb_newels[][8] =
+{
+  //{ 1, 5, 9 },
+  //{ 6, 1, 9 },
+  { 1, 5, 9, 6 },
+  { 5, 2, 7, 9 },
+  { 4, 6, 9, 8 },
+  { 7, 8, 9 },
+  { 8, 7, 10, 11 },
+  { 3, 11, 10 }
+};
+HPRef_Struct refquad_2e_1vb =
+{
+  HP_QUAD,
+  refquad_2e_1vb_splitedges, 
+  refquad_2e_1vb_splitfaces, 
+  0,
+  refquad_2e_1vb_newelstypes, 
+  refquad_2e_1vb_newels
+}
+;
+
+// HP_QUAD_2E_1VC
+int refquad_2e_1vc_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 4, 6 },
+  { 2, 3, 7 },
+  { 4, 1, 8 },
+  { 4, 3, 9 },
+  { 0, 0, 0 }
+};
+int refquad_2e_1vc_splitfaces[][4] =
+{
+  { 1, 2, 4, 10 },
+  { 0, 0, 0, 0 },
+};
+HPREF_ELEMENT_TYPE refquad_2e_1vc_newelstypes[] =
+{
+  //  HP_TRIG_SINGEDGECORNER1,
+  // HP_TRIG_SINGEDGECORNER2,
+  HP_QUAD_2E, 
+  HP_TRIG_SINGEDGECORNER1,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD,
+  HP_NONE,
+};
+int refquad_2e_1vc_newels[][8] =
+{
+  //{ 1, 5, 10 },
+  //{ 6, 1, 10 },
+  { 1, 5, 10, 6}, 
+  { 4, 8, 9 },
+  { 5, 2, 7, 10 },
+  { 8, 6, 10, 9 },
+  { 10, 7, 3, 9 },
+};
+HPRef_Struct refquad_2e_1vc =
+{
+  HP_QUAD,
+  refquad_2e_1vc_splitedges, 
+  refquad_2e_1vc_splitfaces, 
+  0,
+  refquad_2e_1vc_newelstypes, 
+  refquad_2e_1vc_newels
+};
+
+// HP_QUAD_2E_2VA
+int refquad_2e_2va_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 4, 6 },
+  { 2, 3, 7 },
+  { 4, 3, 8 },
+  { 3, 2, 10 },
+  { 3, 4, 11 },
+  { 2, 1, 12 },
+  { 0, 0, 0 }
+};
+int refquad_2e_2va_splitfaces[][4] =
+{
+  { 1, 2, 4, 9 },
+  { 0, 0, 0, 0 },
+};
+HPREF_ELEMENT_TYPE refquad_2e_2va_newelstypes[] =
+{
+  //HP_TRIG_SINGEDGECORNER1,
+  //HP_TRIG_SINGEDGECORNER2,
+  HP_QUAD_2E,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+  HP_TRIG,
+  HP_QUAD,
+  HP_TRIG_SINGCORNER,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_NONE,
+};
+int refquad_2e_2va_newels[][8] =
+{
+  // { 1, 5, 9 },
+  // { 6, 1, 9 },
+  { 1, 5, 9, 6 }, 
+  { 5, 12, 7, 9 },
+  { 4, 6, 9, 8 },
+  { 7, 8, 9 },
+  { 8, 7, 10, 11 },
+  { 3, 11, 10 },
+  { 12, 2, 7 }
+};
+HPRef_Struct refquad_2e_2va =
+{
+  HP_QUAD,
+  refquad_2e_2va_splitedges, 
+  refquad_2e_2va_splitfaces, 
+  0,
+  refquad_2e_2va_newelstypes, 
+  refquad_2e_2va_newels
+};
+
+
+
+
+
+
+// HP_QUAD_2E_2VB
+int refquad_2e_2vb_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 4, 6 },
+  { 2, 1, 7 },
+  { 2, 3, 8 },
+  { 4, 1, 9 },
+  { 4, 3, 10 },
+  { 0, 0, 0 }
+};
+int refquad_2e_2vb_splitfaces[][4] =
+{
+  { 1, 2, 4, 11 },
+  { 0, 0, 0, 0 },
+};
+HPREF_ELEMENT_TYPE refquad_2e_2vb_newelstypes[] =
+{
+  // HP_TRIG_SINGEDGECORNER1,
+  // HP_TRIG_SINGEDGECORNER2,
+  HP_QUAD_2E, 
+  HP_TRIG_SINGEDGECORNER1,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD,
+  HP_NONE,
+};
+int refquad_2e_2vb_newels[][8] =
+{
+  //{ 1, 5, 11 },
+  //{ 6, 1, 11 },
+  { 1, 5, 11, 6 }, 
+  { 4, 9, 10 },
+  { 7, 2, 8 },
+  { 5, 7, 8, 11 },
+  { 9, 6, 11, 10 },
+  { 3, 10, 11, 8 },
+};
+HPRef_Struct refquad_2e_2vb =
+{
+  HP_QUAD,
+  refquad_2e_2vb_splitedges, 
+  refquad_2e_2vb_splitfaces, 
+  0,
+  refquad_2e_2vb_newelstypes, 
+  refquad_2e_2vb_newels
+};
+
+// HP_QUAD_2E_2VC
+int refquad_2e_2vc_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 4, 6 },
+  { 2, 3, 7 },
+  { 4, 3, 8 },
+  { 3, 2, 10 },
+  { 3, 4, 11 },
+  { 4, 1, 12 },
+  { 0, 0, 0 }
+};
+int refquad_2e_2vc_splitfaces[][4] =
+{
+  { 1, 2, 4, 9 },
+  { 0, 0, 0, 0 },
+};
+HPREF_ELEMENT_TYPE refquad_2e_2vc_newelstypes[] =
+{
+  // HP_TRIG_SINGEDGECORNER1,
+  // HP_TRIG_SINGEDGECORNER2,
+  HP_QUAD_2E, 
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+  HP_TRIG,
+  HP_QUAD,
+  HP_TRIG_SINGCORNER,
+  HP_TRIG_SINGEDGECORNER1, //SZ (vorher: SINGEDGECORNER2) 
+  HP_NONE,
+};
+int refquad_2e_2vc_newels[][8] =
+{
+  { 1, 5, 9 },
+  { 6, 1, 9 },
+  { 5, 2, 7, 9 },
+  { 12, 6, 9, 8 },
+  { 7, 8, 9 },
+  { 8, 7, 10, 11 },
+  { 3, 11, 10 },
+  { 4, 12, 8 }
+};
+HPRef_Struct refquad_2e_2vc =
+{
+  HP_QUAD,
+  refquad_2e_2vc_splitedges, 
+  refquad_2e_2vc_splitfaces, 
+  0,
+  refquad_2e_2vc_newelstypes, 
+  refquad_2e_2vc_newels
+};
+
+// HP_QUAD_2E_3V  
+int refquad_2e_3v_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 4, 6 },
+  { 2, 3, 7 },
+  { 4, 3, 8 },
+  { 3, 2, 10 },
+  { 3, 4, 11 },
+  { 2, 1, 12 },
+  { 4, 1, 13 },
+  { 0, 0, 0 }
+};
+int refquad_2e_3v_splitfaces[][4] =
+{
+  { 1, 2, 4, 9 },
+  { 0, 0, 0, 0 },
+};
+HPREF_ELEMENT_TYPE refquad_2e_3v_newelstypes[] =
+{
+  // HP_TRIG_SINGEDGECORNER1,
+  // HP_TRIG_SINGEDGECORNER2,
+  HP_QUAD_2E, 
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+  HP_TRIG,
+  HP_QUAD,
+  HP_TRIG_SINGCORNER,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_TRIG_SINGEDGECORNER1,
+  HP_NONE,
+};
+int refquad_2e_3v_newels[][8] =
+{
+  //{ 1, 5, 9 },
+  //{ 6, 1, 9 },
+  { 1, 5, 9, 6 }, 
+  { 5, 12, 7, 9 },
+  { 13, 6, 9, 8 },
+  { 7, 8, 9 },
+  { 8, 7, 10, 11 },
+  { 3, 11, 10 },
+  { 12, 2, 7 },
+  { 4, 13, 8 }
+};
+HPRef_Struct refquad_2e_3v =
+{
+  HP_QUAD,
+  refquad_2e_3v_splitedges, 
+  refquad_2e_3v_splitfaces, 
+  0,
+  refquad_2e_3v_newelstypes, 
+  refquad_2e_3v_newels
+};
+
+// HP_QUAD_2EB_0V
+int refquad_2eb_0v_splitedges[][3] =
+{
+  { 1, 4, 5 },
+  { 2, 3, 6 },
+  { 3, 2, 7 },
+  { 4, 1, 8 },
+  { 0, 0, 0 }
+};
+int refquad_2eb_0v_splitfaces[][4] =
+{
+  { 0, 0, 0, 0 },
+};
+HPREF_ELEMENT_TYPE refquad_2eb_0v_newelstypes[] =
+{
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD,
+  HP_NONE,
+};
+int refquad_2eb_0v_newels[][8] =
+{
+  { 1, 2, 6, 5 },
+  { 3, 4, 8, 7 },
+  { 5, 6, 7, 8 }
+};
+HPRef_Struct refquad_2eb_0v =
+{
+  HP_QUAD,
+  refquad_2eb_0v_splitedges, 
+  refquad_2eb_0v_splitfaces, 
+  0,
+  refquad_2eb_0v_newelstypes, 
+  refquad_2eb_0v_newels
+};
+
+
+// HP_QUAD_2EB_1VA
+int refquad_2eb_1va_splitedges[][3] =
+{
+  { 1, 4, 5 },
+  { 2, 3, 6 },
+  { 3, 2, 7 },
+  { 4, 1, 8 },
+  { 1, 2, 9 },
+  { 0, 0, 0 }
+};
+int refquad_2eb_1va_splitfaces[][4] =
+{
+  { 0, 0, 0, 0 },
+};
+HPREF_ELEMENT_TYPE refquad_2eb_1va_newelstypes[] =
+{
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+  HP_TRIG_SINGEDGECORNER1,
+  HP_QUAD,
+  HP_NONE,
+};
+int refquad_2eb_1va_newels[][8] =
+{
+  { 9, 2, 6, 5 },
+  { 3, 4, 8, 7 },
+  { 1, 9, 5 },
+  { 5, 6, 7, 8 }
+};
+HPRef_Struct refquad_2eb_1va =
+{
+  HP_QUAD,
+  refquad_2eb_1va_splitedges, 
+  refquad_2eb_1va_splitfaces, 
+  0,
+  refquad_2eb_1va_newelstypes, 
+  refquad_2eb_1va_newels
+};
+
+// HP_QUAD_2EB_1VB
+int refquad_2eb_1vb_splitedges[][3] =
+{
+  { 1, 4, 5 },
+  { 2, 3, 6 },
+  { 3, 2, 7 },
+  { 4, 1, 8 },
+  { 2, 1, 9 },
+  { 0, 0, 0 }
+};
+int refquad_2eb_1vb_splitfaces[][4] =
+{
+  { 0, 0, 0, 0 },
+};
+HPREF_ELEMENT_TYPE refquad_2eb_1vb_newelstypes[] =
+{
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_QUAD,
+  HP_NONE,
+};
+int refquad_2eb_1vb_newels[][8] =
+{
+  { 1, 9, 6, 5 },
+  { 3, 4, 8, 7 },
+  { 9, 2, 6 },
+  { 5, 6, 7, 8 }
+};
+HPRef_Struct refquad_2eb_1vb =
+{
+  HP_QUAD,
+  refquad_2eb_1vb_splitedges, 
+  refquad_2eb_1vb_splitfaces, 
+  0,
+  refquad_2eb_1vb_newelstypes, 
+  refquad_2eb_1vb_newels
+};
+
+// HP_QUAD_2EB_2VA
+int refquad_2eb_2va_splitedges[][3] =
+{
+  { 1, 4, 5 },
+  { 2, 3, 6 },
+  { 3, 2, 7 },
+  { 4, 1, 8 },
+  { 1, 2, 9 },
+  { 2, 1, 10 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE refquad_2eb_2va_newelstypes[] =
+{
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+  HP_TRIG_SINGEDGECORNER1,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_QUAD,
+  HP_NONE,
+};
+int refquad_2eb_2va_newels[][8] =
+{
+  { 9, 10, 6, 5 },
+  { 3, 4, 8, 7 },
+  { 1, 9, 5 },
+  { 10, 2, 6 },
+  { 5, 6, 7, 8 }
+};
+HPRef_Struct refquad_2eb_2va =
+{
+  HP_QUAD,
+  refquad_2eb_2va_splitedges, 
+  0, 0,
+  refquad_2eb_2va_newelstypes, 
+  refquad_2eb_2va_newels
+};
+
+
+
+// HP_QUAD_2EB_2VB
+int refquad_2eb_2vb_splitedges[][3] =
+{
+  { 1, 4, 5 },
+  { 2, 3, 6 },
+  { 3, 2, 7 },
+  { 4, 1, 8 },
+  { 1, 2, 9 },
+  { 3, 4, 10 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE refquad_2eb_2vb_newelstypes[] =
+{
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+  HP_TRIG_SINGEDGECORNER1,
+  HP_TRIG_SINGEDGECORNER1,
+  HP_QUAD,
+  HP_NONE,
+};
+int refquad_2eb_2vb_newels[][8] =
+{
+  { 9, 2, 6, 5 },
+  { 10, 4, 8, 7 },
+  { 1, 9, 5 },
+  { 3, 10, 7 },
+  { 5, 6, 7, 8 }
+};
+HPRef_Struct refquad_2eb_2vb =
+{
+  HP_QUAD,
+  refquad_2eb_2vb_splitedges, 
+  0, 0,
+  refquad_2eb_2vb_newelstypes, 
+  refquad_2eb_2vb_newels
+};
+
+
+
+// HP_QUAD_2EB_2VC
+int refquad_2eb_2vc_splitedges[][3] =
+{
+  { 1, 4, 5 },
+  { 2, 3, 6 },
+  { 3, 2, 7 },
+  { 4, 1, 8 },
+  { 1, 2, 9 },
+  { 4, 3, 10 },
+  { 0, 0, 0 }
+};
+int refquad_2eb_2vc_splitfaces[][4] =
+{
+  { 0, 0, 0, 0 },
+};
+HPREF_ELEMENT_TYPE refquad_2eb_2vc_newelstypes[] =
+{
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+  HP_TRIG_SINGEDGECORNER1,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_QUAD,
+  HP_NONE,
+};
+int refquad_2eb_2vc_newels[][8] =
+{
+  { 9, 2, 6, 5 },
+  { 3, 10, 8, 7 },
+  { 1, 9, 5 },
+  { 10, 4, 8 },
+  { 5, 6, 7, 8 }
+};
+HPRef_Struct refquad_2eb_2vc =
+{
+  HP_QUAD,
+  refquad_2eb_2vc_splitedges, 
+  refquad_2eb_2vc_splitfaces, 
+  0,
+  refquad_2eb_2vc_newelstypes, 
+  refquad_2eb_2vc_newels
+};
+
+
+// HP_QUAD_2EB_2VD
+int refquad_2eb_2vd_splitedges[][3] =
+{
+  { 1, 4, 5 },
+  { 2, 3, 6 },
+  { 3, 2, 7 },
+  { 4, 1, 8 },
+  { 2, 1, 9 },
+  { 4, 3, 10 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE refquad_2eb_2vd_newelstypes[] =
+{
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_QUAD,
+  HP_NONE,
+};
+int refquad_2eb_2vd_newels[][8] =
+{
+  { 1, 9, 6, 5 },
+  { 3, 10, 8, 7 },
+  { 9, 2, 6 },
+  { 10, 4, 8 },
+  { 5, 6, 7, 8 }
+};
+HPRef_Struct refquad_2eb_2vd =
+{
+  HP_QUAD,
+  refquad_2eb_2vd_splitedges, 
+  0, 0,
+  refquad_2eb_2vd_newelstypes, 
+  refquad_2eb_2vd_newels
+};
+
+
+// HP_QUAD_2EB_3VA
+int refquad_2eb_3va_splitedges[][3] =
+{
+  { 1, 4, 5 },
+  { 2, 3, 6 },
+  { 1, 2, 7 },
+  { 2, 1, 8 },
+  { 3, 2, 9 },
+  { 4, 1, 10 },
+  { 3, 4, 11 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE refquad_2eb_3va_newelstypes[] =
+{
+  HP_TRIG_SINGEDGECORNER1,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_TRIG_SINGEDGECORNER1,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD,
+  HP_NONE,
+};
+int refquad_2eb_3va_newels[][8] =
+{
+  { 1, 7, 5 },
+  { 8, 2, 6 },
+  { 3, 11, 9},
+  { 7, 8, 6, 5 },
+  { 11, 4, 10, 9 },
+  { 5, 6, 9, 10 }
+};
+HPRef_Struct refquad_2eb_3va =
+{
+  HP_QUAD,
+  refquad_2eb_3va_splitedges, 
+  0, 0,
+  refquad_2eb_3va_newelstypes, 
+  refquad_2eb_3va_newels
+};
+
+
+// HP_QUAD_2EB_3VB
+int refquad_2eb_3vb_splitedges[][3] =
+{
+  { 1, 4, 5 },
+  { 2, 3, 6 },
+  { 1, 2, 7 },
+  { 2, 1, 8 },
+  { 3, 2, 9 },
+  { 4, 1, 10 },
+  { 4, 3, 11 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE refquad_2eb_3vb_newelstypes[] =
+{
+  HP_TRIG_SINGEDGECORNER1,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD,
+  HP_NONE,
+};
+int refquad_2eb_3vb_newels[][8] =
+{
+  { 1, 7, 5 },
+  { 8, 2, 6 },
+  { 11, 4, 10 },
+  { 7, 8, 6, 5 },
+  { 3, 11, 10, 9 },
+  { 5, 6, 9, 10 }
+};
+HPRef_Struct refquad_2eb_3vb =
+{
+  HP_QUAD,
+  refquad_2eb_3vb_splitedges, 
+  0, 0,
+  refquad_2eb_3vb_newelstypes, 
+  refquad_2eb_3vb_newels
+};
+
+
+// HP_QUAD_2EB_4V
+int refquad_2eb_4v_splitedges[][3] =
+{
+  { 1, 4, 5 },
+  { 2, 3, 6 },
+  { 3, 2, 7 },
+  { 4, 1, 8 },
+  { 1, 2, 9 },
+  { 2, 1, 10 },
+  { 3, 4, 11 },
+  { 4, 3, 12 },
+  { 0, 0, 0 }
+};
+int refquad_2eb_4v_splitfaces[][4] =
+{
+  { 0, 0, 0, 0 },
+};
+HPREF_ELEMENT_TYPE refquad_2eb_4v_newelstypes[] =
+{
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD,
+  HP_TRIG_SINGEDGECORNER1,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_TRIG_SINGEDGECORNER1,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_NONE,
+};
+int refquad_2eb_4v_newels[][8] =
+{
+  { 9, 10, 6, 5 },
+  { 11, 12, 8, 7 },
+  { 5, 6, 7, 8 },
+  { 1, 9, 5 },
+  { 10, 2, 6 },
+  { 3, 11, 7 },
+  { 12, 4, 8 },
+};
+HPRef_Struct refquad_2eb_4v =
+{
+  HP_QUAD,
+  refquad_2eb_4v_splitedges, 
+  refquad_2eb_4v_splitfaces, 
+  0,
+  refquad_2eb_4v_newelstypes, 
+  refquad_2eb_4v_newels
+};
+
+
+
+// HP_QUAD_3E
+int refquad_3e_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 4, 6 },
+  { 2, 1, 7 },
+  { 2, 3, 8 },
+  { 3, 4, 10 },
+  { 4, 3, 12 },
+  { 0, 0, 0 }
+};
+
+int refquad_3e_splitfaces[][4] =
+{
+  { 1, 2, 4, 13 },
+  { 2, 3, 1, 14 },
+  { 0, 0, 0, 0 },
+};
+
+HPREF_ELEMENT_TYPE refquad_3e_newelstypes[] =
+{
+  HP_QUAD_2E,
+  HP_QUAD_2E,
+//   HP_TRIG_SINGEDGECORNER1,
+//   HP_TRIG_SINGEDGECORNER2,
+//   HP_TRIG_SINGEDGECORNER2,
+//   HP_TRIG_SINGEDGECORNER1,
+
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+
+  HP_QUAD,
+  HP_NONE,
+};
+int refquad_3e_newels[][8] =
+{
+//   { 1, 5, 13 },
+//   { 6, 1, 13 },
+//   { 7, 2, 14 },
+//   { 2, 8, 14 },
+  { 1, 5, 13, 6 },
+  { 2, 8, 14, 7 },
+  { 5, 7, 14, 13 },
+  { 8, 3, 10, 14 },
+  { 4, 6, 13, 12 },
+  { 13, 14, 10, 12 }
+};
+HPRef_Struct refquad_3e =
+{
+  HP_QUAD,
+  refquad_3e_splitedges, 
+  refquad_3e_splitfaces, 
+  0,
+  refquad_3e_newelstypes, 
+  refquad_3e_newels
+};
+
+
+
+
+
+
+
+// HP_QUAD_3E_3VA
+int refquad_3e_3va_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 4, 6 },
+  { 2, 1, 7 },
+  { 2, 3, 8 },
+  { 3, 4, 10 },
+  { 3, 2, 11 },
+  { 4, 3, 12 },
+  { 0, 0, 0 }
+};
+
+int refquad_3e_3va_splitfaces[][4] =
+{
+  { 1, 2, 4, 13 },
+  { 2, 3, 1, 14 },
+  { 0, 0, 0, 0 },
+};
+
+HPREF_ELEMENT_TYPE refquad_3e_3va_newelstypes[] =
+{
+  HP_QUAD_2E,
+  HP_QUAD_2E,
+
+//   HP_TRIG_SINGEDGECORNER1,
+//   HP_TRIG_SINGEDGECORNER2,
+//   HP_TRIG_SINGEDGECORNER2,
+//   HP_TRIG_SINGEDGECORNER1,
+  HP_TRIG_SINGEDGECORNER2,
+
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+
+  HP_QUAD,
+  HP_NONE,
+};
+int refquad_3e_3va_newels[][8] =
+{
+//   { 1, 5, 13 },
+//   { 6, 1, 13 },
+//   { 7, 2, 14 },
+//   { 2, 8, 14 },
+  { 1, 5, 13, 6 },
+  { 2, 8, 14, 7 },
+  { 11, 3, 10 },
+  { 5, 7, 14, 13 },
+  { 8, 11, 10, 14 },
+  { 4, 6, 13, 12 },
+  { 13, 14, 10, 12 }
+};
+HPRef_Struct refquad_3e_3va =
+{
+  HP_QUAD,
+  refquad_3e_3va_splitedges, 
+  refquad_3e_3va_splitfaces, 
+  0,
+  refquad_3e_3va_newelstypes, 
+  refquad_3e_3va_newels
+};
+
+// HP_QUAD_3E_3VB
+int refquad_3e_3vb_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 4, 6 },
+  { 2, 1, 7 },
+  { 2, 3, 8 },
+  { 3, 4, 10 },
+  { 4, 1, 11 },
+  { 4, 3, 12 },
+  { 0, 0, 0 }
+};
+
+int refquad_3e_3vb_splitfaces[][4] =
+{
+  { 1, 2, 4, 13 },
+  { 2, 3, 1, 14 },
+  { 0, 0, 0, 0 },
+};
+
+HPREF_ELEMENT_TYPE refquad_3e_3vb_newelstypes[] =
+{
+  HP_QUAD_2E,
+  HP_QUAD_2E,
+
+//   HP_TRIG_SINGEDGECORNER1,
+//   HP_TRIG_SINGEDGECORNER2,
+//   HP_TRIG_SINGEDGECORNER2,
+//   HP_TRIG_SINGEDGECORNER1,
+  HP_TRIG_SINGEDGECORNER1,
+
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+
+  HP_QUAD,
+  HP_NONE,
+};
+int refquad_3e_3vb_newels[][8] =
+{
+//   { 1, 5, 13 },
+//   { 6, 1, 13 },
+//   { 7, 2, 14 },
+//   { 2, 8, 14 },
+  { 1, 5, 13, 6 },
+  { 2, 8, 14, 7 },
+  { 4, 11, 12 },
+  { 5, 7, 14, 13 },
+  { 8, 3, 10, 14 },
+  { 11, 6, 13, 12 },
+  { 13, 14, 10, 12 }
+};
+HPRef_Struct refquad_3e_3vb =
+{
+  HP_QUAD,
+  refquad_3e_3vb_splitedges, 
+  refquad_3e_3vb_splitfaces, 
+  0,
+  refquad_3e_3vb_newelstypes, 
+  refquad_3e_3vb_newels
+};
+
+
+
+
+
+
+
+
+
+// HP_QUAD_3E_4V
+int refquad_3e_4v_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 4, 6 },
+  { 2, 1, 7 },
+  { 2, 3, 8 },
+  { 3, 4, 10 },
+  { 3, 2, 11 },
+  { 4, 3, 12 },
+  { 4, 1, 15 },
+  { 0, 0, 0 }
+};
+
+int refquad_3e_4v_splitfaces[][4] =
+{
+  { 1, 2, 4, 13 },
+  { 2, 3, 1, 14 },
+  { 0, 0, 0, 0 },
+};
+
+HPREF_ELEMENT_TYPE refquad_3e_4v_newelstypes[] =
+{
+  HP_QUAD_2E,
+  HP_QUAD_2E,
+
+//   HP_TRIG_SINGEDGECORNER1,
+//   HP_TRIG_SINGEDGECORNER2,
+//   HP_TRIG_SINGEDGECORNER2,
+//   HP_TRIG_SINGEDGECORNER1,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_TRIG_SINGEDGECORNER1,
+
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+
+  HP_QUAD,
+  HP_NONE,
+};
+int refquad_3e_4v_newels[][8] =
+{
+//   { 1, 5, 13 },
+//   { 6, 1, 13 },
+//   { 7, 2, 14 },
+//   { 2, 8, 14 },
+  { 1, 5, 13, 6 },
+  { 2, 8, 14, 7 },
+  { 11, 3, 10 },
+  { 4, 15, 12 },
+  { 5, 7, 14, 13 },
+  { 8, 11, 10, 14 },
+  { 15, 6, 13, 12 },
+  { 13, 14, 10, 12 }
+};
+HPRef_Struct refquad_3e_4v =
+{
+  HP_QUAD,
+  refquad_3e_4v_splitedges, 
+  refquad_3e_4v_splitfaces, 
+  0,
+  refquad_3e_4v_newelstypes, 
+  refquad_3e_4v_newels
+};
+
+
+
+
+
+
+
+
+
+// HP_QUAD_4E
+int refquad_4e_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 4, 6 },
+  { 2, 1, 7 },
+  { 2, 3, 8 },
+  { 3, 2, 9 },
+  { 3, 4, 10 },
+  { 4, 1, 11 },
+  { 4, 3, 12 },
+  { 0, 0, 0 }
+};
+
+int refquad_4e_splitfaces[][4] =
+{
+  { 1, 2, 4, 13 },
+  { 2, 3, 1, 14 },
+  { 3, 4, 2, 15 },
+  { 4, 1, 3, 16 },
+  { 0, 0, 0, 0 },
+};
+
+HPREF_ELEMENT_TYPE refquad_4e_newelstypes[] =
+{
+  HP_QUAD_2E,
+  HP_QUAD_2E,
+  HP_QUAD_2E,
+  HP_QUAD_2E,
+
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+
+  HP_QUAD,
+  HP_NONE,
+};
+int refquad_4e_newels[][8] =
+{
+  { 1, 5, 13, 6 },
+  { 2, 8, 14, 7 },
+  { 3, 10, 15, 9 },
+  { 4, 11, 16, 12 },
+  { 5, 7, 14, 13 },
+  { 8, 9, 15, 14 },
+  { 10, 12, 16, 15 },
+  { 11, 6, 13, 16 },
+  { 13, 14, 15, 16 }
+};
+HPRef_Struct refquad_4e =
+{
+  HP_QUAD,
+  refquad_4e_splitedges, 
+  refquad_4e_splitfaces, 
+  0,
+  refquad_4e_newelstypes, 
+  refquad_4e_newels
+};
diff --git a/contrib/Netgen/libsrc/meshing/hpref_segm.hpp b/contrib/Netgen/libsrc/meshing/hpref_segm.hpp
new file mode 100644
index 0000000000..2544582321
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/hpref_segm.hpp
@@ -0,0 +1,122 @@
+  // HP_SEGM
+  int refsegm_splitedges[][3] =
+    {
+      { 0, 0, 0 }
+    };
+  
+  HPREF_ELEMENT_TYPE refsegm_newelstypes[] =
+    {
+      HP_SEGM,
+      HP_NONE,
+    };
+  int refsegm_newels[][8] =
+    {
+      { 1, 2 },
+    };
+  HPRef_Struct refsegm =
+    {
+      HP_SEGM, 
+      refsegm_splitedges, 
+      0, 0, 
+      refsegm_newelstypes, 
+      refsegm_newels
+    };
+
+  // HP_SEGM_SINGCORNERL = 2,
+  int refsegm_scl_splitedges[][3] =
+    {
+      { 1, 2, 3 }, 
+      { 0, 0, 0 }
+    };
+  
+  HPREF_ELEMENT_TYPE refsegm_scl_newelstypes[] = 
+    {
+      HP_SEGM_SINGCORNERL,
+      HP_SEGM,
+      HP_NONE,
+    };
+  
+  int refsegm_scl_newels[][8] =
+    {
+      { 1, 3 },
+      { 3, 2 },
+      { 0, 0 },
+    };
+  HPRef_Struct refsegm_scl =
+    {
+      HP_SEGM,
+      refsegm_scl_splitedges,
+      0, 0,
+      refsegm_scl_newelstypes,
+      refsegm_scl_newels
+    };
+
+
+
+  // HP_SEGM_SINGCORNERR
+  int refsegm_scr_splitedges[][3] =
+    {
+      { 2, 1, 3 },
+      { 0, 0, 0 }
+    };
+
+  HPREF_ELEMENT_TYPE refsegm_scr_newelstypes[] =
+    {
+      HP_SEGM,
+      HP_SEGM_SINGCORNERR,
+      HP_NONE,
+    };
+  int refsegm_scr_newels[][8] =
+    {
+      { 1, 3 },
+      { 3, 2 },
+      { 0, 0 },
+    };
+  HPRef_Struct refsegm_scr =
+    {
+      HP_SEGM,
+      refsegm_scr_splitedges,
+      0, 0,
+      refsegm_scr_newelstypes,
+      refsegm_scr_newels
+    };
+
+
+
+
+
+
+  // HP_SEGM_SINGCORNERS = 3,
+  int refsegm_sc2_splitedges[][3] =
+    {
+      { 1, 2, 3 },
+      { 2, 1, 4 },
+      { 0, 0, 0 }
+    };
+
+  HPREF_ELEMENT_TYPE refsegm_sc2_newelstypes[] =
+    {
+      HP_SEGM_SINGCORNERL,
+      HP_SEGM_SINGCORNERR,
+      HP_SEGM,
+      HP_NONE,
+    };
+  int refsegm_sc2_newels[][8] =
+    {
+      { 1, 3 },
+      { 4, 2 },
+      { 3, 4 },
+      { 0, 0 },
+    };
+  HPRef_Struct refsegm_sc2 =
+    {  
+      HP_SEGM,
+      refsegm_sc2_splitedges,
+      0, 0, 
+      refsegm_sc2_newelstypes,
+      refsegm_sc2_newels
+    };
+
+
+
+
diff --git a/contrib/Netgen/libsrc/meshing/hpref_tet.hpp b/contrib/Netgen/libsrc/meshing/hpref_tet.hpp
new file mode 100644
index 0000000000..df0e2af890
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/hpref_tet.hpp
@@ -0,0 +1,3128 @@
+
+ 
+
+// 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_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 },
+  { 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_1E_2VD,  // 1 v on edge
+int reftet_1e_2vd_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_1e_2vd_splitfaces[][4] =
+  {
+    { 1, 3, 4, 19 },
+    { 2, 3, 4, 22 },
+    { 3, 1, 4, 24 },
+    { 3, 2, 4, 25 },
+    { 4, 1, 3, 27 },
+    { 4, 2, 3, 28 },
+    { 0, 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_PYRAMID,
+    HP_HEX,
+    HP_PYRAMID,
+    HP_PRISM,
+    HP_PRISM,
+    HP_NONE,
+  };
+int reftet_1e_2vd_newels[][8] =
+{
+  { 1, 6, 7, 2, 9, 10 },
+  { 3, 11, 12, 13 },
+  { 4, 16, 15, 14 },
+  { 7, 6, 19, 10, 9, 22 },
+  { 7, 19, 27, 14, 10, 22, 28, 15 },
+  { 14, 15, 28, 27, 16 },
+  { 9, 6, 19, 22, 12, 11, 24, 25 },
+  { 12, 11, 24, 25, 13 },
+  { 19, 24, 27, 22, 25, 28 },
+  { 16, 28, 27, 13, 25, 24 }
+};
+HPRef_Struct reftet_1e_2vd =
+{
+  HP_TET,
+  reftet_1e_2vd_splitedges, 
+  reftet_1e_2vd_splitfaces, 
+  0,
+  reftet_1e_2vd_newelstypes, 
+  reftet_1e_2vd_newels
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+// HP_TET_1E_3VA
+int reftet_1e_3va_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_1e_3va_splitelements[][5] =
+{
+  { 1, 2, 3, 4, 14 },
+  { 0 }
+};
+
+HPREF_ELEMENT_TYPE reftet_1e_3va_newelstypes[] =
+{
+  HP_PRISM_SINGEDGE,
+  HP_TET_1E_1VA,
+  HP_TET_1E_1VA,
+  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_3va_newels[][8] =
+{
+  { 5, 6, 7, 8, 9, 10 },
+  { 1, 5, 6, 7 },
+  { 2, 8, 10, 9 },
+  { 3, 11, 12, 13 },
+
+  { 6, 7, 10, 9, 14 },
+  { 4, 10, 7, 14 },
+  { 9, 10, 13, 12, 14 },
+  { 4, 13, 10, 14 },
+  { 6, 11, 13, 7, 14 },
+  { 4, 7, 13, 14 },
+  { 6, 11, 12, 9, 14 },
+  { 11, 13, 12, 14 },
+};
+
+HPRef_Struct reftet_1e_3va =
+{
+  HP_TET,
+  reftet_1e_3va_splitedges, 
+  0,
+  reftet_1e_3va_splitelements, 
+  reftet_1e_3va_newelstypes, 
+  reftet_1e_3va_newels
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+//  HP_TET_1E_3VB,  // 1 v on edge
+int reftet_1e_3vb_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_1e_3vb_splitfaces[][4] =
+  {
+    { 1, 3, 4, 19 },
+    { 2, 3, 4, 22 },
+    { 3, 1, 4, 24 },
+    { 3, 2, 4, 25 },
+    { 4, 1, 3, 27 },
+    { 4, 2, 3, 28 },
+    { 0, 0, 0, 0 }
+  };
+HPREF_ELEMENT_TYPE reftet_1e_3vb_newelstypes[] =
+  {
+    HP_TET_1E_1VA,
+    HP_PRISM_SINGEDGE,
+    HP_TET_0E_1V,
+    HP_TET_0E_1V,
+    HP_PRISM,
+    HP_HEX,
+    HP_PYRAMID,
+    HP_HEX,
+    HP_PYRAMID,
+    HP_PRISM,
+    HP_PRISM,
+    HP_NONE,
+  };
+int reftet_1e_3vb_newels[][8] =
+{
+  { 1, 5, 6, 7 },
+  { 5, 6, 7, 2, 9, 10 },
+  { 3, 11, 12, 13 },
+  { 4, 16, 15, 14 },
+  { 7, 6, 19, 10, 9, 22 },
+  { 7, 19, 27, 14, 10, 22, 28, 15 },
+  { 14, 15, 28, 27, 16 },
+  { 9, 6, 19, 22, 12, 11, 24, 25 },
+  { 12, 11, 24, 25, 13 },
+  { 19, 24, 27, 22, 25, 28 },
+  { 16, 28, 27, 13, 25, 24 }
+};
+HPRef_Struct reftet_1e_3vb =
+{
+  HP_TET,
+  reftet_1e_3vb_splitedges, 
+  reftet_1e_3vb_splitfaces, 
+  0,
+  reftet_1e_3vb_newelstypes, 
+  reftet_1e_3vb_newels
+};
+
+
+
+
+
+
+/*
+// HP_TET_1E_4V
+int reftet_1e_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_1e_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_1e_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_1e_4v_newelstypes[] =
+{
+  HP_HEX_1E_1V,
+  HP_HEX_1E_1V,
+  HP_HEX_0E_1V,
+  HP_HEX_0E_1V,
+  HP_PRISM_SINGEDGE, 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_PRISM,
+  HP_PRISM,
+  HP_PRISM,
+  HP_TET,
+  HP_NONE,
+};
+int reftet_1e_4v_newels[][8] =
+{
+  { 1, 5, 17, 6, 7, 18, 29, 19 },
+  //  { 2, 9, 20, 8, 10, 22, 30, 21 },
+  { 2, 8, 21, 10, 9, 20, 30, 22 },
+  { 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 },
+  { 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_1e_4v =
+{
+  HP_TET,
+  reftet_1e_4v_splitedges, 
+  reftet_1e_4v_splitfaces, 
+  reftet_1e_4v_splitelements, 
+  reftet_1e_4v_newelstypes, 
+  reftet_1e_4v_newels
+};
+*/
+
+
+
+
+// HP_TET_1E_4V
+int reftet_1e_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_1e_4v_splitfaces[][4] =
+  {
+    { 1, 3, 4, 17 },
+    { 2, 3, 4, 18 },
+
+    { 3, 1, 4, 19 },
+    { 3, 2, 4, 20 },
+
+    { 4, 1, 3, 21 },
+    { 4, 2, 3, 22 },
+    { 0, 0, 0, 0 },
+  };
+
+HPREF_ELEMENT_TYPE reftet_1e_4v_newelstypes[] =
+{
+  HP_TET_1E_1VA,
+  HP_TET_1E_1VA,
+  //  HP_TET_1E_1VA,
+  //  HP_TET_1E_1VA,
+  HP_PRISM_SINGEDGE,
+  HP_PRISM,
+  HP_HEX, 
+  HP_HEX, 
+  HP_PRISM,
+  HP_PRISM,
+
+  HP_PYRAMID,
+  HP_TET_0E_1V,
+
+  HP_PYRAMID,
+  HP_TET_0E_1V,
+
+  HP_NONE,
+};
+
+int reftet_1e_4v_newels[][8] =
+{
+  { 1, 5, 6, 7 },
+  { 2, 8, 10, 9 },
+
+  { 5, 6, 7, 8, 9, 10 },
+  { 7, 6, 17, 10, 9, 18 },
+
+  { 7, 10, 18, 17, 14, 15, 22, 21 },
+  { 9, 6, 17, 18, 12, 11, 19, 20 },
+
+  { 17, 19, 21, 18, 20, 22 },
+  { 16, 22, 21, 13, 20, 19 },
+
+  { 14, 15, 22, 21, 16 },
+  { 4, 14, 16, 15 },
+  { 12, 11, 19, 20, 13 },
+  { 3, 11, 12, 13 },
+
+
+
+  { 1, 5, 17, 6, 7, 18, 29, 19 },
+  //  { 2, 9, 20, 8, 10, 22, 30, 21 },
+  { 2, 8, 21, 10, 9, 20, 30, 22 },
+  { 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 },
+  { 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_1e_4v =
+{
+  HP_TET,
+  reftet_1e_4v_splitedges, 
+  reftet_1e_4v_splitfaces, 
+  0, 
+  reftet_1e_4v_newelstypes, 
+  reftet_1e_4v_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_1VA,  // 2 edges connected
+int reftet_2ea_1va_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 3, 6 },
+  { 1, 4, 7 },
+  { 2, 1, 8 },
+  { 2, 3, 9 },
+  { 2, 4, 10 },
+  { 3, 2, 12 },
+  { 3, 4, 13 },
+  { 0, 0, 0 }
+};
+int reftet_2ea_1va_splitfaces[][4] =
+  {
+    { 1, 2, 3, 17 },
+    { 0, 0, 0, 0 }
+  };
+HPREF_ELEMENT_TYPE reftet_2ea_1va_newelstypes[] =
+  {
+    HP_PYRAMID_EDGES,
+    HP_PRISM_SINGEDGE,
+    HP_TET_1E_1VA,
+    HP_PRISM_SINGEDGE,
+    HP_PRISM,
+    HP_TET,
+    HP_NONE,
+  };
+int reftet_2ea_1va_newels[][8] =
+{
+  { 1, 5, 17, 6, 7 },
+  { 5, 17, 7, 8, 9, 10 },
+  { 2, 8, 10, 9 },
+  { 6, 7, 17, 3, 13, 12 },
+  { 17, 9, 12, 7, 10, 13 },
+  { 7, 10, 13, 4 },
+};
+HPRef_Struct reftet_2ea_1va =
+{
+  HP_TET,
+  reftet_2ea_1va_splitedges, 
+  reftet_2ea_1va_splitfaces, 
+  0,
+  reftet_2ea_1va_newelstypes, 
+  reftet_2ea_1va_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_1VC,  // 2 edges connected
+int reftet_2ea_1vc_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_1vc_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_1vc_splitelements[][5] =
+  {
+    { 1, 2, 3, 4, 21 },
+    { 0, 0, 0, 0 }
+  };
+HPREF_ELEMENT_TYPE reftet_2ea_1vc_newelstypes[] =
+  {
+    HP_PYRAMID_EDGES,
+    //    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_1vc_newels[][8] =
+{
+  { 1, 5, 17, 6, 7 },
+  // { 3, 11, 12, 13 },
+  { 4, 15, 14, 16 }, 
+  { 5, 17, 7, 2, 9, 10 },
+  { 6, 7, 17, 3, 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_1vc =
+{
+  HP_TET,
+  reftet_2ea_1vc_splitedges, 
+  reftet_2ea_1vc_splitfaces, 
+  reftet_2ea_1vc_splitelements, 
+  reftet_2ea_1vc_newelstypes, 
+  reftet_2ea_1vc_newels
+};
+
+
+
+
+
+
+
+
+
+
+
+ 
+//  HP_TET_2EA_2VA, 
+int reftet_2ea_2va_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_2ea_2va_splitfaces[][4] =
+  {
+    { 1, 2, 3, 17 },
+    { 0, 0, 0, 0 }
+  };
+HPREF_ELEMENT_TYPE reftet_2ea_2va_newelstypes[] =
+  {
+    HP_PYRAMID_EDGES,
+    HP_TET_1E_1VA,
+    HP_TET_1E_1VA,
+    HP_PRISM_SINGEDGE,
+    HP_PRISM_SINGEDGE,
+    HP_PRISM,
+    HP_TET,
+    HP_NONE,
+  };
+int reftet_2ea_2va_newels[][8] =
+{
+  { 1, 5, 17, 6, 7 },
+  { 3, 11, 12, 13 },
+  { 2, 8, 10, 9 },
+  { 5, 17, 7, 8, 9, 10 },
+  { 6, 7, 17, 11, 13, 12 },
+  { 17, 9, 12, 7, 10, 13 },
+  { 7, 10, 13, 4 },
+};
+HPRef_Struct reftet_2ea_2va =
+{
+  HP_TET,
+  reftet_2ea_2va_splitedges, 
+  reftet_2ea_2va_splitfaces, 
+  0,
+  reftet_2ea_2va_newelstypes, 
+  reftet_2ea_2va_newels
+};
+
+
+
+
+
+
+
+
+
+
+
+//  HP_TET_2EA_2VB,  // 2 edges connected
+int reftet_2ea_2vb_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_2vb_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_2vb_splitelements[][5] =
+  {
+    { 1, 2, 3, 4, 21 },
+    { 0, 0, 0, 0 }
+  };
+HPREF_ELEMENT_TYPE reftet_2ea_2vb_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_2vb_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, 3, 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_2vb =
+{
+  HP_TET,
+  reftet_2ea_2vb_splitedges, 
+  reftet_2ea_2vb_splitfaces, 
+  reftet_2ea_2vb_splitelements, 
+  reftet_2ea_2vb_newelstypes, 
+  reftet_2ea_2vb_newels
+};
+
+
+
+
+
+
+
+ 
+
+
+//  HP_TET_2EA_2VC,  // 2 edges connected
+int reftet_2ea_2vc_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_2vc_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_2vc_splitelements[][5] =
+  {
+    { 1, 2, 3, 4, 21 },
+    { 0, 0, 0, 0 }
+  };
+HPREF_ELEMENT_TYPE reftet_2ea_2vc_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_2vc_newels[][8] =
+{
+  { 1, 5, 17, 6, 7 },
+  //  { 2, 8, 10, 9 },
+  { 3, 11, 12, 13 },
+  { 4, 15, 14, 16 }, 
+  { 5, 17, 7, 2, 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_2vc =
+{
+  HP_TET,
+  reftet_2ea_2vc_splitedges, 
+  reftet_2ea_2vc_splitfaces, 
+  reftet_2ea_2vc_splitelements, 
+  reftet_2ea_2vc_newelstypes, 
+  reftet_2ea_2vc_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_0V,  // 2 opposite edges
+int reftet_2eb_0v_splitedges[][3] =
+{
+  { 1, 3, 5 },
+  { 1, 4, 6 },
+  { 2, 3, 7 },
+  { 2, 4, 8 },
+  { 3, 1, 9 },
+  { 3, 2, 10 },
+  { 4, 1, 11 },
+  { 4, 2, 12 },
+  { 0, 0, 0 }
+};
+
+HPREF_ELEMENT_TYPE reftet_2eb_0v_newelstypes[] =
+  {
+    HP_PRISM_SINGEDGE,
+    HP_PRISM_SINGEDGE,
+    HP_HEX,
+    HP_NONE,
+  };
+int reftet_2eb_0v_newels[][8] =
+{
+  { 1, 5, 6, 2, 7, 8 },
+  { 3, 9, 10, 4, 11, 12 },
+  { 6, 11, 12, 8, 5, 9, 10, 7 },
+};
+HPRef_Struct reftet_2eb_0v =
+{
+  HP_TET,
+  reftet_2eb_0v_splitedges, 
+  0, 0,
+  reftet_2eb_0v_newelstypes, 
+  reftet_2eb_0v_newels
+};
+
+
+//  HP_TET_2EB_1V,    // V1
+
+
+//  HP_TET_2EB_1V,  // 2 opposite edges, V1
+int reftet_2eb_1v_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_1v_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_1v_newels[][8] =
+{
+  { 5, 6, 7, 2, 9, 10 },
+  { 4, 15, 14, 3, 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_1v =
+{
+  HP_TET,
+  reftet_2eb_1v_splitedges, 
+  0, 0,
+  reftet_2eb_1v_newelstypes, 
+  reftet_2eb_1v_newels
+};
+
+
+
+//  HP_TET_2EB_2VA,  // 2 opposite edges, V1,2
+int reftet_2eb_2va_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_2va_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_2va_newels[][8] =
+{
+  { 5, 6, 7, 8, 9, 10 },
+  { 4, 15, 14, 3, 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_2va =
+{
+  HP_TET,
+  reftet_2eb_2va_splitedges, 
+  0, 0,
+  reftet_2eb_2va_newelstypes, 
+  reftet_2eb_2va_newels
+};
+
+
+//  HP_TET_2EB_2VB,   // V1,3
+int reftet_2eb_2vb_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_2vb_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_2vb_newels[][8] =
+{
+  { 5, 6, 7, 2, 9, 10 },
+  { 4, 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_2vb =
+{
+  HP_TET,
+  reftet_2eb_2vb_splitedges, 
+  0, 0,
+  reftet_2eb_2vb_newelstypes, 
+  reftet_2eb_2vb_newels
+};
+
+
+
+
+//  HP_TET_2EB_2VC,   // V1,4
+int reftet_2eb_2vc_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_2vc_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_2vc_newels[][8] =
+{
+  { 5, 6, 7, 2, 9, 10 },
+  { 16, 15, 14, 3, 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_2vc =
+{
+  HP_TET,
+  reftet_2eb_2vc_splitedges, 
+  0, 0,
+  reftet_2eb_2vc_newelstypes, 
+  reftet_2eb_2vc_newels
+};
+
+
+
+
+
+
+//  HP_TET_2EB_3V,    // V1,2,3
+int reftet_2eb_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 }
+};
+
+HPREF_ELEMENT_TYPE reftet_2eb_3v_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_3v_newels[][8] =
+{
+  { 5, 6, 7, 8, 9, 10 },
+  { 4, 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_3v =
+{
+  HP_TET,
+  reftet_2eb_3v_splitedges, 
+  0, 0,
+  reftet_2eb_3v_newelstypes, 
+  reftet_2eb_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_1V,  
+int reftet_3ea_1v_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_1v_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_1v_splitelements[][5] =
+  {
+    { 1, 2, 3, 4, 20 },
+    { 0 },
+  };
+
+HPREF_ELEMENT_TYPE reftet_3ea_1v_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_1v_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 },
+  { 6, 16, 14, 3, 11, 10 },
+  { 14, 16, 20, 10, 11, 18 },
+  //  { 4, 23, 13, 12 },
+  //  { 7, 15, 16, 23, 12, 13 },
+  { 7, 15, 16, 4, 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_1v =
+{
+  HP_TET,
+  reftet_3ea_1v_splitedges, 
+  reftet_3ea_1v_splitfaces, 
+  reftet_3ea_1v_splitelements, 
+  reftet_3ea_1v_newelstypes, 
+  reftet_3ea_1v_newels
+};
+
+
+
+
+
+
+
+
+
+
+//  HP_TET_3EA_2V,  
+int reftet_3ea_2v_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_2v_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_2v_splitelements[][5] =
+  {
+    { 1, 2, 3, 4, 20 },
+    { 0 },
+  };
+
+HPREF_ELEMENT_TYPE reftet_3ea_2v_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_2v_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, 4, 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_2v =
+{
+  HP_TET,
+  reftet_3ea_2v_splitedges, 
+  reftet_3ea_2v_splitfaces, 
+  reftet_3ea_2v_splitelements, 
+  reftet_3ea_2v_newelstypes, 
+  reftet_3ea_2v_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_0V,  
+int reftet_3eb_0v_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_0v_splitfaces[][4] =
+  {
+    { 1, 2, 4, 17 },
+    { 2, 1, 3, 18 },
+    { 0, 0, 0, 0 }
+  };
+int reftet_3eb_0v_splitelements[][5] =
+  {
+    { 1, 2, 3, 4, 20 },
+    { 0 },
+  };
+
+HPREF_ELEMENT_TYPE reftet_3eb_0v_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_0v_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, 4, 15, 16 },
+  { 9, 18, 10, 3, 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_0v =
+{
+  HP_TET,
+  reftet_3eb_0v_splitedges, 
+  reftet_3eb_0v_splitfaces, 
+  reftet_3eb_0v_splitelements, 
+  reftet_3eb_0v_newelstypes, 
+  reftet_3eb_0v_newels
+};
+
+
+
+
+
+
+
+
+
+//  HP_TET_3EV_1V,  
+int reftet_3eb_1v_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_1v_splitfaces[][4] =
+  {
+    { 1, 2, 4, 17 },
+    { 2, 1, 3, 18 },
+    { 0, 0, 0, 0 }
+  };
+int reftet_3eb_1v_splitelements[][5] =
+  {
+    { 1, 2, 3, 4, 20 },
+    { 0 },
+  };
+
+HPREF_ELEMENT_TYPE reftet_3eb_1v_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_1v_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, 4, 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_1v =
+{
+  HP_TET,
+  reftet_3eb_1v_splitedges, 
+  reftet_3eb_1v_splitfaces, 
+  reftet_3eb_1v_splitelements, 
+  reftet_3eb_1v_newelstypes, 
+  reftet_3eb_1v_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_0V,  
+int reftet_3ec_0v_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_0v_splitfaces[][4] =
+  {
+    { 1, 2, 3, 17 },
+    { 2, 1, 4, 18 },
+    { 0, 0, 0, 0 }
+  };
+int reftet_3ec_0v_splitelements[][5] =
+  {
+    { 1, 2, 3, 4, 20 },
+    { 0 },
+  };
+
+HPREF_ELEMENT_TYPE reftet_3ec_0v_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_0v_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, 3, 13, 12 },
+  { 10, 9, 18, 4, 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_0v =
+{
+  HP_TET,
+  reftet_3ec_0v_splitedges, 
+  reftet_3ec_0v_splitfaces, 
+  reftet_3ec_0v_splitelements, 
+  reftet_3ec_0v_newelstypes, 
+  reftet_3ec_0v_newels
+};
+
+
+
+
+
+
+ 
+
+
+//  HP_TET_3EC_1V,  
+int reftet_3ec_1v_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_1v_splitfaces[][4] =
+  {
+    { 1, 2, 3, 17 },
+    { 2, 1, 4, 18 },
+    { 0, 0, 0, 0 }
+  };
+int reftet_3ec_1v_splitelements[][5] =
+  {
+    { 1, 2, 3, 4, 20 },
+    { 0 },
+  };
+
+HPREF_ELEMENT_TYPE reftet_3ec_1v_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_1v_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, 4, 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_1v =
+{
+  HP_TET,
+  reftet_3ec_1v_splitedges, 
+  reftet_3ec_1v_splitfaces, 
+  reftet_3ec_1v_splitelements, 
+  reftet_3ec_1v_newelstypes, 
+  reftet_3ec_1v_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
+};
+
+
+
+
+
+
+
+
+
+
+/* ************************ 1 singular face ******************** */
+
+
+// HP_TET_1F_0E_0V
+int reftet_1f_0e_0v_splitedges[][3] =
+{
+  { 2, 1, 5 },
+  { 3, 1, 6 },
+  { 4, 1, 7 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE reftet_1f_0e_0v_newelstypes[] =
+{
+  HP_PRISM_1FA_0E_0V,
+  HP_TET,
+  HP_NONE,
+};
+int reftet_1f_0e_0v_newels[][8] =
+{
+  { 3, 2, 4, 6, 5, 7 },
+  { 5, 7, 6, 1 }
+};
+HPRef_Struct reftet_1f_0e_0v =
+{
+  HP_TET,
+  reftet_1f_0e_0v_splitedges, 
+  0, 0,
+  reftet_1f_0e_0v_newelstypes, 
+  reftet_1f_0e_0v_newels
+};
+
+
+
+
+
+// HP_TET_1F_0E_1VA    ... singular vertex in face
+int reftet_1f_0e_1va_splitedges[][3] =
+{
+  { 2, 1, 5 },
+  { 2, 3, 6 },
+  { 2, 4, 7 },
+  { 3, 1, 8 },
+  { 4, 1, 9 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE reftet_1f_0e_1va_newelstypes[] =
+{
+  HP_HEX_1F_0E_0V,
+  HP_TET_1F_0E_1VA,
+  HP_TET,
+  HP_NONE,
+};
+int reftet_1f_0e_1va_newels[][8] =
+{
+  { 3, 6, 7, 4, 8, 5, 5, 9 },
+  { 5, 2, 6, 7 },
+  { 5, 9, 8, 1 },
+};
+HPRef_Struct reftet_1f_0e_1va =
+{
+  HP_TET,
+  reftet_1f_0e_1va_splitedges, 
+  0, 0,
+  reftet_1f_0e_1va_newelstypes, 
+  reftet_1f_0e_1va_newels
+};
+
+
+
+
+
+// HP_TET_1F_0E_1VB    ... singular vertex not in face
+int reftet_1f_0e_1vb_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 3, 6 },
+  { 1, 4, 7 },
+  { 2, 1, 8 },
+  { 3, 1, 9 },
+  { 4, 1, 10 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE reftet_1f_0e_1vb_newelstypes[] =
+{
+  HP_PRISM_1FA_0E_0V,
+  HP_PRISM,
+  HP_TET_0E_1V,
+  HP_NONE,
+};
+int reftet_1f_0e_1vb_newels[][8] =
+{
+  { 2, 4, 3, 8, 10, 9 },
+  { 8, 10, 9, 5, 7, 6 }, 
+  { 1, 5, 6, 7 },
+};
+HPRef_Struct reftet_1f_0e_1vb =
+{
+  HP_TET,
+  reftet_1f_0e_1vb_splitedges, 
+  0, 0,
+  reftet_1f_0e_1vb_newelstypes, 
+  reftet_1f_0e_1vb_newels
+};
+
+
+
+
+
+
+
+
+// HP_TET_1F_1EA_0V  ... sing edge is 1..2
+int reftet_1f_1ea_0v_splitedges[][3] =
+{
+  { 1, 3, 5 },
+  { 1, 4, 6 },
+  { 2, 1, 7 },
+  { 2, 3, 8 },
+  { 2, 4, 9 },
+  { 3, 1, 10 },
+  { 4, 1, 11 },
+  { 0, 0, 0 }
+};
+
+int reftet_1f_1ea_0v_splitfaces[][4] =
+  {
+    { 2, 1, 3, 12 },
+    { 2, 1, 4, 13 },
+    { 0, 0, 0, 0 }
+  };
+
+
+HPREF_ELEMENT_TYPE reftet_1f_1ea_0v_newelstypes[] =
+{
+  HP_HEX_1F_0E_0V,
+  //  HP_PRISM,
+  HP_PYRAMID_1FB_0E_1VA,
+  HP_TET_1E_1VA,
+  HP_PRISM_SINGEDGE,
+  HP_PRISM,
+  HP_NONE,
+};
+int reftet_1f_1ea_0v_newels[][8] =
+{
+  { 3, 8, 9, 4, 10, 12, 13, 11 },
+  // { 2, 9, 8, 7, 13, 12 },
+  { 8, 9, 13, 12, 2 },
+  { 2, 7, 13, 12 },
+  { 7, 13, 12, 1, 6, 5 },
+  { 6, 11, 13, 5, 10, 12 }
+};
+HPRef_Struct reftet_1f_1ea_0v =
+{
+  HP_TET,
+  reftet_1f_1ea_0v_splitedges, 
+  reftet_1f_1ea_0v_splitfaces, 
+  0, 
+  reftet_1f_1ea_0v_newelstypes, 
+  reftet_1f_1ea_0v_newels
+};
+
+
+
+
+
+
+
+
+// HP_TET_1F_1EB_0V     singular edge in face, edge is 2-3
+int reftet_1f_1eb_0v_splitedges[][3] =
+{
+  { 2, 1, 5 },
+  { 2, 4, 6 },
+  { 3, 1, 7 },
+  { 3, 4, 8 },
+  { 4, 1, 9 },
+  { 0, 0, 0 }
+};
+
+
+HPREF_ELEMENT_TYPE reftet_1f_1eb_0v_newelstypes[] =
+{
+  HP_PRISM_1FB_1EA_0V,
+  HP_PRISM_1FA_0E_0V,
+  HP_TET,
+  HP_NONE,
+};
+int reftet_1f_1eb_0v_newels[][8] =
+{
+  // { 2, 5, 6, 3, 7, 8 },
+  { 3, 8, 7, 2, 6, 5 },
+  { 6, 4, 8, 5, 9, 7 },
+  { 5, 9, 7, 1}
+};
+HPRef_Struct reftet_1f_1eb_0v =
+{
+  HP_TET,
+  reftet_1f_1eb_0v_splitedges, 
+  0, 0, 
+  reftet_1f_1eb_0v_newelstypes, 
+  reftet_1f_1eb_0v_newels
+};
+
+
+
+
+
+
+
+
+
+
+/* ************************ 2 singular faces ******************** */
+
+
+// HP_TET_2F_0E_0V
+int reftet_2f_0e_0v_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 2, 1, 6 },
+  { 3, 1, 7 },
+  { 3, 2, 8 },
+  { 4, 1, 9 },
+  { 4, 2, 10 },
+  { 0, 0, 0 }
+};
+
+int reftet_2f_0e_0v_splitfaces[][4] =
+  {
+    { 3, 1, 2, 11 },
+    { 4, 1, 2, 12 },
+    { 0, 0, 0, 0 }
+  };
+
+
+HPREF_ELEMENT_TYPE reftet_2f_0e_0v_newelstypes[] =
+{
+  HP_PRISM_1FA_0E_0V,
+  HP_PRISM_1FA_0E_0V,
+  HP_PRISM_1FB_1EA_0V,
+  HP_PRISM_1FB_1EA_0V,
+  HP_TET,
+  HP_NONE,
+};
+int reftet_2f_0e_0v_newels[][8] =
+{
+  { 2, 10, 8, 6, 12, 11 },
+  { 1, 7, 9, 5, 11, 12 },
+  //   { 3, 11, 8, 4, 12, 10 },
+  { 4, 10, 12, 3, 8, 11 }, 
+  { 3, 7, 11, 4, 9, 12 },
+  { 5, 6, 11, 12 }
+};
+HPRef_Struct reftet_2f_0e_0v =
+{
+  HP_TET,
+  reftet_2f_0e_0v_splitedges, 
+  reftet_2f_0e_0v_splitfaces, 
+  0, 
+  reftet_2f_0e_0v_newelstypes, 
+  reftet_2f_0e_0v_newels
+};
+
diff --git a/contrib/Netgen/libsrc/meshing/hpref_trig.hpp b/contrib/Netgen/libsrc/meshing/hpref_trig.hpp
new file mode 100644
index 0000000000..3676ad0f33
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/hpref_trig.hpp
@@ -0,0 +1,776 @@
+
+
+// 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_2D
+int reftrig_singcorner123_2D_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_singcorner123_2D_newelstypes[] =
+{
+  HP_TRIG_SINGCORNER,
+  HP_TRIG_SINGCORNER,
+  HP_TRIG_SINGCORNER,
+  HP_QUAD,
+  HP_QUAD,
+  HP_NONE,
+};
+int reftrig_singcorner123_2D_newels[][8] =
+{
+  { 1, 4, 5 },
+  { 2, 7, 6 },
+  { 3, 8, 9 },
+  { 4, 6, 8, 5 },
+  { 6, 7, 9, 8 },
+};
+HPRef_Struct reftrig_singcorner123_2D =
+{
+  HP_TRIG,
+  reftrig_singcorner123_2D_splitedges, 
+  0, 0,
+  reftrig_singcorner123_2D_newelstypes, 
+  reftrig_singcorner123_2D_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_2E,
+  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_2E,
+  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_2E,
+  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_2E,
+  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_TRIG_3SINGEDGES
+int reftrig_3singedges_splitedges[][3] =
+{
+  { 1, 2, 4 },
+  { 2, 1, 5 }, 
+  { 2, 3, 6 }, 
+  { 3, 2, 7 }, 
+  { 3, 1, 8 }, 
+  { 1, 3, 9 }, 
+  { 0, 0, 0 }
+};
+int reftrig_3singedges_splitfaces[][4] =
+{
+  { 1, 2, 3, 10 },
+  { 2, 3, 1, 11 },
+  { 3, 1, 2, 12 }, 
+  { 0, 0, 0, 0 }
+};
+
+HPREF_ELEMENT_TYPE reftrig_3singedges_newelstypes[] =
+{
+  HP_TRIG, 
+  HP_QUAD_SINGEDGE, 
+  HP_QUAD_SINGEDGE, 
+  HP_QUAD_SINGEDGE, 
+  HP_TRIG_SINGEDGECORNER1, 
+  HP_TRIG_SINGEDGECORNER2, 
+  HP_TRIG_SINGEDGECORNER1, 
+  HP_TRIG_SINGEDGECORNER2, 
+  HP_TRIG_SINGEDGECORNER1, 
+  HP_TRIG_SINGEDGECORNER2, 
+  HP_NONE, 
+};
+int reftrig_3singedges_newels[][8] =
+{
+  { 10, 11, 12 }, 
+  { 4, 5, 11, 10 }, 
+  { 6, 7, 12, 11 },
+  { 8, 9, 10, 12 }, 
+  { 1, 4, 10 }, 
+  { 9, 1, 10 }, 
+  { 2, 6, 11 }, 
+  { 5, 2, 11 }, 
+  { 3, 8, 12 }, 
+  { 7, 3, 12 }, 
+};
+HPRef_Struct reftrig_3singedges =
+{
+  HP_TRIG,
+  reftrig_3singedges_splitedges, 
+  reftrig_3singedges_splitfaces, 
+  0,
+  reftrig_3singedges_newelstypes, 
+  reftrig_3singedges_newels
+};
diff --git a/contrib/Netgen/libsrc/meshing/hprefinement.cpp b/contrib/Netgen/libsrc/meshing/hprefinement.cpp
new file mode 100644
index 0000000000..9c8155ad55
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/hprefinement.cpp
@@ -0,0 +1,1969 @@
+#include <mystdlib.h>
+#include "meshing.hpp"
+#include "hprefinement.hpp" 
+
+namespace netgen
+{
+
+#include "hpref_segm.hpp"
+#include "hpref_trig.hpp"  
+#include "hpref_quad.hpp"
+#include "hpref_tet.hpp"  
+#include "hpref_prism.hpp"
+#include "hpref_hex.hpp" 
+#include "hpref_pyramid.hpp" 
+#include "classifyhpel.hpp"  
+
+
+  void HPRefElement :: Reset(void)
+  {
+    np = 8; 
+    for (int i = 0; i < 8; i++)
+      {
+	pnums[i] = -1;
+	param[i][0] = param[i][1] = param[i][2] = 0;
+        domin=-1; domout=-1; // he:
+      }
+  } 
+
+  HPRefElement :: HPRefElement () 
+  {
+    Reset();
+  }
+
+  HPRefElement :: HPRefElement(Element & el)
+  { 
+    //Reset();
+    np = el.GetNV(); 
+    for (int i=0; i<np ; i++) 
+      pnums[i] = el[i]; 
+    
+    index = el.GetIndex(); 
+    const Point3d * points = 
+      MeshTopology :: GetVertices (el.GetType());
+    for(int i=0;i<np;i++)
+      for(int l=0;l<3;l++) 
+	param[i][l] = points[i].X(l+1); 
+    type = HP_NONE; 
+    domin=-1; domout=-1; // he: needed for segments
+  }
+
+  
+  HPRefElement :: HPRefElement(Element2d & el)
+  { 
+    //Reset();
+    np = el.GetNV(); 
+    
+    for (int i=0; i<np ; i++) 
+      pnums[i] = el[i]; 
+    
+    index = el.GetIndex(); 
+    const Point3d * points = 
+      MeshTopology :: GetVertices (el.GetType());
+    for(int i=0;i<np;i++)
+      for(int l=0;l<3;l++) 
+	param[i][l] = points[i].X(l+1); 
+    type = HP_NONE; 
+    domin=-1; domout=-1; // he: needed for segments
+  }
+
+  HPRefElement :: HPRefElement(Segment & el)
+  { 
+    //Reset();
+    np = 2; 
+    for (int i=0; i<np ; i++) 
+      pnums[i] = el[i];
+    const Point3d * points = 
+      MeshTopology :: GetVertices (SEGMENT); 
+    for(int i=0;i<np;i++)
+      for(int l=0;l<3;l++) 
+        param[i][l] = points[i].X(l+1); 
+
+    /*
+    for (int i=0; i<np; i++)
+    {
+      param[i][0] = i;   
+      param[i][1] = -1; param[i][2] = -1;
+    }
+    */
+
+    singedge_left = el.singedge_left; 
+    singedge_right = el.singedge_right; 
+    type = HP_NONE; 
+    // he: needed for orientation!
+    domin = el.domin;
+    domout = el.domout;
+  }
+  
+  HPRefElement :: HPRefElement(HPRefElement & el)
+  {
+    //Reset();
+    np = el.np; 
+    for (int i=0; i<np ; i++) 
+      {
+	pnums[i] = el[i];
+	for(int l=0; l<3; l++) param[i][l] = el.param[i][l]; 
+      }
+    index = el.index; 
+    levelx = el.levelx; 
+    levely = el.levely; 
+    levelz = el.levelz; 
+    type = el.type; 
+    coarse_elnr = el.coarse_elnr; 
+    singedge_left = el.singedge_left; 
+    singedge_right = el.singedge_right; 
+    domin = el.domin; // he: needed for segments
+    domout=el.domout;
+          
+  }
+
+  void HPRefElement :: SetType (HPREF_ELEMENT_TYPE t) 
+  {
+    type = t; 
+    switch(type)
+      {
+      case HP_SEGM: np=2; break; 
+      case HP_TRIG: np=3; break; 
+      case HP_QUAD: np=4; break; 
+      case HP_TET: np=4; break; 
+      case HP_PRISM: np=6; break; 
+      case HP_PYRAMID: np=5; break; 
+      case HP_HEX: np=8; break;      
+
+      default:
+        cerr << "HPRefElement: illegal type " << type << endl;
+        throw NgException ("HPRefElement::SetType: illegal type");
+      } 
+
+    for(int k = 0; k < 8;k++)
+      {
+	pnums[k]=0;
+	for(int l = 0; l < 3; l++) 
+          param[k][l]=0.;
+      }
+  }
+  
+
+  HPRef_Struct * Get_HPRef_Struct (HPREF_ELEMENT_TYPE type)
+  {
+    HPRef_Struct * hps = NULL;
+
+    switch (type)
+      {
+      case HP_SEGM:
+	hps = &refsegm; break;
+      case HP_SEGM_SINGCORNERL:
+	hps = &refsegm_scl; break;
+      case HP_SEGM_SINGCORNERR:
+	hps = &refsegm_scr; break;
+      case HP_SEGM_SINGCORNERS:
+	hps = &refsegm_sc2; break;
+	
+      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_SINGCORNER123_2D:
+	hps = &reftrig_singcorner123_2D; 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_TRIG_3SINGEDGES:
+	hps = &reftrig_3singedges; 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_0E_2VA:
+	hps = &refquad_0e_2va; break;
+      case HP_QUAD_0E_2VB:
+	hps = &refquad_0e_2vb; break;
+
+      case HP_QUAD_0E_3V:
+	hps = &refquad_0e_3v; break;
+      case HP_QUAD_0E_4V:
+	hps = &refquad_0e_4v; break;
+
+      case HP_QUAD_1E_1VA:
+	hps = &refquad_1e_1va; break;
+      case HP_QUAD_1E_1VB:
+	hps = &refquad_1e_1vb; break;
+      case HP_QUAD_1E_1VC:
+	hps = &refquad_1e_1vc; break;
+      case HP_QUAD_1E_1VD:
+	hps = &refquad_1e_1vd; break;
+
+      case HP_QUAD_1E_2VA:
+	hps = &refquad_1e_2va; break;
+      case HP_QUAD_1E_2VB:
+	hps = &refquad_1e_2vb; break;
+      case HP_QUAD_1E_2VC:
+	hps = &refquad_1e_2vc; break;
+      case HP_QUAD_1E_2VD:
+	hps = &refquad_1e_2vd; break;
+      case HP_QUAD_1E_2VE:
+	hps = &refquad_1e_2ve; break;
+      case HP_QUAD_1E_2VF:
+	hps = &refquad_1e_2vf; break;
+
+      case HP_QUAD_1E_3VA:
+	hps = &refquad_1e_3va; break;
+      case HP_QUAD_1E_3VB:
+	hps = &refquad_1e_3vb; break;
+      case HP_QUAD_1E_3VC:
+	hps = &refquad_1e_3vc; break;
+      case HP_QUAD_1E_3VD:
+	hps = &refquad_1e_3vd; break;
+      case HP_QUAD_1E_4V:
+	hps = &refquad_1e_4v; break;
+
+
+      case HP_QUAD_2E:
+	hps = &refquad_2e; break;
+      case HP_QUAD_2E_1VA:
+	hps = &refquad_2e_1va; break;
+      case HP_QUAD_2E_1VB:
+	hps = &refquad_2e_1vb; break;
+      case HP_QUAD_2E_1VC:
+	hps = &refquad_2e_1vc; break;
+      case HP_QUAD_2E_2VA:
+	hps = &refquad_2e_2va; break;
+      case HP_QUAD_2E_2VB:
+	hps = &refquad_2e_2vb; break;
+      case HP_QUAD_2E_2VC:
+	hps = &refquad_2e_2vc; break;
+      case HP_QUAD_2E_3V:
+	hps = &refquad_2e_3v; break;
+
+      case HP_QUAD_2EB_0V:
+	hps = &refquad_2eb_0v; break;
+
+      case HP_QUAD_2EB_1VA:
+	hps = &refquad_2eb_1va; break;
+      case HP_QUAD_2EB_1VB:
+	hps = &refquad_2eb_1vb; break;
+
+
+      case HP_QUAD_2EB_2VA:
+	hps = &refquad_2eb_2va; break;
+      case HP_QUAD_2EB_2VB:
+	hps = &refquad_2eb_2vb; break;
+      case HP_QUAD_2EB_2VC:
+	hps = &refquad_2eb_2vc; break;
+      case HP_QUAD_2EB_2VD:
+	hps = &refquad_2eb_2vd; break;
+
+      case HP_QUAD_2EB_3VA:
+	hps = &refquad_2eb_3va; break;
+      case HP_QUAD_2EB_3VB:
+	hps = &refquad_2eb_3vb; break;
+
+      case HP_QUAD_2EB_4V:
+	hps = &refquad_2eb_4v; break;
+
+      case HP_QUAD_3E:
+	hps = &refquad_3e; break;
+      case HP_QUAD_3E_3VA:
+	hps = &refquad_3e_3va; break;
+      case HP_QUAD_3E_3VB:
+	hps = &refquad_3e_3vb; break;
+      case HP_QUAD_3E_4V:
+	hps = &refquad_3e_4v; break;
+
+
+      case HP_QUAD_4E:
+	hps = &refquad_4e; 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_1E_3VA:
+	hps = &reftet_1e_3va; break;
+      case HP_TET_1E_3VB:
+	hps = &reftet_1e_3vb; break;
+      case HP_TET_1E_4V:
+	hps = &reftet_1e_4v; 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_1VC:
+	hps = &reftet_2ea_1vc; break;
+      case HP_TET_2EA_1VA:
+	hps = &reftet_2ea_1va; break;
+      case HP_TET_2EA_2VA:
+	hps = &reftet_2ea_2va; break;
+      case HP_TET_2EA_2VB:
+	hps = &reftet_2ea_2vb; break;
+      case HP_TET_2EA_2VC:
+	hps = &reftet_2ea_2vc; break;
+      case HP_TET_2EA_3V:
+	hps = &reftet_2ea_3v; break;
+
+      case HP_TET_2EB_0V:
+	hps = &reftet_2eb_0v; break;
+      case HP_TET_2EB_1V:
+	hps = &reftet_2eb_1v; break;
+      case HP_TET_2EB_2VA:
+	hps = &reftet_2eb_2va; break;
+      case HP_TET_2EB_2VB:
+	hps = &reftet_2eb_2vb; break;
+      case HP_TET_2EB_2VC:
+	hps = &reftet_2eb_2vc; break;
+      case HP_TET_2EB_3V:
+	hps = &reftet_2eb_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_1V:
+	hps = &reftet_3ea_1v; break;
+      case HP_TET_3EA_2V:
+	hps = &reftet_3ea_2v; break;
+      case HP_TET_3EA_3V:
+	hps = &reftet_3ea_3v; break;
+
+      case HP_TET_3EB_0V:
+	hps = &reftet_3eb_0v; break;
+      case HP_TET_3EB_1V:
+	hps = &reftet_3eb_1v; break;
+      case HP_TET_3EB_2V:
+	hps = &reftet_3eb_2v; break;
+      case HP_TET_3EC_0V:
+	hps = &reftet_3ec_0v; break;
+      case HP_TET_3EC_1V:
+	hps = &reftet_3ec_1v; break;
+      case HP_TET_3EC_2V:
+	hps = &reftet_3ec_2v; break;
+
+
+      case HP_TET_1F_0E_0V:
+	hps = &reftet_1f_0e_0v; break;
+      case HP_TET_1F_0E_1VA:
+	hps = &reftet_1f_0e_1va; break;
+      case HP_TET_1F_0E_1VB:
+	hps = &reftet_1f_0e_1vb; break;
+      case HP_TET_1F_1EA_0V:
+	hps = &reftet_1f_1ea_0v; break;
+      case HP_TET_1F_1EB_0V:
+	hps = &reftet_1f_1eb_0v; break;
+      case HP_TET_2F_0E_0V:
+	hps = &reftet_2f_0e_0v; break;
+
+
+      case HP_PRISM:
+	hps = &refprism; break;
+      case HP_PRISM_SINGEDGE:
+	hps = &refprism_singedge; break;
+	//      case HP_PRISM_SINGEDGE_H1:
+	//	hps = &refprism_singedge_h1; break;
+	// case HP_PRISM_SINGEDGE_H12:
+	//	hps = &refprism_singedge_h12; break;
+      case HP_PRISM_SINGEDGE_V12:
+	hps = &refprism_singedge_v12; break;
+	
+
+      case HP_PRISM_1FA_0E_0V:
+	hps = &refprism_1fa_0e_0v; break;
+      case HP_PRISM_2FA_0E_0V:
+	hps = &refprism_2fa_0e_0v; break;
+      case HP_PRISM_1FB_0E_0V:
+	hps = &refprism_1fb_0e_0v; break;
+      case HP_PRISM_1FB_1EA_0V: 
+	hps = &refprism_1fb_1ea_0v; break;
+ 
+      case HP_PRISM_1FA_1E_0V:
+	hps = &refprism_1fa_1e_0v; break;
+      case HP_PRISM_2FA_1E_0V:
+	hps = &refprism_2fa_1e_0v; break; 
+      case HP_PRISM_1FA_1FB_0E_0V: 
+	hps = &refprism_1fa_1fb_0e_0v; break;
+      case HP_PRISM_2FA_1FB_0E_0V: 
+	hps = &refprism_2fa_1fb_0e_0v; break; 
+      case HP_PRISM_1FA_1FB_1EA_0V: 
+	hps = &refprism_1fa_1fb_1ea_0v; break; 
+      case HP_PRISM_1FA_1FB_1EB_0V: 
+	hps = &refprism_1fa_1fb_1eb_0v; break; 
+      case HP_PRISM_2FA_1FB_1EA_0V:  
+	hps = &refprism_2fa_1fb_1ea_0v; break; 
+      case HP_PRISM_1FB_1EC_0V: 
+	hps = &refprism_1fb_1ec_0v; break; 
+      case HP_PRISM_1FA_1FB_1EC_0V: 
+	hps = &refprism_1fa_1fb_1ec_0v; break; 
+      case HP_PRISM_2FA_1FB_1EC_0V: 
+	hps = &refprism_2fa_1fb_1ec_0v; break;  
+      case HP_PRISM_1FB_2EA_0V: 
+	hps = &refprism_1fb_2ea_0v; break; 
+      case HP_PRISM_1FA_1FB_2EA_0V:   
+	hps = &refprism_1fa_1fb_2ea_0v; break; 
+      case HP_PRISM_2FA_1FB_2EA_0V:  
+	hps = &refprism_2fa_1fb_2ea_0v; break;   
+      case HP_PRISM_1FB_2EB_0V: 
+	hps = &refprism_1fb_2eb_0v; break; 
+      case HP_PRISM_1FA_1FB_2EB_0V:   
+	hps = &refprism_1fa_1fb_2eb_0v; break;  
+      case HP_PRISM_1FA_1FB_2EC_0V: 
+	hps = &refprism_1fa_1fb_2ec_0v; break; 
+      case HP_PRISM_2FA_1FB_2EB_0V: 
+	hps = &refprism_2fa_1fb_2eb_0v; break;  
+      case HP_PRISM_1FB_3E_0V: 
+	hps = &refprism_1fb_3e_0v; break; 
+      case HP_PRISM_1FA_1FB_3E_0V:  
+	hps = &refprism_1fa_1fb_3e_0v; break;  
+      case HP_PRISM_2FA_1FB_3E_0V:  
+        hps = &refprism_2fa_1fb_3e_0v; break; 
+      case HP_PRISM_2FB_0E_0V: 
+	hps = &refprism_2fb_0e_0v; break;  
+      case HP_PRISM_1FA_2FB_0E_0V: 
+	hps = &refprism_1fa_2fb_0e_0v; break; 
+      case HP_PRISM_2FA_2FB_0E_0V:    
+        hps = &refprism_2fa_2fb_0e_0v; break;  
+      case HP_PRISM_2FB_1EC_0V:  
+	hps = &refprism_2fb_1ec_0v; break;  
+      case HP_PRISM_1FA_2FB_1EC_0V: 
+        hps = &refprism_1fa_2fb_1ec_0v; break; 
+      case HP_PRISM_2FA_2FB_1EC_0V: 
+	hps = &refprism_2fa_2fb_1ec_0v; break; 
+      case HP_PRISM_1FA_2FB_1EB_0V: 
+	hps = &refprism_1fa_2fb_1eb_0v; break; 
+      case HP_PRISM_2FB_3E_0V:    
+	hps = &refprism_2fb_3e_0v; break;
+      case HP_PRISM_1FA_2FB_3E_0V: 
+	hps = &refprism_1fa_2fb_3e_0v; break;
+      case HP_PRISM_2FA_2FB_3E_0V:  
+	hps = &refprism_2fa_2fb_3e_0v; break;
+      case HP_PRISM_1FA_2E_0V:   
+	hps = &refprism_1fa_2e_0v; break; 
+      case HP_PRISM_2FA_2E_0V:  
+	hps = &refprism_2fa_2e_0v; break;   
+      case HP_PRISM_3E_0V:  
+	hps = &refprism_3e_0v; break;
+      case HP_PRISM_1FA_3E_0V:   
+	hps = &refprism_1fa_3e_0v; break; 
+      case HP_PRISM_2FA_3E_0V:  
+	hps = &refprism_2fa_3e_0v; break;   
+      case HP_PRISM_3FB_0V:  
+	hps = &refprism_3fb_0v; break;
+      case HP_PRISM_1FA_3FB_0V:   
+	hps = &refprism_1fa_3fb_0v; break; 
+      case HP_PRISM_2FA_3FB_0V:  
+	hps = &refprism_2fa_3fb_0v; break;   
+	//  case HP_PRISM_3E_4EH:
+	//  hps = &refprism_3e_4eh; break;   
+	
+	
+	/*case HP_PRISM_1FB_1EB_0V:
+	hps = &refprism_1fb_1eb_0v; break;
+      case HP_PRISM_2F_0E_0V:
+	hps = &refprism_2f_0e_0v; 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_PYRAMID_1FB_0E_1VA:
+	hps = &refpyramid_1fb_0e_1va; break;
+
+	
+      case HP_HEX:
+	hps = &refhex; break;
+      case HP_HEX_0E_1V:
+	hps = &refhex_0e_1v; break;
+      case HP_HEX_1E_1V:
+	hps = &refhex_1e_1v; break;
+      case HP_HEX_1E_0V:
+	hps = &refhex_1e_0v; break;
+      case HP_HEX_3E_0V:
+	hps = &refhex_3e_0v; break;
+
+      case HP_HEX_1F_0E_0V:
+	hps = &refhex_1f_0e_0v; break;
+      case HP_HEX_1FA_1FB_0E_0V: 
+	hps = &refhex_1fa_1fb_0e_0v; break; 
+      }
+
+    /*
+    if (type != HP_TET_1E_4V && type != HP_TET_1E_2VD)
+      {
+	if (hps->geom == HP_TET)
+	  hps = &reftet;
+	if (hps->geom == HP_TRIG)
+	  hps = &reftrig;
+      }
+    */
+
+    if (!hps)
+      {
+	cout << "Attention hps : hp-refinement not implemented for case " << type << endl;
+	PrintSysError ("hp-refinement not implemented for case ", type);
+      }
+
+    return hps;
+  }
+
+  bool CheckSingularities(Mesh & mesh, INDEX_2_HASHTABLE<int> & edges, INDEX_2_HASHTABLE<int> & edgepoiclt_dom, 
+		       BitArray & cornerpoint, BitArray & edgepoint, INDEX_3_HASHTABLE<int> & faces, INDEX_2_HASHTABLE<int> & face_edges, 
+			INDEX_2_HASHTABLE<int> & surf_edges, Array<int, PointIndex::BASE> & facepoint, int & levels, int & act_ref); 
+
+  bool ClassifyHPElements (Mesh & mesh, Array<HPRefElement> & elements, int & act_ref, int & levels);
+  
+  
+  void  InitHPElements(Mesh & mesh, Array<HPRefElement> & elements) 
+  { 
+    for(ElementIndex i = 0; i < mesh.GetNE(); i++) 
+      {
+	HPRefElement hpel(mesh[i]); 
+	hpel.coarse_elnr = i; 
+	
+	switch (mesh[i].GetType()) 
+	  { 
+	  case PRISM:   hpel.type = HP_PRISM;   break; 
+	  case HEX:     hpel.type = HP_HEX;     break; 
+	  case TET:     hpel.type = HP_TET;     break; 
+	  case PYRAMID: hpel.type = HP_PYRAMID; break; 
+
+          default:
+            cerr << "HPRefElement: illegal elementtype (1) " << mesh[i].GetType() << endl;
+            throw NgException ("HPRefElement: illegal elementtype (1)");
+	  } 
+	elements.Append(hpel); 
+      }
+	    
+    for(SurfaceElementIndex i = 0; i < mesh.GetNSE(); i++)
+      {
+	HPRefElement hpel(mesh[i]);
+	hpel.coarse_elnr = i; 
+	switch(mesh[i].GetType())
+	  { 
+	  case TRIG: hpel.type = HP_TRIG; break; 
+	  case QUAD: hpel.type = HP_QUAD; break; 
+
+          default:
+            cerr << "HPRefElement: illegal elementtype (1b) " << mesh[i].GetType() << endl;
+            throw NgException ("HPRefElement: illegal elementtype (1b)");
+	  } 
+	elements.Append(hpel);
+      } 
+        
+    for(SegmentIndex i = 0; i < mesh.GetNSeg(); i++) 
+      { 
+	Segment & seg = mesh[i];
+	HPRefElement hpel(mesh[i]);
+	hpel.coarse_elnr = i; 
+	hpel.type = HP_SEGM; 
+	hpel.index = seg.edgenr + 10000*seg.si; 
+	if(seg.edgenr >= 10000)
+	  {
+	    throw NgException("assumption that seg.edgenr < 10000 is wrong");
+	  }
+	elements.Append(hpel); 
+      }
+  }
+
+ 
+ 
+  /* *******************************  DoRefinement *************************************** */
+  void DoRefinement (Mesh & mesh, Array<HPRefElement> & elements,
+		     Refinement * ref, double fac1) 
+  {
+    elements.SetAllocSize (5 * elements.Size());
+    INDEX_2_HASHTABLE<int> newpts(elements.Size()+1);
+    INDEX_3_HASHTABLE<int> newfacepts(elements.Size()+1);
+
+    // prepare new points  
+    
+    fac1 = max(0.001,min(0.33,fac1));
+    cout << " in HP-REFINEMENT with fac1 " << fac1 << endl; 
+    *testout << " in HP-REFINEMENT with fac1 " << fac1 <<  endl; 
+   
+
+    int oldelsize = elements.Size();
+       
+    for (int i = 0; i < oldelsize; i++)
+      {
+	HPRefElement & el = elements[i]; 
+	HPRef_Struct * hprs = Get_HPRef_Struct (el.type);
+		
+	if (!hprs) 
+	  {
+	    cout << "Refinementstruct not defined for element " << el.type << endl;
+	    continue;
+	  }
+
+	int 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))
+	      {
+		Point<3> np; 
+		for( int l=0;l<3;l++)
+		  np(l) = (1-fac1)*mesh.Point(i2.I1())(l) 
+		    + fac1 * mesh.Point(i2.I2())(l); 
+	
+		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))
+		{
+		  Point<3> np; 
+		  	for( int l=0;l<3;l++)
+			  np(l) = (1-2*fac1)*mesh.Point(i3.I1())(l) 
+			    + fac1*mesh.Point(i3.I2())(l)  + fac1*mesh.Point(i3.I3())(l);  
+		  int npi = mesh.AddPoint (np);
+		  newfacepts.Set (i3, npi);
+		}
+	      j++;
+	    }
+      }
+     
+    for (int i = 0; i < oldelsize; i++)
+      {
+	HPRefElement el = elements[i];
+	HPRef_Struct * hprs = Get_HPRef_Struct (el.type);
+	int newlevel = el.levelx + 1;
+
+	int oldnp = 0;
+	switch (hprs->geom)
+	  {
+	  case HP_SEGM: oldnp = 2; break;
+	  case HP_TRIG: oldnp = 3; break;
+	  case HP_QUAD: oldnp = 4; break;
+	  case HP_TET: oldnp = 4; break;
+	  case HP_PYRAMID: oldnp = 5; break;
+	  case HP_PRISM: oldnp = 6; break;
+	  case HP_HEX: oldnp = 8; break;
+            
+          default:
+            cerr << "HPRefElement: illegal type (3) " << hprs->geom << endl;
+            throw NgException ("HPRefElement::SetType: illegal type (3)");
+	  }
+
+
+	if (el.type == HP_SEGM ||
+	    el.type == HP_TRIG ||
+	    el.type == HP_QUAD ||
+	    el.type == HP_TET ||
+	    el.type == HP_PRISM ||
+	    el.type == HP_HEX || 
+	    el.type == HP_PYRAMID)
+	  newlevel = el.levelx;
+
+	if (!hprs) continue;
+
+	int newpnums[64];
+	double newparam[64][3];
+
+	int j;
+	for (j = 0; j < oldnp; j++)
+	  {
+	    newpnums[j] = el.pnums[j];
+	    for (int l = 0; l < 3; l++)
+	      newparam[j][l] = el.param[j][l];
+	  }
+
+	// split edges, incl. transferring curvature
+	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;
+
+	    for (int l = 0; l < 3; l++)
+	      newparam[hprs->splitedges[j][2]-1][l] =
+		(1-fac1) * el.param[hprs->splitedges[j][0]-1][l] + 
+		fac1 * el.param[hprs->splitedges[j][1]-1][l];
+	      
+	    j++;
+	  }
+
+	// split faces
+	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;
+	    
+
+	      for (int l = 0; l < 3; l++)
+		newparam[hprs->splitfaces[j][3]-1][l] =
+		  (1-2*fac1) * el.param[hprs->splitfaces[j][0]-1][l] + 
+		  fac1 * el.param[hprs->splitfaces[j][1]-1][l] + 
+		  fac1 * el.param[hprs->splitfaces[j][2]-1][l];
+	      j++;
+	    }
+	// split elements
+	j = 0;
+	if (hprs->splitelements)
+	  while (hprs->splitelements[j][0])
+	    {
+	      //int pi1 = el.pnums[hprs->splitelements[j][0]-1];
+	      Point<3> np; 
+	      	for( int l=0;l<3;l++)
+		  np(l) = (1-3*fac1)* mesh.Point(el.pnums[hprs->splitelements[j][0]-1])(l) 
+		    + fac1* mesh.Point(el.pnums[hprs->splitelements[j][1]-1])(l)
+		    + fac1* mesh.Point(el.pnums[hprs->splitelements[j][2]-1])(l)
+		    + fac1* mesh.Point(el.pnums[hprs->splitelements[j][3]-1])(l); 
+	      
+	      int npi = mesh.AddPoint (np);
+	      
+	      newpnums[hprs->splitelements[j][4]-1] = npi;
+	      
+	  	    
+	      for (int l = 0; l  < 3; l++)
+		newparam[hprs->splitelements[j][4]-1][l] =
+		  (1-3*fac1) * el.param[hprs->splitelements[j][0]-1][l] + 
+		  fac1 * el.param[hprs->splitelements[j][1]-1][l] + 
+		  fac1 * el.param[hprs->splitelements[j][2]-1][l] + 
+		  fac1 * el.param[hprs->splitelements[j][3]-1][l];
+
+	      j++;
+	    }
+ 
+	j = 0;
+
+	/*
+	*testout << " newpnums = ";
+	for (int hi = 0; hi < 64; hi++)
+	  *testout << newpnums[hi] << " ";
+	*testout << endl;
+	*/
+
+	while (hprs->neweltypes[j])
+	  {
+	    HPRef_Struct * hprsnew = Get_HPRef_Struct (hprs->neweltypes[j]);
+	    HPRefElement newel(el);
+
+	    newel.type = hprs->neweltypes[j]; 
+            
+	    // newel.index = elements[i].index;
+	    // newel.coarse_elnr = elements[i].coarse_elnr;
+	    newel.levelx = newel.levely = newel.levelz = newlevel;
+            switch(hprsnew->geom) 
+	      {
+	      case HP_SEGM: newel.np=2; break; 
+	      case HP_QUAD: newel.np=4; break; 
+	      case HP_TRIG: newel.np=3; break; 
+	      case HP_HEX: newel.np=8; break; 
+	      case HP_PRISM: newel.np=6; break;
+	      case HP_TET: newel.np=4; break; 
+	      case HP_PYRAMID: newel.np=5; break; 
+              default:
+                throw NgException (string("hprefinement.cpp: illegal type"));
+	      }
+
+	    for (int k = 0; k < newel.np; k++)
+	      newel.pnums[k] = newpnums[hprs->newels[j][k]-1];
+	    
+	    /*
+	    *testout  << " newel pnums " ; 
+	    for (int k = 0; k < newel.np; k++)  
+	      *testout  << newel.pnums[k] << "\t"; 
+	    *testout << endl; 
+	    */
+
+	    for (int k = 0; k < newel.np; k++)  
+	      { 
+		for (int l = 0; l < 3; l++)
+		  { 
+		    newel.param[k][l] = newparam[hprs->newels[j][k]-1][l];
+		    //    *testout << newel.param[k][l] << " \t ";
+		  } 
+		// *testout << endl; 
+	      } 
+	    
+	    if (j == 0) 
+	      elements[i] = newel; // overwrite old element
+	    else        
+	      elements.Append (newel);
+	    j++;
+	  }
+      } 
+  }
+
+
+
+
+
+
+  /* ************************** DoRefineDummies ******************************** */
+
+  void DoRefineDummies (Mesh & mesh, Array<HPRefElement> & elements,
+			Refinement * ref)
+  {
+    int oldelsize = elements.Size();
+
+    for (int i = 0; i < oldelsize; i++)
+      {
+	HPRefElement el = elements[i];
+
+	HPRef_Struct * hprs = Get_HPRef_Struct (el.type);
+	if (!hprs) continue;
+
+	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_1V &&
+	    el.type != HP_HEX_1E_0V &&
+	    el.type != HP_HEX_3E_0V
+	    ) continue;
+
+	int newlevel = el.levelx;
+
+	int newpnums[8];
+	int j;
+	for (j = 0; j < 8; j++)
+	  newpnums[j] = el.pnums[j];
+
+	double newparam[8][3];
+	for (j = 0; j < 8; j++)
+	  for (int k = 0; k < 3; k++)
+	    newparam[j][k] = el.param[j][k];
+
+	j = 0;
+	while (hprs->neweltypes[j])
+	  {
+	    HPRef_Struct * hprsnew = Get_HPRef_Struct (hprs->neweltypes[j]);
+	    HPRefElement newel(el);
+	    switch(hprsnew->geom)
+	      {
+	      case HP_SEGM: newel.np=2; break; 
+	      case HP_QUAD: newel.np=4; break; 
+	      case HP_TRIG: newel.np=3; break; 
+	      case HP_HEX: newel.np=8; break; 
+	      case HP_PRISM: newel.np=6; break;
+	      case HP_TET: newel.np=4; break; 
+	      case HP_PYRAMID: newel.np=5; break; 
+
+              default:
+                cerr << "HPRefElement: illegal type (4) " << hprsnew->geom << endl;
+                throw NgException ("HPRefElement: illegal type (4)");
+                
+	      }
+	    newel.type = hprs->neweltypes[j];
+	    for (int k = 0; k < 8; k++)
+	      newel.pnums[k] = newpnums[hprs->newels[j][k]-1];
+	    newel.index = el.index;
+	    newel.coarse_elnr = el.coarse_elnr;
+	    newel.levelx = newel.levely = newel.levelz = newlevel;
+
+	    for (int k = 0; k < 8; k++)
+	      for (int l = 0; l < 3; l++)
+		newel.param[k][l] = newparam[hprs->newels[j][k]-1][l];
+		
+	    if (j == 0)
+	      elements[i] = newel;
+	    else
+	      elements.Append (newel);
+	    j++;
+	  }
+      }
+  }
+
+
+
+
+
+
+
+  void SubdivideDegeneratedHexes (Mesh & mesh, Array<HPRefElement> & elements, double fac1)
+  {
+    int oldne = elements.Size();
+    for (int i = 0; i < oldne; i++)
+      if (Get_HPRef_Struct (elements[i].type)->geom == HP_HEX)
+	{
+	  bool common = 0;
+	  for (int j = 0; j < 8; j++)
+	    for (int k = 0; k < j; k++)
+	      if (elements[i].pnums[j] == elements[i].pnums[k])
+		common = 1;
+	  if (common)
+	    {
+
+               
+	      cout << " Degenerate Hex found " << endl; 
+              *testout << " Degenerate Hex found " << endl; 
+	      HPRefElement el = elements[i];
+	      HPRefElement newel = el;
+
+	      Point<3> center(0,0,0);
+	      double newparam[3] = { 0, 0, 0 };
+
+	      for (int j = 0; j < 8; j++)
+		{
+		  
+		  
+		  center += 0.125 * Vec<3>(mesh[el.pnums[j]]); 
+		  // 0.125 originates form 8 points not from fac1;
+                  
+		  for (int l = 0; l < 3; l++)
+		    newparam[l] += 0.125 * el.param[j][l];
+                  
+		}
+
+	      int npi = mesh.AddPoint (center);
+
+	      const ELEMENT_FACE * faces = MeshTopology::GetFaces1 (HEX);
+
+	      for (int j = 0; j < 6; j++)  
+		{
+		  Array<int> pts;
+		  for (int k = 0; k < 4; k++)
+		    {
+		      bool same = 0;
+		      for (int l = 0; l < pts.Size(); l++)
+			if (el.pnums[pts[l]] == el.pnums[faces[j][k]-1])
+			  same = 1;
+		      if (!same)
+			pts.Append (faces[j][k]-1);
+
+		    }
+		  
+		  
+		  if (pts.Size() == 3) // TrigFace -> TET 
+		    {
+		      
+		      for (int k = 0; k < 3; k++)
+			{
+			  newel.pnums[k] = el.pnums[pts[2-k]];
+			  for (int l = 0; l < 3; l++)
+			    newel.param[k][l] = el.param[pts[2-k]][l];
+			}
+		      newel.pnums[3] = npi;
+		      for (int l = 0; l < 3; l++)
+			newel.param[3][l] = newparam[l];
+
+		      newel.type = HP_TET;
+		      newel.np = 4; 
+		    }
+		  else
+		    {
+		      for (int k = 0; k < 4; k++)
+			{
+			  newel.pnums[k] = el.pnums[pts[3-k]];
+			  for (int l = 0; l < 3; l++)
+			    newel.param[k][l] = el.param[pts[3-k]][l];
+			}
+
+		      newel.pnums[4] = npi;
+		      for (int l = 0; l < 3; l++)
+			newel.param[4][l] = newparam[l];
+
+		      newel.type = HP_PYRAMID;
+		      newel.np = 5;
+		    }
+		  
+		  if (j == 0)
+		    elements[i] = newel;
+		  else
+		    elements.Append (newel); 
+
+		  
+		}
+
+	      /*     const ELEMENT_EDGE * edges = MeshTopology::GetEdges (HEX);
+	       
+		for(int k=0;k<12;k++) 
+		  { 
+		    int e[2];  
+		    for(int l=0;l<2;l++) e[l] = edges[k][l]-1; 
+		    if(el.PNum(e[0]+1)!=el.PNum(e[1]+1)) 
+		      { 
+			newel.SetType(HP_SEGM);
+			for(int l=0;l<2;l++) 
+			  { 
+			    newel.pnums[0] = el.PNum(e[l]+1); 
+			    newel.pnums[1] = npi; 
+			    for(int j=0;j<3;j++) 
+			      {
+				//	newel.param[0][j] = el.param[e[l]][j]; 
+				//	newel.param[1][j] = newparam[j]; 
+			      } 
+			    
+			    elements.Append(newel);
+			  }
+			newel.SetType(HP_TRIG);
+			newel.pnums[0] = el.PNum(e[0]+1); 			
+			newel.pnums[1] = el.PNum(e[1]+1); 			
+			newel.pnums[2] = npi; 
+			
+			*testout << "DEGHEX TRIG :: newpnums " << newel.pnums[0] << "\t"  << newel.pnums[1] << "\t"  << newel.pnums[2] << endl;  
+	cout << "DEGHEX TRIG :: newpnums " << newel.pnums[0] << "\t"  << newel.pnums[1] << "\t"  << newel.pnums[2] << endl;  
+			for(int j=0;j<3;j++) 
+			  {
+			    // newel.param[0][j] = el.param[e[0]][j]; 
+			    //   newel.param[1][j] = el.param[e[1]][j]; 
+			    //   newel.param[2][j] = newparam[j]; 
+			  } 
+			
+			elements.Append(newel);
+		      }
+			
+		      }*/
+	    }
+	}
+  }
+
+
+  void CalcStatistics (Array<HPRefElement> & elements)
+  {
+    return;
+#ifdef ABC    
+    int i, p;
+    int nsegm = 0, ntrig = 0, nquad = 0;
+    int nhex = 0, nprism = 0, npyramid = 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 (Get_HPRef_Struct (el.type)->geom)
+	  {
+	  case HP_SEGM:
+
+	    {
+	      nsegm++;
+	      break;
+	    }
+	  case HP_TRIG:
+	    {
+	      ntrig ++;
+	      break;
+	    }
+	  case HP_QUAD:
+	    {
+	      nquad++;
+	      break;
+	    }
+	  case HP_TET:
+	    {
+	      ntet++;
+	      break;
+	    }
+
+	  case HP_PRISM:
+	    {
+	      nprism++;
+	      break;
+	    }
+
+	  case HP_PYRAMID:
+	    {
+	      npyramid++;
+	      break;
+	    }
+
+	  case HP_HEX:
+	    {	
+	      nhex++;
+	      break;
+	    }
+
+	  default:
+	    {
+	      cerr << "statistics error, unknown element type" << endl;
+	    }
+	  }
+      }
+
+    cout << "level = " << maxlevel << endl;
+    cout << "nsegm = " << nsegm << endl;
+    cout << "ntrig = " << ntrig << ", nquad = " << nquad << endl;
+    cout << "ntet = " << ntet << ", npyr = " << npyramid
+	 << ", nprism = " << nprism << ", nhex = " << nhex << endl;
+
+    return;
+
+    double memcost = 0, cpucost = 0;
+    for (p = 1; p <= 20; p++)
+      {
+	memcost = (ntet + nprism + nhex) * pow (static_cast<double>(p), 6.0);
+	cpucost = (ntet + nprism + nhex) * pow (static_cast<double>(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 (static_cast<double>(p1), 6.0)
+			 << " (p1-3)^6 = " << pow ( static_cast<double>(max2(p1-3, 0)), 6.0) 
+			 << " p1^3 = " << pow ( static_cast<double>(p1), 3.0) 
+			 << " (p1-3)^3 = " << pow ( static_cast<double>(p1-3), 3.0) 
+			 << " [p1^3-(p1-3)^3]^2 = " << sqr (pow (static_cast<double>(p1),3.0) - pow ( static_cast<double>(p1-3), 3.0))
+			 << endl;
+
+	      p1 /= 2 +1;
+	      memcosttet += pow (static_cast<double>(p1), 6.0);
+	      memcostsctet += pow (static_cast<double>(p1), 6.0) - pow ( static_cast<double>(max2(p1-3, 1)), 6.0);
+	      cpucosttet += pow (static_cast<double>(p1), 9.0);
+	      break;
+	    }
+	  case HP_PRISM:
+	  case HP_PRISM_SINGEDGE:
+	    {
+	      int p1 = maxlevel - el.level + 1;
+	      p1 /= 2 +1;
+	      memcostprism += pow (static_cast<double>(p1), 6.0);
+	      memcostscprism += pow (static_cast<double>(p1), 6.0) - pow ( static_cast<double>(max2(p1-3, 1)), 6.0);
+	      cpucostprism += pow (static_cast<double>(p1), 9.0);
+	      break;
+	    }
+	  case HP_HEX:
+	    {	
+	      int p1 = maxlevel - el.level + 1;
+	      int p2 = maxlevel;
+	      p1 /= 2 +1;
+	      p2 /= 2 +1;
+	      memcosthex += pow (static_cast<double>(p1), 4.0) * pow (static_cast<double>(p2), 2.0);
+	      memcostschex += pow (static_cast<double>(p1), 6.0) - pow ( static_cast<double>(max2(p1-2, 0)), 6.0);
+	      cpucosthex += pow (static_cast<double>(p1), 6.0) * pow (static_cast<double>(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;
+#endif
+  }
+
+
+
+  void ReorderPoints (Mesh & mesh, Array<HPRefElement> & hpelements)
+  {
+    Array<int, 1> map (mesh.GetNP());
+    
+    for (int i = 1; i <= mesh.GetNP(); i++)
+      map[i] = i;
+
+    int nwrong(0), nright(0);
+    for (int k = 0; k < 5; k++)
+      {
+        nwrong = nright = 0;
+        for (int i = 0; i < hpelements.Size(); i++)
+          {
+            const HPRefElement & hpel = hpelements[i];
+            
+            if (Get_HPRef_Struct (hpel.type) -> geom == HP_PRISM)
+              {
+                int minbot = 0, mintop = 0;
+                for (int j = 0; j < 3; j++)
+                  {
+                    if (map[hpel.pnums[j]] < map[hpel.pnums[minbot]]) minbot = j;
+                    if (map[hpel.pnums[j+3]] < map[hpel.pnums[mintop+3]]) mintop = j;
+                  }
+                if (minbot != mintop) 
+                  nwrong++;
+                else
+                  nright++;
+                
+                if (minbot != mintop)
+                  {
+                    if (map[hpel.pnums[minbot]] < map[hpel.pnums[mintop+3]])
+                      swap (map[hpel.pnums[3+minbot]], map[hpel.pnums[3+mintop]]);
+                    else
+                      swap (map[hpel.pnums[minbot]], map[hpel.pnums[mintop]]);
+                  }
+              }
+          }
+        // cout << nwrong << " wrong prisms, " << nright << " right prisms" << endl;
+      }
+
+    cout << nwrong << " wrong prisms, " << nright << " right prisms" << endl;
+
+
+    Array<MeshPoint, 1> hpts(mesh.GetNP());
+
+    for (int i = 1; i <= mesh.GetNP(); i++)
+      hpts[map[i]] = mesh.Point(i);
+
+    for (int i = 1; i <= mesh.GetNP(); i++)
+      mesh.Point(i) = hpts[i];
+
+    for (int i = 0; i < hpelements.Size(); i++)
+      {
+        HPRefElement & hpel = hpelements[i];
+        for (int j = 0; j < hpel.np; j++)
+          hpel.pnums[j] = map[hpel.pnums[j]];
+      }
+  }
+
+
+
+  /* ***************************** HPRefinement ********************************** */
+
+  void HPRefinement (Mesh & mesh, Refinement * ref, int levels, double fac1, bool setorders, bool reflevels)
+  {
+    PrintMessage (1, "HP Refinement called, levels = ", levels);
+
+ 
+    // NgLock mem_lock (mem_mutex,1);
+
+    mesh.coarsemesh = new Mesh; 
+    *mesh.coarsemesh = mesh;
+    
+    // #ifdef CURVEDELEMS_NEW
+    const_cast<CurvedElements&> (mesh.coarsemesh->GetCurvedElements() ).
+      BuildCurvedElements (ref, mesh.GetCurvedElements().GetOrder());
+    // #endif
+
+
+    delete mesh.hpelements;
+    mesh.hpelements = new Array<HPRefElement>;
+        
+    Array<HPRefElement> & hpelements = *mesh.hpelements; 
+        
+    InitHPElements(mesh,hpelements); 
+    
+    Array<int> nplevel;
+    nplevel.Append (mesh.GetNP());
+    
+    int act_ref=1;
+    bool sing = ClassifyHPElements (mesh,hpelements, act_ref, levels); 
+
+    sing = true; // iterate at least once
+    while(sing) 
+      {
+	cout << " Start new hp-refinement: step " <<  act_ref  << endl; 
+		
+	DoRefinement (mesh, hpelements, ref, fac1); 
+	DoRefineDummies (mesh, hpelements, ref);
+	
+	nplevel.Append (mesh.GetNP());
+	CalcStatistics (hpelements);
+	
+	SubdivideDegeneratedHexes (mesh, hpelements,fac1);
+
+        ReorderPoints (mesh, hpelements);
+
+	mesh.ClearSegments();
+	mesh.ClearSurfaceElements();
+  	mesh.ClearVolumeElements();
+
+	for (int i = 0; i < hpelements.Size(); i++)
+	  {
+	    HPRefElement & hpel = hpelements[i];
+	    if (Get_HPRef_Struct (hpel.type))
+	      switch (Get_HPRef_Struct (hpel.type) -> geom)
+		{
+		case HP_SEGM:
+		  {
+		    Segment seg;
+		    seg[0] = hpel.pnums[0];
+		    seg[1] = hpel.pnums[1];
+		    // NOTE: only for less than 10000 elements (HACK) !!!
+		    seg.edgenr = hpel.index % 10000;
+		    seg.si     = hpel.index / 10000;
+
+                    /*
+                    seg.epgeominfo[0].dist = hpel.param[0][0]; // he: war hpel.param[0][0]
+                    seg.epgeominfo[1].dist = hpel.param[1][0]; // he: war hpel.param[1][0]
+                    */
+                    
+                    const Segment & coarseseg = mesh.coarsemesh->LineSegment(hpel.coarse_elnr+1);
+                    double d1 = coarseseg.epgeominfo[0].dist;
+                    double d2 = coarseseg.epgeominfo[1].dist;
+
+                    // seg.epgeominfo[0].dist = hpel.param[0][0]; // he: war hpel.param[0][0]
+                    // seg.epgeominfo[1].dist = hpel.param[1][0]; // he: war hpel.param[1][0]
+
+                    seg.epgeominfo[0].dist = d1 + hpel.param[0][0] * (d2-d1); // JS, June 08
+                    seg.epgeominfo[1].dist = d1 + hpel.param[1][0] * (d2-d1); 
+
+
+		    seg.epgeominfo[0].edgenr = seg.edgenr;
+		    seg.epgeominfo[1].edgenr = seg.edgenr;
+                    seg.domin = hpel.domin; seg.domout=hpel.domout; // he: needed for segments!
+		    seg.hp_elnr = i;
+		    seg.singedge_left = hpel.singedge_left; 
+		    seg.singedge_right = hpel.singedge_right; 
+		    mesh.AddSegment (seg); 
+		    break;
+		  }
+		  
+		case HP_TRIG: 
+		case HP_QUAD: 
+		  { 
+		    Element2d el(hpel.np); 
+		    for(int j=0;j<hpel.np;j++) 
+		      el.PNum(j+1) = hpel.pnums[j]; 
+		    el.hp_elnr = i; 
+		    el.SetIndex(hpel.index);
+		    if(setorders)
+		      el.SetOrder(act_ref+1,act_ref+1,0); 
+		    mesh.AddSurfaceElement(el);
+		    break; 
+		  } 
+		case HP_HEX:
+		case HP_TET:
+		case HP_PRISM:
+		case HP_PYRAMID:
+		  { 
+		    Element el(hpel.np); 
+		    for(int j=0;j<hpel.np;j++) 
+		      el.PNum(j+1) = hpel.pnums[j]; 
+		    el.SetIndex(hpel.index); 
+		    el.hp_elnr = i; 
+		    if(setorders)
+		      el.SetOrder(act_ref+1,act_ref+1,act_ref+1);
+		    mesh.AddVolumeElement(el); 
+		    break;
+		  } 
+		      
+		default:
+		  PrintSysError ("hpref, backconversion failed for element ", 
+				 int(Get_HPRef_Struct (hpel.type) -> geom));
+		}
+	  }
+	cout << " Start with Update Topology " << endl; 
+	mesh.UpdateTopology();
+	cout << " Mesh Update Topology done " << endl; 
+
+	act_ref++; 
+	
+	sing = ClassifyHPElements(mesh,hpelements, act_ref, levels); 
+      }
+
+    cout << " HP-Refinement done with " << --act_ref << " refinement steps." << endl; 
+
+    if(act_ref>=1)
+      { 
+	for(ElementIndex i=0;i<mesh.GetNE(); i++) 
+	  { 
+	    Element el = mesh[i] ;
+	    HPRefElement & hpel = hpelements[mesh[i].hp_elnr];
+	    const ELEMENT_EDGE * edges = MeshTopology::GetEdges1 (mesh[i].GetType());
+	    double dist[3] = {0,0,0}; 
+	    int ord_dir[3] = {0,0,0}; 
+	    int edge_dir[12] = {0,0,0,0,0,0,0,0,0,0,0,0}; 
+	    int ned = 4; 
+	    
+	    switch (mesh[i].GetType())
+	      {
+	      case TET: 
+		/* cout << " TET " ; 
+		for(int k=0;k<4;k++) cout << el[k] << "\t" ; 
+		cout << endl; */ 
+		break; 
+	      case PRISM:
+		/* cout << " PRISM " ; 
+		for(int k=0;k<6;k++) cout << el[k] << "\t" ; 
+		cout << endl;  */ 
+		for(int l=6;l<9;l++) edge_dir[l] = 2; 
+		ord_dir[2] = 2; 
+		ned = 9; 
+		break; 
+	      case HEX: 
+		/* cout << " HEX " ; 
+		for(int k=0;k<8;k++) cout << el[k] << "\t" ; 
+		cout << endl; */
+		for(int l=8;l<12; l++) edge_dir[l] = 2; 
+		edge_dir[2] = edge_dir[3] = edge_dir[6] = edge_dir[7] = 1;
+		ord_dir[1] = 1; 
+		ord_dir[2] = 2; 
+		ned = 12; 
+		break;  
+	      case PYRAMID: 
+		/*	cout << " PYRAMID " ; 
+		for(int k=0;k<5;k++) cout << el[k] << "\t" ; 
+		cout << endl; */ 
+		for(int l=4;l<8;l++) edge_dir[l] = 2; 
+		edge_dir[2] = edge_dir[3] = 1; 
+		ord_dir[1] = 1; 
+		ord_dir[2] = 2; 
+		ned = 8;  
+		break; 
+
+
+              default:
+                cerr << "HPRefElement: illegal elementtype (2) " << mesh[i].GetType() << endl;
+                throw NgException ("HPRefElement: illegal elementtype (2)");
+                
+	      }
+	
+	    for (int j=0;j<ned;j++) 
+	      { 
+			
+		Vec<3> v(hpel.param[edges[j][0]-1][0]-hpel.param[edges[j][1]-1][0],
+			    hpel.param[edges[j][0]-1][1]-hpel.param[edges[j][1]-1][1],
+			    hpel.param[edges[j][0]-1][2]-hpel.param[edges[j][1]-1][2]);
+		dist[edge_dir[j]] = max(v.Length(),dist[edge_dir[j]]);
+	      }
+	    
+	    int refi[3];  
+	    for(int j=0;j<3;j++) 
+	      refi[j] = int(max(double(floor(log(dist[ord_dir[j]]/sqrt(2.))/log(fac1))),0.)); 	
+	    
+	    // cout << " ref " << refi[0] << "\t" << refi[1] << "\t" << refi[2] << endl; 
+	    // cout << " order " << act_ref +1 - refi[0] << "\t" << act_ref +1 - refi[1] << "\t" << act_ref +1 - refi[2] << endl; 
+	   	      
+	    if(setorders)
+	      mesh[i].SetOrder(act_ref+1-refi[0],act_ref+1-refi[1],act_ref+1-refi[2]); 
+	  }
+	for(SurfaceElementIndex i=0;i<mesh.GetNSE(); i++) 
+	  { 
+	    Element2d el = mesh[i] ;
+	    HPRefElement & hpel = hpelements[mesh[i].hp_elnr];
+	    const ELEMENT_EDGE * edges = MeshTopology::GetEdges1 (mesh[i].GetType());
+	    double dist[3] = {0,0,0}; 
+	    int ord_dir[3] = {0,0,0}; 
+	    int  edge_dir[4] = {0,0,0,0} ; 
+	    int ned = 3; 
+	   
+	    if(mesh[i].GetType() == QUAD)
+	      {
+		/*	cout << " QUAD " ; 
+		for(int k=0;k<4;k++) cout << el[k] << "\t" ; 
+		cout << endl; 	*/ 
+ 
+		edge_dir[2] = edge_dir[3] = 1; 
+		ord_dir[1] = 1; 
+		ned = 4; 
+	      }
+	    /*  else 
+	      { 
+		cout << " TRIG " ; 
+		for(int k=0;k<3;k++) cout << el[k] << "\t" ; 
+		cout << endl; 
+		} */ 
+	    
+	    for (int j=0;j<ned;j++) 
+	      { 
+		Vec<3> v(hpel.param[edges[j][0]-1][0]-hpel.param[edges[j][1]-1][0],
+			    hpel.param[edges[j][0]-1][1]-hpel.param[edges[j][1]-1][1],
+			    hpel.param[edges[j][0]-1][2]-hpel.param[edges[j][1]-1][2]);
+		dist[edge_dir[j]] = max(v.Length(),dist[edge_dir[j]]);
+	      }
+	    
+	    int refi[3]; 
+	    for(int j=0;j<3;j++) 
+	      refi[j] = int(max(double(floor(log(dist[ord_dir[j]]/sqrt(2.))/log(fac1))),0.)); 	
+	    
+	    if(setorders)
+	      mesh[i].SetOrder(act_ref+1-refi[0],act_ref+1-refi[1],act_ref+1-refi[2]); 
+
+	      // cout << " ref " << refi[0] << "\t" << refi[1] << endl; 
+	      // cout << " order " << act_ref +1 - refi[0] << "\t" << act_ref +1 - refi[1] << endl; 
+	  }
+      }
+  }
+
+bool CheckSingularities(Mesh & mesh, INDEX_2_HASHTABLE<int> & edges, INDEX_2_HASHTABLE<int> & edgepoint_dom, 
+		       BitArray & cornerpoint, BitArray & edgepoint, INDEX_3_HASHTABLE<int> & faces, INDEX_2_HASHTABLE<int> & face_edges, 
+			INDEX_2_HASHTABLE<int> & surf_edges, Array<int, PointIndex::BASE> & facepoint, int & levels, int & act_ref)
+{ 
+  bool sing = 0; 
+  if (mesh.GetDimension() == 3)
+    {
+	/*
+	// check, if point has as least 3 different surfs:
+
+	Array<INDEX_3, PointIndex::BASE> surfonpoint(mesh.GetNP());
+  	surfonpoint = INDEX_3(0,0,0);
+
+	for (SurfaceElementIndex sei = 0; sei < mesh.GetNSE(); sei++)
+	  {
+	    const Element2d & el = mesh[sei];
+	    int ind = el.GetIndex();
+	    for (int j = 0; j < el.GetNP(); j++)
+	      {
+		INDEX_3 & i3 = surfonpoint[el[j]];
+		if (ind != i3.I1() && ind != i3.I2() && ind != i3.I3())
+		  {
+		    i3.I1() = i3.I2();
+		    i3.I2() = i3.I3();
+		    i3.I3() = ind;
+		  }
+	      }
+	  }
+	for (int i = 1; i <= mesh.GetNP(); i++)
+	  if (surfonpoint.Get(i).I1())
+	    cornerpoint.Set(i);
+	*/
+	cornerpoint.Clear();
+	
+	for (int i = 1; i <= mesh.GetNP(); i++)
+	  {
+	    if (mesh.Point(i).Singularity() * levels >= act_ref)
+	      {
+		cornerpoint.Set(i);
+		sing = 1; 
+	      } 
+	  }
+	cout << endl; 
+
+	for (int i = 1; i <= mesh.GetNSeg(); i++)
+	  if (mesh.LineSegment(i).singedge_left * levels >= act_ref)
+	    {
+	      INDEX_2 i2 (mesh.LineSegment(i)[0], 
+			  mesh.LineSegment(i)[1]);
+
+	      /*
+		// before
+	      edges.Set (i2, 1);
+	      i2.Sort();   
+	      INDEX_2 i2s(i2.I2(), i2.I1());
+	      edges.Set (i2s, 1);
+	      */
+
+	      edges.Set (i2, 1);
+	      INDEX_2 i2s(i2.I2(), i2.I1());
+	      edges.Set (i2s, 1);
+
+
+	      edgepoint.Set (i2.I1());
+	      edgepoint.Set (i2.I2());
+	      sing = 1; 
+	    }
+
+	// if 2 adjacent edges of an element are singular, the 
+	// commen point must be a singular point
+	for (int i = 1; i <= mesh.GetNE(); i++)
+	  {
+	    const Element & el = mesh.VolumeElement(i);
+	    const ELEMENT_EDGE * eledges = MeshTopology::GetEdges1 (el.GetType());
+	    int nedges = MeshTopology::GetNEdges (el.GetType());
+	    for (int j = 0; j < nedges; j++)
+	      for (int k = 0; k < nedges; k++)
+		if (j != k)
+		  {
+		    INDEX_2 ej(el.PNum(eledges[j][0]), el.PNum(eledges[j][1]));
+		    ej.Sort();
+		    INDEX_2 ek(el.PNum(eledges[k][0]), el.PNum(eledges[k][1]));
+		    ek.Sort();
+		    if (edges.Used(ej) && edges.Used(ek))
+		      {
+			if (ej.I1() == ek.I1()) cornerpoint.Set (ek.I1());
+			if (ej.I1() == ek.I2()) cornerpoint.Set (ek.I2());
+			if (ej.I2() == ek.I1()) cornerpoint.Set (ek.I1());
+			if (ej.I2() == ek.I2()) cornerpoint.Set (ek.I2());
+		      }
+		  }
+	  }
+
+	edgepoint.Or (cornerpoint);
+	(*testout) << "cornerpoint = " << endl << cornerpoint << endl;
+	(*testout) << "edgepoint = " << endl << edgepoint << endl;
+
+	facepoint = 0;
+	for (SurfaceElementIndex sei = 0; sei < mesh.GetNSE(); sei++)
+	  {
+	    const Element2d & el = mesh[sei];
+	    const FaceDescriptor & fd = mesh.GetFaceDescriptor (el.GetIndex());
+	  
+	    int domnr = 0;
+	    if (fd.DomainInSingular() * levels < act_ref && fd.DomainOutSingular() * levels < act_ref) 
+	      { domnr=0;  continue;}
+	    
+	    if (fd.DomainInSingular() * levels >= act_ref) 
+	      {
+		domnr = fd.DomainIn();
+		sing = 1;
+	      }
+	    if (fd.DomainOutSingular() * levels >= act_ref)
+	      {
+		domnr = fd.DomainOut();
+		sing = 1; 
+	      } 
+	    if (fd.DomainInSingular() * levels >= act_ref 
+		&& fd.DomainOutSingular() * levels >= act_ref) 
+	      {
+		domnr = -1;
+		sing = 1;
+	      } 
+  
+	    INDEX_3 i3;
+	    if (el.GetNP() == 3) 
+	      i3 = INDEX_3::Sort (el[0], el[1], el[2]);
+	    else
+	      {
+		INDEX_4 i4 (el[0], el[1], el[2], el[3]);
+		i4.Sort();
+		i3 = INDEX_3(i4.I1(), i4.I2(), i4.I3());
+	      }
+	    faces.Set (i3, domnr);
+	
+	    for (int j = 0; j < el.GetNP(); j++)
+	      {
+		face_edges.Set (INDEX_2::Sort (el[j], el[(j+1)%el.GetNP()]), domnr);
+	
+		surf_edges.Set (INDEX_2::Sort (el[j], el[(j+1)%el.GetNP()]), fd.SurfNr()+1);
+		
+		facepoint[el[j]] = domnr;
+	      }
+	   
+	  }
+	(*testout) << "singular faces = " << faces << endl;
+	(*testout) << "singular faces_edges = " << face_edges << endl;
+      }
+    else
+      {
+	// 2D case
+
+	// check, if point has as least 3 different surfs:
+	Array<INDEX_3, PointIndex::BASE> surfonpoint(mesh.GetNP());
+
+	for (int i = 1; i <= mesh.GetNP(); i++)
+	  surfonpoint.Elem(i) = INDEX_3(0,0,0);
+	
+	for (int i = 1; i <= mesh.GetNSeg(); i++)
+	  {
+	    const Segment & seg = mesh.LineSegment(i);
+	    int ind = seg.edgenr;
+	    
+	    if (seg.singedge_left * levels >= act_ref)
+	      {
+		INDEX_2 i2 (mesh.LineSegment(i)[0], 
+			    mesh.LineSegment(i)[1]);
+		edges.Set(i2,1); 
+		edgepoint.Set(i2.I1());
+		edgepoint.Set(i2.I2());
+		*testout << " singleft " << endl;  
+		*testout << " mesh.LineSegment(i).domout " << mesh.LineSegment(i).domout << endl;      
+		*testout << " mesh.LineSegment(i).domin " << mesh.LineSegment(i).domin << endl;      
+		edgepoint_dom.Set (INDEX_2(mesh.LineSegment(i).domin, i2.I1()), 1);
+		edgepoint_dom.Set (INDEX_2(mesh.LineSegment(i).domin, i2.I2()), 1);
+		sing = 1; 
+		
+	      }
+	    
+	    if (seg.singedge_right * levels >= act_ref)
+	      {
+		INDEX_2 i2 (mesh.LineSegment(i)[1], 
+			    mesh.LineSegment(i)[0]);  
+		edges.Set (i2, 1);
+		edgepoint.Set(i2.I1());
+		edgepoint.Set(i2.I2());
+		
+		*testout << " singright " << endl;  
+		*testout << " mesh.LineSegment(i).domout " << mesh.LineSegment(i).domout << endl;      
+		*testout << " mesh.LineSegment(i).domin " << mesh.LineSegment(i).domin << endl;      
+		
+		edgepoint_dom.Set (INDEX_2(mesh.LineSegment(i).domout, i2.I1()), 1);
+		edgepoint_dom.Set (INDEX_2(mesh.LineSegment(i).domout, i2.I2()), 1);
+		sing = 1;
+	      }
+	    
+	    // (*testout) << "seg = " << ind << ", " << seg[0] << "-" << seg[1] << endl;
+	    
+
+	    if (seg.singedge_left * levels >= act_ref
+		|| seg.singedge_right* levels >= act_ref)
+	      {
+		for (int j = 0; j < 2; j++)
+		  {
+		    int pi = (j == 0) ? seg[0] : seg[1];
+		    INDEX_3 & i3 = surfonpoint.Elem(pi);
+		    if (ind != i3.I1() &&
+			ind != i3.I2())
+		      {
+			i3.I1() = i3.I2();
+			i3.I2() = ind;
+		      }
+		  }
+	      }
+	  }
+
+
+	for (int i = 1; i <= mesh.GetNP(); i++)
+	  {
+	    // mark points for refinement that are in corners between two anisotropic edges 
+	    if (surfonpoint.Get(i).I1())
+	      {
+		// cornerpoint.Set(i);    // disabled by JS, Aug 2009
+		edgepoint.Set(i);
+	      }
+	
+	    // mark points for refinement that are explicity specified in input file
+	    if (mesh.Point(i).Singularity()*levels >= act_ref)
+	      {
+		cornerpoint.Set(i);
+		edgepoint.Set(i);
+		sing =  1; 
+	      }
+	  }
+
+	edgepoint.Or (cornerpoint);
+
+	(*testout) << "2d sing edges: " << endl << edges << endl;
+	(*testout) << "2d cornerpoints: " << endl << cornerpoint << endl
+		   << "2d edgepoints: " << endl << edgepoint << endl;
+	
+	facepoint = 0;
+      }
+
+    if (!sing)
+      cout << "PrepareElements no more to do for actual refinement " << act_ref << endl; 
+
+    return(sing); 
+}
+
+
+
+  bool ClassifyHPElements (Mesh & mesh, Array<HPRefElement> & elements, int & act_ref, int & levels)
+  {
+    INDEX_2_HASHTABLE<int> edges(mesh.GetNSeg()+1);
+    BitArray edgepoint(mesh.GetNP());
+    INDEX_2_HASHTABLE<int> edgepoint_dom(mesh.GetNSeg()+1);
+
+    edgepoint.Clear();
+    BitArray cornerpoint(mesh.GetNP());
+    cornerpoint.Clear();
+
+    // value = nr > 0 ... refine elements in domain nr
+    // value = -1   ..... refine elements in any domain
+    INDEX_3_HASHTABLE<int> faces(mesh.GetNSE()+1);
+    INDEX_2_HASHTABLE<int> face_edges(mesh.GetNSE()+1);
+    INDEX_2_HASHTABLE<int> surf_edges(mesh.GetNSE()+1);
+    Array<int, PointIndex::BASE> facepoint(mesh.GetNP());
+
+    bool sing = CheckSingularities(mesh, edges, edgepoint_dom, 
+			      cornerpoint, edgepoint, faces, face_edges, 
+			      surf_edges, facepoint, levels, act_ref); 
+  
+    if(sing==0) return(sing); 
+
+    int cnt_undef = 0, cnt_nonimplement = 0;
+    Array<int> misses(10000);
+    misses = 0;
+
+    (*testout) << "edgepoint_dom = " << endl << edgepoint_dom << endl;
+
+    for( int i = 0; i<elements.Size(); i++) 
+      {
+	// *testout << "classify element " << i << endl;
+
+	HPRefElement & hpel = elements[i]; 
+	HPRef_Struct * hprs = Get_HPRef_Struct (hpel.type);
+	HPRefElement old_el = elements[i]; 
+	int dd=3; 
+
+
+	if(act_ref !=1 && (hpel.type == HP_HEX || hpel.type == HP_PRISM || hpel.type == HP_TET 
+			   || hpel.type == HP_PYRAMID || hpel.type == HP_QUAD || hpel.type == HP_TRIG || hpel.type == HP_SEGM)) 
+	  continue; 
+	
+	sing = 1; 
+	switch (hprs->geom)
+	  {
+	  case HP_TET:
+	    {
+	      hpel.type = ClassifyTet(hpel, edges, edgepoint_dom, cornerpoint, edgepoint, faces,face_edges, surf_edges, facepoint); 
+	      break;
+	    }
+	  case HP_PRISM:
+	    {
+	      hpel.type = ClassifyPrism(hpel, edges, edgepoint_dom, cornerpoint, edgepoint, faces,
+					face_edges, surf_edges, facepoint); 	    	    
+	 
+	    
+	      break;
+	    }
+	  case HP_HEX:
+	    { 
+	      hpel.type = hpel.type = ClassifyHex(hpel, edges, edgepoint_dom, cornerpoint, edgepoint, faces,
+						  face_edges, surf_edges, facepoint); 	    	    
+	      break; 
+	    } 
+	  case HP_TRIG: 
+	    { 
+	      int dim = mesh.GetDimension(); 
+	      const FaceDescriptor & fd = mesh.GetFaceDescriptor (hpel.GetIndex());	
+	      
+	      hpel.type = ClassifyTrig(hpel, edges, edgepoint_dom, cornerpoint, edgepoint, 
+				       faces, face_edges, surf_edges, facepoint, dim, fd);    
+	     
+	      dd = 2; 
+	      break; 
+	    } 
+	  case HP_QUAD: 
+	    { 
+	      int dim = mesh.GetDimension(); 
+	      const FaceDescriptor & fd = mesh.GetFaceDescriptor (hpel.GetIndex());	
+	      hpel.type = ClassifyQuad(hpel, edges, edgepoint_dom, cornerpoint, edgepoint, 
+				  faces, face_edges, surf_edges, facepoint, dim, fd);    
+
+	      dd = 2; 
+	      break; 
+	    }
+	  case HP_SEGM: 
+	    {
+	      hpel.type = ClassifySegm(hpel, edges, edgepoint_dom, cornerpoint, edgepoint, 
+				       faces, face_edges, surf_edges, facepoint);    
+	      dd = 1; 
+	      break; 
+	    }
+	  case HP_PYRAMID: 
+	    {
+	      hpel.type = ClassifyPyramid(hpel, edges, edgepoint_dom, cornerpoint, edgepoint, faces,
+						  face_edges, surf_edges, facepoint); 	    	    
+	      
+	      cout << " ** Pyramid classified  " << hpel.type << endl; 
+	      break; 
+	    }
+	  default:
+	    {
+	      cout << "illegal element type for hp-prepare elements " << hpel.type << endl;
+	      throw NgException ("hprefinement.cpp: don't know how to set parameters");
+	    }
+	  }
+	    
+	if(hpel.type == HP_NONE) 
+	  cnt_undef++; 
+
+	//else 
+	//cout << "elem " << i << " classified type " << hpel.type << endl; 
+
+	
+	
+	if (!Get_HPRef_Struct (hpel.type)) 
+	  {
+	    (*testout) << "hp-element-type " << hpel.type << " not implemented   " << endl;
+	    (*testout) << " elType " << hprs->geom << endl; 
+ (cout) << " elType " << hprs->geom << endl;        
+	    cnt_nonimplement++;
+	    misses[hpel.type]++;
+	  }
+	
+  
+	for(int j=0; j<hpel.np; j++)
+	  {
+	    for( int k=0; k<hpel.np; k++) 
+	      if(hpel[j] == old_el.pnums[k]) 
+		{ 
+		  for(int l=0;l<dd;l++) 
+		    hpel.param[j][l] = old_el.param[k][l];
+		  break;
+		}
+	  } 
+
+      }
+    
+    
+    cout << "undefined elements update classification: " << cnt_undef << endl;
+    cout << "non-implemented in update classification: " << cnt_nonimplement << endl;
+
+    for (int i = 0; i < misses.Size(); i++)
+      if (misses[i])
+	cout << " in update classification missing case " << i << " occured " << misses[i] << " times" << endl;
+
+    return(sing); 
+  }
+}
+  
diff --git a/contrib/Netgen/libsrc/meshing/hprefinement.hpp b/contrib/Netgen/libsrc/meshing/hprefinement.hpp
new file mode 100644
index 0000000000..f299ae8aa1
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/hprefinement.hpp
@@ -0,0 +1,319 @@
+#ifndef FILE_HPREFINEMENT
+#define FILE_HPREFINEMENT
+
+/**************************************************************************/
+/* File:   hprefinement.hh                                                */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   27. Oct. 2000                                                  */
+/**************************************************************************/
+
+/*
+  HP Refinement
+*/
+
+
+
+
+enum HPREF_ELEMENT_TYPE {
+  HP_NONE=0,
+
+  HP_SEGM = 1,
+  HP_SEGM_SINGCORNERL,
+  HP_SEGM_SINGCORNERR,
+  HP_SEGM_SINGCORNERS,
+
+  HP_TRIG = 10,
+  HP_TRIG_SINGCORNER,
+  HP_TRIG_SINGCORNER12,
+  HP_TRIG_SINGCORNER123,
+  HP_TRIG_SINGCORNER123_2D,   // not rotational symmetric
+  HP_TRIG_SINGEDGE = 20,
+  HP_TRIG_SINGEDGECORNER1,   // E = 100, V = 100
+  HP_TRIG_SINGEDGECORNER2,   // E = 100, V = 010
+  HP_TRIG_SINGEDGECORNER12,  // E = 100, V = 110
+  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_0E_2VA,  // V = 1100
+  HP_QUAD_0E_2VB,  // V = 1010
+  HP_QUAD_0E_3V,
+  HP_QUAD_0E_4V,
+
+  // one edge: marked edge is always edge from vertex 1 to vertex 2 (E = 1000)
+  HP_QUAD_1E_1VA,  // vertex on beginning of edge: V = 1000
+  HP_QUAD_1E_1VB,  // vertex on end of edge: V = 0100
+  HP_QUAD_1E_1VC,  // V = 0010
+  HP_QUAD_1E_1VD,  // V = 0001
+
+  HP_QUAD_1E_2VA,  // V = 1100
+  HP_QUAD_1E_2VB,  // V = 1010
+  HP_QUAD_1E_2VC,  // V = 1001
+  HP_QUAD_1E_2VD,  // V = 0110
+  HP_QUAD_1E_2VE,  // V = 0101
+  HP_QUAD_1E_2VF,  // V = 0011
+
+  HP_QUAD_1E_3VA,  // V = 1110
+  HP_QUAD_1E_3VB,  // V = 1101
+  HP_QUAD_1E_3VC,  // V = 1011
+  HP_QUAD_1E_3VD,  // V = 0111
+
+  HP_QUAD_1E_4V,   // V = 1111
+
+
+  HP_QUAD_2E,      // E = 1001, V = 1000
+  HP_QUAD_2E_1VA,  // E = 1001, V = 1100
+  HP_QUAD_2E_1VB,  // E = 1001, V = 1010
+  HP_QUAD_2E_1VC,  // E = 1001, V = 1001
+  HP_QUAD_2E_2VA,  // E = 1001, V = 1110
+  HP_QUAD_2E_2VB,  // E = 1001, V = 1101
+  HP_QUAD_2E_2VC,  // E = 1001, V = 1011
+  HP_QUAD_2E_3V,   // E = 1001, V = 1111
+
+  HP_QUAD_2EB_0V,   // E = 1010, V = 0000
+  HP_QUAD_2EB_1VA,  // E = 1010, V = 1000
+  HP_QUAD_2EB_1VB,  // E = 1010, V = 0100
+  HP_QUAD_2EB_2VA,  // E = 1010, V = 1100
+  HP_QUAD_2EB_2VB,  // E = 1010, V = 1010
+  HP_QUAD_2EB_2VC,  // E = 1010, V = 1001
+  HP_QUAD_2EB_2VD,  // E = 1010, V = 0101
+  HP_QUAD_2EB_3VA,  // E = 1010, V = 1110
+  HP_QUAD_2EB_3VB,  // E = 1010, V = 1101
+
+  HP_QUAD_2EB_4V,
+
+
+  HP_QUAD_3E,      // E = 1101, V = 1100
+  HP_QUAD_3E_3VA,  // E = 1101, V = 1110
+  HP_QUAD_3E_3VB,  // E = 1101, V = 1101
+  HP_QUAD_3E_4V,   // E = 1101, V = 1111
+
+  HP_QUAD_4E,
+
+
+  HP_TET = 100,     // no singular vertex/edge
+  HP_TET_0E_1V,     // V1
+  HP_TET_0E_2V,     // V1,2
+  HP_TET_0E_3V,     // V1,2,3  
+  HP_TET_0E_4V,     // V1,2,3,4
+  HP_TET_1E_0V = 200,   // E1-2
+  HP_TET_1E_1VA,    // V1
+  HP_TET_1E_1VB,    // V3
+  HP_TET_1E_2VA,    // V1,2
+  HP_TET_1E_2VB,    // V1,3
+  HP_TET_1E_2VC,    // V1,4
+  HP_TET_1E_2VD,    // V3,4
+  HP_TET_1E_3VA,    // V1,2,3
+  HP_TET_1E_3VB,    // V1,3,4
+  HP_TET_1E_4V,     // V1,2,3,4
+
+
+  // 2 connected edges, additonally marked Vs
+  HP_TET_2EA_0V = 220,    // E1-2, E1-3
+  HP_TET_2EA_1VA,   // V2
+  HP_TET_2EA_1VB,   // V3
+  HP_TET_2EA_1VC,   // V4
+  HP_TET_2EA_2VA,   // V2,3
+  HP_TET_2EA_2VB,   // V2,4
+  HP_TET_2EA_2VC,   // V3,4
+  HP_TET_2EA_3V,    // V2,3,4
+
+  // 2 opposite edges
+  HP_TET_2EB_0V = 230,    // E1-2, E3-4
+  HP_TET_2EB_1V,    // V1
+  HP_TET_2EB_2VA,   // V1,2
+  HP_TET_2EB_2VB,   // V1,3
+  HP_TET_2EB_2VC,   // V1,4
+  HP_TET_2EB_3V,    // V1,2,3
+  HP_TET_2EB_4V,    // V1,2,3,4
+
+  HP_TET_3EA_0V = 400,  // E1-2, E1-3, E1-4, 3 edges connected
+  HP_TET_3EA_1V,        // V2
+  HP_TET_3EA_2V,        // V2,3
+  HP_TET_3EA_3V,        // V2,3,4
+
+  HP_TET_3EB_0V = 420,  // E1-2, E1-4, E2-3  3 edges chain
+  HP_TET_3EB_1V,        // 
+  HP_TET_3EB_2V,        // 
+  HP_TET_3EC_0V = 430,  // 3 edges chain, alter
+  HP_TET_3EC_1V,        // 3 edges chain, alter
+  HP_TET_3EC_2V,        // 3 edges chain, alter
+
+
+  HP_TET_1F_0E_0V = 500,  // 1 singular face
+  HP_TET_1F_0E_1VA,       // 1 sing vertex in face (V2)
+  HP_TET_1F_0E_1VB,       // 1 sing vertex not in face (V1)
+  HP_TET_1F_1EA_0V,       // 1 sing edge not in face
+  HP_TET_1F_1EB_0V,       // 1 sing edge in face
+  HP_TET_2F_0E_0V = 600,  // 2 singular faces
+
+  HP_PRISM = 1000,
+  HP_PRISM_SINGEDGE,
+  HP_PRISM_SINGEDGE_V12,
+  HP_PRISM_SINGEDGE_H1,
+  HP_PRISM_SINGEDGE_H12,
+
+  HP_PRISM_1FA_0E_0V,     // 1 singular trig face
+  HP_PRISM_2FA_0E_0V,     // 2 singular trig faces
+  HP_PRISM_1FB_0E_0V,     // 1 singular quad face  1-2-4-5
+
+  HP_PRISM_1FB_1EA_0V,     // 1 singular quad face, edge is 1-2
+  HP_PRISM_1FA_1E_0V, 
+  HP_PRISM_2FA_1E_0V, 
+  HP_PRISM_1FA_1FB_0E_0V, 
+  HP_PRISM_2FA_1FB_0E_0V,
+  HP_PRISM_1FA_1FB_1EA_0V, 
+  HP_PRISM_1FA_1FB_1EB_0V, 
+  HP_PRISM_2FA_1FB_1EA_0V,
+  HP_PRISM_1FB_1EC_0V, 
+  HP_PRISM_1FA_1FB_1EC_0V, 
+  HP_PRISM_2FA_1FB_1EC_0V,
+  HP_PRISM_1FB_2EA_0V, 
+  HP_PRISM_1FA_1FB_2EA_0V, 
+  HP_PRISM_2FA_1FB_2EA_0V,
+  HP_PRISM_1FB_2EB_0V,
+  HP_PRISM_1FA_1FB_2EB_0V,  
+  HP_PRISM_1FA_1FB_2EC_0V, 
+  HP_PRISM_2FA_1FB_2EB_0V, 
+  HP_PRISM_1FB_3E_0V, 
+  HP_PRISM_1FA_1FB_3E_0V, 
+  HP_PRISM_2FA_1FB_3E_0V, 
+  HP_PRISM_2FB_0E_0V, 
+  HP_PRISM_1FA_2FB_0E_0V, 
+  HP_PRISM_2FA_2FB_0E_0V,
+  HP_PRISM_2FB_1EC_0V, 
+  HP_PRISM_1FA_2FB_1EC_0V,
+  HP_PRISM_1FA_2FB_1EB_0V,
+  HP_PRISM_2FA_2FB_1EC_0V,
+  HP_PRISM_2FB_3E_0V, 
+  HP_PRISM_1FA_2FB_3E_0V, 
+  HP_PRISM_2FA_2FB_3E_0V, 
+  HP_PRISM_1FA_2E_0V, 
+  HP_PRISM_2FA_2E_0V,
+  HP_PRISM_3E_0V, 
+  HP_PRISM_1FA_3E_0V, 
+  HP_PRISM_2FA_3E_0V,  
+  HP_PRISM_3FB_0V, 
+  HP_PRISM_1FA_3FB_0V, 
+  HP_PRISM_2FA_3FB_0V,  
+  HP_PRISM_3E_4EH,
+  
+ 
+
+  /*  HP_PRISM_1FB_1EA_0V,     // 1 singular quad face, edge is 1-4
+  HP_PRISM_1FB_1EB_0V,     // 1 singular quad face, edge is 2-5
+  HP_PRISM_2F_0E_0V,      // 2 singular quad faces
+  */
+
+  HP_PYRAMID = 2000,
+  HP_PYRAMID_0E_1V,
+  HP_PYRAMID_EDGES,
+  HP_PYRAMID_1FB_0E_1VA,  // 1 trig face, top vertex
+
+  HP_HEX = 3000,
+  HP_HEX_0E_1V,
+  HP_HEX_1E_1V,
+  HP_HEX_1E_0V,
+  HP_HEX_3E_0V,
+  HP_HEX_1F_0E_0V,
+  HP_HEX_1FA_1FB_0E_0V
+};
+
+
+
+struct HPRef_Struct {
+  HPREF_ELEMENT_TYPE geom;
+  int (*splitedges)[3];
+  int (*splitfaces)[4];
+  int (*splitelements)[5];
+  HPREF_ELEMENT_TYPE * neweltypes;
+  int (*newels)[8];
+};
+
+
+
+
+class HPRefElement
+{
+private:
+  void Reset(void);
+
+public:
+  HPRefElement (); 
+  HPRefElement(Element & el);
+  HPRefElement(Element2d & el);
+  HPRefElement(Segment & el);	
+  HPRefElement(HPRefElement & el);
+
+  void SetType( HPREF_ELEMENT_TYPE t);
+  // HPRefElement(HPRefElement & el, HPREF_ELEMENT_TYPE t); 
+	       
+  /* HPRefElement(HPRefElement & el, HPREF_ELEMENT_TYPE t)
+  { 
+    type = t; 
+    HPRef_Struct * hprs = Get_HPRef_Struct(t);
+    for (int i=0; i<np ; i++) 
+      {
+	pnums[i] = el[i];
+	for(int l=0; l<np; l++) param[i][l] = el.param[i][l]; 
+      }
+    switch(hprs->geom)
+      {
+      case HP_SEGM: np=2; sing_edge_left=0; sing_edge_right=0; break; 
+      case HP_QUAD: np=4; break; 
+      case HP_TRIG: np=3; break; 
+      case HP_HEX: np=8; break; 
+      case HP_PRISM: np=6; break;
+      case HP_TET: np=4; break; 
+      case HP_PYRAMID: np=5; break; 
+      }
+    index = el.index; 
+    levelx = el.levelx; 
+    levely = el.levely; 
+    levelz = el.levelz; 
+    type = el.type; 
+    coarse_elnr = el.coarse_elnr;
+    singedge_left = el.singedge_left; 
+    singedge_right = el.singedge_left; 
+    } */ 
+  
+  HPREF_ELEMENT_TYPE type;
+  PointIndex pnums[8];
+  double param[8][3];
+  int index;
+  int levelx;
+  int levely;
+  int levelz;
+  int np; 
+  int coarse_elnr;
+  int domin, domout; // he: needed for segment!! in 3d there should be surf1, surf2!!
+  // int coarse_hpelnr; 
+  PointIndex & operator[](int i) { return(pnums[i]);}
+  PointIndex & PNumMod(int i) { return pnums[(i-1) % np]; };
+  PointIndex & PNum(int i) {return pnums[(i-1)]; };
+  int GetIndex () const { return index; }; 
+  double singedge_left, singedge_right; 
+  
+
+  //  EdgePointGeomInfo epgeominfo[2];
+  
+};
+
+
+
+extern void HPRefinement (Mesh & mesh, Refinement * ref, int levels, 
+			  double fac1=0.125, bool setorders=true, bool ref_level = false);
+
+
+#endif
+
diff --git a/contrib/Netgen/libsrc/meshing/improve2.cpp b/contrib/Netgen/libsrc/meshing/improve2.cpp
new file mode 100644
index 0000000000..eea6c51137
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/improve2.cpp
@@ -0,0 +1,854 @@
+#include <mystdlib.h>
+
+#include "meshing.hpp"
+#include <opti.hpp>
+
+#ifndef SMALLLIB
+//#ifndef NOTCL
+//#include <visual.hpp>
+//#endif
+#endif
+
+namespace netgen
+{
+
+  class Neighbour
+  {
+    int nr[3];
+    int orient[3];
+
+  public:
+    Neighbour () { ; } 
+
+    void SetNr (int side, int anr) { nr[side] = anr; }
+    int GetNr (int side) { return nr[side]; }
+
+    void SetOrientation (int side, int aorient) { orient[side] = aorient; }
+    int GetOrientation (int side) { return orient[side]; }
+
+
+
+    /*
+      void SetNr1 (int side, int anr) { nr[side-1] = anr; }
+      int GetNr1 (int side) { return nr[side-1]; }
+
+      void SetOrientation1 (int side, int aorient) { orient[side-1] = aorient; }
+      int GetOrientation1 (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;
+	mesh.CalcSurfacesOfNode();
+	return;
+      }
+
+
+    static int timer = NgProfiler::CreateTimer ("EdgeSwapping 2D");
+    NgProfiler::RegionTimer reg1 (timer);
+
+    static int timerstart = NgProfiler::CreateTimer ("EdgeSwapping 2D start");
+    NgProfiler::StartTimer (timerstart);
+
+
+    Array<SurfaceElementIndex> seia;
+    mesh.GetSurfaceElementsOfFace (faceindex, seia);
+
+    for (int 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());
+
+
+    // int e;
+    // double d;
+    // Vec3d nv1, nv2;
+
+    // double loch(-1);
+    static const double minangle[] = { 0, 1.481, 2.565, 3.627, 4.683, 5.736, 7, 9 };
+
+
+    for (int i = 0; i < seia.Size(); i++)
+      {
+	const Element2d & sel = mesh[seia[i]];
+	for (int j = 0; j < 3; j++)
+	  pangle[sel[j]] = 0.0;
+      }
+    // pangle = 0;
+
+    for (int i = 0; i < seia.Size(); i++)
+      {
+	const Element2d & sel = mesh[seia[i]];
+	for (int j = 0; j < 3; j++)
+	  {
+	    POINTTYPE typ = mesh[sel[j]].Type();
+	    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 (PointIndex pi = PointIndex::BASE; 
+    // pi < mesh.GetNP()+PointIndex::BASE; pi++)
+    
+    // pdef = 0;
+    for (int i = 0; i < seia.Size(); i++)
+      {
+	const Element2d & sel = mesh[seia[i]];
+	for (int j = 0; j < 3; j++)
+	  {
+	    PointIndex pi = sel[j];
+	    if (mesh[pi].Type() == INNERPOINT || mesh[pi].Type() == SURFACEPOINT)
+	      pdef[pi] = -6;
+	    else
+	      for (int j = 0; j < 8; j++)
+		if (pangle[pi] >= minangle[j])
+		  pdef[pi] = -1-j;
+	  }
+      }
+
+    for (int i = 0; i < seia.Size(); i++)
+      {
+	const Element2d & sel = mesh[seia[i]];
+	for (int j = 0; j < 3; j++)
+	  pdef[sel[j]]++;
+      }
+
+    for (int i = 0; i < seia.Size(); i++)
+      {
+	for (int j = 0; j < 3; j++)
+	  {
+	    neighbors[seia[i]].SetNr (j, -1);
+	    neighbors[seia[i]].SetOrientation (j, 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 (int i = 0; i < seia.Size(); i++)
+      {
+	const Element2d & sel = mesh[seia[i]];
+
+	for (int j = 0; j < 3; j++)
+	  {
+	    PointIndex pi1 = sel.PNumMod(j+2);
+	    PointIndex pi2 = sel.PNumMod(j+3);
+	  
+	    //	    double 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();
+	      
+		int i2 = other.Get(ii2).tnr;
+		int 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 (int i = 0; i < seia.Size(); i++)
+      swapped[seia[i]] = 0;
+
+    NgProfiler::StopTimer (timerstart);
+  
+
+
+    int t = 4;
+    int done = 0;
+    while (!done && t >= 2)
+      {
+	for (int i = 0; i < seia.Size(); i++)
+	  {
+	    SurfaceElementIndex t1 = seia[i];
+
+	    if (mesh[t1].IsDeleted())
+	      continue;
+
+	    if (mesh[t1].GetIndex() != faceindex)
+	      continue;
+
+	    if (multithread.terminate)
+	      throw NgException ("Meshing stopped");
+
+	    for (int o1 = 0; o1 < 3; o1++)
+	      {
+		bool should;
+
+
+		SurfaceElementIndex t2 = neighbors[t1].GetNr (o1);
+		int o2 = neighbors[t1].GetOrientation (o1);
+
+		if (t2 == -1) continue;
+		if (swapped[t1] || swapped[t2]) continue;
+	      
+
+		PointIndex pi1 = mesh[t1].PNumMod(o1+1+1);
+		PointIndex pi2 = mesh[t1].PNumMod(o1+1+2);
+		PointIndex pi3 = mesh[t1].PNumMod(o1+1);
+		PointIndex pi4 = mesh[t2].PNumMod(o2+1);
+	      
+		PointGeomInfo gi1 = mesh[t1].GeomInfoPiMod(o1+1+1);
+		PointGeomInfo gi2 = mesh[t1].GeomInfoPiMod(o1+1+2);
+		PointGeomInfo gi3 = mesh[t1].GeomInfoPiMod(o1+1);
+		PointGeomInfo gi4 = mesh[t2].GeomInfoPiMod(o2+1);
+	    
+		bool allowswap = true;
+
+		Vec<3> auxvec1 = mesh[pi3]-mesh[pi4];
+		Vec<3> auxvec2 = mesh[pi1]-mesh[pi4];
+
+		allowswap = allowswap && fabs(1.-(auxvec1*auxvec2)/(auxvec1.Length()*auxvec2.Length())) > 1e-4;
+
+		if(!allowswap)
+		  continue;
+
+		// normal of new
+		Vec<3> nv1 = Cross (auxvec1, auxvec2);
+
+		auxvec1 = mesh.Point(pi4)-mesh.Point(pi3);
+		auxvec2 = mesh.Point(pi2)-mesh.Point(pi3);
+		allowswap = allowswap && fabs(1.-(auxvec1*auxvec2)/(auxvec1.Length()*auxvec2.Length())) > 1e-4;
+
+
+		if(!allowswap)
+		  continue;
+
+		Vec<3> nv2 = Cross (auxvec1, auxvec2);
+
+	      
+		// normals of original
+		Vec<3> nv3 = Cross (mesh[pi1]-mesh[pi4], mesh[pi2]-mesh[pi4]);
+		Vec<3> nv4 = Cross (mesh[pi2]-mesh[pi3], mesh[pi1]-mesh[pi3]);
+	      
+		nv3 *= -1;
+		nv4 *= -1;
+		nv3.Normalize();
+		nv4.Normalize();
+
+		nv1.Normalize();
+		nv2.Normalize();
+	    
+		Vec<3> 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
+		allowswap = allowswap &&
+		  (nv1 * nvp3 > critval) && 
+		  (nv1 * nvp4 > critval) && 
+		  (nv2 * nvp3 > critval) && 
+		  (nv2 * nvp4 > critval) &&
+		  (nvp3 * nv3 > critval) && 
+		  (nvp4 * nv4 > critval);
+	      
+
+		double 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)
+		      {
+			int e = pdef[pi1] + pdef[pi2] - pdef[pi3] - pdef[pi4];
+			double d = 
+			  Dist2 (mesh.Point(pi1), mesh.Point(pi2)) - 
+			  Dist2 (mesh.Point(pi3), mesh.Point(pi4));
+		      
+			should = e >= t && (e > 2 || d > 0);
+		      }
+		    else
+		      {
+			double loch = mesh.GetH(mesh[pi1]);
+			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 (pi3, 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 !
+		      
+			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[t1] = 1;
+			swapped[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;
+      }
+
+
+    static int timer = NgProfiler::CreateTimer ("Combineimprove 2D");
+    NgProfiler::RegionTimer reg (timer);
+
+    static int timerstart = NgProfiler::CreateTimer ("Combineimprove 2D start");
+    NgProfiler::StartTimer  (timerstart);
+
+
+    static int timerstart1 = NgProfiler::CreateTimer ("Combineimprove 2D start1");
+    NgProfiler::StartTimer  (timerstart1);
+
+
+
+    // int i, j, k, l;
+    // PointIndex pi;
+    // SurfaceElementIndex sei;
+
+
+    Array<SurfaceElementIndex> seia;
+    mesh.GetSurfaceElementsOfFace (faceindex, seia);
+
+
+    for (int i = 0; i < seia.Size(); i++)
+      if (mesh[seia[i]].GetNP() != 3)
+	return;
+
+
+
+    int surfnr = 0;
+    if (faceindex)
+      surfnr = mesh.GetFaceDescriptor (faceindex).SurfNr();
+
+
+    // PointIndex pi1, pi2;
+    // MeshPoint p1, p2, pnew;
+    double bad1, bad2;
+    Vec<3> nv;
+
+    int np = mesh.GetNP();
+    //int nse = mesh.GetNSE();
+
+    TABLE<SurfaceElementIndex,PointIndex::BASE> elementsonnode(np); 
+    Array<SurfaceElementIndex> hasonepi, hasbothpi;
+
+    for (int i = 0; i < seia.Size(); i++)
+      {
+	Element2d & el = mesh[seia[i]];
+	for (int j = 0; j < el.GetNP(); j++)
+	  elementsonnode.Add (el[j], seia[i]);
+      }
+
+    Array<bool,PointIndex::BASE> fixed(np);
+    fixed = false;
+
+    NgProfiler::StopTimer  (timerstart1);
+
+    /*
+    for (SegmentIndex si = 0; si < mesh.GetNSeg(); si++)
+      {
+	INDEX_2 i2(mesh[si][0], mesh[si][1]);
+	fixed[i2.I1()] = true;
+	fixed[i2.I2()] = true;
+      }
+    */
+
+    for (int i = 0; i < seia.Size(); i++)
+      {
+	Element2d & sel = mesh[seia[i]];
+	for (int j = 0; j < sel.GetNP(); j++)
+	  {
+	    PointIndex pi1 = sel.PNumMod(j+2);
+	    PointIndex pi2 = sel.PNumMod(j+3);
+	    if (mesh.IsSegment (pi1, pi2))
+	      {	
+		fixed[pi1] = true;
+		fixed[pi2] = true;
+	      }
+	  }
+      }
+
+
+
+    for(int i = 0; i < mesh.LockedPoints().Size(); i++)
+      fixed[mesh.LockedPoints()[i]] = true;
+
+
+
+    Array<Vec<3>,PointIndex::BASE> normals(np);
+
+    for (PointIndex pi = PointIndex::BASE; 
+	 pi < np + PointIndex::BASE; pi++)
+      {
+	if (elementsonnode[pi].Size())
+	  {
+	    Element2d & hel = mesh[elementsonnode[pi][0]];
+	    for (int 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;
+		}
+	  }
+      }
+
+    NgProfiler::StopTimer  (timerstart);
+
+    for (int i = 0; i < seia.Size(); i++)
+      {
+	SurfaceElementIndex sei = seia[i];
+	Element2d & elem = mesh[sei];
+	if (elem.IsDeleted()) continue;
+
+	for (int j = 0; j < 3; j++)
+	  {
+	    PointIndex pi1 = elem[j];
+	    PointIndex 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 (int 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 (int 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;
+		}
+
+	    //	  nv = normals.Get(pi1);
+
+
+
+	    for (int 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 (int 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 (int 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());
+
+	    MeshPoint p1 = mesh[pi1];
+	    MeshPoint p2 = mesh[pi2];
+
+	    MeshPoint pnew = p1;
+	    mesh[pi1] = pnew;
+	    mesh[pi2] = pnew;
+
+	    bad2 = 0;
+	    for (int 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;
+
+		Vec<3> hnv = Cross (Vec3d (mesh[el[0]],
+					   mesh[el[1]]),
+				    Vec3d (mesh[el[0]],
+					   mesh[el[2]]));
+		if (hnv * nv < 0)
+		  bad2 += 1e10;
+              
+		for (int 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;
+		bool gi_set(false);
+	      
+	      
+		Element2d *el1p(NULL);
+		int l = 0;
+		while(mesh[elementsonnode[pi1][l]].IsDeleted() && l<elementsonnode.EntrySize(pi1)) l++;
+		if(l<elementsonnode.EntrySize(pi1))
+		  el1p = &mesh[elementsonnode[pi1][l]];
+		else
+		  cerr << "OOPS!" << endl;
+
+		for (l = 0; l < el1p->GetNP(); l++)
+		  if ((*el1p)[l] == pi1)
+		    {
+		      gi = el1p->GeomInfoPi (l+1);
+		      gi_set = true;
+		    }
+
+		// (*testout) << "Connect point " << pi2 << " to " << pi1 << "\n";
+		for (int k = 0; k < elementsonnode[pi2].Size(); k++)
+		  {
+		    Element2d & el = mesh[elementsonnode[pi2][k]];
+		    if(el.IsDeleted()) continue;
+		    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 (int l = 0; l < el.GetNP(); l++)
+		      {
+			if (el[l] == pi2)
+			  {
+			    el[l] = pi1;
+			    el.GeomInfoPi (l+1) = gi;
+			  }
+
+			fixed[el[l]] = true;
+		      }
+		  }
+
+		/*
+		  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 (int 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/contrib/Netgen/libsrc/meshing/improve2.hpp b/contrib/Netgen/libsrc/meshing/improve2.hpp
new file mode 100644
index 0000000000..4a6e49ea5e
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/improve2.hpp
@@ -0,0 +1,102 @@
+#ifndef FILE_IMPROVE2
+#define FILE_IMPROVE2
+
+
+
+///
+class MeshOptimize2d
+{
+  int faceindex;
+  int improveedges;
+  double metricweight;
+  int writestatus;
+
+public:
+  ///
+  MeshOptimize2d ();
+  ///
+  void ImproveMesh (Mesh & mesh2d, const MeshingParameters & mp);
+  void ImproveMeshJacobian (Mesh & mesh2d, const MeshingParameters & mp);
+  void ImproveVolumeMesh (Mesh & mesh);
+  void ProjectBoundaryPoints(Array<int> & surfaceindex, 
+			     const Array<Point<3>* > & from, Array<Point<3>* > & dest);
+
+  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 Point<3> & p,
+				     const PointGeomInfo & gi);
+  ///
+  virtual void ProjectPoint (INDEX /* surfind */, Point<3> & /* p */) const { };
+
+  /// project point, use gi as initial value, and compute new gi
+  virtual int ProjectPointGI (INDEX surfind, Point<3> & p, PointGeomInfo & gi) const 
+  { ProjectPoint (surfind, p); return CalcPointGeomInfo (surfind, gi, p); }
+
+  ///
+  virtual void ProjectPoint2 (INDEX /* surfind */, INDEX /* surfind2 */, Point<3> & /* 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 Point<3> & /*p3*/) const
+    { gi.trignum = 1; return 1;};
+
+  virtual int CalcPointGeomInfo(int /* surfind */, PointGeomInfo& gi, const Point<3> & p3) const
+    { return CalcPointGeomInfo (gi, p3); }
+
+  ///
+  virtual void GetNormalVector(INDEX surfind, const Point<3>  & p, PointGeomInfo & gi, Vec<3> & n) const;
+  virtual void GetNormalVector(INDEX surfind, const Point<3> & p, Vec<3> & 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/contrib/Netgen/libsrc/meshing/improve2gen.cpp b/contrib/Netgen/libsrc/meshing/improve2gen.cpp
new file mode 100644
index 0000000000..e5b65308a4
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/improve2gen.cpp
@@ -0,0 +1,455 @@
+#include <mystdlib.h>
+
+#include "meshing.hpp"
+#include <opti.hpp>
+
+namespace netgen
+{
+
+  class ImprovementRule
+  {
+  public:
+    Array<Element2d> oldels;
+    Array<Element2d> newels;
+    Array<INDEX_2> deledges;
+    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;
+
+    
+//     for (SurfaceElementIndex sei = 0; sei < ne; sei++)
+//       {
+// 	const Element2d & el = mesh[sei];
+// 	(*testout) << "element " << sei << ": " <<flush;
+// 	for(int j=0; j<el.GetNP(); j++)
+// 	  (*testout) << el[j] << " " << flush;
+// 	(*testout) << "IsDeleted() " << el.IsDeleted()<< endl;
+//       }
+
+    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->deledges.Append (INDEX_2 (2,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->deledges.Append (INDEX_2 (2, 3));
+    r1->deledges.Append (INDEX_2 (3, 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->deledges.Append (INDEX_2 (2, 3));
+    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->deledges.Append (INDEX_2 (2, 3));
+    r1->deledges.Append (INDEX_2 (3, 4));
+    r1->deledges.Append (INDEX_2 (3, 6));
+    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->deledges.Append (INDEX_2 (2, 3));
+    r1->deledges.Append (INDEX_2 (3, 4));
+    r1->deledges.Append (INDEX_2 (3, 5));
+    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->deledges.Append (INDEX_2 (1, 4));
+    r1->deledges.Append (INDEX_2 (2, 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->deledges.Append (INDEX_2 (1, 4));
+    r1->deledges.Append (INDEX_2 (2, 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->deledges.Append (INDEX_2 (2, 3));
+    r1->deledges.Append (INDEX_2 (3, 4));
+    r1->deledges.Append (INDEX_2 (3, 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->deledges.Append (INDEX_2 (2, 3));
+    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->deledges.Append (INDEX_2 (2, 3));
+    r1->onp = 5;
+    r1->bonus = 0;
+    rules.Append (r1);
+
+
+    // 2 quads to quad + 2 trigs
+    r1 = new ImprovementRule;
+    r1->oldels.Append (Element2d (1, 2, 3, 4));
+    r1->oldels.Append (Element2d (3, 2, 5, 6));
+    r1->newels.Append (Element2d (1, 5, 6, 4));
+    r1->newels.Append (Element2d (1, 2, 5));
+    r1->newels.Append (Element2d (4, 6, 3));
+    r1->deledges.Append (INDEX_2 (2, 3));
+    r1->onp = 6;
+    r1->bonus = 0;
+    //    rules.Append (r1);
+
+
+
+
+    Array<int> mapped(rules.Size());
+    Array<int> used(rules.Size());
+    used = 0;
+    mapped = 0;
+
+  
+
+    for (int ri = 0; ri < rules.Size(); ri++)
+      {
+	ImprovementRule & rule = *rules[ri];
+	rule.incelsonnode.SetSize (rule.onp);
+	rule.reused.SetSize (rule.onp);
+
+	for (int j = 1; j <= rule.onp; j++)
+	  {
+	    rule.incelsonnode.Elem(j) = 0;
+	    rule.reused.Elem(j) = 0;
+	  }
+
+	for (int j = 1; j <= rule.oldels.Size(); j++)
+	  {
+	    const Element2d & el = rule.oldels.Elem(j);
+	    for (int k = 1; k <= el.GetNP(); k++)
+	      rule.incelsonnode.Elem(el.PNum(k))--;
+	  }
+
+	for (int j = 1; j <= rule.newels.Size(); j++)
+	  {
+	    const Element2d & el = rule.newels.Elem(j);
+	    for (int 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<SurfaceElementIndex> nbels(ne);
+
+    nelonnode = -4;
+
+    for (SurfaceElementIndex sei = 0; sei < ne; sei++)
+      {
+	const Element2d & el = mesh[sei];
+
+	if (el.GetIndex() == faceindex && !el.IsDeleted())
+	  {
+	    for (int j = 0; j < el.GetNP(); j++)
+	      elonnode.Add (el[j], sei);
+	  }
+	if(!el.IsDeleted())
+	  {
+	    for (int j = 0; j < el.GetNP(); j++)
+	      nelonnode[el[j]]++;
+	  }
+      }
+
+    for (SurfaceElementIndex sei = 0; sei < ne; sei++)
+      {
+	const Element2d & el = mesh[sei];
+	if (el.GetIndex() == faceindex && !el.IsDeleted())
+	  {
+	    for (int j = 0; j < el.GetNP(); j++)
+	      {
+		for (int k = 0; k < elonnode[el[j]].Size(); k++)
+		  {
+		    int nbel = elonnode[el[j]] [k];
+		    bool inuse = false;
+		    for (int l = 0; l < nbels[sei].Size(); l++)
+		      if (nbels[sei][l] == nbel)
+			inuse = true;
+		    if (!inuse)
+		      nbels.Add (sei, nbel);
+		  }
+	      }
+	  }
+      }
+
+
+    for (int 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);
+
+
+	for (SurfaceElementIndex sei = 0; sei < ne; sei++)
+	  {
+	    if (multithread.terminate)
+	      break;
+	    if (mesh[sei].IsDeleted()) continue;
+
+	    elmap[0] = sei;
+	    FlatArray<SurfaceElementIndex> neighbours = nbels[sei];
+	    
+	    for (elrot[0] = 0; elrot[0] < mesh[sei].GetNP(); elrot[0]++)
+	      {
+		const Element2d & el0 = mesh[sei];
+		const Element2d & rel0 = rule.oldels[0];
+
+		if (el0.GetIndex() != faceindex) continue;
+		if (el0.IsDeleted()) continue;
+		if (el0.GetNP() != rel0.GetNP()) continue;
+
+
+		pmap = -1;
+ 
+		for (int k = 0; k < el0.GetNP(); k++)
+		  {
+		    pmap.Elem(rel0[k]) = el0.PNumMod(k+elrot[0]+1);
+		    pgi.Elem(rel0[k]) = el0.GeomInfoPiMod(k+elrot[0]+1);
+		  }
+		
+		ok = 1;
+		for (int i = 1; i < elmap.Size(); i++)
+		  {
+		    // try to find a mapping for reference-element i
+
+		    const Element2d & rel = rule.oldels[i];
+		    bool possible = 0;
+
+		    for (elmap[i] = 0; elmap[i] < neighbours.Size(); elmap[i]++)
+		      {
+			const Element2d & el = mesh[neighbours[elmap[i]]];
+			if (el.IsDeleted()) continue;
+			if (el.GetNP() != rel.GetNP()) continue;
+
+			for (elrot[i] = 0; elrot[i] < rel.GetNP(); elrot[i]++)
+			  {
+			    possible = 1;
+
+			    for (int k = 0; k < rel.GetNP(); k++)
+			      if (pmap.Elem(rel[k]) != -1 &&
+				  pmap.Elem(rel[k]) != el.PNumMod (k+elrot[i]+1))
+				possible = 0;
+
+			    if (possible) 
+			      {
+				for (int k = 0; k < el.GetNP(); k++)
+				  {
+				    pmap.Elem(rel[k]) = el.PNumMod(k+elrot[i]+1);
+				    pgi.Elem(rel[k]) = el.GeomInfoPiMod(k+elrot[i]+1);
+				  }
+				break;
+			      }
+			  }
+			if (possible) break;
+		      }
+
+		    if (!possible) 
+		      {
+			ok = 0;
+			break;
+		      }
+
+		    elmap[i] = neighbours[elmap[i]];
+		  }
+
+		for(int i=0; ok && i<rule.deledges.Size(); i++)
+		  {
+		    ok = !mesh.IsSegment(pmap.Elem(rule.deledges[i].I1()),
+					 pmap.Elem(rule.deledges[i].I2()));
+		  }
+								    
+								    
+		
+		
+		if (!ok) continue;
+
+		mapped[ri]++;
+
+		olddef = 0;
+		for (int j = 1; j <= pmap.Size(); j++)
+		  olddef += sqr (nelonnode[pmap.Get(j)]);
+		olddef += rule.bonus;
+
+		newdef = 0;
+		for (int 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;
+		Vec<3> n;
+
+		SelectSurfaceOfPoint (mesh.Point(pmap.Get(1)), pgi.Get(1));
+		GetNormalVector (surfnr, mesh.Point(pmap.Get(1)), pgi.Elem(1), n);
+		  
+		for (int j = 1; j <= rule.oldels.Size(); j++)
+		  bad1 += mesh.SurfaceElement(elmap.Get(j)).CalcJacobianBadness (mesh.Points(), n);
+		  
+		// check new element:
+		for (int j = 1; j <= rule.newels.Size(); j++)
+		  {
+		    const Element2d & rnel = rule.newels.Get(j);
+		    Element2d nel(rnel.GetNP());
+		    for (int 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 (int j = 1; j <= rule.newels.Size(); j++)
+		  {
+		    const Element2d & rnel = rule.newels.Get(j);
+		    Element2d nel(rnel.GetNP());
+		    nel.SetIndex (faceindex);
+		    for (int 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 (int j = 0; j < rule.oldels.Size(); j++)
+		  mesh.DeleteSurfaceElement ( elmap[j] );
+
+		for (int j = 1; j <= pmap.Size(); j++)
+		  nelonnode[pmap.Get(j)] += rule.incelsonnode.Get(j);
+
+		used[ri]++;
+	      }
+	  }
+      }
+
+    mesh.Compress();
+
+    for (int ri = 0; ri < rules.Size(); ri++)
+      {
+	PrintMessage (5, "rule ", ri+1, " ",
+		      mapped[ri], "/", used[ri], " mapped/used");
+      }
+  }
+
+
+
+
+}
diff --git a/contrib/Netgen/libsrc/meshing/improve3.cpp b/contrib/Netgen/libsrc/meshing/improve3.cpp
new file mode 100644
index 0000000000..8a236aa201
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/improve3.cpp
@@ -0,0 +1,2779 @@
+#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 np = mesh.GetNP();
+  int ne = mesh.GetNE();
+
+  TABLE<ElementIndex, PointIndex::BASE> elementsonnode(np); 
+  Array<ElementIndex> hasonepi, hasbothpi;
+
+  Array<double> oneperr;
+  Array<double> elerrs (ne);
+
+  PrintMessage (3, "CombineImprove");
+  (*testout)  << "Start CombineImprove" << "\n";
+
+  //  mesh.CalcSurfacesOfNode ();
+  const char * savetask = multithread.task;
+  multithread.task = "Combine Improve";
+
+
+  double totalbad = 0;
+  for (ElementIndex ei = 0; ei < ne; ei++)
+    {
+      double elerr = CalcBad (mesh.Points(), mesh[ei], 0);
+      totalbad += elerr;
+      elerrs[ei] = elerr;
+    }
+
+  if (goal == OPT_QUALITY)
+    {
+      totalbad = CalcTotalBad (mesh.Points(), mesh.VolumeElements());
+      (*testout) << "Total badness = " << totalbad << endl;
+      PrintMessage (5, "Total badness = ", totalbad);
+    }
+
+  for (ElementIndex ei = 0; ei < ne; ei++)
+    if (!mesh[ei].IsDeleted())
+      for (int j = 0; j < mesh[ei].GetNP(); j++)
+	elementsonnode.Add (mesh[ei][j], ei);
+  
+  INDEX_2_HASHTABLE<int> edgetested (np+1);
+
+  int cnt = 0;
+
+  for (ElementIndex ei = 0; ei < ne; ei++)
+    {
+      if (multithread.terminate)
+	break;
+      
+      multithread.percent = 100.0 * (ei+1) / ne;
+
+      if (mesh.ElementType(ei) == FIXEDELEMENT)
+	continue;
+
+      for (int 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 } };
+
+	  PointIndex pi1 = elemi[tetedges[j][0]];
+	  PointIndex 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 (int 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)
+		{
+		  hasbothpi.Append (row1[k]);
+		}
+	      else
+		{
+		  hasonepi.Append (row1[k]);
+		}
+	    } 
+	  
+	  FlatArray<ElementIndex> row2 = elementsonnode[pi2];	  
+	  for (int 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
+		{
+		  hasonepi.Append (row2[k]);
+		}
+	    } 
+	  
+	  double bad1 = 0;
+	  for (int k = 0; k < hasonepi.Size(); k++)
+	    bad1 += elerrs[hasonepi[k]];
+	  for (int k = 0; k < hasbothpi.Size(); k++)
+	    bad1 += elerrs[hasbothpi[k]];
+	  
+	  MeshPoint p1 = mesh[pi1];
+	  MeshPoint p2 = mesh[pi2];
+	  
+
+	  // if (mesh.PointType(pi2) != INNERPOINT)
+	  if (p2.Type() != INNERPOINT)
+	    continue;
+	  
+	  MeshPoint pnew;
+	  // if (mesh.PointType(pi1) != INNERPOINT)
+	  if (p1.Type() != INNERPOINT)
+	    pnew = p1;
+	  else
+	    pnew = Center (p1, p2);
+	    
+	  mesh[pi1] = pnew;
+	  mesh[pi2] = pnew;
+
+	  oneperr.SetSize (hasonepi.Size());
+
+	  double bad2 = 0;
+	  for (int k = 0; k < hasonepi.Size(); k++)
+	    {
+	      const Element & elem = mesh[hasonepi[k]];
+	      double err = CalcBad (mesh.Points(), elem, 0);
+	      // CalcTetBadness (mesh[elem[0]], mesh[elem[1]],  
+	      // mesh[elem[2]], mesh[elem[3]], 0, mparam);
+	      bad2 += err;
+	      oneperr[k] = err;
+	    }
+	  
+	  mesh[pi1] = p1;
+	  mesh[pi2] = p2;
+
+	  // if (mesh.PointType(pi1) != INNERPOINT)
+	  if (p1.Type() != INNERPOINT)
+	    {
+	      for (int k = 0; k < hasonepi.Size(); k++)
+		{
+		  Element & elem = mesh[hasonepi[k]];
+		  int l;
+		  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 / hasonepi.Size()  < 
+	      bad1 / (hasonepi.Size()+hasbothpi.Size()))
+	    {
+	      mesh[pi1] = pnew;
+	      cnt++;
+
+	      FlatArray<ElementIndex> row = elementsonnode[pi2];
+	      for (int k = 0; k < row.Size(); k++)
+		{
+		  Element & elem = mesh[row[k]];
+		  if (elem.IsDeleted()) continue;
+
+		  elementsonnode.Add (pi1, row[k]);
+		  for (int 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[pi2][k] << endl;
+		}
+
+	      for (int k = 0; k < hasonepi.Size(); k++)
+		elerrs[hasonepi[k]] = oneperr[k];
+	      
+	      for (int k = 0; k < hasbothpi.Size(); k++)
+		{
+		  mesh[hasbothpi[k]].flags.illegal_valid = 0;
+		  mesh[hasbothpi[k]].Delete();
+		}
+	    }
+	}
+    }
+
+  mesh.Compress();
+  mesh.MarkIllegalElements();
+
+  PrintMessage (5, cnt, " elements combined");
+  (*testout) << "CombineImprove done" << "\n";
+
+  totalbad = 0;
+  for (ElementIndex ei = 0; ei < mesh.GetNE(); ei++)
+    totalbad += CalcBad (mesh.Points(), mesh[ei], 0);
+
+  if (goal == OPT_QUALITY)
+    {
+      totalbad = CalcTotalBad (mesh.Points(), mesh.VolumeElements());
+      (*testout) << "Total badness = " << totalbad << endl;
+
+      int cntill = 0;
+      for (ElementIndex 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();
+
+  const 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 (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, mp, -1);
+	  OptiParameters par;
+	  par.maxit_linsearch = 50;
+	  par.maxit_bfgs = 20;
+
+	  pnew = Center (p1, p2);
+	  Vector px(3);
+	  px(0) = pnew.X();
+	  px(1) = pnew.Y();
+	  px(2) = pnew.Z();
+
+	  if (elerrs[ei] > 0.1 * badmax)
+	    BFGS (px, pf, par);
+
+	  bad2 = pf.Func (px);
+
+	  pnew.X() = px(0);
+	  pnew.Y() = px(1);
+	  pnew.Z() = px(2);
+
+
+	  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,
+				    const BitArray * working_elements)
+{
+  PointIndex pi1(0), pi2(0), pi3(0), pi4(0), pi5(0), pi6(0);
+  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();
+  
+  // contains at least all elements at node
+  TABLE<ElementIndex,PointIndex::BASE> elementsonnode(np);
+
+  Array<ElementIndex> hasbothpoints;
+
+  PrintMessage (3, "SwapImprove ");
+  (*testout) << "\n" << "Start SwapImprove" << endl;
+
+  const char * savetask = multithread.task;
+  multithread.task = "Swap Improve";
+  
+  //  mesh.CalcSurfacesOfNode ();
+    
+  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 (ElementIndex ei = 0; ei < ne; ei++)
+    for (int j = 0; j < mesh[ei].GetNP(); j++)
+      elementsonnode.Add (mesh[ei][j], ei);
+
+
+  // INDEX_2_HASHTABLE<int> edgeused(2 * ne + 5);
+  INDEX_2_CLOSED_HASHTABLE<int> edgeused(12 * ne + 5);
+  
+  for (ElementIndex ei = 0; ei < ne; ei++)
+    {
+      if (multithread.terminate)
+	break;
+      
+      multithread.percent = 100.0 * (ei+1) / ne;
+
+      if ((mesh.ElementType(ei)) == FIXEDELEMENT)
+	continue;
+
+      if(working_elements && 
+	 ei < working_elements->Size() &&
+	 !working_elements->Test(ei))
+	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 (int j = 0; j < 6; j++)
+	{
+	  // loop over edges
+
+	  const Element & elemi = mesh[ei];
+	  if (elemi.IsDeleted()) continue;
+
+
+	  //	  (*testout) << "check element " << elemi << endl;
+
+	  int 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 (int 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 (int l = 0; l < elem.GetNP(); l++)
+		{
+		  if (elem[l] == pi1) has1 = 1;
+		  if (elem[l] == pi2) has2 = 1;
+		}
+
+	      if (has1 && has2) 
+		{ // only once
+		  for (int l = 0; l < hasbothpoints.Size(); l++)
+		    if (hasbothpoints[l] == elnr)
+		      has1 = 0;
+		  
+		  if (has1)
+		    hasbothpoints.Append (elnr);
+		}
+	    }
+	  
+	  bool puretet = 1;
+	  for (int 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 (int 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 (int k = 1; k < 3; k++)
+		{
+		  const Element & elemk = mesh[hasbothpoints[k]];
+		  bool has1 = 0;
+		  for (int l = 0; l < 4; l++)
+		    if (elemk[l] == pi4)
+		      has1 = 1;
+		  if (has1)
+		    {
+		      for (int l = 0; l < 4; l++)
+			if (elemk[l] != pi1 && elemk[l] != pi2 && elemk[l] != pi4)
+			  pi5 = elemk[l];
+		    }
+		}
+
+	      if(pi5 == 0)
+                throw NgException("Illegal state observed in SwapImprove");
+
+
+	      
+	      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 (int l = 0; l < 4; l++)
+		    mesh[hasbothpoints[2]][l] = 0;
+		  mesh[hasbothpoints[2]].Delete();
+
+		  for (int k = 0; k < 2; k++)
+		    for (int l = 0; l < 4; l++)
+		      elementsonnode.Add (mesh[hasbothpoints[k]][l], hasbothpoints[k]);
+		}
+	    }	  
+          
+	  if (nsuround == 4)
+	    {
+	      const Element & elem1 = mesh[hasbothpoints[0]];
+	      for (int 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 (int k = 1; k < 4; k++)
+		{
+		  const Element & elem = mesh[hasbothpoints[k]];
+		  bool has1 = 0;
+		  for (int l = 0; l < 4; l++)
+		    if (elem[l] == pi4)
+		      has1 = 1;
+		  if (has1)
+		    {
+		      for (int l = 0; l < 4; l++)
+			if (elem[l] != pi1 && elem[l] != pi2 && elem[l] != pi4)
+			  pi5 = elem[l];
+		    }
+		}
+	      
+	      pi6 = 0;
+	      for (int k = 1; k < 4; k++)
+		{
+		  const Element & elem = mesh[hasbothpoints[k]];
+		  bool has1 = 0;
+		  for (int l = 0; l < 4; l++)
+		    if (elem[l] == pi3)
+		      has1 = 1;
+		  if (has1)
+		    {
+		      for (int 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 (int k = 0; k < 4; k++)
+		    for (int 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 (int k = 0; k < 4; k++)
+		    for (int 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 (int 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 (int l = 2; l < nsuround; l++)
+		{
+		  int oldpi = suroundpts[l-1];
+		  int newpi = 0;
+
+		  for (int 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;
+			    }			
+		      }
+		}
+
+	      
+	      bad1 = 0;
+	      for (int 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 (int l = 0; l < nsuround; l++)
+		{
+		  bad2 = 0;
+
+		  for (int 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 (int 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 (int 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 (int 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 (int 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;
+}
+  
+
+
+
+
+
+void MeshOptimize3d :: SwapImproveSurface (Mesh & mesh, OPTIMIZEGOAL goal,
+					   const BitArray * working_elements,
+					   const Array< Array<int,PointIndex::BASE>* > * idmaps)
+{
+  Array< Array<int,PointIndex::BASE>* > locidmaps;
+  const Array< Array<int,PointIndex::BASE>* > * used_idmaps;
+
+  if(idmaps)
+    used_idmaps = idmaps;
+  else
+    {
+      used_idmaps = &locidmaps;
+      
+      for(int i=1; i<=mesh.GetIdentifications().GetMaxNr(); i++)
+	{
+	  if(mesh.GetIdentifications().GetType(i) == Identifications::PERIODIC)
+	    {
+	      locidmaps.Append(new Array<int,PointIndex::BASE>);
+	      mesh.GetIdentifications().GetMap(i,*locidmaps.Last(),true);
+	    }
+	}
+    }
+
+
+  PointIndex pi1, pi2, pi3, pi4, pi5, pi6;
+  PointIndex pi1other, pi2other;
+  int cnt = 0;
+
+  //double bad1, bad2, bad3, sbad;
+  double bad1, sbad;
+  double h;
+
+  int np = mesh.GetNP();
+  int ne = mesh.GetNE();
+  int nse = mesh.GetNSE();
+
+  int mattype, othermattype;
+
+  
+  // contains at least all elements at node
+  TABLE<ElementIndex,PointIndex::BASE> elementsonnode(np);
+  TABLE<SurfaceElementIndex,PointIndex::BASE> surfaceelementsonnode(np);
+  TABLE<int,PointIndex::BASE> surfaceindicesonnode(np);
+
+  Array<ElementIndex> hasbothpoints;
+  Array<ElementIndex> hasbothpointsother;
+
+  PrintMessage (3, "SwapImproveSurface ");
+  (*testout) << "\n" << "Start SwapImproveSurface" << endl;
+
+  const char * savetask = multithread.task;
+  multithread.task = "Swap Improve Surface";
+    
+      
+  
+  // find elements on node
+  for (ElementIndex ei = 0; ei < ne; ei++)
+    for (int j = 0; j < mesh[ei].GetNP(); j++)
+      elementsonnode.Add (mesh[ei][j], ei);
+
+  for (SurfaceElementIndex sei = 0; sei < nse; sei++)
+    for(int j=0; j<mesh[sei].GetNP(); j++)
+      {
+	surfaceelementsonnode.Add(mesh[sei][j], sei);
+	if(!surfaceindicesonnode[mesh[sei][j]].Contains(mesh[sei].GetIndex()))
+	  surfaceindicesonnode.Add(mesh[sei][j],mesh[sei].GetIndex());
+      }
+
+  bool periodic;
+  int idnum(-1);
+
+  // INDEX_2_HASHTABLE<int> edgeused(2 * ne + 5);
+  INDEX_2_CLOSED_HASHTABLE<int> edgeused(12 * ne + 5);
+
+  for (ElementIndex ei = 0; ei < ne; ei++)
+    {
+      if (multithread.terminate)
+	break;
+      
+      multithread.percent = 100.0 * (ei+1) / ne;
+
+      if (mesh.ElementType(ei) == FIXEDELEMENT)
+	continue;
+      
+      if(working_elements && 
+	 ei < working_elements->Size() &&
+	 !working_elements->Test(ei))
+	continue;
+
+      if (mesh[ei].IsDeleted())
+	continue;
+
+      if ((goal == OPT_LEGAL) && 
+	  mesh.LegalTet (mesh[ei]) &&
+	  CalcBad (mesh.Points(), mesh[ei], 0) < 1e3)
+	continue;
+
+      const Element & elemi = mesh[ei];
+      //Element elemi = mesh[ei];
+      if (elemi.IsDeleted()) continue;
+
+
+      mattype = elemi.GetIndex();
+
+      bool swapped = false;
+
+      for (int j = 0; !swapped && j < 6; j++)
+	{
+	  // loop over edges
+
+	  
+	  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);
+	    	  
+	  
+	  bool found = false;
+	  for(int k=0; !found && k<used_idmaps->Size(); k++)
+	    {
+	      if(pi2 < (*used_idmaps)[k]->Size() + PointIndex::BASE)
+		{
+		  pi1other = (*(*used_idmaps)[k])[pi1];
+		  pi2other = (*(*used_idmaps)[k])[pi2];
+		  found = (pi1other != 0 && pi2other != 0 && pi1other != pi1 && pi2other != pi2);
+		  if(found)
+		    idnum = k;
+		}
+	    }
+	  if(found)
+	    periodic = true;
+	  else
+	    {
+	      periodic = false;
+	      pi1other = pi1; pi2other = pi2;
+	    }
+
+
+	 	  
+	  if (!mesh.BoundaryEdge (pi1, pi2) ||
+	      mesh.IsSegment(pi1, pi2)) continue;
+
+	  othermattype = -1;
+
+	  
+	  INDEX_2 i2 (pi1, pi2);
+	  i2.Sort();
+	  if (edgeused.Used(i2)) continue;
+	  edgeused.Set (i2, 1);
+	  if(periodic)
+	    {
+	      i2.I1() = pi1other;
+	      i2.I2() = pi2other;
+	      i2.Sort();
+	      edgeused.Set(i2,1);
+	    }
+	  
+	  
+	  hasbothpoints.SetSize (0);
+	  hasbothpointsother.SetSize (0);
+	  for (int k = 0; k < elementsonnode[pi1].Size(); k++)
+	    {
+	      bool has1 = false, has2 = false;
+	      ElementIndex elnr = elementsonnode[pi1][k];
+	      const Element & elem = mesh[elnr];
+	      
+	      if (elem.IsDeleted()) continue;
+	      
+	      for (int l = 0; l < elem.GetNP(); l++)
+		{
+		  if (elem[l] == pi1) has1 = true;
+		  if (elem[l] == pi2) has2 = true;
+		}
+
+	      if (has1 && has2) 
+		{ 
+		  if(othermattype == -1 && elem.GetIndex() != mattype)
+		    othermattype = elem.GetIndex();
+
+		  if(elem.GetIndex() == mattype)
+		    {
+		      // only once
+		      for (int l = 0; l < hasbothpoints.Size(); l++)
+			if (hasbothpoints[l] == elnr)
+			  has1 = 0;
+		      
+		      if (has1)
+			hasbothpoints.Append (elnr);
+		    }
+		  else if(elem.GetIndex() == othermattype)
+		    {
+		      // only once
+		      for (int l = 0; l < hasbothpointsother.Size(); l++)
+			if (hasbothpointsother[l] == elnr)
+			  has1 = 0;
+		      
+		      if (has1)
+			hasbothpointsother.Append (elnr);
+		    }
+		  else
+		    {
+		      cout << "problem with domain indices" << endl;
+		      (*testout) << "problem: mattype = " << mattype << ", othermattype = " << othermattype 
+				 << " elem " << elem << " mt " << elem.GetIndex() << endl
+				 << " pi1 " << pi1 << " pi2 " << pi2 << endl;
+		      (*testout) << "hasbothpoints:" << endl;
+		      for(int ii=0; ii < hasbothpoints.Size(); ii++)
+			(*testout) << mesh[hasbothpoints[ii]] << endl;
+		      (*testout) << "hasbothpointsother:" << endl;
+		      for(int ii=0; ii < hasbothpointsother.Size(); ii++)
+			(*testout) << mesh[hasbothpointsother[ii]] << endl;
+		    }
+		}
+	    }
+
+	  if(hasbothpointsother.Size() > 0 && periodic)
+	    throw NgException("SwapImproveSurface: Assumption about interface/periodicity wrong!");
+
+	  if(periodic)
+	    {
+	      for (int k = 0; k < elementsonnode[pi1other].Size(); k++)
+		{
+		  bool has1 = false, has2 = false;
+		  ElementIndex elnr = elementsonnode[pi1other][k];
+		  const Element & elem = mesh[elnr];
+	      
+		  if (elem.IsDeleted()) continue;
+	      
+		  for (int l = 0; l < elem.GetNP(); l++)
+		    {
+		      if (elem[l] == pi1other) has1 = true;
+		      if (elem[l] == pi2other) has2 = true;
+		    }
+		  
+		  if (has1 && has2) 
+		    { 
+		      if(othermattype == -1)
+			othermattype = elem.GetIndex();
+
+		      // only once
+		      for (int l = 0; l < hasbothpointsother.Size(); l++)
+			if (hasbothpointsother[l] == elnr)
+			  has1 = 0;
+		      
+		      if (has1)
+			hasbothpointsother.Append (elnr);
+		    }
+		}
+	    }
+
+
+	  //for(k=0; k<hasbothpoints.Size(); k++)
+	  //  (*testout) << "hasbothpoints["<<k<<"]: " << mesh[hasbothpoints[k]] << endl;
+
+	  
+	  SurfaceElementIndex sel1=-1,sel2=-1;
+	  SurfaceElementIndex sel1other=-1,sel2other=-1;
+	  for(int k = 0; k < surfaceelementsonnode[pi1].Size(); k++)
+	    {
+	      bool has1 = false, has2 = false;
+	      SurfaceElementIndex elnr = surfaceelementsonnode[pi1][k];
+	      const Element2d & elem = mesh[elnr];
+
+	      if (elem.IsDeleted()) continue;
+
+	      for (int l = 0; l < elem.GetNP(); l++)
+		{
+		  if (elem[l] == pi1) has1 = true;
+		  if (elem[l] == pi2) has2 = true;
+		}
+
+	      if(has1 && has2 && elnr != sel2)
+		{
+		  sel1 = sel2;
+		  sel2 = elnr;
+		}
+	    }
+
+	  if(periodic)
+	    {
+	      for(int k = 0; k < surfaceelementsonnode[pi1other].Size(); k++)
+		{
+		  bool has1 = false, has2 = false;
+		  SurfaceElementIndex elnr = surfaceelementsonnode[pi1other][k];
+		  const Element2d & elem = mesh[elnr];
+
+		  if (elem.IsDeleted()) continue;
+
+		  for (int l = 0; l < elem.GetNP(); l++)
+		    {
+		      if (elem[l] == pi1other) has1 = true;
+		      if (elem[l] == pi2other) has2 = true;
+		    }
+
+		  if(has1 && has2 && elnr != sel2other)
+		    {
+		      sel1other = sel2other;
+		      sel2other = elnr;
+		    }
+		}
+	    }
+	  else
+	    {
+	      sel1other = sel1; sel2other = sel2;
+	    }
+
+	  //(*testout) << "sel1 " << sel1 << " sel2 " << sel2 << " el " << mesh[sel1] << " resp. " << mesh[sel2] << endl;
+
+	  PointIndex sp1(0), sp2(0);
+	  PointIndex sp1other, sp2other;
+	  for(int l=0; l<mesh[sel1].GetNP(); l++)
+	    if(mesh[sel1][l] != pi1 && mesh[sel1][l] != pi2)
+	      sp1 = mesh[sel1][l];
+	  for(int l=0; l<mesh[sel2].GetNP(); l++)
+	    if(mesh[sel2][l] != pi1 && mesh[sel2][l] != pi2)
+	      sp2 = mesh[sel2][l];
+
+	  if(periodic)
+	    {
+	      sp1other = (*(*used_idmaps)[idnum])[sp1];
+	      sp2other = (*(*used_idmaps)[idnum])[sp2];
+
+	      bool change = false;
+	      for(int l=0; !change && l<mesh[sel1other].GetNP(); l++)
+		change = (sp2other == mesh[sel1other][l]);
+	      
+	      if(change)
+		{
+		  SurfaceElementIndex aux = sel1other;
+		  sel1other = sel2other;
+		  sel2other = aux;
+		}
+
+	    }
+	  else
+	    {
+	      sp1other = sp1; sp2other = sp2;
+	    }
+	  
+	  Vec<3> v1 = mesh[sp1]-mesh[pi1],
+	    v2 = mesh[sp2]-mesh[pi1],
+	    v3 = mesh[sp1]-mesh[pi2],
+	    v4 = mesh[sp2]-mesh[pi2];
+	  double vol = 0.5*(Cross(v1,v2).Length() + Cross(v3,v4).Length());
+	  h = sqrt(vol);
+	  h = 0;
+
+	  sbad = CalcTriangleBadness (mesh[pi1],mesh[pi2],mesh[sp1],0,0) + 
+	    CalcTriangleBadness (mesh[pi2],mesh[pi1],mesh[sp2],0,0);
+	  
+
+
+	  bool puretet = true;
+	  for (int k = 0; puretet && k < hasbothpoints.Size(); k++)
+	    if (mesh[hasbothpoints[k]].GetType () != TET)
+	      puretet = false;
+	  for (int k = 0; puretet && k < hasbothpointsother.Size(); k++)
+	    if (mesh[hasbothpointsother[k]].GetType () != TET)
+	      puretet = false;
+	  if (!puretet)
+	    continue;
+
+	  int nsuround = hasbothpoints.Size();
+	  int nsuroundother = hasbothpointsother.Size();
+
+	  Array < int > outerpoints(nsuround+1);
+	  outerpoints[0] = sp1;
+
+	  for(int i=0; i<nsuround; i++)
+	    {
+	      bool done = false;
+	      for(int jj=i; !done && jj<hasbothpoints.Size(); jj++)
+		{
+		  for(int k=0; !done && k<4; k++)
+		    if(mesh[hasbothpoints[jj]][k] == outerpoints[i])
+		      {
+			done = true;
+			for(int l=0; l<4; l++)
+			  if(mesh[hasbothpoints[jj]][l] != pi1 &&
+			     mesh[hasbothpoints[jj]][l] != pi2 &&
+			     mesh[hasbothpoints[jj]][l] != outerpoints[i])
+			    outerpoints[i+1] = mesh[hasbothpoints[jj]][l];
+		      }
+		  if(done)
+		    {
+		      ElementIndex aux = hasbothpoints[i];
+		      hasbothpoints[i] = hasbothpoints[jj];
+		      hasbothpoints[jj] = aux;
+		    }
+		}
+	    }
+	  if(outerpoints[nsuround] != sp2)
+	    {
+	      cerr << "OJE OJE OJE" << endl;
+	      (*testout) << "OJE OJE OJE" << endl;
+	      (*testout) << "hasbothpoints: " << endl;
+	      for(int ii=0; ii < hasbothpoints.Size(); ii++)
+		{
+		  (*testout) << mesh[hasbothpoints[ii]] << endl;
+		  for(int jj=0; jj<mesh[hasbothpoints[ii]].GetNP(); jj++)
+		    if(mesh.mlbetweennodes[mesh[hasbothpoints[ii]][jj]][0] > 0)
+		      (*testout) << mesh[hasbothpoints[ii]][jj] << " between "
+				 << mesh.mlbetweennodes[mesh[hasbothpoints[ii]][jj]][0] << " and "
+				 << mesh.mlbetweennodes[mesh[hasbothpoints[ii]][jj]][1] << endl;
+		}
+	      (*testout) << "outerpoints: " << outerpoints << endl;
+	      (*testout) << "sel1 " << mesh[sel1] << endl
+			 << "sel2 " << mesh[sel2] << endl;
+	      for(int ii=0; ii<3; ii++)
+		{
+		  if(mesh.mlbetweennodes[mesh[sel1][ii]][0] > 0)
+		    (*testout) << mesh[sel1][ii] << " between "
+			       << mesh.mlbetweennodes[mesh[sel1][ii]][0] << " and "
+			       << mesh.mlbetweennodes[mesh[sel1][ii]][1] << endl;
+		  if(mesh.mlbetweennodes[mesh[sel2][ii]][0] > 0)
+		    (*testout) << mesh[sel2][ii] << " between "
+			       << mesh.mlbetweennodes[mesh[sel2][ii]][0] << " and "
+			       << mesh.mlbetweennodes[mesh[sel2][ii]][1] << endl;
+		}
+	    }
+
+	  
+	  Array < int > outerpointsother;
+
+	  if(nsuroundother > 0)
+	    {
+	      outerpointsother.SetSize(nsuroundother+1);
+	      outerpointsother[0] = sp2other;
+	    }
+
+	  for(int i=0; i<nsuroundother; i++)
+	    {
+	      bool done = false;
+	      for(int jj=i; !done && jj<hasbothpointsother.Size(); jj++)
+		{
+		  for(int k=0; !done && k<4; k++)
+		    if(mesh[hasbothpointsother[jj]][k] == outerpointsother[i])
+		      {
+			done = true;
+			for(int l=0; l<4; l++)
+			  if(mesh[hasbothpointsother[jj]][l] != pi1other &&
+			     mesh[hasbothpointsother[jj]][l] != pi2other &&
+			     mesh[hasbothpointsother[jj]][l] != outerpointsother[i])
+			    outerpointsother[i+1] = mesh[hasbothpointsother[jj]][l];
+		      }
+		  if(done)
+		    {
+		      ElementIndex aux = hasbothpointsother[i];
+		      hasbothpointsother[i] = hasbothpointsother[jj];
+		      hasbothpointsother[jj] = aux;
+		    }
+		}
+	    }
+	  if(nsuroundother > 0 && outerpointsother[nsuroundother] != sp1other)
+	    {
+	      cerr << "OJE OJE OJE (other)" << endl;
+	      (*testout) << "OJE OJE OJE (other)" << endl;
+	      (*testout) << "pi1 " << pi1 << " pi2 " << pi2 << " sp1 " << sp1 << " sp2 " << sp2 << endl;
+	      (*testout) << "hasbothpoints: " << endl;
+	      for(int ii=0; ii < hasbothpoints.Size(); ii++)
+		{
+		  (*testout) << mesh[hasbothpoints[ii]] << endl;
+		  for(int jj=0; jj<mesh[hasbothpoints[ii]].GetNP(); jj++)
+		    if(mesh.mlbetweennodes[mesh[hasbothpoints[ii]][jj]][0] > 0)
+		      (*testout) << mesh[hasbothpoints[ii]][jj] << " between "
+				 << mesh.mlbetweennodes[mesh[hasbothpoints[ii]][jj]][0] << " and "
+				 << mesh.mlbetweennodes[mesh[hasbothpoints[ii]][jj]][1] << endl;
+		}
+	      (*testout) << "outerpoints: " << outerpoints << endl;
+	      (*testout) << "sel1 " << mesh[sel1] << endl
+			 << "sel2 " << mesh[sel2] << endl;
+	      for(int ii=0; ii<3; ii++)
+		{
+		  if(mesh.mlbetweennodes[mesh[sel1][ii]][0] > 0)
+		    (*testout) << mesh[sel1][ii] << " between "
+			       << mesh.mlbetweennodes[mesh[sel1][ii]][0] << " and "
+			       << mesh.mlbetweennodes[mesh[sel1][ii]][1] << endl;
+		  if(mesh.mlbetweennodes[mesh[sel2][ii]][0] > 0)
+		    (*testout) << mesh[sel2][ii] << " between "
+			       << mesh.mlbetweennodes[mesh[sel2][ii]][0] << " and "
+			       << mesh.mlbetweennodes[mesh[sel2][ii]][1] << endl;
+		}
+		  
+	      (*testout) << "pi1other " << pi1other << " pi2other " << pi2other << " sp1other " << sp1other << " sp2other " << sp2other << endl;
+	      (*testout) << "hasbothpointsother: " << endl;
+	      for(int ii=0; ii < hasbothpointsother.Size(); ii++)
+		{
+		  (*testout) << mesh[hasbothpointsother[ii]] << endl;
+		  for(int jj=0; jj<mesh[hasbothpointsother[ii]].GetNP(); jj++)
+		    if(mesh.mlbetweennodes[mesh[hasbothpointsother[ii]][jj]][0] > 0)
+		      (*testout) << mesh[hasbothpointsother[ii]][jj] << " between "
+				 << mesh.mlbetweennodes[mesh[hasbothpointsother[ii]][jj]][0] << " and "
+				 << mesh.mlbetweennodes[mesh[hasbothpointsother[ii]][jj]][1] << endl;
+		}
+	      (*testout) << "outerpoints: " << outerpointsother << endl;
+	      (*testout) << "sel1other " << mesh[sel1other] << endl
+			 << "sel2other " << mesh[sel2other] << endl;
+	      for(int ii=0; ii<3; ii++)
+		{
+		  if(mesh.mlbetweennodes[mesh[sel1other][ii]][0] > 0)
+		    (*testout) << mesh[sel1other][ii] << " between "
+			       << mesh.mlbetweennodes[mesh[sel1other][ii]][0] << " and "
+			       << mesh.mlbetweennodes[mesh[sel1other][ii]][1] << endl;
+		  if(mesh.mlbetweennodes[mesh[sel2other][ii]][0] > 0)
+		    (*testout) << mesh[sel2other][ii] << " between "
+			       << mesh.mlbetweennodes[mesh[sel2other][ii]][0] << " and "
+			       << mesh.mlbetweennodes[mesh[sel2other][ii]][1] << endl;
+		}
+	    }
+
+	  bad1=0;
+	  for(int i=0; i<hasbothpoints.Size(); i++)
+	    bad1 += CalcBad(mesh.Points(), mesh[hasbothpoints[i]],h);
+	  for(int i=0; i<hasbothpointsother.Size(); i++)
+	    bad1 += CalcBad(mesh.Points(), mesh[hasbothpointsother[i]],h);
+	  bad1 /= double(hasbothpoints.Size() + hasbothpointsother.Size());
+
+	  
+	  int startpoints,startpointsother;
+
+
+	  if(outerpoints.Size() == 3)
+	    startpoints = 1;
+	  else if(outerpoints.Size() == 4)
+	    startpoints = 2;
+	  else
+	    startpoints = outerpoints.Size();
+	  
+	  if(outerpointsother.Size() == 3)
+	    startpointsother = 1;
+	  else if(outerpointsother.Size() == 4)
+	    startpointsother = 2;
+	  else
+	    startpointsother = outerpointsother.Size();
+	  
+
+	  Array < Array < Element* > * > newelts(startpoints);
+	  Array < Array < Element* > * > neweltsother(startpointsother);
+
+	  double minbad = 1e50, minbadother = 1e50, currbad;
+	  int minpos = -1, minposother = -1;
+
+	  //(*testout) << "pi1 " << pi1 << " pi2 " << pi2 << " outerpoints " << outerpoints << endl;
+
+	  for(int i=0; i<startpoints; i++)
+	    {
+	      newelts[i] = new Array <Element*>(2*(nsuround-1));
+	      
+	      for(int jj=0; jj<nsuround-1; jj++)
+		{
+		  (*newelts[i])[2*jj] = new Element(TET);
+		  (*newelts[i])[2*jj+1] = new Element(TET);
+		  Element & newel1 = *((*newelts[i])[2*jj]);
+		  Element & newel2 = *((*newelts[i])[2*jj+1]);
+
+		  newel1[0] = pi1;
+		  newel1[1] = outerpoints[i];
+		  newel1[2] = outerpoints[(i+jj+1)%outerpoints.Size()];
+		  newel1[3] = outerpoints[(i+jj+2)%outerpoints.Size()];
+
+		  newel2[0] = pi2;
+		  newel2[1] = outerpoints[i];
+		  newel2[2] = outerpoints[(i+jj+2)%outerpoints.Size()];
+		  newel2[3] = outerpoints[(i+jj+1)%outerpoints.Size()];
+		  
+
+		  //(*testout) << "j " << j << " newel1 " << newel1[0] << " "<< newel1[1] << " "<< newel1[2] << " "<< newel1[3] << endl
+		  //     << " newel2 " << newel2[0] << " "<< newel2[1] << " "<< newel2[2] << " "<< newel2[3] << endl;
+		  
+		  newel1.SetIndex(mattype);
+		  newel2.SetIndex(mattype);
+
+		}
+
+	      bool wrongorientation = true;
+	      for(int jj = 0; wrongorientation && jj<newelts[i]->Size(); jj++)
+		wrongorientation = wrongorientation && WrongOrientation(mesh.Points(), *(*newelts[i])[jj]);
+	      
+	      currbad = 0;
+
+	      for(int jj=0; jj<newelts[i]->Size(); jj++)
+		{
+		  if(wrongorientation)
+		    Swap((*(*newelts[i])[jj])[2],(*(*newelts[i])[jj])[3]);
+
+
+		  // not two new faces on same surface
+		  Array<int> face_index;
+		  for(int k = 0; k<surfaceindicesonnode[(*(*newelts[i])[jj])[0]].Size(); k++)
+		    face_index.Append(surfaceindicesonnode[(*(*newelts[i])[jj])[0]][k]);
+
+		  for(int k=1; k<4; k++)
+		    {
+		      for(int l=0; l<face_index.Size(); l++)
+			{
+			  if(face_index[l] != -1 && 
+			     !(surfaceindicesonnode[(*(*newelts[i])[jj])[k]].Contains(face_index[l])))
+			    face_index[l] = -1;
+			}
+
+		    }
+		      
+		  for(int k=0; k<face_index.Size(); k++)
+		    if(face_index[k] != -1)
+		      currbad += 1e12;
+
+
+		  currbad += CalcBad(mesh.Points(),*(*newelts[i])[jj],h);
+
+
+		}  
+
+	      //currbad /= double(newelts[i]->Size());
+		    
+
+
+	      if(currbad < minbad)
+		{
+		  minbad = currbad;
+		  minpos = i;
+		}
+
+	    }
+
+	  if(startpointsother == 0)
+	    minbadother = 0;
+
+	  for(int i=0; i<startpointsother; i++)
+	    {
+	      neweltsother[i] = new Array <Element*>(2*(nsuroundother));
+	      
+	      for(int jj=0; jj<nsuroundother; jj++)
+		{
+		  (*neweltsother[i])[2*jj] = new Element(TET);
+		  (*neweltsother[i])[2*jj+1] = new Element(TET);
+		  Element & newel1 = *((*neweltsother[i])[2*jj]);
+		  Element & newel2 = *((*neweltsother[i])[2*jj+1]);
+
+		  newel1[0] = pi1other;
+		  newel1[1] = outerpointsother[i];
+		  newel1[2] = outerpointsother[(i+jj+1)%outerpointsother.Size()];
+		  newel1[3] = outerpointsother[(i+jj+2)%outerpointsother.Size()];
+
+		  newel2[0] = pi2other;
+		  newel2[1] = outerpointsother[i];
+		  newel2[2] = outerpointsother[(i+jj+2)%outerpointsother.Size()];
+		  newel2[3] = outerpointsother[(i+jj+1)%outerpointsother.Size()];
+		  
+
+		  //(*testout) << "j " << j << " newel1 " << newel1[0] << " "<< newel1[1] << " "<< newel1[2] << " "<< newel1[3] << endl
+		  //	     << " newel2 " << newel2[0] << " "<< newel2[1] << " "<< newel2[2] << " "<< newel2[3] << endl;
+		  
+		  newel1.SetIndex(othermattype);
+		  newel2.SetIndex(othermattype);
+
+		}
+
+	      bool wrongorientation = true;
+	      for(int jj = 0; wrongorientation && jj<neweltsother[i]->Size(); jj++)
+		wrongorientation = wrongorientation && WrongOrientation(mesh.Points(), *(*neweltsother[i])[jj]);
+	      
+	      currbad = 0;
+
+	      for(int jj=0; jj<neweltsother[i]->Size(); jj++)
+		{
+		  if(wrongorientation)
+		    Swap((*(*neweltsother[i])[jj])[2],(*(*neweltsother[i])[jj])[3]);
+
+		  currbad += CalcBad(mesh.Points(),*(*neweltsother[i])[jj],h);
+		}  
+
+	      //currbad /= double(neweltsother[i]->Size());
+		    
+
+
+	      if(currbad < minbadother)
+		{
+		  minbadother = currbad;
+		  minposother = i;
+		}
+
+	    }
+
+	  //(*testout) << "minbad " << minbad << " bad1 " << bad1 << endl;
+
+	  
+	  double sbadnew = CalcTriangleBadness (mesh[pi1],mesh[sp2],mesh[sp1],0,0) + 
+	    CalcTriangleBadness (mesh[pi2],mesh[sp1],mesh[sp2],0,0);
+	  
+
+	  int denom = newelts[minpos]->Size();
+	  if(minposother >= 0)
+	    denom += neweltsother[minposother]->Size();
+	  
+
+	  if((minbad+minbadother)/double(denom) < bad1 && 
+	     sbadnew < sbad)
+	    {
+	      cnt++;
+
+	      swapped = true;
+
+
+	      int start1 = -1;
+	      for(int l=0; l<3; l++)
+		if(mesh[sel1][l] == pi1)
+		  start1 = l;
+	      if(mesh[sel1][(start1+1)%3] == pi2)
+		{
+		  mesh[sel1][0] = pi1;
+		  mesh[sel1][1] = sp2;
+		  mesh[sel1][2] = sp1;
+		  mesh[sel2][0] = pi2;
+		  mesh[sel2][1] = sp1;
+		  mesh[sel2][2] = sp2;
+		}
+	      else
+		{
+		  mesh[sel1][0] = pi2;
+		  mesh[sel1][1] = sp2;
+		  mesh[sel1][2] = sp1;
+		  mesh[sel2][0] = pi1;
+		  mesh[sel2][1] = sp1;
+		  mesh[sel2][2] = sp2;
+		}
+	      //(*testout) << "changed surface element " << sel1 << " to " << mesh[sel1] << ", " << sel2 << " to " << mesh[sel2] << endl;
+
+	      for(int l=0; l<3; l++)
+		{
+		  surfaceelementsonnode.Add(mesh[sel1][l],sel1);
+		  surfaceelementsonnode.Add(mesh[sel2][l],sel2);
+		}
+	      
+
+
+	      if(periodic)
+		{
+		  start1 = -1;
+		  for(int l=0; l<3; l++)
+		    if(mesh[sel1other][l] == pi1other)
+		      start1 = l;
+		  
+
+
+		  //(*testout) << "changed surface elements " << mesh[sel1other] << " and " << mesh[sel2other] << endl;
+		  if(mesh[sel1other][(start1+1)%3] == pi2other)
+		    {
+		      mesh[sel1other][0] = pi1other;
+		      mesh[sel1other][1] = sp2other;
+		      mesh[sel1other][2] = sp1other;
+		      mesh[sel2other][0] = pi2other;
+		      mesh[sel2other][1] = sp1other;
+		      mesh[sel2other][2] = sp2other;
+		      //(*testout) << "       with rule 1" << endl;
+		    }
+		  else
+		    {
+		      mesh[sel1other][0] = pi2other;
+		      mesh[sel1other][1] = sp2other;
+		      mesh[sel1other][2] = sp1other;
+		      mesh[sel2other][0] = pi1other;
+		      mesh[sel2other][1] = sp1other;
+		      mesh[sel2other][2] = sp2other;
+		      //(*testout) << "       with rule 2" << endl;
+		    }
+		  //(*testout) << "         to " << mesh[sel1other] << " and " << mesh[sel2other] << endl;
+		  
+		  //(*testout) << "  and surface element " << sel1other << " to " << mesh[sel1other] << ", " << sel2other << " to " << mesh[sel2other] << endl;
+
+		  for(int l=0; l<3; l++)
+		    {
+		      surfaceelementsonnode.Add(mesh[sel1other][l],sel1other);
+		      surfaceelementsonnode.Add(mesh[sel2other][l],sel2other);
+		    }
+		}
+
+
+
+
+	      for(int i=0; i<hasbothpoints.Size(); i++)
+		{
+		  mesh[hasbothpoints[i]] = *(*newelts[minpos])[i];
+
+		  for(int l=0; l<4; l++)
+		    elementsonnode.Add((*(*newelts[minpos])[i])[l],hasbothpoints[i]);
+		}
+
+	      for(int i=hasbothpoints.Size(); i<(*newelts[minpos]).Size(); i++)
+		{
+		  ElementIndex ni = mesh.AddVolumeElement(*(*newelts[minpos])[i]);
+		  
+		  for(int l=0; l<4; l++)
+		    elementsonnode.Add((*(*newelts[minpos])[i])[l],ni);
+		}
+
+	      if(hasbothpointsother.Size() > 0)
+		{
+		  for(int i=0; i<hasbothpointsother.Size(); i++)
+		    {
+		      mesh[hasbothpointsother[i]] = *(*neweltsother[minposother])[i];
+		      for(int l=0; l<4; l++)
+			elementsonnode.Add((*(*neweltsother[minposother])[i])[l],hasbothpointsother[i]);
+		    }
+		  
+		  for(int i=hasbothpointsother.Size(); i<(*neweltsother[minposother]).Size(); i++)
+		    {
+		      ElementIndex ni = mesh.AddVolumeElement(*(*neweltsother[minposother])[i]);
+		      for(int l=0; l<4; l++)
+			elementsonnode.Add((*(*neweltsother[minposother])[i])[l],ni);
+		    }
+		}
+
+	      
+
+	    }
+
+	  for(int i=0; i<newelts.Size(); i++)
+	    {
+	      for(int jj=0; jj<newelts[i]->Size(); jj++)
+		delete (*newelts[i])[jj];
+	      delete newelts[i];
+	    }
+
+	  for(int i=0; i<neweltsother.Size(); i++)
+	    {
+	      for(int jj=0; jj<neweltsother[i]->Size(); jj++)
+		delete (*neweltsother[i])[jj];
+	      delete neweltsother[i];
+	    }
+	
+	}
+    }
+
+  PrintMessage (5, cnt, " swaps performed");
+
+
+  for(int i=0; i<locidmaps.Size(); i++)
+    delete locidmaps[i];
+
+
+  mesh.Compress ();
+
+  multithread.task = savetask;
+}
+  
+
+
+
+
+
+
+
+/*
+  2 -> 3 conversion
+*/
+
+
+void MeshOptimize3d :: SwapImprove2 (Mesh & mesh, OPTIMIZEGOAL goal)
+{
+  PointIndex pi1(0), pi2(0), pi3(0), pi4(0), pi5(0);
+  Element el21(TET), el22(TET), el31(TET), el32(TET), el33(TET);
+
+  int cnt = 0;
+  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;
+  //  cout << "tot bad = " << bad1 << endl;
+
+  // find elements on node
+
+  for (ElementIndex ei = 0; ei < ne; ei++)
+    for (int j = 0; j < mesh[ei].GetNP(); j++)
+      elementsonnode.Add (mesh[ei][j], ei);
+
+  for (SurfaceElementIndex sei = 0; sei < nse; sei++)
+    for (int j = 0; j < 3; j++)
+      belementsonnode.Add (mesh[sei][j], sei);
+
+  for (ElementIndex eli1 = 0; eli1 < ne; 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;
+
+      // cout << "eli = " << eli1 << endl;
+      //      (*testout) << "swapimp2, eli = " << eli1 << "; el = " << mesh[eli1] << endl;
+
+      for (int j = 0; j < 4; j++)
+	{
+	  // loop over faces
+      
+	  Element & elem = mesh[eli1];
+	  // if (elem[0] < PointIndex::BASE) continue;
+	  if (elem.IsDeleted()) continue;
+
+	  int 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 (int k = 0; k < belementsonnode[pi1].Size(); k++)
+	    {
+	      const Element2d & bel = 
+		mesh[belementsonnode[pi1][k]];
+
+	      bool bface1 = 1;
+	      for (int 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 (int k = 0; k < row.Size(); k++)
+	    {
+	      ElementIndex 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 (int 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)
+			{
+			  //			  cout << "do swap, eli1 = " << eli1 << "; eli2 = " << eli2 << endl;
+			  //			  (*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 (int l = 0; l < 4; l++)
+			    {
+			      elementsonnode.Add (el31[l], eli1);
+			      elementsonnode.Add (el32[l], eli2);
+			      elementsonnode.Add (el33[l], neli);
+			    }
+
+			  break;
+			}
+		    }
+		}
+	    }
+	}
+    }
+
+
+  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/contrib/Netgen/libsrc/meshing/improve3.hpp b/contrib/Netgen/libsrc/meshing/improve3.hpp
new file mode 100644
index 0000000000..41001e8426
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/improve3.hpp
@@ -0,0 +1,125 @@
+#ifndef FILE_IMPROVE3
+#define FILE_IMPROVE3
+
+
+extern double CalcTotalBad (const Mesh::T_POINTS & points, 
+			    const Mesh::T_VOLELEMENTS & elements,
+			    const MeshingParameters & mp);
+
+
+///
+class MeshOptimize3d
+{
+  const MeshingParameters & mp;
+public:
+  MeshOptimize3d (const MeshingParameters & amp) : mp(amp) { ; }
+  void CombineImprove (Mesh & mesh, OPTIMIZEGOAL goal = OPT_QUALITY);
+  void SplitImprove (Mesh & mesh, OPTIMIZEGOAL goal = OPT_QUALITY);
+  void SwapImprove (Mesh & mesh, OPTIMIZEGOAL goal = OPT_QUALITY,
+		    const BitArray * working_elements = NULL);
+  void SwapImproveSurface (Mesh & mesh, OPTIMIZEGOAL goal = OPT_QUALITY,
+			   const BitArray * working_elements = NULL,
+			   const Array< Array<int,PointIndex::BASE>* > * idmaps = NULL);
+  void SwapImprove2 (Mesh & mesh, OPTIMIZEGOAL goal = OPT_QUALITY);
+
+  double 
+  CalcBad (const Mesh::T_POINTS & points, const Element & elem, double h)
+  {
+    if (elem.GetType() == TET)
+      return CalcTetBadness (points[elem[0]], points[elem[1]],  
+			     points[elem[2]], points[elem[3]], h, mp);  
+    return 0;
+  }
+
+
+  double CalcTotalBad (const Mesh::T_POINTS & points, 
+		       const Mesh::T_VOLELEMENTS & elements)
+  {
+    return netgen::CalcTotalBad (points, elements, mp);
+  }
+
+};
+
+
+inline double 
+CalcBad (const Mesh::T_POINTS & points, const Element & elem, double h, const MeshingParameters & mp)
+{
+  if (elem.GetType() == TET)
+    return CalcTetBadness (points[elem[0]], points[elem[1]],  
+			   points[elem[2]], points[elem[3]], h, mp);  
+  return 0;
+}
+
+
+
+extern int WrongOrientation (const Mesh::T_POINTS & points, const Element & el);
+
+
+/* Functional depending of inner point inside triangular surface */
+
+
+class MinFunctionSum : public MinFunction
+{
+protected:
+  Array<MinFunction*> functions;
+ 
+public:
+  
+  virtual double Func (const Vector & x) const;
+  virtual void Grad (const Vector & x, Vector & g) 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;
+
+  void AddFunction(MinFunction & fun);
+  
+  const MinFunction & Function(int i) const;
+  MinFunction & Function(int i);  
+};
+  
+
+class PointFunction1 : public MinFunction
+{
+  Mesh::T_POINTS & points;
+  const Array<INDEX_3> & faces;
+  const MeshingParameters & mp;
+  double h;
+public:
+  PointFunction1 (Mesh::T_POINTS & apoints, 
+		  const Array<INDEX_3> & afaces,
+		  const MeshingParameters & amp,
+		  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;
+};
+
+class JacobianPointFunction : public MinFunction
+{
+public:
+  Mesh::T_POINTS & points;
+  const Mesh::T_VOLELEMENTS & elements;
+  TABLE<INDEX> elementsonpoint;
+  PointIndex actpind;
+
+  bool onplane;
+  Vec<3> nv;
+  
+public:
+  JacobianPointFunction (Mesh::T_POINTS & apoints, 
+			 const Mesh::T_VOLELEMENTS & aelements);
+  
+  virtual void SetPointIndex (PointIndex 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;
+
+  inline void SetNV(const Vec<3> & anv) {nv = anv; onplane = true;}
+  inline void UnSetNV(void) {onplane = false;}
+};
+
+
+
+#endif
diff --git a/contrib/Netgen/libsrc/meshing/localh.cpp b/contrib/Netgen/libsrc/meshing/localh.cpp
new file mode 100644
index 0000000000..99767360be
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/localh.cpp
@@ -0,0 +1,708 @@
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+
+namespace netgen
+{
+
+  GradingBox :: GradingBox (const double * ax1, const double * ax2)
+  {
+    h2 = 0.5 * (ax2[0] - ax1[0]);
+    for (int i = 0; i < 3; i++)
+      xmid[i] = 0.5 * (ax1[i] + ax2[i]);
+
+    for (int i = 0; i < 8; i++)
+      childs[i] = NULL;
+    father = NULL;
+
+    flags.cutboundary = 0;
+    flags.isinner = 0;
+    flags.oldcell = 0;
+    flags.pinner = 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()
+  {
+    for (int 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;
+
+    boundingbox = Box3d (pmin, pmax);
+    grading = agrading;
+
+    // a small enlargement, non-regular points 
+    double val = 0.0879;
+    for (int 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 (int i = 1; i <= 2; i++)
+      if (x2[i] - x1[i] > hmax)
+	hmax = x2[i] - x1[i];
+
+    for (int i = 0; i <= 2; i++)
+      x2[i] = x1[i] + hmax;
+
+    root = new GradingBox (x1, x2);
+    boxes.Append (root);
+  }
+
+
+  LocalH :: LocalH (const Box<3> & box, double agrading)
+  {
+    Point3d pmin = box.PMin();
+    Point3d pmax = box.PMax();
+
+    double x1[3], x2[3];
+    double hmax;
+
+    boundingbox = Box3d (pmin, pmax);
+    grading = agrading;
+
+    // a small enlargement, non-regular points 
+    double val = 0.0879;
+    for (int 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 (int i = 1; i <= 2; i++)
+      if (x2[i] - x1[i] > hmax)
+	hmax = x2[i] - x1[i];
+
+    for (int 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;
+    for (int 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);
+      }
+  }
+
+
+
+  double LocalH :: GetH (const Point3d & x) const
+  {
+    const GradingBox * box = root;
+
+    while (1)
+      {
+	int 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;
+
+	if (box->childs[childnr])
+	  box = box->childs[childnr];
+	else
+	  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;
+      
+    double hmin = 2 * box->h2; // box->x2[0] - box->x1[0];
+  
+    for (int i = 0; i < 8; i++)
+      if (box->childs[i])
+	hmin = min2 (hmin, GetMinHRec (pmin, pmax, box->childs[i]));
+
+    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;
+
+
+    box->flags.cutboundary = 1;
+    for (int i = 0; i < 8; i++)
+      if (box->childs[i])
+	CutBoundaryRec (pmin, pmax, box->childs[i]);
+  }
+
+
+
+
+  void LocalH :: FindInnerBoxes (AdFront3 * adfront,
+				 int (*testinner)(const Point3d & p1))
+  {
+    int nf = adfront->GetNF();
+
+    for (int 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 (int i = 1; i <= nf; i++)
+      {
+	faceinds.Elem(i) = i;
+	adfront->GetFaceBoundingBox(i, faceboxes.Elem(i));
+      }
+  
+    for (int 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;
+  
+    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);
+
+    ArrayMem<int, 100> faceused;
+    ArrayMem<int, 100> faceused2;
+    ArrayMem<int, 100> facenotused;
+
+    /*
+    faceused.SetSize(0);
+    facenotused.SetSize(0);
+    faceused2.SetSize(0);
+    */
+
+    for (int 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 (int j = 1; j <= faceused.Size(); j++)
+      faceinds.Elem(j) = faceused.Get(j);
+    for (int 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;
+      }
+
+    // cout << "faceused: " << faceused.Size() << ", " << faceused2.Size() << ", " << facenotused.Size() << endl;
+
+    int nf = faceused.Size();
+    for (int i = 0; i < 8; i++)
+      FindInnerBoxesRec2 (box->childs[i], adfront, faceboxes, faceinds, nf);
+  }
+
+
+
+  void LocalH :: FindInnerBoxesRec ( int (*inner)(const Point3d & p),
+				     GradingBox * box)
+  {
+    if (box->flags.cutboundary)
+      {
+	for (int i = 0; i < 8; i++)
+	  if (box->childs[i])
+	    FindInnerBoxesRec (inner, box->childs[i]);
+      }
+    else
+      {
+	if (inner (box->PMid()))
+	  SetInnerBoxesRec (box);
+      }
+  }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+  void LocalH :: FindInnerBoxes (AdFront2 * adfront,
+				 int (*testinner)(const Point<2> & p1))
+  {
+    int nf = adfront->GetNFL();
+
+    for (int i = 0; i < boxes.Size(); i++)
+      boxes[i] -> flags.isinner = 0;
+
+    root->flags.isinner = 0;
+
+    Point<2> rpmid(root->xmid[0], root->xmid[1], root->xmid[2]);
+    Vec<2> rv(root->h2, root->h2);
+    Point<2> rx2 = rpmid + rv;
+    // Point<2> rx1 = rpmid - rv;
+
+
+    root->flags.pinner = !adfront->SameSide (rpmid, rx2);
+  
+    if (testinner)
+      (*testout) << "inner = " << root->flags.pinner << " =?= "
+		 << testinner(rpmid) << endl;
+  
+    Array<int> faceinds(nf);
+    Array<Box<3> > faceboxes(nf);
+
+    for (int i = 0; i < nf; i++)
+      {
+	faceinds[i] = i;
+	// adfront->GetFaceBoundingBox(i, faceboxes.Elem(i));
+
+	const FrontLine & line = adfront->GetLine(i);
+	faceboxes[i].Set (adfront->GetPoint (line.L().I1()));
+	faceboxes[i].Add (adfront->GetPoint (line.L().I2()));
+
+      }
+  
+    for (int i = 0; i < 8; i++)
+      FindInnerBoxesRec2 (root->childs[i], adfront, faceboxes, faceinds, nf);
+  }
+
+
+  void LocalH :: 
+  FindInnerBoxesRec2 (GradingBox * box,
+		      class AdFront2 * adfront, 
+		      Array<Box<3> > & faceboxes,
+		      Array<int> & faceinds, int nfinbox)
+  {
+    if (!box) return;
+  
+    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);
+
+    ArrayMem<int, 100> faceused;
+    ArrayMem<int, 100> faceused2;
+    ArrayMem<int, 100> facenotused;
+
+
+    for (int 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 (int j = 1; j <= faceused.Size(); j++)
+      faceinds.Elem(j) = faceused.Get(j);
+    for (int 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
+	  {
+	    Point<2> c2d (c.X(), c.Y());
+	    Point<2> cf2d (cf.X(), cf.Y());
+	    if (adfront->SameSide (c2d, cf2d, &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;
+      }
+
+    // cout << "faceused: " << faceused.Size() << ", " << faceused2.Size() << ", " << facenotused.Size() << endl;
+
+    int nf = faceused.Size();
+    for (int i = 0; i < 8; i++)
+      FindInnerBoxesRec2 (box->childs[i], adfront, faceboxes, faceinds, nf);
+  }
+
+
+
+  void LocalH :: FindInnerBoxesRec ( int (*inner)(const Point<2> & p),
+				     GradingBox * box)
+  {
+    if (box->flags.cutboundary)
+      {
+	for (int i = 0; i < 8; i++)
+	  if (box->childs[i])
+	    FindInnerBoxesRec (inner, box->childs[i]);
+      }
+    else
+      {
+	Point<2> p2d(box->PMid()(0), box->PMid()(1)); 
+	if (inner (p2d))
+	  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 ()
+  {
+    for (int i = 0; i < boxes.Size(); i++)
+      {
+	double h = boxes[i]->hopt;
+	Point3d c = boxes[i]->PMid();
+      
+	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<Point<3> > & points)
+  {
+    for (int i = 0; i < boxes.Size(); i++)
+      if (boxes[i] -> flags.isinner)
+	points.Append ( boxes[i] -> PMid() );
+  }
+
+
+  void LocalH :: GetOuterPoints (Array<Point<3> > & points)
+  {
+    for (int i = 0; i < boxes.Size(); i++)
+      if (!boxes[i]->flags.isinner && !boxes[i]->flags.cutboundary)
+	points.Append ( boxes[i] -> PMid());
+  }
+
+
+  void LocalH :: Convexify ()
+  {
+    ConvexifyRec (root);
+  }
+
+  void LocalH :: ConvexifyRec (GradingBox * box)
+  {
+    Point<3> center = box -> PMid();
+
+    double size = 2 * box->h2; // box->x2[0] - box->x1[0];
+    double dx = 0.6 * size;
+
+    double maxh = box->hopt;
+  
+    for (int i = 0; i < 3; i++)
+      {
+	Point<3> hp = center;
+	hp(i) += dx;
+	maxh = max2 (maxh, GetH(hp));
+	hp(i) = center(i)-dx;
+	maxh = max2 (maxh, GetH(hp));
+      }
+
+    if (maxh < 0.95 * box->hopt)
+      SetH (center, maxh);
+
+    for (int 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/contrib/Netgen/libsrc/meshing/localh.hpp b/contrib/Netgen/libsrc/meshing/localh.hpp
new file mode 100644
index 0000000000..ee279c8696
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/localh.hpp
@@ -0,0 +1,187 @@
+#ifndef LOCALH
+#define LOCALH
+
+/**************************************************************************/
+/* File:   localh.hh                                                      */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   29. Jan. 97                                                    */
+/**************************************************************************/
+
+
+namespace netgen
+{
+
+
+  /// box for grading
+  class GradingBox
+  {
+    /// xmid
+    float xmid[3];
+    /// half edgelength
+    float h2;
+    ///
+    GradingBox * childs[8];
+    ///
+    GradingBox * father;
+    ///
+    double hopt;
+    ///
+  public:
+
+    struct 
+    {
+      unsigned int cutboundary:1;
+      unsigned int isinner:1;
+      unsigned int oldcell:1;
+      unsigned int pinner:1;
+    } flags;
+
+    ///
+    GradingBox (const double * ax1, const double * ax2);
+    ///
+    void DeleteChilds();
+    ///
+
+    Point<3> PMid() const { return Point<3> (xmid[0], xmid[1], xmid[2]); }
+    double H2() const { return h2; }
+
+    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 (const Box<3> & box, double grading);
+    ///
+    ~LocalH();
+    ///
+    void Delete();
+    ///
+    void SetGrading (double agrading) { grading = agrading; }
+    ///
+    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); }
+    void CutBoundary (const Box<3> & box)
+    { CutBoundaryRec (box.PMin(), box.PMax(), root); }
+  
+    /// find inner boxes
+    void FindInnerBoxes (class AdFront3 * adfront,
+			 int (*testinner)(const Point3d & p1));
+
+    void FindInnerBoxes (class AdFront2 * adfront,
+			 int (*testinner)(const Point<2> & p1));
+
+
+    /// clears all flags 
+    void ClearFlags ()
+    { ClearFlagsRec(root); }
+
+    /// widen refinement zone
+    void WidenRefinement ();
+
+    /// get points in inner elements
+    void GetInnerPoints (Array<Point<3> > & points);
+
+    /// get points in outer closure
+    void GetOuterPoints (Array<Point<3> > & 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 FindInnerBoxesRec ( int (*inner)(const Point<2> & p),
+			     GradingBox * box);
+
+    ///
+    void FindInnerBoxesRec2 (GradingBox * box,
+			     class AdFront2 * adfront,
+			     Array<Box<3> > & faceboxes,
+			     Array<int> & finds, int nfinbox);
+
+
+
+    ///
+    void SetInnerBoxesRec (GradingBox * box);
+
+    ///
+    void ClearFlagsRec (GradingBox * box);
+  
+    ///
+    void ConvexifyRec (GradingBox * box);
+
+    friend ostream & operator<< (ostream & ost, const LocalH & loch);
+  };
+
+
+
+
+  inline ostream & operator<< (ostream & ost, const GradingBox & box)
+  {
+    ost << "gradbox, pmid = " << box.PMid() << ", h2 = " << box.H2() 
+	<< " cutbound = " << box.flags.cutboundary << " isinner = " << box.flags.isinner 
+	<< endl;
+    return ost;
+  }
+
+  inline ostream & operator<< (ostream & ost, const LocalH & loch)
+  {
+    for (int i = 0; i < loch.boxes.Size(); i++)
+      ost << "box[" << i << "] = " << *(loch.boxes[i]);
+    return ost;
+  }
+
+}
+
+#endif
diff --git a/contrib/Netgen/libsrc/meshing/meshclass.cpp b/contrib/Netgen/libsrc/meshing/meshclass.cpp
new file mode 100644
index 0000000000..430a95ff85
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/meshclass.cpp
@@ -0,0 +1,5648 @@
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+namespace netgen
+{
+
+  Mesh :: Mesh ()
+  {
+    // volelements.SetName ("vol elements");
+    // surfelements.SetName ("surf elements");
+    // points.SetName ("meshpoints");
+
+    boundaryedges = NULL;
+    surfelementht = NULL; 
+    segmentht = NULL;
+
+    lochfunc = NULL;
+    mglevels = 1;
+    elementsearchtree = NULL;
+    elementsearchtreets = NextTimeStamp();
+    majortimestamp = timestamp = NextTimeStamp();
+    hglob = 1e10;
+    hmin = 0;
+    numvertices = -1;
+    dimension = 3;
+
+    topology = new MeshTopology (*this);
+    curvedelems = new CurvedElements (*this);
+    clusters = new AnisotropicClusters (*this);
+    ident = new Identifications (*this);
+
+    hpelements = NULL;
+    coarsemesh = NULL;
+
+    ps_startelement = 0;
+
+    geomtype = NO_GEOM;
+
+    bcnames.SetSize(0);
+
+#ifdef PARALLEL
+    paralleltop = new ParallelMeshTopology (*this);
+#endif
+  }
+
+
+  Mesh :: ~Mesh()
+  {
+    delete lochfunc;
+    delete boundaryedges;
+    delete surfelementht;
+    delete segmentht;
+    delete curvedelems;
+    delete clusters;
+    delete topology;
+    delete ident;
+    delete elementsearchtree;
+    delete coarsemesh;
+    delete hpelements;
+
+    for (int i = 0; i < materials.Size(); i++)
+      delete [] materials[i];
+
+    for(int i = 0; i < userdata_int.Size(); i++)
+      delete userdata_int[i];
+    for(int i = 0; i < userdata_double.Size(); i++)
+      delete userdata_double[i];
+
+    for (int i = 0; i < bcnames.Size(); i++ )
+      if ( bcnames[i] ) delete bcnames[i];
+
+#ifdef PARALLEL
+    delete paralleltop;
+#endif
+  }
+
+
+  Mesh & Mesh :: operator= (const Mesh & mesh2)
+  {
+    points = mesh2.points;
+    // eltyps = mesh2.eltyps;
+    segments = mesh2.segments;
+    surfelements = mesh2.surfelements;
+    volelements = mesh2.volelements;
+    lockedpoints = mesh2.lockedpoints;
+    facedecoding = mesh2.facedecoding;
+    dimension = mesh2.dimension;
+
+    bcnames.SetSize( mesh2.bcnames.Size() );
+    for ( int i = 0; i < mesh2.bcnames.Size(); i++ )
+      if ( mesh2.bcnames[i] ) bcnames[i] = new string ( *mesh2.bcnames[i] );
+      else bcnames[i] = 0;
+
+    return *this;
+  }
+
+
+  void Mesh :: DeleteMesh()
+  {
+    NgLock lock(mutex);
+    lock.Lock();
+
+    points.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);
+
+    delete ident;
+    ident = new Identifications (*this);
+    delete topology;
+    topology = new MeshTopology (*this);
+    delete curvedelems;
+    curvedelems = new CurvedElements (*this);
+    delete clusters;
+    clusters = new AnisotropicClusters (*this);
+
+    for ( int i = 0; i < bcnames.Size(); i++ )
+      if ( bcnames[i] ) delete bcnames[i];
+
+#ifdef PARALLEL
+    delete paralleltop;
+    paralleltop = new ParallelMeshTopology (*this);
+#endif
+
+    lock.UnLock();
+
+    timestamp = NextTimeStamp();
+  }
+
+
+  void Mesh :: ClearSurfaceElements()
+  { 
+    surfelements.SetSize(0); 
+    for (int i = 0; i < facedecoding.Size(); i++)
+      facedecoding[i].firstelement = -1;
+
+    timestamp = NextTimeStamp();
+  }
+
+
+
+  PointIndex Mesh :: AddPoint (const Point3d & p, int layer)
+  { 
+    NgLock lock(mutex);
+    lock.Lock();
+
+    timestamp = NextTimeStamp();
+
+    PointIndex pi = points.Size() + PointIndex::BASE;
+    points.Append ( MeshPoint (p, layer, INNERPOINT) ); 
+
+#ifdef PARALLEL
+    points.Last().SetGhost(0);
+#endif
+
+    lock.UnLock();
+
+    return pi;
+  }
+
+  PointIndex Mesh :: AddPoint (const Point3d & p, int layer, POINTTYPE type)
+  { 
+    NgLock lock(mutex);
+    lock.Lock();
+
+    timestamp = NextTimeStamp();
+
+    PointIndex pi = points.Size() + PointIndex::BASE;
+    points.Append ( MeshPoint (p, layer, type) ); 
+
+#ifdef PARALLEL
+    points.Last().SetGhost(0);
+#endif
+
+    lock.UnLock();
+
+    return pi;
+  }
+
+
+#ifdef PARALLEL
+  PointIndex Mesh :: AddPoint (const Point3d & p, bool isghost,  int layer)
+  { 
+    NgLock lock(mutex);
+    lock.Lock();
+
+    timestamp = NextTimeStamp();
+
+    PointIndex pi = points.Size() + PointIndex::BASE;
+    points.Append ( MeshPoint (p, layer, INNERPOINT) ); 
+
+    points.Last().SetGhost(isghost);
+
+    lock.UnLock();
+
+    return pi;
+  }
+
+  PointIndex Mesh :: AddPoint (const Point3d & p, bool isghost, int layer, POINTTYPE type)
+  { 
+    NgLock lock(mutex);
+    lock.Lock();
+
+    timestamp = NextTimeStamp();
+
+    PointIndex pi = points.Size() + PointIndex::BASE;
+    points.Append ( MeshPoint (p, layer, type) ); 
+
+    points.Last().SetGhost(isghost);
+
+    lock.UnLock();
+
+    return pi;
+  }
+
+#endif
+
+
+
+  SegmentIndex Mesh :: AddSegment (const Segment & s)
+  { 
+    NgLock lock(mutex);	
+    lock.Lock();
+    timestamp = NextTimeStamp();
+
+    int maxn = max2 (s[0], s[1]);
+    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[0]] > EDGEPOINT) ptyps[s[0]] = EDGEPOINT;
+      if (ptyps[s[1]] > EDGEPOINT) ptyps[s[1]] = EDGEPOINT;
+    */
+
+    if (maxn <= points.Size())
+      {
+        if (points[s[0]].Type() > EDGEPOINT)
+          points[s[0]].SetType (EDGEPOINT);
+        if (points[s[1]].Type() > EDGEPOINT)
+          points[s[1]].SetType (EDGEPOINT);
+      }
+    /*
+      else
+      {
+      cerr << "edge points nrs > points.Size" << endl;
+      }
+    */
+
+    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 maxn = el[0];
+    for (int 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;
+
+      }
+    */
+    if (maxn <= points.Size())
+      {
+        for (int i = 0; i < el.GetNP(); i++)
+          if (points[el[i]].Type() > SURFACEPOINT)
+            points[el[i]].SetType(SURFACEPOINT);
+      }
+    /*
+      else
+      {
+      cerr << "surf points nrs > points.Size" << endl;      
+      }
+    */
+
+    SurfaceElementIndex si = surfelements.Size();
+    surfelements.Append (el); 
+
+    if (el.index > facedecoding.Size())
+      cerr << "has no facedecoding: fd.size = " << facedecoding.Size() << ", ind = " << el.index << endl;
+
+    surfelements.Last().next = facedecoding[el.index-1].firstelement;
+    facedecoding[el.index-1].firstelement = si;
+
+#ifdef PARALLEL
+    surfelements.Last().SetGhost ( el.IsGhost() );
+#endif
+
+    lock.UnLock();
+    return si;
+  }
+
+
+  ElementIndex Mesh :: AddVolumeElement (const Element & el)
+  { 
+    NgLock lock(mutex);
+    lock.Lock();
+
+    int maxn = el[0];
+    for (int 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;
+      }
+    */
+    /*
+      if (maxn > points.Size())
+      {
+      cerr << "add vol element before point" << endl;
+      }
+    */
+
+    int ve = volelements.Size();
+
+    volelements.Append (el); 
+    volelements.Last().flags.illegal_valid = 0;
+
+#ifdef PARALLEL
+    volelements.Last().SetGhost ( el.IsGhost() );
+#endif
+
+    // while (volelements.Size() > eltyps.Size())
+    // eltyps.Append (FREEELEMENT);
+
+    timestamp = NextTimeStamp();
+
+    lock.UnLock();
+    return ve;
+  }
+
+
+
+
+
+
+  void Mesh :: Save (const string & filename) const
+  {
+
+    ofstream outfile(filename.c_str());
+
+    Save(outfile);
+  }
+
+
+
+  void Mesh :: Save (ostream & outfile) const
+  {
+    int i, j;
+
+    double scale = 1;  // globflags.GetNumFlag ("scale", 1);
+    int inverttets = 0;  // globflags.GetDefineFlag ("inverttets");
+    int invertsurf = 0;  // globflags.GetDefineFlag ("invertsurfacemesh");
+
+
+
+    outfile << "mesh3d" << "\n";
+
+    outfile << "dimension\n" << GetDimension() << "\n";
+
+    outfile << "geomtype\n" << int(geomtype) << "\n";
+
+
+    outfile << "\n";
+    outfile << "# surfnr    bcnr   domin  domout      np      p1      p2      p3"
+            << "\n";
+
+
+    switch (geomtype)
+      {
+      case GEOM_STL:
+        outfile << "surfaceelementsgi" << "\n";
+        break;
+      case GEOM_OCC: case GEOM_ACIS:
+        outfile << "surfaceelementsuv" << "\n";
+        break;
+      default:
+        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];
+          }
+
+
+        switch (geomtype)
+          {
+          case GEOM_STL:
+            for (j = 1; j <= sel.GetNP(); j++)
+              {
+                outfile.width(7);	  
+                outfile << " " << sel.GeomInfoPi(j).trignum;
+              }
+            break;
+          case GEOM_OCC: case GEOM_ACIS:
+            for (j = 1; j <= sel.GetNP(); j++)
+              {
+                outfile.width(7);	  
+                outfile << " " << sel.GeomInfoPi(j).u;
+                outfile << " " << sel.GeomInfoPi(j).v;
+              }
+            break;
+          default:
+            ; // outfile << "\n";
+          }
+
+
+        outfile << "\n";
+      }
+
+    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++)
+          for (int k = 0; k < el.GetNP()-1; k++)
+          if (el[k] > el[k+1]) swap (el[k], el[k+1]);
+        */
+
+        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 << "# surfid  0   p1   p2   trignum1    trignum2   domin/surfnr1    domout/surfnr2   ednr1   dist1   ednr2   dist2 \n";
+    outfile << "edgesegmentsgi2" << "\n";
+    outfile << GetNSeg() << "\n";
+
+    for (i = 1; i <= GetNSeg(); i++)
+      {
+        const Segment & seg = LineSegment (i);
+        outfile.width(8);
+        outfile << seg.si; // 2D: bc number, 3D: wievielte Kante
+        outfile.width(8);
+        outfile << 0;
+        outfile.width(8);
+        outfile << seg[0];
+        outfile.width(8);
+        outfile << seg[1];
+        outfile << " ";
+        outfile.width(8);
+        outfile << seg.geominfo[0].trignum;  // stl dreiecke
+        outfile << " ";
+        outfile.width(8);
+        outfile << seg.geominfo[1].trignum; // << endl;  // stl dreieck
+
+        if (dimension == 3)
+          {
+            outfile << " ";
+            outfile.width(8);
+            outfile << seg.surfnr1+1;
+            outfile << " ";
+            outfile.width(8);
+            outfile << seg.surfnr2+1;
+          }
+        else
+          {
+            outfile << " ";
+            outfile.width(8);
+            outfile << seg.domin;
+            outfile << " ";
+            outfile.width(8);
+            outfile << seg.domout;
+          }
+
+        outfile << " ";
+        outfile.width(8);
+        outfile << seg.edgenr;
+        outfile << " ";
+        outfile.width(12);
+        outfile.precision(16);
+        outfile << seg.epgeominfo[0].dist;  // splineparameter (2D)
+        outfile << " ";
+        outfile.width(8);
+        outfile.precision(16);
+        outfile << seg.epgeominfo[1].edgenr;  // geometry dependent
+        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 = PointIndex::BASE; 
+         pi < GetNP()+PointIndex::BASE; pi++)
+      {
+        outfile.width(22);
+        outfile << (*this)[pi](0)/scale << "  ";
+        outfile.width(22);
+        outfile << (*this)[pi](1)/scale << "  ";
+        outfile.width(22);
+        outfile << (*this)[pi](2)/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";
+              }
+          }
+
+        outfile << "identificationtypes\n";
+        outfile << ident -> GetMaxNr() << "\n";
+        for (i = 1; i <= ident -> GetMaxNr(); i++)
+          {
+            int type = ident -> GetType(i);
+            outfile << " " << type;
+          }
+        outfile << "\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;
+      }
+
+
+    int cntbcnames = 0;
+    for ( int ii = 0; ii < bcnames.Size(); ii++ )
+      if ( bcnames[ii] ) cntbcnames++;
+
+    if ( cntbcnames )
+      {
+        outfile << "\n\nbcnames" << endl << bcnames.Size() << endl;
+        for ( i = 0; i < bcnames.Size(); i++ )
+          outfile << i+1 << "\t" << GetBCName(i) << endl;
+        outfile << endl << endl;
+      }
+
+    /*
+      if ( GetDimension() == 2 )
+      {
+      for (i = 1; i <= GetNSeg(); i++)
+      {
+      const Segment & seg = LineSegment (i);
+      if ( ! bcprops.Contains(seg.si) && seg.GetBCName() != "" )
+      {
+      bcprops.Append(seg.si);
+      cntbcnames++;
+      }
+      }
+      }
+      else
+      {
+      for (sei = 0; sei < GetNSE(); sei++)
+      {
+      if ((*this)[sei].GetIndex())
+      {
+      int bcp = GetFaceDescriptor((*this)[sei].GetIndex ()).BCProperty();
+      string name = GetFaceDescriptor((*this)[sei].GetIndex ()).BCName();
+      if ( !bcprops.Contains(bcp) &&
+      name != "" )
+      {
+      bcprops.Append(bcp);
+      cntbcnames++;
+      }
+      }
+      }
+      }
+
+      bcprops.SetSize(0);
+      if ( cntbcnames )
+      {
+      outfile << "\nbcnames" << endl << cntbcnames << endl;
+      if ( GetDimension() == 2 )
+      {
+      for (i = 1; i <= GetNSeg(); i++)
+      {
+      const Segment & seg = LineSegment (i);
+      if ( ! bcprops.Contains(seg.si) && seg.GetBCName() != "" )
+      {
+      bcprops.Append(seg.si);
+      outfile << seg.si << "\t" << seg.GetBCName() << endl;
+      }
+      }
+      }
+      else
+      {
+      for (sei = 0; sei < GetNSE(); sei++)
+      {
+      if ((*this)[sei].GetIndex())
+      {
+      int bcp = GetFaceDescriptor((*this)[sei].GetIndex ()).BCProperty();
+      string name = GetFaceDescriptor((*this)[sei].GetIndex ()).BCName();
+      if ( !bcprops.Contains(bcp) &&
+      name != "" )
+      {
+      bcprops.Append(bcp);
+      outfile << bcp << "\t" << name << endl;
+      }
+      }
+      }
+      }
+      outfile << endl << endl;
+      }
+    */
+
+    int cnt_sing = 0;
+    for (PointIndex pi = PointIndex::BASE; pi < GetNP()+PointIndex::BASE; pi++)
+      if ((*this)[pi].Singularity()>=1.) cnt_sing++;
+
+    if (cnt_sing)
+      {
+        outfile << "singular_points" << endl << cnt_sing << endl;
+        for (PointIndex pi = PointIndex::BASE; pi < GetNP()+PointIndex::BASE; pi++)
+          if ((*this)[pi].Singularity()>=1.) 
+            outfile << int(pi) << "\t" << (*this)[pi].Singularity() << endl;
+      }
+
+    cnt_sing = 0;
+    for (SegmentIndex si = 0; si < GetNSeg(); si++)
+      if ( segments[si].singedge_left ) cnt_sing++;
+    if (cnt_sing)
+      {
+        outfile << "singular_edge_left" << endl << cnt_sing << endl;
+        for (SegmentIndex si = 0; si < GetNSeg(); si++)
+          if ( segments[si].singedge_left )
+            outfile << int(si) << "\t" << segments[si].singedge_left << endl;
+      }
+
+    cnt_sing = 0;
+    for (SegmentIndex si = 0; si < GetNSeg(); si++)
+      if ( segments[si].singedge_right ) cnt_sing++;
+    if (cnt_sing)
+      {
+        outfile << "singular_edge_right" << endl << cnt_sing << endl;
+        for (SegmentIndex si = 0; si < GetNSeg(); si++)
+          if ( segments[si].singedge_right  )
+            outfile << int(si) << "\t" << segments[si].singedge_right << endl;
+      }
+
+
+    cnt_sing = 0;
+    for (SurfaceElementIndex sei = 0; sei < GetNSE(); sei++)
+      if ( GetFaceDescriptor ((*this)[sei].GetIndex()).domin_singular) 
+        cnt_sing++;
+
+    if (cnt_sing)
+      {
+        outfile << "singular_face_inside" << endl << cnt_sing << endl;
+        for (SurfaceElementIndex sei = 0; sei < GetNSE(); sei++)
+          if ( GetFaceDescriptor ((*this)[sei].GetIndex()).domin_singular) 
+            outfile << int(sei)  << "\t" << 
+              GetFaceDescriptor ((*this)[sei].GetIndex()).domin_singular  << endl;
+      }
+
+    cnt_sing = 0;
+    for (SurfaceElementIndex sei = 0; sei < GetNSE(); sei++)
+      if ( GetFaceDescriptor ((*this)[sei].GetIndex()).domout_singular) cnt_sing++;
+    if (cnt_sing)
+      {
+        outfile << "singular_face_outside" << endl << cnt_sing << endl;
+        for (SurfaceElementIndex sei = 0; sei < GetNSE(); sei++)
+          if ( GetFaceDescriptor ((*this)[sei].GetIndex()).domout_singular) 
+            outfile << int(sei) << "\t" 
+                    << GetFaceDescriptor ((*this)[sei].GetIndex()).domout_singular << endl;
+      }
+
+
+    // Philippose - 09/07/2009
+    // Add mesh face colours to Netgen Vol file format
+    // The colours are saved in RGB triplets
+    int cnt_facedesc = GetNFD();
+    if (cnt_facedesc)
+    {
+       outfile << endl << endl << "#   Surfnr     Red     Green     Blue" << endl;
+       outfile << "face_colours" << endl << cnt_facedesc << endl;
+
+       outfile.precision(8);
+       outfile.setf(ios::fixed, ios::floatfield);
+       outfile.setf(ios::showpoint);
+
+       for(i = 1; i <= cnt_facedesc; i++)
+       {
+          outfile.width(8);
+          outfile << GetFaceDescriptor(i).SurfNr()+1 << " ";
+          outfile.width(12);
+          outfile << GetFaceDescriptor(i).SurfColour().X() << " ";
+          outfile.width(12);
+          outfile << GetFaceDescriptor(i).SurfColour().Y() << " ";
+          outfile.width(12);
+          outfile << GetFaceDescriptor(i).SurfColour().Z();
+          outfile << endl;
+       }
+    }
+
+  }
+
+
+
+  void Mesh :: Load (const string & filename)
+  {
+
+    ifstream infile(filename.c_str());
+    if (!infile.good())
+      throw NgException ("mesh file not found");
+
+    Load(infile);
+  }
+
+
+
+
+  void Mesh :: Load (istream & infile)
+  {
+
+    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");
+
+
+    facedecoding.SetSize(0);
+
+    bool endmesh = false;
+
+    while (infile.good() && !endmesh)
+      {
+        infile >> str;
+
+        if (strcmp (str, "dimension") == 0)
+          {
+            infile >> dimension;
+          }
+
+        if (strcmp (str, "geomtype") == 0)
+          {
+            int hi;
+            infile >> hi;
+            geomtype = GEOM_TYPE(hi);
+          }
+
+
+        if (strcmp (str, "surfaceelements") == 0 || strcmp (str, "surfaceelementsgi")==0 || strcmp (str, "surfaceelementsuv") == 0)
+          {
+            infile >> n;
+            PrintMessage (3, n, " surface elements");
+            for (i = 1; i <= n; i++)
+              {
+                int surfnr, bcp, domin, domout, nep, faceind = 0;
+
+                infile >> surfnr >> bcp >> domin >> domout;
+                surfnr--;
+
+		bool invert_el = false;
+		/*
+		if (domin == 0) 
+		  {
+		    invert_el = true;
+		    Swap (domin, domout);
+		  }
+		*/
+
+                for (int 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 (int j = 1; j <= nep; j++)
+                  infile >> tri.PNum(j);
+
+                if (strcmp (str, "surfaceelementsgi") == 0)
+                  for (int j = 1; j <= nep; j++)
+                    infile >> tri.GeomInfoPi(j).trignum;
+
+                if (strcmp (str, "surfaceelementsuv") == 0)
+                  for (int j = 1; j <= nep; j++)
+                    infile >> tri.GeomInfoPi(j).u >> tri.GeomInfoPi(j).v;
+
+                if (invertsurf)
+                  tri.Invert();
+		if (invert_el)
+		  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[0] >> seg[1];
+                AddSegment (seg);
+              }
+          }
+
+
+
+        if (strcmp (str, "edgesegmentsgi") == 0)
+          {
+            infile >> n;
+            for (i = 1; i <= n; i++)
+              {
+                Segment seg;
+                int hi;
+                infile >> seg.si >> hi >> seg[0] >> seg[1]
+                       >> seg.geominfo[0].trignum
+                       >> seg.geominfo[1].trignum;
+                AddSegment (seg);
+              }
+          }
+
+        if (strcmp (str, "edgesegmentsgi2") == 0)
+          {
+            int a; 
+            infile >> a;
+            n=a; 
+
+            PrintMessage (3, n, " curve elements");
+
+            for (i = 1; i <= n; i++)
+              {
+                Segment seg;
+                int hi;
+                infile >> seg.si >> hi >> seg[0] >> seg[1]
+                       >> seg.geominfo[0].trignum
+                       >> seg.geominfo[1].trignum
+                       >> seg.surfnr1 >> seg.surfnr2
+                       >> seg.edgenr
+                       >> seg.epgeominfo[0].dist
+                       >> seg.epgeominfo[1].edgenr
+                       >> seg.epgeominfo[1].dist;
+
+                seg.epgeominfo[0].edgenr = seg.epgeominfo[1].edgenr;
+
+                seg.domin = seg.surfnr1;
+                seg.domout = seg.surfnr2;
+
+                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, "identificationtypes") == 0)
+          {
+            infile >> n;
+            for (i = 1; i <= n; i++)
+              {
+                int type;
+                infile >> type;
+                ident -> SetType(i,Identifications::ID_TYPE(type));
+              }
+          }
+
+        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());
+              }
+          }
+
+        if ( strcmp (str, "bcnames" ) == 0 )
+          {
+            infile >> n;
+            Array<int,0> bcnrs(n);
+            SetNBCNames(n);
+            for ( i = 1; i <= n; i++ )
+              {
+                string nextbcname;
+                infile >> bcnrs[i-1] >> nextbcname;
+                bcnames[bcnrs[i-1]-1] = new string(nextbcname);
+              }
+
+            if ( GetDimension() == 2 )
+              {
+                for (i = 1; i <= GetNSeg(); i++)
+                  {
+                    Segment & seg = LineSegment (i);
+                    if ( seg.si <= n )
+                      seg.SetBCName (bcnames[seg.si-1]);
+                    else
+                      seg.SetBCName(0);
+                  }
+              }
+            else
+              {
+                for (SurfaceElementIndex sei = 0; sei < GetNSE(); sei++)
+                  {
+                    if ((*this)[sei].GetIndex())
+                      {
+                        int bcp = GetFaceDescriptor((*this)[sei].GetIndex ()).BCProperty();
+                        if ( bcp <= n )
+                          GetFaceDescriptor((*this)[sei].GetIndex ()).SetBCName(bcnames[bcp-1]);
+                        else
+                          GetFaceDescriptor((*this)[sei].GetIndex ()).SetBCName(0);
+
+                      }
+                  }
+
+              }
+
+
+          }
+
+        if (strcmp (str, "singular_points") == 0)
+          {
+            infile >> n;
+            for (i = 1; i <= n; i++)
+              {
+                PointIndex pi;
+                double s; 
+                infile >> pi;
+                infile >> s; 
+                (*this)[pi].Singularity (s);
+              }
+          }
+
+        if (strcmp (str, "singular_edge_left") == 0)
+          {
+            infile >> n;
+            for (i = 1; i <= n; i++)
+              {
+                SegmentIndex si;
+                double s; 
+                infile >> si;
+                infile >> s; 
+                (*this)[si].singedge_left = s;
+              }
+          }
+        if (strcmp (str, "singular_edge_right") == 0)
+          {
+            infile >> n;
+            for (i = 1; i <= n; i++)
+              {
+                SegmentIndex si;
+                double s; 
+                infile >> si;
+                infile >> s; 
+                (*this)[si].singedge_right = s;
+              }
+          }
+
+        if (strcmp (str, "singular_face_inside") == 0)
+          {
+            infile >> n;
+            for (i = 1; i <= n; i++)
+              {
+                SurfaceElementIndex sei;
+                double s; 
+                infile >> sei;
+                infile >> s; 
+                GetFaceDescriptor((*this)[sei].GetIndex()).domin_singular = s;
+              }
+          }
+
+        if (strcmp (str, "singular_face_outside") == 0)
+          {
+            infile >> n;
+            for (i = 1; i <= n; i++)
+              {
+                SurfaceElementIndex sei;
+                double s; 
+                infile >> sei;
+                infile >> s; 
+                GetFaceDescriptor((*this)[sei].GetIndex()).domout_singular = s;
+              }
+          }
+
+        // Philippose - 09/07/2009
+        // Add mesh face colours to Netgen Vol file format
+        // The colours are read in as RGB triplets
+        if (strcmp (str, "face_colours") == 0)
+        {
+           int cnt_facedesc = GetNFD();
+           infile >> n;
+           if(n == cnt_facedesc)
+           {
+              for(i = 1; i <= n; i++)
+              {
+                 int surfnr = 0;
+                 Vec3d surfcolour(0.0,1.0,0.0);
+
+                 infile >> surfnr 
+                        >> surfcolour.X() 
+                        >> surfcolour.Y() 
+                        >> surfcolour.Z();
+
+                 surfnr--;
+
+                 if(surfnr > 0) 
+                 {
+                    for(int facedesc = 1; facedesc <= cnt_facedesc; facedesc++)
+                    {
+                       if(surfnr == GetFaceDescriptor(facedesc).SurfNr())
+                       {
+                          GetFaceDescriptor(facedesc).SetSurfColour(surfcolour);
+                       }
+                    }
+                 }
+              }
+           }
+        }
+
+        if (strcmp (str, "endmesh") == 0)
+          endmesh = true;
+
+
+
+        strcpy (str, "");
+      }
+
+    CalcSurfacesOfNode ();
+    //  BuildConnectedNodes ();
+    topology -> Update();
+    clusters -> Update();
+
+    SetNextMajorTimeStamp();
+    //  PrintMemInfo (cout);
+
+
+#ifdef PARALLEL
+    if ( ntasks > 1 )
+      {
+        // for parallel processing
+        Distribute ();
+        return;
+      }
+#endif
+
+  }
+
+
+
+
+
+  void Mesh :: Merge (const string & filename, const int surfindex_offset)
+  {
+    ifstream infile(filename.c_str());
+    if (!infile.good())
+      throw NgException ("mesh file not found");
+
+    Merge(infile,surfindex_offset);
+
+  }
+
+
+
+  void Mesh :: Merge (istream & infile, const int surfindex_offset)
+  {
+    char str[100];
+    int i, n;
+
+
+    int inverttets = 0;  // globflags.GetDefineFlag ("inverttets");
+
+    int oldnp = GetNP();
+    int oldne = GetNSeg();
+    int oldnd = GetNDomains();
+
+    for(SurfaceElementIndex si = 0; si < GetNSE(); si++)
+      for(int j=1; j<=(*this)[si].GetNP(); j++) (*this)[si].GeomInfoPi(j).trignum = -1;
+
+    int max_surfnr = 0;
+    for (i = 1; i <= GetNFD(); i++)
+      max_surfnr = max2 (max_surfnr, GetFaceDescriptor(i).SurfNr());
+    max_surfnr++;
+
+    if(max_surfnr < surfindex_offset) max_surfnr = surfindex_offset;
+
+
+    bool endmesh = false;
+
+    while (infile.good() && !endmesh)
+      {
+        infile >> str;
+
+        if (strcmp (str, "surfaceelementsgi") == 0 || 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--;
+
+                if(domin > 0) domin += oldnd;
+                if(domout > 0) domout += oldnd;
+                surfnr += max_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));
+                    if(GetDimension() == 2) bcp++;
+                    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);
+                    tri.PNum(j) = tri.PNum(j) + oldnp;
+                  }
+
+
+                if (strcmp (str, "surfaceelementsgi") == 0)
+                  for (j = 1; j <= nep; j++)
+                    {
+                      infile >> tri.GeomInfoPi(j).trignum;
+                      tri.GeomInfoPi(j).trignum = -1;
+                    }
+
+                AddSurfaceElement (tri);
+              }
+          }
+
+
+        if (strcmp (str, "edgesegments") == 0)
+          {
+            infile >> n;
+            for (i = 1; i <= n; i++)
+              {
+                Segment seg;
+                int hi;
+                infile >> seg.si >> hi >> seg[0] >> seg[1];
+                seg[0] = seg[0] + oldnp;
+                seg[1] = seg[1] + oldnp;
+                AddSegment (seg);
+              }
+          }
+
+
+
+        if (strcmp (str, "edgesegmentsgi") == 0)
+          {
+            infile >> n;
+            for (i = 1; i <= n; i++)
+              {
+                Segment seg;
+                int hi;
+                infile >> seg.si >> hi >> seg[0] >> seg[1]
+                       >> seg.geominfo[0].trignum
+                       >> seg.geominfo[1].trignum;
+                seg[0] = seg[0] + oldnp;
+                seg[1] = seg[1] + oldnp;
+                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[0] >> seg[1]
+                       >> seg.geominfo[0].trignum
+                       >> seg.geominfo[1].trignum
+                       >> seg.surfnr1 >> seg.surfnr2
+                       >> seg.edgenr
+                       >> seg.epgeominfo[0].dist
+                       >> seg.epgeominfo[1].edgenr
+                       >> seg.epgeominfo[1].dist;
+                seg.epgeominfo[0].edgenr = seg.epgeominfo[1].edgenr;
+
+                seg.surfnr1--;
+                seg.surfnr2--;
+
+                if(seg.surfnr1 >= 0)  seg.surfnr1 = seg.surfnr1 + max_surfnr;
+                if(seg.surfnr2 >= 0)  seg.surfnr2 = seg.surfnr2 + max_surfnr;
+                seg[0] = seg[0] +oldnp;
+                seg[1] = seg[1] +oldnp;
+                seg.edgenr = seg.edgenr + oldne;
+                seg.epgeominfo[1].edgenr = seg.epgeominfo[1].edgenr + oldne;
+
+                AddSegment (seg);
+              }
+          }
+
+        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+oldnd);
+                infile >> nep;
+                el.SetNP(nep);
+
+                for (int j = 0; j < nep; j++)
+                  {
+                    infile >> (int&)(el[j]);
+                    el[j] = el[j]+oldnp;
+                  }
+
+                if (inverttets)
+                  el.Invert();
+
+                AddVolumeElement (el);
+              }
+          }
+
+
+        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();
+                AddPoint (p);
+              }
+          }
+
+
+        if (strcmp (str, "endmesh") == 0)
+          {
+            endmesh = true;
+          }
+
+
+        if (strcmp (str, "materials") == 0)
+          {
+            infile >> n;
+            for (i = 1; i <= n; i++)
+              {
+                int nr;
+                string mat;
+                infile >> nr >> mat;
+                SetMaterial (nr+oldnd, mat.c_str());
+              }
+          }
+
+
+        strcpy (str, "");
+      }
+
+    CalcSurfacesOfNode ();
+
+    topology -> Update();
+    clusters -> Update();
+
+    SetNextMajorTimeStamp();
+  }
+
+
+
+
+
+
+
+
+
+
+  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 :: SetAllocSize(int nnodes, int nsegs, int nsel, int nel)
+  {
+    points.SetAllocSize(nnodes);
+    segments.SetAllocSize(nsegs);
+    surfelements.SetAllocSize(nsel);
+    volelements.SetAllocSize(nel);
+  }
+
+
+  void Mesh :: BuildBoundaryEdges(void)
+  {
+    delete boundaryedges;
+
+    boundaryedges = new INDEX_2_CLOSED_HASHTABLE<int>
+      (3 * (GetNSE() + GetNOpenElements()) + GetNSeg() + 1);
+
+
+    for (SurfaceElementIndex sei = 0; sei < GetNSE(); sei++)
+      {
+        const Element2d & sel = surfelements[sei];
+        if (sel.IsDeleted()) continue;
+
+        // int si = sel.GetIndex();
+
+        for (int j = 0; j < sel.GetNP(); j++)
+          {
+            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 (int i = 0; i < openelements.Size(); i++)
+      {
+        const Element2d & sel = openelements[i];
+        for (int 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);
+
+            points[sel[j]].SetType(FIXEDPOINT);
+          }
+      }
+
+    for (int i = 0; i < GetNSeg(); i++)
+      {
+        const Segment & seg = segments[i];
+        INDEX_2 i2(seg[0], seg[1]);
+        i2.Sort();
+
+        boundaryedges -> Set (i2, 2);
+        //segmentht -> Set (i2, i);
+      }
+
+
+  }
+
+  void Mesh :: CalcSurfacesOfNode ()
+  {
+    int i, j, k;
+    SurfaceElementIndex sei;
+
+    surfacesonnode.SetSize (GetNP());
+
+    delete boundaryedges;
+    boundaryedges = NULL;
+
+    delete surfelementht;
+    delete segmentht;
+
+    /*
+      surfelementht = new INDEX_3_HASHTABLE<int> (GetNSE()/4 + 1);
+      segmentht = new INDEX_2_HASHTABLE<int> (GetNSeg() + 1);
+    */
+
+    surfelementht = new INDEX_3_CLOSED_HASHTABLE<int> (3*GetNSE() + 1);
+    segmentht = new INDEX_2_CLOSED_HASHTABLE<int> (3*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);
+
+          }
+      }
+    /*
+      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, sei);   // war das wichtig ???    sel.GetIndex());
+      }
+
+    int np = GetNP();
+
+    if (dimension == 3)
+      {
+        for (PointIndex pi = PointIndex::BASE; 
+             pi < np+PointIndex::BASE; pi++)
+          points[pi].SetType (INNERPOINT);
+
+        if (GetNFD() == 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];
+                    points[pi].SetType(FIXEDPOINT);
+                  }
+              }
+          }
+        else
+          {
+            for (sei = 0; sei < GetNSE(); sei++)
+              {
+                const Element2d & sel = surfelements[sei];
+                if (sel.IsDeleted()) continue;
+                for (j = 0; j < sel.GetNP(); j++)
+                  {
+                    PointIndex pi = sel[j];
+                    int ns = surfacesonnode[pi].Size();
+                    if (ns == 1)
+                      points[pi].SetType(SURFACEPOINT);
+                    if (ns == 2)
+                      points[pi].SetType(EDGEPOINT);
+                    if (ns >= 3)
+                      points[pi].SetType(FIXEDPOINT);
+                  }      
+              }
+          }
+
+        for (i = 0; i < segments.Size(); i++)
+          {
+            const Segment & seg = segments[i];
+            for (j = 1; j <= 2; j++)
+              {
+                PointIndex hi = (j == 1) ? seg[0] : seg[1];
+
+                if (points[hi].Type() == INNERPOINT ||
+                    points[hi].Type() == SURFACEPOINT)
+                  points[hi].SetType(EDGEPOINT);
+              }
+          }
+
+
+        for (i = 0; i < lockedpoints.Size(); i++)
+          points[lockedpoints[i]].SetType(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);
+
+      points[sel[j]].SetType(FIXEDPOINT);
+      }
+      }
+    */
+
+    // eltyps.SetSize (GetNE());
+    // eltyps = FREEELEMENT;
+
+    for (i = 0; i < GetNSeg(); i++)
+      {
+        const Segment & seg = segments[i];
+        INDEX_2 i2(seg[0], seg[1]);
+        i2.Sort();
+
+        //boundaryedges -> Set (i2, 2);
+        segmentht -> Set (i2, i);
+      }
+  }
+
+
+  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))
+        {
+          points.Elem(i).SetType (FIXEDPOINT);
+        }
+  }
+
+
+  void Mesh :: FindOpenElements (int dom)
+  {
+    static int timer = NgProfiler::CreateTimer ("Mesh::FindOpenElements");
+    NgProfiler::RegionTimer reg (timer);
+
+    int np = GetNP();
+    int ne = GetNE();
+    int nse = GetNSE();
+
+    Array<int,PointIndex::BASE> numonpoint(np);
+
+    numonpoint = 0;
+
+    for (ElementIndex ei = 0; ei < ne; ei++)
+      {
+        const Element & el = (*this)[ei];
+        if (dom == 0 || dom == el.GetIndex())
+          {
+            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 (int j = 0; j < el.GetNP(); j++)
+                numonpoint[el[j]]++;
+          }
+      }
+
+    TABLE<ElementIndex,PointIndex::BASE> elsonpoint(numonpoint);
+    for (ElementIndex ei = 0; ei < ne; ei++)
+      {
+        const Element & el = (*this)[ei];
+        if (dom == 0 || dom == el.GetIndex())
+          {
+            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 (int j = 0; j < el.GetNP(); j++)
+                elsonpoint.Add (el[j], ei);
+          }
+      }
+
+
+    Array<char, 1> hasface(GetNFD());
+
+    int i;
+    for (i = 1; i <= GetNFD(); i++)
+      {
+        int domin = GetFaceDescriptor(i).DomainIn();
+        int domout = GetFaceDescriptor(i).DomainOut();
+        hasface[i] = 
+          ( dom == 0 && (domin != 0 || domout != 0) ) ||
+          ( dom != 0 && (domin == dom || domout == dom) );
+      }
+
+    numonpoint = 0;
+    for (SurfaceElementIndex sii = 0; sii < nse; sii++)
+      {
+        int ind = surfelements[sii].GetIndex();
+        /*
+          if (
+          GetFaceDescriptor(ind).DomainIn() && 
+          (dom == 0 || dom == GetFaceDescriptor(ind).DomainIn())
+          ||
+          GetFaceDescriptor(ind).DomainOut() && 
+          (dom == 0 || dom == GetFaceDescriptor(ind).DomainOut())
+          )
+        */
+        if (hasface[ind])
+          {
+            /*
+              Element2d hel = surfelements[i];
+              hel.NormalizeNumbering();	  
+              numonpoint[hel[0]]++;
+            */
+            const Element2d & hel = surfelements[sii];
+            int mini = 0;
+            for (int j = 1; j < hel.GetNP(); j++)
+              if (hel[j] < hel[mini])
+                mini = j;
+            numonpoint[hel[mini]]++;
+          }
+      }
+
+    TABLE<SurfaceElementIndex,PointIndex::BASE> selsonpoint(numonpoint);
+    for (SurfaceElementIndex sii = 0; sii < nse; sii++)
+      {
+        int ind = surfelements[sii].GetIndex();
+
+        /*
+          if (
+          GetFaceDescriptor(ind).DomainIn() && 
+          (dom == 0 || dom == GetFaceDescriptor(ind).DomainIn())
+          ||
+          GetFaceDescriptor(ind).DomainOut() && 
+          (dom == 0 || dom == GetFaceDescriptor(ind).DomainOut())
+          )
+        */
+        if (hasface[ind])
+          {
+            /*
+              Element2d hel = surfelements[i];
+              hel.NormalizeNumbering();	  
+              selsonpoint.Add (hel[0], i);
+            */
+            const Element2d & hel = surfelements[sii];
+            int mini = 0;
+            for (int j = 1; j < hel.GetNP(); j++)
+              if (hel[j] < hel[mini])
+                mini = j;
+            selsonpoint.Add (hel[mini], sii);
+          }
+      }
+
+
+    int ii;
+    PointIndex pi;
+    SurfaceElementIndex sei;
+    Element2d hel;
+
+
+    INDEX_3_CLOSED_HASHTABLE<INDEX_2> faceht(100);   
+    openelements.SetSize(0);
+
+    for (PointIndex pi = PointIndex::BASE; pi < np+PointIndex::BASE; pi++)
+      if (selsonpoint[pi].Size()+elsonpoint[pi].Size())
+        {
+          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 (int 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 (int i = 0; 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 (int 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);
+                  }
+              }
+        }
+
+    int cnt3 = 0;
+    for (i = 0; i < openelements.Size(); i++)
+      if (openelements[i].GetNP() == 3)
+        cnt3++;
+
+    int cnt4 = openelements.Size() - cnt3;
+
+
+    MyStr treequad;
+    if (cnt4)
+      treequad = MyStr(" (") + MyStr(cnt3) + MyStr (" + ") + 
+        MyStr(cnt4) + MyStr(")");
+
+    PrintMessage (5, openelements.Size(), treequad, " open elements");
+
+    BuildBoundaryEdges();
+
+
+    for (int i = 1; i <= openelements.Size(); i++)
+      {
+        const Element2d & sel = openelements.Get(i);
+
+        if (boundaryedges)
+          for (int 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 (int j = 1; j <= 3; j++)
+          {
+            int pi = sel.PNum(j);
+            if (pi < points.Size()+PointIndex::BASE)
+              points[pi].SetType (FIXEDPOINT);
+          }
+      }
+
+
+
+    /*
+      for (i = 1; i <= GetNSeg(); i++)
+      {
+      const Segment & seg = LineSegment(i);
+      INDEX_2 i2(seg[0], seg[1]);
+      i2.Sort();
+
+      if (!boundaryedges->Used (i2))
+      cerr << "WARNING: no boundedge, but seg edge: " << i2 << endl;
+
+      boundaryedges -> Set (i2, 2);
+      segmentht -> Set (i2, i-1);
+      }
+    */
+  }
+
+  bool Mesh :: HasOpenQuads () const
+  {
+    int no = GetNOpenElements();
+    for (int i = 0; i < no; i++)
+      if (openelements[i].GetNP() == 4)
+        return true;
+    return false;
+  }
+
+
+
+
+
+  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[0], seg[1]);
+            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[1], seg[0]);
+            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 (el.IsDeleted()) continue;
+
+        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 (seg.I1() <= 0 || seg.I2() <= 0)
+                  cerr << "seg = " << seg << endl;
+
+                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[0] = i2.I1();
+              seg[1] = 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[0] == el.PNum(k))
+                        seg.geominfo[0] = el.GeomInfoPi(k);
+                      if (seg[1] == 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[0] << " - " << seg[1] 
+                         << " len = " << Dist (Point(seg[0]), Point(seg[1]))
+                         << 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[0]) = EDGEPOINT;
+      ptyps.Elem(seg[1]) = EDGEPOINT;
+      }
+      for (i = 1; i <= GetNOpenSegments(); i++)
+      {
+      const Segment & seg = GetOpenSegment (i);
+      ptyps.Elem(seg[0]) = EDGEPOINT;
+      ptyps.Elem(seg[1]) = EDGEPOINT;
+      }
+    */
+    for (i = 1; i <= points.Size(); i++)
+      points.Elem(i).SetType(SURFACEPOINT);
+
+    for (i = 1; i <= GetNSeg(); i++)
+      {
+        const Segment & seg = LineSegment (i);
+        points[seg[0]].SetType(EDGEPOINT);
+        points[seg[1]].SetType(EDGEPOINT);
+      }
+    for (i = 1; i <= GetNOpenSegments(); i++)
+      {
+        const Segment & seg = GetOpenSegment (i);
+        points[seg[0]].SetType (EDGEPOINT);
+        points[seg[1]].SetType (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[0]);
+        frontpoints.Set (seg[1]);
+      }
+
+    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();
+          }
+      }
+
+    RebuildSurfaceElementLists ();
+    /*
+    for (int i = 0; i < facedecoding.Size(); i++)
+      facedecoding[i].firstelement = -1;
+    for (int i = surfelements.Size()-1; i >= 0; i--)
+      {
+        int ind = surfelements[i].GetIndex();
+        surfelements[i].next = facedecoding[ind-1].firstelement;
+        facedecoding[ind-1].firstelement = i;
+      }
+    */
+
+    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 (int i = 1; i <= GetNOpenElements(); i++)
+      {
+        const Element2d & face = OpenElement(i);
+        for (j = 0; j < face.GetNP(); j++)
+          dist[face[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++)
+      {
+        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]];
+
+        el.flags.fixed = elmin > layers;
+        // 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)
+          points[pi].SetType(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)
+  {
+    if(hloc < hmin)
+      hloc = hmin;
+
+    //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)
+  {
+    if(hloc < hmin)
+      hloc = hmin;
+
+    // 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 :: SetMinimalH (double h)
+  {
+    hmin = h;
+  }
+
+
+  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 (double grading) 
+  {
+    if (!lochfunc)
+      {
+        Point3d pmin, pmax;
+        GetBox (pmin, pmax);
+        // SetLocalH (pmin, pmax, mparam.grading);
+	SetLocalH (pmin, pmax, grading);
+      }
+
+    PrintMessage (3,
+                  "CalcLocalH: ", 
+                  GetNP(), " Points ", 
+                  GetNE(), " Elements ", 
+                  GetNSE(), " Surface Elements");
+
+
+    for (int 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 (int i = 0; i < GetNSeg(); i++)
+      {
+        const Segment & seg = segments[i];
+        const Point3d & p1 = points[seg[0]];
+        const Point3d & p2 = points[seg[1]];
+        /*
+          INDEX_2 i21(seg[0], seg[1]);
+          INDEX_2 i22(seg[1], seg[0]);
+          if (identifiedpoints)
+          if (!identifiedpoints->Used (i21) && !identifiedpoints->Used (i22))
+        */
+        if (!ident -> UsedSymmetric (seg[0], seg[1]))
+          {
+            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 :: CalcLocalHFromPointDistances(double grading)
+  {
+    PrintMessage (3, "Calculating local h from point distances");
+
+    if (!lochfunc)
+      {
+        Point3d pmin, pmax;
+        GetBox (pmin, pmax);
+
+        // SetLocalH (pmin, pmax, mparam.grading);
+	SetLocalH (pmin, pmax, grading);
+      }
+
+    PointIndex i,j;
+    double hl;
+
+
+    for (i = PointIndex::BASE; 
+         i < GetNP()+PointIndex::BASE; i++)
+      {
+        for(j=i+1; j<GetNP()+PointIndex::BASE; j++)
+          {
+            const Point3d & p1 = points[i];
+            const Point3d & p2 = points[j];
+            hl = Dist(p1,p2);
+            RestrictLocalH(p1,hl);
+            RestrictLocalH(p2,hl);
+            //cout << "restricted h at " << p1 << " and " << p2 << " to " << hl << endl;
+          }
+      }
+
+
+  }
+
+
+  void Mesh :: CalcLocalHFromSurfaceCurvature (double grading, double elperr) 
+  {
+    PrintMessage (3, "Calculating local h from surface curvature");
+
+    if (!lochfunc)
+      {
+        Point3d pmin, pmax;
+        GetBox (pmin, pmax);
+
+        // SetLocalH (pmin, pmax, mparam.grading);
+	SetLocalH (pmin, pmax, 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[0], seg[1]);
+        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[0]);
+        const Point3d & p2 = Point(seg[1]);
+        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)[0]);
+    linepoint.Set (LineSegment(i)[1]);
+    }
+
+    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[0]), Point(seg[1]), loch);
+          break;
+        }
+      }
+  }
+
+
+  void Mesh :: LoadLocalMeshSize (const char * meshsizefilename)
+  {
+    // Philippose - 10/03/2009
+    // Improve error checking when loading and reading
+    // the local mesh size file
+
+    if (!meshsizefilename) return;
+
+    ifstream msf(meshsizefilename);
+
+    // Philippose - 09/03/2009
+    // Adding print message information in case the specified 
+    // does not exist, or does not load successfully due to 
+    // other reasons such as access rights, etc...
+    if (!msf) 
+      {
+        PrintMessage(3, "Error loading mesh size file: ", meshsizefilename, "....","Skipping!");
+        return;
+      }
+
+    PrintMessage (3, "Load local mesh-size file: ", meshsizefilename);
+
+    int nmsp = 0;
+    int nmsl = 0;
+
+    msf >> nmsp;
+    if(!msf.good())
+      throw NgException ("Mesh-size file error: No points found\n");
+
+    if(nmsp > 0)
+      PrintMessage (4, "Number of mesh-size restriction points: ", nmsp);
+
+    for (int i = 0; i < nmsp; i++)
+      {
+        Point3d pi;
+        double hi;
+        msf >> pi.X() >> pi.Y() >> pi.Z();
+        msf >> hi;
+        if (!msf.good())
+          throw NgException ("Mesh-size file error: Number of points don't match specified list size\n");
+        RestrictLocalH (pi, hi);
+      }
+
+    msf >> nmsl;
+    if(!msf.good())
+      throw NgException ("Mesh-size file error: No line definitions found\n");
+
+    if(nmsl > 0)
+      PrintMessage (4, "Number of mesh-size restriction lines: ", nmsl);
+
+    for (int i = 0; i < nmsl; i++)
+      {
+        Point3d p1, p2;
+        double hi;
+        msf >> p1.X() >> p1.Y() >> p1.Z();
+        msf >> p2.X() >> p2.Y() >> p2.Z();
+        msf >> hi;
+        if (!msf.good())
+          throw NgException ("Mesh-size file error: Number of line definitions don't match specified list size\n");
+        RestrictLocalHLine (p1, p2, hi);
+      }
+
+    msf.close();
+  }
+
+
+
+  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 (points[pi].Type() <= ptyp)
+        {
+          pmin.SetToMin ( (*this) [pi] );
+          pmax.SetToMax ( (*this) [pi] );
+        }
+  }
+
+
+
+
+  double Mesh :: ElementError (int eli, const MeshingParameters & mp) 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, mp);
+  }
+
+  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<MeshPoint> 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][0] <= PointIndex::BASE-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[0]);
+        pused.Set (seg[1]);
+      }
+
+    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 doesnt 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[0] = op2np[seg[0]];
+        seg[1] = op2np[seg[1]];
+      }
+
+    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]];
+
+    for (int i = 0; i < facedecoding.Size(); i++)
+      facedecoding[i].firstelement = -1;
+    for (int i = surfelements.Size()-1; i >= 0; i--)
+      {
+        int ind = surfelements[i].GetIndex();
+        surfelements[i].next = facedecoding[ind-1].firstelement;
+        facedecoding[ind-1].firstelement = 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);
+    INDEX_2 i2, i2s, edge;
+    int err = 0;
+
+    for (int i = 1; i <= nf; i++)
+      {
+        const Element2d & sel = OpenElement(i);
+
+        for (int 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);
+          }
+      }
+
+    for (int i = 1; i <= edges.GetNBags(); i++)
+      for (int 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");
+
+              (*testout) << "Edge " << i2 << " multiple times in surface mesh" << endl;
+              i2s = i2;
+              i2s.Sort();
+              for (int k = 1; k <= nf; k++)
+                {
+                  const Element2d & sel = OpenElement(k);
+                  for (int l = 1; l <= sel.GetNP(); l++)
+                    {
+                      edge.I1() = sel.PNumMod(l);
+                      edge.I2() = sel.PNumMod(l+1);
+                      edge.Sort();
+
+                      if (edge == i2s) 
+                        (*testout) << "edge of element " << sel << endl;
+                    }
+                }
+
+
+              err = 2;
+            }
+        }
+
+    return err;
+  }
+
+
+
+  int Mesh :: CheckOverlappingBoundary () 
+  {
+    int i, j, k;
+
+    Point3d pmin, pmax;
+    GetBox (pmin, pmax);
+    Box3dTree setree(pmin, pmax);
+    Array<int> inters;
+
+    bool overlap = 0;
+    bool incons_layers = 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));	  
+
+            if ( (*this)[tri[0]].GetLayer() != (*this)[tri2[0]].GetLayer())
+              continue;
+
+            if ( (*this)[tri[0]].GetLayer() != (*this)[tri[1]].GetLayer() ||
+                 (*this)[tri[0]].GetLayer() != (*this)[tri[2]].GetLayer())
+              {
+                incons_layers = 1;
+                cout << "inconsistent layers in triangle" << endl;
+              }
+
+
+            const netgen::Point<3> *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;
+
+                cout << "el1 = " << tri << endl;
+                cout << "el2 = " << tri2 << endl;
+                cout << "layer1 = " <<  (*this)[tri[0]].GetLayer() << endl;
+                cout << "layer2 = " <<  (*this)[tri2[0]].GetLayer() << 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;
+
+                (*testout) << "Face1 = " << GetFaceDescriptor(tri.GetIndex()) << endl;
+                (*testout) << "Face1 = " << GetFaceDescriptor(tri2.GetIndex()) << 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;
+              }
+          }
+      }
+
+    // bug 'fix'
+    if (incons_layers) overlap = 0;
+
+    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
+  {
+    // static int timer1 = NgProfiler::CreateTimer ("Legaltet2");
+
+    // Test, whether 4 points have a common surface plus
+    // at least 4 edges at the boundary
+
+    if(!boundaryedges)
+      const_cast<Mesh *>(this)->BuildBoundaryEdges();
+
+
+    // non-tets are always legal
+    if (el.GetType() != TET)
+      {
+        el.SetLegal (1);
+        return 1;
+      }
+
+    POINTTYPE pointtype[4];
+    for(int i = 0; i < 4; i++)
+      pointtype[i] = (*this)[el[i]].Type();
+
+
+
+    // element has at least 2 inner points ---> legal
+    int cnti = 0;
+    for (int j = 0; j < 4; j++)
+      if ( pointtype[j] == INNERPOINT)
+        {
+          cnti++;
+          if (cnti >= 2)
+            {
+              el.SetLegal (1);
+              return 1;
+            }
+        }
+
+
+
+    // which faces are boundary faces ?
+    int bface[4];
+    for (int i = 0; i < 4; i++)
+      {
+        bface[i] = surfelementht->Used (INDEX_3::Sort(el[gftetfacesa[i][0]],
+                                                      el[gftetfacesa[i][1]],
+                                                      el[gftetfacesa[i][2]]));
+      }
+
+    int bedge[4][4];
+    int segedge[4][4];
+    static const int pi3map[4][4] = { { -1,  2,  1,  1 },
+                                      {  2, -1,  0,  0 },
+                                      {  1,  0, -1,  0 },
+                                      {  1,  0,  0, -1 } };
+
+    static const int pi4map[4][4] = { { -1,  3,  3,  2 },
+                                      {  3, -1,  3,  2 },
+                                      {  3,  3, -1,  1 },
+                                      {  2,  2,  1, -1 } };
+
+
+    for (int i = 0; i < 4; i++)
+      for (int j = 0; j < i; j++)
+        {
+          bool sege = false, be = false;
+
+          int pos = boundaryedges -> Position(INDEX_2::Sort(el[i], el[j]));
+          if (pos)
+            {
+              be = true;
+              if (boundaryedges -> GetData(pos) == 2)
+                sege = true;
+            }
+
+          segedge[j][i] = segedge[i][j] = sege;
+          bedge[j][i] = bedge[i][j] = be;
+        }
+
+    // two boundary faces and no edge is illegal
+    for (int i = 0; i < 3; i++)
+      for (int j = i+1; j < 4; j++)
+        {
+          if (bface[i] && bface[j])
+            if (!segedge[pi3map[i][j]][pi4map[i][j]])
+              {
+                // 2 boundary faces withoud edge in between
+                el.SetLegal (0);
+                return 0;
+              }
+        }
+
+    // three boundary edges meeting in a Surface point
+    for (int i = 0; i < 4; i++)
+      {
+        if ( pointtype[i] == SURFACEPOINT)
+          {
+            bool alledges = 1;
+            for (int j = 0; j < 4; j++)
+              if (j != i && !bedge[i][j])
+                {
+                  alledges = 0;
+                  break;
+                }
+            if (alledges)
+              {
+                // cout << "tet illegal due to unmarked node" << endl;
+                el.SetLegal (0);
+                return 0;
+              }
+          }
+      }
+
+
+
+    for (int fnr = 0; fnr < 4; fnr++)
+      if (!bface[fnr])
+        for (int i = 0; i < 4; i++)
+          if (i != fnr)
+            {
+              int pi1 = pi3map[i][fnr];
+              int pi2 = pi4map[i][fnr];
+
+              if ( pointtype[i] == SURFACEPOINT)
+                {
+                  // two connected edges on surface, but no face
+                  if (bedge[i][pi1] && bedge[i][pi2])
+                    {
+                      el.SetLegal (0);
+                      return 0;
+                    }
+                }
+
+              if ( pointtype[i] == EDGEPOINT)
+                {
+                  // connected surface edge and edge edge, but no face
+                  if ( (bedge[i][pi1] && segedge[i][pi2]) ||
+                       (bedge[i][pi2] && segedge[i][pi1]) )
+                    {
+                      el.SetLegal (0);
+                      return 0;
+                    }
+                }
+
+            }
+
+
+    el.SetLegal (1);
+    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()
+  {
+    PrintMessage (1, "Split To Tets");
+    bool has_prisms = 0;
+
+    int oldne = GetNE(); 
+    for (int i = 1; i <= oldne; i++)
+      {
+        Element el = VolumeElement(i);
+
+        if (el.GetType() == PRISM)
+          {
+            // prism, to 3 tets
+
+            // make minimal node to node 1
+            int minpi=0;
+            PointIndex minpnum;
+            minpnum = GetNP() + 1;
+
+            for (int j = 1; j <= 6; j++)
+              {
+                if (el.PNum(j) < minpnum)
+                  {
+                    minpnum = el.PNum(j);
+                    minpi = j;
+                  }
+              }
+
+            if (minpi >= 4)
+              {
+                for (int j = 1; j <= 3; j++)
+                  swap (el.PNum(j), el.PNum(j+3));
+                minpi -= 3;
+              }
+
+            while (minpi > 1)
+              {
+                int hi = 0;
+                for (int 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,
+            */
+
+            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 (int j = 1; j <= 3; j++)
+              {
+                Element nel(TET);
+                for (int k = 1; k <= 4; k++)
+                  nel.PNum(k) = el.PNum(min2pi[4 * j + k - 5]);
+                nel.SetIndex (el.GetIndex());
+
+                int legal = 1;
+                for (int k = 1; k <= 3; k++)
+                  for (int 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) cout << "no legal";
+            (*testout) << endl;
+          }
+
+
+
+        else if (el.GetType() == HEX)
+          {
+            // hex to A) 2 prisms or B) to 5 tets
+
+            // make minimal node to node 1
+            int minpi=0;
+            PointIndex minpnum;
+            minpnum = GetNP() + 1;
+
+            for (int j = 1; j <= 8; j++)
+              {
+                if (el.PNum(j) < minpnum)
+                  {
+                    minpnum = el.PNum(j);
+                    minpi = j;
+                  }
+              }
+
+            if (minpi >= 5)
+              {
+                for (int j = 1; j <= 4; j++)
+                  swap (el.PNum(j), el.PNum(j+4));
+                minpi -= 4;
+              }
+
+            while (minpi > 1)
+              {
+                int hi = 0;
+                for (int j = 0; j <= 4; j+= 4)
+                  {
+                    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) = el.PNum(4+j);
+                    el.PNum(4+j) = hi;
+                  }
+                minpi--;
+              }
+
+
+
+            static const int to_prisms[3][12] =
+              { { 0, 1, 2, 4, 5, 6, 0, 2, 3, 4, 6, 7 },
+                { 0, 1, 5, 3, 2, 6, 0, 5, 4, 3, 6, 7 },
+                { 0, 7, 4, 1, 6, 5, 0, 3, 7, 1, 2, 6 },
+              };
+
+            const int * min2pi = 0;
+            if (min2 (el[4], el[6]) < min2 (el[5], el[7]))
+              min2pi = &to_prisms[0][0];
+            else if (min2 (el[3], el[6]) < min2 (el[2], el[7]))
+              min2pi = &to_prisms[1][0];
+            else if (min2 (el[1], el[6]) < min2 (el[2], el[5]))
+              min2pi = &to_prisms[2][0];
+
+            if (min2pi)
+              {
+                has_prisms = 1;
+                for (int j = 0; j < 2; j++)
+                  {
+                    Element nel(PRISM);
+                    for (int k = 0; k < 6; k++)
+                      nel[k] = el[min2pi[6*j + k]];
+                    nel.SetIndex (el.GetIndex());
+
+                    if (j == 0)
+                      VolumeElement(i) = nel;
+                    else
+                      AddVolumeElement(nel);
+                  }
+              }
+            else
+              {
+                // split to 5 tets
+
+                static const int to_tets[20] =
+                  {
+                    1, 2, 0, 5,
+                    3, 0, 2, 7,
+                    4, 5, 7, 0,
+                    6, 7, 5, 2,
+                    0, 2, 7, 5
+                  };
+
+                for (int j = 0; j < 5; j++)
+                  {
+                    Element nel(TET);
+                    for (int k = 0; k < 4; k++)
+                      nel[k] = el[to_tets[4*j + k]];
+                    nel.SetIndex (el.GetIndex());
+
+                    if (j == 0)
+                      VolumeElement(i) = nel;
+                    else
+                      AddVolumeElement(nel);
+                  }
+
+              }
+          }
+
+
+
+
+
+        else if (el.GetType() == PYRAMID)
+          {
+            // pyramid, to 2 tets
+
+            // cout << "pyramid: " << el << endl;
+
+            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[0], el[2]) < min2 (el[1], el[3]))
+              min2pi = &ntets[0][0];
+            else
+              min2pi = &ntets[1][0];
+
+            bool firsttet = 1;
+            for (int j = 0; j < 2; j++)
+              {
+                Element nel(TET);
+                for (int k = 0; k < 4; k++)
+                  nel[k] = el[min2pi[4*j + k]-1];
+                nel.SetIndex (el.GetIndex());
+
+                // cout << "pyramid-tet: " << nel << endl;
+
+                bool legal = 1;
+                for (int k = 0; k < 3; k++)
+                  for (int l = k+1; l < 4; l++)
+                    if (nel[k] == nel[l])
+                      legal = 0;
+
+                if (legal)
+                  {
+                    (*testout) << nel << " ";
+                    if (firsttet)
+                      VolumeElement(i) = nel;
+                    else
+                      AddVolumeElement(nel);
+
+                    firsttet = 0;
+                  }
+              }
+            if (firsttet) cout << "no legal";
+            (*testout) << endl;
+          }
+      }
+
+
+    int oldnse = GetNSE(); 
+    for (int 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 (int j = 0; j <6; j++)
+              (*testout) << min2pi[j] << " ";
+
+
+            int firsttri = 1;
+            for (int j = 1; j <= 2; j++)
+              {
+                Element2d nel(3);
+                for (int k = 1; k <= 3; k++)
+                  nel.PNum(k) = el.PNum(min2pi[3 * j + k - 4]);
+                nel.SetIndex (el.GetIndex());
+
+                int legal = 1;
+                for (int k = 1; k <= 2; k++)
+                  for (int 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;
+
+          }
+      }
+
+
+    if (has_prisms)
+
+      Split2Tets();
+
+    else
+      {
+        for (int 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));
+          }
+
+
+
+        UpdateTopology();
+        timestamp = NextTimeStamp();
+      }
+  }
+
+  void Mesh :: BuildElementSearchTree ()
+  {
+    if (elementsearchtreets == GetTimeStamp())
+      return;
+
+    NgLock lock(mutex);
+    lock.Lock();
+
+    PrintMessage (4, "Rebuild element searchtree");
+
+    delete elementsearchtree;
+    elementsearchtree = NULL;
+
+    Box3d box;
+    int ne = (dimension == 2) ? GetNSE() : GetNE();
+    if (!ne) 
+      {
+        lock.UnLock();
+        return;
+      }
+
+    if (dimension == 2)
+      {
+	box.SetPoint (Point (SurfaceElement(1).PNum(1)));
+	for (int i = 1; i <= ne; i++)
+	  {
+	    const Element2d & el = SurfaceElement(i);
+	    for (int 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 (int i = 1; i <= ne; i++)
+	  {
+	    const Element2d & el = SurfaceElement(i);
+	    box.SetPoint (Point (el.PNum(1)));
+	    for (int j = 1; j <= el.GetNP(); j++)
+	      box.AddPoint (Point (el.PNum(j)));
+
+	    elementsearchtree -> Insert (box.PMin(), box.PMax(), i);
+	  }
+      }
+    else
+      {
+	box.SetPoint (Point (VolumeElement(1).PNum(1)));
+	for (int i = 1; i <= ne; i++)
+	  {
+	    const Element & el = VolumeElement(i);
+	    for (int 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 (int i = 1; i <= ne; i++)
+	  {
+	    const Element & el = VolumeElement(i);
+	    box.SetPoint (Point (el.PNum(1)));
+	    for (int j = 1; j <= el.GetNP(); j++)
+	      box.AddPoint (Point (el.PNum(j)));
+
+	    elementsearchtree -> Insert (box.PMin(), box.PMax(), i);
+	  }
+      }
+
+    elementsearchtreets = GetTimeStamp();
+
+    lock.UnLock();
+  }
+
+
+
+  bool Mesh :: PointContainedIn2DElement(const Point3d & p,
+                                         double lami[3],
+                                         const int element,
+                                         bool consider3D) const
+  {
+    Vec3d col1, col2, col3;
+    Vec3d rhs, sol;
+    const double eps = 1e-6;
+
+    Array<Element2d> loctrigs;
+
+
+    //SZ 
+    if(SurfaceElement(element).GetType()==QUAD)
+      {
+        const Element2d & el = SurfaceElement(element); 
+
+        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)); 
+
+        // Coefficients of Bilinear Mapping from Ref-Elem to global Elem
+        // X = a + b x + c y + d x y 
+        Vec3d a = p1; 
+        Vec3d b = p2 - a; 
+        Vec3d c = p4 - a; 
+        Vec3d d = p3 - a - b - c; 
+
+        double dxb = d.X()*b.Y()-d.Y()*b.X();
+        double dxc = d.X()*c.Y()-d.Y()*c.X(); 
+        double dxa = d.X()*a.Y()-d.Y()*a.X(); 
+        double dxp = d.X()*p.Y()-d.Y()*p.X(); 
+
+        double c0,c1,c2; // ,rt; 
+        lami[2]=0.; 
+        double eps = 1.E-12; 
+
+        if(fabs(d.X()) <= eps && fabs(d.Y())<= eps)
+          {
+            //Solve Linear System
+            lami[0]=(c.Y()*(p.X()-a.X())-c.X()*(p.Y()-a.Y()))/
+              (b.X()*c.Y() -b.Y()*c.X()); 
+            lami[1]=(-b.Y()*(p.X()-a.X())+b.X()*(p.Y()-a.Y()))/
+              (b.X()*c.Y() -b.Y()*c.X()); 
+          } 
+        else
+          if(fabs(dxb) <= eps) 
+            {
+              lami[1] = (dxp-dxa)/dxc;
+              if(fabs(b.X()-d.X()*lami[1])>=eps)
+                lami[0] = (p.X()-a.X() - c.X()*lami[1])/(b.X()+d.X()*lami[1]); 
+              else
+                lami[0] = (p.Y()-a.Y() - c.Y()*lami[1])/(b.Y()+d.Y()*lami[1]); 
+            }
+          else
+            if(fabs(dxc) <= eps)
+              {
+                lami[0] = (dxp-dxa)/dxb;
+                if(fabs(c.X()-d.X()*lami[0])>=eps)
+                  lami[1] = (p.X()-a.X() - b.X()*lami[0])/(c.X()+d.X()*lami[0]); 
+                else
+                  lami[1] = (p.Y()-a.Y() - b.Y()*lami[0])/(c.Y()+d.Y()*lami[0]); 
+              }
+            else //Solve quadratic equation
+              {
+                if(fabs(d.X()) >= eps)
+                  {
+                    c2 = d.X()*dxc;
+                    c1 = d.X()*dxc - c.X()*dxb - d.X()*(dxp-dxa);
+                    c0 = -b.X()*(dxp -dxa) - (a.X()-p.X())*dxb;
+                  }
+                else 
+                  {
+                    c2 = d.Y()*dxc;
+                    c1 = d.Y()*dxc - c.Y()*dxb - d.Y()*(dxp-dxa);
+                    c0 = -b.Y()*(dxp -dxa) - (a.Y()-p.Y())*dxb;
+                  }
+
+                double rt =  c1*c1 - 4*c2*c0;
+                if (rt < 0.) return false; 
+                lami[1] = (-c1 + sqrt(rt))/2/c2;
+                if(lami[1]<=1. && lami[1]>=0.)
+                  {
+                    lami[0] = (dxp - dxa -dxc*lami[1])/dxb;
+                    if(lami[0]<=1. && lami[0]>=0.)
+                      return true;
+                  }
+
+                lami[1] = (-c1 - sqrt(rt))/2/c2;
+                lami[0] = (dxp - dxa -dxc*lami[1])/dxb;
+              }
+
+        if( lami[0] <= 1.+eps  && lami[0] >= -eps && lami[1]<=1.+eps && lami[1]>=-eps)
+          {
+            if(consider3D)
+              {
+                Vec3d n = Cross(b,c);
+                lami[2] = 0;
+                for(int i=1; i<=3; i++)
+                  lami[2] +=(p.X(i)-a.X(i)-lami[0]*b.X(i)-lami[1]*c.X(i)) * n.X(i);
+                if(lami[2] >= -eps && lami[2] <= eps)
+                  return true;
+              }
+            else
+              return true;
+          }
+
+        return false;
+
+      }
+    else
+      {
+        //	  SurfaceElement(element).GetTets (loctets);
+        loctrigs.SetSize(1);
+        loctrigs.Elem(1) = SurfaceElement(element);
+
+
+
+        for (int 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 = Cross(col1,col2);
+            //col3 = Vec3d(0, 0, 1);
+            rhs = p - p1;
+
+            // int retval = 
+            SolveLinearSystem (col1, col2, col3, rhs, sol);
+
+            //(*testout) << "retval " << retval << endl;
+
+            //(*testout) << "col1 " << col1 << " col2 " << col2 << " col3 " << col3 << " rhs " << rhs << endl;
+            //(*testout) << "sol " << sol << endl;
+
+            if (sol.X() >= -eps && sol.Y() >= -eps && 
+                sol.X() + sol.Y() <= 1+eps)
+              {
+                if(!consider3D || (sol.Z() >= -eps && sol.Z() <= eps))
+                  {
+                    lami[0] = sol.X();
+                    lami[1] = sol.Y();
+                    lami[2] = sol.Z();
+
+                    return true;
+                  }
+              }
+          }
+      }
+
+    return false;
+
+  }
+
+
+
+
+  bool Mesh :: PointContainedIn3DElement(const Point3d & p,
+                                         double lami[3],
+                                         const int element) const
+  {
+    //bool oldresult = PointContainedIn3DElementOld(p,lami,element);
+    //(*testout) << "old result: " << oldresult
+    //       << " lam " << lami[0] << " " << lami[1] << " " << lami[2] << endl;
+
+    //if(!curvedelems->IsElementCurved(element-1))
+    //  return PointContainedIn3DElementOld(p,lami,element);
+
+
+    const double eps = 1.e-4;
+    const Element & el = VolumeElement(element);
+
+    netgen::Point<3> lam = 0.0;
+
+    if (el.GetType() == TET)
+      {
+        lam = 0.25;
+      }
+    else if (el.GetType() == PRISM)
+      {
+        lam(0) = 0.33; lam(1) = 0.33; lam(2) = 0.5;
+      }
+    else if (el.GetType() == PYRAMID)
+      {
+        lam(0) = 0.4; lam(1) = 0.4; lam(2) = 0.2;
+      }
+    else if (el.GetType() == HEX)
+      {
+        lam = 0.5;
+      }
+
+
+    Vec<3> deltalam,rhs;
+    netgen::Point<3> x;
+    Mat<3,3> Jac,Jact;
+
+    double delta=1;
+
+    bool retval;
+
+    int i = 0;
+
+    const int maxits = 30;
+
+    while(delta > 1e-16 && i<maxits)
+      {
+        curvedelems->CalcElementTransformation(lam,element-1,x,Jac);
+
+        rhs = p-x;
+        Jac.Solve(rhs,deltalam);
+
+        lam += deltalam;
+
+        delta = deltalam.Length2();
+
+        i++;
+        //(*testout) << "pcie i " << i << " delta " << delta << " p " << p << " x " << x << " lam " << lam << endl;
+        //<< "Jac " << Jac << endl;
+      }
+
+    if(i==maxits)
+      return false;
+
+
+    for(i=0; i<3; i++)
+      lami[i] = lam(i);
+
+
+
+    if (el.GetType() == TET)
+      {
+        retval = (lam(0) > -eps && 
+                  lam(1) > -eps && 
+                  lam(2) > -eps && 
+                  lam(0) + lam(1) + lam(2) < 1+eps);
+      }
+    else if (el.GetType() == PRISM)
+      {
+        retval = (lam(0) > -eps &&
+                  lam(1) > -eps &&
+                  lam(2) > -eps &&
+                  lam(2) < 1+eps &&
+                  lam(0) + lam(1) < 1+eps);
+      }
+    else if (el.GetType() == PYRAMID)
+      {
+        retval = (lam(0) > -eps &&
+                  lam(1) > -eps &&
+                  lam(2) > -eps &&
+                  lam(0) + lam(2) < 1+eps &&
+                  lam(1) + lam(2) < 1+eps);
+      }
+    else if (el.GetType() == HEX)
+      {
+        retval = (lam(0) > -eps && lam(0) < 1+eps &&
+                  lam(1) > -eps && lam(1) < 1+eps &&
+                  lam(2) > -eps && lam(2) < 1+eps);
+      }
+    else
+      throw NgException("Da haun i wos vagessn");
+
+    return retval;
+  }
+
+
+
+  bool Mesh :: PointContainedIn3DElementOld(const Point3d & p,
+                                            double lami[3],
+                                            const int element) const
+  {
+    Vec3d col1, col2, col3;
+    Vec3d rhs, sol;
+    const double eps = 1.e-4;
+
+    Array<Element> loctets;
+
+    VolumeElement(element).GetTets (loctets);
+
+    for (int 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<netgen::Point<3> > pointsloc;
+
+            VolumeElement(element).GetTetsLocal (loctetsloc);
+            VolumeElement(element).GetNodesLocalNew (pointsloc);
+
+            const Element & le = loctetsloc.Get(j);
+
+
+            Point3d pp = 
+              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] = pp.X();
+            lami[1] = pp.Y();
+            lami[2] = pp.Z();
+            return true;
+          }
+      }
+    return false;
+  }
+
+
+  int Mesh :: GetElementOfPoint (const Point3d & p,
+                                 double lami[3],
+                                 bool build_searchtree,
+                                 const int index,
+                                 const bool allowindex) const
+  {
+    if(index != -1) 
+      {
+        Array<int> dummy(1);
+        dummy[0] = index;
+        return GetElementOfPoint(p,lami,&dummy,build_searchtree,allowindex);
+      }
+    else
+      return GetElementOfPoint(p,lami,NULL,build_searchtree,allowindex);
+  }
+
+
+
+
+  int Mesh :: GetElementOfPoint (const Point3d & p,
+                                 double lami[3],
+                                 const Array<int> * const indices,
+                                 bool build_searchtree,
+                                 const bool allowindex) const
+  {
+    if (dimension == 2)
+      {
+        int ne;
+
+
+        if(ps_startelement != 0 && ps_startelement <= GetNSE() && PointContainedIn2DElement(p,lami,ps_startelement))
+          return ps_startelement;
+
+        Array<int> locels;
+        if (elementsearchtree || build_searchtree)
+          {
+            // update if necessary:
+            const_cast<Mesh&>(*this).BuildElementSearchTree (); 
+            elementsearchtree->GetIntersecting (p, p, locels);
+            ne = locels.Size();
+          }
+        else
+          ne = GetNSE();
+
+        for (int i = 1; i <= ne; i++)
+          {
+            int ii;
+
+            if (elementsearchtree)
+              ii = locels.Get(i);
+            else
+              ii = i;
+
+            if(ii == ps_startelement) continue;
+
+            if(indices != NULL && indices->Size() > 0)
+              {
+                bool contained = indices->Contains(SurfaceElement(ii).GetIndex());
+                if((allowindex && !contained) || (!allowindex && contained)) continue;
+              }
+
+            if(PointContainedIn2DElement(p,lami,ii)) return ii;
+
+          }
+        return 0;
+      }
+    else
+
+      {
+        // int i, j;
+        int ne;
+
+        if(ps_startelement != 0 && PointContainedIn3DElement(p,lami,ps_startelement))
+          return ps_startelement;
+
+        Array<int> locels;
+        if (elementsearchtree || build_searchtree)
+          {
+            // update if necessary:
+            const_cast<Mesh&>(*this).BuildElementSearchTree (); 
+            elementsearchtree->GetIntersecting (p, p, locels);
+            ne = locels.Size();
+          }
+        else
+          ne = GetNE();
+
+        for (int i = 1; i <= ne; i++)
+          {
+            int ii;
+
+            if (elementsearchtree)
+              ii = locels.Get(i);
+            else
+              ii = i;
+
+            if(ii == ps_startelement) continue;
+
+            if(indices != NULL && indices->Size() > 0)
+              {
+                bool contained = indices->Contains(VolumeElement(ii).GetIndex());
+                if((allowindex && !contained) || (!allowindex && contained)) continue;
+              }
+
+            if(PointContainedIn3DElement(p,lami,ii)) 
+              {
+                ps_startelement = ii;
+                return ii;
+              }
+          }
+
+        // Not found, try uncurved variant:
+        for (int i = 1; i <= ne; i++)
+          {
+            int ii;
+
+            if (elementsearchtree)
+              ii = locels.Get(i);
+            else
+              ii = i;
+
+            if(indices != NULL && indices->Size() > 0)
+              {
+                bool contained = indices->Contains(VolumeElement(ii).GetIndex());
+                if((allowindex && !contained) || (!allowindex && contained)) continue;
+              }
+
+
+            if(PointContainedIn3DElementOld(p,lami,ii)) 
+              {
+                ps_startelement = ii;
+                (*testout) << "WARNING: found element of point " << p <<" only for uncurved mesh" << endl;
+                return ii;
+              }
+          }
+
+
+        return 0;
+      }
+  }
+
+
+
+  int Mesh :: GetSurfaceElementOfPoint (const Point3d & p,
+                                        double lami[3],
+                                        bool build_searchtree,
+                                        const int index,
+                                        const bool allowindex) const
+  {
+    if(index != -1) 
+      {
+        Array<int> dummy(1);
+        dummy[0] = index;
+        return GetSurfaceElementOfPoint(p,lami,&dummy,build_searchtree,allowindex);
+      }
+    else
+      return GetSurfaceElementOfPoint(p,lami,NULL,build_searchtree,allowindex);
+  }
+
+
+
+
+  int Mesh :: GetSurfaceElementOfPoint (const Point3d & p,
+                                        double lami[3],
+                                        const Array<int> * const indices,
+                                        bool build_searchtree,
+                                        const bool allowindex) const
+  {
+    if (dimension == 2)
+      {
+        throw NgException("GetSurfaceElementOfPoint not yet implemented for 2D meshes");
+      }
+    else
+      {
+        double vlam[3];
+        int velement = GetElementOfPoint(p,vlam,NULL,build_searchtree,allowindex);
+
+        //(*testout) << "p " << p << endl;
+        //(*testout) << "velement " << velement << endl;
+
+        Array<int> faces;
+        topology->GetElementFaces(velement,faces);
+
+        //(*testout) << "faces " << faces << endl;
+
+        for(int i=0; i<faces.Size(); i++)
+          faces[i] = topology->GetFace2SurfaceElement(faces[i]);
+
+        //(*testout) << "surfel " << faces << endl;
+
+        for(int i=0; i<faces.Size(); i++)
+          {
+            if(faces[i] == 0)
+              continue;
+
+            if(indices && indices->Size() != 0)
+              {
+                if(indices->Contains(SurfaceElement(faces[i]).GetIndex()) &&
+                   PointContainedIn2DElement(p,lami,faces[i],true))
+                  return faces[i];
+              }
+            else
+              {
+                if(PointContainedIn2DElement(p,lami,faces[i],true))
+                  {
+                    //(*testout) << "found point " << p << " in sel " << faces[i]
+                    //	       << ", lam " << lami[0] << ", " << lami[1] << ", " << lami[2] << endl;
+                    return faces[i];
+                  }
+              }
+          }
+
+      }
+
+    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 ()
+  {
+    PrintMessage (3, "SplitSeparateFaces");
+    int fdi;
+    int np = GetNP();
+
+    BitArray usedp(np);
+    Array<SurfaceElementIndex> els_of_face;
+
+    fdi = 1;
+    while (fdi <= GetNFD())
+      {
+        GetSurfaceElementsOfFace (fdi, els_of_face);
+
+        if (els_of_face.Size() == 0) continue;
+
+        SurfaceElementIndex firstel = els_of_face[0];
+
+        usedp.Clear();
+        for (int j = 1; j <= SurfaceElement(firstel).GetNP(); j++)
+          usedp.Set (SurfaceElement(firstel).PNum(j));
+
+        bool changed;
+        do
+          {
+            changed = false;
+
+            for (int i = 0; i < els_of_face.Size(); i++)
+              {
+                const Element2d & el = SurfaceElement(els_of_face[i]);
+
+                bool has = 0;
+                bool hasno = 0;
+                for (int j = 0; j < el.GetNP(); j++)
+                  {
+                    if (usedp.Test(el[j]))
+                      has = true;
+                    else
+                      hasno = true;
+                  }
+
+                if (has && hasno)
+                  changed = true;
+
+                if (has)
+                  for (int j = 0; j < el.GetNP(); j++)
+                    usedp.Set (el[j]);
+              }
+          }
+        while (changed);
+
+        int nface = 0;
+        for (int i = 0; i < els_of_face.Size(); i++)
+          {
+            Element2d & el = SurfaceElement(els_of_face[i]);
+
+            int hasno = 0;
+            for (int 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);
+              }
+          }
+
+        // reconnect list
+        if (nface)
+          {
+            facedecoding[nface-1].firstelement = -1;
+            facedecoding[fdi-1].firstelement = -1;
+
+            for (int i = 0; i < els_of_face.Size(); i++)
+              {
+                int ind = SurfaceElement(els_of_face[i]).GetIndex();
+                SurfaceElement(els_of_face[i]).next = facedecoding[ind-1].firstelement;
+                facedecoding[ind-1].firstelement = els_of_face[i];
+              }
+          }
+
+        fdi++;
+      }
+
+
+    /*
+      fdi = 1;
+      while (fdi <= GetNFD())
+      {
+      int firstel = 0;
+      for (int i = 1; i <= GetNSE(); i++)
+      if (SurfaceElement(i).GetIndex() == fdi)
+      {
+      firstel = i;
+      break;
+      }
+      if (!firstel) continue;
+
+      usedp.Clear();
+      for (int j = 1; j <= SurfaceElement(firstel).GetNP(); j++)
+      usedp.Set (SurfaceElement(firstel).PNum(j));
+
+      int changed;
+      do
+      {
+      changed = 0;
+      for (int i = 1; i <= GetNSE(); i++)
+      {
+      const Element2d & el = SurfaceElement(i);
+      if (el.GetIndex() != fdi)
+      continue;
+
+      int has = 0;
+      int hasno = 0;
+      for (int 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 (int j = 1; j <= el.GetNP(); j++)
+      usedp.Set (el.PNum(j));
+      }
+      }
+      while (changed);
+
+      int nface = 0;
+      for (int i = 1; i <= GetNSE(); i++)
+      {
+      Element2d & el = SurfaceElement(i);
+      if (el.GetIndex() != fdi)
+      continue;	  
+
+      int hasno = 0;
+      for (int 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 :: RebuildSurfaceElementLists ()
+  {
+    for (int i = 0; i < facedecoding.Size(); i++)
+      facedecoding[i].firstelement = -1;
+    for (int i = surfelements.Size()-1; i >= 0; i--)
+      {
+        int ind = surfelements[i].GetIndex();
+        surfelements[i].next = facedecoding[ind-1].firstelement;
+        facedecoding[ind-1].firstelement = i;
+      }
+  }
+
+  void Mesh :: GetSurfaceElementsOfFace (int facenr, Array<SurfaceElementIndex> & sei) const
+  {
+    static int timer = NgProfiler::CreateTimer ("GetSurfaceElementsOfFace");
+    NgProfiler::RegionTimer reg (timer);
+
+
+     /*
+     sei.SetSize (0);
+     for (SurfaceElementIndex i = 0; i < GetNSE(); i++)
+     {
+        if ( (*this)[i].GetIndex () == facenr && (*this)[i][0] >= PointIndex::BASE &&
+           !(*this)[i].IsDeleted() )
+        {
+           sei.Append (i);
+        }
+     }
+     */
+
+     /* Philippose - 01/10/2009
+     Commented out the following lines, and activated the originally 
+     commented out lines above because of a bug which causes corruption 
+     of the variable "facedecoding" when a mesh is converted to second order
+     */
+
+     //      int size1 = sei.Size();
+     sei.SetSize(0);
+
+     SurfaceElementIndex si = facedecoding[facenr-1].firstelement;
+     while (si != -1)
+     {
+        if ( (*this)[si].GetIndex () == facenr && (*this)[si][0] >= PointIndex::BASE &&
+             !(*this)[si].IsDeleted() )
+        {
+           sei.Append (si);
+        }
+
+        si = (*this)[si].next;
+     }
+     
+     /*
+     // *testout << "with list = " << endl << sei << endl;
+
+     if (size1 != sei.Size()) 
+     {
+        cout << "size mismatch" << endl;
+        exit(1);
+     }
+     */
+  }
+
+
+
+
+  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 :: InitPointCurve(double red, double green, double blue) const
+  {
+    pointcurves_startpoint.Append(pointcurves.Size());
+    pointcurves_red.Append(red);
+    pointcurves_green.Append(green);
+    pointcurves_blue.Append(blue);
+  }
+  void Mesh :: AddPointCurvePoint(const Point3d & pt) const
+  {
+    pointcurves.Append(pt);
+  }
+  int Mesh :: GetNumPointCurves(void) const
+  {
+    return pointcurves_startpoint.Size();
+  }
+  int Mesh :: GetNumPointsOfPointCurve(int curve) const
+  {
+    if(curve == pointcurves_startpoint.Size()-1)
+      return (pointcurves.Size() - pointcurves_startpoint.Last());
+    else
+      return (pointcurves_startpoint[curve+1]-pointcurves_startpoint[curve]);
+  }
+
+  Point3d & Mesh :: GetPointCurvePoint(int curve, int n) const
+  {
+    return pointcurves[pointcurves_startpoint[curve]+n];
+  }
+
+  void Mesh :: GetPointCurveColor(int curve, double & red, double & green, double & blue) const
+  {
+    red = pointcurves_red[curve];
+    green = pointcurves_green[curve];
+    blue = pointcurves_blue[curve];
+  }
+
+
+  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;
+        }
+
+    GetIdentifications().SetMaxPointNr (np + 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;
+    
+    if (!faceindex)
+      {
+	for (int i = 1; i <= GetNSE(); i++)
+	  if (SurfaceElement(i).GetNP() != 3)
+	    return false;
+	return true;
+      }
+
+    for (int i = 1; i <= GetNSE(); i++)
+      if (SurfaceElement(i).GetIndex() == faceindex &&
+          SurfaceElement(i).GetNP() != 3)
+        return false;
+    return true;
+  }
+
+  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 ::SetNBCNames ( int nbcn )
+  {
+    if ( bcnames.Size() )
+      for ( int i = 0; i < bcnames.Size(); i++)
+        if ( bcnames[i] ) delete bcnames[i];
+    bcnames.SetSize(nbcn);
+    bcnames = 0;
+  }
+
+  void Mesh ::SetBCName ( int bcnr, const string & abcname )
+  {
+    if ( bcnames[bcnr] ) delete bcnames[bcnr];
+    if ( abcname != "default" )
+      bcnames[bcnr] = new string ( abcname );
+    else
+      bcnames[bcnr] = 0;
+  }
+
+  string Mesh ::GetBCName ( int bcnr ) const
+  {
+    if ( !bcnames.Size() )
+      return "default";
+    if ( bcnames[bcnr] )
+      return *bcnames[bcnr];
+    else
+      return "default";
+  }
+
+  void Mesh :: SetUserData(const char * id, Array<int> & data)
+  {
+    if(userdata_int.Used(id))
+      delete userdata_int.Get(id);
+
+    Array<int> * newdata = new Array<int>(data);
+
+    userdata_int.Set(id,newdata);      
+  }
+  bool Mesh :: GetUserData(const char * id, Array<int> & data, int shift) const
+  {
+    if(userdata_int.Used(id))
+      {
+        if(data.Size() < (*userdata_int.Get(id)).Size()+shift)
+          data.SetSize((*userdata_int.Get(id)).Size()+shift);
+        for(int i=0; i<(*userdata_int.Get(id)).Size(); i++)
+          data[i+shift] = (*userdata_int.Get(id))[i];
+        return true;
+      }
+    else
+      {
+        data.SetSize(0);
+        return false;
+      }
+  }
+  void Mesh :: SetUserData(const char * id, Array<double> & data)
+  {
+    if(userdata_double.Used(id))
+      delete userdata_double.Get(id);
+
+    Array<double> * newdata = new Array<double>(data);
+
+    userdata_double.Set(id,newdata);      
+  }
+  bool Mesh :: GetUserData(const char * id, Array<double> & data, int shift) const
+  {
+    if(userdata_double.Used(id))
+      {
+        if(data.Size() < (*userdata_double.Get(id)).Size()+shift)
+          data.SetSize((*userdata_double.Get(id)).Size()+shift);
+        for(int i=0; i<(*userdata_double.Get(id)).Size(); i++)
+          data[i+shift] = (*userdata_double.Get(id))[i];
+        return true;
+      }
+    else
+      {
+        data.SetSize(0);
+        return false;
+      }
+  }
+
+
+
+  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/contrib/Netgen/libsrc/meshing/meshclass.hpp b/contrib/Netgen/libsrc/meshing/meshclass.hpp
new file mode 100644
index 0000000000..1f45d1f0ec
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/meshclass.hpp
@@ -0,0 +1,770 @@
+#ifndef MESHCLASS
+#define MESHCLASS
+
+/**************************************************************************/
+/* File:   meshclass.hpp                                                  */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   20. Nov. 99                                                    */
+/**************************************************************************/
+
+/*
+  The mesh class
+*/
+
+namespace netgen
+{
+
+  enum resthtype { RESTRICTH_FACE, RESTRICTH_EDGE, 
+		   RESTRICTH_SURFACEELEMENT, RESTRICTH_POINT, RESTRICTH_SEGMENT };
+
+  class HPRefElement;
+
+
+  /// 2d/3d mesh
+  class Mesh
+  {
+  public:
+    typedef ::netgen::T_POINTS T_POINTS;
+
+    // typedef MoveableArray<MeshPoint,PointIndex::BASE> 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;
+
+    /// 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_CLOSED_HASHTABLE<int> * segmentht;
+    ///
+    INDEX_3_CLOSED_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;
+    ///
+    double hmin;
+    ///
+    Array<double> maxhdomain;
+  
+    /**
+       the face-index of the surface element maps into
+       this table.
+    */
+    Array<FaceDescriptor> facedecoding;
+
+  
+    /**
+       the edge-index of the line element maps into
+       this table.
+    */
+    Array<EdgeDescriptor> edgedecoding;
+
+    /// sub-domain materials 
+    Array<char*> materials;
+
+    /// labels for boundary conditions
+    Array<string*> bcnames;
+
+    /// 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 semaphors.
+    NgMutex mutex;
+    /// mesh access semaphors.
+    NgMutex majormutex;
+
+    SYMBOLTABLE< Array<int>* > userdata_int;
+    SYMBOLTABLE< Array<double>* > userdata_double; 
+
+
+    mutable Array< Point3d > pointcurves;
+    mutable Array<int> pointcurves_startpoint;
+    mutable Array<double> pointcurves_red,pointcurves_green,pointcurves_blue;
+
+
+    /// start element for point search (GetElementOfPoint)
+    mutable int ps_startelement;
+
+
+#ifdef PARALLEL
+    /// connection to parallel meshes
+    class ParallelMeshTopology * paralleltop;
+
+#endif
+
+
+  private:
+    void BuildBoundaryEdges(void);
+
+  public:
+    bool PointContainedIn2DElement(const Point3d & p,
+				   double lami[3],
+				   const int element,
+				   bool consider3D = false) const;
+    bool PointContainedIn3DElement(const Point3d & p,
+				   double lami[3],
+				   const int element) const;
+    bool PointContainedIn3DElementOld(const Point3d & p,
+				      double lami[3],
+				      const int element) const;
+
+  public:
+
+    // store coarse mesh before hp-refinement
+    Array<HPRefElement> * hpelements;
+    Mesh * coarsemesh;
+  
+  
+    /// 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;
+
+
+
+    ///
+    DLL_HEADER Mesh();
+    ///
+    DLL_HEADER ~Mesh();
+
+    Mesh & operator= (const Mesh & mesh2);
+  
+    ///
+    DLL_HEADER void DeleteMesh();
+  
+    ///
+    void ClearSurfaceElements();
+
+    ///
+    void ClearVolumeElements()
+    {
+      volelements.SetSize(0); 
+      timestamp = NextTimeStamp();
+    }
+
+    ///
+    void ClearSegments()
+    { 
+      segments.SetSize(0); 
+      timestamp = NextTimeStamp();
+    }
+  
+    ///
+    bool TestOk () const;
+
+    void SetAllocSize(int nnodes, int nsegs, int nsel, int nel);
+
+
+    DLL_HEADER PointIndex AddPoint (const Point3d & p, int layer = 1);
+    DLL_HEADER PointIndex AddPoint (const Point3d & p, int layer, POINTTYPE type);
+#ifdef PARALLEL
+    PointIndex AddPoint (const Point3d & p, bool aisghost, int layer = 1);
+    PointIndex AddPoint (const Point3d & p, bool aisghost, int layer, POINTTYPE type);
+#endif
+    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]; }
+
+    const T_POINTS & Points() const { return points; }
+    T_POINTS & Points() { return points; }
+
+
+    DLL_HEADER SegmentIndex AddSegment (const Segment & s);
+    void DeleteSegment (int segnr)
+    {
+      segments.Elem(segnr)[0] = PointIndex::BASE-1;
+      segments.Elem(segnr)[1] = PointIndex::BASE-1;
+    }
+    void FullDeleteSegment (int segnr)  // von wem ist das ???
+    {
+      segments.Delete(segnr-PointIndex::BASE);
+    }
+
+    int GetNSeg () const { return segments.Size(); }
+    Segment & LineSegment(int i) { return segments.Elem(i); }
+    const Segment & LineSegment(int i) const { return segments.Get(i); }
+
+    Segment & LineSegment(SegmentIndex si) { return segments[si]; }
+    const Segment & LineSegment(SegmentIndex si) const { return segments[si]; }
+    const Segment & operator[] (SegmentIndex si) const { return segments[si]; }
+    Segment & operator[] (SegmentIndex si) { return segments[si]; }
+
+
+
+
+    DLL_HEADER 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]; }
+
+  
+    DLL_HEADER void RebuildSurfaceElementLists ();
+    DLL_HEADER void GetSurfaceElementsOfFace (int facenr, Array<SurfaceElementIndex> & sei) const;
+
+    DLL_HEADER 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 (ElementIndex i) const 
+    { return (volelements[i].flags.fixed) ? FIXEDELEMENT : FREEELEMENT; }
+
+    const T_VOLELEMENTS & VolumeElements() const { return volelements; }
+    T_VOLELEMENTS & VolumeElements() { return volelements; }
+
+
+    ///
+    DLL_HEADER double ElementError (int eli, const MeshingParameters & mp) const;
+
+    /// 
+    DLL_HEADER 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 */
+    DLL_HEADER void FindOpenElements (int dom = 0);
+
+  
+    /**
+       finds segments without surface element,
+       and surface elements without neighbours.
+       store in opensegmentsy
+    */
+    DLL_HEADER void FindOpenSegments (int surfnr = 0);
+    /**
+       remove one layer of surface elements
+    */
+    DLL_HEADER void RemoveOneLayerSurfaceElements ();
+
+
+    int GetNOpenSegments () { return opensegments.Size(); }
+    const Segment & GetOpenSegment (int nr) { return opensegments.Get(nr); }
+  
+    /**
+       Checks overlap of boundary
+       return == 1, iff overlap
+    */
+    DLL_HEADER int CheckOverlappingBoundary ();
+    /**
+       Checks consistent boundary
+       return == 0, everything ok
+    */
+    DLL_HEADER int CheckConsistentBoundary () const;
+
+    /*
+      checks element orientation
+    */
+    DLL_HEADER int CheckVolumeMesh () const;
+
+
+    /**
+       finds average h of surface surfnr if surfnr > 0,
+       else of all surfaces.
+    */
+    DLL_HEADER double AverageH (int surfnr = 0) const;
+    /// Calculates localh 
+    DLL_HEADER void CalcLocalH (double grading);
+    ///
+    DLL_HEADER void SetLocalH (const Point3d & pmin, const Point3d & pmax, double grading);
+    ///
+    DLL_HEADER void RestrictLocalH (const Point3d & p, double hloc);
+    ///
+    DLL_HEADER void RestrictLocalHLine (const Point3d & p1, const Point3d & p2, 
+			     double hloc);
+    /// number of elements per radius
+    DLL_HEADER void CalcLocalHFromSurfaceCurvature(double grading, double elperr);
+    ///
+    DLL_HEADER void CalcLocalHFromPointDistances(double grading);
+    ///
+    DLL_HEADER void RestrictLocalH (resthtype rht, int nr, double loch);
+    ///
+    DLL_HEADER void LoadLocalMeshSize (const char * meshsizefilename);
+    ///
+    DLL_HEADER void SetGlobalH (double h);
+    ///
+    void SetMinimalH (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; }
+    ///
+    bool LocalHFunctionGenerated(void) const { return (lochfunc != NULL); }
+
+    /// Find bounding box
+    DLL_HEADER void GetBox (Point3d & pmin, Point3d & pmax, int dom = -1) const;
+
+    /// Find bounding box of points of typ ptyp or less
+    DLL_HEADER 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
+    bool 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
+    {
+      if(!boundaryedges)
+	const_cast<Mesh *>(this)->BuildBoundaryEdges();
+
+      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);
+    }
+
+    SegmentIndex SegmentNr (PointIndex pi1, PointIndex pi2) const
+    {
+      INDEX_2 i2 (pi1, pi2);
+      i2.Sort();
+      return segmentht->Get (i2);
+    }
+
+
+    /**
+       Remove unused points. etc.
+    */
+    DLL_HEADER void Compress ();
+
+    ///
+    void Save (ostream & outfile) const;
+    ///
+    void Load (istream & infile);
+    ///
+    void Merge (istream & infile, const int surfindex_offset = 0);
+    ///
+    void Save (const string & filename) const;
+    ///
+    void Load (const string & filename);
+    ///
+    void Merge (const string & filename, const int surfindex_offset = 0);
+
+
+    ///
+    void ImproveMesh (const MeshingParameters & mp, OPTIMIZEGOAL goal = OPT_QUALITY);
+
+    ///
+    void ImproveMeshJacobian (const MeshingParameters & mp, OPTIMIZEGOAL goal = OPT_QUALITY, const BitArray * usepoint = NULL);
+    ///
+    void ImproveMeshJacobianOnSurface (const MeshingParameters & mp,
+				       const BitArray & usepoint, 
+				       const Array< Vec<3>* > & nv,
+				       OPTIMIZEGOAL goal = OPT_QUALITY,
+				       const Array< Array<int,PointIndex::BASE>* > * idmaps = NULL);
+    /**
+       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
+    DLL_HEADER void BuildElementSearchTree ();
+
+    void SetPointSearchStartElement(const int el) const {ps_startelement = el;}
+
+    /// gives element of point, barycentric coordinates
+    int GetElementOfPoint (const Point3d & p,
+			   double * lami,
+			   bool build_searchtree = 0,
+			   const int index = -1,
+			   const bool allowindex = true) const;
+    int GetElementOfPoint (const Point3d & p,
+			   double * lami,
+			   const Array<int> * const indices,
+			   bool build_searchtree = 0,
+			   const bool allowindex = true) const;
+    int GetSurfaceElementOfPoint (const Point3d & p,
+				  double * lami,
+				  bool build_searchtree = 0,
+				  const int index = -1,
+				  const bool allowindex = true) const;
+    int GetSurfaceElementOfPoint (const Point3d & p,
+				  double * lami,
+				  const Array<int> * const indices,
+				  bool build_searchtree = 0,
+				  const bool allowindex = true) 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); }
+
+    int AddEdgeDescriptor(const EdgeDescriptor & fd)
+    { return edgedecoding.Append(fd) - 1; }
+
+    ///
+    DLL_HEADER void SetMaterial (int domnr, const char * mat);
+    ///
+    const char * GetMaterial (int domnr) const;
+    
+    DLL_HEADER void SetNBCNames ( int nbcn );
+
+    DLL_HEADER void SetBCName ( int bcnr, const string & abcname );
+
+    string GetBCName ( int bcnr ) const;
+
+    string * GetBCNamePtr ( int bcnr )
+    { return bcnames[bcnr]; }
+
+    ///
+    void ClearFaceDescriptors()
+    { facedecoding.SetSize(0); }
+
+    ///
+    int GetNFD () const
+    { return facedecoding.Size(); }
+
+    const FaceDescriptor & GetFaceDescriptor (int i) const
+    { return facedecoding.Get(i); }
+
+    const EdgeDescriptor & GetEdgeDescriptor (int i) const
+    { return edgedecoding[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; }
+
+
+    void InitPointCurve(double red = 1, double green = 0, double blue = 0) const;
+    void AddPointCurvePoint(const Point3d & pt) const;
+    int GetNumPointCurves(void) const;
+    int GetNumPointsOfPointCurve(int curve) const;
+    Point3d & GetPointCurvePoint(int curve, int n) const;
+    void GetPointCurveColor(int curve, double & red, double & green, double & blue) const;
+
+
+
+
+    /// 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; }
+    NgMutex & MajorMutex ()   { return majormutex; }
+
+
+    ///
+    void SetUserData(const char * id, Array<int> & data);
+    ///
+    bool GetUserData(const char * id, Array<int> & data, int shift = 0) const;
+    ///
+    void SetUserData(const char * id, Array<double> & data);
+    ///
+    bool GetUserData(const char * id, Array<double> & data, int shift = 0) const;
+
+    ///
+    friend void OptimizeRestart (Mesh & mesh3d);
+    ///
+    void PrintMemInfo (ostream & ost) const;
+    /// 
+    friend class Meshing3;
+
+
+    enum GEOM_TYPE { NO_GEOM = 0, GEOM_2D = 1, GEOM_CSG = 10, GEOM_STL = 11, GEOM_OCC = 12, GEOM_ACIS = 13 };
+    GEOM_TYPE geomtype;
+  
+
+
+#ifdef PARALLEL
+    /// returns parallel topology
+    class ParallelMeshTopology & GetParallelTopology () const
+    { return *paralleltop; }
+
+
+    /// distributes the master-mesh to local meshes
+    void Distribute ();
+
+
+    /// find connection to parallel meshes
+    //   void FindExchangePoints () ;
+
+    //   void FindExchangeEdges ();
+    //   void FindExchangeFaces ();
+
+    /// use metis to decompose master mesh 
+    void ParallelMetis (); //  Array<int> & neloc );
+    void PartHybridMesh (); //  Array<int> & neloc );
+    void PartDualHybridMesh (); //  Array<int> & neloc );
+    void PartDualHybridMesh2D ();  // ( Array<int> & neloc );
+
+
+    /// send mesh from master to local procs
+    void SendRecvMesh ();
+
+    /// send mesh to parallel machine, keep global mesh at master 
+    void SendMesh ( ) const;   // Mesh * mastermesh, Array<int> & neloc) const;
+    /// loads a mesh sent from master processor
+    void ReceiveParallelMesh ();
+
+
+    void UpdateOverlap ();
+ 
+#endif
+
+
+  };
+
+  inline ostream& operator<<(ostream& ost, const Mesh& mesh)
+  {
+    ost << "mesh: " << endl;
+    mesh.Save(ost);
+    return ost;
+  }
+
+}
+
+#endif
+
+
diff --git a/contrib/Netgen/libsrc/meshing/meshfunc.cpp b/contrib/Netgen/libsrc/meshing/meshfunc.cpp
new file mode 100644
index 0000000000..9dbc8a8ca9
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/meshfunc.cpp
@@ -0,0 +1,717 @@
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+namespace netgen
+{
+  extern const char * tetrules[];
+  // 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 oldne;
+     int meshed;
+
+     Array<INDEX_2> connectednodes;
+
+     if (&mesh3d.LocalHFunction() == NULL) mesh3d.CalcLocalH(mp.grading);
+
+     mesh3d.Compress();
+
+     //  mesh3d.PrintMemInfo (cout);
+
+     if (mp.checkoverlappingboundary)
+        if (mesh3d.CheckOverlappingBoundary())
+           throw NgException ("Stop meshing since boundary mesh is overlapping");
+
+     int nonconsist = 0;
+     for (int k = 1; k <= mesh3d.GetNDomains(); k++)
+     {
+        PrintMessage (3, "Check subdomain ", k, " / ", mesh3d.GetNDomains());
+
+        mesh3d.FindOpenElements(k);
+
+        /*
+        bool res = mesh3d.CheckOverlappingBoundary();
+        if (res)
+        {
+        PrintError ("Surface is overlapping !!");
+        nonconsist = 1;
+        }
+        */
+
+        bool res = (mesh3d.CheckConsistentBoundary() != 0);
+        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 (int k = 1; k <= mesh3d.GetNDomains(); k++)
+       {
+	 if (multithread.terminate)
+           break;
+	 
+	 PrintMessage (2, "");
+	 PrintMessage (1, "Meshing subdomain ", k, " of ", mesh3d.GetNDomains());
+	 (*testout) << "Meshing subdomain " << k << endl;
+	 
+	 mp.maxh = min2 (globmaxh, mesh3d.MaxHDomain(k));
+	 
+	 mesh3d.CalcSurfacesOfNode();
+	 mesh3d.FindOpenElements(k);
+	 
+	 if (!mesh3d.GetNOpenElements())
+           continue;
+	 
+	 
+
+	 Box<3> domain_bbox( Box<3>::EMPTY_BOX ); 
+	 
+	 for (SurfaceElementIndex sei = 0; sei < mesh3d.GetNSE(); sei++)
+	   {
+	     const Element2d & el = mesh3d[sei];
+	     if (el.IsDeleted() ) continue;
+	     
+	     if (mesh3d.GetFaceDescriptor(el.GetIndex()).DomainIn() == k ||
+		 mesh3d.GetFaceDescriptor(el.GetIndex()).DomainOut() == k)
+	       
+	       for (int j = 0; j < el.GetNP(); j++)
+		 domain_bbox.Add (mesh3d[el[j]]);
+	   }
+	 domain_bbox.Increase (0.01 * domain_bbox.Diam());
+	 
+	
+        for (int qstep = 1; qstep <= 3; qstep++)
+	  {
+	    // cout << "openquads = " << mesh3d.HasOpenQuads() << endl;
+	    if (mesh3d.HasOpenQuads())
+	      {
+		string rulefile = ngdir;
+		
+		const char ** rulep = NULL;
+		switch (qstep)
+		  {
+		  case 1:
+		    rulefile += "/rules/prisms2.rls";
+		    rulep = prismrules2;
+		    break;
+		  case 2: // connect pyramid to triangle
+		    rulefile += "/rules/pyramids2.rls";
+		    rulep = pyramidrules2;
+		    break;
+		  case 3: // connect to vis-a-vis point
+		    rulefile += "/rules/pyramids.rls";
+		    rulep = pyramidrules;
+		    break;
+		  }
+		
+		//		Meshing3 meshing(rulefile);
+		Meshing3 meshing(rulep); 
+		
+		MeshingParameters mpquad = mp;
+		
+		mpquad.giveuptol = 15;
+		mpquad.baseelnp = 4;
+		mpquad.starshapeclass = 1000;
+		mpquad.check_impossible = qstep == 1;   // for prisms only (air domain in trafo)
+		
+		
+		for (PointIndex pi = PointIndex::BASE; 
+		     pi < mesh3d.GetNP()+PointIndex::BASE; pi++)
+		  meshing.AddPoint (mesh3d[pi], pi);
+		
+		mesh3d.GetIdentifications().GetPairs (0, connectednodes);
+		for (int i = 1; i <= connectednodes.Size(); i++)
+		  meshing.AddConnectedPair (connectednodes.Get(i));
+		
+		for (int i = 1; i <= mesh3d.GetNOpenElements(); i++)
+		  {
+		    Element2d hel = mesh3d.OpenElement(i);
+		    meshing.AddBoundaryElement (hel);
+		  }
+		
+		oldne = mesh3d.GetNE();
+		
+		meshing.GenerateMesh (mesh3d, mpquad);
+		
+		for (int i = oldne + 1; i <= mesh3d.GetNE(); i++)
+		  mesh3d.VolumeElement(i).SetIndex (k);
+		
+		(*testout) 
+		  << "mesh has " << mesh3d.GetNE() << " prism/pyramid 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((const char**)NULL);
+
+           mesh3d.FindOpenElements(k);
+
+
+           for (PointIndex pi = PointIndex::BASE; 
+              pi < mesh3d.GetNP()+PointIndex::BASE; pi++)
+              meshing.AddPoint (mesh3d[pi], pi);
+
+
+           for (int i = 1; i <= mesh3d.GetNOpenElements(); i++)
+              meshing.AddBoundaryElement (mesh3d.OpenElement(i));
+
+           oldne = mesh3d.GetNE();
+
+           meshing.Delaunay (mesh3d, k, mp);
+
+           for (int i = oldne + 1; i <= mesh3d.GetNE(); i++)
+              mesh3d.VolumeElement(i).SetIndex (k);
+
+           PrintMessage (3, mesh3d.GetNP(), " points, ",
+              mesh3d.GetNE(), " elements");
+        }
+
+
+        int cntsteps = 0;
+        if (mesh3d.GetNOpenElements())
+           do
+           {
+              if (multithread.terminate)
+                 break;
+
+              mesh3d.FindOpenElements(k);
+              PrintMessage (5, mesh3d.GetNOpenElements(), " open faces");
+              cntsteps++;
+
+              if (cntsteps > mp.maxoutersteps) 
+                 throw NgException ("Stop meshing since too many attempts");
+
+              string rulefile = ngdir + "/tetra.rls";
+              PrintMessage (1, "start tetmeshing");
+
+              //	  Meshing3 meshing(rulefile);
+              Meshing3 meshing(tetrules);
+
+              Array<int, PointIndex::BASE> glob2loc(mesh3d.GetNP());
+              glob2loc = -1;
+
+              for (PointIndex pi = PointIndex::BASE; 
+                 pi < mesh3d.GetNP()+PointIndex::BASE; pi++)
+
+                 if (domain_bbox.IsIn (mesh3d[pi]))
+                    glob2loc[pi] = 
+                    meshing.AddPoint (mesh3d[pi], pi);
+
+              for (int i = 1; i <= mesh3d.GetNOpenElements(); i++)
+              {
+                 Element2d hel = mesh3d.OpenElement(i);
+                 for (int j = 0; j < hel.GetNP(); j++)
+                    hel[j] = glob2loc[hel[j]];
+                 meshing.AddBoundaryElement (hel);
+                 // meshing.AddBoundaryElement (mesh3d.OpenElement(i));
+              }
+
+              oldne = mesh3d.GetNE();
+
+              mp.giveuptol = 15 + 10 * cntsteps; 
+              mp.sloppy = 5;
+              meshing.GenerateMesh (mesh3d, mp);
+
+              for (ElementIndex ei = oldne; ei < mesh3d.GetNE(); ei++)
+                 mesh3d[ei].SetIndex (k);
+
+
+              mesh3d.CalcSurfacesOfNode();
+              mesh3d.FindOpenElements(k);
+
+              // teterrpow = 2;
+              if (mesh3d.GetNOpenElements() != 0)
+              {
+                 meshed = 0;
+                 PrintMessage (5, mesh3d.GetNOpenElements(), " open faces found");
+
+                 MeshOptimize3d optmesh(mp);
+
+                 const char * optstr = "mcmstmcmstmcmstmcm";
+                 for (size_t j = 1; j <= strlen(optstr); j++)
+                 {
+                    mesh3d.CalcSurfacesOfNode();
+                    mesh3d.FreeOpenElementsEnvironment(2);
+                    mesh3d.CalcSurfacesOfNode();
+
+                    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(mp, OPT_REST); break;
+                    }	  
+
+                 }
+
+                 mesh3d.FindOpenElements(k);	      
+                 PrintMessage (3, "Call remove problem");
+                 RemoveProblem (mesh3d, k);
+                 mesh3d.FindOpenElements(k);
+              }
+              else
+              {
+                 meshed = 1;
+                 PrintMessage (1, "Success !");
+              }
+           }
+           while (!meshed);
+
+           PrintMessage (1, mesh3d.GetNP(), " points, ",
+              mesh3d.GetNE(), " elements");
+     }
+
+     mp.maxh = globmaxh;
+
+     MeshQuality3d (mesh3d);
+
+     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;
+
+    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(mp);
+
+	// teterrpow = mp.opterrpow;
+	for (size_t 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 'u': optmesh.SwapImproveSurface(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(mp); break;
+	      case 'M': mesh3d.ImproveMesh(mp); break;
+#endif
+	      case 'j': mesh3d.ImproveMeshJacobian(mp); break;
+	      }
+	  }
+	mesh3d.mglevels = 1;
+	MeshQuality3d (mesh3d);
+      }
+  
+    return MESHING3_OK;
+  }
+
+
+
+
+  void RemoveIllegalElements (Mesh & mesh3d)
+  {
+    int it = 10;
+    int nillegal, oldn;
+
+    PrintMessage (1, "Remove Illegal Elements");
+    // return, if non-pure tet-mesh
+    /*
+      if (!mesh3d.PureTetMesh())
+      return;
+    */
+    mesh3d.CalcSurfacesOfNode();
+
+    nillegal = mesh3d.MarkIllegalElements();
+
+    MeshingParameters dummymp;
+    MeshOptimize3d optmesh(dummymp);
+    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/contrib/Netgen/libsrc/meshing/meshfunc.hpp b/contrib/Netgen/libsrc/meshing/meshfunc.hpp
new file mode 100644
index 0000000000..f39c0a8fcb
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/meshfunc.hpp
@@ -0,0 +1,41 @@
+#ifndef FILE_MESHFUNC
+#define FILE_MESHFUNC
+
+/**************************************************************************/
+/* File:   meshfunc.hpp                                                   */
+/* Author: Johannes Gerstmayr, Joachim Schoeberl                          */
+/* Date:   26. Jan. 98                                                    */
+/**************************************************************************/
+
+
+/*
+  Functions for mesh-generations strategies
+ */
+
+class Mesh;
+// 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/contrib/Netgen/libsrc/meshing/meshfunc2d.cpp b/contrib/Netgen/libsrc/meshing/meshfunc2d.cpp
new file mode 100644
index 0000000000..495f877760
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/meshfunc2d.cpp
@@ -0,0 +1,61 @@
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+namespace netgen
+{
+
+  DLL_HEADER void Optimize2d (Mesh & mesh, MeshingParameters & mp)
+  {
+    int i;
+
+    //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 (size_t 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, mp);
+		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/contrib/Netgen/libsrc/meshing/meshing.hpp b/contrib/Netgen/libsrc/meshing/meshing.hpp
new file mode 100644
index 0000000000..7fd9c19632
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/meshing.hpp
@@ -0,0 +1,71 @@
+#ifndef FILE_MESHING
+#define FILE_MESHING
+
+
+
+#include "../include/myadt.hpp"
+#include "../include/gprim.hpp"
+#include "../include/linalg.hpp"
+#include "../include/opti.hpp"
+
+
+
+namespace netgen
+{
+  // extern int printmessage_importance;
+
+  class CSGeometry;
+  class NetgenGeometry;
+}
+  
+  
+#include "msghandler.hpp"
+#include "meshtype.hpp"
+#include "localh.hpp"
+#include "meshclass.hpp"
+#include "global.hpp"
+
+
+namespace netgen
+{
+#include "meshtool.hpp"
+#include "ruler2.hpp"
+#include "adfront2.hpp"
+#include "meshing2.hpp"
+#include "improve2.hpp"
+
+
+#include "geomsearch.hpp"
+#include "adfront3.hpp"
+#include "ruler3.hpp"
+
+#define _INCLUDE_MORE
+
+
+#include "meshing3.hpp"
+#include "improve3.hpp"
+
+#include "findip.hpp"
+#include "findip2.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"
+}
+
+#include "validate.hpp"
+#include "basegeom.hpp"
+
+#ifdef PARALLEL
+#include "paralleltop.hpp"
+#endif
+
+
+#endif
diff --git a/contrib/Netgen/libsrc/meshing/meshing2.cpp b/contrib/Netgen/libsrc/meshing/meshing2.cpp
new file mode 100644
index 0000000000..d31c73e1d5
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/meshing2.cpp
@@ -0,0 +1,1957 @@
+#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;
+
+
+  Meshing2 :: Meshing2 (const MeshingParameters & mp, const Box<3> & aboundingbox)
+  {
+    boundingbox = aboundingbox;
+    
+    LoadRules (NULL, mp.quad);
+    // LoadRules ("rules/quad.rls");
+    // LoadRules ("rules/triangle.rls");
+
+    adfront = new AdFront2(boundingbox);
+    starttime = GetTime();
+
+    maxarea = -1;
+  }
+
+
+  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,
+			     bool pointonsurface)
+  {
+    //(*testout) << "add point " << globind << endl;
+    adfront ->AddPoint (p, globind, mgi, pointonsurface);
+  }
+
+  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-1, i2-1, 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;
+  }
+
+  
+  void Meshing2 :: SetMaxArea (double amaxarea)
+  {
+    maxarea = amaxarea;
+  }
+
+
+  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 (const Point3d & p1, const 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 (globp1, locpoint);
+
+    //    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, const MeshingParameters & mp, double gh, int facenr)
+  {
+    static int timer = NgProfiler::CreateTimer ("surface meshing");
+
+    static int timer1 = NgProfiler::CreateTimer ("surface meshing1");
+    static int timer2 = NgProfiler::CreateTimer ("surface meshing2");
+    static int timer3 = NgProfiler::CreateTimer ("surface meshing3");
+    NgProfiler::RegionTimer reg (timer);
+
+
+    Array<int> pindex, lindex;
+    Array<int> delpoints, dellines;
+
+    Array<PointGeomInfo> upgeominfo;  // unique info
+    Array<MultiPointGeomInfo> mpgeominfo;  // multiple info
+
+    Array<Element2d> locelements;
+
+    int z1, z2, oldnp(-1);
+    bool found;
+    int rulenr(-1);
+    int globind;
+    Point<3> p1, p2;
+
+    const PointGeomInfo * blgeominfo1;
+    const PointGeomInfo * blgeominfo2;
+
+    bool morerisc;
+    bool debugflag;
+
+    double h, his, hshould;
+
+
+    Array<Point3d> locpoints;
+    Array<int> legalpoints;
+    Array<Point2d> plainpoints;
+    Array<int> plainzones;
+    Array<INDEX_2> loclines;
+    int cntelem = 0, trials = 0, nfaces = 0;
+    int oldnl = 0;
+    int qualclass;
+
+
+
+    // 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;
+
+    StartMesh();
+
+    Array<Point2d> chartboundpoints;
+    Array<Point3d> chartboundpoints3d;
+    Array<INDEX_2> chartboundlines;
+
+    // illegal points: points with more then 50 elements per node
+    int maxlegalpoint(-1), maxlegalline(-1);
+    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)
+	  {
+	    Box<3> box;
+	    box.Set ( mesh[sel[0]] );
+	    box.Add ( mesh[sel[1]] );
+	    box.Add ( mesh[sel[2]] );
+	    surfeltree.Insert (box, sei);
+	  }
+      }
+    */
+    Array<SurfaceElementIndex> seia;
+    mesh.GetSurfaceElementsOfFace (facenr, seia);
+    for (int i = 0; i < seia.Size(); i++)
+      {
+	const Element2d & sel = mesh[seia[i]];
+
+	if (sel.IsDeleted()) continue;
+
+	Box<3> box;
+	box.Set ( mesh[sel[0]] );
+	box.Add ( mesh[sel[1]] );
+	box.Add ( mesh[sel[2]] );
+	surfeltree.Insert (box, i);
+      }
+
+
+
+
+    if (totalarea > 0 || maxarea > 0)
+      for (SurfaceElementIndex sei = 0; sei < mesh.GetNSE(); sei++)
+	{
+	  const Element2d & sel = mesh[sei];
+	  if (sel.IsDeleted()) continue;
+	
+	  double trigarea = Cross ( mesh[sel[1]]-mesh[sel[0]],
+				    mesh[sel[2]]-mesh[sel[0]] ).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;
+	}
+
+
+
+
+    const char * savetask = multithread.task;
+    multithread.task = "Surface meshing";
+
+    adfront ->SetStartFront ();
+
+
+    int plotnexttrial = 999;
+
+    double meshedarea_before = meshedarea;
+
+
+    while (!adfront ->Empty() && !multithread.terminate)
+      {
+	NgProfiler::RegionTimer reg1 (timer1);
+
+	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 + 0.0001)));
+	    plotnexttrial += 1000;
+	  }
+
+
+	// unique-pgi, multi-pgi
+	upgeominfo.SetSize(0);
+	mpgeominfo.SetSize(0);
+
+
+	nfaces = adfront->GetNFL();
+	trials ++;
+    
+
+	if (trials % 1000 == 0)
+	  {
+	    (*testout) << "\n";
+	    for (int 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";
+	  }
+
+
+	int baselineindex = adfront -> SelectBaseLine (p1, p2, blgeominfo1, blgeominfo2, qualclass);
+
+
+	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;
+
+	double hinner = (3 + qualclass) * max2 (his, hshould);
+
+	adfront ->GetLocals (baselineindex, locpoints, mpgeominfo, loclines, 
+			     pindex, lindex, 2*hinner);
+
+
+	NgProfiler::RegionTimer reg2 (timer2);
+
+	//(*testout) << "h for locals: " << 2*hinner << endl;
+	
+
+	//(*testout) << "locpoints " << locpoints << endl;
+
+	if (qualclass > mp.giveuptol2d)
+	  {
+	    PrintMessage (3, "give up with qualclass ", qualclass);
+	    PrintMessage (3, "number of frontlines = ", adfront->GetNFL());
+	    // throw NgException ("Give up 2d meshing");
+	    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;
+	  }
+	
+	if (debugparam.haltlargequalclass && qualclass > 50)
+	  debugflag = 1;
+
+	// 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();
+	  
+	    if (debugflag)
+	      (*testout) << "define new transformation" << endl;
+
+	    DefineTransformation (p1, p2, blgeominfo1, blgeominfo2);
+	  
+	    plainpoints.SetSize (locpoints.Size());
+	    plainzones.SetSize (locpoints.Size());
+
+	    // (*testout) << endl;
+
+	    if (debugflag)
+	      {
+		*testout << "3d->2d transformation" << endl;
+		*testout << "3d points: " << endl << locpoints << endl;
+	      }
+
+	    for (int 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));
+		//		(*testout) << mpgeominfo.Get(i).GetPGI(1).u << " " << mpgeominfo.Get(i).GetPGI(1).v << " ";
+		//		(*testout) << plainpoints.Get(i).X() << " " << plainpoints.Get(i).Y() << endl;
+		//(*testout) << "transform " << locpoints.Get(i) << " to " << plainpoints.Get(i).X() << " " << plainpoints.Get(i).Y() << endl;
+	      }
+	    //	    (*testout) << endl << endl << endl;
+
+
+	    if (debugflag)
+	      *testout << "2d points: " << endl << plainpoints << endl;
+
+
+	    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 (int 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 (-1);
+			    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 (int i = 1; i <= legalpoints.Size(); i++)
+	      legalpoints.Elem(i) = 1;
+
+	    double avy = 0;
+	    for (int i = 1; i <= plainpoints.Size(); i++)
+	      avy += plainpoints.Elem(i).Y();
+	    avy *= 1./plainpoints.Size();
+		
+
+	    for (int 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) == -1)
+		  {
+		    legalpoints.Elem(i) = 0;
+		  }
+		    
+
+		if (plainpoints.Elem(i).Y() < -1e-10*avy) // changed
+		  {
+		    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 (mp.checkchartboundary)
+	      {
+		for (int i = 1; i <= chartboundpoints.Size(); i++)
+		  {
+		    plainpoints.Append (chartboundpoints.Get(i));
+		    locpoints.Append (chartboundpoints3d.Get(i));
+		    legalpoints.Append (0);
+		  }
+	      
+
+		for (int 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, mp);
+
+	    //	    (*testout) << "Rule Nr = " << rulenr << endl;
+	    if (!rulenr)
+	      {
+		found = 0;
+		if ( debugflag || debugparam.haltnosuccess )
+		  PrintWarning ("no rule found");
+	      }
+	  }
+      
+	NgProfiler::RegionTimer reg3 (timer3);
+
+
+	for (int i = 1; i <= locelements.Size() && found; i++)
+	  {
+	    const Element2d & el = locelements.Get(i);
+
+	    for (int j = 1; j <= el.GetNP(); j++)
+	      if (el.PNum(j) <= oldnp && pindex.Get(el.PNum(j)) == -1)
+		{
+		  found = 0;
+		  PrintSysError ("meshing2, index missing");
+		}
+	  }
+
+
+	if (found)
+	  {
+	    locpoints.SetSize (plainpoints.Size());
+	    upgeominfo.SetSize(locpoints.Size());
+
+	    for (int 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 (int i = oldnl+1; i <= loclines.Size(); i++)
+	      {
+		double eh = Dist (locpoints.Get(loclines.Get(i).I1()),
+				  locpoints.Get(loclines.Get(i).I2()));
+
+		// Markus (brute force method to avoid bad elements on geometries like \_/ )
+		//if(eh > 4.*mesh.GetH(locpoints.Get(loclines.Get(i).I1()))) found = 0;
+		//if(eh > 4.*mesh.GetH(locpoints.Get(loclines.Get(i).I2()))) found = 0;
+		// Markus end
+
+		if (eh > newedgemaxh)
+		  newedgemaxh = eh;
+	      }
+
+	    for (int i = 1; i <= locelements.Size(); i++)
+	      {
+		Point3d pmin = locpoints.Get(locelements.Get(i).PNum(1));
+		Point3d pmax = pmin;
+		for (int 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;
+	      }
+
+	    for (int i = 1; i <= locelements.Size(); i++)
+	      for (int j = 1; j <= locelements.Get(i).GetNP(); j++)
+		if (Dist2 (locpoints.Get(locelements.Get(i).PNum(j)), pmid) > hinner*hinner)
+		  found = 0;
+
+	    //	  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 (int i = 1; i <= locelements.Size(); i++)
+	      for (int 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 && mp.checkoverlap)
+	  {
+	    // cout << "checkoverlap" << endl;
+	    // test for overlaps
+	  
+	    Point3d hullmin(1e10, 1e10, 1e10);
+	    Point3d hullmax(-1e10, -1e10, -1e10);
+	  
+	    for (int i = 1; i <= locelements.Size(); i++)
+	      for (int 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 (int i = oldnp+1; i <= locpoints.Size(); i++)
+	      critpoints.Append (locpoints.Get(i));
+
+	    for (int 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 (int 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++)
+		  {
+		    int 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 (int 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 (int 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 (int i = oldnp+1; i <= locpoints.Size(); i++)
+	      {
+		globind = mesh.AddPoint (locpoints.Get(i));
+		pindex.Elem(i) = adfront -> AddPoint (locpoints.Get(i), globind);
+	      }
+	      
+	    for (int 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()) == -1 || 
+		    pindex.Get(loclines.Get(i).I2()) == -1)
+		  {
+		    (*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 (int 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 (int 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 (int 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;
+
+
+	      
+		Box<3> box;
+		box.Set (mesh[mtri[0]]);
+		box.Add (mesh[mtri[1]]);
+		box.Add (mesh[mtri[2]]);
+		surfeltree.Insert (box, mesh.GetNSE());
+
+		const Point3d & sep1 = mesh.Point (mtri.PNum(1));
+		const Point3d & sep2 = mesh.Point (mtri.PNum(2));
+		const Point3d & sep3 = mesh.Point (mtri.PNum(3));
+
+		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;
+
+		if(maxarea > 0 && meshedarea-meshedarea_before > maxarea)
+		  {
+		    cerr << "meshed area = " << meshedarea-meshedarea_before << endl
+			 << "maximal area = " << maxarea << endl
+			 << "GIVING UP" << endl;
+		    return MESHING2_GIVEUP;
+		  }
+	      
+
+
+		for (int 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 (int 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 (int i = 1; i <= dellines.Size(); i++)
+	      adfront -> DeleteLine (lindex.Get(dellines.Get(i)));
+	      
+	    //	  rname = rules.Get(rulenr)->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 )
+	      {
+		// adfront -> PrintOpenSegments (*testout);
+		cout << "success of rule" << rules.Get(rulenr)->Name() << 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()));
+		  }
+		*/
+
+		(*testout) << "success of rule" << rules.Get(rulenr)->Name() << endl;
+		(*testout) << "trials = " << trials << endl;
+
+		(*testout) << "locpoints " << endl;
+		for (int i = 1; i <= pindex.Size(); i++)
+		  (*testout) << adfront->GetGlobalIndex (pindex.Get(i)) << endl;
+
+		(*testout) << "old number of lines = " << oldnl << endl;
+		for (int i = 1; i <= loclines.Size(); i++)
+		  {
+		    (*testout) << "line ";
+		    for (int 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;
+		  }
+
+
+
+		glrender(1);
+	      }
+	  }
+	else
+	  {
+	    adfront -> IncrementClass (lindex.Get(1));
+
+	    if ( debugparam.haltnosuccess || debugflag )
+	      {
+		cout << "Problem with seg " << gpi1 << " - " << gpi2
+		     << ", class = " << qualclass << endl;
+
+		(*testout) << "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 (int i = 1; i <= loclines.Size(); i++)
+		  {
+		    (*testout) << "line ";
+		    for (int 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;
+
+
+    EndMesh ();
+
+
+    if (!adfront->Empty())
+      return MESHING2_GIVEUP;
+    
+    return MESHING2_OK;
+  }
+
+
+
+
+
+
+
+
+
+}
+
+
+
+
+
+
+// #define OPENGL
+#ifdef OPENGLxx
+
+/* *********************** 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;
+
+    if (loclines.Size() != changeval)
+      {
+	center = Point<3>(0,0,-5);
+	rad = 0.1;
+  
+	CalcTransformationMatrices();
+	changeval = loclines.Size();
+      }
+
+  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);
+  glEnable (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);
+
+    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_colp[] = { 1, 0, 0, 1 };
+
+    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();
+
+
+
+
+
+
+  glDisable (GL_POLYGON_OFFSET_FILL);
+ 
+  glPopMatrix();
+  DrawCoordinateCross ();
+  DrawNetgenLogo ();
+  glFinish();  
+
+  /*
+    glDisable (GL_POLYGON_OFFSET_FILL);
+
+    //  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/contrib/Netgen/libsrc/meshing/meshing2.hpp b/contrib/Netgen/libsrc/meshing/meshing2.hpp
new file mode 100644
index 0000000000..4e14596438
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/meshing2.hpp
@@ -0,0 +1,164 @@
+#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;
+  /// 
+  Box<3> boundingbox;
+  ///
+  double starttime;
+  ///
+  double maxarea;
+
+  Vec3d ex, ey;
+  Point3d globp1;
+
+public:
+  ///
+  DLL_HEADER Meshing2 (const MeshingParameters & mp, const Box<3> & aboundingbox);
+
+  ///
+  DLL_HEADER virtual ~Meshing2 ();
+
+  /// Load rules, either from file, or compiled rules
+  void LoadRules (const char * filename, bool quad);
+
+  /// 
+  DLL_HEADER MESHING2_RESULT GenerateMesh (Mesh & mesh, const MeshingParameters & mp, double gh, int facenr);
+
+  DLL_HEADER void Delaunay (Mesh & mesh, int domainnr, const MeshingParameters & mp);
+  DLL_HEADER void BlockFillLocalH (Mesh & mesh, const MeshingParameters & mp);
+
+
+  ///
+  DLL_HEADER void AddPoint (const Point3d & p, PointIndex globind, MultiPointGeomInfo * mgi = NULL,
+		 bool pointonsurface = true);
+
+  ///
+  DLL_HEADER void AddBoundaryElement (INDEX i1, INDEX i2,
+			   const PointGeomInfo & gi1, const PointGeomInfo & gi2);
+  
+  ///
+  void SetStartTime (double astarttime);
+
+  ///
+  void SetMaxArea (double amaxarea);
+
+protected:
+  ///
+  virtual void StartMesh ();
+  ///
+  virtual void EndMesh ();
+  ///
+  virtual double CalcLocalH (const Point3d & p, double gh) const;
+
+  ///
+  virtual void DefineTransformation (const Point3d & p1, const 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,
+		  const MeshingParameters & mp);
+  
+
+};
+
+
+
+
+
+
+
+
+#endif
+
+
+
+
+
+
+
diff --git a/contrib/Netgen/libsrc/meshing/meshing3.cpp b/contrib/Netgen/libsrc/meshing/meshing3.cpp
new file mode 100644
index 0000000000..3421c3192c
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/meshing3.cpp
@@ -0,0 +1,1264 @@
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+namespace netgen
+{
+
+double minother;
+double minwithoutother;
+
+
+
+
+
+MeshingStat3d :: MeshingStat3d ()
+{
+  cntsucc = cnttrials = cntelem = qualclass = 0;
+  vol0 = h = 1;
+  problemindex = 1;
+}  
+  
+
+Meshing3 :: Meshing3 (const string & rulefilename) 
+{
+  tolfak = 1;
+
+  LoadRules (rulefilename.c_str(), NULL);
+  adfront = new AdFront3;
+
+  problems.SetSize (rules.Size());
+  foundmap.SetSize (rules.Size());
+  canuse.SetSize (rules.Size());
+  ruleused.SetSize (rules.Size());
+
+  for (int 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 ** rulep)
+{
+  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];
+    }
+}
+
+
+
+static double CalcLocH (const Array<Point3d> & locpoints,
+			const Array<MiniElement2d> & 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;
+}
+
+
+PointIndex Meshing3 :: AddPoint (const Point3d & p, PointIndex globind)
+{
+  return adfront -> AddPoint (p, globind);  
+}  
+
+void Meshing3 :: AddBoundaryElement (const Element2d & elem)
+{
+  MiniElement2d mini(elem.GetNP());
+  for (int j = 0; j < elem.GetNP(); j++)
+    mini[j] = elem[j];
+  adfront -> AddFace(mini);
+}  
+
+
+void Meshing3 :: AddBoundaryElement (const MiniElement2d & elem)
+{
+  adfront -> AddFace(elem);
+}
+
+int Meshing3 :: AddConnectedPair (const INDEX_2 & apair)
+{
+  return adfront -> AddConnectedPair (apair);
+}
+
+MESHING3_RESULT Meshing3 :: 
+GenerateMesh (Mesh & mesh, const MeshingParameters & mp)
+{
+  static int meshing3_timer = NgProfiler::CreateTimer ("Meshing3::GenerateMesh");
+  static int meshing3_timer_a = NgProfiler::CreateTimer ("Meshing3::GenerateMesh a");
+  static int meshing3_timer_b = NgProfiler::CreateTimer ("Meshing3::GenerateMesh b");
+  static int meshing3_timer_c = NgProfiler::CreateTimer ("Meshing3::GenerateMesh c");
+  static int meshing3_timer_d = NgProfiler::CreateTimer ("Meshing3::GenerateMesh d");
+  NgProfiler::RegionTimer reg (meshing3_timer);
+
+
+  Array<Point3d > locpoints;      // local points
+  Array<MiniElement2d> 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
+  
+  bool loktestmode = false;
+
+  int uselocalh = mp.uselocalh;
+
+  // int giveuptol = mp.giveuptol; // 
+  MeshingStat3d stat;      // statistics
+  int plotstat_oldne = -1;
+
+  
+  // for star-shaped domain meshing
+  Array<MeshPoint> grouppoints;      
+  Array<MiniElement2d> groupfaces;
+  Array<PointIndex> grouppindex;
+  Array<INDEX> groupfindex;
+  
+  
+  float minerr;
+  int hasfound;
+  double tetvol;
+  // int giveup = 0;
+
+  
+  Array<Point3d> tempnewpoints;
+  Array<MiniElement2d> 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");
+
+      // 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);  // connected 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 MiniElement2d & 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));
+
+      // (*testout) << endl << "base = " << bel << endl;
+
+
+      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);
+
+      NgProfiler::StartTimer (meshing3_timer_a);
+      stat.qualclass =
+        adfront -> GetLocals (baseelem, locpoints, locfaces, 
+			      pindex, findex, connectedpairs,
+			      houter, hinner,
+			      locfacesplit);
+      NgProfiler::StopTimer (meshing3_timer_a);
+
+      // (*testout) << "locfaces = " << endl << locfaces << endl;
+
+      int pi1 = pindex.Get(locfaces[0].PNum(1));
+      int pi2 = pindex.Get(locfaces[0].PNum(2));
+      int pi3 = pindex.Get(locfaces[0].PNum(3));
+
+      //loktestmode = 1;
+      testmode = loktestmode;  //changed 
+      // loktestmode = testmode =  (adfront->GetFace (baseelem).GetNP() == 4) && (rules.Size() == 5);
+
+      loktestmode = stat.qualclass > 5;
+      
+
+      if (loktestmode)
+	{
+	  (*testout) << "baseel = " << baseelem << ", ind = " << findex.Get(1) << endl;
+	  (*testout) << "pi = " << pi1 << ", " << pi2 << ", " << pi3 << endl;
+	}
+
+
+
+
+
+      if (testmode)
+	{
+	  (*testout) << "baseelem = " << baseelem << " qualclass = " << stat.qualclass << endl;
+	  (*testout) << "locpoints = " << endl << locpoints << endl;
+	  (*testout) << "connected = " << endl << connectedpairs << 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) ? 2 : 1;
+	  }
+      else
+	allowpoint = 2;
+
+
+      
+      if (stat.qualclass >= mp.starshapeclass &&
+	  mp.baseelnp != 4)   
+	{
+	  NgProfiler::RegionTimer reg1 (meshing3_timer_b);
+	  // star-shaped domain removing
+
+	  grouppoints.SetSize (0);
+	  groupfaces.SetSize (0);
+	  grouppindex.SetSize (0);
+	  groupfindex.SetSize (0);
+	  
+	  adfront -> GetGroup (findex[0], grouppoints, groupfaces, 
+			       grouppindex, groupfindex);
+
+	  bool onlytri = 1;
+	  for (i = 0; i < groupfaces.Size(); i++)
+	    if (groupfaces[i].GetNP() != 3) 
+	      onlytri = 0;
+	  
+	  if (onlytri && groupfaces.Size() <= 20 + 2*stat.qualclass &&
+	      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;
+
+      bool impossible = 1;
+
+      for (rotind = 1; rotind <= locfaces[0].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);
+
+
+	  for (i = 1; i <= allowpoint.Size(); i++)
+	    {
+	      if (plainpoints.Get(i).Z() > 0)
+		{
+		  //if(loktestmode)
+		  //  (*testout) << "plainpoints.Get(i).Z() = " << plainpoints.Get(i).Z() << " > 0" << endl;
+		  allowpoint.Elem(i) = 0;
+		}
+	    }
+
+	  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;
+	    }
+
+	  NgProfiler::StartTimer (meshing3_timer_c);	  
+
+	  found = ApplyRules (plainpoints, allowpoint, 
+			      locfaces, locfacesplit, connectedpairs,
+			      locelements, delfaces, 
+			      stat.qualclass, mp.sloppy, rotind, err);
+
+	  if (found >= 0) impossible = 0;
+	  if (found < 0) found = 0;
+
+
+	  NgProfiler::StopTimer (meshing3_timer_c);	  
+
+	  if (!found) loktestmode = 0;
+
+	  NgProfiler::RegionTimer reg2 (meshing3_timer_d);	  
+	  
+	  if (loktestmode)
+	    {
+	      (*testout) << "plainpoints = " << endl << plainpoints << endl;
+	      (*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)++;
+
+
+	  // 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) << "found is active, 3" << 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 (loktestmode)
+	    {
+	      (*testout) << "apply rule" << 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));
+	  if (impossible && mp.check_impossible)
+	    {
+	      (*testout) << "skip face since it is impossible" << endl;
+	      for (j = 0; j < 100; j++)
+		adfront->IncrementClass (findex.Get(1));
+	    }
+	}
+
+      locelements.SetSize (0);
+      delpoints.SetSize(0);
+      delfaces.SetSize(0);
+
+      if (stat.qualclass >= mp.giveuptol)
+	break;
+    }
+  
+  PrintMessage (5, "");  // line feed after statistics
+
+  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(0), i1, i2, i3, j1, j2, j3;
+  int n1, n2, n3, n, min1, min2, min3, max1, max2, max3;
+  int changed, filled;
+  double xmin(0), xmax(0), ymin(0), ymax(0), zmin(0), zmax(0);
+  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 MiniElement2d & 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(0), pi2(0), pi3(0), pi4(0);
+
+	      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)
+		    {
+		      MiniElement2d 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)
+{
+  double filldist = mp.filldist;
+
+  (*testout) << "blockfill local h" << endl;
+  (*testout) << "rel filldist = " << filldist << endl;
+  PrintMessage (3, "blockfill local h");
+
+
+  Array<Point<3> > npoints;
+  
+  adfront -> CreateTrees();
+
+  Box<3> bbox ( Box<3>::EMPTY_BOX );
+  double maxh = 0;
+
+  for (int i = 1; i <= adfront->GetNF(); i++)
+    {
+      const MiniElement2d & el = adfront->GetFace(i);
+      for (int 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;
+
+	  bbox.Add (p1);
+	}
+    }
+
+
+  Point3d mpmin = bbox.PMin();
+  Point3d mpmax = bbox.PMax();
+  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;
+
+  bool changed;
+  do 
+    {
+      mesh.LocalHFunction().ClearFlags();
+
+      for (int i = 1; i <= adfront->GetNF(); i++)
+	{
+	  const MiniElement2d & el = adfront->GetFace(i);
+	  
+	  Box<3> bbox (adfront->GetPoint (el[0]));
+	  bbox.Add (adfront->GetPoint (el[1]));
+	  bbox.Add (adfront->GetPoint (el[2]));
+
+
+	  double filld = filldist * bbox.Diam();
+	  bbox.Increase (filld);
+      
+      	  mesh.LocalHFunction().CutBoundary (bbox); // .PMin(), bbox.PMax());
+	}
+
+      //      locadfront = adfront;
+      mesh.LocalHFunction().FindInnerBoxes (adfront, NULL);
+
+      npoints.SetSize(0);
+      mesh.LocalHFunction().GetInnerPoints (npoints);
+
+      changed = false;
+      for (int i = 1; i <= npoints.Size(); i++)
+	{
+	  if (mesh.LocalHFunction().GetH(npoints.Get(i)) > 1.5 * maxh)
+	    {
+	      mesh.LocalHFunction().SetH (npoints.Get(i), maxh);
+	      changed = true;
+	    }
+	}
+    }
+  while (changed);
+
+  if (debugparam.slowchecks)
+    (*testout) << "Blockfill with points: " << endl;
+  for (int 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 (int i = 1; i <= adfront->GetNF(); i++)
+    {
+      const MiniElement2d & el = adfront->GetFace(i);
+      Point3d pmin = adfront->GetPoint (el.PNum(1));
+      Point3d pmax = pmin;
+      
+      for (int 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 (int i = 1; i <= adfront->GetNF(); i++)
+    {
+      const MiniElement2d & el = adfront->GetFace(i);
+      Point3d pmin = adfront->GetPoint (el.PNum(1));
+      Point3d pmax = pmin;
+      
+      for (int 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);
+      loch2.CutBoundary (Box<3> (pmin, pmax)); // pmin, pmax);
+    }
+
+  // locadfront = adfront;
+  loch2.FindInnerBoxes (adfront, NULL);
+
+  npoints.SetSize(0);
+  loch2.GetOuterPoints (npoints);
+  
+  for (int 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/contrib/Netgen/libsrc/meshing/meshing3.hpp b/contrib/Netgen/libsrc/meshing/meshing3.hpp
new file mode 100644
index 0000000000..84e9ca6b71
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/meshing3.hpp
@@ -0,0 +1,130 @@
+#ifndef FILE_MESHING3
+#define FILE_MESHING3
+
+
+
+
+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 string & rulefilename); 
+  /// 
+  Meshing3 (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<MiniElement2d> & lfaces, INDEX lfacesplit,
+		  INDEX_2_HASHTABLE<int> & connectedpairs,
+		  Array<Element> & elements,
+		  Array<INDEX> & delfaces, int tolerance, 
+		  double sloppy, int rotind1,
+		  float & retminerr);
+  
+  ///
+  PointIndex AddPoint (const Point3d & p, PointIndex globind);
+  ///
+  void AddBoundaryElement (const Element2d & elem);
+  ///
+  void AddBoundaryElement (const MiniElement2d & 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, int domainnr, 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;
+};
+
+
+
+
+
+/*
+template <typename POINTArray, typename FACEArray>
+extern int FindInnerPoint (POINTArray & grouppoints,
+			   FACEArray & groupfaces,
+			   Point3d & p);
+
+*/
+
+
+
+
+
+#endif
+
+
+
+
+
+
+
+
+
+
diff --git a/contrib/Netgen/libsrc/meshing/meshtool.cpp b/contrib/Netgen/libsrc/meshing/meshtool.cpp
new file mode 100644
index 0000000000..4a349ac9c4
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/meshtool.cpp
@@ -0,0 +1,1015 @@
+#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;
+
+    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 Point<3> *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);
+    (*testout) << setprecision(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)
+  }
+
+
+
+
+  // static double teterrpow = 2;
+
+  double CalcTetBadness (const Point3d & p1, const Point3d & p2,
+			 const Point3d & p3, const Point3d & p4, double h,
+			 const MeshingParameters & mp)
+  {
+    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)  * (-0.166666666666666);
+
+    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 = 0.0080187537 * lll / vol;    // sqrt(216) / (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;
+    
+    double teterrpow = mp.opterrpow;
+    if(teterrpow < 1) teterrpow = 1;
+    
+    if (teterrpow == 1) return err;
+    if (teterrpow == 2) return err*err;
+    return pow (err, teterrpow);
+  }
+
+
+  double CalcTetBadnessGrad (const Point3d & p1, const Point3d & p2,
+			     const Point3d & p3, const Point3d & p4, double h,
+			     int pi, Vec<3> & grad,
+			     const MeshingParameters & mp)
+  {
+    double vol, l, ll, lll;
+    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);
+
+    vol = Determinant (v1, v2, v3) * (-0.166666666666666);
+
+    Vec3d gradvol;
+    Cross (v5, v4, gradvol);
+    gradvol *= (-1.0/6.0);
+
+
+    double ll1 = v1.Length2();
+    double ll2 = v2.Length2();
+    double ll3 = v3.Length2();
+    double ll4 = v4.Length2();
+    double ll5 = v5.Length2();
+    double ll6 = v6.Length2();
+
+    ll = ll1 + ll2 + ll3 + ll4 + ll5 + ll6;
+    l = sqrt (ll);
+    lll = l * ll;
+
+    if (vol <= 1e-24 * lll)
+      { 
+	grad = Vec3d (0, 0, 0);
+	return 1e24;
+      }
+
+
+
+    Vec3d gradll1 (*pp2, *pp1);
+    Vec3d gradll2 (*pp3, *pp1);
+    Vec3d gradll3 (*pp4, *pp1);
+    gradll1 *= 2;
+    gradll2 *= 2;
+    gradll3 *= 2;
+
+    Vec3d gradll (gradll1);
+    gradll += gradll2;
+    gradll += gradll3;
+
+    /*
+    Vec3d gradll;
+    gradll = v1+v2+v3;
+    gradll *= -2;
+    */
+
+    err = 0.0080187537 * lll / vol; 
+
+
+    gradll *= (0.0080187537 * 1.5 * l / vol);
+    Vec3d graderr(gradll);
+    gradvol *= ( -0.0080187537 * lll / (vol * vol) );
+    graderr += gradvol;
+  
+    if (h > 0)
+      {
+	/*
+	Vec3d gradll1 (*pp2, *pp1);
+	Vec3d gradll2 (*pp3, *pp1);
+	Vec3d gradll3 (*pp4, *pp1);
+	gradll1 *= 2;
+	gradll2 *= 2;
+	gradll3 *= 2;
+	*/
+	err += ll / (h*h) + 
+	  h*h * ( 1 / ll1 + 1 / ll2 + 1 / ll3 + 
+		  1 / ll4 + 1 / ll5 + 1 / ll6 ) - 12;
+
+	graderr += (1/(h*h) - h*h/(ll1*ll1)) * gradll1;
+	graderr += (1/(h*h) - h*h/(ll2*ll2)) * gradll2;
+	graderr += (1/(h*h) - h*h/(ll3*ll3)) * gradll3;
+      }
+
+    double errpow;
+
+    double teterrpow = mp.opterrpow;
+    if(teterrpow < 1) teterrpow = 1;
+
+    if (teterrpow == 1)
+    {
+       errpow = err;
+       grad = graderr;
+    }
+
+    if (teterrpow == 2)
+      {
+        errpow = err*err;   
+        grad = (2 * err) * graderr;
+      }
+
+    if(teterrpow > 2)
+      {
+        errpow = pow (err, teterrpow);
+        grad = (teterrpow * errpow / err) * graderr;
+      }
+    return errpow;
+  }
+  
+
+
+
+
+  /*
+
+  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;
+
+  // just for timing
+  // l += 1e-40 * CalcTetBadnessNew (p1, p2, p3, p4, h);
+
+  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) << setprecision(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)(0) << " "
+	 << mesh.Point(i)(1) << " "
+	 << mesh.Point(i)(2) << "\n";
+    
+    of << 2 * mesh.GetNSeg() << endl;
+    for (i = 1; i <= mesh.GetNSeg(); i++)
+      {
+	seg = &mesh.LineSegment(i);
+
+	of << (*seg)[1] << " " << (*seg)[0] << " " << 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)(0) << " "
+	      << mesh.Point(i)(1) << " "
+	      << mesh.Point(i)(2) << 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)[0] << " "
+	      << mesh2d.LineSegment(i)[1] << "  " << 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)(0) << " "
+	      << mesh.Point(i)(1) << " "
+	      << mesh.Point(i)(2) << 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 (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 domainnr)
+  {
+    int i, j, k;
+  
+    mesh.FindOpenElements(domainnr);
+    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++)
+    k = domainnr;
+      {
+	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/contrib/Netgen/libsrc/meshing/meshtool.hpp b/contrib/Netgen/libsrc/meshing/meshtool.hpp
new file mode 100644
index 0000000000..b6472ce080
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/meshtool.hpp
@@ -0,0 +1,81 @@
+#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,
+			      const MeshingParameters & mp);
+///
+extern double CalcTetBadnessGrad (const Point3d & p1, const Point3d & p2,
+				  const Point3d & p3, const Point3d & p4, 
+				  double h, int pi,
+				  Vec<3> & grad,
+				  const MeshingParameters & mp);
+
+
+/** 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, int domainnr);
+#endif
diff --git a/contrib/Netgen/libsrc/meshing/meshtype.cpp b/contrib/Netgen/libsrc/meshing/meshtype.cpp
new file mode 100644
index 0000000000..8bdbe8cb38
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/meshtype.cpp
@@ -0,0 +1,2680 @@
+#include <mystdlib.h>
+
+#include "meshing.hpp"  
+
+namespace netgen
+{
+  int MultiPointGeomInfo :: 
+  AddPointGeomInfo (const PointGeomInfo & gi)
+  {
+    for (int k = 0; k < cnt; k++)
+      if (mgi[k].trignum == gi.trignum)
+	return 0;
+  
+    if (cnt < MULTIPOINTGEOMINFO_MAX)
+      {
+	mgi[cnt] = gi;
+	cnt++;
+	return 0;
+      }
+
+    throw NgException ("Please report error: MPGI Size too small\n");
+  }
+  
+
+
+#ifdef PARALLEL
+  MPI_Datatype MeshPoint :: MyGetMPIType ( )
+  { 
+    static MPI_Datatype type = NULL;
+    static MPI_Datatype htype = NULL;
+    if (!type)
+      {
+	MeshPoint hp;
+	int blocklen[] = { 3, 1, 1 };
+	MPI_Aint displ[] = { (char*)&hp.x[0] - (char*)&hp,
+			     (char*)&hp.layer - (char*)&hp,
+			     (char*)&hp.singular - (char*)&hp };
+	MPI_Datatype types[] = { MPI_DOUBLE, MPI_INT, MPI_DOUBLE };
+	*testout << "displ = " << displ[0] << ", " << displ[1] << ", " << displ[2] << endl;
+	*testout << "sizeof = " << sizeof (MeshPoint) << endl;
+	MPI_Type_create_struct (3, blocklen, displ, types, &htype);
+	MPI_Type_commit ( &htype );
+	MPI_Aint lb, ext;
+	MPI_Type_get_extent (htype, &lb, &ext);
+	*testout << "lb = " << lb << endl;
+	*testout << "ext = " << ext << endl;
+	ext = sizeof (MeshPoint);
+	MPI_Type_create_resized (htype, lb, ext, &type);
+	MPI_Type_commit ( &type );
+	
+      }
+    return type;
+  }
+#endif
+
+
+
+
+  Segment :: Segment() 
+  {
+    pnums[0] = -1;
+    pnums[1] = -1; 
+    edgenr = -1;
+
+    singedge_left = 0.;
+    singedge_right = 0.;
+    seginfo = 0;
+
+    si = -1;
+
+    domin = -1;
+    domout = -1;
+    tlosurf = -1;
+
+    surfnr1 = -1;
+    surfnr2 = -1;
+    pnums[2] = -1;
+    meshdocval = 0;
+    /*
+      geominfo[0].trignum=-1; 
+      geominfo[1].trignum=-1; 
+
+      epgeominfo[0].edgenr = 1;
+      epgeominfo[0].dist = 0;
+      epgeominfo[1].edgenr = 1;
+      epgeominfo[1].dist = 0;
+    */
+
+    bcname = 0;
+  }    
+
+  Segment::Segment (const Segment & other)
+    :
+    edgenr(other.edgenr),
+    singedge_left(other.singedge_left),
+    singedge_right(other.singedge_right),
+    seginfo(other.seginfo),
+    si(other.si),
+    domin(other.domin),
+    domout(other.domout),
+    tlosurf(other.tlosurf),
+    geominfo(),
+    surfnr1(other.surfnr1),
+    surfnr2(other.surfnr2),
+    epgeominfo(),
+    meshdocval(other.meshdocval),
+    hp_elnr(other.hp_elnr)
+  {
+    for (int j = 0; j < 3; j++)
+      pnums[j] = other.pnums[j];
+
+    geominfo[0] = other.geominfo[0];
+    geominfo[1] = other.geominfo[1];
+    epgeominfo[0] = other.epgeominfo[0];
+    epgeominfo[1] = other.epgeominfo[1];
+    bcname = other.bcname;
+  }
+
+  Segment& Segment::operator=(const Segment & other)
+  {
+    if (&other != this)
+      {
+	pnums[0] = other[0];
+	pnums[1] = other[1];
+	edgenr = other.edgenr;
+	singedge_left = other.singedge_left;
+	singedge_right = other.singedge_right;
+	seginfo = other.seginfo;
+	si = other.si;
+	domin = other.domin;
+	domout = other.domout;
+	tlosurf = other.tlosurf;
+	geominfo[0] = other.geominfo[0];
+	geominfo[1] = other.geominfo[1];
+	surfnr1 = other.surfnr1;
+	surfnr2 = other.surfnr2;
+	epgeominfo[0] = other.epgeominfo[0];
+	epgeominfo[1] = other.epgeominfo[1];
+	pnums[2] = other.pnums[2];
+	meshdocval = other.meshdocval;
+	hp_elnr = other.hp_elnr;
+	bcname = other.bcname;
+      }
+    
+    return *this;
+  }
+
+
+  ostream & operator<<(ostream  & s, const Segment & seg)
+  {
+    s << seg[0] << "(gi=" << seg.geominfo[0].trignum << ") - "
+      << seg[1] << "(gi=" << seg.geominfo[1].trignum << ")"
+      << " domin = " << seg.domin << ", domout = " << seg.domout 
+      << " si = " << seg.si << ", edgenr = " << seg.edgenr;
+    return s;
+  }
+
+
+  Element2d :: Element2d ()
+  { 
+    for (int i = 0; i < ELEMENT2D_MAXPOINTS; i++)
+      {
+	pnum[i] = 0;
+	geominfo[i].trignum = 0;
+      }
+    np = 3;
+    index = 0;
+    badel = 0;
+    deleted = 0;
+    visible = 1;
+    typ = TRIG;
+    orderx = ordery = 1;
+    refflag = 1;
+    strongrefflag = false;
+#ifdef PARALLEL
+    isghost = 0;
+#endif
+  } 
+
+
+  Element2d :: Element2d (int anp)
+  { 
+    for (int i = 0; i < ELEMENT2D_MAXPOINTS; i++)
+      {
+	pnum[i] = 0;
+	geominfo[i].trignum = 0;
+      }
+    np = anp;
+    index = 0;
+    badel = 0;
+    deleted = 0;
+    visible = 1;
+    switch (np)
+      {
+      case 3: typ = TRIG; break;
+      case 4: typ = QUAD; break;
+      case 6: typ = TRIG6; break;
+      case 8: typ = QUAD8; break;
+      }
+    orderx = ordery = 1;
+    refflag = 1;
+    strongrefflag = false;
+#ifdef PARALLEL
+    isghost = 0;
+#endif
+  } 
+
+  Element2d :: Element2d (ELEMENT_TYPE atyp)
+  { 
+    for (int i = 0; i < ELEMENT2D_MAXPOINTS; i++)
+      {
+	pnum[i] = 0;
+	geominfo[i].trignum = 0;
+      }
+
+    SetType (atyp);
+
+    index = 0;
+    badel = 0;
+    deleted = 0;
+    visible = 1;
+    orderx = ordery = 1;
+    refflag = 1;
+    strongrefflag = false;
+#ifdef PARALLEL
+    isghost = 0;
+#endif
+
+  } 
+
+
+
+  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 < ELEMENT2D_MAXPOINTS; i++)
+      geominfo[i].trignum = 0;
+    index = 0;
+    badel = 0;
+    refflag = 1;
+    strongrefflag = false;
+    deleted = 0;
+    visible = 1;
+    orderx = ordery = 1;
+
+#ifdef PARALLEL
+    isghost = 0;
+#endif
+
+  }
+
+  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 < ELEMENT2D_MAXPOINTS; i++)
+      geominfo[i].trignum = 0;
+    index = 0;
+    badel = 0;
+    refflag = 1;
+    strongrefflag = false;
+    deleted = 0;
+    visible = 1;
+    orderx = ordery = 1;
+
+#ifdef PARALLEL
+    isghost = 0;
+#endif
+  }
+
+
+  /*
+    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]));
+  }
+
+  bool Element2d :: operator==(const Element2d & el2) const
+  {
+    bool retval = (el2.GetNP() == np);
+    for(int i= 0; retval && i<np; i++)
+      retval = (el2[i] == (*this)[i]);
+
+    return retval;
+  }
+
+
+  void Element2d :: Invert2()
+  {
+    switch (typ)
+      {
+      case TRIG:
+        {
+          Swap (pnum[1], pnum[2]);
+          break;
+        }
+      case TRIG6:
+        {
+          Swap (pnum[1], pnum[2]);
+          Swap (pnum[4], pnum[5]);
+          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)
+      {
+        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
+      {
+        int mini = 1;
+        for (int i = 2; i <= GetNP(); i++)
+          if (PNum(i) < PNum(mini)) mini = i;
+      
+        Element2d hel = (*this);
+        for (int 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();
+    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();
+
+#ifdef DEBUG
+    if (pmat.Width() != np || pmat.Height() != 2)
+      {
+        (*testout) << "GetTransofrmation: pmat doesn't fit" << endl;
+        return;
+      }
+#endif
+
+    ComputeIntegrationPointData ();
+    DenseMatrix * dshapep = NULL;
+    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(0) = 1 - p.X() - p.Y();
+        shape(1) = p.X();
+        shape(2) = p.Y();
+        break;
+      case QUAD:
+        shape(0) = (1-p.X()) * (1-p.Y());
+        shape(1) = p.X() * (1-p.Y());
+        shape(2) = p.X() * p.Y();
+        shape(3) = (1-p.X()) * p.Y();
+        break;
+      default:
+        PrintSysError ("Element2d::GetShape, illegal type ", typ);
+      }
+  }
+
+
+
+  void Element2d :: GetShapeNew (const Point<2> & p, FlatVector & shape) const
+  {
+    switch (typ)
+      {
+      case TRIG:
+        {
+          shape(0) = p(0);
+          shape(1) = p(1);
+          shape(2) = 1-p(0)-p(1);
+          break;
+        }
+
+      case QUAD:
+        {
+          shape(0) = (1-p(0))*(1-p(1));
+          shape(1) =    p(0) *(1-p(1));
+          shape(2) =    p(0) *   p(1) ;
+          shape(3) = (1-p(0))*   p(1) ;
+          break;
+        }
+      }
+  }
+
+
+
+
+
+
+
+
+
+  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 :: 
+  GetDShapeNew (const Point<2> & p, MatrixFixWidth<2> & dshape) const
+  {
+    switch (typ)
+      {
+      case TRIG:
+        {
+          dshape = 0;
+          dshape(0,0) = 1;
+          dshape(1,1) = 1;
+          dshape(2,0) = -1;
+          dshape(2,1) = -1;
+          break;
+        }
+      case QUAD:
+        {
+          dshape(0,0) = -(1-p(1));
+          dshape(0,1) = -(1-p(0));
+
+          dshape(1,0) =  (1-p(1));
+          dshape(1,1) =  -p(0);
+
+          dshape(2,0) = p(1);
+          dshape(2,1) = p(0);
+
+          dshape(3,0) = -p(1);
+          dshape(3,1) = (1-p(0));
+          break;
+        }
+      }
+  }
+
+
+
+
+
+  void Element2d :: 
+  GetPointMatrix (const Array<Point2d> & points,
+                  DenseMatrix & pmat) const
+  {
+    int np = GetNP();
+
+#ifdef DEBUG
+    if (pmat.Width() != np || pmat.Height() != 2)
+      {
+        cerr << "Element::GetPointMatrix: sizes don't fit" << endl;
+        return;
+      }
+#endif
+  
+    for (int 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();
+    DenseMatrix trans(2,2);
+    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;
+  }
+
+
+
+  static const int qip_table[4][4] =
+    { { 0, 1, 0, 3 },
+      { 0, 1, 1, 2 },
+      { 3, 2, 0, 3 },
+      { 3, 2, 1, 2 }
+    };
+
+  double Element2d :: 
+  CalcJacobianBadnessDirDeriv (const Array<Point2d> & points,
+                               int pi, Vec2d & dir, double & dd) const
+  {
+    if (typ == QUAD)
+      {
+        Mat<2,2> trans, dtrans;
+        Mat<2,4> vmat, pmat;
+      
+        for (int j = 0; j < 4; j++)
+          {
+            const Point2d & p = points.Get( (*this)[j] );
+            pmat(0, j) = p.X();
+            pmat(1, j) = p.Y();
+          }
+
+        vmat = 0.0;
+        vmat(0, pi-1) = dir.X();
+        vmat(1, pi-1) = dir.Y();
+      
+        double err = 0;
+        dd = 0;
+
+        for (int i = 0; i < 4; i++)
+          {
+            int ix1 = qip_table[i][0];
+            int ix2 = qip_table[i][1];
+            int iy1 = qip_table[i][2];
+            int iy2 = qip_table[i][3];
+	      
+            trans(0,0) = pmat(0, ix2) - pmat(0,ix1);
+            trans(1,0) = pmat(1, ix2) - pmat(1,ix1);
+            trans(0,1) = pmat(0, iy2) - pmat(0,iy1);
+            trans(1,1) = pmat(1, iy2) - pmat(1,iy1);
+
+            double det = trans(0,0)*trans(1,1)-trans(1,0)*trans(0,1);
+
+            if (det <= 0)
+              {
+                dd = 0;
+                return 1e12;
+              }
+	  
+            dtrans(0,0) = vmat(0, ix2) - vmat(0,ix1);
+            dtrans(1,0) = vmat(1, ix2) - vmat(1,ix1);
+            dtrans(0,1) = vmat(0, iy2) - vmat(0,iy1);
+            dtrans(1,1) = vmat(1, iy2) - vmat(1,iy1);
+
+
+            // Frobenius norm
+            double frob = 0;
+            for (int j = 0; j < 4; j++) 
+              frob += sqr (trans(j));
+            frob = sqrt (frob);
+	  
+            double dfrob = 0;
+            for (int j = 0; j < 4; j++)
+              dfrob += trans(j) * dtrans(j);
+            dfrob = dfrob / frob;
+	  
+            frob /= 2;      
+            dfrob /= 2;
+	  
+	  
+            // ddet = \sum_j det (m_j)   with m_j = trans, except col j = dtrans
+            double ddet 
+              = dtrans(0,0) * trans(1,1) - trans(0,1) * dtrans(1,0)
+              + trans(0,0) * dtrans(1,1) - dtrans(0,1) * trans(1,0);
+	  
+            err += frob * frob / det;
+            dd += (2 * frob * dfrob * det - frob * frob * ddet) / (det * det);
+          }
+      
+        err /= 4;
+        dd /= 4;
+        return err;
+      }
+
+    int nip = GetNIP();
+    DenseMatrix trans(2,2), dtrans(2,2);
+    DenseMatrix pmat, vmat;
+  
+    pmat.SetSize (2, GetNP());
+    vmat.SetSize (2, GetNP());
+
+    GetPointMatrix (points, pmat);
+  
+    vmat = 0.0;
+    vmat.Elem(1, pi) = dir.X();
+    vmat.Elem(2, pi) = dir.Y();
+
+
+    double err = 0;
+    dd = 0;
+
+    for (int i = 1; i <= nip; i++)
+      {
+        GetTransformation (i, pmat, trans);
+        GetTransformation (i, vmat, dtrans);
+
+        // Frobenius norm
+        double frob = 0;
+        for (int j = 1; j <= 4; j++)
+          frob += sqr (trans.Get(j));
+        frob = sqrt (frob);
+      
+        double dfrob = 0;
+        for (int j = 1; j <= 4; j++)
+          dfrob += trans.Get(j) * dtrans.Get(j);
+        dfrob = dfrob / frob;
+      
+        frob /= 2;      
+        dfrob /= 2;
+      
+        double det = trans(0,0)*trans(1,1)-trans(1,0)*trans(0,1);
+
+        // ddet = \sum_j det (m_j)   with m_j = trans, except col j = dtrans
+        double ddet 
+          = dtrans(0,0) * trans(1,1) - trans(0,1) * dtrans(1,0)
+          + trans(0,0) * dtrans(1,1) - dtrans(0,1) * trans(1,0);
+
+        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 Vec<3> & n) const
+  {
+    int i, j;
+    int nip = GetNIP();
+    DenseMatrix trans(2,2);
+    DenseMatrix pmat;
+  
+    pmat.SetSize (2, GetNP());
+
+    Vec<3> t1, t2;
+    t1 = n.GetNormal();
+    t2 = Cross (n, t1);
+
+    for (i = 1; i <= GetNP(); i++)
+      {
+        Point3d p = points.Get(PNum(i));
+        pmat.Elem(1, i) = p.X() * t1(0) + p.Y() * t1(1) + p.Z() * t1(2);
+        pmat.Elem(2, i) = p.X() * t2(0) + p.Y() * t2(1) + p.Z() * t2(2);
+      }
+
+    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;
+      }
+
+    for (int i = 1; i <= GetNIP(); i++)
+      {
+        IntegrationPointData * ipd = new IntegrationPointData;
+        Point2d hp;
+        GetIntegrationPoint (i, hp, ipd->weight);
+        ipd->p(0) = hp.X();
+        ipd->p(1) = hp.Y();
+        ipd->p(2) = 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.badness_valid = 0;
+    flags.refflag = 1;
+    flags.strongrefflag = false;
+    flags.deleted = 0;
+    flags.fixed = 0;
+    orderx = ordery = orderz = 1;
+
+#ifdef PARALLEL
+    partitionNumber = -1;
+    isghost = 0;
+#endif
+
+  }
+
+
+  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.badness_valid = 0;
+    flags.refflag = 1;
+    flags.strongrefflag = false;
+    flags.deleted = 0;
+    flags.fixed = 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;
+      }
+    orderx = ordery = orderz = 1;
+
+#ifdef PARALLEL
+    isghost = 0;
+#endif
+  }
+
+  void Element :: SetOrder (const int aorder) 
+  { 
+    orderx = aorder; 
+    ordery = aorder; 
+    orderz = aorder;
+  }
+
+
+  void Element :: SetOrder (const int ox, const int oy, const int oz) 
+  { 
+    orderx = ox; 
+    ordery = oy;
+    orderz = oz; 
+  }
+
+
+  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.badness_valid = 0;
+    flags.refflag = 1;
+    flags.strongrefflag = false;
+    flags.deleted = 0;
+    flags.fixed = 0;
+    orderx = ordery = orderz = 1;
+
+#ifdef PARALLEL
+    isghost = 0;
+#endif
+  }
+
+
+
+
+
+  Element & Element :: operator= (const Element & el2)
+  {
+    typ = el2.typ;
+    np = el2.np;
+    for (int i = 0; i < ELEMENT_MAXPOINTS; i++)
+      pnum[i] = el2.pnum[i];
+    index = el2.index;
+    flags = el2.flags;
+    orderx = el2.orderx;
+    ordery = el2.ordery;
+    orderz = el2.orderz;
+    hp_elnr = el2.hp_elnr;
+    flags = el2.flags;
+    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;
+
+      default: break;
+        cerr << "Element::SetType unknown type  " << int(typ) << endl;
+      }
+  }
+
+
+
+  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
+  {
+    Vec<3> v1 = points.Get(PNum(2)) - points.Get(PNum(1));
+    Vec<3> v2 = points.Get(PNum(3)) - points.Get(PNum(1));
+    Vec<3> 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 tet10faces[][7] = 
+      { { 3, 2, 3, 4, 10, 9, 8 },
+        { 3, 3, 1, 4, 7, 10, 6 },
+        { 3, 1, 2, 4, 9, 7, 5 },
+        { 3, 2, 1, 3, 6, 8, 5 } };
+
+    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
+        {
+          face.SetType(TRIG);
+          for (int j = 1; j <= 3; j++)
+            face.PNum(j) = PNum(tetfaces[i-1][j]);
+          break;
+        }
+
+      case 10: // tet10
+        {
+          face.SetType(TRIG6);
+          for (int j = 1; j <= 6; j++)
+            face.PNum(j) = PNum(tet10faces[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;
+        }
+      }
+  }
+
+  bool Element :: operator==(const Element & el2) const
+  {
+    bool retval = (el2.GetNP() == np);
+    for(int i= 0; retval && i<np; i++)
+      retval = (el2[i] == (*this)[i]);
+
+    return retval;
+  }
+
+
+#ifdef OLD
+  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 },
+        { 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]));
+  }
+#endif
+
+
+
+
+
+
+  void Element :: GetNodesLocalNew (Array<Point<3> > & 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;
+	  pp = NULL;
+        }
+      }
+  
+    points.SetSize(0);
+    for (i = 0; i < np; i++)
+      points.Append (Point<3> (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 } };
+
+    static int tet10trigs[][3] = 
+      { { 2, 8, 9 }, { 3, 10, 8}, { 4, 9, 10 }, { 9, 8, 10 },
+        { 3, 6, 10 }, { 1, 7, 6 }, { 4, 10, 7 }, { 6, 7, 10 },
+        { 1, 5, 7 }, { 2, 9, 5 }, { 4, 7, 9 }, { 5, 9, 7 },
+        { 1, 6, 5 }, { 2, 5, 8 }, { 3, 8, 6 }, { 5, 6, 8 }
+      };
+
+    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 = 16;
+          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(TRIG);
+        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< AutoPtr < IntegrationPointData > > ipdtet;
+  Array< AutoPtr < 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, Point<3> & 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 = NULL;
+    switch (typ)
+      {
+      case TET: pp = &eltetqp[0][0]; break;
+      case TET10: pp = &eltet10qp[ip-1][0]; break;
+      }
+
+    p(0) = pp[0];
+    p(1) = pp[1];
+    p(2) = pp[2];
+    weight = pp[3];
+  }
+
+  void Element :: 
+  GetTransformation (int ip, const T_POINTS & points,
+                     DenseMatrix & trans) const
+  {
+    int np = GetNP();
+    DenseMatrix pmat(3, np), dshape(3, np);
+    pmat.SetSize (3, np);
+    dshape.SetSize (3, np);
+
+    Point<3> 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 = 0;
+    switch (GetType())
+      {
+      case TET: dshapep = &ipdtet.Get(ip)->dshape; break;
+      case TET10: dshapep = &ipdtet10.Get(ip)->dshape; break;
+      default:
+        PrintSysError ("Element::GetTransformation, illegal type ", int(typ));
+      }
+  
+    CalcABt (pmat, *dshapep, trans);
+  }
+
+
+  void Element :: GetShape (const Point<3> & hp, Vector & shape) const
+  {
+    Point3d p = hp;
+
+    if (shape.Size() != GetNP())
+      {
+        cerr << "Element::GetShape: Length not fitting" << endl;
+        return;
+      }
+
+    switch (typ)
+      {
+      case TET:
+        {
+          shape(0) = 1 - p.X() - p.Y() - p.Z(); 
+          shape(1) = p.X();
+          shape(2) = p.Y();
+          shape(3) = 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(4) = 4 * lam1 * lam2;
+          shape(5) = 4 * lam1 * lam3;
+          shape(6) = 4 * lam1 * lam4;
+          shape(7) = 4 * lam2 * lam3;
+          shape(8) = 4 * lam2 * lam4;
+          shape(9) = 4 * lam3 * lam4;
+	
+          shape(0) = lam1 - 0.5 * (shape(4) + shape(5) + shape(6));
+          shape(1) = lam2 - 0.5 * (shape(4) + shape(7) + shape(8));
+          shape(2) = lam3 - 0.5 * (shape(5) + shape(7) + shape(9));
+          shape(3) = lam4 - 0.5 * (shape(6) + shape(8) + shape(9));
+          break;
+        }
+
+      case PRISM:
+        {
+          Point<3> hp = p; 
+          shape(0) = hp(0) * (1-hp(2));
+          shape(1) = hp(1) * (1-hp(2));
+          shape(2) = (1-hp(0)-hp(1)) * (1-hp(2));
+          shape(3) = hp(0) * hp(2);
+          shape(4) = hp(1) * hp(2);
+          shape(5) = (1-hp(0)-hp(1)) * hp(2);
+          break;
+        }
+      case HEX:
+        {
+          Point<3> hp = p; 
+          shape(0) = (1-hp(0))*(1-hp(1))*(1-hp(2));
+          shape(1) = (  hp(0))*(1-hp(1))*(1-hp(2));
+          shape(2) = (  hp(0))*(  hp(1))*(1-hp(2));
+          shape(3) = (1-hp(0))*(  hp(1))*(1-hp(2));
+          shape(4) = (1-hp(0))*(1-hp(1))*(  hp(2));
+          shape(5) = (  hp(0))*(1-hp(1))*(  hp(2));
+          shape(6) = (  hp(0))*(  hp(1))*(  hp(2));
+          shape(7) = (1-hp(0))*(  hp(1))*(  hp(2));
+          break;
+        }
+      }
+  }
+
+
+
+  void Element :: GetShapeNew (const Point<3> & p, FlatVector & shape) const
+  {
+    /*
+      if (shape.Size() < GetNP())
+      {
+      cerr << "Element::GetShape: Length not fitting" << endl;
+      return;
+      }
+    */
+
+    switch (typ)
+      {
+      case TET:
+        {
+          shape(0) = p(0);
+          shape(1) = p(1);
+          shape(2) = p(2);
+          shape(3) = 1-p(0)-p(1)-p(2);
+          break;
+        }
+
+      case TET10:
+        {
+          double lam1 = p(0);
+          double lam2 = p(1);
+          double lam3 = p(2);
+          double lam4 = 1-p(0)-p(1)-p(2);
+	
+          shape(0) = 2 * lam1 * (lam1-0.5);
+          shape(1) = 2 * lam2 * (lam2-0.5);
+          shape(2) = 2 * lam3 * (lam3-0.5);
+          shape(3) = 2 * lam4 * (lam4-0.5);
+
+          shape(4) = 4 * lam1 * lam2;
+          shape(5) = 4 * lam1 * lam3;
+          shape(6) = 4 * lam1 * lam4;
+          shape(7) = 4 * lam2 * lam3;
+          shape(8) = 4 * lam2 * lam4;
+          shape(9) = 4 * lam3 * lam4;
+	
+          break;
+        }
+
+
+      case PYRAMID:
+        {
+          double noz = 1-p(2);
+          if (noz == 0.0) noz = 1e-10;
+
+          double xi  = p(0) / noz;
+          double eta = p(1) / noz;
+          shape(0) = (1-xi)*(1-eta) * (noz);
+          shape(1) = (  xi)*(1-eta) * (noz);
+          shape(2) = (  xi)*(  eta) * (noz);
+          shape(3) = (1-xi)*(  eta) * (noz);
+          shape(4) = p(2);
+          break;
+        }
+
+      case PRISM:
+        {
+          shape(0) = p(0) * (1-p(2));
+          shape(1) = p(1) * (1-p(2));
+          shape(2) = (1-p(0)-p(1)) * (1-p(2));
+          shape(3) = p(0) * p(2);
+          shape(4) = p(1) * p(2);
+          shape(5) = (1-p(0)-p(1)) * p(2);
+          break;
+        }
+      case HEX:
+        {
+          shape(0) = (1-p(0))*(1-p(1))*(1-p(2));
+          shape(1) = (  p(0))*(1-p(1))*(1-p(2));
+          shape(2) = (  p(0))*(  p(1))*(1-p(2));
+          shape(3) = (1-p(0))*(  p(1))*(1-p(2));
+          shape(4) = (1-p(0))*(1-p(1))*(  p(2));
+          shape(5) = (  p(0))*(1-p(1))*(  p(2));
+          shape(6) = (  p(0))*(  p(1))*(  p(2));
+          shape(7) = (1-p(0))*(  p(1))*(  p(2));
+          break;
+        }
+      }
+  }
+
+
+
+  void Element :: 
+  GetDShape (const Point<3> & hp, DenseMatrix & dshape) const
+  {
+    Point3d p = hp;
+
+    int np = GetNP();
+    if (dshape.Height() != 3 || dshape.Width() != np)
+      {
+        cerr << "Element::DShape: Sizes don't fit" << endl;
+        return;
+      }
+
+    double eps = 1e-6;
+    Vector shaper(np), shapel(np);
+
+    for (int 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 (int j = 0; j < np; j++)
+          dshape(i-1, j) = (shaper(j) - shapel(j)) / (2 * eps);
+      }
+  }
+
+
+  void Element :: 
+  GetDShapeNew (const Point<3> & p, MatrixFixWidth<3> & dshape) const
+  {
+    switch (typ)
+      {
+      case TET:
+        {
+          dshape = 0;
+          dshape(0,0) = 1;
+          dshape(1,1) = 1;
+          dshape(2,2) = 1;
+          dshape(3,0) = -1;
+          dshape(3,1) = -1;
+          dshape(3,2) = -1;
+          break;
+        }
+      case PRISM:
+        {
+          dshape = 0;
+          dshape(0,0) = 1-p(2);
+          dshape(0,2) = -p(0);
+          dshape(1,1) = 1-p(2);
+          dshape(1,2) = -p(1);
+          dshape(2,0) = -(1-p(2));
+          dshape(2,1) = -(1-p(2));
+          dshape(2,2) = -(1-p(0)-p(1));
+
+          dshape(3,0) = p(2);
+          dshape(3,2) = p(0);
+          dshape(4,1) = p(2);
+          dshape(4,2) = p(1);
+          dshape(5,0) = -p(2);
+          dshape(5,1) = -p(2);
+          dshape(5,2) = 1-p(0)-p(1);
+          break;
+        }
+
+      default:
+        {
+          int np = GetNP();
+          double eps = 1e-6;
+          Vector shaper(np), shapel(np);
+	
+          for (int i = 1; i <= 3; i++)
+            {
+              Point3d pr(p), pl(p);
+              pr.X(i) += eps;
+              pl.X(i) -= eps;
+	    
+              GetShapeNew (pr, shaper);
+              GetShapeNew (pl, shapel);
+              for (int j = 0; j < np; j++)
+                dshape(j, i-1) = (shaper(j) - shapel(j)) / (2 * eps);
+            }
+        }
+      }
+  }
+
+  void Element :: 
+  GetPointMatrix (const T_POINTS & points,
+                  DenseMatrix & pmat) const
+  {
+    int np = GetNP();
+    for (int 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 nip = GetNIP();
+    DenseMatrix trans(3,3);
+    DenseMatrix pmat;
+  
+    pmat.SetSize (3, GetNP());
+    GetPointMatrix (points, pmat);
+
+    double err = 0;
+    for (int i = 1; i <= nip; i++)
+      {
+        GetTransformation (i, pmat, trans);
+
+        // Frobenius norm
+        double frob = 0;
+        for (int 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, Vec<3> & dir, double & dd) const
+  {
+    int i, j, k;
+    int nip = GetNIP();
+    DenseMatrix trans(3,3), dtrans(3,3), hmat(3,3);
+    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(j-1);
+
+
+
+    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;
+  }
+
+  double Element :: 
+  CalcJacobianBadnessGradient (const T_POINTS & points,
+                               int pi, Vec<3> & grad) const
+  {
+    int nip = GetNIP();
+    DenseMatrix trans(3,3), dtrans(3,3), hmat(3,3);
+    DenseMatrix pmat, vmat;
+  
+    pmat.SetSize (3, GetNP());
+    vmat.SetSize (3, GetNP());
+
+    GetPointMatrix (points, pmat);
+  
+    for (int i = 1; i <= np; i++)
+      for (int j = 1; j <= 3; j++)
+        vmat.Elem(j, i) = 0;
+    for (int j = 1; j <= 3; j++)
+      vmat.Elem(j, pi) = 1.;
+
+
+    double err = 0;
+
+    double dfrob[3];
+
+    grad = 0;
+
+    for (int i = 1; i <= nip; i++)
+      {
+        GetTransformation (i, pmat, trans);
+        GetTransformation (i, vmat, dtrans);
+ 
+        // Frobenius norm
+        double frob = 0;
+        for (int j = 1; j <= 9; j++)
+          frob += sqr (trans.Get(j));
+        frob = sqrt (frob);
+
+        for(int k = 0; k<3; k++)
+          {
+            dfrob[k] = 0;
+            for (int j = 1; j <= 3; j++)
+              dfrob[k] += trans.Get(k+1,j) * dtrans.Get(k+1,j);
+            dfrob[k] = dfrob[k] / (3.*frob);
+          }
+
+        frob /= 3;      
+
+        double det = trans.Det();
+        double ddet[3]; // = 0;
+      
+        for(int k=1; k<=3; k++)
+          {
+            int km1 = (k > 1) ? (k-1) : 3;
+            int kp1 = (k < 3) ? (k+1) : 1;
+            ddet[k-1] = 0;
+            for(int j=1; j<=3; j++)
+              {
+                int jm1 = (j > 1) ? (j-1) : 3;
+                int jp1 = (j < 3) ? (j+1) : 1;
+	      
+                ddet[k-1] += (-1.)* dtrans.Get(k,j) * ( trans.Get(km1,jm1)*trans.Get(kp1,jp1) - 
+                                                        trans.Get(km1,jp1)*trans.Get(kp1,jm1) );
+              }
+          }
+
+      
+        det *= -1;
+      
+        if (det <= 0)
+          err += 1e12;
+        else
+          {
+            err += frob * frob * frob / det;
+            double fac = (frob * frob)/(det * det);
+            for(int j=0; j<3; j++)
+              grad(j) += fac * (3 * dfrob[j] * det - frob * ddet[j]);
+          }
+      }
+
+    err /= nip;
+    grad *= 1./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));
+      }
+
+    switch (GetType())
+      {
+      case TET: ipdtet.SetSize(GetNIP()); break;
+      case TET10: ipdtet10.SetSize(GetNIP()); break;
+      default:
+        PrintSysError ("Element::ComputeIntegrationPoint, illegal type2 ", int(typ));
+      }
+
+
+    for (int 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.Elem(i).Reset(ipd); break;
+          case TET10: ipdtet10.Elem(i).Reset(ipd); break;
+          default:
+            PrintSysError ("Element::ComputeIntegrationPoint(2), illegal type ", int(typ));
+          }
+      }
+  }
+
+
+
+
+
+
+
+  FaceDescriptor ::  FaceDescriptor()
+  { 
+    surfnr = domin = domout  = bcprop = 0; 
+    domin_singular = domout_singular = 0.;
+    // Philippose - 06/07/2009
+    // Initialise surface colour
+    surfcolour = Vec3d(0.0,1.0,0.0);
+    tlosurf = -1; 
+    bcname = 0;
+    firstelement = -1;
+  }
+
+  FaceDescriptor ::  FaceDescriptor(const FaceDescriptor& other)
+    : surfnr(other.surfnr), domin(other.domin), domout(other.domout),
+      tlosurf(other.tlosurf), bcprop(other.bcprop), 
+      surfcolour(other.surfcolour), bcname(other.bcname),
+      domin_singular(other.domin_singular), domout_singular(other.domout_singular)
+  { 
+    firstelement = -1;
+  }
+
+  FaceDescriptor :: 
+  FaceDescriptor(int surfnri, int domini, int domouti, int tlosurfi)
+  { 
+    surfnr = surfnri; 
+    domin = domini; 
+    domout = domouti;
+    // Philippose - 06/07/2009
+    // Initialise surface colour
+    surfcolour = Vec3d(0.0,1.0,0.0);
+    tlosurf = tlosurfi; 
+    bcprop = surfnri;
+    domin_singular = domout_singular = 0.;
+    bcname = 0;
+    firstelement = -1;
+  }
+
+  FaceDescriptor :: FaceDescriptor(const Segment & seg)
+  { 
+    surfnr = seg.si; 
+    domin = seg.domin+1;
+    domout = seg.domout+1;
+    // Philippose - 06/07/2009
+    // Initialise surface colour
+    surfcolour = Vec3d(0.0,1.0,0.0);
+    tlosurf = seg.tlosurf+1;
+    bcprop = 0;
+    domin_singular = domout_singular = 0.;
+    bcname = 0;
+    firstelement = -1;
+  }
+
+  int FaceDescriptor ::  SegmentFits (const Segment & seg)
+  {
+    return
+      surfnr == seg.si &&
+      domin == seg.domin+1 &&
+      domout == seg.domout+1  &&
+      tlosurf == seg.tlosurf+1;
+  }
+
+
+  string FaceDescriptor :: GetBCName () const
+  {
+    if ( bcname )
+      return *bcname;
+    else 
+      return "default";
+  
+  }
+
+  /*
+    void FaceDescriptor :: SetBCName (string * bcn)
+    {
+    bcname = bcn;
+    }
+  */
+
+
+  ostream & operator<<(ostream  & s, const FaceDescriptor & fd)
+  {
+    s << "surfnr = " << fd.SurfNr() 
+      << ", domin = " << fd.DomainIn()
+      << ", domout = " << fd.DomainOut()
+      << ", tlosurf = " << fd.TLOSurface()
+      << ", bcprop = " << fd.BCProperty()
+      << ", domin_sing = " << fd.DomainInSingular()
+      << ", domout_sing = " << fd.DomainOutSingular()
+      << ", colour = " << fd.SurfColour();
+    return s;
+  }
+
+
+
+
+
+
+  Identifications :: Identifications (Mesh & amesh)
+    : mesh(amesh)
+  {
+    identifiedpoints = new INDEX_2_HASHTABLE<int>(100);
+    identifiedpoints_nr = new INDEX_3_HASHTABLE<int>(100);
+    maxidentnr = 0;
+  }
+
+  Identifications :: ~Identifications ()
+  {
+    delete identifiedpoints;
+    delete identifiedpoints_nr;
+  }
+
+  void Identifications :: Delete ()
+  {
+    delete identifiedpoints;
+    identifiedpoints = new INDEX_2_HASHTABLE<int>(100);
+    delete identifiedpoints_nr;
+    identifiedpoints_nr = new INDEX_3_HASHTABLE<int>(100);
+    maxidentnr = 0;
+  }
+
+  void Identifications :: Add (PointIndex pi1, PointIndex pi2, int identnr)
+  {
+    //  (*testout) << "Identification::Add, pi1 = " << pi1 << ", pi2 = " << pi2 << ", identnr = " << identnr << endl;
+    INDEX_2 pair (pi1, pi2);
+    identifiedpoints->Set (pair, identnr);
+
+    INDEX_3 tripl (pi1, pi2, identnr);
+    identifiedpoints_nr->Set (tripl, 1);
+
+    if (identnr > maxidentnr) maxidentnr = identnr;
+
+    if (identnr+1 > idpoints_table.Size())
+      idpoints_table.ChangeSize (identnr+1);
+    idpoints_table.Add (identnr, pair);
+  
+    //  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;
+  }
+
+  bool Identifications :: Get (PointIndex pi1, PointIndex pi2, int nr) const
+  {
+    INDEX_3 tripl(pi1, pi2, nr);
+    if (identifiedpoints_nr->Used (tripl))
+      return 1;
+    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, bool symmetric) const
+  {
+    identmap.SetSize (mesh.GetNP());
+    identmap = 0;
+
+    if (identnr)
+      for (int i = 0; i < idpoints_table[identnr].Size(); i++)
+        {
+          INDEX_2 pair = idpoints_table[identnr][i];
+          identmap[pair.I1()] = pair.I2();
+          if(symmetric)
+            identmap[pair.I2()] = pair.I1();
+        }
+
+    else
+      {
+        cout << "getmap, identnr = " << identnr << endl;
+
+        for (int i = 1; i <= identifiedpoints_nr->GetNBags(); i++)
+          for (int j = 1; j <= identifiedpoints_nr->GetBagSize(i); j++)
+            {
+              INDEX_3 i3;
+              int dummy;
+              identifiedpoints_nr->GetData (i, j, i3, dummy);
+	    
+              if (i3.I3() == identnr || !identnr)
+                {
+                  identmap.Elem(i3.I1()) = i3.I2();
+                  if(symmetric)
+                    identmap.Elem(i3.I2()) = i3.I1();
+                }
+            }  
+      }
+
+  }
+
+
+  void Identifications :: GetPairs (int identnr, 
+                                    Array<INDEX_2> & identpairs) const
+  {
+    identpairs.SetSize(0);
+  
+    if (identnr == 0)
+      for (int i = 1; i <= identifiedpoints->GetNBags(); i++)
+        for (int j = 1; j <= identifiedpoints->GetBagSize(i); j++)
+          {
+            INDEX_2 i2;
+            int nr;
+            identifiedpoints->GetData (i, j, i2, nr);
+            identpairs.Append (i2);
+          }  
+    else
+      for (int i = 1; i <= identifiedpoints_nr->GetNBags(); i++)
+        for (int j = 1; j <= identifiedpoints_nr->GetBagSize(i); j++)
+          {
+            INDEX_3 i3;
+            int dummy;
+            identifiedpoints_nr->GetData (i, j, i3 , dummy);
+	  
+            if (i3.I3() == identnr)
+              identpairs.Append (INDEX_2(i3.I1(), i3.I2()));
+          }  
+  }
+
+
+  void Identifications :: SetMaxPointNr (int maxpnum)
+  {
+    for (int i = 1; i <= identifiedpoints->GetNBags(); i++)
+      for (int j = 1; j <= identifiedpoints->GetBagSize(i); j++)
+        {
+          INDEX_2 i2;
+          int nr;
+          identifiedpoints->GetData (i, j, i2, nr);
+	
+          if (i2.I1() > maxpnum || i2.I2() > maxpnum)
+            {
+              i2.I1() = i2.I2() = -1;
+              identifiedpoints->SetData (i, j, i2, -1);	    
+            }
+        }
+  }
+
+
+  void Identifications :: Print (ostream & ost) const
+  {
+    ost << "Identifications:" << endl;
+    ost << "pairs: " << endl << *identifiedpoints << endl;
+    ost << "pairs and nr: " << endl << *identifiedpoints_nr << endl;
+    ost << "table: " << endl << idpoints_table << endl;
+  }
+
+
+  MeshingParameters :: MeshingParameters ()
+  {
+    optimize3d = "cmdmustm";
+    //optimize3d = "cmdmstm";
+    optsteps3d = 3;
+    optimize2d = "smsmsmSmSmSm";
+    optsteps2d = 3;
+    opterrpow = 2;
+    blockfill = 1;
+    filldist = 0.1;
+    safety = 5;
+    relinnersafety = 3;
+    uselocalh = 1;
+    grading = 0.3;
+    delaunay = 1;
+    maxh = 1e10;
+    minh = 0;
+    meshsizefilename = NULL;
+    startinsurface = 0;
+    checkoverlap = 1;
+    checkoverlappingboundary = 1;
+    checkchartboundary = 1;
+    curvaturesafety = 2;
+    segmentsperedge = 1;
+    parthread = 0;
+
+    elsizeweight = 0.2;
+    giveuptol2d = 200;
+    giveuptol = 10;
+    maxoutersteps = 10;
+    starshapeclass = 5;
+    baseelnp = 0;
+    sloppy = 1;
+
+    badellimit = 175;
+    check_impossible = 0;
+    secondorder = 0;
+  }
+
+  void MeshingParameters :: Print (ostream & ost) const
+  {
+    ost << "Meshing parameters: " << endl
+        << "optimize3d = " << optimize3d << endl
+        << "optsteps3d = " << optsteps3d << endl
+        << " optimize2d = " <<  optimize2d << endl
+        << " optsteps2d = " <<  optsteps2d << endl
+        << " opterrpow = " <<  opterrpow << endl
+        << " blockfill = " <<  blockfill << endl
+        << " filldist = " <<  filldist << endl
+        << " safety = " <<  safety << endl
+        << " relinnersafety = " <<  relinnersafety << endl
+        << " uselocalh = " <<  uselocalh << endl
+        << " grading = " <<  grading << endl
+        << " delaunay = " <<  delaunay << endl
+        << " maxh = " <<  maxh << endl;
+    if(meshsizefilename)
+      ost << " meshsizefilename = " <<  meshsizefilename << endl;
+    else
+      ost << " meshsizefilename = NULL" << endl;
+    ost << " startinsurface = " <<  startinsurface << endl
+        << " checkoverlap = " <<  checkoverlap << endl
+        << " checkchartboundary = " <<  checkchartboundary << endl
+        << " curvaturesafety = " <<  curvaturesafety << endl
+        << " segmentsperedge = " <<  segmentsperedge << endl
+        << " parthread = " <<  parthread << endl
+        << " elsizeweight = " <<  elsizeweight << endl
+        << " giveuptol2d = " <<  giveuptol2d << endl
+        << " giveuptol = " <<  giveuptol << endl
+        << " maxoutersteps = " <<  maxoutersteps << endl
+        << " starshapeclass = " <<  starshapeclass << endl
+        << " baseelnp        = " <<  baseelnp        << endl
+        << " sloppy = " <<  sloppy << endl
+        << " badellimit = " <<  badellimit << endl
+        << " secondorder = " <<  secondorder << endl
+        << " elementorder = " <<  elementorder << endl
+        << " quad = " <<  quad << endl
+        << " inverttets = " <<  inverttets << endl
+        << " inverttrigs = " <<  inverttrigs << endl;
+  }
+
+  void MeshingParameters :: CopyFrom(const MeshingParameters & other)
+  {
+    //strcpy(optimize3d,other.optimize3d); 
+    optimize3d = other.optimize3d;
+    optsteps3d = other.optsteps3d;
+    //strcpy(optimize2d,other.optimize2d); 
+    optimize2d = other.optimize2d;
+    optsteps2d = other.optsteps2d;
+    opterrpow = other.opterrpow;
+    blockfill = other.blockfill;
+    filldist = other.filldist;
+    safety = other.safety;
+    relinnersafety = other.relinnersafety;
+    uselocalh = other.uselocalh;
+    grading = other.grading;
+    delaunay = other.delaunay;
+    maxh = other.maxh;
+    //strcpy(const_cast<char*>(meshsizefilename), other.meshsizefilename);
+    //const_cast<char*>(meshsizefilename) = other.meshsizefilename; //???
+    startinsurface = other.startinsurface;
+    checkoverlap = other.checkoverlap;
+    checkoverlappingboundary = other.checkoverlappingboundary;
+    checkchartboundary = other.checkchartboundary;
+    curvaturesafety = other.curvaturesafety;
+    segmentsperedge = other.segmentsperedge;
+    parthread = other.parthread;
+    elsizeweight = other.elsizeweight;
+    giveuptol2d = other.giveuptol2d;
+    giveuptol = other.giveuptol;
+    maxoutersteps = other.maxoutersteps;
+    starshapeclass = other.starshapeclass;
+    baseelnp = other.baseelnp;       
+    sloppy = other.sloppy;
+    badellimit = other.badellimit;
+    secondorder = other.secondorder;
+    elementorder = other.elementorder;
+    quad = other.quad;
+    inverttets = other.inverttets;
+    inverttrigs = other.inverttrigs;
+  }
+
+
+  DebugParameters :: DebugParameters ()
+  {
+    slowchecks = 0;
+    haltsuccess = 0;
+    haltnosuccess = 0;
+    haltlargequalclass = 0;
+    haltsegment = 0;
+    haltsegmentp1 = 0;
+    haltsegmentp2 = 0;
+  };
+
+
+
+}
+
diff --git a/contrib/Netgen/libsrc/meshing/meshtype.hpp b/contrib/Netgen/libsrc/meshing/meshtype.hpp
new file mode 100644
index 0000000000..c7b3609ded
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/meshtype.hpp
@@ -0,0 +1,1306 @@
+#ifndef MESHTYPE
+#define MESHTYPE
+
+
+/**************************************************************************/
+/* File:   meshtype.hpp                                                   */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   01. Okt. 95                                                    */
+/**************************************************************************/
+
+namespace netgen
+{
+
+  /*
+    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 8
+
+
+  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 };
+
+
+
+  extern DLL_HEADER int GetTimeStamp();
+  extern DLL_HEADER int NextTimeStamp();
+
+  class PointGeomInfo
+  {
+  public:
+    int trignum;   // for STL Meshing
+    double u, v;   // for OCC Meshing
+
+    PointGeomInfo () 
+      : trignum(-1), u(0), v(0) { ; }
+  };
+
+  inline ostream & operator<< (ostream & ost, const PointGeomInfo & gi)
+  {
+    return (ost << gi.trignum << " " << gi.u << " " << gi.v);
+  }
+
+  inline istream & operator>> (istream & ist, PointGeomInfo & gi)
+  {
+    return (ist >> gi.trignum >> gi.u >> gi.v);
+  }
+
+
+
+#define MULTIPOINTGEOMINFO_MAX 100
+  class MultiPointGeomInfo
+  {
+    int cnt;
+    PointGeomInfo mgi[MULTIPOINTGEOMINFO_MAX];
+  public:
+    MultiPointGeomInfo () { cnt = 0; }
+    int AddPointGeomInfo (const PointGeomInfo & gi);
+    void Init () { cnt = 0; }
+    void DeleteAll () { cnt = 0; }
+
+    int GetNPGI () const { return cnt; }
+    const PointGeomInfo & GetPGI (int i) const { return mgi[i-1]; }
+  };
+
+
+  class EdgePointGeomInfo
+  {
+  public:
+    int edgenr;
+    int body;    // for ACIS
+    double dist; // for 2d meshing
+    double u, v; // for OCC Meshing
+
+  public:
+    EdgePointGeomInfo ()
+      : edgenr(0), body(0), dist(0.0), u(0.0), v(0.0) { ; }
+
+
+    EdgePointGeomInfo & operator= (const EdgePointGeomInfo & gi2)
+    {
+      edgenr = gi2.edgenr;  
+      body = gi2.body;
+      dist = gi2.dist;
+      u = gi2.u; v = gi2.v;
+      return *this;
+    }
+  };
+
+  inline ostream & operator<< (ostream & ost, const EdgePointGeomInfo & gi)
+  {
+    ost << "epgi: edgnr=" << gi.edgenr << ", dist=" << gi.dist;
+    return ost;
+  }
+
+
+
+
+
+  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 PointIndex(hi); }
+    PointIndex operator-- (int) { int hi = i; i--; return PointIndex(hi); }
+
+#ifdef BASE0
+    enum { BASE = 0 };
+#else
+    enum { BASE = 1 };
+#endif  
+  };
+
+  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; }
+  };
+
+  inline istream & operator>> (istream & ist, ElementIndex & pi)
+  {
+    int i; ist >> i; pi = i; return ist;
+  }
+
+  inline ostream & operator<< (ostream & ost, const ElementIndex & pi)
+  {
+    return (ost << int(pi));
+  }
+
+
+  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; }
+  };
+
+  inline istream & operator>> (istream & ist, SurfaceElementIndex & pi)
+  {
+    int i; ist >> i; pi = i; return ist;
+  }
+
+  inline ostream & operator<< (ostream & ost, const SurfaceElementIndex & pi)
+  {
+    return (ost << int(pi));
+  }
+
+  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; }
+  };
+
+  inline istream & operator>> (istream & ist, SegmentIndex & pi)
+  {
+    int i; ist >> i; pi = i; return ist;
+  }
+
+  inline ostream & operator<< (ostream & ost, const SegmentIndex & pi)
+  {
+    return (ost << int(pi));
+  }
+
+
+
+
+  /**
+     Point in the mesh.
+     Contains layer (a new feature in 4.3 for overlapping meshes.
+  */
+  class MeshPoint : public Point<3>
+  {
+    int layer;
+    double singular; // singular factor for hp-refinement
+    POINTTYPE type;
+
+#ifdef PARALLEL
+    bool isghost;
+#endif
+
+  public:
+    MeshPoint () 
+    { 
+#ifdef PARALLEL
+      isghost = 0;
+#endif
+      ;
+    }
+
+    MeshPoint (const Point<3> & ap, int alayer = 1, POINTTYPE apt = INNERPOINT)
+      : Point<3> (ap), layer(alayer), singular(0.),type(apt) 
+    { 
+#ifdef PARALLEL
+      isghost = 0;
+#endif  
+      ;
+    }
+  
+    void SetPoint (const Point<3> & ap)
+    { 
+      Point<3>::operator= (ap); 
+      layer = 0; 
+      singular = 0; 
+#ifdef PARALLEL
+      isghost = 0;
+#endif
+    }
+
+    int GetLayer() const { return layer; }
+
+    POINTTYPE Type() const { return type; }
+    void SetType(POINTTYPE at) { type = at; }
+ 
+    double Singularity() const { return singular; }
+    void Singularity(double s) { singular = s; }
+    bool IsSingular() const { return (singular != 0.0); }
+
+#ifdef PARALLEL
+    bool IsGhost () const { return isghost; }
+    void SetGhost ( bool aisghost ) { isghost = aisghost; }
+
+    static MPI_Datatype MyGetMPIType ( );
+#endif
+
+  };
+
+  inline ostream & operator<<(ostream  & s, const MeshPoint & pt)
+  { 
+    return (s << Point<3> (pt)); 
+  }
+
+
+
+
+  typedef Array<MeshPoint, PointIndex::BASE> T_POINTS;
+
+
+
+  /**
+     Triangle element for surface mesh generation.
+  */
+  class Element2d
+  { 
+    /// point numbers
+    PointIndex pnum[ELEMENT2D_MAXPOINTS];
+    /// geom info of points
+    PointGeomInfo geominfo[ELEMENT2D_MAXPOINTS];
+
+    /// surface nr
+    int index:16;
+    ///
+    ELEMENT_TYPE typ:6;
+    /// number of points
+    unsigned int np:4;
+    bool badel:1;
+    bool refflag:1;  // marked for refinement
+    bool strongrefflag:1;
+    bool deleted:1;  // element is deleted
+
+    // Philippose - 08 August 2010
+    // Set a new property for each element, to 
+    // control whether it is visible or not
+    bool visible:1;  // element visible
+
+    /// order for hp-FEM
+    unsigned int orderx:6;
+    unsigned int ordery:6;
+
+#ifdef PARALLEL
+    bool isghost;
+    int partitionNumber; 
+#endif
+
+    /// a linked list for all segments in the same face
+    SurfaceElementIndex next;
+
+  public:
+    ///
+    Element2d ();
+    ///
+    Element2d (int anp);
+    ///
+    DLL_HEADER 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)
+    {
+      typ = atyp;
+      switch (typ)
+	{
+	case TRIG: np = 3; break;
+	case QUAD: np = 4; break;
+	case TRIG6: np = 6; break;
+	case QUAD6: np = 6; break;
+	case QUAD8: np = 8; break;
+	default:
+	  PrintSysError ("Element2d::SetType, illegal type ", typ);
+	}
+    }
+    ///
+    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 orderx; }
+    void SetOrder (int aorder) { orderx = ordery = aorder; }
+
+
+    void GetOrder (int & ox, int & oy) const { ox = orderx, oy =ordery;};
+    void GetOrder (int & ox, int & oy, int & oz) const { ox = orderx; oy = ordery; oz=0; }
+    void SetOrder (int ox, int oy, int  /* oz */) { orderx = ox; ordery = oy;}
+    void SetOrder (int ox, int oy) { orderx = ox; ordery = oy;}
+
+
+    ///
+    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;
+    void GetShapeNew (const Point<2> & p, class FlatVector & shape) const;
+    /// matrix 2 * np
+    void GetDShape (const Point2d & p, class DenseMatrix & dshape) const;
+    void GetDShapeNew (const Point<2> & p, class MatrixFixWidth<2> & 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 Vec<3> & 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; 
+    }
+
+    // Philippose - 08 August 2010
+    // Access functions for the new property: visible
+    void Visible(bool vis = 1) 
+    { visible = vis; }
+    bool IsVisible () const 
+    { return visible; }
+   
+    void SetRefinementFlag (bool rflag = 1) 
+    { refflag = rflag; }
+    bool TestRefinementFlag () const
+    { return refflag; }
+
+    void SetStrongRefinementFlag (bool rflag = 1) 
+    { strongrefflag = rflag; }
+    bool TestStrongRefinementFlag () const
+    { return strongrefflag; }
+
+  
+    SurfaceElementIndex NextElement() { return next; }
+
+    bool operator==(const Element2d & el2) const;
+
+    int HasFace(const Element2d& el) const;
+    ///
+    int meshdocval;
+    ///
+    int hp_elnr;
+
+#ifdef PARALLEL
+    bool IsGhost () const { return isghost; }
+    void SetGhost ( bool aisghost ) { isghost = aisghost; }
+
+    // by JS, only for 2D meshes ????
+    int GetPartition () const { return partitionNumber; }
+    void SetPartition (int nr) { partitionNumber = nr; }; 
+
+#else
+    bool IsGhost () const { return false; }
+#endif
+  };
+
+
+  ostream & operator<<(ostream  & s, const Element2d & el);
+
+
+
+
+
+  class IntegrationPointData
+  {
+  public:
+    Point<3> p;
+    double weight;
+    Vector shape;
+    DenseMatrix dshape;
+  };
+
+
+
+
+
+
+
+
+  /**
+     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;
+    ///
+    class flagstruct { 
+    public:
+      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 strongrefflag:1;
+      bool deleted:1;   // element is deleted, will be removed from array
+      bool fixed:1;     // don't change element in optimization
+    };
+
+    /// sub-domain index
+    short int index;
+    /// order for hp-FEM
+    unsigned int orderx:6;
+    unsigned int ordery:6;
+    unsigned int orderz:6;
+    /* unsigned int levelx:6;
+       unsigned int levely:6;
+       unsigned int levelz:6; */ 
+    /// stored shape-badness of element
+    float badness;
+  
+#ifdef PARALLEL
+    /// number of partition for parallel computation 
+    int partitionNumber;
+    bool isghost;
+#endif
+
+  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: 
+	case TET10: 
+	  return 4;
+	case PRISM12: 
+	case PRISM: 
+	  return 6; 
+	case PYRAMID:
+	  return 5;
+	case HEX:
+	  return 8;
+	default:
+#ifdef DEBUG
+	  PrintSysError ("Element3d::GetNV not implemented for typ ", typ)
+#endif
+	    ;
+	}
+      return np;
+    }
+
+    bool operator==(const Element & el2) const;
+
+    // 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 orderx; }
+    void SetOrder (const int aorder) ; 
+
+    void GetOrder (int & ox, int & oy, int & oz) const { ox = orderx; oy = ordery; oz = orderz; }
+    void SetOrder (const int ox, const int oy, const int oz);
+    // void GetLevel (int & ox, int & oy, int & oz) const { ox = levelx; oy = levely; oz = levelz; }
+    // void SetLevel (int ox, int oy, int oz) { levelx = ox; levely = oy; levelz = oz; }
+
+
+    ///
+    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<Point<3> > & points) const;
+    void GetNodesLocalNew (Array<Point<3> > & 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, Point<3> & 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 Point<3> & p, class Vector & shape) const;
+    void GetShapeNew (const Point<3> & p, class FlatVector & shape) const;
+    /// matrix 2 * np
+    void GetDShape (const Point<3> & p, class DenseMatrix & dshape) const;
+    void GetDShapeNew (const Point<3> & p, class MatrixFixWidth<3> & 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, Vec<3> & dir, double & dd) const;
+    double CalcJacobianBadnessGradient (const T_POINTS & points,
+					int pi, Vec<3> & grad) const;
+
+    ///
+    // friend ostream & operator<<(ostream  & s, const Element & el);
+
+    void SetRefinementFlag (bool rflag = 1) 
+    { flags.refflag = rflag; }
+    int TestRefinementFlag () const
+    { return flags.refflag; }
+
+    void SetStrongRefinementFlag (bool rflag = 1) 
+    { flags.strongrefflag = rflag; }
+    int TestStrongRefinementFlag () const
+    { return flags.strongrefflag; }
+
+    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; 
+    }
+
+
+
+#ifdef PARALLEL
+    int GetPartition () const { return partitionNumber; }
+    void SetPartition (int nr) { partitionNumber = nr; }; 
+
+    bool IsGhost () const { return isghost; }
+    void SetGhost ( const bool aisghost ) { isghost = aisghost; }
+#else
+    bool IsGhost () const { return false; }
+    int GetPartition () const { return 0; }
+#endif
+
+    int hp_elnr;
+  };
+
+  ostream & operator<<(ostream  & s, const Element & el);
+
+
+
+
+
+
+  /**
+     Edge segment.
+  */
+  class Segment
+  {
+  public:
+    ///
+    DLL_HEADER Segment();
+    DLL_HEADER Segment (const Segment& other);
+
+    ~Segment()
+    { ; }
+
+    // friend ostream & operator<<(ostream  & s, const Segment & seg);
+
+    PointIndex pnums[3];  // p1, p2, pmid
+
+    int edgenr;
+    ///
+    double singedge_left;
+    double singedge_right;
+
+    /// 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;
+
+  private:
+    string* bcname;
+
+  public:
+    /*
+      PointIndex operator[] (int i) const
+      { return (i == 0) ? p1 : p2; }
+
+      PointIndex & operator[] (int i) 
+      { return (i == 0) ? p1 : p2; }
+    */
+
+    Segment& operator=(const Segment & other);
+
+  
+    int hp_elnr;
+
+    void SetBCName ( string * abcname )
+    {
+      bcname = abcname;
+    }
+
+    string * BCNamePtr () 
+    { return bcname; }
+
+    const string * BCNamePtr () const 
+    { return bcname; }
+
+    string GetBCName () const
+    {
+      if (! bcname )
+	{
+	  return "default";
+	}
+      return *bcname;
+    }
+
+    int GetNP() const
+    {
+      return (pnums[2] < 0) ? 2 : 3;
+    }
+
+    ELEMENT_TYPE GetType() const
+    {
+      return (pnums[2] < 0) ? SEGMENT : SEGMENT3;
+    }
+  
+    PointIndex & operator[] (int i) { return pnums[i]; }
+    const PointIndex & operator[] (int i) const { return pnums[i]; }
+  };
+
+  ostream & operator<<(ostream  & s, const Segment & seg);
+
+
+
+
+  // class Surface;  
+  // class FaceDescriptor;
+
+  ///
+  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;
+    // Philippose - 06/07/2009
+    // Add capability to store surface colours along with 
+    // other face data
+    /// surface colour (Default: R=0.0 ; G=1.0 ; B=0.0)
+    Vec3d surfcolour;
+
+    ///
+    string * bcname;
+    /// root of linked list 
+    SurfaceElementIndex firstelement;
+  
+    double domin_singular;
+    double domout_singular;
+
+  public:
+    DLL_HEADER FaceDescriptor();
+    DLL_HEADER FaceDescriptor(int surfnri, int domini, int domouti, int tlosurfi);
+    DLL_HEADER FaceDescriptor(const Segment & seg);
+    DLL_HEADER FaceDescriptor(const FaceDescriptor& other);
+    DLL_HEADER ~FaceDescriptor()  { ; }
+
+    DLL_HEADER 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; }
+
+
+    double DomainInSingular() const { return domin_singular; }
+    double DomainOutSingular() const { return domout_singular; }
+
+    // Philippose - 06/07/2009
+    // Get Surface colour
+    Vec3d SurfColour () const { return surfcolour; }
+    string GetBCName () const; 
+    // string * BCNamePtr () { return bcname; }
+    // const string * BCNamePtr () const  { return bcname; }
+    void SetSurfNr (int sn) { surfnr = sn; }
+    void SetDomainIn (int di) { domin = di; }
+    void SetDomainOut (int dom) { domout = dom; }
+    void SetBCProperty (int bc) { bcprop = bc; }
+    void SetBCName (string * bcn) { bcname = bcn; }
+    // Philippose - 06/07/2009
+    // Set the surface colour
+    void SetSurfColour (Vec3d colour) { surfcolour = colour; }
+
+    void SetDomainInSingular (double v) { domin_singular = v; }
+    void SetDomainOutSingular (double v) { domout_singular = v; }
+
+    SurfaceElementIndex FirstElement() { return firstelement; }
+    // friend ostream & operator<<(ostream  & s, const FaceDescriptor & fd);
+    friend class Mesh;
+  };
+
+  ostream & operator<< (ostream  & s, const FaceDescriptor & fd);
+
+ 
+  class EdgeDescriptor
+  {
+    int tlosurf;
+    int surfnr[2];
+  public:
+    EdgeDescriptor ()
+      : tlosurf(-1)
+    { surfnr[0] = surfnr[1] = -1; }
+
+    int SurfNr (int i) const { return surfnr[i]; }
+    void SetSurfNr (int i, int nr) { surfnr[i] = nr; }
+
+    int TLOSurface() const { return tlosurf; }
+    void SetTLOSurface (int nr) { tlosurf = nr; }
+  };
+
+
+
+  class DLL_HEADER 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
+       */
+    const 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
+       **/
+    const 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;
+    /// minimal mesh size
+    double minh;
+    /// file for meshsize
+    const char * meshsizefilename;
+    /// start surfacemeshing from everywhere in surface
+    int startinsurface;
+    /// check overlapping surfaces (debug)
+    int checkoverlap;
+    /// check overlapping surface mesh before volume meshing
+    int checkoverlappingboundary;
+    /// 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, 2d meshing
+    int giveuptol2d;
+    /// give up quality class, 3d meshing
+    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;
+
+    bool check_impossible;
+  
+    ///
+    int secondorder;
+    /// high order element curvature
+    int elementorder;
+    /// quad-dominated surface meshing
+    int quad;
+    ///
+    int inverttets;
+    ///
+    int inverttrigs;
+    ///
+    int autozrefine;
+    ///
+    MeshingParameters ();
+    ///
+    void Print (ostream & ost) const;
+
+    void CopyFrom(const MeshingParameters & other);
+  };
+
+
+
+  class DebugParameters 
+  {
+  public:
+    ///
+    int debugoutput;
+    /// use slow checks
+    int slowchecks;
+    ///
+    int haltsuccess;
+    ///
+    int haltnosuccess;
+    ///
+    int haltlargequalclass;
+    ///
+    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
+  {
+  public:
+    enum ID_TYPE { UNDEFINED = 1, PERIODIC = 2, CLOSESURFACES = 3, CLOSEEDGES = 4};
+  
+
+  private:
+    class Mesh & mesh;
+
+    /// identify points (thin layers, periodic b.c.)  
+    INDEX_2_HASHTABLE<int> * identifiedpoints;
+  
+    /// the same, with info about the id-nr
+    INDEX_3_HASHTABLE<int> * identifiedpoints_nr;
+
+    /// sorted by identification nr
+    TABLE<INDEX_2> idpoints_table;
+
+    Array<ID_TYPE> type;
+
+    /// number of identifications (or, actually used identifications ?)
+    int maxidentnr;
+
+  public:
+    ///
+    DLL_HEADER Identifications (class Mesh & amesh);
+    ///
+    DLL_HEADER ~Identifications ();
+
+    DLL_HEADER void Delete ();
+
+    /*
+      Identify points pi1 and pi2, due to
+      identification nr identnr
+    */
+    DLL_HEADER void Add (PointIndex pi1, PointIndex pi2, int identnr);
+
+
+    int Get (PointIndex pi1, PointIndex pi2) const;
+    int GetSymmetric (PointIndex pi1, PointIndex pi2) const;
+
+    bool Get (PointIndex pi1, PointIndex pi2, int identnr) const;
+    bool GetSymmetric (PointIndex pi1, PointIndex pi2, int identnr) 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, bool symmetric = false) const;
+    ///
+    ID_TYPE GetType(int identnr) const
+    {
+      if(identnr <= type.Size())
+	return type[identnr-1];
+      else
+	return UNDEFINED;
+    }
+    void SetType(int identnr, ID_TYPE t)
+    {
+      while(type.Size() < identnr)
+	type.Append(UNDEFINED);
+      type[identnr-1] = t;
+    }
+    
+    ///
+    void GetPairs (int identnr, Array<INDEX_2> & identpairs) const;
+    ///
+    int GetMaxNr () const { return maxidentnr; }  
+
+    /// remove secondorder
+    void SetMaxPointNr (int maxpnum);
+
+    void Print (ostream & ost) const;
+  };
+
+
+}
+
+
+
+
+#endif
+
diff --git a/contrib/Netgen/libsrc/meshing/msghandler.cpp b/contrib/Netgen/libsrc/meshing/msghandler.cpp
new file mode 100644
index 0000000000..e2818858a4
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/msghandler.cpp
@@ -0,0 +1,227 @@
+//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)
+{
+  if (importance <= printmessage_importance)
+    {
+      Ng_PrintDest(MyStr(" ")+s1+s2+MyStr("\n"));
+    }
+}
+
+void PrintMessage(int importance, 
+		  const MyStr& s1, const MyStr& s2, const MyStr& s3, const MyStr& s4)
+{
+  if (importance <= printmessage_importance)
+    {
+      Ng_PrintDest(MyStr(" ")+s1+s2+s3+s4+MyStr("\n"));
+    }
+}
+
+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"));
+}
+
+
+static Array<MyStr*> msgstatus_stack(0);
+static Array<double> threadpercent_stack(0);
+static MyStr msgstatus = "";
+
+
+
+
+void ResetStatus()
+{
+  SetStatMsg("idle");
+
+  for (int i = 0; i < msgstatus_stack.Size(); i++)
+    delete msgstatus_stack[i];
+  msgstatus_stack.SetSize(0);
+  threadpercent_stack.SetSize(0);
+
+  // multithread.task = "";
+  multithread.percent = 100.;
+}
+
+void PushStatus(const MyStr& s)
+{
+  msgstatus_stack.Append(new MyStr (s));  
+  SetStatMsg(s);
+  threadpercent_stack.Append(0);
+}
+
+void PushStatusF(const MyStr& s)
+{
+  msgstatus_stack.Append(new MyStr (s));
+  SetStatMsg(s);
+  threadpercent_stack.Append(0);
+  PrintFnStart(s);
+}
+
+void PopStatus()
+{
+  if (msgstatus_stack.Size())
+    {
+      if (msgstatus_stack.Size() > 1)
+	SetStatMsg (*msgstatus_stack.Last());
+      else
+	SetStatMsg ("");
+      delete msgstatus_stack.Last();
+      msgstatus_stack.DeleteLast();
+      threadpercent_stack.DeleteLast();
+      if(threadpercent_stack.Size() > 0)
+	multithread.percent = threadpercent_stack.Last();
+      else
+	multithread.percent = 100.;
+    }
+  else
+    {
+      PrintSysError("PopStatus failed");
+    }
+}
+
+
+
+/*
+void SetStatMsgF(const MyStr& s)
+{
+  PrintFnStart(s);
+  SetStatMsg(s);
+}
+*/
+
+void SetStatMsg(const MyStr& s)
+{
+  msgstatus = s;
+  multithread.task = msgstatus.c_str();  
+}
+
+void SetThreadPercent(double percent)
+{
+  multithread.percent = percent;
+  if(threadpercent_stack.Size() > 0)
+    threadpercent_stack.Last() = percent;
+}
+
+
+void GetStatus(MyStr & s, double & percentage)
+{
+  if(threadpercent_stack.Size() > 0)
+    percentage = threadpercent_stack.Last();
+  else
+    percentage = multithread.percent;
+  
+  if ( msgstatus_stack.Size() )
+    s = *msgstatus_stack.Last();
+  else
+    s = "idle";     
+}
+
+/*
+#ifdef SMALLLIB
+#define SMALLLIBORNOTCL
+#endif
+#ifdef NOTCL
+#define SMALLLIBORNOTCL
+#endif
+
+#ifdef SMALLLIBORNOTCL
+void Ng_PrintDest(const char * s){cout << s <<flush;}
+double GetTime(){return 0;}
+void MyError(const char * ch)
+{
+  cerr << ch << endl;
+}
+#endif
+*/
+
+
+}
diff --git a/contrib/Netgen/libsrc/meshing/msghandler.hpp b/contrib/Netgen/libsrc/meshing/msghandler.hpp
new file mode 100644
index 0000000000..bab5717441
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/msghandler.hpp
@@ -0,0 +1,57 @@
+#ifndef FILE_MSGHANDLER
+#define FILE_MSGHANDLER
+
+/**************************************************************************/
+/* File:   msghandler.hh                                                  */
+/* Author: Johannes Gerstmayr                                             */
+/* Date:   20. Nov. 99                                                    */
+/**************************************************************************/
+
+
+namespace netgen
+{
+
+  extern void PrintDot(char ch = '.');
+
+
+  //Message Pipeline:
+
+  //importance: importance of message: 1=very important, 3=middle, 5=low, 7=unimportant
+  extern DLL_HEADER void PrintMessage(int importance, 
+			   const MyStr& s1, const MyStr& s2=MyStr());
+  extern DLL_HEADER void PrintMessage(int importance, 
+			   const MyStr& s1, const MyStr& s2, const MyStr& s3, const MyStr& s4=MyStr());
+  extern DLL_HEADER void PrintMessage(int importance, 
+			   const MyStr& s1, const MyStr& s2, const MyStr& s3, const MyStr& s4, 
+			   const MyStr& s5, const MyStr& s6=MyStr(), const MyStr& s7=MyStr(), const MyStr& s8=MyStr());
+
+  // CR without line-feed
+  extern DLL_HEADER 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 DLL_HEADER 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 DLL_HEADER 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 DLL_HEADER 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 DLL_HEADER 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 DLL_HEADER 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 DLL_HEADER 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 DLL_HEADER 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 DLL_HEADER void SetStatMsg(const MyStr& s);
+
+  extern DLL_HEADER void PushStatus(const MyStr& s);
+  extern DLL_HEADER void PushStatusF(const MyStr& s);
+  extern DLL_HEADER void PopStatus();
+  extern DLL_HEADER void SetThreadPercent(double percent);
+  extern DLL_HEADER void GetStatus(MyStr & s, double & percentage);
+}
+
+
+#endif
+
diff --git a/contrib/Netgen/libsrc/meshing/netrule2.cpp b/contrib/Netgen/libsrc/meshing/netrule2.cpp
new file mode 100644
index 0000000000..015ed6fa7c
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/netrule2.cpp
@@ -0,0 +1,222 @@
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+namespace netgen
+{
+
+netrule :: netrule ()
+{
+  name = new char[1];
+  name[0] = char(0);
+  quality = 0;
+}
+
+netrule ::  ~netrule()
+{
+  delete [] name;
+  for(int i = 0; i < oldutofreearea_i.Size(); i++)
+    delete oldutofreearea_i[i];
+  for(int i = 0; i < freezone_i.Size(); i++)
+    delete freezone_i[i];
+}
+
+
+
+void netrule :: SetFreeZoneTransformation (const Vector & devp, int tolclass)
+{
+  double lam1 = 1.0/tolclass;
+  double lam2 = 1.-lam1;
+
+  double mem1[100], mem2[100], mem3[100];
+
+  int vs = oldutofreearea.Height();
+  FlatVector devfree(vs, mem1);
+
+  int fzs = freezone.Size();
+  transfreezone.SetSize (fzs);
+
+  if (tolclass <= oldutofreearea_i.Size())
+    {
+      oldutofreearea_i[tolclass-1] -> Mult (devp, devfree);
+
+      Array<Point2d> & fzi = *freezone_i[tolclass-1];
+      for (int i = 0; i < fzs; i++)
+	{
+	  transfreezone[i].X() = fzi[i].X() + devfree[2*i];
+	  transfreezone[i].Y() = fzi[i].Y() + devfree[2*i+1];
+	}
+    }
+  else
+    {
+      FlatVector devfree1(vs, mem2);
+      FlatVector devfree2(vs, mem3);
+
+      oldutofreearea.Mult (devp, devfree1);
+      oldutofreearealimit.Mult (devp, devfree2);
+      devfree.Set2 (lam1, devfree1, lam2, devfree2);
+
+      for (int i = 0; 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 (fzs > 0)
+    {
+      fzmaxx = fzminx = transfreezone[0].X();
+      fzmaxy = fzminy = transfreezone[0].Y();
+    }
+
+  for (int i = 1; i < fzs; i++)
+    {
+      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 (int 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 /= sqrt (len2);    // scaling necessary ?
+
+	  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
+{
+  for (int i = 0; i < transfreezone.Size(); i++)
+    {
+      if (freesetinequ(i, 0) * p.X() + 
+	  freesetinequ(i, 1) * p.Y() +
+	  freesetinequ(i, 2) > 0) return 0;
+    }
+  return 1;
+}
+*/
+
+int netrule :: IsLineInFreeZone2 (const Point2d & p1, const Point2d & p2) const
+{
+  int left, right, allleft, allright;
+
+  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 (int i = 1; i <= transfreezone.Size(); i++)
+    {
+      if (freesetinequ.Get(i, 1) * p1.X() + freesetinequ.Get(i, 2) * p1.Y() +
+	  freesetinequ.Get(i, 3) > -1e-8 &&    // -1e-6
+	  freesetinequ.Get(i, 1) * p2.X() + freesetinequ.Get(i, 2) * p2.Y() +
+	  freesetinequ.Get(i, 3) > -1e-8       // -1e-6
+	  ) return 0;
+    }
+
+  double nx =  (p2.Y() - p1.Y());
+  double ny = -(p2.X() - p1.X());
+  double nl = sqrt (nx * nx + ny * ny);
+  if (nl > 1e-8)
+    {
+      nx /= nl;
+      ny /= nl;
+      double c = - (p1.X() * nx + p1.Y() * ny);
+
+      allleft = 1;
+      allright = 1;
+
+      for (int 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 n = transfreezone.Size();
+  for (int i = 1; i <= n; i++)
+    {
+      const bool counterclockwise = CCW (transfreezone.Get(i), 
+					 transfreezone.Get(i % n + 1),
+					 transfreezone.Get( (i+1) % n + 1 ),
+					 1e-7);
+      //(*testout) << "ccw " << counterclockwise << endl << " p1 " << transfreezone.Get(i) << " p2 " << transfreezone.Get(i % n + 1)
+      //		 << " p3 " << transfreezone.Get( (i+1) % n + 1 ) << endl;
+      if (!counterclockwise )
+	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 * ltf = &linetolerances.Get(li);
+  return ltf->f1 * dx * dx + ltf->f2 * dx * dy + ltf->f3 * dy * dy;
+}
+
+
+
+
+/*
+int GetNRules ()
+  {
+  return rules.Size();
+  }
+*/
+
+
+
+
+
+
+
+
+
+
+
+}
diff --git a/contrib/Netgen/libsrc/meshing/netrule3.cpp b/contrib/Netgen/libsrc/meshing/netrule3.cpp
new file mode 100644
index 0000000000..de0e35e424
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/netrule3.cpp
@@ -0,0 +1,1138 @@
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+
+
+namespace netgen
+{
+
+
+vnetrule :: vnetrule ()
+{
+  name = new char[1];
+  name[0] = char(0);
+  quality = 0;
+}
+
+vnetrule :: ~vnetrule ()
+{
+  // if (strlen(name)) 
+  delete [] name;
+  for (int i = 1; i <= freefaces.Size(); i++)
+    delete freefaces.Elem(i);
+  for (int i = 1; i <= freesets.Size(); i++)
+    delete freesets.Elem(i);
+  for (int i = 1; i <= freeedges.Size(); i++)
+    delete freeedges.Elem(i);
+  for (int i = 1; i <= freefaceinequ.Size(); i++)
+    delete freefaceinequ.Elem(i);
+  delete oldutofreezone;
+  delete oldutofreezonelimit;
+}
+
+int vnetrule :: TestFlag (char flag) const
+{
+  for (int 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;
+
+  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(j-1) = allp(i+3*j-3-1);
+
+      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(j-1);
+    }
+
+  // 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;
+
+
+  ArrayMem<int,3> 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;
+  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 lambda1 = rs1 * vii22 - rs2 * vii12;
+	      double lambda2 = rs2 * vii11 - rs1 * vii12;
+
+	      if (fabs (lambda1) > fabs (lambda2))
+		{
+		  if (lambda1 < 0)
+		    an *= -1;
+		}
+	      else
+		{
+		  if (lambda2 < 0)
+		    an *= -1;
+		}
+
+
+	      if (lambda1 * lambda2 < 0 && 0)
+		{
+		  if (fabs (lambda1) > 1e-14 && fabs (lambda2) > 1e-14)
+		    {
+		      //		      (*mycout) << "lambda1 lambda2 < 0" << endl;
+		      (*testout) << "lambdai 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) << "lambdai = " << lambda1 << ", " << lambda2 << 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 lambda1 = rs1 * vii22 - rs2 * vii12;
+	      double lambda2 = rs2 * vii11 - rs1 * vii12;
+
+	      //	      (*testout) << "lambda1, lambda2 = " << lambda1 << ", " << lambda2 << endl;
+
+
+	      if (fabs (lambda1) > fabs (lambda2))
+		{
+		  if (lambda1 < 0)
+		    an *= -1;
+		}
+	      else
+		{
+		  if (lambda2 < 0)
+		    an *= -1;
+		}
+
+
+	      if (lambda1 * lambda2 < 0)
+		{
+		  if (fabs (lambda1) > 1e-14 && fabs (lambda2) > 1e-14)
+		    {
+		      //		      (*mycout) << "lambda1 lambda2 < 0" << endl;
+		      (*testout) << "lambdai 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) << "lambdai = " << lambda1 << ", " << lambda2 << 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;
+
+
+  ArrayMem<int,4> 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;
+    }
+
+  ArrayMem<int,3> 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/contrib/Netgen/libsrc/meshing/parallelmesh.cpp b/contrib/Netgen/libsrc/meshing/parallelmesh.cpp
new file mode 100644
index 0000000000..03f436aef9
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/parallelmesh.cpp
@@ -0,0 +1,1173 @@
+#ifdef PARALLEL
+
+#include <meshing.hpp>
+#include "paralleltop.hpp"
+
+#define METIS4
+
+
+#ifdef METIS
+namespace metis {
+  extern "C" {
+
+#ifdef METIS4
+#include <metis.h>
+    typedef idxtype idx_t;   
+#else
+#include <metis.h>
+    typedef idx_t idxtype;   
+#endif
+  } 
+}
+
+using namespace metis;
+#endif
+
+
+
+namespace netgen
+{
+
+  template <>
+  inline MPI_Datatype MyGetMPIType<netgen::PointIndex> ( ) 
+  { return MPI_INT; }
+
+
+
+
+
+  void Mesh :: SendRecvMesh ()
+  {
+    if (id == 0)
+      PrintMessage (1, "Send/Receive mesh");
+
+    {
+      // distribute global information
+      int nelglob, nseglob, nvglob;
+      if (id == 0)
+	{
+	  paralleltop -> SetNV (GetNV());
+	  paralleltop -> SetNE (GetNE());
+	  paralleltop -> SetNSegm (GetNSeg());
+	  paralleltop -> SetNSE (GetNSE());
+	  
+	  nelglob = GetNE();
+	  nseglob = GetNSE();
+	  nvglob = GetNV();
+	}
+      
+      MyMPI_Bcast (dimension);
+      MyMPI_Bcast (nelglob);
+      MyMPI_Bcast (nseglob);
+      MyMPI_Bcast (nvglob);
+      
+      if (id > 0)
+	{
+	  paralleltop -> SetNEGlob (nelglob);
+	  paralleltop -> SetNSEGlob (nseglob);
+	  paralleltop -> SetNVGlob (nvglob);
+	}
+    }
+
+
+
+    {
+      // distribute number of local elements
+      if (id == 0)
+	{
+	  Array<int> num_els_on_proc(ntasks);
+	  num_els_on_proc = 0;
+	  for (ElementIndex ei = 0; ei < GetNE(); ei++)
+	    num_els_on_proc[(*this)[ei].GetPartition()]++;
+	  
+	  MPI_Scatter (&num_els_on_proc[0], 1, MPI_INT,
+		       MPI_IN_PLACE, -1, MPI_INT, 0, MPI_COMM_WORLD);
+	}
+      else
+	{
+	  int nelloc;
+	  MPI_Scatter (NULL, 0, MPI_INT,
+		       &nelloc, 1, MPI_INT, 0, MPI_COMM_WORLD);
+	  
+	  paralleltop -> SetNE (nelloc);
+	}
+    }
+
+    if (id == 0)
+      SendMesh ();
+    else
+      ReceiveParallelMesh();
+  }
+
+
+
+
+
+
+
+  void Mesh :: SendMesh () const   
+  {
+    Array<MPI_Request> sendrequests;
+
+    PrintMessage ( 3, "Sending vertices");
+
+
+    Array<int> num_els_on_proc(ntasks);
+    num_els_on_proc = 0;
+    for (ElementIndex ei = 0; ei < GetNE(); ei++)
+      num_els_on_proc[(*this)[ei].GetPartition()]++;
+
+    TABLE<ElementIndex> els_of_proc (num_els_on_proc);
+    for (ElementIndex ei = 0; ei < GetNE(); ei++)
+      els_of_proc.Add ( (*this)[ei].GetPartition(), ei);
+
+
+    Array<int> num_sels_on_proc(ntasks);
+    num_sels_on_proc = 0;
+    for (SurfaceElementIndex ei = 0; ei < GetNSE(); ei++)
+      num_sels_on_proc[(*this)[ei].GetPartition()]++;
+
+    TABLE<SurfaceElementIndex> sels_of_proc (num_sels_on_proc);
+    for (SurfaceElementIndex ei = 0; ei < GetNSE(); ei++)
+      sels_of_proc.Add ( (*this)[ei].GetPartition(), ei);
+
+
+
+
+    Array<int, PointIndex::BASE> vert_flag (GetNV());
+    Array<int, PointIndex::BASE> num_procs_on_vert (GetNV());
+    Array<int> num_verts_on_proc (ntasks);
+
+    num_verts_on_proc = 0;
+    num_procs_on_vert = 0;
+    vert_flag = -1;
+
+    Array<int> nelloc (ntasks);
+    nelloc = 0;
+    Array<int> nselloc (ntasks);
+    nselloc = 0;
+
+
+    for (int dest = 1; dest < ntasks; dest++)
+      {
+	FlatArray<ElementIndex> els = els_of_proc[dest];
+
+	for (int hi = 0; hi < els.Size(); hi++)
+	  {
+	    const Element & el = (*this) [ els[hi] ];
+	    for (int i = 0; i < el.GetNP(); i++)
+	      {
+		PointIndex epi = el[i]; 
+		if (vert_flag[epi] < dest)
+		  {
+		    vert_flag[epi] = dest;
+
+		    num_verts_on_proc[dest]++;
+		    num_procs_on_vert[epi]++;
+
+		    paralleltop -> SetDistantPNum ( dest, epi, num_verts_on_proc[dest]);
+		  }
+	      }
+	    nelloc[dest] ++;
+	    paralleltop -> SetDistantEl ( dest, els[hi]+1, nelloc[dest] );
+	  }
+
+
+	FlatArray<SurfaceElementIndex> sels = sels_of_proc[dest];
+
+	for (int hi = 0; hi < sels.Size(); hi++)
+	  {
+	    const Element2d & el = (*this) [ sels[hi] ];
+	    for (int i = 0; i < el.GetNP(); i++)
+	      {
+		PointIndex epi = el[i]; 
+		if (vert_flag[epi] < dest)
+		  {
+		    vert_flag[epi] = dest;
+
+		    num_verts_on_proc[dest]++;
+		    num_procs_on_vert[epi]++;
+
+		    paralleltop -> SetDistantPNum ( dest, epi, num_verts_on_proc[dest]);
+		  }
+	      }
+	    nselloc[dest] ++;
+	    paralleltop -> SetDistantSurfEl ( dest, sels[hi]+1, nselloc[dest] );
+	  }
+      }
+
+    TABLE<PointIndex> verts_of_proc (num_verts_on_proc);
+    TABLE<int, PointIndex::BASE> procs_of_vert (num_procs_on_vert);
+    TABLE<int, PointIndex::BASE> loc_num_of_vert (num_procs_on_vert);
+
+    vert_flag = -1;
+    for (int dest = 1; dest < ntasks; dest++)
+      {
+	FlatArray<ElementIndex> els = els_of_proc[dest];
+	for (int hi = 0; hi < els.Size(); hi++)
+	  {
+	    const Element & el = (*this) [ els[hi] ];
+	    for (int i = 0; i < el.GetNP(); i++)
+	      {
+		PointIndex epi = el[i];
+		if (vert_flag[epi] < dest)
+		  {
+		    vert_flag[epi] = dest;
+		    procs_of_vert.Add (epi, dest);
+		  }
+	      }
+	  }
+
+	FlatArray<SurfaceElementIndex> sels = sels_of_proc[dest];
+	for (int hi = 0; hi < sels.Size(); hi++)
+	  {
+	    const Element2d & el = (*this) [ sels[hi] ];
+	    for (int i = 0; i < el.GetNP(); i++)
+	      {
+		PointIndex epi = el[i];
+		if (vert_flag[epi] < dest)
+		  {
+		    vert_flag[epi] = dest;
+		    procs_of_vert.Add (epi, dest);
+		  }
+	      }
+	  }
+
+      }
+
+    for (int vert = 1; vert <= GetNP(); vert++ )
+      {
+	FlatArray<int> procs = procs_of_vert[vert];
+	for (int j = 0; j < procs.Size(); j++)
+	  {
+	    int dest = procs[j];
+	    verts_of_proc.Add (dest, vert);
+	    loc_num_of_vert.Add (vert, verts_of_proc[dest].Size());
+	  }
+      }
+
+    for (int dest = 1; dest < ntasks; dest++)
+      {
+	FlatArray<PointIndex> verts = verts_of_proc[dest];
+
+	sendrequests.Append (MyMPI_ISend (verts, dest, MPI_TAG_MESH+1));
+
+	MPI_Datatype mptype = MeshPoint::MyGetMPIType();
+
+	int numv = verts.Size();
+
+	MPI_Datatype newtype;
+	Array<int> blocklen (numv);
+	blocklen = 1;
+	
+	MPI_Type_indexed (numv, &blocklen[0], 
+			  reinterpret_cast<int*> (&verts[0]), 
+			  mptype, &newtype);
+	MPI_Type_commit (&newtype);
+
+	MPI_Request request;
+	MPI_Isend( &points[0], 1, newtype, dest, MPI_TAG_MESH+1, MPI_COMM_WORLD, &request);
+	sendrequests.Append (request);
+      }
+
+
+    Array<int> num_distpnums(ntasks);
+    num_distpnums = 0;
+
+    for (int vert = 1; vert <= GetNP(); vert++)
+      {
+	FlatArray<int> procs = procs_of_vert[vert];
+	for (int j = 0; j < procs.Size(); j++)
+	  num_distpnums[procs[j]] += 3 * (procs.Size()-1);
+      }
+
+    TABLE<int> distpnums (num_distpnums);
+
+    for (int vert = 1; vert <= GetNP(); vert++)
+      {
+	FlatArray<int> procs = procs_of_vert[vert];
+	for (int j = 0; j < procs.Size(); j++)
+	  for (int k = 0; k < procs.Size(); k++)
+	    if (j != k)
+	      {
+		distpnums.Add (procs[j], loc_num_of_vert[vert][j]);
+		distpnums.Add (procs[j], procs_of_vert[vert][k]);
+		distpnums.Add (procs[j], loc_num_of_vert[vert][k]);
+	      }
+      }
+    
+    for ( int dest = 1; dest < ntasks; dest ++ )
+      sendrequests.Append (MyMPI_ISend (distpnums[dest], dest, MPI_TAG_MESH+1));
+
+
+
+    PrintMessage ( 3, "Sending elements" );
+
+    Array<int> elarraysize (ntasks);
+    elarraysize = 0;
+    for ( int ei = 1; ei <= GetNE(); ei++)
+      {
+	const Element & el = VolumeElement (ei);
+	int dest = el.GetPartition();
+	elarraysize[dest] += 3 + el.GetNP();
+      }
+
+    TABLE<int> elementarrays(elarraysize);
+
+    for (int ei = 1; ei <= GetNE(); ei++)
+      {
+	const Element & el = VolumeElement (ei);
+	int dest = el.GetPartition();
+
+	elementarrays.Add (dest, ei);
+	elementarrays.Add (dest, el.GetIndex());
+	elementarrays.Add (dest, el.GetNP());
+	for (int i = 0; i < el.GetNP(); i++)
+	  elementarrays.Add (dest, el[i]);
+      }
+
+    for (int dest = 1; dest < ntasks; dest ++ )
+      sendrequests.Append (MyMPI_ISend (elementarrays[dest], dest, MPI_TAG_MESH+2));
+
+
+    PrintMessage ( 3, "Sending Face Descriptors" );
+
+    Array<double> fddata (6 * GetNFD());
+    for (int fdi = 1; fdi <= GetNFD(); fdi++)
+      {
+	fddata[6*fdi-6] = GetFaceDescriptor(fdi).SurfNr();
+	fddata[6*fdi-5] = GetFaceDescriptor(fdi).DomainIn();	
+	fddata[6*fdi-4] = GetFaceDescriptor(fdi).DomainOut();
+	fddata[6*fdi-3] = GetFaceDescriptor(fdi).BCProperty();
+	fddata[6*fdi-2] = GetFaceDescriptor(fdi).domin_singular;
+	fddata[6*fdi-1] = GetFaceDescriptor(fdi).domout_singular;
+	
+      }
+    for (int dest = 1; dest < ntasks; dest++)
+      sendrequests.Append (MyMPI_ISend (fddata, dest, MPI_TAG_MESH+3));
+
+    PrintMessage ( 3, "Sending Surface elements" );
+  
+    Array <int> nlocsel(ntasks), bufsize(ntasks); 
+    nlocsel = 0;
+    bufsize = 1;
+
+    for (int sei = 1; sei <= GetNSE(); sei++ )
+      {
+	const Element2d & sel = SurfaceElement (sei);
+	int dest = sel.GetPartition();
+	nlocsel[dest] ++;
+	bufsize[dest] += 4 + 2*sel.GetNP();
+      }
+    
+    TABLE<int> selbuf(bufsize);
+
+    for (int dest = 1; dest < ntasks; dest++ )
+      selbuf.Add (dest, nlocsel[dest]);
+
+    for (int sei = 1; sei <= GetNSE(); sei ++ )
+      {
+	const Element2d & sel = SurfaceElement (sei);
+	int dest = sel.GetPartition();
+
+	selbuf.Add (dest, sei);
+	selbuf.Add (dest, sel.GetIndex());
+	selbuf.Add (dest, 0);
+	selbuf.Add (dest, sel.GetNP());
+	
+	for ( int ii = 1; ii <= sel.GetNP(); ii++)
+	  {
+	    selbuf.Add (dest, sel.PNum(ii));
+	    selbuf.Add (dest, sel.GeomInfoPi(ii).trignum);
+	  }
+      }
+
+    for (int dest = 1; dest < ntasks; dest++)
+      sendrequests.Append (MyMPI_ISend(selbuf[dest], dest, MPI_TAG_MESH+4));
+
+    PrintMessage ( 3, "Sending Edge Segments");
+
+    Array <int> nlocseg(ntasks), segi(ntasks);
+    for ( int i = 0; i < ntasks; i++)
+      {
+	nlocseg[i] = 0;
+	bufsize[i] = 0;
+	segi[i] = 0;
+      }
+
+    for (int segi = 1; segi <= GetNSeg(); segi ++ )
+      {
+	Array<int> volels;
+	const MeshTopology & topol = GetTopology();
+	topol . GetSegmentSurfaceElements ( segi, volels );
+        for (int j = 0; j < volels.Size(); j++)
+          {
+            int ei = volels[j];
+            if ( ei > 0 && ei <= GetNSE() )
+              {
+                const Element2d & el = SurfaceElement (ei);
+                int dest = el.GetPartition();
+		nlocseg[dest] ++;
+		bufsize[dest] += 14;
+              }
+	  }
+      }
+
+    TABLE<double> segmbuf(bufsize);
+
+    for ( int ls=1; ls <= GetNSeg(); ls++)
+      {
+	Array<int> volels;
+	GetTopology().GetSegmentSurfaceElements ( ls, volels );
+	const Segment & seg = LineSegment (ls);
+
+        for (int j = 0; j < volels.Size(); j++)
+          {
+            int ei = volels[j];
+            if ( ei > 0 && ei <= GetNSE() )
+              {
+                const Element2d & el = SurfaceElement (ei);
+                int dest = el.GetPartition();
+
+		if ( dest > 0 )
+		  {
+		    segmbuf.Add (dest, ls);
+		    segmbuf.Add (dest, seg.si);
+		    segmbuf.Add (dest, seg.pnums[0]);
+		    segmbuf.Add (dest, seg.pnums[1]);
+		    segmbuf.Add (dest, seg.geominfo[0].trignum);
+		    segmbuf.Add (dest, seg.geominfo[1].trignum);
+		    segmbuf.Add (dest, seg.surfnr1);
+		    segmbuf.Add (dest, seg.surfnr2);
+		    segmbuf.Add (dest, seg.edgenr);
+		    segmbuf.Add (dest, seg.epgeominfo[0].dist);
+		    segmbuf.Add (dest, seg.epgeominfo[1].edgenr);
+		    segmbuf.Add (dest, seg.epgeominfo[1].dist);
+		    segmbuf.Add (dest, seg.singedge_right);
+		    segmbuf.Add (dest, seg.singedge_left);
+		    segi[dest] += 14;
+		  }
+		paralleltop -> SetDistantSegm ( dest, ls, int ( segi[dest] / 14 ) );
+	      }
+	  }
+      }
+
+    for ( int dest = 1; dest < ntasks; dest++)
+      sendrequests.Append (MyMPI_ISend(segmbuf[dest], dest, MPI_TAG_MESH+5));
+
+    MPI_Waitall (sendrequests.Size(), &sendrequests[0], MPI_STATUS_IGNORE);
+
+    MPI_Barrier(MPI_COMM_WORLD);
+  }
+
+
+
+
+
+
+
+
+  // slaves receive the mesh from the master
+  void Mesh :: ReceiveParallelMesh ( )
+  {
+    int timer = NgProfiler::CreateTimer ("ReceiveParallelMesh");
+    int timer_pts = NgProfiler::CreateTimer ("Receive points");
+    int timer_els = NgProfiler::CreateTimer ("Receive elements");
+    int timer_sels = NgProfiler::CreateTimer ("Receive surface elements");
+    NgProfiler::RegionTimer reg(timer);
+
+
+    // string st;
+
+    // receive vertices
+    NgProfiler::StartTimer (timer_pts);
+    
+    Array<int> verts;
+    MyMPI_Recv (verts, 0, MPI_TAG_MESH+1);
+      
+    int numvert = verts.Size();
+    paralleltop -> SetNV (numvert);
+    
+    // INDEX_CLOSED_HASHTABLE<int> glob2loc_vert_ht (3*numvert+1);
+    INDEX_HASHTABLE<int> glob2loc_vert_ht (3*numvert+1);
+
+    for (int vert = 0; vert < numvert; vert++)
+      {
+	int globvert = verts[vert];
+	paralleltop->SetLoc2Glob_Vert ( vert+1, globvert  );
+	glob2loc_vert_ht.Set (globvert, vert+1);
+      }
+    
+    for (int i = 0; i < numvert; i++)
+      AddPoint (netgen::Point<3> (0,0,0));
+    
+    MPI_Datatype mptype = MeshPoint::MyGetMPIType();
+    MPI_Status status;
+    MPI_Recv( &points[1], numvert, mptype, 0, MPI_TAG_MESH+1, MPI_COMM_WORLD, &status);
+    
+    Array<int> dist_pnums;
+    MyMPI_Recv (dist_pnums, 0, MPI_TAG_MESH+1);
+    
+    for (int hi = 0; hi < dist_pnums.Size(); hi += 3)
+      paralleltop ->
+	SetDistantPNum (dist_pnums[hi+1], dist_pnums[hi], dist_pnums[hi+2]);
+    
+    NgProfiler::StopTimer (timer_pts);
+    *testout << "got " << numvert << " vertices" << endl;
+
+    {
+      Element el;
+      
+      Array<int> elarray;
+      MyMPI_Recv (elarray, 0, MPI_TAG_MESH+2);
+      
+      NgProfiler::RegionTimer reg(timer_els);
+
+      for (int ind = 0, elnum = 1; ind < elarray.Size(); elnum++)
+	{
+	  paralleltop->SetLoc2Glob_VolEl ( elnum,  elarray[ind++]);
+	  
+	  el.SetIndex(elarray[ind++]);
+	  el.SetNP(elarray[ind++]);
+	  
+	  for ( int j = 0; j < el.GetNP(); j++)
+	    el[j] = glob2loc_vert_ht.Get (elarray[ind++]); 
+	  
+	  AddVolumeElement (el);
+	}
+    }
+
+    {
+      Array<double> fddata;
+      MyMPI_Recv (fddata, 0, MPI_TAG_MESH+3);
+      for (int i = 0; i < fddata.Size(); i += 6)
+	{
+	  int faceind = AddFaceDescriptor (FaceDescriptor(int(fddata[i]), int(fddata[i+1]), int(fddata[i+2]), 0));
+	  GetFaceDescriptor(faceind).SetBCProperty (int(fddata[i+3]));
+	  GetFaceDescriptor(faceind).domin_singular = fddata[i+4];
+	  GetFaceDescriptor(faceind).domout_singular = fddata[i+5];
+	}
+    }
+
+    {
+      NgProfiler::RegionTimer reg(timer_sels);
+      Array<int> selbuf;
+
+      MyMPI_Recv ( selbuf, 0, MPI_TAG_MESH+4);
+      
+      int ii = 0;
+      int sel = 0;
+
+      int nlocsel = selbuf[ii++];
+      paralleltop -> SetNSE ( nlocsel );
+      
+      while (ii < selbuf.Size()-1)
+	{
+	  int globsel = selbuf[ii++];
+	  int faceind = selbuf[ii++];
+	  bool isghost = selbuf[ii++];
+	  int nep = selbuf[ii++];
+	  Element2d tri(nep);
+	  tri.SetIndex(faceind);
+	  for(int j = 1; j <= nep; j++)
+	    {
+	      tri.PNum(j) = glob2loc_vert_ht.Get (selbuf[ii++]);
+	      tri.GeomInfoPi(j).trignum = selbuf[ii++];
+	    }
+	  
+	  tri.SetGhost(isghost);
+	  
+	  paralleltop->SetLoc2Glob_SurfEl ( sel+1, globsel );
+	  AddSurfaceElement (tri);
+	  sel ++;
+	}
+    }
+    
+
+
+    {
+      Array<double> segmbuf;
+      MyMPI_Recv ( segmbuf, 0, MPI_TAG_MESH+5);
+
+      Segment seg;
+      int globsegi;
+      int ii = 0;
+      int segi = 1;
+      int nsegloc = int ( segmbuf.Size() / 14 ) ;
+      paralleltop -> SetNSegm ( nsegloc );
+      while ( ii < segmbuf.Size() )
+	{
+	  globsegi = int (segmbuf[ii++]);
+	  seg.si = int (segmbuf[ii++]);
+	  
+	  seg.pnums[0] = glob2loc_vert_ht.Get (int(segmbuf[ii++]));
+	  seg.pnums[1] = glob2loc_vert_ht.Get (int(segmbuf[ii++]));
+	  seg.geominfo[0].trignum = int( segmbuf[ii++] );
+	  seg.geominfo[1].trignum = int ( segmbuf[ii++]);
+	  seg.surfnr1 = int ( segmbuf[ii++]);
+	  seg.surfnr2 = int ( segmbuf[ii++]);
+	  seg.edgenr = int ( segmbuf[ii++]);
+	  seg.epgeominfo[0].dist = segmbuf[ii++];
+	  seg.epgeominfo[1].edgenr = int (segmbuf[ii++]);
+	  seg.epgeominfo[1].dist = segmbuf[ii++];
+	  
+	  seg.singedge_left = segmbuf[ii++];
+	  seg.singedge_right = segmbuf[ii++];
+	  
+	  seg.epgeominfo[0].edgenr = seg.epgeominfo[1].edgenr;
+	  
+	  seg.domin = seg.surfnr1;
+	  seg.domout = seg.surfnr2;
+	  if ( seg.pnums[0] >0 && seg.pnums[1] > 0 )
+	    {
+	      paralleltop-> SetLoc2Glob_Segm ( segi,  globsegi );
+	      
+	      AddSegment (seg);
+	      segi++;
+	    }
+	  
+	}
+    }
+    
+    MPI_Barrier(MPI_COMM_WORLD);
+
+    int timerloc = NgProfiler::CreateTimer ("Update local mesh");
+    int timerloc2 = NgProfiler::CreateTimer ("CalcSurfacesOfNode");
+
+    NgProfiler::RegionTimer regloc(timerloc);
+    PrintMessage (2, "Got ", GetNE(), " elements and ", GetNSE(), " surface elements");
+    // PrintMessage (2, "Got ", GetNSE(), " surface elements");
+
+    NgProfiler::StartTimer (timerloc2);
+
+    CalcSurfacesOfNode ();
+
+    NgProfiler::StopTimer (timerloc2);
+
+    topology -> Update();
+    clusters -> Update();
+    
+    SetNextMajorTimeStamp();
+    // paralleltop->Print();
+  }
+  
+
+
+  
+  
+  // distribute the mesh to the slave processors
+  // call it only for the master !
+  void Mesh :: Distribute ()
+  {
+    if (id != 0 || ntasks == 1 ) return;
+
+#ifdef METIS
+    ParallelMetis ();
+#else
+    for (ElementIndex ei = 0; ei < GetNE(); ei++)
+      (*this)[ei].SetPartition(ntasks * ei/GetNE() + 1);
+#endif
+
+    for (ElementIndex ei = 0; ei < GetNE(); ei++)
+      *testout << "el(" << ei << ") is in part " << (*this)[ei].GetPartition() << endl;
+    for (SurfaceElementIndex ei = 0; ei < GetNSE(); ei++)
+      *testout << "sel(" << int(ei) << ") is in part " << (*this)[ei].GetPartition() << endl;
+
+    // send partition
+    MyMPI_SendCmd ("mesh");
+    SendRecvMesh (); 
+
+    paralleltop -> UpdateCoarseGrid();
+    // paralleltop -> Print();
+  }
+  
+
+
+
+
+#ifdef METIS
+  void Mesh :: ParallelMetis ( )  
+  {
+    int timer = NgProfiler::CreateTimer ("Mesh::Partition");
+    NgProfiler::RegionTimer reg(timer);
+
+    PrintMessage (3, "Metis called");
+      
+    if (GetDimension() == 2) 
+      {
+	PartDualHybridMesh2D ( ); // neloc );
+	return;
+      }
+
+
+    idx_t ne = GetNE();
+    idx_t nn = GetNP();
+
+    if (ntasks <= 2 || ne <= 1)
+      {
+        if (ntasks == 1) return;
+        
+        for (int i=1; i<=ne; i++)
+          VolumeElement(i).SetPartition(1);
+
+        for (int i=1; i<=GetNSE(); i++)
+          SurfaceElement(i).SetPartition(1);
+
+        return;
+      }
+
+
+    bool uniform_els = true;
+
+    ELEMENT_TYPE elementtype = TET; 
+    for ( int el = 1; el <= GetNE(); el++ )
+      if ( VolumeElement(el).GetType() != elementtype )
+	{
+	  uniform_els = false;
+	  break;
+	}
+
+
+    if (!uniform_els)
+      {
+	PartHybridMesh ();  
+      }
+    else
+      {
+	
+	// uniform (TET) mesh,  JS
+	int npe = VolumeElement(1).GetNP();
+	Array<idxtype> elmnts(ne*npe);
+	
+	int etype;
+	if (elementtype == TET)
+	  etype = 2;
+	else if (elementtype == HEX)
+	  etype = 3;
+	
+    
+    for (int i=1; i<=ne; i++)
+      for (int j=1; j<=npe; j++)
+	elmnts[(i-1)*npe+(j-1)] = VolumeElement(i).PNum(j)-1;
+    
+    int numflag = 0;
+    int nparts = ntasks-1;
+    int ncommon = 3;
+    int edgecut;
+    Array<idxtype> epart(ne), npart(nn);
+
+//     if ( ntasks == 1 ) 
+//       {
+// 	(*this) = *mastermesh;
+// 	nparts = 4;	   
+// 	metis :: METIS_PartMeshDual (&ne, &nn, elmnts, &etype, &numflag, &nparts,
+// 				     &edgecut, epart, npart);
+// 	cout << "done" << endl;
+	
+// 	cout << "edge-cut: " << edgecut << ", balance: " << metis :: ComputeElementBalance(ne, nparts, epart) << endl;
+	
+// 	for (int i=1; i<=ne; i++)
+// 	  {
+// 	    mastermesh->VolumeElement(i).SetPartition(epart[i-1]);
+// 	  }
+	
+// 	return;
+//       }
+    
+
+
+
+    int timermetis = NgProfiler::CreateTimer ("Metis itself");
+    NgProfiler::StartTimer (timermetis);
+
+#ifdef METIS4
+    cout << "call metis ... " << flush;
+    METIS_PartMeshDual (&ne, &nn, &elmnts[0], &etype, &numflag, &nparts,
+			&edgecut, &epart[0], &npart[0]);
+#else
+    cout << "call metis-5 ... " << endl;
+    idx_t options[METIS_NOPTIONS];
+    
+    Array<idx_t> eptr(ne+1);
+    for (int j = 0; j < ne+1; j++)
+      eptr[j] = 4*j;
+
+    METIS_PartMeshDual (&ne, &nn, &eptr[0], &elmnts[0], NULL, NULL, &ncommon, &nparts,
+			NULL, NULL,
+			&edgecut, &epart[0], &npart[0]);
+#endif
+
+    NgProfiler::StopTimer (timermetis);
+
+    cout << "complete" << endl;
+#ifdef METIS4
+    cout << "edge-cut: " << edgecut << ", balance: " 
+     	 << ComputeElementBalance(ne, nparts, &epart[0]) << endl;
+#endif
+
+    // partition numbering by metis : 0 ...  ntasks - 1
+    // we want:                       1 ...  ntasks
+    for (int i=1; i<=ne; i++)
+      VolumeElement(i).SetPartition(epart[i-1] + 1);
+      }
+
+
+
+    for (int sei = 1; sei <= GetNSE(); sei++ )
+      {
+	int ei1, ei2;
+	GetTopology().GetSurface2VolumeElement (sei, ei1, ei2);
+	Element2d & sel = SurfaceElement (sei);
+
+        for (int j = 0; j < 2; j++)
+          {
+            int ei = (j == 0) ? ei1 : ei2;
+            if ( ei > 0 && ei <= GetNE() )
+              {
+		sel.SetPartition (VolumeElement(ei).GetPartition());
+		break;
+	      }
+	  }	
+      }
+    
+  }
+#endif
+
+
+  void Mesh :: PartHybridMesh () 
+  {
+#ifdef METIS
+    int ne = GetNE();
+    
+    int nn = GetNP();
+    int nedges = topology->GetNEdges();
+
+    idxtype  *xadj, * adjacency, *v_weights = NULL, *e_weights = NULL;
+
+    int weightflag = 0;
+    int numflag = 0;
+    int nparts = ntasks - 1;
+
+    int options[5];
+    options[0] = 0;
+    int edgecut;
+    idxtype * part;
+
+    xadj = new idxtype[nn+1];
+    part = new idxtype[nn];
+
+    Array<int> cnt(nn+1);
+    cnt = 0;
+
+    for ( int edge = 1; edge <= nedges; edge++ )
+      {
+	int v1, v2;
+	topology->GetEdgeVertices ( edge, v1, v2);
+	cnt[v1-1] ++;
+	cnt[v2-1] ++;
+      }
+
+    xadj[0] = 0;
+    for ( int n = 1; n <= nn; n++ )
+      {
+	xadj[n] = idxtype(xadj[n-1] + cnt[n-1]); 
+      }
+
+    adjacency = new idxtype[xadj[nn]];
+    cnt = 0;
+
+    for ( int edge = 1; edge <= nedges; edge++ )
+      {
+	int v1, v2;
+	topology->GetEdgeVertices ( edge, v1, v2);
+	adjacency[ xadj[v1-1] + cnt[v1-1] ] = v2-1;
+	adjacency[ xadj[v2-1] + cnt[v2-1] ] = v1-1;
+	cnt[v1-1]++;
+	cnt[v2-1]++;
+      }
+
+    for ( int vert = 0; vert < nn; vert++ )
+      {
+	FlatArray<int> array ( cnt[vert], &adjacency[ xadj[vert] ] );
+	BubbleSort(array);
+      }
+
+#ifdef METIS4
+    METIS_PartGraphKway ( &nn, xadj, adjacency, v_weights, e_weights, &weightflag, 
+			  &numflag, &nparts, options, &edgecut, part );
+#else
+    cout << "currently not supported (metis5), A" << endl;
+#endif
+
+    Array<int> nodesinpart(ntasks);
+
+    for ( int el = 1; el <= ne; el++ )
+      {
+	Element & volel = VolumeElement(el);
+	nodesinpart = 0;
+
+	//	VolumeElement(el).SetPartition(part[ volel[1] ] + 1);
+	
+	int el_np = volel.GetNP();
+	int partition = 0; 
+	for ( int i = 0; i < el_np; i++ )
+	  nodesinpart[ part[volel[i]-1]+1 ] ++;
+
+	for ( int i = 1; i < ntasks; i++ )
+	  if ( nodesinpart[i] > nodesinpart[partition] ) 
+	    partition = i;
+
+	volel.SetPartition(partition);
+
+      }
+
+    /*
+    for ( int i=1; i<=ne; i++)
+      {
+	neloc[ VolumeElement(i).GetPartition() ] ++;
+      }
+    */
+
+    delete [] xadj;
+    delete [] part;
+    delete [] adjacency;
+#else
+    cout << "parthybridmesh not available" << endl;
+#endif
+  }
+
+
+  void Mesh :: PartDualHybridMesh ( ) // Array<int> & neloc ) 
+  {
+#ifdef METIS
+    int ne = GetNE();
+    
+    // int nn = GetNP();
+    // int nedges = topology->GetNEdges();
+    int nfaces = topology->GetNFaces();
+
+    idxtype  *xadj, * adjacency, *v_weights = NULL, *e_weights = NULL;
+
+    int weightflag = 0;
+    int numflag = 0;
+    int nparts = ntasks - 1;
+
+    int options[5];
+    options[0] = 0;
+    int edgecut;
+    idxtype * part;
+
+    Array<int, 0> facevolels1(nfaces), facevolels2(nfaces);
+    facevolels1 = -1;
+    facevolels2 = -1;
+
+    Array<int, 0> elfaces;
+    xadj = new idxtype[ne+1];
+    part = new idxtype[ne];
+
+    Array<int, 0> cnt(ne+1);
+    cnt = 0;
+
+    for ( int el=1; el <= ne; el++ )
+      {
+	Element volel = VolumeElement(el);
+	topology->GetElementFaces(el, elfaces);
+	for ( int i = 0; i < elfaces.Size(); i++ )
+	  {
+	    if ( facevolels1[elfaces[i]-1] == -1 )
+	      facevolels1[elfaces[i]-1] = el;
+	    else
+	      {
+		facevolels2[elfaces[i]-1] = el;
+		cnt[facevolels1[elfaces[i]-1]-1]++;
+		cnt[facevolels2[elfaces[i]-1]-1]++;
+	      }
+	  }
+      }
+
+    xadj[0] = 0;
+    for ( int n = 1; n <= ne; n++ )
+      {
+	xadj[n] = idxtype(xadj[n-1] + cnt[n-1]); 
+      }
+
+    adjacency = new idxtype[xadj[ne]];
+    cnt = 0;
+
+    for ( int face = 1; face <= nfaces; face++ )
+      {
+	int e1, e2;
+	e1 = facevolels1[face-1];
+	e2 = facevolels2[face-1];
+	if ( e2 == -1 ) continue;
+	adjacency[ xadj[e1-1] + cnt[e1-1] ] = e2-1;
+	adjacency[ xadj[e2-1] + cnt[e2-1] ] = e1-1;
+	cnt[e1-1]++;
+	cnt[e2-1]++;
+      }
+
+    for ( int el = 0; el < ne; el++ )
+      {
+	FlatArray<int> array ( cnt[el], &adjacency[ xadj[el] ] );
+	BubbleSort(array);
+      }
+
+    int timermetis = NgProfiler::CreateTimer ("Metis itself");
+    NgProfiler::StartTimer (timermetis);
+
+#ifdef METIS4
+    METIS_PartGraphKway ( &ne, xadj, adjacency, v_weights, e_weights, &weightflag, 
+			  &numflag, &nparts, options, &edgecut, part );
+#else
+    cout << "currently not supported (metis5), B" << endl;
+#endif
+
+
+    NgProfiler::StopTimer (timermetis);
+
+    Array<int> nodesinpart(ntasks);
+
+    for ( int el = 1; el <= ne; el++ )
+      {
+	// Element & volel = VolumeElement(el);
+	nodesinpart = 0;
+
+	VolumeElement(el).SetPartition(part[el-1 ] + 1);
+	
+      }
+
+    /*    
+    for ( int i=1; i<=ne; i++)
+      {
+	neloc[ VolumeElement(i).GetPartition() ] ++;
+      }
+    */
+
+    delete [] xadj;
+    delete [] part;
+    delete [] adjacency;
+#else
+    cout << "partdualmesh not available" << endl;
+#endif
+
+  }
+
+
+
+
+
+  void Mesh :: PartDualHybridMesh2D ( ) 
+  {
+#ifdef METIS
+    int ne = GetNSE();
+    int nv = GetNV();
+
+    Array<idxtype> xadj(ne+1);
+    Array<idxtype> adjacency(ne*4);
+
+    // first, build the vertex 2 element table:
+    Array<int, PointIndex::BASE> cnt(nv);
+    cnt = 0;
+    for (SurfaceElementIndex sei = 0; sei < GetNSE(); sei++)
+      for (int j = 0; j < (*this)[sei].GetNP(); j++)
+	cnt[ (*this)[sei][j] ] ++;
+    
+    TABLE<SurfaceElementIndex, PointIndex::BASE> vert2els(cnt);
+    for (SurfaceElementIndex sei = 0; sei < GetNSE(); sei++)
+      for (int j = 0; j < (*this)[sei].GetNP(); j++)
+	vert2els.Add ((*this)[sei][j], sei);
+    
+
+    // find all neighbour elements
+    int cntnb = 0;
+    Array<int> marks(ne);   // to visit each neighbour just once
+    marks = -1;
+    for (SurfaceElementIndex sei = 0; sei < ne; sei++)
+      {
+	xadj[sei] = cntnb;
+	for (int j = 0; j < (*this)[sei].GetNP(); j++)
+	  {
+	    PointIndex vnr = (*this)[sei][j];
+
+	    // all elements with at least one common vertex
+	    for (int k = 0; k < vert2els[vnr].Size(); k++)   
+	      {
+		SurfaceElementIndex sei2 = vert2els[vnr][k];
+		if (sei == sei2) continue;
+		if (marks[sei2] == sei) continue;
+		
+		// neighbour, if two common vertices
+		int common = 0;
+		for (int m1 = 0; m1 < (*this)[sei].GetNP(); m1++)
+		  for (int m2 = 0; m2 < (*this)[sei2].GetNP(); m2++)
+		    if ( (*this)[sei][m1] == (*this)[sei2][m2])
+		      common++;
+		
+		if (common >= 2)
+		  {
+		    marks[sei2] = sei;     // mark as visited
+		    adjacency[cntnb++] = sei2;
+		  }
+	      }
+	  }
+      }
+    xadj[ne] = cntnb;
+
+    idxtype *v_weights = NULL, *e_weights = NULL;
+
+    int weightflag = 0;
+    int numflag = 0;
+    int nparts = ntasks - 1;
+
+    int options[5];
+    options[0] = 0;
+    int edgecut;
+    Array<idxtype> part(ne);
+
+    for ( int el = 0; el < ne; el++ )
+      BubbleSort (adjacency.Range (xadj[el], xadj[el+1]));
+
+#ifdef METIS4	
+    METIS_PartGraphKway ( &ne, &xadj[0], &adjacency[0], v_weights, e_weights, &weightflag, 
+			  &numflag, &nparts, options, &edgecut, &part[0] );
+#else
+    idx_t ncon = 1;
+    METIS_PartGraphKway ( &ne, &ncon, &xadj[0], &adjacency[0], 
+			  v_weights, NULL, e_weights, 
+			  &nparts, 
+			  NULL, NULL, NULL,
+			  &edgecut, &part[0] );
+#endif
+
+
+    for (SurfaceElementIndex sei = 0; sei < ne; sei++)
+      (*this) [sei].SetPartition (part[sei]+1);
+#else
+    cout << "partdualmesh not available" << endl;
+#endif
+
+  }
+
+
+
+
+
+
+  
+  void Mesh :: UpdateOverlap()
+  {
+    cout << "UpdateOverlap depreciated" << endl;
+  }
+
+
+
+
+
+
+
+
+}
+
+
+
+#endif
diff --git a/contrib/Netgen/libsrc/meshing/paralleltop.cpp b/contrib/Netgen/libsrc/meshing/paralleltop.cpp
new file mode 100644
index 0000000000..7467b03b36
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/paralleltop.cpp
@@ -0,0 +1,896 @@
+#ifdef PARALLEL
+
+
+#include <meshing.hpp>
+#include "paralleltop.hpp"
+
+
+namespace netgen
+{
+
+  static MPI_Group MPI_HIGHORDER_WORLD;
+  static MPI_Comm MPI_HIGHORDER_COMM;
+
+  void MyMPI_ExchangeTable (TABLE<int> & send_verts, 
+			    TABLE<int> & recv_verts, int tag,
+			    MPI_Comm comm = MPI_COMM_WORLD)
+  {
+    int ntasks, rank;
+    MPI_Comm_size(comm, &ntasks);
+    MPI_Comm_rank(comm, &rank);
+
+    Array<MPI_Request> requests;
+    for (int dest = 0; dest < ntasks; dest++)
+      if (dest != rank)
+	requests.Append (MyMPI_ISend (send_verts[dest], dest, tag, comm));
+
+    for (int i = 0; i < ntasks-1; i++)
+      {
+	MPI_Status status;
+	MPI_Probe (MPI_ANY_SOURCE, tag, comm, &status);
+	int size, src = status.MPI_SOURCE;
+	MPI_Get_count (&status, MPI_INT, &size);
+	recv_verts.SetEntrySize (src, size, sizeof(int));
+	requests.Append (MyMPI_IRecv (recv_verts[src], src, tag, comm));
+      }
+    MPI_Waitall (requests.Size(), &requests[0], MPI_STATUS_IGNORE);
+  }
+
+
+
+
+  void ParallelMeshTopology :: Reset ()
+  {
+    *testout << "ParallelMeshTopology::Reset" << endl;
+    
+    if ( ntasks == 1 ) return;
+    
+    int nvold = nv;
+    
+    ne = mesh.GetNE();
+    nv = mesh.GetNV();
+    nseg = mesh.GetNSeg();
+    nsurfel = mesh.GetNSE();
+    
+    ned = mesh.GetTopology().GetNEdges();
+    nfa = mesh.GetTopology().GetNFaces();
+    
+    loc2distedge.ChangeSize (ned);
+    for (int i = 0; i < ned; i++)
+      if (loc2distedge[i].Size() == 0)
+        loc2distedge.Add (i, -1);  // will be the global nr
+
+    loc2distface.ChangeSize (nfa);
+    for (int i = 0; i < nfa; i++)
+      if (loc2distface[i].Size() == 0)
+        loc2distface.Add (i, -1);  // will be the global nr
+
+    if ( nvold == nv ) return;
+
+    SetNV(nv);
+    SetNE(ne);
+  }
+
+
+  ParallelMeshTopology :: ~ParallelMeshTopology ()
+  {
+    ;
+  }
+
+
+
+  ParallelMeshTopology :: ParallelMeshTopology ( const netgen::Mesh & amesh )
+    : mesh(amesh)
+  {
+    ned = 0; 
+    nfa = 0; 
+    nv = 0;
+    ne = 0;
+    np = 0;
+    nseg = 0;
+    nsurfel = 0;
+    neglob = 0;
+    nvglob = 0;
+
+    nparel = 0;
+
+    coarseupdate = 0;
+  }
+
+ 
+
+  void ParallelMeshTopology ::  Print() const
+  {
+
+    (*testout) << endl <<  "TOPOLOGY FOR PARALLEL MESHES" << endl << endl;
+
+    for ( int i = 1; i <= nv; i++ )
+      if ( IsExchangeVert (i) )
+	{
+	  (*testout) << "exchange point  " << i << ":  global " << GetLoc2Glob_Vert(i) << endl;
+	  for ( int dest = 0; dest < ntasks; dest ++)
+	    if ( dest != id )
+ 	      if ( GetDistantPNum( dest, i  ) > 0 )
+ 		(*testout) << "   p" << dest << ": " << GetDistantPNum ( dest, i ) << endl; 
+	}
+
+    for ( int i = 1; i <= ned; i++ )
+      if ( IsExchangeEdge ( i ) )
+	{
+	  int v1, v2;
+	  mesh . GetTopology().GetEdgeVertices(i, v1, v2);
+	  (*testout) << "exchange edge  " << i << ":  global vertices "  << GetLoc2Glob_Vert(v1) << "  " 
+		     << GetLoc2Glob_Vert(v2) << endl;
+	  for ( int dest = 0; dest < ntasks; dest++)
+	    if ( GetDistantEdgeNum ( dest, i ) > 0 )
+	      if ( dest != id )
+		(*testout) << "   p" << dest << ": " << GetDistantEdgeNum ( dest, i ) << endl;
+	}
+
+    for ( int i = 1; i <= nfa; i++ )
+      if ( IsExchangeFace(i) )
+	{
+	  Array<int> facevert;
+	  mesh . GetTopology().GetFaceVertices(i, facevert);
+	    
+	  (*testout) << "exchange face  " << i << ":  global vertices " ;
+	  for ( int fi=0; fi < facevert.Size(); fi++)
+	    (*testout) << GetLoc2Glob_Vert(facevert[fi]) << "  ";
+	  (*testout) << endl; 
+	  for ( int dest = 0; dest < ntasks; dest++)
+	    if ( dest != id )
+	      {
+		if ( GetDistantFaceNum ( dest, i ) >= 0 )
+		  (*testout) << "   p" << dest << ": " << GetDistantFaceNum ( dest, i ) << endl;
+	      }
+	}
+
+
+    /*
+    for ( int i = 1; i < mesh.GetNE(); i++)
+      {
+	if ( !IsExchangeElement(i) ) continue;
+	Array<int> vert;
+	const Element & el = mesh.VolumeElement(i);
+
+	(*testout) << "parallel local element " << i << endl;
+	  
+	(*testout) << "vertices " ;
+	for ( int j = 0; j < el.GetNV(); j++)
+	  (*testout) << el.PNum(j+1)  << "  ";
+	(*testout) << "is ghost " << IsGhostEl(i) << endl;
+	(*testout) << endl;
+      }
+    */
+  }
+
+
+
+
+
+  int  ParallelMeshTopology :: GetDistantPNum ( int proc, int locpnum ) const
+  {
+    if ( proc == 0 )
+      return loc2distvert[locpnum][0];
+
+    for (int i = 1; i < loc2distvert[locpnum].Size(); i += 2)
+      if ( loc2distvert[locpnum][i] == proc )
+	return loc2distvert[locpnum][i+1];
+
+    return -1;
+  } 
+
+  int  ParallelMeshTopology :: GetDistantFaceNum ( int proc, int locfacenum ) const
+  {
+    if ( proc == 0 )
+      return loc2distface[locfacenum-1][0];
+
+    for ( int i = 1; i < loc2distface[locfacenum-1].Size(); i+=2 )
+      if ( loc2distface[locfacenum-1][i] == proc )
+	return loc2distface[locfacenum-1][i+1];
+
+    return -1;
+  } 
+
+  int  ParallelMeshTopology :: GetDistantEdgeNum ( int proc, int locedgenum ) const
+  {
+    if ( proc == 0 )
+      return loc2distedge[locedgenum-1][0];
+
+    for ( int i = 1; i < loc2distedge[locedgenum-1].Size(); i+=2 )
+      if ( loc2distedge[locedgenum-1][i] == proc )
+	return loc2distedge[locedgenum-1][i+1];
+
+    return -1;
+  } 
+
+  int  ParallelMeshTopology :: GetDistantElNum ( int proc, int locelnum ) const
+  {
+    if ( proc == 0 )
+      return loc2distel[locelnum-1][0];
+
+    for ( int i = 1; i < loc2distel[locelnum-1].Size(); i+=2 )
+      if ( loc2distel[locelnum-1][i] == proc )
+	return loc2distel[locelnum-1][i+1];
+
+    return -1;
+  } 
+
+
+
+  // gibt anzahl an distant pnums zurueck
+  // * pnums entspricht Array<int[2] >
+  int  ParallelMeshTopology :: GetDistantPNums ( int locpnum, int * distpnums ) const
+  {
+    distpnums[0] = 0;
+    distpnums[1] = loc2distvert[locpnum][0];
+    for ( int i = 1; i < loc2distvert[locpnum].Size(); i++ )
+      distpnums[i+1] = loc2distvert[locpnum][i];
+
+    int size = loc2distvert[locpnum].Size() / 2 + 1;
+    return size;
+  } 
+
+  int  ParallelMeshTopology :: GetDistantFaceNums ( int locfacenum, int * distfacenums ) const
+  {
+    distfacenums[0] = 0;
+    distfacenums[1] = loc2distface[locfacenum-1][0];
+
+    for ( int i = 1; i < loc2distface[locfacenum-1].Size(); i++ )
+      distfacenums[i+1] = loc2distface[locfacenum-1][i];
+
+    int size = loc2distface[locfacenum-1].Size() / 2 + 1;
+    return size;
+  } 
+
+  int  ParallelMeshTopology :: GetDistantEdgeNums ( int locedgenum, int * distedgenums ) const
+  {
+    distedgenums[0] = 0;
+    distedgenums[1] = loc2distedge[locedgenum-1][0];
+
+    for ( int i = 1; i < loc2distedge[locedgenum-1].Size(); i++ )
+      distedgenums[i+1] = loc2distedge[locedgenum-1][i];
+
+    int size = loc2distedge[locedgenum-1].Size() / 2 + 1;
+    return size;
+  } 
+
+  int  ParallelMeshTopology :: GetDistantElNums ( int locelnum, int * distelnums ) const
+  {
+    distelnums[0] = 0;
+    distelnums[1] = loc2distel[locelnum-1][0];
+
+    for ( int i = 1; i < loc2distel[locelnum-1].Size(); i++ )
+      distelnums[i+1] = loc2distel[locelnum-1][i];
+
+    int size = loc2distel[locelnum-1].Size() / 2 + 1;
+    return size;
+  } 
+
+
+
+
+  void ParallelMeshTopology :: SetDistantFaceNum ( int dest, int locnum, int distnum )
+  {
+    if ( dest == 0 )
+      {
+	loc2distface[locnum-1][0] = distnum;
+	return;
+      }
+
+    for ( int i = 1; i < loc2distface[locnum-1].Size(); i+=2 )
+      if ( loc2distface[locnum-1][i] == dest )
+	{
+	  loc2distface[locnum-1][i+1] = distnum;
+	  return;
+	}
+
+    loc2distface.Add(locnum-1, dest);
+    loc2distface.Add(locnum-1, distnum);
+  }
+
+  void ParallelMeshTopology :: SetDistantPNum ( int dest, int locnum, int distnum )
+  {
+    if ( dest == 0 )
+      {
+	loc2distvert[locnum][0] = distnum;  // HERE
+	return;
+      }
+
+    for ( int i = 1;  i < loc2distvert[locnum].Size(); i+=2 )
+      if ( loc2distvert[locnum][i] == dest )
+	{
+	  loc2distvert[locnum][i+1] = distnum;
+	  return;
+	}
+
+    loc2distvert.Add (locnum, dest);  
+    loc2distvert.Add (locnum, distnum); 
+  }
+
+
+  void ParallelMeshTopology :: SetDistantEdgeNum ( int dest, int locnum, int distnum )
+  {
+    if ( dest == 0 )
+      {
+	loc2distedge[locnum-1][0] = distnum;
+	return;
+      }
+
+    for ( int i = 1; i < loc2distedge[locnum-1].Size(); i+=2 )
+      if ( loc2distedge[locnum-1][i] == dest )
+	{
+	  loc2distedge[locnum-1][i+1] = distnum;
+	  return;
+	}
+
+    loc2distedge.Add (locnum-1, dest);
+    loc2distedge.Add (locnum-1, distnum);
+  }
+
+  void ParallelMeshTopology :: SetDistantEl ( int dest, int locnum, int distnum )
+  {
+    if ( dest == 0 )
+      {
+	loc2distel[locnum-1][0] = distnum;
+	return;
+      }
+
+    for ( int i = 1; i < loc2distel[locnum-1].Size(); i+=2 )
+      if ( loc2distel[locnum-1][i] == dest )
+	{
+	  loc2distel[locnum-1][i+1] = distnum;
+	  return;
+	}
+
+
+    loc2distel.Add (locnum-1, dest);
+    loc2distel.Add (locnum-1, distnum);
+  }
+
+  void ParallelMeshTopology :: SetDistantSurfEl ( int dest, int locnum, int distnum )
+  {
+    if ( dest == 0 )
+      {
+	loc2distsurfel[locnum-1][0] = distnum;
+	return;
+      }
+
+    for ( int i = 1;  i < loc2distsurfel[locnum-1].Size(); i+=2 )
+      if ( loc2distsurfel[locnum-1][i] == dest )
+	{
+	  loc2distsurfel[locnum-1][i+1] = distnum;
+	  return;
+	}
+
+    loc2distsurfel.Add (locnum-1, dest);
+    loc2distsurfel.Add (locnum-1, distnum);
+  }
+
+  void ParallelMeshTopology :: SetDistantSegm ( int dest, int locnum, int distnum )
+  {
+    if ( dest == 0 )
+      {
+	loc2distsegm[locnum-1][0] = distnum;
+	return;
+      }
+
+    for (int i = 1; i < loc2distsegm[locnum-1].Size(); i+=2 )
+      if ( loc2distsegm[locnum-1][i] == dest )
+	{
+	  loc2distsegm[locnum-1][i+1] = distnum;
+	  return;
+	}
+
+    loc2distsegm.Add (locnum-1, dest);
+    loc2distsegm.Add (locnum-1, distnum);
+  }
+
+  void ParallelMeshTopology :: GetVertNeighbours ( int vnum, Array<int> & dests ) const
+  {
+    dests.SetSize(0);
+    int i = 1;
+    while ( i < loc2distvert[vnum].Size() )
+      {
+	dests.Append ( loc2distvert[vnum][i] );
+	i+=2;
+      }
+  }
+
+
+  void ParallelMeshTopology :: Update ()
+  {
+    ne = mesh.GetNE();
+    nv = mesh.GetNV();
+    nseg = mesh.GetNSeg();
+    nsurfel = mesh.GetNSE();
+    
+    ned = mesh.GetTopology().GetNEdges();
+    nfa = mesh.GetTopology().GetNFaces();
+  }
+
+
+
+
+
+
+
+
+  void ParallelMeshTopology :: UpdateRefinement ()
+  {
+    ; 
+  }
+
+
+
+
+  void ParallelMeshTopology :: UpdateCoarseGridGlobal ()
+  {
+    if (id == 0)
+      PrintMessage ( 3, "UPDATE GLOBAL COARSEGRID STARTS" );      // JS
+
+
+    MPI_Group MPI_GROUP_WORLD;
+    int process_ranks[] = { 0 };
+    MPI_Comm_group (MPI_COMM_WORLD, &MPI_GROUP_WORLD);
+    MPI_Group_excl (MPI_GROUP_WORLD, 1, process_ranks, &MPI_HIGHORDER_WORLD);
+    MPI_Comm_create (MPI_COMM_WORLD, MPI_HIGHORDER_WORLD, &MPI_HIGHORDER_COMM);
+
+
+    int timer = NgProfiler::CreateTimer ("UpdateCoarseGridGlobal");
+    NgProfiler::RegionTimer reg(timer);
+
+
+    *testout << "ParallelMeshTopology :: UpdateCoarseGridGlobal" << endl;
+
+    const MeshTopology & topology = mesh.GetTopology();
+  
+    Array<int> sendarray, recvarray;
+
+    nfa = topology . GetNFaces();
+    ned = topology . GetNEdges();
+    np = mesh . GetNP();
+    nv = mesh . GetNV();
+    ne = mesh . GetNE();
+    nseg = mesh.GetNSeg();
+    nsurfel = mesh.GetNSE();
+
+    // low order processor - save mesh partition
+    if ( id == 0 )
+      {
+	for ( int eli = 1; eli <= ne; eli++ )
+	  loc2distel[eli-1][0] = eli;
+      
+	for ( int i = 1; i <= mesh .GetNV(); i++)
+	  loc2distvert[i][0] = i;
+      
+	for ( int i = 0; i < mesh . GetNSeg(); i++)
+	  loc2distsegm[i][0] = i+1;
+      
+	for ( int i = 0; i < mesh . GetNSE(); i++)
+	  loc2distsurfel[i][0] = i+1;
+      
+	for ( int i = 0; i < topology .GetNEdges(); i++)
+	  loc2distedge[i][0] = i+1;
+
+	for ( int i = 0; i < topology .GetNFaces(); i++)
+	  loc2distface[i][0] = i+1;
+      }
+
+
+    
+    if ( id == 0 )
+      {
+	sendarray.Append (nfa);
+	sendarray.Append (ned);
+
+	Array<int> edges, pnums, faces, elpnums;
+	sendarray.Append (ne);
+	for ( int el = 1; el <= ne; el++ )
+	  {
+	    topology.GetElementFaces (el, faces);
+	    topology.GetElementEdges ( el, edges );
+	    const Element & volel = mesh.VolumeElement (el);
+
+	    int globeli = GetLoc2Glob_VolEl(el);
+	    // cout << "el = " << el << ", globeli = " << globeli << endl;
+
+	    sendarray. Append ( globeli );
+	    sendarray. Append ( faces.Size() );
+	    sendarray. Append ( edges.Size() );
+	    sendarray. Append ( volel.GetNP() );
+
+	    for ( int i = 0; i < faces.Size(); i++ )
+	      sendarray. Append(faces[i] );
+	    for ( int i = 0; i < edges.Size(); i++ )
+	      sendarray. Append(edges[i] );
+
+	    for ( int i = 0; i < volel.GetNP(); i++ )
+	      if (id == 0)
+		sendarray. Append(volel[i] );
+	      else
+		sendarray. Append(GetLoc2Glob_Vert (volel[i]));
+	  }
+
+
+	sendarray.Append (nsurfel);
+	for (int el = 1; el <= nsurfel; el++)
+	  {
+	    topology.GetSurfaceElementEdges ( el, edges );
+	    const Element2d & surfel = mesh.SurfaceElement (el);
+
+	    sendarray. Append ( el );
+	    sendarray. Append ( edges.Size() );
+	    sendarray. Append ( surfel.GetNP() );
+
+	    for ( int i = 0; i < edges.Size(); i++ )
+	      sendarray. Append(edges[i] );
+
+	    for ( int i = 0; i < surfel.GetNP(); i++ )
+	      sendarray. Append(surfel[i] );
+	  }
+
+      }
+
+
+    if (id == 0)
+      MyMPI_Bcast ( sendarray );
+    else
+      MyMPI_Bcast ( recvarray );
+
+
+    if (id != 0)
+      {
+	Array<int,1> glob2loc_el;
+
+	glob2loc_el.SetSize (neglob);  
+	glob2loc_el = -1;
+	for ( int locel = 1; locel <= mesh.GetNE(); locel++)
+	  glob2loc_el[GetLoc2Glob_VolEl(locel)] = locel;
+
+	int ii = 0;
+	nfaglob = recvarray[ii++];
+	nedglob = recvarray[ii++];
+
+	Array<int> faces, edges;
+	Array<int> pnums, globalpnums;
+
+	int recv_ne = recvarray[ii++];
+	for (int hi = 0; hi < recv_ne; hi++)
+	  {
+	    int globvolel = recvarray[ii++];
+	    int distnfa = recvarray[ii++];
+	    int distned = recvarray[ii++];
+	    int distnp  = recvarray[ii++];
+
+	    int volel = glob2loc_el[globvolel];
+	    if (volel != -1)
+	      {
+		topology.GetElementFaces( volel, faces);
+		topology.GetElementEdges ( volel, edges);
+		const Element & volelement = mesh.VolumeElement (volel);
+
+		for ( int i = 0; i  < faces.Size(); i++)
+		  SetDistantFaceNum ( 0, faces[i], recvarray[ii++]);
+		
+		for ( int i = 0; i  < edges.Size(); i++)
+		  SetDistantEdgeNum ( 0, edges[i], recvarray[ii++]);
+
+		for ( int i = 0; i  < volelement.GetNP(); i++)
+		  SetDistantPNum ( 0, volelement[i], recvarray[ii++]);
+	      }
+	    else
+	      ii += distnfa + distned + distnp;
+	  }
+
+	
+	Array<int,1> glob2loc_sel;
+
+	int recv_nse = recvarray[ii++];
+	nseglob = recv_nse;
+
+	glob2loc_sel.SetSize (nseglob);  
+	glob2loc_sel = -1;
+	for ( int locel = 1; locel <= mesh.GetNSE(); locel++)
+	  glob2loc_sel[GetLoc2Glob_SurfEl(locel)] = locel;
+
+
+	for (int hi = 0; hi < recv_nse; hi++)
+	  {
+	    int globvolel = recvarray[ii++];
+	    int distned = recvarray[ii++];
+	    int distnp  = recvarray[ii++];
+
+	    int surfel = glob2loc_sel[globvolel];
+	    if (surfel != -1)
+	      {
+		topology.GetSurfaceElementEdges ( surfel, edges);
+		const Element2d & element = mesh.SurfaceElement (surfel);
+		
+		for ( int i = 0; i  < edges.Size(); i++)
+		  SetDistantEdgeNum ( 0, edges[i], recvarray[ii++]);
+
+		for ( int i = 0; i  < element.GetNP(); i++)
+		  SetDistantPNum ( 0, element[i], recvarray[ii++]);
+	      }
+	    else
+	      ii += distned + distnp;
+	  }
+
+
+      }
+    
+    if (id != 0)
+      {
+	*testout << "l2d - vert = " << loc2distvert << endl;
+	*testout << "l2d - edge = " << loc2distedge << endl;
+	*testout << "l2d - el = " << loc2distel << endl;
+	*testout << "l2d - sel = " << loc2distsurfel << endl;
+      }
+
+    coarseupdate = 1;
+  }
+
+
+
+
+
+
+  void ParallelMeshTopology :: UpdateCoarseGrid ()
+  {
+    static int timer = NgProfiler::CreateTimer ("UpdateCoarseGrid");
+    NgProfiler::RegionTimer reg(timer);
+
+
+    (*testout) << "UPDATE COARSE GRID PARALLEL TOPOLOGY " << endl;
+    if (id == 0)
+      PrintMessage (1, "UPDATE COARSE GRID PARALLEL TOPOLOGY ");
+
+
+    // find exchange edges - first send exchangeedges locnum, v1, v2
+    // receive distant distnum, v1, v2
+    // find matching
+    const MeshTopology & topology = mesh.GetTopology();
+
+    UpdateCoarseGridGlobal();
+    
+    MPI_Barrier (MPI_COMM_WORLD);
+
+    if ( id == 0 ) 
+      {
+	return;
+      }
+
+
+    Array<int> sendarray, recvarray;
+
+    nfa = topology . GetNFaces();
+    ned = topology . GetNEdges();
+    np = mesh . GetNP();
+    nv = mesh . GetNV();
+    ne = mesh . GetNE();
+    nseg = mesh.GetNSeg();
+    nsurfel = mesh.GetNSE();
+    
+
+    static int timerv = NgProfiler::CreateTimer ("UpdateCoarseGrid - ex vertices");
+    static int timere = NgProfiler::CreateTimer ("UpdateCoarseGrid - ex edges");
+    static int timerf = NgProfiler::CreateTimer ("UpdateCoarseGrid - ex faces");
+
+
+    Array<int,1> glob2loc;
+    Array<int> cnt_send(ntasks-1);
+
+    NgProfiler::StartTimer (timere);
+
+    // exchange edges
+    int maxedge = 0;
+    for (int edge = 1; edge <= ned; edge++)
+      maxedge = max (maxedge, GetDistantEdgeNum (0, edge));
+
+    glob2loc.SetSize (maxedge);
+    glob2loc = -1;
+    
+    for (int edge = 1; edge <= ned; edge++)
+      glob2loc[GetDistantEdgeNum(0, edge)] = edge;
+
+    cnt_send = 0;
+    int v1, v2;
+    for (int edge = 1; edge <= ned; edge++)
+      {
+	topology.GetEdgeVertices (edge, v1, v2);
+	for (int dest = 1; dest < ntasks; dest++)
+	  if (IsExchangeVert (dest, v1) && 
+	      IsExchangeVert (dest, v2))
+	    {
+	      cnt_send[dest-1]+=2;
+	    }
+      }
+    
+    TABLE<int> send_edges(cnt_send);
+    for (int edge = 1; edge <= ned; edge++)
+      {
+	topology.GetEdgeVertices (edge, v1, v2);
+	for (int dest = 1; dest < ntasks; dest++)
+	  {
+	    if (IsExchangeVert (dest, v1) && 
+		IsExchangeVert (dest, v2))
+	      {
+		send_edges.Add (dest-1, GetDistantEdgeNum(0, edge));
+		send_edges.Add (dest-1, edge);
+	      }
+	  }
+      }
+
+
+    // *testout << "send exchange edges: " << send_edges << endl;
+
+    TABLE<int> recv_edges(ntasks-1);
+    MyMPI_ExchangeTable (send_edges, recv_edges, MPI_TAG_MESH+9, MPI_HIGHORDER_COMM);
+
+    // *testout << "recv exchange edges: " << recv_edges << endl;
+
+    for (int sender = 1; sender < ntasks; sender ++)
+      if (id != sender)
+	{
+	  FlatArray<int> recvarray = recv_edges[sender-1];
+
+	  for (int ii = 0; ii < recvarray.Size(); )
+	    { 
+	      int globe = recvarray[ii++];
+	      int diste = recvarray[ii++];
+
+	      if (globe <= maxedge)
+		{
+		  int loce = glob2loc[globe];
+		  if (loce != -1)
+		    SetDistantEdgeNum (sender, loce, diste);
+		}
+	    }
+	} 
+
+
+ 
+    NgProfiler::StopTimer (timere);
+
+
+    MPI_Barrier (MPI_HIGHORDER_COMM);
+
+    if (mesh.GetDimension() == 3)
+      {
+
+    NgProfiler::StartTimer (timerf);
+
+    glob2loc.SetSize (nfaglob);
+    glob2loc = -1;
+    
+    for (int loc = 1; loc <= nfa; loc++)
+      glob2loc[GetDistantFaceNum(0, loc)] = loc;
+
+    cnt_send = 0;
+    Array<int> verts;
+    for (int face = 1; face <= nfa; face++)
+      {
+	topology.GetFaceVertices (face, verts);
+	for (int dest = 1; dest < ntasks; dest++)
+	  if (IsExchangeVert (dest, verts[0]) && 
+	      IsExchangeVert (dest, verts[1]) &&
+	      IsExchangeVert (dest, verts[2]))
+	    {
+	      cnt_send[dest-1]+=2;
+	    }
+      }
+    
+    TABLE<int> send_faces(cnt_send);
+    for (int face = 1; face <= nfa; face++)
+      {
+	topology.GetFaceVertices (face, verts);
+	for (int dest = 1; dest < ntasks; dest++)
+	  {
+	    if (IsExchangeVert (dest, verts[0]) && 
+		IsExchangeVert (dest, verts[1]) &&
+		IsExchangeVert (dest, verts[2]))
+	      {
+		send_faces.Add (dest-1, GetDistantFaceNum(0, face));
+		send_faces.Add (dest-1, face);
+	      }
+	  }
+      }
+    TABLE<int> recv_faces(ntasks-1);
+    MyMPI_ExchangeTable (send_faces, recv_faces, MPI_TAG_MESH+8, MPI_HIGHORDER_COMM);
+
+    // *testout << "send exchange faces: " << send_faces << endl;
+    // *testout << "recv exchange faces: " << recv_faces << endl;
+
+    for (int sender = 1; sender < ntasks; sender ++)
+      if (id != sender)
+	{
+	  FlatArray<int> recvarray = recv_faces[sender-1];
+
+	  for (int ii = 0; ii < recvarray.Size(); )
+	    { 
+	      int globf = recvarray[ii++];
+	      int distf = recvarray[ii++];
+	      int locf = glob2loc[globf];
+
+	      // *testout << "set distant face, sender = " << sender << ", locf = " << locf << "; distf = " << distf << endl;
+	      if (locf != -1)
+		SetDistantFaceNum (sender, locf, distf);
+	    }
+	} 
+
+
+    NgProfiler::StopTimer (timerf);
+      }
+
+
+    // set which elements are where for the master processor
+
+    coarseupdate = 1;
+  }
+
+
+
+
+
+  void ParallelMeshTopology :: UpdateTopology () 
+  {
+    ;
+  }
+
+
+
+
+
+
+
+  void ParallelMeshTopology :: SetNV ( const int anv )
+  {
+    *testout << "called setnv"  << endl
+             << "old size: " << loc2distvert.Size() << endl
+             << "new size: " << anv << endl;
+
+    loc2distvert.ChangeSize (anv);
+    for (int i = 1; i <= anv; i++)
+      if (loc2distvert.EntrySize(i) == 0)
+        loc2distvert.Add (i, -1);  // will be the global nr
+
+    nv = anv;
+  }
+
+  void ParallelMeshTopology :: SetNE ( const int ane )
+  {
+    loc2distel.ChangeSize (ane);
+    for (int i = 0; i < ane; i++)
+      if (loc2distel[i].Size() == 0)
+	loc2distel.Add (i, -1);   // will be the global nr
+    ne = ane;
+  }
+
+  void ParallelMeshTopology :: SetNSE ( int anse )
+  {
+    loc2distsurfel.ChangeSize (anse);
+    for (int i = 0; i < anse; i++)
+      if (loc2distsurfel[i].Size() == 0)
+        loc2distsurfel.Add (i, -1);  // will be the global nr
+
+    nsurfel = anse;
+  }
+
+  void ParallelMeshTopology :: SetNSegm ( int anseg )
+  {
+    loc2distsegm.ChangeSize (anseg);
+    for (int i = 0; i < anseg; i++)
+      if (loc2distsegm[i].Size() == 0)
+        loc2distsegm.Add (i, -1);  // will be the global nr
+
+    nseg = anseg;
+  }
+
+
+}
+
+
+
+
+#endif
diff --git a/contrib/Netgen/libsrc/meshing/paralleltop.hpp b/contrib/Netgen/libsrc/meshing/paralleltop.hpp
new file mode 100644
index 0000000000..52c03c5225
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/paralleltop.hpp
@@ -0,0 +1,156 @@
+#ifndef FILE_PARALLELTOP
+#define FILE_PARALLELTOP
+
+namespace netgen
+{
+
+  //  extern int ntasks;
+
+  class ParallelMeshTopology
+  {
+    const Mesh & mesh;
+
+    // number of local elements, vertices, points (?), edges, faces
+    int ne, nv, np, ned, nfa;
+
+    // number of local segments and surface elements
+    int nseg, nsurfel;
+
+    // number of global elements, vertices, ???,  faces
+    int neglob, nseglob, nvglob;
+    int nparel;
+    int nfaglob;
+    int nedglob;
+
+    /**
+       mapping from local to distant vertex number
+       each row of the table corresponds to one vertex
+       each row contains a list of pairs (procnr, dist_vnum)
+    */
+    TABLE<int,PointIndex::BASE> loc2distvert;
+    TABLE<int,0> loc2distedge, loc2distface;
+    TABLE<int,0> loc2distel, loc2distsegm, loc2distsurfel;
+
+    bool coarseupdate;
+
+  public:
+
+    ParallelMeshTopology (const Mesh & amesh);
+    ~ParallelMeshTopology ();
+
+    /// set number of local vertices, reset sizes of loc2dist_vert, isexchangevert...
+    void SetNV (int anv);
+    void SetNE (int ane);
+    void SetNSE (int anse);
+    void SetNSegm (int anseg);
+
+    void SetNVGlob ( int anvglob )   { nvglob = anvglob; }
+    void SetNEGlob ( int aneglob )   { neglob = aneglob; }
+    void SetNSEGlob ( int anseglob )   { nseglob = anseglob; }
+
+    int GetNVGlob ()  { return nvglob; }
+    int GetNEGlob ()  { return neglob; }
+
+
+    void Reset ();
+
+    void SetLoc2Glob_Vert   ( int locnum, int globnum ) { loc2distvert[locnum][0] = globnum; }
+    void SetLoc2Glob_VolEl  ( int locnum, int globnum ) { loc2distel[locnum-1][0] = globnum; }
+    void SetLoc2Glob_SurfEl ( int locnum, int globnum ) { loc2distsurfel[locnum-1][0] = globnum; }
+    void SetLoc2Glob_Segm   ( int locnum, int globnum ) { loc2distsegm[locnum-1][0] = globnum; }
+
+    int GetLoc2Glob_Vert  ( int locnum ) const { return loc2distvert[locnum][0]; }
+    int GetLoc2Glob_VolEl ( int locnum ) const { return loc2distel[locnum-1][0]; }
+    int GetLoc2Glob_SurfEl ( int locnum ) const { return loc2distsurfel[locnum-1][0]; }
+
+    void GetVertNeighbours ( int vnum, Array<int> & dests ) const;
+
+
+    int GetNDistantPNums ( int locpnum ) const       
+    { return loc2distvert[locpnum].Size() / 2 + 1; } 
+
+    int GetNDistantFaceNums ( int locfacenum ) const 
+    { return loc2distface[locfacenum-1].Size() / 2 + 1; } 
+
+    int GetNDistantEdgeNums ( int locedgenum ) const  
+    { return loc2distedge[locedgenum-1].Size() / 2 + 1; }
+
+    int GetNDistantElNums ( int locelnum ) const      
+    { return loc2distel[locelnum-1].Size() / 2 + 1; }
+
+    int GetDistantPNum ( int proc, int locpnum ) const;
+    int GetDistantEdgeNum ( int proc, int locedgenum ) const;
+    int GetDistantFaceNum ( int proc, int locedgenum ) const;
+    int GetDistantElNum ( int proc, int locelnum ) const;
+
+    int GetDistantPNums ( int locpnum, int * distpnums ) const;
+    int GetDistantEdgeNums ( int locedgenum, int * distedgenums ) const;
+    int GetDistantFaceNums ( int locedgenum, int * distfacenums ) const;
+    int GetDistantElNums ( int locelnum, int * distfacenums ) const;
+
+    void Print() const;
+
+
+    bool IsExchangeVert ( PointIndex vnum ) const  { return loc2distvert[vnum].Size() > 1; }
+    bool IsExchangeEdge ( int ednum ) const  { return loc2distedge[ednum-1].Size() > 1; }
+    bool IsExchangeFace ( int fnum ) const   { return loc2distface[fnum-1].Size() > 1; }
+    bool IsExchangeElement ( int elnum ) const   { return false; }
+
+
+    bool IsExchangeSEl ( int selnum ) const { return loc2distsurfel[selnum-1].Size() > 1; }
+
+
+    bool IsExchangeVert (int dest, int vnum ) const
+    {
+      FlatArray<int> exchange = loc2distvert[vnum];
+      for (int i = 1; i < exchange.Size(); i += 2)
+	if (exchange[i] == dest) return true;
+      return false;
+    }
+
+    bool IsExchangeEdge (int dest, int ednum ) const
+    {
+      FlatArray<int> exchange = loc2distedge[ednum-1];
+      for (int i = 1; i < exchange.Size(); i += 2)
+	if (exchange[i] == dest) return true;
+      return false;
+    }
+
+    bool IsExchangeFace (int dest, int fnum ) const
+    {
+      FlatArray<int> exchange = loc2distface[fnum-1];
+      for (int i = 1; i < exchange.Size(); i += 2)
+	if (exchange[i] == dest) return true;
+      return false;
+    }
+
+    bool IsExchangeElement (int dest, int elnum ) const  { return false; }
+
+    void Update();
+
+    void UpdateCoarseGrid();
+    void UpdateRefinement ();
+    void UpdateTopology ();
+    void UpdateExchangeElements();
+
+    void UpdateCoarseGridGlobal();
+
+    bool DoCoarseUpdate() const { return !coarseupdate; }
+
+    void SetDistantFaceNum ( int dest, int locnum, int distnum );
+    void SetDistantPNum ( int dest, int locnum, int distnum );
+    void SetDistantEdgeNum ( int dest, int locnum, int distnum );
+    void SetDistantEl ( int dest, int locnum, int distnum );
+    void SetDistantSurfEl ( int dest, int locnum, int distnum );
+    void SetDistantSegm ( int dest, int locnum, int distnum );
+
+    bool IsGhostEl ( int elnum ) const   { return mesh.VolumeElement(elnum).IsGhost(); }
+  };
+ 
+
+}
+
+
+
+
+#endif
diff --git a/contrib/Netgen/libsrc/meshing/parser2.cpp b/contrib/Netgen/libsrc/meshing/parser2.cpp
new file mode 100644
index 0000000000..55bd1a5d6e
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/parser2.cpp
@@ -0,0 +1,605 @@
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+#ifdef WIN32
+#define COMMASIGN ':'
+#else
+#define COMMASIGN ','
+#endif
+
+
+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 == COMMASIGN)
+	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);
+
+  // if(name != NULL) 
+  delete [] name;
+  name = new char[strlen (buf) + 1];
+  strcpy (name, buf);
+  //(*testout) << "name " << name << endl;
+  //  (*mycout) << "Rule " << name << " found." << endl;
+
+  do
+    {
+      ist >> buf;
+
+      //(*testout) << "buf " << buf << endl;
+
+      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 = 1.0;
+	      tolerances.Elem(noldp).f2 = 0;
+	      tolerances.Elem(noldp).f3 = 1.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;    // ')'
+
+
+	      //(*testout) << "read line " << lin.I1() << " " << lin.I2() << endl;
+	      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;
+
+	      //(*testout) << "mapl1" << endl; 
+	      ist >> ch;
+	      while (ch != ';')
+		{
+		  //(*testout) << "working on character \""<<ch<<"\""<< endl;
+		  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'
+		      //(*testout) << "read del" << endl;
+		    }
+
+		  ist >> ch;
+		  //(*testout) << "read character \""<<ch<<"\""<< endl;
+		}
+
+	      ist >> ch;
+	      //(*testout) << "read next character \""<<ch<<"\""<< endl;
+	    }
+	  
+
+	  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 == COMMASIGN)
+		{
+		  ist >> elements.Last().PNum(2);
+		  ist >> ch;    // ','
+		}
+	      if (ch == COMMASIGN)
+		{
+		  ist >> elements.Last().PNum(3);
+		  ist >> ch;    // ','
+		}
+	      if (ch == COMMASIGN)
+		{
+		  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));
+      }
+  }
+
+  oldutofreearea_i.SetSize (10);
+  freezone_i.SetSize (10);
+
+  for (i = 0; i < oldutofreearea_i.Size(); i++)
+    {
+      double lam1 = 1.0/(i+1);
+
+      oldutofreearea_i[i] = new DenseMatrix (oldutofreearea.Height(), oldutofreearea.Width());
+      DenseMatrix & mati = *oldutofreearea_i[i];
+      for (j = 0; j < oldutofreearea.Height(); j++)
+	for (int k = 0; k < oldutofreearea.Width(); k++)
+	  mati(j,k) = lam1 * oldutofreearea(j,k) + (1 - lam1) * oldutofreearealimit(j,k);
+
+      freezone_i[i] = new Array<Point2d> (freezone.Size());
+      Array<Point2d> & fzi = *freezone_i[i];
+      for (int j = 0; j < freezone.Size(); j++)
+	fzi[j] = freezonelimit[j] + lam1 * (freezone[j] - freezonelimit[j]);
+    }
+}
+
+
+
+
+extern const char * triarules[];
+extern const char * quadrules[];
+
+void Meshing2 :: LoadRules (const char * filename, bool quad)
+{
+  char buf[256];
+  istream * ist;
+  //char *tr1 = NULL;
+  string tr1;
+
+  /*
+  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)
+      if (!quad)
+	{
+	  hcp = triarules;
+	  PrintMessage (3, "load internal triangle rules");
+	}
+      else
+	{
+	  hcp = quadrules;
+	  PrintMessage (3, "load internal quad rules");
+	  // LoadRules ("rules/quad.rls");
+	}
+
+      size_t len = 0;
+      while (*hcp)
+	{
+	  //	  (*testout) << "POS2 *hcp " << *hcp << endl;
+	  len += strlen (*hcp);
+	  hcp++;
+	}
+      //tr1 = new char[len+1];
+      //tr1[0] = 0;
+      tr1.reserve(len+1);
+
+
+      // if (!mparam.quad)
+      if (!quad)
+	hcp = triarules;
+      else
+	hcp = quadrules;
+
+
+      //char * tt1 = tr1;
+      while (*hcp)
+	{
+	  //strcat (tt1, *hcp);
+	  //tt1 += strlen (*hcp);
+	  tr1.append(*hcp);
+	  hcp++;
+	}
+      
+#ifdef WIN32
+      // VC++ 2005 workaround
+	  for(string::size_type i=0; i<tr1.size(); i++)
+	if(tr1[i] == ',')
+	  tr1[i] = ':';
+#endif
+
+      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)
+	{
+	  //(*testout) << "found rule" << endl;
+	  netrule * rule = new netrule;
+	  //(*testout) << "fr1" << endl;
+	  rule -> LoadRule(*ist);
+	  //(*testout) << "fr2" << endl;
+	  
+	  rules.Append (rule);
+	}
+      //(*testout) << "loop" << endl;
+    }
+  //(*testout) << "POS3" << endl;
+
+  delete ist;
+  //delete [] tr1;
+}
+
+}
diff --git a/contrib/Netgen/libsrc/meshing/parser3.cpp b/contrib/Netgen/libsrc/meshing/parser3.cpp
new file mode 100644
index 0000000000..c6ccba4a68
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/parser3.cpp
@@ -0,0 +1,1019 @@
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+#ifdef WIN32
+#define COMMASIGN ':'
+#else
+#define COMMASIGN ','
+#endif
+
+
+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 == COMMASIGN)
+	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);
+
+  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, "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 == COMMASIGN)
+		{
+		  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 == COMMASIGN)
+		{
+		  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 k, nfp;
+
+	  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 k, nfp;
+	  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 == COMMASIGN)
+		{
+		  //		  elements.Last().SetNP(2);
+		  ist >> elements.Last().PNum(2);
+		  ist >> ch;    // ','
+		}
+	      if (ch == COMMASIGN)
+		{
+		  //		  elements.Last().SetNP(3);
+		  ist >> elements.Last().PNum(3);
+		  ist >> ch;    // ','
+		}
+	      if (ch == COMMASIGN)
+		{
+		  //		  elements.Last().SetNP(4);
+		  elements.Last().SetType(TET);
+		  ist >> elements.Last().PNum(4);
+		  ist >> ch;    // ','
+		}
+	      if (ch == COMMASIGN)
+		{
+		  //		  elements.Last().SetNP(5);
+		  elements.Last().SetType(PYRAMID);
+		  ist >> elements.Last().PNum(5);
+		  ist >> ch;    // ','
+		}
+	      if (ch == COMMASIGN)
+		{
+		  //		  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 (int i = 1; i <= 3; i++)
+	{
+	  for (int j = 1; j <= points.Size(); j++)
+	    vp(j-1) = points.Get(j).X(i);
+	  oldutofreezone->Mult(vp, vfp);
+	  for (int j = 1; j <= freezone.Size(); j++)
+	    freezone.Elem(j).X(i) = vfp(j-1);
+	}
+      //      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));
+    }
+
+
+  {
+    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 <= edges.Size(); i++)
+	  {
+	    int pi1 = edges.Get(i).i1;
+	    int pi2 = edges.Get(i).i2;
+
+	    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;
+	      }
+	  }
+	
+
+	for (i = 1; i <= elements.Size(); i++)
+	  if (elements.Get(i).GetNP() == 6)  // prism rule
+	    {
+	      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);
+
+    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));
+      }
+
+    // (*testout) << "rule " << name << ", pnear = " << pnearness << endl;
+  }
+
+  
+  //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 ed(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))
+			{
+			  ed.I(1) = f1.I(f11);
+			  ed.I(2) = f1.I(f12);
+			}
+	      //	      (*testout) << "ed = " << ed.I(1) << "-" << ed.I(2) << endl;
+	      //	      (*testout) << "ind = " << ind << " ed = " << ed << endl;
+	      for (int eli = 1; eli <= GetNOldF(); eli++)
+		{
+		  if (GetNP(eli) == 4)
+		    {
+		      for (int elr = 1; elr <= 4; elr++)
+			{
+			  if (GetPointNrMod (eli, elr) == ed.I(1) &&
+			      GetPointNrMod (eli, elr+2) == ed.I(2))
+			    {
+			      /*
+			      (*testout) << "ed is diagonal of rectangle" << endl;
+			      (*testout) << "ed = " << ed.I(1) << "-" << ed.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; 
+      size_t 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++;
+	}
+
+
+#ifdef WIN32
+      // VC++ 2005 workaround
+      for(size_t i=0; i<len; i++)
+	if(tr1[i] == ',')
+	  tr1[i] = ':';
+#endif
+
+      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/contrib/Netgen/libsrc/meshing/prism2rls.cpp b/contrib/Netgen/libsrc/meshing/prism2rls.cpp
new file mode 100644
index 0000000000..7e696554c0
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/prism2rls.cpp
@@ -0,0 +1,457 @@
+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",\
+"freeset\n",\
+"1 2 4 5 6 7;\n",\
+"\n",\
+"freeset\n",\
+"2 3 4 5 6 8;\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",\
+"freeset\n",\
+"1 2 4 5 6 7;\n",\
+"\n",\
+"freeset\n",\
+"2 3 4 5 6 8;\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 100\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/contrib/Netgen/libsrc/meshing/prism2rls_2.cpp b/contrib/Netgen/libsrc/meshing/prism2rls_2.cpp
new file mode 100644
index 0000000000..baf0bef388
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/prism2rls_2.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/contrib/Netgen/libsrc/meshing/pyramid2rls.cpp b/contrib/Netgen/libsrc/meshing/pyramid2rls.cpp
new file mode 100644
index 0000000000..a97e7f13e5
--- /dev/null
+++ b/contrib/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/contrib/Netgen/libsrc/meshing/pyramidrls.cpp b/contrib/Netgen/libsrc/meshing/pyramidrls.cpp
new file mode 100644
index 0000000000..d4e997c1fe
--- /dev/null
+++ b/contrib/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/contrib/Netgen/libsrc/meshing/quadrls.cpp b/contrib/Netgen/libsrc/meshing/quadrls.cpp
new file mode 100644
index 0000000000..1c2cd23b77
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/quadrls.cpp
@@ -0,0 +1,887 @@
+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 (2)\"\n",\
+"\n",\
+"quality 2\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 X2, 1 X3 } { 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.5) { 0.7 X2, 0.5 X3 } { 0.5 Y3 };\n",\
+"(1, 1) { 1 X3 } { 1 Y3 };\n",\
+"(-0.5, 1.5) { -2 X2, 1.5 X3 } { 1.5 Y3 };\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 X2, 1 X3 } { 1 Y3 };\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4);\n",\
+"\n",\
+"\n",\
+"orientations\n",\
+"(1, 2, 3);\n",\
+"\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"rule \"Quad P Right (150)\"\n",\
+"\n",\
+"quality 150\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 X2, -1 X3 } { 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.5) { 0.7 X2, 0.5 X3 } { 0.5 Y3 };\n",\
+"(1, 1) { 1 X3 } { 1 Y3 };\n",\
+"(-0.5, 1.5) { -2 X2, 1.5 X3 } { 1.5 Y3 };\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 X2, -1 X3 } { 1 Y3 };\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4);\n",\
+"\n",\
+"orientations\n",\
+"(1, 2, 3);\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"rule \"Quad Right PL (2)\"\n",\
+"\n",\
+"quality 2\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.1 X2, 0.6 X3, 0.6 X4 } { -0.1 Y2, 0.6 Y3, 0.6 Y4 };\n",\
+"(0, 1) { 1 X4 } { 1 Y4 };\n",\
+"(-0.2, 0.5) { -0.1 X2, -0.1 X3, 0.6 X4 } { -0.1 Y2, -0.1 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",\
+"orientations\n",\
+"(1, 2, 3);\n",\
+"(1, 3, 4);\n",\
+"(1, 2, 4);\n",\
+"(4, 2, 3);\n",\
+"\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 (2)\"\n",\
+"\n",\
+"quality 2\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",\
+"rule \"Left P Quad (150)\"\n",\
+"\n",\
+"quality 150\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 (2)\"\n",\
+"\n",\
+"quality 2\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.1 X3 } { 0.6 Y2, 0.6 Y4, -0.1 Y3 };\n",\
+"(1, 1) { 1 X4 } { 1 Y4 };\n",\
+"(0.5, 1.2) { -0.1 X2, 0.6 X3, 0.6 X4 } { -0.1 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",\
+"orientations\n",\
+"(1, 2, 4);\n",\
+"(1, 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 (2)\"\n",\
+"\n",\
+"quality 2\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",\
+"orientations\n",\
+"(1, 3, 4);\n",\
+"(2, 3, 4);\n",\
+"(1, 2, 3);\n",\
+"(1, 2, 4);\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Triangle Vis A Vis (200)\"\n",\
+"\n",\
+"quality 200\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",\
+"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/contrib/Netgen/libsrc/meshing/refine.cpp b/contrib/Netgen/libsrc/meshing/refine.cpp
new file mode 100644
index 0000000000..403e45325b
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/refine.cpp
@@ -0,0 +1,757 @@
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+
+namespace netgen
+{
+
+  void Refinement :: Refine (Mesh & mesh) const
+  {
+    const_cast<Refinement&> (*this).Refine(mesh);
+  }
+
+
+  void Refinement :: Refine (Mesh & mesh)
+  {
+    // reduce 2nd order
+    mesh.ComputeNVertices();
+    mesh.SetNP(mesh.GetNV());
+
+
+    INDEX_2_HASHTABLE<int> between(mesh.GetNP() + 5);
+      
+    int oldne, oldns, oldnf;
+
+    // refine edges
+
+    Array<EdgePointGeomInfo,PointIndex::BASE> epgi;
+
+    oldns = mesh.GetNSeg();
+    for (SegmentIndex si = 0; si < oldns; si++)
+      {
+	const Segment & el = mesh.LineSegment(si);
+
+	INDEX_2 i2 = INDEX_2::Sort(el[0], el[1]);
+	PointIndex pinew;
+	EdgePointGeomInfo ngi;
+
+	if (between.Used(i2))
+	  {
+	    pinew = between.Get(i2);
+	    ngi = epgi[pinew]; 
+	  }
+	else
+	  {
+	    Point<3> pnew;
+	    PointBetween (mesh.Point (el[0]),
+			  mesh.Point (el[1]), 0.5,
+			  el.surfnr1, el.surfnr2,
+			  el.epgeominfo[0], el.epgeominfo[1],
+			  pnew, ngi);
+
+	    pinew = mesh.AddPoint (pnew);
+	    between.Set (i2, pinew);
+
+
+	    if (pinew >= epgi.Size()+PointIndex::BASE)
+	      epgi.SetSize (pinew+1-PointIndex::BASE);
+	    epgi[pinew] = ngi;
+	  }
+
+	Segment ns1 = el;
+	Segment ns2 = el;
+	ns1[1] = pinew;
+	ns1.epgeominfo[1] = ngi;
+	ns2[0] = pinew;
+	ns2.epgeominfo[0] = ngi;
+
+	mesh.LineSegment(si) = ns1;
+	mesh.AddSegment (ns2);
+      }
+
+    // refine surface elements
+    Array<PointGeomInfo,PointIndex::BASE> surfgi (8*mesh.GetNP());
+    for (int i = PointIndex::BASE;
+	 i < surfgi.Size()+PointIndex::BASE; i++)
+      surfgi[i].trignum = -1;
+
+
+    oldnf = mesh.GetNSE();
+    for (SurfaceElementIndex sei = 0; sei < oldnf; sei++)
+      {
+	int j, k;
+	const Element2d & el = mesh.SurfaceElement(sei);
+
+	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++)
+		{
+		  PointIndex pi1 = pnums.Elem(betw[j][0]);
+		  PointIndex pi2 = pnums.Elem(betw[j][1]);
+
+		  INDEX_2 i2 (pi1, pi2);
+		  i2.Sort();
+
+		  Point<3> 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);
+		}
+
+
+	      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(sei) = nel;
+		  else
+		    mesh.AddSurfaceElement(nel);
+		}
+	      break;
+	    }
+	  case QUAD:
+	  case QUAD6:
+	  case QUAD8:
+	    {
+	      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 },
+		  { 5, 7, 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
+		    {
+		      Point<3> 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(sei) = nel;
+		  else
+		    mesh.AddSurfaceElement(nel);
+		}
+	      break;
+	    }
+	  default:
+	    PrintSysError ("Refine: undefined surface element type ", int(el.GetType()));
+	  }
+      }
+
+    // refine volume elements
+    oldne = mesh.GetNE();
+    for (ElementIndex ei = 0; ei < oldne; ei++)
+      {
+	int j, k;
+
+	const Element & el = mesh.VolumeElement(ei);
+	switch (el.GetType())
+	  {
+	  case TET:
+	  case TET10:
+	    {
+	     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 bool reverse[8] =
+	   {
+	      false, false, false, false, false, true, false, true
+	   };
+
+	   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 = !nel.flags.reverse;
+		swap (nel.PNum(3), nel.PNum(4));
+	      }
+
+	      if (j == 0)
+	        mesh.VolumeElement(ei) = nel;
+	      else
+	        mesh.AddVolumeElement (nel);
+	    }
+	    break;
+          }
+          case HEX:
+          {
+	     ArrayMem<int,27> pnums(27);
+	     static int betw[13][3] =
+	     { { 1, 2, 9 },
+	       { 3, 4, 10 },
+	       { 4, 1, 11 },
+               { 2, 3, 12 },
+	       { 5, 6, 13 },
+	       { 7, 8, 14 },
+	       { 8, 5, 15 },
+	       { 6, 7, 16 },
+	       { 1, 5, 17 },
+	       { 2, 6, 18 },
+	       { 3, 7, 19 },
+	       { 4, 8, 20 },
+	       { 2, 8, 21 },
+	       };
+
+             /*
+	     static int fbetw[12][3] =
+	     { { 1, 3, 22 },
+	       { 2, 4, 22 },
+	       { 5, 7, 23 },
+               { 6, 8, 23 },
+	       { 1, 6, 24 },
+	       { 2, 5, 24 },
+	       { 2, 7, 25 },
+	       { 3, 6, 25 },
+	       { 3, 8, 26 },
+	       { 4, 7, 26 },
+	       { 1, 8, 27 },
+	       { 4, 5, 27 },
+	       };
+             */
+             
+             // udpated by anonymous supporter, donations please to Karo W.
+             static int fbetw[12][3] =
+               { { 11, 12, 22 },
+                 { 9, 10, 22 },
+                 { 13, 14, 23 },
+                 { 15, 16, 23 },
+                 { 9, 13, 24 },
+                 { 17, 18, 24 },
+                 { 12, 16, 25 },
+                 { 18, 19, 25 },
+                 { 19, 20, 26 },
+                 { 10, 14, 26 },
+                 { 11, 15, 27 },
+                 { 17, 20, 27 },
+               };
+
+	     pnums = -1;
+
+	     for (j = 1; j <= 8; j++)
+	     pnums.Elem(j) = el.PNum(j);
+
+
+	     for (j = 0; j < 13; 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(9+j) = between.Get(i2);
+	       else
+	       {
+		  pnums.Elem(9+j) = mesh.AddPoint
+		  (Center (mesh.Point(i2.I1()),
+			   mesh.Point(i2.I2())));
+		  between.Set (i2, pnums.Elem(9+j));
+	       }
+	    }
+
+	    for (j = 0; j < 6; j++)
+	    {
+	       INDEX_2 i2a, i2b;
+	       i2a.I1() = pnums.Get(fbetw[2*j][0]);
+	       i2a.I2() = pnums.Get(fbetw[2*j][1]);
+	       i2a.Sort();
+	       i2b.I1() = pnums.Get(fbetw[2*j+1][0]);
+	       i2b.I2() = pnums.Get(fbetw[2*j+1][1]);
+	       i2b.Sort();
+
+	       if (between.Used(i2a))
+		 pnums.Elem(22+j) = between.Get(i2a);
+	       else if (between.Used(i2b))
+		 pnums.Elem(22+j) = between.Get(i2b);
+	       else
+		 {
+		   pnums.Elem(22+j) = mesh.AddPoint
+		     (Center (mesh.Point(i2a.I1()),
+			      mesh.Point(i2a.I2())));
+
+		   between.Set (i2a, pnums.Elem(22+j));
+		 }
+	    }
+
+	    static int reftab[8][8] =
+	    { { 1, 9, 22, 11, 17, 24, 21, 27 },
+	      { 9, 2, 12, 22, 24, 18, 25, 21 },
+	      { 11, 22, 10, 4, 27, 21, 26, 20},
+	      { 22, 12, 3, 10, 21, 25, 19, 26},
+	      { 17, 24, 21, 27, 5, 13, 23, 15},
+	      { 24, 18, 25, 21, 13, 6, 16, 23},
+	      { 27, 21, 26, 20, 15, 23, 14, 8},
+	      { 21, 25, 19, 26, 23, 16, 7, 14} };
+
+
+	   int ind = el.GetIndex();
+	   for (j = 0; j < 8; j++)
+	   {
+	      Element nel(HEX);
+	      for (k = 1; k <= 8; k++)
+	        nel.PNum(k) = pnums.Get(reftab[j][k-1]);
+	      nel.SetIndex(ind);
+
+              if (j == 0)
+	        mesh.VolumeElement(ei) = nel;
+	      else
+	        mesh.AddVolumeElement (nel);
+           }
+           break;
+	  }
+	  case PRISM:
+          {
+	     ArrayMem<int,18> pnums(18);
+	     static int betw[9][3] =
+	     { { 3, 1, 7 },
+	       { 1, 2, 8 },
+	       { 3, 2, 9 },
+               { 6, 4, 10 },
+	       { 4, 5, 11 },
+	       { 6, 5, 12 },
+	       { 1, 4, 13 },
+	       { 3, 6, 14 },
+	       { 2, 5, 15 },
+	       };
+
+// he: 15.jul 08, old version is wrong
+//                produces double points ad quad faces and inconsistent mesh
+// 	     static int fbetw[6][3] =
+// 	     { { 1, 6, 16 },
+// 	       { 3, 4, 16 },
+// 	       { 1, 5, 17 },
+//                { 2, 4, 17 },
+// 	       { 2, 6, 18 },
+// 	       { 3, 5, 18 },
+// 	       };
+           
+           static int fbetw[6][3] =
+           { { 7, 10, 16 },
+           { 14, 13, 16 },
+           { 11, 8, 17 },
+           { 13, 15, 17 },
+           { 12, 9, 18 },
+           { 14, 15, 18 },
+           };
+
+	     //int elrev = el.flags.reverse;
+	     pnums = -1;
+
+	     for (j = 1; j <= 6; j++)
+	     pnums.Elem(j) = el.PNum(j);
+	    // if (elrev)
+	    // swap (pnums.Elem(3), pnums.Elem(4));
+
+	     for (j = 0; j < 9; 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(7+j) = between.Get(i2);
+	       else
+	       {
+		  pnums.Elem(7+j) = mesh.AddPoint
+		  (Center (mesh.Point(i2.I1()),
+			   mesh.Point(i2.I2())));
+		  between.Set (i2, pnums.Elem(7+j));
+	       }
+	    }
+
+	    for (j = 0; j < 3; j++)
+	    {
+	       INDEX_2 i2a, i2b;
+	       i2a.I1() = pnums.Get(fbetw[2*j][0]);
+	       i2a.I2() = pnums.Get(fbetw[2*j][1]);
+	       i2a.Sort();
+	       i2b.I1() = pnums.Get(fbetw[2*j+1][0]);
+	       i2b.I2() = pnums.Get(fbetw[2*j+1][1]);
+	       i2b.Sort();
+
+	       if (between.Used(i2a))
+		 pnums.Elem(16+j) = between.Get(i2a);
+	       else if (between.Used(i2b))
+		 pnums.Elem(16+j) = between.Get(i2b);
+	       else
+		 {
+		   pnums.Elem(16+j) = mesh.AddPoint
+		     (Center (mesh.Point(i2a.I1()),
+			      mesh.Point(i2a.I2())));
+
+		   between.Set (i2a, pnums.Elem(16+j));
+		 }
+	    }
+
+
+	    static int reftab[8][6] =
+	    { { 1, 8, 7, 13, 17, 16 },
+	      { 7, 8, 9, 16, 17, 18 },
+	      { 7, 9, 3, 16, 18, 14 },
+	      { 8, 2, 9, 17, 15, 18 },
+	      { 13, 17, 16, 4, 11, 10 },
+	      { 16, 17, 18, 10, 11, 12 },
+	      { 16, 18, 14, 10, 12, 6 },
+	      { 17, 15, 18, 11, 5, 12 } };
+
+
+	   int ind = el.GetIndex();
+	   for (j = 0; j < 8; j++)
+	   {
+	      Element nel(PRISM);
+	      for (k = 1; k <= 6; 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(ei) = nel;
+	      else
+	        mesh.AddVolumeElement (nel);
+           }
+           break;
+	  }
+	  default:
+	    PrintSysError ("Refine: undefined volume element type ", int(el.GetType()));
+        }
+      }
+
+
+    // update identification tables
+    for (int i = 1; i <= mesh.GetIdentifications().GetMaxNr(); i++)
+      {
+	Array<int,PointIndex::BASE> identmap;
+	mesh.GetIdentifications().GetMap (i, identmap);
+
+	for (int j = 1; j <= between.GetNBags(); j++)
+	  for (int 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.ComputeNVertices();
+    mesh.RebuildSurfaceElementLists();
+    return;
+
+    int cnttrials = 10;
+    int wrongels = 0;
+    for (int 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<Point<3> > should(np);
+	Array<Point<3> > can(np);
+	for (int i = 1; i <= np; i++)
+	  {
+	    should.Elem(i) = can.Elem(i) = mesh.Point(i);
+	  }
+	for (int i = 1; i <= between.GetNBags(); i++)
+	  for (int 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 (int i = 1; i <= mesh.GetNSE(); i++)
+	  {
+	    const Element2d & sel = mesh.SurfaceElement(i);
+	    for (int 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 (int i = 1; i <= np; i++)
+		  if (boundp.Test(i))
+		    {
+		      for (int j = 0; j < 3; j++)
+			mesh.Point(i)(j) = 
+			  lam * should.Get(i)(j) +
+			  (1-lam) * can.Get(i)(j);
+		    }
+		  else
+		    mesh.Point(i) = can.Get(i);
+	      
+
+		BitArray free (mesh.GetNP()), fhelp(mesh.GetNP());
+		free.Clear();
+		for (int i = 1; i <= mesh.GetNE(); i++)
+		  {
+		    const Element & el = mesh.VolumeElement(i);
+		    if (el.Volume(mesh.Points()) < 0)
+		      for (int j = 1; j <= el.GetNP(); j++)
+			free.Set (el.PNum(j));
+		  }
+		for (int k = 1; k <= 3; k++)
+		  {
+		    fhelp.Clear();
+		    for (int i = 1; i <= mesh.GetNE(); i++)
+		      {
+			const Element & el = mesh.VolumeElement(i);
+			int freeel = 0;
+			for (int j = 1; j <= el.GetNP(); j++)
+			  if (free.Test(el.PNum(j)))
+			    freeel = 1;
+			if (freeel)
+			  for (int j = 1; j <= el.GetNP(); j++)
+			    fhelp.Set (el.PNum(j));
+		      }
+		    free.Or (fhelp);
+		  }
+
+		(*testout) << "smooth points: " << endl;
+		for (int i = 1; i <= free.Size(); i++)
+		  if (free.Test(i))
+		    (*testout) << "p " << i << endl;
+
+		(*testout) << "surf points: " << endl;
+		for (int i = 1; i <= mesh.GetNSE(); i++)
+		  for (int j = 1; j <= 3; j++)
+		    (*testout) << mesh.SurfaceElement(i).PNum(j) << endl;
+		  
+
+
+		mesh.CalcSurfacesOfNode();
+		free.Invert();
+		mesh.FixPoints (free);
+		MeshingParameters dummymp;
+		mesh.ImproveMesh (dummymp, OPT_REST);
+
+
+		wrongels = 0;
+		for (int 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 (int 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 (int i = 1; i <= np; i++)
+	      can.Elem(i) = mesh.Point(i);
+	  }
+      }
+
+    if (cnttrials <= 0)
+      {
+	cerr << "ERROR: Sorry, reverted elements" << endl;
+      }
+ 
+    mesh.ComputeNVertices();
+  }
+}
diff --git a/contrib/Netgen/libsrc/meshing/ruler2.cpp b/contrib/Netgen/libsrc/meshing/ruler2.cpp
new file mode 100644
index 0000000000..62058d2ed2
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/ruler2.cpp
@@ -0,0 +1,719 @@
+#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> & llines1,
+			     int maxlegalline,
+			     Array<Element2d> & elements,
+			     Array<INDEX> & dellines, int tolerance,
+			     const MeshingParameters & mp)
+  {
+    static int timer = NgProfiler::CreateTimer ("meshing2::ApplyRules");
+    NgProfiler::RegionTimer reg (timer);
+
+
+
+    double maxerr = 0.5 + 0.3 * tolerance;
+    double minelerr = 2 + 0.5 * tolerance * tolerance;
+
+    int noldlp = lpoints.Size();
+    int noldll = llines1.Size();
+
+
+    ArrayMem<int,100> pused(maxlegalpoint), lused(maxlegalline);
+    ArrayMem<int,100> pnearness(noldlp), lnearness(llines1.Size());
+
+    ArrayMem<int, 20> pmap, pfixed, lmap;
+  
+    ArrayMem<Point2d,100> tempnewpoints;
+    ArrayMem<INDEX_2,100> tempnewlines;
+    ArrayMem<int,100> tempdellines;
+    ArrayMem<Element2d,100> tempelements;
+
+
+    elements.SetSize (0);
+    dellines.SetSize (0);
+
+    testmode = debugparam.debugoutput;
+
+#ifdef LOCDEBUG
+    int loctestmode = testmode;
+
+    if (loctestmode)
+      {
+	(*testout) << endl << endl << "Check new environment" << endl;
+	(*testout) << "tolerance = " << tolerance << endl;
+	for (int i = 1; i <= lpoints.Size(); i++)
+	  (*testout) << "P" << i << " = " << lpoints.Get(i) << endl;
+	(*testout) << endl;
+	for (int i = 1; i <= llines1.Size(); i++)
+	  (*testout) << "(" << llines1.Get(i).I1() << "-" << llines1.Get(i).I2() << ")" << endl;
+      }
+#endif
+
+    // check every rule
+
+    int found = 0;   // rule number
+
+    pnearness = 1000;
+  
+    for (int j = 0; j < 2; j++)
+      pnearness.Set(llines1[0][j], 0);
+
+
+
+    enum { MAX_NEARNESS = 3 };
+
+    for (int cnt = 0; cnt < MAX_NEARNESS; cnt++)
+      {
+	bool ok = true;
+	for (int i = 0; i < maxlegalline; i++)
+	  {
+	    const INDEX_2 & hline = llines1[i];
+
+	    int minn = min2 (pnearness.Get(hline[0]),  pnearness.Get(hline[1]));
+
+	    for (int j = 0; j < 2; j++)
+	      if (pnearness.Get(hline[j]) > minn+1)
+		{
+		  ok = false;
+		  pnearness.Set(hline[j], minn+1);
+		}
+	  }
+	if (!ok) break;
+      }
+
+
+    for (int i = 0; i < maxlegalline; i++)
+      lnearness[i] = pnearness.Get(llines1[i][0]) + pnearness.Get(llines1[i][1]);
+
+
+    // resort lines after lnearness
+    Array<INDEX_2> llines(llines1.Size());
+    Array<int> sortlines(llines1.Size());
+    int lnearness_class[MAX_NEARNESS];
+
+    for (int j = 0; j < MAX_NEARNESS; j++)
+      lnearness_class[j] = 0;
+    for (int i = 0; i < maxlegalline; i++)
+      if (lnearness[i] < MAX_NEARNESS)
+	lnearness_class[lnearness[i]]++;
+    
+    int cumm = 0;
+    for (int j = 0; j < MAX_NEARNESS; j++)
+      {
+	int hcnt = lnearness_class[j];
+	lnearness_class[j] = cumm;
+	cumm += hcnt;
+      }
+
+    for (int i = 0; i < maxlegalline; i++)
+      if (lnearness[i] < MAX_NEARNESS)
+	{
+	  llines[lnearness_class[lnearness[i]]] = llines1[i];
+	  sortlines[lnearness_class[lnearness[i]]] = i+1;
+	  lnearness_class[lnearness[i]]++;
+	}
+      else
+	{
+	  llines[cumm] = llines1[i];
+	  sortlines[cumm] = i+1;
+	  cumm++;
+	}
+
+    for (int i = maxlegalline; i < llines1.Size(); i++)
+      {
+	llines[cumm] = llines1[i];
+	sortlines[cumm] = i+1;
+	cumm++;
+      }
+
+    for (int i = 0; i < maxlegalline; i++)
+      lnearness[i] = pnearness.Get(llines[i][0]) + pnearness.Get(llines[i][1]);
+
+
+
+
+    static bool firsttime = true;
+    static int timers[100];
+    static int timers2[100];
+    static int timers3[100];
+    if (firsttime)
+      {
+	for (int ri = 0; ri < rules.Size(); ri++)
+	  timers[ri] = NgProfiler::CreateTimer (string("netrule ")+rules[ri]->Name());
+	for (int ri = 0; ri < rules.Size(); ri++)
+	  timers2[ri] = NgProfiler::CreateTimer (string("netrule,mapped ")+rules[ri]->Name());
+	for (int ri = 0; ri < rules.Size(); ri++)
+	  timers3[ri] = NgProfiler::CreateTimer (string("netrule,lines mapped ")+rules[ri]->Name());
+	firsttime = false;
+      }
+
+    lused = 0;
+    pused = 0;
+
+
+    static int timer1 = NgProfiler::CreateTimer ("meshing2::ApplyRules 1");
+    NgProfiler::RegionTimer reg1 (timer1);
+
+
+    for (int ri = 1; ri <= rules.Size(); ri++)
+      {
+	NgProfiler::RegionTimer reg(timers[ri-1]);
+	netrule * rule = rules.Get(ri);
+
+#ifdef LOCDEBUG
+	if (loctestmode)
+	  (*testout) << "Rule " << rule->Name() << endl;
+#endif
+
+	if (rule->GetQuality() > tolerance) continue;
+
+	pmap.SetSize (rule->GetNP());
+	lmap.SetSize (rule->GetNL());
+      
+	pmap = 0;
+	lmap = 0;
+
+	lused[0] = 1; 
+	lmap[0] = 1;  
+
+	for (int j = 0; j < 2; j++)
+	  {
+	    pmap.Elem(rule->GetLine(1)[j]) = llines[0][j];
+	    pused.Elem(llines[0][j])++;
+	  }
+
+
+
+	int nlok = 2;
+
+
+	bool ok = false;
+
+	while (nlok >= 2)
+	  {
+
+	    if (nlok <= rule->GetNOldL())
+
+	      {
+		ok = 0;
+		
+		int maxline = (rule->GetLNearness(nlok) < MAX_NEARNESS) ? lnearness_class[rule->GetLNearness(nlok)] : maxlegalline;
+		// int maxline = maxlegalline;
+
+		while (!ok && lmap.Get(nlok) < maxline)
+		  {
+		    lmap.Elem(nlok)++;
+		    int locli = lmap.Get(nlok);
+
+		    if (lnearness.Get(locli) > rule->GetLNearness (nlok) ) continue;
+		    if (lused.Get(locli)) continue;
+
+
+		    ok = 1;
+
+		    INDEX_2 loclin = llines.Get(locli);
+		    Vec2d linevec = lpoints.Get(loclin.I2()) - lpoints.Get(loclin.I1());
+
+		    if (rule->CalcLineError (nlok, linevec) > maxerr)
+		      {
+			ok = 0;
+#ifdef LOCDEBUG
+			if(loctestmode)
+			  (*testout) << "not ok pos1" << endl;
+#endif
+			continue;
+		      }
+
+		    for (int j = 0; j < 2; j++)
+		      {
+			int refpi = rule->GetLine(nlok)[j];
+
+			if (pmap.Get(refpi) != 0)
+			  {
+			    if (pmap.Get(refpi) != loclin[j])
+			      {
+				ok = 0;
+#ifdef LOCDEBUG
+				if(loctestmode)
+				  (*testout) << "not ok pos2" << endl;
+#endif
+				break;
+			      }
+			  }
+			else
+			  {
+			    if (rule->CalcPointDist (refpi, lpoints.Get(loclin[j])) > maxerr
+				|| !legalpoints.Get(loclin[j])
+				|| pused.Get(loclin[j]))
+			      {
+				ok = 0;
+#ifdef LOCDEBUG
+				if(loctestmode)
+				  {
+				    (*testout) << "nok pos3" << endl;
+				    //if(rule->CalcPointDist (refpi, lpoints.Get(loclin[j])) > maxerr)
+				    //(*testout) << "r1" << endl;
+				    //if(!legalpoints.Get(loclin[j]))
+				    //(*testout) << "r2 legalpoints " << legalpoints << " loclin " << loclin << " j " << j << endl;
+				    //if(pused.Get(loclin[j]))
+				    //(*testout) << "r3" << endl;
+				  }
+#endif
+				break;
+			      }
+			  }
+		      }
+		  }
+
+		if (ok)
+		  {
+		    int locli = lmap.Get(nlok);
+		    INDEX_2 loclin = llines.Get(locli);
+
+		    lused.Elem (locli) = 1;
+		    for (int j = 0; j < 2; j++)
+		      {
+			pmap.Set(rule->GetLine (nlok)[j], loclin[j]);
+			pused.Elem(loclin[j])++;
+		      }
+
+		    nlok++;
+		  }
+		else
+		  {
+		    lmap.Elem(nlok) = 0;
+		    nlok--;
+
+		    lused.Elem (lmap.Get(nlok)) = 0;
+		    for (int j = 0; j < 2; j++)
+		      {
+			pused.Elem(llines.Get(lmap.Get(nlok))[j]) --;
+			if (! pused.Get (llines.Get (lmap.Get (nlok))[j]))
+			  pmap.Set (rule->GetLine (nlok)[j], 0);
+		      }
+		  }
+	      }
+
+	    else
+
+	      {
+		NgProfiler::RegionTimer reg(timers3[ri-1]);
+
+		// all lines are mapped !!
+
+		// map also all points:
+
+		int npok = 1;
+		int incnpok = 1;
+
+		pfixed.SetSize (pmap.Size());
+		for (int i = 0; i < pmap.Size(); i++)
+		  pfixed[i] = (pmap[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)
+			      {
+				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
+
+		      {
+			NgProfiler::RegionTimer reg(timers2[ri-1]);
+
+			npok = rule->GetNOldP();
+			incnpok = 0;
+
+			if (ok)
+			  foundmap.Elem(ri)++; 
+
+#ifdef LOCDEBUG
+			if (loctestmode)
+			  (*testout) << "lines and points mapped" << endl;
+#endif
+
+			ok = 1;
+
+			// check orientations
+
+			for (int i = 1; i <= rule->GetNOrientations(); 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;
+#ifdef LOCDEBUG
+				if (loctestmode)
+				  (*testout) << "Orientation " << i << " not ok" << endl;
+#endif
+				break;
+			      }
+			  }
+
+
+			if (!ok) continue;
+
+			Vector oldu (2 * rule->GetNOldP());
+		      
+			for (int i = 1; i <= rule->GetNOldP(); i++)
+			  {
+			    Vec2d ui(rule->GetPoint(i), lpoints.Get(pmap.Get(i)));
+			    oldu (2*i-2) = ui.X();
+			    oldu (2*i-1) = ui.Y();
+			  }
+		      
+			rule -> SetFreeZoneTransformation (oldu, tolerance);
+
+		      
+			if (!ok) continue;
+			if (!rule->ConvexFreeZone())
+			  {
+			    ok = 0;
+#ifdef LOCDEBUG
+			    if (loctestmode) 
+			      (*testout) << "freezone not convex" << endl;
+#endif
+			    /*
+			      static int cnt = 0;
+			      cnt++;
+			      if (cnt % 100 == 0)
+			      {
+			      cout << "freezone not convex, cnt = " << cnt << "; rule = " << rule->Name() << endl;
+			      (*testout) << "freezone not convex, cnt = " << cnt << "; rule = " << rule->Name() << endl;
+			      (*testout) << "tol = " << tolerance << endl;
+			      (*testout) << "maxerr = " << maxerr << "; minerr = " << minelerr << endl;
+			      (*testout) << "freezone = " << rule->GetTransFreeZone() << endl;
+			      }
+			    */
+			  }
+
+			// check freezone:
+			if (!ok) continue;
+			for (int i = 1; i <= maxlegalpoint && ok; i++)
+			  {
+			    if ( !pused.Get(i) &&
+				 rule->IsInFreeZone (lpoints.Get(i)) )
+			      {
+				ok = 0;
+#ifdef LOCDEBUG
+				if (loctestmode)
+				  (*testout) << "Point " << i << " in freezone" << endl;
+#endif
+				break;
+			      }
+			  }
+
+			if (!ok) continue;
+			for (int i = maxlegalpoint+1; i <= lpoints.Size(); i++)
+			  {
+			    if ( rule->IsInFreeZone (lpoints.Get(i)) )
+			      {
+				ok = 0;
+#ifdef LOCDEBUG
+				if (loctestmode)
+				  (*testout) << "Point " << i << " in freezone" << endl;
+#endif
+				break;
+			      }
+			  }
+
+
+			if (!ok) continue;
+			for (int i = 1; i <= maxlegalline; i++)
+			  {
+			    if (!lused.Get(i) && 
+				rule->IsLineInFreeZone (lpoints.Get(llines.Get(i).I1()),
+							lpoints.Get(llines.Get(i).I2())))
+			      {
+				ok = 0;
+#ifdef LOCDEBUG
+				if (loctestmode)
+				  (*testout) << "line " << llines.Get(i).I1() << "-"
+					     << llines.Get(i).I2() << " in freezone" << endl;
+#endif
+				break;
+			      }
+			  }
+
+			if (!ok) continue;
+
+			for (int i = maxlegalline+1; i <= llines.Size(); i++)
+			  {
+			    if (rule->IsLineInFreeZone (lpoints.Get(llines.Get(i).I1()),
+							lpoints.Get(llines.Get(i).I2())))
+			      {
+				ok = 0;
+#ifdef LOCDEBUG
+				if (loctestmode)
+				  (*testout) << "line " << llines.Get(i).I1() << "-"
+					     << llines.Get(i).I2() << " in freezone" << endl;
+#endif
+				break;
+			      }
+			  }
+
+
+			/*
+			// 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) continue;
+
+#ifdef LOCDEBUG
+			if (loctestmode)
+			  (*testout) << "rule ok" << endl;
+#endif
+
+			// Setze neue Punkte:
+			if (rule->GetNOldP() < rule->GetNP())
+			  {
+			    Vector newu(rule->GetOldUToNewU().Height());
+			    rule->GetOldUToNewU().Mult (oldu, newu);
+			    
+			    int oldnp = rule->GetNOldP();
+			    for (int i = oldnp + 1; i <= rule->GetNP(); i++)
+			      {
+				Point2d np = rule->GetPoint(i);
+				np.X() += newu (2 * (i-oldnp) - 2);
+				np.Y() += newu (2 * (i-oldnp) - 1);
+				
+				pmap.Elem(i) = lpoints.Append (np);
+			      }
+			  }
+
+			// Setze neue Linien:
+
+			for (int i = rule->GetNOldL() + 1; i <= rule->GetNL(); i++)
+			  {
+			    llines.Append (INDEX_2 (pmap.Get(rule->GetLine (i)[0]),
+						    pmap.Get(rule->GetLine (i)[1])));
+			  }
+
+
+			// delete old lines:
+			for (int i = 1; i <= rule->GetNDelL(); i++)
+			  dellines.Append (sortlines.Elem (lmap.Get(rule->GetDelLine(i))));
+			// dellines.Append (lmap.Get(rule->GetDelLine(i))));
+
+			// dellines.Append (lmap.Elem(rule->GetDelLines()));
+			// lmap[rule->GetDelLines()];
+
+
+			// insert new elements:
+
+			for (int i = 1; i <= rule->GetNE(); i++)
+			  {
+			    elements.Append (rule->GetElement(i));
+			    for (int j = 1; j <= elements.Get(i).GetNP(); j++)
+			      elements.Elem(i).PNum(j) = pmap.Get(elements.Get(i).PNum(j));
+			  }
+
+
+			double elerr = 0;
+			for (int i = 1; i <= elements.Size(); i++)
+			  {
+			    double hf;
+			    if (!mp.quad)
+			      hf = CalcElementBadness (lpoints, elements.Get(i));
+			    else
+			      hf = elements.Get(i).CalcJacobianBadness (lpoints) * 5;
+#ifdef LOCDEBUG
+			    if (loctestmode)
+			      (*testout) << "r " << rule->Name() << "bad = " << hf << endl;
+#endif
+			    if (hf > elerr) elerr = hf;
+			  }
+
+#ifdef LOCDEBUG
+			if (loctestmode)
+			  (*testout) << "error = " << elerr;
+#endif
+
+			canuse.Elem(ri) ++;
+
+			if (elerr < 0.99*minelerr)
+			  {
+#ifdef LOCDEBUG
+			    if (loctestmode)
+			      {
+				(*testout) << "rule = " << rule->Name() << endl;
+				(*testout) << "class = " << tolerance << endl;
+				(*testout) << "lpoints: " << endl;
+				for (int i = 1; i <= lpoints.Size(); i++)
+				  (*testout) << lpoints.Get(i) << endl;
+				(*testout) << "llines: " << endl;
+				for (int i = 1; i <= llines.Size(); i++)
+				  (*testout) << llines.Get(i).I1() << " " << llines.Get(i).I2() << endl;
+
+				(*testout) << "Freezone: ";
+				for (int i = 1; i <= rule -> GetTransFreeZone().Size(); i++)
+				  (*testout) << rule->GetTransFreeZone().Get(i) << endl;
+			      }
+#endif
+
+			    minelerr = elerr;
+			    found = ri;
+
+			    tempnewpoints = lpoints.Range (noldlp, lpoints.Size());
+			    tempnewlines = llines.Range (noldll, llines.Size());
+			    tempdellines = dellines;
+			    tempelements = elements;
+			  }
+
+			lpoints.SetSize (noldlp);
+			llines.SetSize (noldll);
+			dellines.SetSize (0);
+			elements.SetSize (0);
+			ok = 0;
+		      }
+		  }
+
+		nlok = rule->GetNOldL();
+
+		lused.Set (lmap.Get(nlok), 0);
+
+		for (int j = 1; j <= 2; j++)
+		  {
+		    int refpi = rule->GetPointNr (nlok, j);
+		    pused.Elem(pmap.Get(refpi))--;
+
+		    if (pused.Get(pmap.Get(refpi)) == 0)
+		      pmap.Set(refpi, 0);
+		  }
+	      }
+	  }
+      }
+
+
+    if (found)
+      {
+	lpoints.Append (tempnewpoints);
+	llines1.Append (tempnewlines);
+	dellines.Append (tempdellines);
+	elements.Append (tempelements);
+      }
+
+
+    return found;
+  }
+
+
+
+
+
+}
diff --git a/contrib/Netgen/libsrc/meshing/ruler2.hpp b/contrib/Netgen/libsrc/meshing/ruler2.hpp
new file mode 100644
index 0000000000..afbe6b985a
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/ruler2.hpp
@@ -0,0 +1,169 @@
+#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<Array<Point2d>*> freezone_i;
+  ///
+  Array<Point2d> transfreezone;
+
+  ///
+  Array<int> dellines;
+  ///
+  Array<Element2d> elements;
+  ///
+  Array<threefloat> tolerances, linetolerances;
+  ///
+  Array<threeint> orientations;
+  ///
+  DenseMatrix oldutonewu, oldutofreearea, oldutofreearealimit;
+  ///
+  Array<DenseMatrix*> oldutofreearea_i;
+  ///
+  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); }
+  ///
+  const Array<int> & GetDelLines() const { return dellines; }
+  ///
+  void GetFreeZone (Array<Point2d> & afreearea);
+  ///
+
+  double CalcPointDist (int pi, const Point2d & p) const
+  {
+    double dx = p.X() - points.Get(pi).X();
+    double dy = p.Y() - points.Get(pi).Y();
+    const threefloat * tfp = &tolerances.Get(pi);
+    return tfp->f1 * dx * dx + tfp->f2 * dx * dy + tfp->f3 * dy * dy;
+  }
+
+  ///
+  float CalcLineError (int li, const Vec2d & v) const;
+
+  ///
+  void SetFreeZoneTransformation (const Vector & u, int tolclass);
+
+  ///
+  bool IsInFreeZone (const Point2d & p) const
+  {
+    if (p.X() < fzminx || p.X() > fzmaxx ||
+	p.Y() < fzminy || p.Y() > fzmaxy) return 0;
+
+    for (int i = 0; i < transfreezone.Size(); i++)
+      {
+	if (freesetinequ(i, 0) * p.X() + 
+	    freesetinequ(i, 1) * p.Y() +
+	    freesetinequ(i, 2) > 0) return 0;
+      }
+    return 1;
+  }
+
+  ///
+  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/contrib/Netgen/libsrc/meshing/ruler3.cpp b/contrib/Netgen/libsrc/meshing/ruler3.cpp
new file mode 100644
index 0000000000..3b6f7a91ac
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/ruler3.cpp
@@ -0,0 +1,1136 @@
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+
+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: 2 .. it is allowed to use pointi, 1..will be allowed later, 0..no means
+ Array<MiniElement2d> & 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 
+ )
+
+{
+  NgProfiler::RegionTimer regtot(97);
+
+  int i, j, k, ri, nfok, npok, incnpok, refpi, locpi, locfi, locfr;
+  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 MiniElement2d * locface = NULL;
+  int loktestmode;
+
+
+  Array<int> pused;        // point is already mapped
+  Array<char> fused;       // face is already mapped
+  Array<int> pmap;         // map of reference point to local point
+  Array<char> pfixed;      // point mapped by face-map
+  Array<int> fmapi;        // face in reference is mapped to face nr ...
+  Array<int> fmapr;        // face in reference is rotated to map 
+  Array<Point3d> transfreezone;  // transformed free-zone
+  INDEX_2_CLOSED_HASHTABLE<int> ledges(100); // edges in local environment
+  
+  Array<Point3d> tempnewpoints;
+  Array<MiniElement2d> tempnewfaces;
+  Array<int> tempdelfaces;
+  Array<Element> tempelements;
+  Array<Box3d> triboxes;         // bounding boxes of local faces
+
+  Array<int, PointIndex::BASE> pnearness;
+  Array<int> fnearness;
+
+  static int cnt = 0;
+  cnt++;
+  
+  delfaces.SetSize (0);
+  elements.SetSize (0);
+
+  // determine topological distance of faces and points to
+  // base element
+
+  pnearness.SetSize (lpoints.Size());
+  fnearness.SetSize (lfacesplit);
+
+  pnearness = INT_MAX/10;
+  for (j = 0; j < lfaces[0].GetNP(); j++)
+    pnearness[lfaces[0][j]] = 0;
+
+  NgProfiler::RegionTimer reg2(98);
+  
+  NgProfiler::StartTimer (90);
+
+  for (int loop = 0; loop < 2; loop++)
+    {
+
+      for (i = 0; i < lfacesplit; i++)
+	{
+	  const MiniElement2d & hface = lfaces[i];
+
+	  int minn = INT_MAX-1;
+	  for (j = 0; j < hface.GetNP(); j++)
+	    {
+	      int hi = pnearness[hface[j]];
+	      if (hi < minn) minn = hi;
+	    }
+	  if (minn < INT_MAX/10)
+	    for (j = 0; j < hface.GetNP(); j++)
+	      if (pnearness[hface[j]] > minn+1)
+		pnearness[hface[j]] = 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 (pnearness[edge.I1()] > pnearness[edge.I2()] + 1)
+	      pnearness[edge.I1()] = pnearness[edge.I2()] + 1;
+
+	    if (pnearness[edge.I2()] > pnearness[edge.I1()] + 1)
+	      pnearness[edge.I2()] = pnearness[edge.I1()] + 1;
+	  }
+
+    }
+
+  for (i = 0; i < fnearness.Size(); i++)
+    {
+      int sum = 0;
+      for (j = 0; j < lfaces[i].GetNP(); j++)
+	sum += pnearness[lfaces[i][j]];
+      fnearness[i] = sum;
+    }
+
+  
+  NgProfiler::StopTimer (90);
+  NgProfiler::StartTimer (91);
+
+  // find bounding boxes of faces
+
+  triboxes.SetSize (lfaces.Size());
+  for (i = 0; i < lfaces.Size(); i++)
+    {
+      const MiniElement2d & face = lfaces[i];
+      triboxes[i].SetPoint (lpoints.Get(face[0]));
+      for (j = 1; j < face.GetNP(); j++)
+	triboxes[i].AddPoint (lpoints.Get(face[j]));
+    }
+
+  NgProfiler::StopTimer (91);
+  NgProfiler::StartTimer (92);
+
+  
+  bool useedges = 0;
+  for (ri = 0; ri < rules.Size(); ri++)
+    if (rules[ri]->GetNEd()) useedges = 1;
+
+  if (useedges)
+    {
+      ledges.SetSize (5 * lfacesplit);
+      
+      for (j = 0; j < lfacesplit; j++)
+	// if (fnearness[j] <= 5) 
+	  {
+	    const MiniElement2d & face = lfaces[j];
+	    int newp, oldp;
+	    
+	    newp = face[face.GetNP()-1];
+	    for (k = 0; k < face.GetNP(); k++)
+	      {
+		oldp = newp;
+		newp = face[k];
+		ledges.Set (INDEX_2::Sort(oldp, newp), 1);
+	      }
+	  }
+    }
+
+  NgProfiler::StopTimer (92);
+
+  NgProfiler::RegionTimer reg3(99);
+
+  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;
+
+
+
+  // impossible, if no rule can be applied at any tolerance class
+  bool impossible = 1;
+
+
+  // check each rule:
+
+  for (ri = 1; ri <= rules.Size(); ri++)
+    { 
+      int base = (lfaces[0].GetNP() == 3) ? 100 : 200;
+      NgProfiler::RegionTimer regx1(base);
+      NgProfiler::RegionTimer regx(base+ri);
+
+      sprintf (problems.Elem(ri), "");
+
+      rule = rules.Get(ri);
+      
+      if (rule->GetNP(1) != lfaces[0].GetNP())
+	continue;
+
+      if (rule->GetQuality() > tolerance)
+	{
+	  if (rule->GetQuality() < 100) impossible = 0;
+
+	  if (testmode)
+	    sprintf (problems.Elem(ri), "Quality not ok");
+	  continue;
+	}
+      
+      if (testmode)
+	sprintf (problems.Elem(ri), "no mapping found");
+      
+      loktestmode = testmode || rule->TestFlag ('t') || tolerance > 5;
+
+      if (loktestmode)
+	(*testout) << "Rule " << ri << " = " << rule->Name() << endl;
+      
+      pmap.SetSize (rule->GetNP());
+      fmapi.SetSize (rule->GetNF());
+      fmapr.SetSize (rule->GetNF());
+      
+      fused = 0;
+      pused = 0;
+      pmap = 0;
+      fmapi = 0;
+      for (i = 1; i <= fmapr.Size(); i++)
+	fmapr.Set(i, rule->GetNP(i));
+      
+      fused[0] = 1;
+      fmapi[0] = 1;
+      fmapr[0] = rotind1;
+
+      
+      for (j = 1; j <= lfaces.Get(1).GetNP(); j++)
+	{
+	  locpi = lfaces[0].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;
+      NgProfiler::RegionTimer regfa(300);
+      NgProfiler::RegionTimer regx2(base+50+ri);
+      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)
+				    {
+				      impossible = 0;
+				      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
+	    
+	    { 
+	      NgProfiler::RegionTimer regfb(301);
+
+	      // 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) || 
+				  pnearness.Get(locpi) > rule->GetPNearness(npok))
+				{
+				  ok = 0;
+				}
+			      else if (allowpoint.Get(locpi) != 2)
+				{
+				  ok = 0;
+				  if (allowpoint.Get(locpi) == 1)
+				    impossible = 0;
+				}
+			      else
+				{
+				  const Point3d & lp = lpoints.Get(locpi);
+				  const Point3d & rp = rule->GetPoint(npok);
+
+				  if ( Dist2 (lp, rp) * rule->PointDistFactor(npok) > minerr)
+				    {
+				      ok = 0;
+				      impossible = 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
+		    
+		    {
+		      NgProfiler::RegionTimer regfa2(302);		      
+
+		      // 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++)
+			{
+			  INDEX_2 in2(pmap.Get(rule->GetEdge(i).i1),
+				      pmap.Get(rule->GetEdge(i).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++)
+				{
+				  INDEX_2 in2(pmap.Get(el.PNum(j)),
+					      pmap.Get(el.PNum(j+3)));      
+				  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 (3*i-3) = lp.X()-rp.X();
+                          oldu (3*i-2) = lp.Y()-rp.Y();
+			  oldu (3*i-1) = lp.Z()-rp.Z();
+			  
+			  allp (3*i-3) = lp.X();
+                          allp (3*i-2) = lp.Y();
+                          allp (3*i-1) = 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 (3*i-3) = rp.X() + newu(3*i-3 - idiff);
+                          allp (3*i-2) = rp.Y() + newu(3*i-2 - idiff);
+                          allp (3*i-1) = rp.Z() + newu(3*i-1 - 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 MiniElement2d & 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);
+			    }
+
+
+			  //			  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 (3 * (i-oldnp) - 3);
+			      np.Y() += newu (3 * (i-oldnp) - 2);
+			      np.Z() += newu (3 * (i-oldnp) - 1);
+			      
+			      pmap.Elem(i) = lpoints.Append (np);
+			    }
+			  
+			  // Set new Faces:
+			  
+			  for (i = rule->GetNOldF() + 1; i <= rule->GetNF(); i++)
+			    if (!fmapi.Get(i))
+			      {
+				MiniElement2d 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*n.Length()*v3.Length()) // OR -1e-7???
+			      if (n * v3 >= -1e-9)
+				{
+				  if (loktestmode)
+				    {
+				      sprintf (problems.Elem(ri), "Orientation wrong");
+				      (*testout) << "Orientation wrong ("<< n*v3 << ")" << 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 (teterr > minteterr) impossible = 0;
+
+			  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;
+    }
+
+  if (found)
+    {
+      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;
+
+
+  if (impossible && found == 0)
+    return -1;
+
+  return found;
+}
+}
diff --git a/contrib/Netgen/libsrc/meshing/ruler3.hpp b/contrib/Netgen/libsrc/meshing/ruler3.hpp
new file mode 100644
index 0000000000..fcbf8f5990
--- /dev/null
+++ b/contrib/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/contrib/Netgen/libsrc/meshing/secondorder.cpp b/contrib/Netgen/libsrc/meshing/secondorder.cpp
new file mode 100644
index 0000000000..5b5b5d7f55
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/secondorder.cpp
@@ -0,0 +1,490 @@
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+
+namespace netgen
+{
+
+  void Refinement :: MakeSecondOrder (Mesh & mesh) const
+  {
+    const_cast<Refinement&> (*this).MakeSecondOrder(mesh);
+  }
+
+  
+  void Refinement :: MakeSecondOrder (Mesh & mesh)
+  {
+    int nseg, nse, ne;
+
+    mesh.ComputeNVertices();
+    mesh.SetNP(mesh.GetNV());
+  
+    INDEX_2_HASHTABLE<int> between(mesh.GetNP() + 5);
+
+
+    bool thinlayers = 0;
+    for (ElementIndex ei = 0; ei < mesh.GetNE(); ei++)
+      if (mesh[ei].GetType() == PRISM ||
+	  mesh[ei].GetType() == PRISM12)
+	thinlayers = 1;
+    
+
+    nseg = mesh.GetNSeg();
+    for (SegmentIndex si = 0; si < nseg; si++)
+      {
+	Segment & el = mesh.LineSegment(si);
+
+	INDEX_2 i2 = INDEX_2::Sort (el[0], el[1]);
+
+	if (between.Used(i2))
+	  el[2] = between.Get(i2);
+	else
+	  {
+	    Point<3> pb;
+	    EdgePointGeomInfo ngi;
+            PointBetween (mesh.Point (el[0]),
+                          mesh.Point (el[1]), 0.5,
+			  el.surfnr1, el.surfnr2,
+			  el.epgeominfo[0], el.epgeominfo[1],
+			  pb, ngi);
+	  
+	    el[2] = mesh.AddPoint (pb);
+	    between.Set (i2, el[2]);
+	  }
+      }
+
+    // refine surface elements
+    nse = mesh.GetNSE();
+    for (SurfaceElementIndex sei = 0; sei < nse; sei++)
+      {
+	int j;
+	const Element2d & el = mesh.SurfaceElement(sei);
+
+	int onp(0);
+      
+	Element2d newel;
+	newel.SetIndex (el.GetIndex());
+
+	static int betw_trig[3][3] =
+	  { { 1, 2, 3 },
+	    { 0, 2, 4 },
+	    { 0, 1, 5 } };
+	static int betw_quad6[2][3] =
+	  { { 0, 1, 4 },
+	    { 3, 2, 5 } };
+	static int betw_quad8[4][3] =
+	  { { 0, 1, 4 },
+	    { 3, 2, 5 },
+	    { 0, 3, 6 },
+	    { 1, 2, 7 } };
+	int (*betw)[3] = NULL;
+      
+	switch (el.GetType())
+	  {
+	  case TRIG:
+	  case TRIG6:
+	    {
+	      betw = betw_trig;
+	      newel.SetType (TRIG6);
+	      onp = 3;
+	      break;
+	    }
+	  case QUAD:
+	  case QUAD6: 
+	  case QUAD8:
+	    {
+	      if (thinlayers)
+		{
+		  betw = betw_quad6;
+		  newel.SetType (QUAD6);
+		}
+	      else
+		{
+		  betw = betw_quad8;
+		  newel.SetType (QUAD8);
+		}
+	      onp = 4;
+	      break;
+	    }
+	  default:
+	    PrintSysError ("Unhandled element in secondorder:", int(el.GetType()));
+	  }
+
+	for (j = 0; j < onp; j++)
+	  newel[j] = el[j];
+      
+	int nnp = newel.GetNP();
+	for (j = 0; j < nnp-onp; j++)
+	  {
+	    int pi1 = newel[betw[j][0]];
+	    int pi2 = newel[betw[j][1]];
+	  
+	    INDEX_2 i2 = INDEX_2::Sort (pi1, pi2);
+	  
+	    if (between.Used(i2))
+	      newel[onp+j] = between.Get(i2);
+	    else
+	      {
+		Point<3> pb;
+		PointGeomInfo newgi;
+		PointBetween (mesh.Point (pi1),
+			      mesh.Point (pi2), 0.5, 
+			      mesh.GetFaceDescriptor(el.GetIndex ()).SurfNr(),
+			      el.GeomInfoPi (betw[j][0]+1),
+			      el.GeomInfoPi (betw[j][1]+1),
+			      pb, newgi);
+
+		newel[onp+j] = mesh.AddPoint (pb);
+		between.Set (i2, newel[onp+j]);
+	      }
+	  }
+      
+	mesh.SurfaceElement(sei) = newel;
+      }
+
+ 
+    //    int i, j;
+
+
+
+    // refine volume elements
+    ne = mesh.GetNE();
+    for (int i = 1; i <= ne; i++)
+      {
+	const Element & el = mesh.VolumeElement(i);
+	int onp(0);
+
+	Element newel;
+	newel.SetIndex (el.GetIndex());
+
+	static int betw_tet[6][3] =
+	  { { 0, 1, 4 },
+	    { 0, 2, 5 },
+	    { 0, 3, 6 },
+	    { 1, 2, 7 },
+	    { 1, 3, 8 },
+	    { 2, 3, 9 } };
+	static int betw_prism[6][3] =
+	  {
+	    { 0, 2, 6 },
+	    { 0, 1, 7 },
+	    { 1, 2, 8 },
+	    { 3, 5, 9 },
+	    { 3, 4, 10 },
+	    { 4, 5, 11 },
+	  };
+	int (*betw)[3] = NULL;
+
+	switch (el.GetType())
+	  {
+	  case TET:
+	  case TET10:
+	    {
+	      betw = betw_tet;
+	      newel.SetType (TET10);
+	      onp = 4;
+	      break;
+	    }
+	  case PRISM:
+	  case PRISM12:
+	    {
+	      betw = betw_prism;
+	      newel.SetType (PRISM12);
+	      onp = 6;
+	      break;
+	    }
+	  default:
+	    PrintSysError ("MakeSecondOrder, illegal vol type ", el.GetType());
+	  }
+
+
+	for (int j = 1; j <= onp; j++)
+	  newel.PNum(j) = el.PNum(j);
+	int nnp = newel.GetNP();
+
+	for (int j = 0; j < nnp-onp; j++)
+	  {
+	    INDEX_2 i2(newel[betw[j][0]],
+		       newel[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 (int i = 1; i <= mesh.GetIdentifications().GetMaxNr(); i++)
+      {
+	Array<int,PointIndex::BASE> identmap;
+	mesh.GetIdentifications().GetMap (i, identmap);
+
+	for (INDEX_2_HASHTABLE<int>::Iterator it = between.Begin();
+	     it != between.End(); it++)
+	  {
+	      INDEX_2 i2;
+	      int newpi;
+	      between.GetData (it, 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);
+		}
+	  }
+
+	/*
+	for (int j = 1; j <= between.GetNBags(); j++)
+	  for (int 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 (int i = oldsize; i < mesh.GetNP(); i++)
+      mesh.mlbetweennodes[i] = INDEX_2(0,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;
+	}
+    */
+
+    for (INDEX_2_HASHTABLE<int>::Iterator it = between.Begin();
+	 it != between.End(); it++)
+      {
+	mesh.mlbetweennodes[between.GetData (it)] = between.GetHash(it);
+      }
+
+    mesh.ComputeNVertices();
+    mesh.RebuildSurfaceElementLists();
+    //  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 (int i = 1; i <= np; i++)
+      parents.Elem(i) = INDEX_2(0,0);
+
+    for (int 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 (int 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 (int 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<Point<3> > should(np);
+	Array<Point<3> > can(np);
+
+	for (int i = 1; i <= np; i++)
+	  {
+	    should.Elem(i) = can.Elem(i) = mesh.Point(i);
+	  }
+
+	for (int 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 (int i = 1; i <= mesh.GetNSE(); i++)
+	  {
+	    const Element2d & sel = mesh.SurfaceElement(i);
+	    for (int j = 1; j <= sel.GetNP(); j++)
+	      boundp.Set(sel.PNum(j));
+	  }
+
+
+	(*testout) << "bpoints:" << endl;
+	for (int 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 (int i = 1; i <= np; i++)
+		  if (boundp.Test(i))
+		    {
+		      for (int j = 0; j < 3; j++)
+			mesh.Point(i)(j) = 
+			  lam * should.Get(i)(j) +
+			  (1-lam) * can.Get(i)(j);
+		    }
+		  else
+		    mesh.Point(i) = Point<3> (can.Get(i));
+	      
+		//	      (*testout) << "bad els: " << endl;
+		wrongels = 0;
+		for (int 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();
+	    MeshingParameters dummymp;
+	    mesh.ImproveMeshJacobian (dummymp, OPT_WORSTCASE);	      
+	  
+	    facok = factry;
+	    for (int i = 1; i <= np; i++)
+	      can.Elem(i) = mesh.Point(i);
+	  }
+      }
+
+
+      
+    for (int 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/contrib/Netgen/libsrc/meshing/smoothing2.5.cpp b/contrib/Netgen/libsrc/meshing/smoothing2.5.cpp
new file mode 100644
index 0000000000..c9de8e2144
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/smoothing2.5.cpp
@@ -0,0 +1,265 @@
+#include <mystdlib.h>
+
+#include "meshing.hpp"
+#include <opti.hpp>
+
+namespace netgen
+{
+
+
+  void MeshOptimize2d :: ProjectBoundaryPoints(Array<int> & surfaceindex, 
+					       const Array<Point<3>* > & from, Array<Point<3>* > & dest)
+  {
+    for(int i=0; i<surfaceindex.Size(); i++)
+      {
+	if(surfaceindex[i] >= 0)
+	  {
+	    *dest[i] = *from[i];
+	    ProjectPoint(surfaceindex[i],*dest[i]);
+	  }
+      }
+      
+
+  }
+
+  void MeshOptimize2d :: ImproveVolumeMesh (Mesh & mesh)
+  {
+    
+    if (!faceindex)
+      {
+	PrintMessage (3, "Smoothing");
+
+	for (faceindex = 1; faceindex <= mesh.GetNFD(); faceindex++)
+	  {
+	    ImproveVolumeMesh (mesh);
+	    if (multithread.terminate)
+	      throw NgException ("Meshing stopped");
+	  }
+	faceindex = 0;
+	return;
+      }
+      
+
+
+    static int timer = NgProfiler::CreateTimer ("MeshSmoothing 2D");
+    NgProfiler::RegionTimer reg (timer);
+
+
+
+    CheckMeshApproximation (mesh);
+
+    int i, j, k;
+    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;
+    bool moveisok;
+
+    PointGeomInfo ngi;
+    Point<3> origp;
+
+    Vector x(3);
+
+    Array<MeshPoint, PointIndex::BASE> savepoints(mesh.GetNP());
+
+    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]);
+      }
+    
+
+    JacobianPointFunction pf(mesh.Points(),mesh.VolumeElements());
+
+
+
+//     Opti2SurfaceMinFunction surfminf(mesh);
+//     Opti2EdgeMinFunction edgeminf(mesh);
+//     Opti2SurfaceMinFunctionJacobian surfminfj(mesh);
+
+    OptiParameters par;
+    par.maxit_linsearch = 8;
+    par.maxit_bfgs = 5;
+
+    int np = mesh.GetNP();
+    int ne = mesh.GetNE();
+
+    BitArray badnodes(np);
+    badnodes.Clear();
+
+    for (i = 1; i <= ne; i++)
+      {
+	const Element & el = mesh.VolumeElement(i);
+	double bad = el.CalcJacobianBadness (mesh.Points());
+	if (bad > 1)
+	  for (j = 1; j <= el.GetNP(); j++)
+	    badnodes.Set (el.PNum(j));
+      }
+
+
+    bool printeddot = 0;
+    char plotchar = '.';
+    int modplot = 1;
+    if (mesh.GetNP() > 1000)
+      {
+	plotchar = '+';
+	modplot = 10;
+      }
+    if (mesh.GetNP() > 10000)
+      {
+	plotchar = 'o';
+	modplot = 100;
+      }
+    int cnt = 0;
+
+
+    Array<SurfaceElementIndex> locelements(0);
+    Array<int> locrots(0);
+
+    for (PointIndex pi = PointIndex::BASE; 
+	 pi < mesh.GetNP()+PointIndex::BASE; pi++)
+      {
+	if (mesh[pi].Type() != SURFACEPOINT)
+	  continue;
+
+	if (multithread.terminate)
+	  throw NgException ("Meshing stopped");
+	
+	int surfi(-1);
+
+	if(elementsonpoint[pi].Size() == 0)
+	  continue;
+
+	Element2d & hel = mesh[elementsonpoint[pi][0]];
+
+	if(hel.GetIndex() != faceindex)
+	  continue;
+
+	cnt++;
+	if (cnt % modplot == 0 && writestatus)
+	  {
+	    printeddot = 1;
+	    PrintDot (plotchar);
+	  }
+
+		
+	int hpi = 0;
+	for (j = 1; j <= hel.GetNP(); j++)
+	  if (hel.PNum(j) == pi)
+	    {
+	      hpi = j;
+	      break;
+	    }
+	PointGeomInfo gi1 = hel.GeomInfoPi(hpi);
+	
+	locelements.SetSize(0);
+	locrots.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;
+		}
+	  }
+	 
+
+	double lh = mesh.GetH(mesh.Point(pi));
+	par.typx = lh;
+
+	pf.SetPointIndex(pi);
+	
+	x = 0;
+	bool pok = (pf.Func (x) < 1e10); 
+	
+	if (pok)
+	  {
+	    BFGS (x, pf, par);
+	    
+	    origp = mesh[pi];
+	    loci = 1;
+	    fact = 1;
+	    moveisok = false;
+	
+	    
+	    //optimizer loop (if whole distance is not possible, move only a bit!!!!)
+	    while (loci <= 5 && !moveisok)
+	      {
+		loci ++;
+		mesh[pi](0) = origp(0) + x(0)*fact;
+		mesh[pi](1) = origp(1) + x(1)*fact;
+		mesh[pi](2) = origp(2) + x(2)*fact;
+		fact = fact/2.;
+	    
+	    
+		//cout << "origp " << origp << " newp " << mesh[pi];
+	    
+		ngi = gi1;
+		moveisok = (ProjectPointGI (surfi, mesh[pi], ngi) != 0);
+
+		//cout << " projected " << mesh[pi] << endl;
+
+		// point lies on same chart in stlsurface
+		
+		if (moveisok)
+		  {
+		    for (j = 0; j < locelements.Size(); j++)
+		      mesh[locelements[j]].GeomInfoPi(locrots[j]) = ngi;
+
+		    //cout << "moved " << origp << " to " << mesh[pi] << endl;
+		  }
+		else
+		  {
+		    mesh[pi] = origp;
+		  }
+	    
+	      }
+	  }
+	else
+	  {
+	    cout << "el not ok (point " << pi << ": " << mesh[pi] << ")" << endl;
+	  }
+      }
+
+    if (printeddot)
+      PrintDot ('\n');
+  
+    CheckMeshApproximation (mesh);
+    mesh.SetNextTimeStamp();
+  }
+
+  
+}
diff --git a/contrib/Netgen/libsrc/meshing/smoothing2.cpp b/contrib/Netgen/libsrc/meshing/smoothing2.cpp
new file mode 100644
index 0000000000..fe47f8b88d
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/smoothing2.cpp
@@ -0,0 +1,903 @@
+#include <mystdlib.h>
+
+#include "meshing.hpp"
+#include <opti.hpp>
+
+namespace netgen
+{
+
+  static const double c_trig = 0.14433756;      // sqrt(3.0) / 12
+  static const double c_trig4 = 0.57735026;     // sqrt(3.0) / 3
+
+  inline double CalcTriangleBadness (double x2, double x3, double y3, 
+				     double metricweight, double h)
+  {
+    // badness = sqrt(3.0) / 12 * (\sum l_i^2) / area - 1 
+    // p1 = (0, 0), p2 = (x2, 0), p3 = (x3, y3);
+
+    double cir_2 = (x2*x2 + x3*x3 + y3*y3 - x2*x3);
+    double area = x2 * y3;
+    
+    if (area <= 1e-24 * cir_2)
+      return 1e10;
+    
+    double badness = c_trig4 * cir_2 / area - 1;
+    
+    if (metricweight > 0)
+      {
+	// add:  metricweight * (area / h^2 + h^2 / area - 2)
+
+	double areahh = area / (h * h);
+	badness += metricweight * (areahh + 1 / areahh - 2);
+      }
+    return badness;
+  }
+
+  
+  inline void CalcTriangleBadness (double x2, double x3, double y3, double metricweight,
+				   double h, double & badness, double & g1x, double & g1y)
+  {
+    // old: badness = sqrt(3.0) /36 * circumference^2 / area - 1 
+    // badness = sqrt(3.0) / 12 * (\sum l_i^2) / area - 1 
+    // p1 = (0, 0), p2 = (x2, 0), p3 = (x3, y3);
+
+
+    double cir_2 = 2* (x2*x2 + x3*x3 + y3*y3 - x2*x3);
+    double area = 0.5 * x2 * y3;
+
+    if (area <= 1e-24 * cir_2)
+      {
+	g1x = 0;
+	g1y = 0;
+	badness = 1e10;
+	return;
+      }
+
+    badness = c_trig * cir_2 / area - 1;
+
+    double c1 = -2 * c_trig / area;
+    double c2 = 0.5 * c_trig * cir_2 / (area * area);
+    g1x = c1 * (x2 + x3) + c2 * y3;
+    g1y = c1 * (y3)      + c2 * (x2-x3); 
+
+    if (metricweight > 0)
+      {
+	// area = (x2 - x1) * (y3 - y1) - (x3 - x1) * (y2 - y1);
+	// add:  metricweight * (area / h^2 + h^2 / area - 2)
+      
+	area = x2 * y3;
+	double dareax1 = -y3; 
+	double dareay1 = x3 - x2; 
+
+	double areahh = area / (h * h);
+	double fac = metricweight * (areahh - 1 / areahh) / area;
+
+	badness += metricweight * (areahh + 1 / areahh - 2);
+	g1x += fac * dareax1;
+	g1y += fac * dareay1; 
+      }
+  }
+
+
+
+
+
+  double CalcTriangleBadness (const Point3d & p1, 
+			      const Point3d & p2, 
+			      const Point3d & p3,
+			      double metricweight,
+			      double h)
+  {
+    // badness = sqrt(3.0) / 12 * (\sum l_i^2) / area - 1 
+    // p1 = (0, 0), p2 = (x2, 0), p3 = (x3, y3);
+
+    Vec3d e12(p1,p2);
+    Vec3d e13(p1,p3);
+    Vec3d e23(p2,p3);
+  
+    double l12_2 = e12.Length2();
+    double l13_2 = e13.Length2();
+    double l23_2 = e23.Length2();
+
+    double cir_2 = l12_2 + l13_2 + l23_2;
+    Vec3d area_v = Cross (e12, e13);
+    double area = 0.5 * area_v.Length();
+
+    if (area <= 1e-24 * cir_2)
+      return 1e10;
+
+    double badness = c_trig * cir_2 / area - 1;
+
+    if (metricweight > 0)
+      {
+	// area = (x2 - x1) * (y3 - y1) - (x3 - x1) * (y2 - y1);
+	// add:  metricweight * (area / h^2 + h^2 / area - 2)
+
+	const double areahh = area / (h * h);
+	badness += metricweight * (areahh + 1 / areahh - 2);
+      }
+
+    return badness;
+  }
+
+
+  double CalcTriangleBadness (const Point3d & p1, 
+			      const Point3d & p2, 
+			      const Point3d & p3,
+			      const Vec3d & n,
+			      double metricweight,
+			      double h)
+  {
+    Vec3d v1 (p1, p2);
+    Vec3d v2 (p1, p3);
+
+    Vec3d e1 = v1;
+    Vec3d e2 = v2;
+
+    e1 -= (e1 * n) * n;
+    e1 /= (e1.Length() + 1e-24);
+    e2 = Cross (n, e1);
+
+    return CalcTriangleBadness ( (e1 * v1), (e1 * v2), (e2 * v2), 
+				 metricweight, h);
+  }
+
+
+
+  class Opti2dLocalData
+  {
+  public:
+    const MeshOptimize2d * meshthis;
+    MeshPoint sp1; 
+    PointGeomInfo gi1;
+    Vec<3> normal, t1, t2;
+    Array<SurfaceElementIndex> locelements;
+    Array<int> locrots;
+    Array<double> lochs;
+  // static int locerr2;
+    double locmetricweight;
+    double loch;
+    int surfi, surfi2;
+    int uselocalh;
+  public:
+    Opti2dLocalData ()
+    {
+      locmetricweight = 0;
+    }
+  };
+
+
+  class Opti2SurfaceMinFunction : public MinFunction
+  {
+    const Mesh & mesh;
+    Opti2dLocalData & ld;
+  public:
+    Opti2SurfaceMinFunction (const Mesh & amesh,
+			     Opti2dLocalData & ald)
+      : mesh(amesh), ld(ald)
+    { } ;
+    virtual double FuncGrad (const Vector & x, Vector & g) const;
+    virtual double FuncDeriv (const Vector & x, const Vector & dir, double & deriv) 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
+  {
+    Vec<3> n, vgrad;
+    Point<3> pp1;
+    double g1x, g1y;
+    double badness, hbadness;
+
+    vgrad = 0;
+    badness = 0;
+
+    ld.meshthis -> GetNormalVector (ld.surfi, ld.sp1, ld.gi1, n);
+    pp1 = ld.sp1 + x(0) * ld.t1 + x(1) * ld.t2;
+
+    //  meshthis -> ProjectPoint (surfi, pp1);
+    // meshthis -> GetNormalVector (surfi, pp1, n);
+
+    for (int j = 0; j < ld.locelements.Size(); j++)
+      {
+	int roti = ld.locrots[j];
+	const Element2d & bel = mesh[ld.locelements[j]];
+
+	Vec<3> e1 = mesh[bel.PNumMod(roti + 1)] - pp1;
+	Vec<3> e2 = mesh[bel.PNumMod(roti + 2)] - pp1;
+
+	if (ld.uselocalh) ld.loch = ld.lochs[j];
+
+	double e1l = e1.Length();
+	if (Determinant(e1, e2, n) > 1e-8 * e1l * e2.Length())
+	  {
+	    e1 /= e1l;
+	    double e1e2 = e1 * e2;
+            e2 -= e1e2 * e1;
+	    double e2l = e2.Length();
+
+	    CalcTriangleBadness ( e1l, e1e2, e2l, ld.locmetricweight, ld.loch,
+				  hbadness, g1x, g1y);
+
+	    badness += hbadness;
+            vgrad += g1x * e1 + (g1y/e2l) * e2;
+	  }
+	else
+	  {
+	    // (*testout) << "very very bad badness" << endl;
+	    badness += 1e8;
+	  }
+      }
+
+    vgrad -=  (vgrad * n) * n;
+
+    grad(0) = vgrad * ld.t1;
+    grad(1) = vgrad * ld.t2;
+    return badness;
+  }
+
+
+
+
+  double Opti2SurfaceMinFunction :: 
+  FuncDeriv (const Vector & x, const Vector & dir, double & deriv) const
+  {
+    Vec<3> n, vgrad;
+    Point<3> pp1;
+    double g1x, g1y;
+    double badness, hbadness;
+
+    vgrad = 0;
+    badness = 0;
+
+    ld.meshthis -> GetNormalVector (ld.surfi, ld.sp1, ld.gi1, n);
+
+    pp1 = ld.sp1 + x(0) * ld.t1 + x(1) * ld.t2;
+
+    for (int j = 0; j < ld.locelements.Size(); j++)
+      {
+	int roti = ld.locrots[j];
+
+	const Element2d & bel = mesh[ld.locelements[j]];
+
+	Vec<3> e1 = mesh[bel.PNumMod(roti + 1)] - pp1;
+	Vec<3> e2 = mesh[bel.PNumMod(roti + 2)] - pp1;
+
+	if (ld.uselocalh) ld.loch = ld.lochs[j];
+
+	double e1l = e1.Length();
+	if (Determinant(e1, e2, n) > 1e-8 * e1l * e2.Length())
+	  {
+	    e1 /= e1l;
+	    double e1e2 = e1 * e2;
+	    e2 -= e1e2 * e1;
+	    double e2l = e2.Length();
+	    CalcTriangleBadness ( e1l, e1e2, e2l, ld.locmetricweight, ld.loch,
+				  hbadness, g1x, g1y);
+
+	    badness += hbadness;
+            vgrad += g1x * e1 + (g1y / e2l) * e2;
+	  }
+	else
+	  {
+	    // (*testout) << "very very bad badness" << endl;
+	    badness += 1e8;
+	  }
+      }
+
+    vgrad -= (vgrad * n) * n;
+    deriv = dir(0) * (vgrad*ld.t1) + dir(1) * (vgrad*ld.t2);
+
+    return badness;
+  }
+
+
+
+
+
+
+
+
+
+
+
+
+  class Opti2EdgeMinFunction : public MinFunction
+  {
+    const Mesh & mesh;
+    Opti2dLocalData & ld;
+
+  public:
+    Opti2EdgeMinFunction (const Mesh & amesh,
+			  Opti2dLocalData & ald)
+      : mesh(amesh), ld(ald) { } ;
+
+    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;
+    Vec<3> n1, n2, v1, v2, e1, e2, vgrad;
+    Point<3> pp1;
+    Vec<2> g1;
+    double badness, hbadness;
+
+    vgrad = 0.0;
+    badness = 0;
+
+    pp1 = ld.sp1 + x(0) * ld.t1;
+    ld.meshthis -> ProjectPoint2 (ld.surfi, ld.surfi2, pp1);
+
+    for (j = 0; j < ld.locelements.Size(); j++)
+      {
+	rot = ld.locrots[j];
+	const Element2d & bel = mesh[ld.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 (ld.uselocalh) ld.loch = ld.lochs[j];
+	CalcTriangleBadness ( (e1 * v1), (e1 * v2), (e2 * v2), ld.locmetricweight, ld.loch,
+			      hbadness, g1(0), g1(1));
+
+	badness += hbadness;
+        vgrad += g1(0) * e1 + g1(1) * e2;
+      }
+
+    ld.meshthis -> GetNormalVector (ld.surfi, pp1, n1);
+    ld.meshthis -> GetNormalVector (ld.surfi2, pp1, n2);
+
+    v1 = Cross (n1, n2);
+    v1.Normalize();
+
+    grad(0) = (vgrad * v1) * (ld.t1 * v1);
+
+    return badness;
+  }
+
+
+
+
+  class Opti2SurfaceMinFunctionJacobian : public MinFunction
+  {
+    const Mesh & mesh;
+    Opti2dLocalData & ld;
+
+  public:
+    Opti2SurfaceMinFunctionJacobian (const Mesh & amesh,
+				     Opti2dLocalData & ald)
+      : mesh(amesh), ld(ald)
+    { } ;
+    virtual double FuncGrad (const Vector & x, Vector & g) const;
+    virtual double FuncDeriv (const Vector & x, const Vector & dir, double & deriv) 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 lpi, gpi;
+    Vec<3> n, vgrad;
+    Point<3> pp1;
+    Vec2d g1, vdir;
+    double badness, hbad, hderiv;
+
+    vgrad = 0;
+    badness = 0;
+
+    ld.meshthis -> GetNormalVector (ld.surfi, ld.sp1, ld.gi1, n);
+
+    pp1 = ld.sp1 + x(0) * ld.t1 + x(1) * ld.t2;
+
+    //  meshthis -> ProjectPoint (surfi, pp1);
+    //  meshthis -> GetNormalVector (surfi, pp1, n);
+
+    static Array<Point2d> pts2d;
+    pts2d.SetSize(mesh.GetNP());
+
+    grad = 0;
+
+    for (int j = 1; j <= ld.locelements.Size(); j++)
+      {
+	lpi = ld.locrots.Get(j);
+	const Element2d & bel = 
+	  mesh[ld.locelements.Get(j)];
+      
+	gpi = bel.PNum(lpi);
+
+	for (int k = 1; k <= bel.GetNP(); k++)
+	  {
+	    PointIndex pi = bel.PNum(k);
+	    pts2d.Elem(pi) = Point2d (ld.t1 * (mesh.Point(pi) - ld.sp1), 
+				      ld.t2 * (mesh.Point(pi) - ld.sp1)); 
+	  }				    
+	pts2d.Elem(gpi) = Point2d (x(0), x(1));
+      
+
+	for (int 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(k-1) += hderiv;
+	    if (k == 1)
+	      badness += hbad;
+	  }
+      }
+
+
+    /*
+      vgrad.Add (-(vgrad * n), n);
+
+      grad.Elem(1) = vgrad * t1;
+      grad.Elem(2) = vgrad * t2;
+    */
+    return badness;
+  }
+
+
+
+
+  double Opti2SurfaceMinFunctionJacobian :: 
+  FuncDeriv (const Vector & x, const Vector & dir, double & deriv) const
+  {
+    // from 2d:
+
+    int j, k, lpi, gpi;
+    Vec<3> n, vgrad;
+    Point<3> pp1;
+    Vec2d g1, vdir;
+    double badness, hbad, hderiv;
+
+    vgrad = 0;
+    badness = 0;
+
+    ld.meshthis -> GetNormalVector (ld.surfi, ld.sp1, ld.gi1, n);
+
+    // pp1 = sp1;
+    //    pp1.Add2 (x.Get(1), t1, x.Get(2), t2);
+    pp1 = ld.sp1 + x(0) * ld.t1 + x(1) * ld.t2;
+
+    static Array<Point2d> pts2d;
+    pts2d.SetSize(mesh.GetNP());
+
+    deriv = 0;
+
+    for (j = 1; j <= ld.locelements.Size(); j++)
+      {
+	lpi = ld.locrots.Get(j);
+	const Element2d & bel = 
+	  mesh[ld.locelements.Get(j)];
+      
+	gpi = bel.PNum(lpi);
+
+	for (k = 1; k <= bel.GetNP(); k++)
+	  {
+	    PointIndex pi = bel.PNum(k);
+	    pts2d.Elem(pi) = Point2d (ld.t1 * (mesh.Point(pi) - ld.sp1), 
+				      ld.t2 * (mesh.Point(pi) - ld.sp1)); 
+	  }				    
+	pts2d.Elem(gpi) = Point2d (x(0), x(1));
+      
+
+	vdir = Vec2d (dir(0), dir(1));
+	  
+	hbad = bel.
+	  CalcJacobianBadnessDirDeriv (pts2d, lpi, vdir, hderiv);
+      
+	deriv += hderiv;
+	badness += hbad;
+      }
+
+
+    return badness;
+  }
+
+
+
+
+
+
+
+  MeshOptimize2d dummy;
+
+  MeshOptimize2d :: MeshOptimize2d ()
+  {
+    SetFaceIndex (0);
+    SetImproveEdges (0);
+    SetMetricWeight (0);
+    SetWriteStatus (1);
+  }
+
+
+  void MeshOptimize2d :: SelectSurfaceOfPoint (const Point<3> & p,
+					       const PointGeomInfo & gi)
+  {
+    ;
+  }
+
+  void MeshOptimize2d :: ImproveMesh (Mesh & mesh, const MeshingParameters & mp)
+  {
+    if (!faceindex)
+      {
+	PrintMessage (3, "Smoothing");
+
+	for (faceindex = 1; faceindex <= mesh.GetNFD(); faceindex++)
+	  {
+	    ImproveMesh (mesh, mp);
+	    if (multithread.terminate)
+	      throw NgException ("Meshing stopped");
+	  }
+	faceindex = 0;
+	return;
+      }
+ 
+
+    static int timer = NgProfiler::CreateTimer ("MeshSmoothing 2D");
+    static int timer1 = NgProfiler::CreateTimer ("MeshSmoothing 2D start");
+
+    NgProfiler::RegionTimer reg (timer);
+    NgProfiler::StartTimer (timer1);
+
+    CheckMeshApproximation (mesh);
+
+    Opti2dLocalData ld;
+
+    // SurfaceElementIndex sei;
+
+    Array<SurfaceElementIndex> seia;
+    mesh.GetSurfaceElementsOfFace (faceindex, seia);
+
+    bool mixed = 0;
+    for (int 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<MeshPoint, PointIndex::BASE> savepoints(mesh.GetNP());
+
+    ld.uselocalh = mp.uselocalh;
+
+
+    Array<int, PointIndex::BASE> nelementsonpoint(mesh.GetNP());
+    nelementsonpoint = 0;
+    for (int i = 0; i < seia.Size(); i++)
+      {
+	const Element2d & el = mesh[seia[i]];
+	for (int j = 0; j < el.GetNP(); j++)
+	  nelementsonpoint[el[j]]++;
+      }
+
+    TABLE<SurfaceElementIndex,PointIndex::BASE> elementsonpoint(nelementsonpoint);
+
+    for (int i = 0; i < seia.Size(); i++)
+      {
+	const Element2d & el = mesh[seia[i]];
+	for (int j = 0; j < el.GetNP(); j++)
+	  elementsonpoint.Add (el[j], seia[i]);
+      }
+
+
+    ld.loch = mp.maxh;
+    ld.locmetricweight = metricweight;
+    ld.meshthis = this;
+
+
+
+    Opti2SurfaceMinFunction surfminf(mesh, ld);
+    Opti2EdgeMinFunction edgeminf(mesh, ld);
+    Opti2SurfaceMinFunctionJacobian surfminfj(mesh, ld);
+
+    OptiParameters par;
+    par.maxit_linsearch = 8;
+    par.maxit_bfgs = 5;
+
+    /*
+    int i, j, k;
+
+      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;
+      }
+    if (mesh.GetNP() > 10000)
+      {
+	plotchar = 'o';
+	modplot = 100;
+      }
+    int cnt = 0;
+
+
+    NgProfiler::StopTimer (timer1);
+
+
+    for (PointIndex pi = PointIndex::BASE; pi < mesh.GetNP()+PointIndex::BASE; pi++)
+      if (mesh[pi].Type() == SURFACEPOINT)
+	{
+	  if (multithread.terminate)
+	    throw NgException ("Meshing stopped");
+	
+	  cnt++;
+	  if (cnt % modplot == 0 && writestatus)
+	    {
+	      printeddot = 1;
+	      PrintDot (plotchar);
+	    }
+
+	  if (elementsonpoint[pi].Size() == 0)
+	    continue;
+
+	
+	  ld.sp1 = mesh[pi];
+
+	  Element2d & hel = mesh[elementsonpoint[pi][0]];
+
+	  int hpi = 0;
+	  for (int j = 1; j <= hel.GetNP(); j++)
+	    if (hel.PNum(j) == pi)
+	      {
+		hpi = j;
+		break;
+	      }
+
+	  ld.gi1 = hel.GeomInfoPi(hpi);
+	  SelectSurfaceOfPoint (ld.sp1, ld.gi1);
+	  
+	  ld.locelements.SetSize(0);
+	  ld.locrots.SetSize (0);
+	  ld.lochs.SetSize (0);
+	
+	  for (int j = 0; j < elementsonpoint[pi].Size(); j++)
+	    {
+	      SurfaceElementIndex sei = elementsonpoint[pi][j];
+	      const Element2d & bel = mesh[sei];
+	      ld.surfi = mesh.GetFaceDescriptor(bel.GetIndex()).SurfNr();
+	    
+	      ld.locelements.Append (sei);
+	    
+	      for (int k = 1; k <= bel.GetNP(); k++)
+		if (bel.PNum(k) == pi)
+		  {
+		    ld.locrots.Append (k);
+		    break;
+		  }
+	      
+	      if (ld.uselocalh)
+		{
+		  Point3d pmid = Center (mesh[bel[0]], mesh[bel[1]], mesh[bel[2]]);
+		  ld.lochs.Append (mesh.GetH(pmid));
+		}
+	    }
+	  
+	  GetNormalVector (ld.surfi, ld.sp1, ld.gi1, ld.normal);
+	  ld.t1 = ld.normal.GetNormal ();
+	  ld.t2 = Cross (ld.normal, ld.t1);
+	  
+	  // save points, and project to tangential plane
+	  for (int j = 0; j < ld.locelements.Size(); j++)
+	    {
+	      const Element2d & el = mesh[ld.locelements[j]];
+	      for (int k = 0; k < el.GetNP(); k++)
+		savepoints[el[k]] = mesh[el[k]];
+	    }
+
+	  for (int j = 0; j < ld.locelements.Size(); j++)
+	    {
+	      const Element2d & el = mesh[ld.locelements[j]];
+	      for (int k = 0; k < el.GetNP(); k++)
+		{
+		  PointIndex hhpi = el[k];
+		  double lam = ld.normal * (mesh[hhpi] - ld.sp1);
+		  mesh[hhpi] -= lam * ld.normal;
+		}
+	    }
+	  
+	  x = 0;
+	  par.typx = ld.lochs[0];
+
+	  if (mixed)
+	    {
+	      //	      (*testout) << "vorher : " << surfminfj.Func (x) << endl;
+	      BFGS (x, surfminfj, par, 1e-6);
+	      //	      (*testout) << "nachher: " << surfminfj.Func (x) << endl;
+	      //	      (*testout) << "x = " << x << endl;
+	    }
+	  else
+	    {
+	      //	      (*testout) << "vorher : " << surfminf.Func (x) << endl;
+	      BFGS (x, surfminf, par, 1e-6);
+	      //	      (*testout) << "nachher: " << surfminf.Func (x) << endl;
+	      //	      (*testout) << "x = " << x << endl;
+	    }
+
+	
+	  origp = mesh[pi];
+	  loci = 1;
+	  fact = 1;
+	  moveisok = 0;
+
+	  // restore other points
+	  for (int j = 0; j < ld.locelements.Size(); j++)
+	    {
+	      const Element2d & el = mesh[ld.locelements[j]];
+	      for (int k = 0; k < el.GetNP(); k++)
+		{
+		  PointIndex hhpi = el[k];
+		  if (hhpi != pi) mesh[hhpi] = savepoints[hhpi];
+		}
+	    }
+
+	  
+	  //optimizer loop (if 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;
+              */
+              Vec<3> hv = x(0) * ld.t1 + x(1) * ld.t2;
+              Point3d hnp = origp + Vec3d (hv);
+              mesh[pi](0) = hnp.X();
+              mesh[pi](1) = hnp.Y();
+              mesh[pi](2) = hnp.Z();
+
+	      fact = fact/2.;
+
+	      // ProjectPoint (surfi, mesh[pi]);
+	      // moveisok = CalcPointGeomInfo(surfi, ngi, mesh[pi]); 
+
+	      ngi = ld.gi1;
+	      moveisok = ProjectPointGI (ld.surfi, mesh[pi], ngi);
+	      // point lies on same chart in stlsurface
+	    
+	      if (moveisok)
+		{
+		  for (int j = 0; j < ld.locelements.Size(); j++)
+		    mesh[ld.locelements[j]].GeomInfoPi(ld.locrots[j]) = ngi;
+		}
+	      else
+		{
+		  mesh[pi] = Point<3> (origp);
+		}
+	    
+	    }
+	}
+
+    if (printeddot)
+      PrintDot ('\n');
+  
+    CheckMeshApproximation (mesh);
+    mesh.SetNextTimeStamp();
+  }
+
+  void MeshOptimize2d :: GetNormalVector(INDEX /* surfind */, const Point<3> & p, Vec<3> & nv) const
+  {
+    nv = Vec<3> (0, 0, 1);
+  }
+
+  void MeshOptimize2d :: GetNormalVector(INDEX surfind, const Point<3> & p, PointGeomInfo & gi, Vec<3> & n) const
+  {
+    GetNormalVector (surfind, p, n);
+  }
+}
diff --git a/contrib/Netgen/libsrc/meshing/smoothing3.cpp b/contrib/Netgen/libsrc/meshing/smoothing3.cpp
new file mode 100644
index 0000000000..bf2958848b
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/smoothing3.cpp
@@ -0,0 +1,1838 @@
+#include <mystdlib.h>
+
+#include "meshing.hpp"
+#ifdef SOLIDGEOM
+#include <csg.hpp>
+#endif
+#include <opti.hpp>
+
+
+namespace netgen
+{
+  
+
+  double MinFunctionSum :: Func (const Vector & x) const
+  {
+    double retval = 0;
+    for(int i=0; i<functions.Size(); i++)
+      retval += functions[i]->Func(x);
+      
+    return retval;
+  }
+
+  void MinFunctionSum :: Grad (const Vector & x, Vector & g) const
+  {
+    g = 0.;
+    VectorMem<3> gi;
+    for(int i=0; i<functions.Size(); i++)
+      {
+	functions[i]->Grad(x,gi);
+	for(int j=0; j<g.Size(); j++)
+	  g[j] += gi[j];
+      }
+  }
+      
+
+  double MinFunctionSum :: FuncGrad (const Vector & x, Vector & g) const
+  {
+    double retval = 0;
+    g = 0.;
+    VectorMem<3> gi;
+    for(int i=0; i<functions.Size(); i++)
+      {
+	retval += functions[i]->FuncGrad(x,gi);
+	for(int j=0; j<g.Size(); j++)
+	  g[j] += gi[j];
+      }
+    return retval;
+  }
+
+  double MinFunctionSum :: FuncDeriv (const Vector & x, const Vector & dir, double & deriv) const
+  {
+    double retval = 0;
+    deriv = 0.;
+    double derivi;
+    for(int i=0; i<functions.Size(); i++)
+      {
+	retval += functions[i]->FuncDeriv(x,dir,derivi);
+	deriv += derivi;
+      }
+    return retval;
+  }
+
+  double MinFunctionSum :: GradStopping (const Vector & x) const
+  {
+    double minfs(0), mini;
+    for(int i=0; i<functions.Size(); i++)
+      {
+	mini = functions[i]->GradStopping(x);
+	if(i==0 || mini < minfs)
+	  minfs = mini;
+      }
+    return minfs;
+  }
+
+
+  void MinFunctionSum :: AddFunction(MinFunction & fun)
+  {
+    functions.Append(&fun);
+  }
+  
+  const MinFunction & MinFunctionSum :: Function(int i) const
+  {
+    return *functions[i];
+  }
+  MinFunction & MinFunctionSum :: Function(int i)
+  {
+    return *functions[i];
+  }
+
+  PointFunction1 :: PointFunction1 (Mesh::T_POINTS & apoints, 
+				    const Array<INDEX_3> & afaces,
+				    const MeshingParameters & amp,
+				    double ah)
+    : points(apoints), faces(afaces), mp(amp)
+  {
+    h = ah;
+  }
+  
+
+  double PointFunction1 :: Func (const Vector & vp) const
+  {
+    double badness = 0;
+    Point<3> pp(vp(0), vp(1), vp(2));
+
+    for (int j = 0; j < faces.Size(); j++)
+      {
+	const INDEX_3 & el = faces[j];
+
+	double bad = CalcTetBadness (points[el.I1()], 
+				     points[el.I3()], 
+				     points[el.I2()], 
+				     pp, 0, mp);
+	badness += bad;
+      }
+ 
+    return badness;
+  }
+
+
+  double PointFunction1 :: 
+  FuncDeriv (const Vector & x, const Vector & dir, double & deriv) const
+  {
+    VectorMem<3> hx;
+    const 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
+  {
+    VectorMem<3> hx;
+    double eps = 1e-6;
+
+    hx = x;
+    for (int i = 0; i < 3; i++)
+      {
+	hx(i) = x(i) + eps * h;
+	double fr = Func (hx);
+	hx(i) = x(i) - eps * h;
+	double fl = Func (hx);
+	hx(i) = x(i);
+
+	g(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 */
+
+  // is it used ????
+  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 nf = faces.Size();
+
+    m.SetSize (nf, 4);
+  
+    for (int i = 1; i <= nf; i++)
+      {
+	const Point3d & p1 = points[faces.Get(i).I1()];
+	const Point3d & p2 = points[faces.Get(i).I2()];
+	const Point3d & p3 = points[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;
+    VectorMem<4> hv;
+    Vector res(m.Height());
+
+    for (i = 0;i < 3; i++)
+      hv(i) = vp(i);
+    hv(3) = 1;
+    m.Mult (hv, res);
+
+    for (i = 1; i <= res.Size(); i++)
+      {
+	if (res(i-1) < 1e-10)
+	  badness += 1e24;
+	else
+	  badness += 1 / res(i-1);
+      }
+ 
+    return badness;
+  }
+
+
+  double CheapPointFunction1 :: FuncGrad (const Vector & x, Vector & g) const
+  {
+    VectorMem<3> hx;
+    double eps = 1e-6;
+
+    hx = x;
+    for (int i = 0; i < 3; i++)
+      {
+	hx(i) = x(i) + eps * h;
+	double fr = Func (hx);
+	hx(i) = x(i) - eps * h;
+	double fl = Func (hx);
+	hx(i) = x(i);
+
+	g(i) = (fr - fl) / (2 * eps * h);
+      }
+
+    return Func(x);
+  }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+  /* ************* PointFunction **************************** */
+
+
+  class PointFunction 
+  {
+  public:
+    Mesh::T_POINTS & points;
+    const Mesh::T_VOLELEMENTS & elements;
+    TABLE<int,PointIndex::BASE> elementsonpoint;
+    const MeshingParameters & mp;
+    PointIndex actpind;
+    double h;
+  
+  public:
+    PointFunction (Mesh::T_POINTS & apoints, 
+		   const Mesh::T_VOLELEMENTS & aelements,
+		   const MeshingParameters & amp);
+  
+    virtual void SetPointIndex (PointIndex aactpind);
+    void SetLocalH (double ah) { h = ah; }
+    double GetLocalH () const { return h; }
+    virtual double PointFunctionValue (const Point<3> & pp) const;
+    virtual double PointFunctionValueGrad (const Point<3> & pp, Vec<3> & grad) const;
+    virtual double PointFunctionValueDeriv (const Point<3> & pp, const Vec<3> & dir, double & deriv) const;
+
+    int MovePointToInner ();
+  };
+
+
+  PointFunction :: PointFunction (Mesh::T_POINTS & apoints, 
+				  const Mesh::T_VOLELEMENTS & aelements,
+				  const MeshingParameters & amp)
+    : points(apoints), elements(aelements), elementsonpoint(apoints.Size()), mp(amp)
+  {
+    for (int i = 0; i < elements.Size(); i++)
+      if (elements[i].NP() == 4)
+        for (int j = 0; j < elements[i].NP(); j++)
+          elementsonpoint.Add (elements[i][j], i);  
+  }
+
+  void PointFunction :: SetPointIndex (PointIndex aactpind)
+  {
+    actpind = aactpind; 
+  }  
+
+  double PointFunction :: PointFunctionValue (const Point<3> & pp) const
+  {
+    double badness;
+    Point<3> hp;
+
+    badness = 0;
+
+    hp = points[actpind];
+    points[actpind] = Point<3> (pp);
+
+    for (int j = 0; j < elementsonpoint[actpind].Size(); j++)
+      {
+        const Element & el = elements[elementsonpoint[actpind][j]];
+	badness += CalcTetBadness (points[el[0]], points[el[1]], 
+				   points[el[2]], points[el[3]], -1, mp);
+      }
+  
+    points[actpind] = Point<3> (hp); 
+    return badness;
+  }
+
+
+  double PointFunction :: PointFunctionValueGrad (const Point<3> & pp, Vec<3> & grad) const
+  {
+    double f = 0;
+
+    Point<3> hp = points[actpind];
+    Vec<3> vgradi, vgrad(0,0,0);
+    points[actpind] = Point<3> (pp);
+
+    for (int j = 0; j < elementsonpoint[actpind].Size(); j++)
+      {
+        const Element & el = elements[elementsonpoint[actpind][j]];
+	for (int k = 0; k < 4; k++)
+	  if (el[k] == actpind)
+	    {
+	      f += CalcTetBadnessGrad (points[el[0]], points[el[1]], 
+                                       points[el[2]], points[el[3]], 
+                                       -1, k+1, vgradi, mp);
+
+              vgrad += vgradi;
+	    }
+      }
+
+    points[actpind] = Point<3> (hp); 
+
+    grad = vgrad;
+    return f;
+  }
+
+
+  double PointFunction :: PointFunctionValueDeriv (const Point<3> & pp, const Vec<3> & dir,
+						   double & deriv) const
+  {
+    Vec<3> vgradi, vgrad(0,0,0);
+
+    Point<3> hp = points[actpind];
+    points[actpind] = pp;
+    double f = 0;
+
+    for (int j = 0; j < elementsonpoint[actpind].Size(); j++)
+      {
+        const Element & el = elements[elementsonpoint[actpind][j]];
+
+	for (int k = 1; k <= 4; k++)
+	  if (el.PNum(k) == actpind)
+	    {
+	      f += CalcTetBadnessGrad (points[el.PNum(1)], 
+				       points[el.PNum(2)], 
+				       points[el.PNum(3)], 
+				       points[el.PNum(4)], -1, k, vgradi, mp);
+
+	      vgrad += vgradi;
+	    }
+      }
+
+    points[actpind] = Point<3> (hp); 
+    deriv = dir * vgrad;
+    return f;
+  }
+
+  int PointFunction :: MovePointToInner ()
+  {
+    // try point movement 
+    Array<Element2d> faces;
+  
+    for (int j = 0; j < elementsonpoint[actpind].Size(); j++)
+      {
+	const Element & el = 
+	  elements[elementsonpoint[actpind][j]];
+      
+	for (int 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[actpind] = Point<3> (hp);
+      }
+    else
+      ;
+    //      cout << "no inner point found" << endl;
+
+    /*
+    Point3d hp2;
+    int hi2 = FindInnerPoint (points, faces, hp2);
+    if (hi2)
+      {
+	cout << "new: inner point found" << endl;
+      }
+    else
+      cout << "new: no inner point found" << endl;
+  
+    (*testout) << "hi(orig) = " << hi << ", hi(new) = " << hi2;
+    if (hi != hi2) (*testout) << "hi different" << endl;
+    */
+
+    return hi;
+  }
+
+
+
+
+
+
+  class CheapPointFunction : public PointFunction
+  {
+    DenseMatrix m;
+  public:
+    CheapPointFunction (Mesh::T_POINTS & apoints, 
+			const Mesh::T_VOLELEMENTS & aelements,
+			const MeshingParameters & amp);
+    virtual void SetPointIndex (PointIndex aactpind);
+    virtual double PointFunctionValue (const Point<3> & pp) const;
+    virtual double PointFunctionValueGrad (const Point<3> & pp, Vec<3> & grad) const;
+  };
+
+
+  CheapPointFunction :: CheapPointFunction (Mesh::T_POINTS & apoints, 
+					    const Mesh::T_VOLELEMENTS & aelements,
+					    const MeshingParameters & amp)
+    : PointFunction (apoints, aelements, amp)
+  {
+    ;
+  }
+
+
+  void CheapPointFunction :: SetPointIndex (PointIndex aactpind)
+  {
+    actpind = aactpind; 
+
+    int ne = elementsonpoint[actpind].Size();
+    int i, j;
+    int pi1, pi2, pi3;
+
+    m.SetSize (ne, 4);
+
+    for (i = 0; i < ne; i++)
+      {
+	pi1 = 0;
+	pi2 = 0;
+	pi3 = 0;
+
+	const Element & el = elements[elementsonpoint[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[pi1];
+	Vec3d v1 (p1, points[pi2]);
+	Vec3d v2 (p1, points[pi3]);
+	Vec3d n;
+	Cross (v1, v2, n);
+	n /= n.Length();
+
+	Vec3d v (p1, points[actpind]);
+	double c = v * n;
+      
+	if (c < 0)
+	  n *= -1;    
+      
+	// n is inner normal
+
+	m.Elem(i+1, 1) = n.X();
+	m.Elem(i+1, 2) = n.Y();
+	m.Elem(i+1, 3) = n.Z();
+	m.Elem(i+1, 4) = - (n.X() * p1.X() + n.Y() * p1.Y() + n.Z() * p1.Z());
+      }
+  }
+
+  double CheapPointFunction :: PointFunctionValue (const Point<3> & pp) const
+  {
+    VectorMem<4> p4;
+    Vector di;
+    int n = m.Height();
+
+    p4(0) = pp(0);
+    p4(1) = pp(1);
+    p4(2) = pp(2);
+    p4(3) = 1;
+
+    di.SetSize (n);
+    m.Mult (p4, di);
+  
+    double sum = 0;
+    for (int i = 0; i < n; i++)
+      {
+	if (di(i) > 0)
+	  sum += 1 / di(i);
+	else
+	  return 1e16;
+      }
+    return sum;
+  }
+
+
+
+
+  double CheapPointFunction :: PointFunctionValueGrad (const Point<3> & pp, Vec<3> & grad) const
+  {
+    VectorMem<4> p4;
+    Vector di;
+
+    int n = m.Height();
+
+    p4(0) = pp(0);
+    p4(1) = pp(1);
+    p4(2) = pp(2);
+    p4(3) = 1;
+
+    di.SetSize (n);
+    m.Mult (p4, di);
+  
+    double sum = 0;
+    grad = 0;
+    for (int i = 0; i < n; i++)
+      {
+	if (di(i) > 0)
+	  {
+	    double idi = 1 / di(i);
+	    sum += idi;
+	    grad(0) -= idi * idi * m(i, 0);
+	    grad(1) -= idi * idi * m(i, 1);
+	    grad(2) -= idi * idi * m(i, 2);
+	  }
+	else
+	  {
+	    return 1e16;
+	  }
+      }
+    return sum;
+  }
+
+
+
+
+
+
+
+
+  class Opti3FreeMinFunction : public MinFunction
+  { 
+    const PointFunction & pf;
+    Point<3> sp1;
+  
+  public:
+    Opti3FreeMinFunction (const PointFunction & apf);
+    void SetPoint (const Point<3> & 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
+  {
+    Point<3> pp;
+    for (int j = 0; j < 3; j++)
+      pp(j) = sp1(j) + x(j);
+    return pf.PointFunctionValue (pp);
+  }
+  
+  double Opti3FreeMinFunction :: FuncGrad (const Vector & x, Vector & grad) const
+  {
+    Vec<3> vgrad;
+    Point<3> pp;
+
+    for (int j = 0; j < 3; j++)
+      pp(j) = sp1(j) + x(j);
+
+    double val = pf.PointFunctionValueGrad (pp, vgrad);
+
+    for (int j = 0; j < 3; j++)
+      grad(j) = vgrad(j);
+
+    return val;
+  }
+
+  double Opti3FreeMinFunction :: FuncDeriv (const Vector & x, const Vector & dir, double & deriv) const
+  {
+    Point<3> pp;
+
+    for (int j = 0; j < 3; j++)
+      pp(j) = sp1(j) + x(j);
+
+    Vec<3> vdir;
+    for (int j = 0; j < 3; j++)
+      vdir(j) = dir(j);
+
+    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();
+
+    Vector hx;
+    hx.SetSize(n);
+
+    double eps = 1e-8;
+    double f, f11, f22; //, f12, f21
+
+    f = Func(x);
+  
+    for (int i = 1; i <= n; i++)
+      {
+	for (int 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(i-1) = x(i-1) + eps;
+	f11 = Func(hx);
+	hx(i-1) = x(i-1) - 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;
+    VectorMem<3> freegrad;
+
+    CalcNewPoint (x, pp1);
+
+    double 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;
+  VectorMem<3> freegrad;
+
+  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 CalcTotalBad (const Mesh::T_POINTS & points, 
+		     const Mesh::T_VOLELEMENTS & elements,
+		     const MeshingParameters & mp)
+{
+  double sum = 0;
+  double elbad;
+  
+  tets_in_qualclass.SetSize(20);
+  tets_in_qualclass = 0;
+
+  double teterrpow = mp.opterrpow;
+
+  for (int i = 1; i <= elements.Size(); i++)
+    {
+      elbad = pow (max2(CalcBad (points, elements.Get(i), 0, mp),1e-10),
+		   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;
+//   PointIndex actpind;
+  
+// public:
+//   JacobianPointFunction (Mesh::T_POINTS & apoints, 
+// 			 const Mesh::T_VOLELEMENTS & aelements);
+  
+//   virtual void SetPointIndex (PointIndex 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);  
+    }
+
+  onplane = false;
+}
+
+void JacobianPointFunction :: SetPointIndex (PointIndex aactpind)
+{
+  actpind = aactpind; 
+}  
+
+
+double JacobianPointFunction :: Func (const Vector & v) const
+{
+  int j;
+  double badness = 0;
+
+  Point<3> hp = points.Elem(actpind);
+
+  points.Elem(actpind) = hp + Vec<3> (v(0), v(1), v(2));
+
+  if(onplane)
+    points.Elem(actpind) -= (v(0)*nv(0)+v(1)*nv(1)+v(2)*nv(2)) * nv;
+
+
+  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;
+
+  Point<3> hp = points.Elem(actpind);
+  points.Elem(actpind) = hp + Vec<3> (x(0), x(1), x(2));
+
+  if(onplane)
+    points.Elem(actpind) -= (x(0)*nv(0)+x(1)*nv(1)+x(2)*nv(2)) * nv;
+
+  Vec<3> 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;
+
+      badness += elements.Get(eli).
+	CalcJacobianBadnessGradient (points, lpi, hderiv);
+
+      for(k=0; k<3; k++)
+	g(k) += hderiv(k);
+	
+      /*
+      for (k = 1; k <= 3; k++)
+	{
+	  vdir = Vec3d(0,0,0);
+	  vdir.X(k) = 1;
+
+	  hbad = elements.Get(eli).
+	    CalcJacobianBadnessDirDeriv (points, lpi, vdir, hderiv);
+	  //(*testout) << "hderiv " << k << ": " << hderiv << endl;
+	  g.Elem(k) += hderiv;
+	  if (k == 1)
+	    badness += hbad;
+	}
+      */
+    }
+
+  if(onplane)
+    {
+      double scal = nv(0)*g(0) + nv(1)*g(1) + nv(2)*g(2);
+      g(0) -= scal*nv(0);
+      g(1) -= scal*nv(1);
+      g(2) -= scal*nv(2);
+    }
+
+  //(*testout) << "g = " << g << endl;
+
+  
+  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;
+
+  Point<3> hp = points.Elem(actpind);
+  points.Elem(actpind) = Point<3> (hp + Vec3d (x(0), x(1), x(2)));
+
+  if(onplane)
+    points.Elem(actpind) -= (Vec3d (x(0), x(1), x(2))*nv) * nv;
+
+  double hderiv;
+  deriv = 0;
+  Vec<3> vdir(dir(0), dir(1), dir(2));
+ 
+  if(onplane)
+    {
+      double scal = vdir * nv;
+      vdir -= scal*nv;
+    }
+
+  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;
+  
+}
+
+
+
+
+
+
+
+
+
+
+#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;
+    }
+
+  const 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) << setprecision(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;
+
+  int printmod = 1;
+  char printdot = '.';
+  if (points.Size() > 1000)
+    {
+      printmod = 10;
+      printdot = '+';
+    }
+  if (points.Size() > 10000)
+    {
+      printmod = 100;
+      printdot = '*';
+    }
+
+  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 ('+');
+      */
+      if (i % printmod == 0) PrintDot (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 (const MeshingParameters & mp, OPTIMIZEGOAL goal)
+{
+  int typ = 1;
+  
+  (*testout) << "Improve Mesh" << "\n";
+  PrintMessage (3, "ImproveMesh");
+
+  int np = GetNP();
+  int ne = GetNE();
+
+
+  Array<double,PointIndex::BASE> perrs(np);
+  perrs = 1.0;
+
+  double bad1 = 0;
+  double badmax = 0;
+
+  if (goal == OPT_QUALITY)
+    {
+      for (int i = 1; i <= ne; i++)
+	{
+	  const Element & el = VolumeElement(i);
+	  if (el.GetType() != TET)
+	    continue;
+	  
+	  double hbad = CalcBad (points, el, 0, mp);
+	  for (int j = 0; j < 4; j++)
+	    perrs[el[j]] += hbad;
+	  
+	  bad1 += hbad;
+	}
+      
+      for (PointIndex i = PointIndex::BASE; i < np+PointIndex::BASE; i++)
+	if (perrs[i] > badmax) 
+	  badmax = perrs[i];
+      badmax = 0;
+    }
+
+  if (goal == OPT_QUALITY)
+    {
+      bad1 = CalcTotalBad (points, volelements, mp);
+      (*testout) << "Total badness = " << bad1 << endl;
+      PrintMessage (5, "Total badness = ", bad1);
+    }
+  
+  Vector x(3);
+  
+  (*testout) << setprecision(8);
+  
+  //int uselocalh = mparam.uselocalh;
+
+
+  PointFunction * pf;
+
+  if (typ == 1)
+    pf = new PointFunction(points, volelements, mp);
+  else
+    pf = new CheapPointFunction(points, volelements, mp);
+
+  //  pf->SetLocalH (h);
+  
+  Opti3FreeMinFunction freeminf(*pf);
+
+  OptiParameters par;
+  par.maxit_linsearch = 20;
+  par.maxit_bfgs = 20;
+
+  Array<double, PointIndex::BASE> pointh (points.Size());
+
+  if(lochfunc)
+    {
+      for(int i=1; i<=points.Size(); i++)
+	pointh[i] = GetH(points.Get(i));
+    }
+  else
+    {
+      pointh = 0;
+      for(int i=0; i<GetNE(); i++)
+	{
+	  const Element & el = VolumeElement(i+1);
+	  double h = pow(el.Volume(points),1./3.);
+	  for(int j=1; j<=el.GetNV(); j++)
+	    if(h > pointh[el.PNum(j)])
+	      pointh[el.PNum(j)] = h;
+	}
+    }
+ 
+
+  int printmod = 1;
+  char printdot = '.';
+  if (points.Size() > 1000)
+    {
+      printmod = 10;
+      printdot = '+';
+    }
+  if (points.Size() > 10000)
+    {
+      printmod = 100;
+      printdot = '*';
+    }
+
+
+  const char * savetask = multithread.task;
+  multithread.task = "Smooth Mesh";
+  
+  for (PointIndex i = PointIndex::BASE; 
+       i < points.Size()+PointIndex::BASE; i++)
+    if ( (*this)[i].Type() == INNERPOINT && perrs[i] > 0.01 * badmax)
+      {
+	if (multithread.terminate)
+	  throw NgException ("Meshing stopped");
+
+	multithread.percent = 100.0 * (i+1-PointIndex::BASE) / points.Size();
+        /*
+	if (points.Size() < 1000)
+	  PrintDot ();
+	else
+	  if ( (i+1-PointIndex::BASE) % 10 == 0)
+	    PrintDot ('+');
+        */
+        if (  (i+1-PointIndex::BASE) % printmod == 0) PrintDot (printdot);
+
+	double lh = pointh[i];
+	pf->SetLocalH (lh);
+	par.typx = lh;
+
+	freeminf.SetPoint (points[i]);
+	pf->SetPointIndex (i);
+
+	x = 0;
+	int pok;
+	pok = freeminf.Func (x) < 1e10; 
+
+	if (!pok)
+	  {
+	    pok = pf->MovePointToInner ();
+
+	    freeminf.SetPoint (points[i]);
+	    pf->SetPointIndex (i);
+	  }
+
+	if (pok)
+	  {
+            //*testout << "start BFGS, pok" << endl;
+	    BFGS (x, freeminf, par);
+            //*testout << "BFGS complete, pok" << endl;
+	    points[i](0) += x(0);
+	    points[i](1) += x(1);
+	    points[i](2) += x(2);
+	  }
+      }
+  PrintDot ('\n');
+  
+  
+  delete pf;
+
+  multithread.task = savetask;
+
+  if (goal == OPT_QUALITY)
+    {
+      bad1 = CalcTotalBad (points, volelements, mp);
+      (*testout) << "Total badness = " << bad1 << endl;
+      PrintMessage (5, "Total badness = ", bad1);
+    }
+}
+
+
+
+
+// Improve Condition number of Jacobian, any elements  
+void Mesh :: ImproveMeshJacobian (const MeshingParameters & mp,
+				  OPTIMIZEGOAL goal, const BitArray * usepoint)
+{
+  int i, j;
+  
+  (*testout) << "Improve Mesh Jacobian" << "\n";
+  PrintMessage (3, "ImproveMesh Jacobian");
+
+  int np = GetNP();
+  int ne = GetNE();
+
+  
+  Vector x(3);
+  
+  (*testout) << setprecision(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));
+    }
+
+  Array<double, PointIndex::BASE> pointh (points.Size());
+
+  if(lochfunc)
+    {
+      for(i = 1; i<=points.Size(); i++)
+	pointh[i] = GetH(points.Get(i));
+    }
+  else
+    {
+      pointh = 0;
+      for(i=0; i<GetNE(); i++)
+	{
+	  const Element & el = VolumeElement(i+1);
+	  double h = pow(el.Volume(points),1./3.);
+	  for(j=1; j<=el.GetNV(); j++)
+	    if(h > pointh[el.PNum(j)])
+	      pointh[el.PNum(j)] = h;
+	}
+    }
+ 
+
+
+  const char * savetask = multithread.task;
+  multithread.task = "Smooth Mesh Jacobian";
+  
+  for (i = 1; i <= points.Size(); i++)
+    {
+      if ((*this)[PointIndex(i)].Type() != INNERPOINT)
+	continue;
+
+      if(usepoint && !usepoint->Test(i))
+	continue;
+
+      //(*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 = pointh[i];
+      par.typx = lh;
+
+      pf.SetPointIndex (i);
+
+      x = 0;
+      int pok = (pf.Func (x) < 1e10); 
+
+      if (pok)
+	{
+          //*testout << "start BFGS, Jacobian" << endl;
+	  BFGS (x, pf, par);
+          //*testout << "end BFGS, Jacobian" << endl;
+	  points.Elem(i)(0) += x(0);
+	  points.Elem(i)(1) += x(1);
+	  points.Elem(i)(2) += x(2);
+	}
+      else
+	{
+	  cout << "el not ok" << endl;
+	}
+    }
+  PrintDot ('\n');
+  
+
+  multithread.task = savetask;
+}
+
+
+
+
+// Improve Condition number of Jacobian, any elements  
+void Mesh :: ImproveMeshJacobianOnSurface (const MeshingParameters & mp,
+					   const BitArray & usepoint, 
+					   const Array< Vec<3>* > & nv,
+					   OPTIMIZEGOAL goal,
+					   const Array< Array<int,PointIndex::BASE>* > * idmaps)
+{
+  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);
+
+  Array< Array<int,PointIndex::BASE>* > locidmaps;
+  const Array< Array<int,PointIndex::BASE>* > * used_idmaps;
+
+  if(idmaps)
+    used_idmaps = idmaps;
+  else
+    {
+      used_idmaps = &locidmaps;
+      
+      for(i=1; i<=GetIdentifications().GetMaxNr(); i++)
+	{
+	  if(GetIdentifications().GetType(i) == Identifications::PERIODIC)
+	    {
+	      locidmaps.Append(new Array<int,PointIndex::BASE>);
+	      GetIdentifications().GetMap(i,*locidmaps.Last(),true);
+	    }
+	}
+    }
+
+  
+  bool usesum = (used_idmaps->Size() > 0);
+  MinFunctionSum pf_sum;
+  
+  JacobianPointFunction * pf2ptr = NULL;
+  if(usesum)
+    {
+      pf2ptr = new JacobianPointFunction(points, volelements);
+      pf_sum.AddFunction(pf);
+      pf_sum.AddFunction(*pf2ptr);
+    }
+  
+
+  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));
+    }
+
+  Array<double, PointIndex::BASE> pointh (points.Size());
+ 
+  if(lochfunc)
+    {
+      for(i=1; i<=points.Size(); i++)
+	pointh[i] = GetH(points.Get(i));
+    }
+  else
+    {
+      pointh = 0;
+      for(i=0; i<GetNE(); i++)
+	{
+	  const Element & el = VolumeElement(i+1);
+	  double h = pow(el.Volume(points),1./3.);
+	  for(j=1; j<=el.GetNV(); j++)
+	    if(h > pointh[el.PNum(j)])
+	      pointh[el.PNum(j)] = h;
+	}
+    }
+
+
+  const char * savetask = multithread.task;
+  multithread.task = "Smooth Mesh Jacobian";
+  
+  for (i = 1; i <= points.Size(); i++)
+    if ( usepoint.Test(i) )
+      {
+	//(*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 = pointh[i];//GetH(points.Get(i));
+	par.typx = lh;
+
+	pf.SetPointIndex (i);
+
+	int brother = -1;
+	if(usesum)
+	  {
+	    for(j=0; brother == -1 && j<used_idmaps->Size(); j++)
+	      {
+		if(i < (*used_idmaps)[j]->Size() + PointIndex::BASE)
+		  {
+		    brother = (*(*used_idmaps)[j])[i];
+		    if(brother == i || brother == 0)
+		      brother = -1;
+		  }
+	      }
+	    if(brother >= i)
+	      {
+		pf2ptr->SetPointIndex(brother);
+		pf2ptr->SetNV(*nv[brother-1]);
+	      }
+	  }
+
+	if(usesum && brother < i)
+	  continue;
+
+	//pf.UnSetNV(); x = 0;
+	//(*testout) << "before " << pf.Func(x);
+
+	pf.SetNV(*nv[i-1]);
+
+	x = 0;
+	int pok = (brother == -1) ? (pf.Func (x) < 1e10) : (pf_sum.Func (x) < 1e10);
+
+	if (pok)
+	  {
+	    
+	    if(brother == -1)
+	      BFGS (x, pf, par);
+	    else
+	      BFGS (x, pf_sum, par);
+
+
+	    for(j=0; j<3; j++)
+	      points.Elem(i)(j) += x(j);// - scal*nv[i-1].X(j);
+
+	    if(brother != -1)
+	      for(j=0; j<3; j++)
+		points.Elem(brother)(j) += x(j);// - scal*nv[brother-1].X(j);
+
+
+	  }
+	else
+	  {
+	    cout << "el not ok" << endl;
+	    (*testout) << "el not ok" << endl
+		       << "   func " << ((brother == -1) ? pf.Func(x) : pf_sum.Func (x)) << endl;
+	    if(brother != -1)
+	      (*testout) << "   func1 " << pf.Func(x) << endl
+			 << "   func2 " << pf2ptr->Func(x) << endl;
+	  }
+      }
+  
+  PrintDot ('\n');
+
+  delete pf2ptr;
+  for(i=0; i<locidmaps.Size(); i++)
+    delete locidmaps[i];
+
+  multithread.task = savetask;
+}
+
+
+
+
+}
diff --git a/contrib/Netgen/libsrc/meshing/specials.cpp b/contrib/Netgen/libsrc/meshing/specials.cpp
new file mode 100644
index 0000000000..0a218e10a6
--- /dev/null
+++ b/contrib/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(0.3);
+}
+
+
+
+
+void HelmholtzMesh (Mesh & mesh)
+{
+  int i;
+  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++)
+    {
+      Point<3> & p = mesh.Point(i);
+      double rold = sqrt (sqr(p(0)) + sqr(p(1)) + sqr(p(2)));
+      if (rold < ri) continue;
+
+      double rnew = 1 / (a * rold - b);
+      double fac = rnew / rold;
+      p(0) *= fac;
+      p(1) *= fac;
+      p(2) *= fac;
+    }
+}
+}
diff --git a/contrib/Netgen/libsrc/meshing/specials.hpp b/contrib/Netgen/libsrc/meshing/specials.hpp
new file mode 100644
index 0000000000..700ba4596b
--- /dev/null
+++ b/contrib/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/contrib/Netgen/libsrc/meshing/tetrarls.cpp b/contrib/Netgen/libsrc/meshing/tetrarls.cpp
new file mode 100644
index 0000000000..cb28648b6a
--- /dev/null
+++ b/contrib/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/contrib/Netgen/libsrc/meshing/topology.cpp b/contrib/Netgen/libsrc/meshing/topology.cpp
new file mode 100644
index 0000000000..e620854cbf
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/topology.cpp
@@ -0,0 +1,1726 @@
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+namespace netgen
+{
+  template <class T>
+  void QuickSortRec (FlatArray<T> & data,
+		     int left, int right)
+  {
+    int i = left;
+    int j = right;
+    T midval = data[(left+right)/2];
+  
+    do
+      {
+	while (data[i] < midval) i++;
+	while (midval < data[j]) j--;
+      
+	if (i <= j)
+	  {
+	    Swap (data[i], data[j]);
+	    i++; j--;
+	  }
+      }
+    while (i <= j);
+    if (left < j) QuickSortRec (data, left, j);
+    if (i < right) QuickSortRec (data, i, right);
+  }
+
+  template <class T>
+  void QuickSort (FlatArray<T> & data)
+  {
+    if (data.Size() > 1)
+      QuickSortRec (data, 0, data.Size()-1);
+  }
+
+
+
+
+
+
+  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");
+  }
+
+  MeshTopology :: ~MeshTopology ()
+  {
+    delete vert2element;
+    delete vert2surfelement;
+    delete vert2segment;
+  }
+
+  void MeshTopology :: Update()
+  {
+    static int timer = NgProfiler::CreateTimer ("topology");
+    NgProfiler::RegionTimer reg (timer);
+
+#ifdef PARALLEL
+    ParallelMeshTopology & paralleltop = mesh.GetParallelTopology();
+#endif
+
+    bool isparallel = 0;
+
+  
+    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();
+
+    if (id == 0)
+      PrintMessage (3, "Update mesh topology");
+
+    (*testout) << " UPDATE MESH TOPOLOGY " << endl; 
+    (*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,PointIndex::BASE> cnt(nv);
+    Array<int> vnums;
+
+    /*
+      generate:
+      vertex to element 
+      vertex to surface element
+      vertex to segment 
+    */
+
+
+    cnt = 0;
+    for (ElementIndex ei = 0; ei < ne; ei++)
+      {
+	const Element & el = mesh[ei];
+	for (int j = 0; j < el.GetNV(); j++)
+	  cnt[el[j]]++;
+      }
+
+    vert2element = new TABLE<int,PointIndex::BASE> (cnt);
+    for (ElementIndex ei = 0; ei < ne; ei++)
+      {
+	const Element & el = mesh[ei];
+	for (int j = 0; j < el.GetNV(); j++)
+	  vert2element->AddSave (el[j], ei+1);
+      }
+
+    cnt = 0;
+    for (SurfaceElementIndex sei = 0; sei < nse; sei++)
+      {
+	const Element2d & el = mesh[sei];
+	for (int j = 0; j < el.GetNV(); j++)
+	  cnt[el[j]]++;
+      }
+
+    vert2surfelement = new TABLE<int,PointIndex::BASE> (cnt);
+    for (SurfaceElementIndex sei = 0; sei < nse; sei++)
+      {
+	const Element2d & el = mesh[sei];
+	for (int j = 0; j < el.GetNV(); j++)
+	  vert2surfelement->AddSave (el[j], sei+1);
+      }
+
+    cnt = 0;
+    for (int i = 1; i <= nseg; i++)
+      {
+	const Segment & seg = mesh.LineSegment(i);
+	cnt[seg[0]]++;
+	cnt[seg[1]]++;
+      }
+ 
+    vert2segment = new TABLE<int,PointIndex::BASE> (cnt);
+    for (int i = 1; i <= nseg; i++)
+      {
+	const Segment & seg = mesh.LineSegment(i);
+	vert2segment->AddSave (seg[0], i);
+	vert2segment->AddSave (seg[1], i);
+      }
+
+
+    if (buildedges)
+      {
+	static int timer1 = NgProfiler::CreateTimer ("topology::buildedges");
+	NgProfiler::RegionTimer reg1 (timer1);
+
+	if (id == 0)
+	  PrintMessage (5, "Update edges ");
+      
+	edges.SetSize(ne);
+	surfedges.SetSize(nse); 
+	segedges.SetSize(nseg);
+
+	for (int i = 0; i < ne; i++)
+	  for (int j = 0; j < 12; j++)
+	    edges[i][j] = 0;
+	for (int i = 0; i < nse; i++)
+	  for (int j = 0; j < 4; j++)
+	    surfedges[i][j] = 0;
+
+	// keep existing edges
+	cnt = 0;
+	for (int i = 0; i < edge2vert.Size(); i++)
+	  cnt[edge2vert[i][0]]++;
+	TABLE<int,PointIndex::BASE> vert2edge (cnt);
+	for (int i = 0; i < edge2vert.Size(); i++)
+	  vert2edge.AddSave (edge2vert[i][0], i+1);
+
+	// ensure all coarse grid and intermediate level edges
+	cnt = 0;
+	for (int i = mesh.mlbetweennodes.Begin(); i < mesh.mlbetweennodes.End(); i++)
+	  {
+	    /*  JS, Oct 2009
+		int pa[2];
+		pa[0] = mesh.mlbetweennodes[i].I1();
+		pa[1] = mesh.mlbetweennodes[i].I2();
+		if (pa[0] > pa[1]) Swap (pa[0], pa[1]);
+		if (pa[0] > 0)
+		cnt.Elem(pa[0])++;
+	    */
+	    INDEX_2 parents = mesh.mlbetweennodes[i];
+	    parents.Sort();
+	    if (parents[0] >= PointIndex::BASE) cnt[parents[0]]++;
+	  }
+
+	TABLE<int,PointIndex::BASE> vert2vertcoarse (cnt);
+	for (int i = mesh.mlbetweennodes.Begin(); i < mesh.mlbetweennodes.End(); i++)
+	  {
+	    /*
+	      int pa[2];
+	      pa[0] = mesh.mlbetweennodes[i].I1();
+	      pa[1] = mesh.mlbetweennodes[i].I2();
+	      if (pa[0] > pa[1]) swap (pa[0], pa[1]);
+	      if (pa[0] > 0)
+	      vert2vertcoarse.AddSave1 (pa[0], pa[1]);
+	    */
+	    INDEX_2 parents = mesh.mlbetweennodes[i];
+	    parents.Sort();
+	    if (parents[0] > PointIndex::BASE) vert2vertcoarse.AddSave (parents[0], parents[1]);
+	  }
+
+
+	Array<int,PointIndex::BASE> edgenr(nv);
+	Array<int,PointIndex::BASE> edgeflag(nv);
+	Array<int> vertex2;
+
+	edgeflag = 0;
+
+	ned = edge2vert.Size();
+	Array<INDEX_3> missing;
+
+	for (int i = PointIndex::BASE; i < nv+PointIndex::BASE; i++)
+	  {
+	    vertex2.SetSize (0);
+
+	    for (int j = 0; j < vert2edge[i].Size(); j++)
+	      {
+		int ednr = vert2edge[i][j];
+		int i2 = edge2vert.Get(ednr)[1];
+		edgeflag[i2] = i;
+		edgenr[i2] = ednr;
+	      }
+
+	    for (int j = 0; j < vert2vertcoarse[i].Size(); j++)      // fix by Markus
+	      {
+		int v2 = vert2vertcoarse[i][j];
+		if (edgeflag[v2] < i)
+		  {
+		    *testout << "do we really need that ??????????????" << endl;
+		    // ned++;
+		    // edgenr[v2] = ned;
+		    edgeflag[v2] = i;
+		    vertex2.Append (v2);
+		    // missing.Append (INDEX_3(i,v2,ned));
+		  }
+	      }
+
+	    for (int j = 0; j < (*vert2element)[i].Size(); j++)
+	      {
+		int elnr = (*vert2element)[i][j];
+		const Element & el = mesh.VolumeElement (elnr);
+
+		int neledges = GetNEdges (el.GetType());
+		const ELEMENT_EDGE * eledges = GetEdges0 (el.GetType());
+	  
+		for (int k = 0; k < neledges; k++)
+		  {
+		    INDEX_2 edge(el[eledges[k][0]], el[eledges[k][1]]);
+		    edge.Sort();
+		    if (edge.I1() != i) continue;
+	     
+		    if (edgeflag[edge.I2()] < i)
+		      {
+			vertex2.Append (edge.I2());
+			edgeflag[edge.I2()] = i;
+		      }
+		  }
+	      }
+
+	    for (int j = 0; j < (*vert2surfelement)[i].Size(); j++)
+	      {
+		int elnr = (*vert2surfelement)[i][j];
+		const Element2d & el = mesh.SurfaceElement (elnr);
+
+		int neledges = GetNEdges (el.GetType());
+		const ELEMENT_EDGE * eledges = GetEdges0 (el.GetType());
+	  
+		for (int k = 0; k < neledges; k++)
+		  {
+		    INDEX_2 edge(el[eledges[k][0]], el[eledges[k][1]]);
+		    edge.Sort();
+		    if (edge.I1() != i) continue;
+	     
+		    if (edgeflag[edge.I2()] < i)
+		      {
+			vertex2.Append (edge.I2());
+			edgeflag[edge.I2()] = i;
+		      }
+		  }
+	      }
+
+	    for (int j = 0; j < (*vert2segment)[i].Size(); j++)
+	      {
+		int elnr = (*vert2segment)[i][j];
+		const Segment & el = mesh.LineSegment (elnr);
+
+		INDEX_2 edge(el[0], el[1]);
+		edge.Sort();
+		if (edge.I1() != i) continue;
+	     
+		if (edgeflag[edge.I2()] < i)
+		  {
+		    vertex2.Append (edge.I2());
+		    edgeflag[edge.I2()] = i;
+		  }   
+	      }
+
+	    
+	    QuickSort (vertex2);
+	    for (int j = 0; j < vertex2.Size(); j++)
+	      edgenr[vertex2[j]] = ++ned;
+
+	    for (int j = 0; j < vert2vertcoarse[i].Size(); j++)      // fix by Markus
+	      {
+		int v2 = vert2vertcoarse[i][j];
+		if (edgeflag[v2] < i)
+		  {
+		    // ned++;
+		    // edgenr[v2] = ned;
+		    // edgeflag[v2] = i;
+		    missing.Append (INDEX_3(i,v2,edgenr[v2]));
+		  }
+	      }
+
+	    for (int j = 0; j < (*vert2element)[i].Size(); j++)
+	      {
+		int elnr = (*vert2element)[i][j];
+		const Element & el = mesh.VolumeElement (elnr);
+
+		int neledges = GetNEdges (el.GetType());
+		const ELEMENT_EDGE * eledges = GetEdges0 (el.GetType());
+	  
+		for (int k = 0; k < neledges; k++)
+		  {
+		    INDEX_2 edge(el[eledges[k][0]], el[eledges[k][1]]);
+	      
+		    int edgedir = (edge.I1() > edge.I2());
+		    if (edgedir) swap (edge.I1(), edge.I2());
+	     
+		    if (edge.I1() != i)
+		      continue;
+
+		    int edgenum = edgenr[edge.I2()];
+		    if (edgedir) edgenum *= -1;
+		    edges.Elem(elnr)[k] = edgenum;
+		  }
+	      }
+
+	    for (int j = 0; j < (*vert2surfelement)[i].Size(); j++)
+	      {
+		int elnr = (*vert2surfelement)[i][j];
+		const Element2d & el = mesh.SurfaceElement (elnr);
+
+		int neledges = GetNEdges (el.GetType());
+		const ELEMENT_EDGE * eledges = GetEdges0 (el.GetType());
+	  
+		for (int k = 0; k < neledges; k++)
+		  {
+		    INDEX_2 edge(el[eledges[k][0]], el[eledges[k][1]]);
+	      
+		    int edgedir = (edge.I1() > edge.I2());
+		    if (edgedir) swap (edge.I1(), edge.I2());
+	     
+		    if (edge.I1() != i) continue;
+
+		    int edgenum = edgenr[edge.I2()];
+		    if (edgedir) edgenum *= -1;
+		    surfedges.Elem(elnr)[k] = edgenum;
+		  }
+	      }
+
+	    for (int j = 0; j < (*vert2segment)[i].Size(); j++)
+	      {
+		int elnr = (*vert2segment)[i][j];
+		const Segment & el = mesh.LineSegment (elnr);
+
+		INDEX_2 edge(el[0], el[1]);
+	      
+		int edgedir = (edge.I1() > edge.I2());
+		if (edgedir) swap (edge.I1(), edge.I2());
+	      
+		if (edge.I1() != i) continue;
+
+		int edgenum = edgenr[edge.I2()];
+		if (edgedir) edgenum *= -1;
+		segedges.Elem(elnr) = edgenum;
+	      }
+	  }
+
+
+
+	edge2vert.SetSize (ned);
+	for (int i = 1; i <= ne; i++)
+	  {
+	    const Element & el = mesh.VolumeElement (i);
+      
+	    int neledges = GetNEdges (el.GetType());
+	    const ELEMENT_EDGE * eledges = GetEdges0 (el.GetType());
+	  
+	    for (int k = 0; k < neledges; k++)
+	      {
+		INDEX_2 edge(el[eledges[k][0]], el[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();
+	      }
+	  }
+
+	/*
+	*testout << "edge 2 vert:" << endl;
+	for (int i = 0; i < edge2vert.Size(); i++)
+	  *testout << edge2vert[i][0] << " " << edge2vert[i][1] << endl;
+	  */
+
+	for (int i = 1; i <= nse; i++)
+	  {
+	    const Element2d & el = mesh.SurfaceElement (i);
+      
+	    int neledges = GetNEdges (el.GetType());
+	    const ELEMENT_EDGE * eledges = GetEdges0 (el.GetType());
+	  
+	    for (int k = 0; k < neledges; k++)
+	      {
+		INDEX_2 edge(el[eledges[k][0]], el[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 (int i = 1; i <= nseg; i++)
+	  {
+	    const Segment & el = mesh.LineSegment (i);
+      
+	    INDEX_2 edge(el[0], el[1]);
+	    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 (int 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 (int i = 1; i <= edge2vert.Size(); i++)
+	  (*testout) << "edge " << i << ", v1,2 = " << edge2vert.Elem(i)[0] << ", " << edge2vert.Elem(i)[1] << endl;
+	  (*testout) << "surfedges:" << endl;
+	  for (int i = 1; i <= surfedges.Size(); i++)
+	  (*testout) << "el " << i << ", edges = " 
+	  << surfedges.Elem(i)[0] << ", "
+	  << surfedges.Elem(i)[1] << ", "
+	  << surfedges.Elem(i)[2] << endl;
+	*/ 
+     
+    
+      }
+
+
+    //  cout << "build edges done" << endl;
+
+
+
+    // generate faces
+    if (buildfaces) //  && mesh.GetDimension() == 3)
+      {
+	static int timer2 = NgProfiler::CreateTimer ("topology::buildfaces");
+	NgProfiler::RegionTimer reg2 (timer2);
+
+	if (id == 0)
+	  PrintMessage (5, "Update faces ");
+
+
+
+
+	faces.SetSize(ne);
+	surffaces.SetSize(nse);
+	
+	int oldnfa = face2vert.Size();
+
+	cnt = 0;
+	for (int i = 0; i < face2vert.Size(); i++)
+	  cnt[face2vert[i][0]]++;
+	TABLE<int,PointIndex::BASE> vert2oldface(cnt);
+	for (int i = 0; i < face2vert.Size(); i++)
+	  vert2oldface.AddSave (face2vert[i][0], i);
+
+
+	for (int elnr = 0; elnr < ne; elnr++)
+	  for (int j = 0; j < 6; j++)
+	    faces[elnr][j] = 0;
+	
+
+	int max_face_on_vertex = 0;
+	for (int i = PointIndex::BASE; i < nv+PointIndex::BASE; i++)
+	  {
+	    int onv = vert2oldface[i].Size() + (*vert2element)[i].Size() + (*vert2surfelement)[i].Size();
+	    max_face_on_vertex = max (onv, max_face_on_vertex);
+	  }
+	
+
+	/*
+	for (int pass = 1; pass <= 2; pass++)
+	  {
+	    nfa = oldnfa;
+	    for (int v = PointIndex::BASE; v < nv+PointIndex::BASE; v++)
+	      {
+		INDEX_3_CLOSED_HASHTABLE<int> vert2face(2*max_face_on_vertex+10); 
+		
+		for (int j = 0; j < vert2oldface[v].Size(); j++)
+		  {
+		    int fnr = vert2oldface[v][j];
+		    INDEX_3 face (face2vert[fnr].I1(),
+				  face2vert[fnr].I2(),
+				  face2vert[fnr].I3());
+		    vert2face.Set (face, fnr+1);
+		  }
+
+
+		// cout << "inherited faces: " << endl << vert2face << endl;
+
+
+		for (int j = 0; j < (*vert2element)[v].Size(); j++)
+		  {
+		    int elnr = (*vert2element)[v][j];
+		    const Element & el = mesh.VolumeElement (elnr);
+	  
+		    int nelfaces = GetNFaces (el.GetType());
+		    const ELEMENT_FACE * elfaces = GetFaces1 (el.GetType());
+	  
+		    for (int j = 0; j < nelfaces; j++)
+		      if (elfaces[j][3] == 0)
+	      
+			{ // triangle
+			  int facenum, 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 (face.I1() != v) continue;
+		      
+			  if (vert2face.Used (face))
+			    facenum = vert2face.Get(face);
+			  else
+			    {
+			      nfa++;
+			      vert2face.Set (face, nfa);
+			      facenum = nfa;
+			  
+			      INDEX_4 hface(face.I1(),face.I2(),face.I3(),0);
+			      if (pass == 2) face2vert.Append (hface);
+			    }
+			  faces.Elem(elnr)[j] = 8*(facenum-1)+facedir+1;
+			}
+		
+		      else
+		    
+			{
+			  // quad
+			  int facenum, 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());
+			    }
+
+		
+			  INDEX_3 face(face4.I1(), face4.I2(), face4.I3());
+
+			  if (face.I1() != v) continue;
+		      
+			  if (vert2face.Used (face))
+			    {
+			      facenum = vert2face.Get(face);
+			    }
+			  else
+			    {
+			      nfa++;
+			      vert2face.Set (face, nfa);
+			      facenum = nfa;
+			  
+			      INDEX_4 hface(face4.I1(),face4.I2(),face4.I3(),face4.I4());
+			      if (pass == 2) face2vert.Append (hface);
+			    }
+		      
+			  faces.Elem(elnr)[j] = 8*(facenum-1)+facedir+1;
+			}
+		  }
+
+		for (int j = 0; j < (*vert2surfelement)[v].Size(); j++)
+		  {
+		    int elnr = (*vert2surfelement)[v][j];
+		    // cout << "surfelnr = " << elnr << endl;
+		    const Element2d & el = mesh.SurfaceElement (elnr);
+		
+		    const ELEMENT_FACE * elfaces = GetFaces1 (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]));
+		    
+			// cout << "face = " << face << endl;
+
+			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 (face.I1() != v) continue;
+		    
+			if (vert2face.Used (face))
+			  facenum = vert2face.Get(face);
+			else
+			  {
+			    nfa++;
+			    vert2face.Set (face, nfa);
+			    facenum = nfa;
+			
+			    INDEX_4 hface(face.I1(),face.I2(),face.I3(),0);
+			    if (pass == 2) face2vert.Append (hface);
+			  }
+
+			// cout << "face = " << face << " selnr = " << elnr << endl;
+			surffaces.Elem(elnr) = 8*(facenum-1)+facedir+1;
+			// face2surfel.Elem(facenum) = elnr;
+		      }
+	  
+		    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 (face.I1() != v) continue;
+		    
+			if (vert2face.Used (face))
+			  facenum = vert2face.Get(face);
+			else
+			  {
+			    nfa++;
+			    vert2face.Set (face, nfa);
+			    facenum = nfa;
+			
+			    INDEX_4 hface(face4.I1(),face4.I2(),face4.I3(),face4.I3());
+			    if (pass == 2) face2vert.Append (hface);
+			  }
+		    
+			surffaces.Elem(elnr) = 8*(facenum-1)+facedir+1;
+		      }
+		  }
+	      }
+
+	    face2vert.SetAllocSize (nfa);
+	    }
+	*/
+
+
+
+
+
+
+
+
+	for (int pass = 1; pass <= 2; pass++)
+	  {
+	    nfa = oldnfa;
+	    for (int v = PointIndex::BASE; v < nv+PointIndex::BASE; v++)
+	      {
+		int first_fa = nfa;
+
+		INDEX_3_CLOSED_HASHTABLE<int> vert2face(2*max_face_on_vertex+10); 
+		
+		for (int j = 0; j < vert2oldface[v].Size(); j++)
+		  {
+		    int fnr = vert2oldface[v][j];
+		    INDEX_3 face (face2vert[fnr].I1(),
+				  face2vert[fnr].I2(),
+				  face2vert[fnr].I3());
+		    vert2face.Set (face, fnr+1);
+		  }
+
+
+		if (pass == 2)
+		  for (int j = nfa; j < face2vert.Size(); j++)
+		    {
+		      if (face2vert[j][0] == v)
+			{
+			  INDEX_3 face (face2vert[j].I1(),
+					face2vert[j].I2(),
+					face2vert[j].I3());
+			  vert2face.Set (face, j+1);
+			  nfa++;
+			}
+		      else
+			break;
+		    }
+		
+
+		// cout << "inherited faces: " << endl << vert2face << endl;
+
+
+		for (int j = 0; j < (*vert2element)[v].Size(); j++)
+		  {
+		    int elnr = (*vert2element)[v][j];
+		    const Element & el = mesh.VolumeElement (elnr);
+	  
+		    int nelfaces = GetNFaces (el.GetType());
+		    const ELEMENT_FACE * elfaces = GetFaces1 (el.GetType());
+	  
+		    for (int j = 0; j < nelfaces; j++)
+		      if (elfaces[j][3] == 0)
+	      
+			{ // triangle
+			  int facenum, 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 (face.I1() != v) continue;
+		      
+			  if (vert2face.Used (face))
+			    facenum = vert2face.Get(face);
+			  else
+			    {
+			      nfa++;
+			      vert2face.Set (face, nfa);
+			      facenum = nfa;
+			  
+			      INDEX_4 hface(face.I1(),face.I2(),face.I3(),0);
+			      face2vert.Append (hface);
+			    }
+			  faces.Elem(elnr)[j] = 8*(facenum-1)+facedir+1;
+			}
+		
+		      else
+		    
+			{
+			  // quad
+			  int facenum, 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());
+			    }
+
+		
+			  INDEX_3 face(face4.I1(), face4.I2(), face4.I3());
+
+			  if (face.I1() != v) continue;
+		      
+			  if (vert2face.Used (face))
+			    {
+			      facenum = vert2face.Get(face);
+			    }
+			  else
+			    {
+			      nfa++;
+			      vert2face.Set (face, nfa);
+			      facenum = nfa;
+			  
+			      INDEX_4 hface(face4.I1(),face4.I2(),face4.I3(),face4.I4());
+			      face2vert.Append (hface);
+			    }
+		      
+			  faces.Elem(elnr)[j] = 8*(facenum-1)+facedir+1;
+			}
+		  }
+
+		for (int j = 0; j < (*vert2surfelement)[v].Size(); j++)
+		  {
+		    int elnr = (*vert2surfelement)[v][j];
+		    // cout << "surfelnr = " << elnr << endl;
+		    const Element2d & el = mesh.SurfaceElement (elnr);
+		
+		    const ELEMENT_FACE * elfaces = GetFaces1 (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]));
+		    
+			// cout << "face = " << face << endl;
+
+			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 (face.I1() != v) continue;
+		    
+			if (vert2face.Used (face))
+			  facenum = vert2face.Get(face);
+			else
+			  {
+			    nfa++;
+			    vert2face.Set (face, nfa);
+			    facenum = nfa;
+			
+			    INDEX_4 hface(face.I1(),face.I2(),face.I3(),0);
+			    face2vert.Append (hface);
+			  }
+
+			surffaces.Elem(elnr) = 8*(facenum-1)+facedir+1;
+		      }
+	  
+		    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 (face.I1() != v) continue;
+		    
+			if (vert2face.Used (face))
+			  facenum = vert2face.Get(face);
+			else
+			  {
+			    nfa++;
+			    vert2face.Set (face, nfa);
+			    facenum = nfa;
+			
+			    INDEX_4 hface(face4.I1(),face4.I2(),face4.I3(),face4.I3());
+			    face2vert.Append (hface);
+			  }
+		    
+			surffaces.Elem(elnr) = 8*(facenum-1)+facedir+1;
+		      }
+		  }
+
+		// sort faces
+		// *testout << "faces = " << face2vert << endl;
+		if (pass == 1)
+		  {
+		    // *testout << "sort from " << first_fa << " to " << nfa << endl;
+		    for (int i = first_fa; i < nfa; i++)
+		      for (int j = first_fa+1; j < nfa; j++)
+			if (face2vert[j] < face2vert[j-1])
+			  Swap (face2vert[j-1], face2vert[j]);
+		  }
+		// *testout << "faces, sorted = " << face2vert << endl;
+	      }
+
+
+	    face2vert.SetAllocSize (nfa);
+
+	  }
+
+
+	// *testout << "face2vert = " << endl << face2vert << endl;
+
+
+
+
+
+
+
+	
+	face2surfel.SetSize (nfa);
+	face2surfel = 0;
+	for (int i = 1; i <= nse; i++)
+	  face2surfel.Elem(GetSurfaceElementFace(i)) = i;
+
+	/*
+	  cout << "build table complete" << endl;
+
+	  cout << "faces = " << endl;
+
+	  cout << "face2vert = " << endl << face2vert << endl;
+	  cout << "surffaces = " << endl << surffaces << endl;
+	  cout << "face2surfel = " << endl << face2surfel << endl;
+	*/
+
+	
+	surf2volelement.SetSize (nse);
+	for (int i = 1; i <= nse; i++)
+	  {
+	    surf2volelement.Elem(i)[0] = 0;
+	    surf2volelement.Elem(i)[1] = 0;
+	  }
+	for (int i = 1; i <= ne; i++)
+	  for (int j = 0; j < 6; j++)
+	    {
+	      int fnum = (faces.Get(i)[j]+7) / 8;
+	      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());
+
+	// face table complete
+
+
+#ifdef PARALLEL
+	(*testout) << " RESET Paralleltop" << endl;
+	paralleltop.Reset ();
+#endif
+
+	Array<short int> face_els(nfa), face_surfels(nfa);
+	face_els = 0;
+	face_surfels = 0;
+	Array<int> hfaces;
+	for (int i = 1; i <= ne; i++)
+	  {
+	    GetElementFaces (i, hfaces);
+	    for (int j = 0; j < hfaces.Size(); j++)
+	      face_els[hfaces[j]-1]++;
+	  }
+	for (int i = 1; i <= nse; i++)
+	  face_surfels[GetSurfaceElementFace (i)-1]++;
+
+
+	if (ne)
+	  {
+	    int cnt_err = 0;
+	    for (int i = 0; i < nfa; i++)
+	      {
+		/*
+		  (*testout) << "face " << i << " has " << int(face_els[i]) << " els, " 
+		  << int(face_surfels[i]) << " surfels, tot = "
+		  << face_els[i] + face_surfels[i] << endl; 
+		*/
+		if (face_els[i] + face_surfels[i] == 1)
+		  {
+		    cnt_err++;
+#ifdef PARALLEL
+		    if ( ntasks > 1 )
+		      {
+			if ( !paralleltop.DoCoarseUpdate() ) continue;
+		      }
+		    else
+#endif
+		      {
+			(*testout) << "illegal face : " << i << endl;
+			(*testout) << "points = " << face2vert[i] << endl;
+			(*testout) << "pos = ";
+			for (int j = 0; j < 4; j++)
+			  if (face2vert[i].I(j+1) >= 1)
+			    (*testout) << mesh[(PointIndex)face2vert[i].I(j+1)] << " ";
+			(*testout) << endl;
+
+			FlatArray<int> vertels = GetVertexElements (face2vert[i].I(1));
+			for (int k = 0; k < vertels.Size(); k++)
+			  {
+			    int elfaces[10], orient[10];
+			    int nf = GetElementFaces (vertels[k], elfaces, orient);
+			    for (int l = 0; l < nf; l++)
+			      if (elfaces[l] == i)
+				{
+				  (*testout) << "is face of element " << vertels[k] << endl;
+			    
+				  if (mesh.coarsemesh && mesh.hpelements->Size() == mesh.GetNE() )
+				    {
+				      const HPRefElement & hpref_el =
+					(*mesh.hpelements) [ mesh.VolumeElement (vertels[k]).hp_elnr];
+				      (*testout) << "coarse eleme = " << hpref_el.coarse_elnr << endl;
+				    }
+
+				}
+			  }
+		      }
+		  }
+	      }
+
+	    if (cnt_err && ntasks == 1)
+	      cout << cnt_err << " elements are not matching !!!" << endl;
+
+	    if (cnt_err && ntasks > 1)
+	      isparallel = 1;
+	  }
+      }
+    
+
+#ifdef PARALLEL
+    if (mesh.GetDimension() == 3)
+      if (isparallel != (id != 0))
+	{
+	  cerr << " ****************************** " << endl;
+	  cerr << " **** wrong isparallel   ****** " << endl;
+	  cerr << " ****************************** " << endl;
+	}
+    
+    if (id != 0)    // if (isparallel)
+      {
+	paralleltop.Update();
+	if ( paralleltop.DoCoarseUpdate() )
+	  paralleltop.UpdateCoarseGrid();
+      }
+#endif
+ 
+ 
+  
+    /* 
+       for (i = 1; i <= ne; i++)
+       {
+       (*testout) << "Element " << i << endl;
+       (*testout) << "PNums " << endl; 
+       for( int l=1;l<=8;l++) *testout << mesh.VolumeElement(i).PNum(l) << "\t"; 
+       *testout << endl; 
+       (*testout) << "edges: " << endl;
+       for (j = 0; j < 9; j++)
+       (*testout) << edges.Elem(i)[j] << " ";
+       (*testout) << "faces: " << endl;
+       for (j = 0; j < 6; j++)m
+       (*testout) << faces.Elem(i)[j] << " ";
+       }
+
+       for (i = 1; i <= nse; i++)
+       {
+       (*testout) << "SElement " << i << endl;
+       (*testout) << "PNums " << endl; 
+       for( int l=1;l<=4;l++) *testout << mesh.SurfaceElement(i).PNum(l) << "\t"; 
+       *testout << endl; 
+       }
+    */
+    timestamp = NextTimeStamp();
+  }
+
+  
+
+
+
+  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:
+      case QUAD8:
+	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;
+  }
+
+
+
+
+
+
+
+
+  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, bool withorientation) const
+  {
+    int nfa = GetNFaces (mesh.VolumeElement(elnr).GetType());
+    elfaces.SetSize (nfa);
+
+    if (!withorientation)
+
+      for (int i = 1; i <= nfa; i++)
+	{
+	  elfaces.Elem(i) = (faces.Get(elnr)[i-1]-1) / 8 + 1;
+	}
+    
+    else
+      
+      for (int i = 1; i <= nfa; i++)
+	{
+	  elfaces.Elem(i) = (faces.Get(elnr)[i-1]-1) / 8 + 1;
+	  int orient = (faces.Get(elnr)[i-1]-1) % 8;
+	  if(orient == 1 || orient == 2 || orient == 4 || orient == 7)
+	    elfaces.Elem(i) *= -1;
+	}
+  }
+
+  void MeshTopology :: GetElementEdgeOrientations (int elnr, Array<int> & eorient) const
+  {
+    int ned = GetNEdges (mesh.VolumeElement(elnr).GetType());
+    eorient.SetSize (ned);
+    for (int 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 nfa = GetNFaces (mesh.VolumeElement(elnr).GetType());
+    forient.SetSize (nfa);
+    for (int 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 ned = GetNEdges (mesh.VolumeElement(elnr).GetType());
+
+    if (mesh.GetDimension()==3 || 1)
+      {
+	if (orient)
+	  {
+	    for (int 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 (int i = 0; i < 12; i++)
+	      {
+		if (!edges.Get(elnr)[i]) return i;
+		eledges[i] = abs (edges.Get(elnr)[i]);
+	      }
+	  }
+	return 12;
+      }
+    else
+      {
+	throw NgException("rethink implementation");
+	/*
+	  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 nfa = GetNFaces (mesh.VolumeElement(elnr).GetType());
+    if (orient)
+      {
+	for (int 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 (int 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 ned = GetNEdges (mesh.SurfaceElement(elnr).GetType());
+    eorient.SetSize (ned);
+    for (int 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> & fedges, bool withorientation) const
+  {
+    ArrayMem<int,4> pi(4);
+    ArrayMem<int,12> eledges;
+  
+    fedges.SetSize (0);
+    GetFaceVertices(fnr, pi);
+
+    // Sort Edges according to global vertex numbers 
+    // e1 = fmax, f2 
+    // e2 = fmax, f1 
+    // e3 = op e1(f2,f3) 
+    // e4 = op e2(f1,f3) 
+
+    /*  ArrayMem<int,4> fp; 
+	fp[0] = pi[0]; 
+	for(int k=1;k<pi.Size();k++) 
+	if(fp[k]>fp[0]) swap(fp[k],fp[0]); 
+  
+	fp[1] = fp[0]+ */ 
+  
+
+    //  GetVertexElements (pi[0], els);
+    FlatArray<int> els= GetVertexElements (pi[0]);
+
+    // find one element having all vertices of the face
+    for (int i = 0; i < els.Size(); i++)
+      {
+	const Element & el = mesh.VolumeElement(els[i]);
+	int nref_faces = GetNFaces (el.GetType());
+	const ELEMENT_FACE * ref_faces = GetFaces1 (el.GetType());
+	int nfa_ref_edges = GetNEdges (GetFaceType(fnr));
+      
+	int cntv = 0,fa=-1; 
+	for(int m=0;m<nref_faces;m++)
+	  { 
+	    cntv=0;
+	    for(int j=0;j<nfa_ref_edges && ref_faces[m][j]>0;j++)
+	      for(int k=0;k<pi.Size();k++)
+		{
+		  if(el[ref_faces[m][j]-1] == pi[k])
+		    cntv++;
+		}
+	    if (cntv == pi.Size())
+	      {
+		fa=m;
+		break;
+	      }
+	  }
+     
+	if(fa>=0)
+	  {
+	    const ELEMENT_EDGE * fa_ref_edges = GetEdges1 (GetFaceType(fnr)); 
+	    fedges.SetSize(nfa_ref_edges);
+	    GetElementEdges (els[i], eledges);
+	  
+	    for (int j = 0; j < eledges.Size(); j++)
+	      {
+		int vi1, vi2;
+		GetEdgeVertices (eledges[j], vi1, vi2);
+	    
+		bool has1 = 0;
+		bool has2 = 0;
+		for (int k = 0; k < pi.Size(); k++)
+		  {
+		    if (vi1 == pi[k]) has1 = 1;
+		    if (vi2 == pi[k]) has2 = 1;
+		  
+		  }
+	      
+		if (has1 && has2) // eledges[j] is on face 
+		  {
+		    // fedges.Append (eledges[j]);
+		    for(int k=0;k<nfa_ref_edges;k++)
+		      {
+			int w1 = el[ref_faces[fa][fa_ref_edges[k][0]-1]-1]; 
+			int w2 = el[ref_faces[fa][fa_ref_edges[k][1]-1]-1]; 
+
+			if(withorientation)
+			  {
+			    if(w1==vi1 && w2==vi2)
+			      fedges[k] = eledges[j];
+			    if(w1==vi2 && w2==vi1)
+			      fedges[k] = -eledges[j];
+			  }
+			else
+			  if((w1==vi1 && w2==vi2) || (w1==vi2 && w2==vi1))
+			    fedges[k] = eledges[j];
+		      }
+		  }
+	      }
+	  
+	    // *testout << " Face " << fnr << endl; 
+	    // *testout << " GetFaceEdges " << fedges << endl;
+	  
+	    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];
+    return FlatArray<int> (0,0);
+  }
+
+  FlatArray<int> MeshTopology :: GetVertexSurfaceElements (int vnr) const
+  {
+    if (vert2surfelement)
+      return (*vert2surfelement)[vnr];
+    return FlatArray<int> (0,0);
+  }
+
+
+  void MeshTopology :: GetVertexSurfaceElements( int vnr, 
+						 Array<int>& elements ) const
+  {
+    if (vert2surfelement)
+      {
+	int i;
+	int ne = vert2surfelement->EntrySize(vnr);
+	elements.SetSize(ne);
+	for (i = 1; i <= ne; i++)
+	  elements.Elem(i) = vert2surfelement->Get(vnr, i);
+      }
+  }
+
+
+  int MeshTopology :: GetVerticesEdge ( int v1, int v2 ) const
+  {
+    Array<int> elements_v1, elementedges;
+    GetVertexElements ( v1, elements_v1);
+    int edv1, edv2;
+
+    for ( int i = 0; i < elements_v1.Size(); i++ )
+      {
+	GetElementEdges( elements_v1[i], elementedges );
+	for ( int ed = 0; ed < elementedges.Size(); ed ++)
+	  {
+	    GetEdgeVertices( elementedges[ed], edv1, edv2 );
+	    if ( ( edv1 == v1 && edv2 == v2 ) || ( edv1 == v2 && edv2 == v1 ) )
+	      return elementedges[ed];
+	  }
+      }
+
+    return -1;
+  }
+
+
+
+  void MeshTopology :: 
+  GetSegmentVolumeElements ( int segnr, Array<int> & volels ) const
+  {
+    int v1, v2;
+    GetEdgeVertices ( GetSegmentEdge (segnr), v1, v2 );
+    Array<int> volels1, volels2;
+    GetVertexElements ( v1, volels1 );
+    GetVertexElements ( v2, volels2 );
+    volels.SetSize(0);
+
+    for ( int eli1=1; eli1 <= volels1.Size(); eli1++)
+      if ( volels2.Contains( volels1.Elem(eli1) ) )
+	volels.Append ( volels1.Elem(eli1) );
+  }
+
+  void MeshTopology :: 
+  GetSegmentSurfaceElements (int segnr, Array<int> & els) const
+  {
+    int v1, v2;
+    GetEdgeVertices ( GetSegmentEdge (segnr), v1, v2 );
+    Array<int> els1, els2;
+    GetVertexSurfaceElements ( v1, els1 );
+    GetVertexSurfaceElements ( v2, els2 );
+    els.SetSize(0);
+
+    for ( int eli1=1; eli1 <= els1.Size(); eli1++)
+      if ( els2.Contains( els1.Elem(eli1) ) )
+	els.Append ( els1.Elem(eli1) );
+  }
+
+
+
+
+}
diff --git a/contrib/Netgen/libsrc/meshing/topology.hpp b/contrib/Netgen/libsrc/meshing/topology.hpp
new file mode 100644
index 0000000000..a453fa84dd
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/topology.hpp
@@ -0,0 +1,683 @@
+#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;
+  bool buildedges;
+  bool 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,PointIndex::BASE> *vert2element;
+  TABLE<int,PointIndex::BASE> *vert2surfelement;
+  TABLE<int,PointIndex::BASE> *vert2segment;
+  int timestamp;
+public:
+  int GetNSurfedges() const {return surfedges.Size();}
+
+  MeshTopology (const Mesh & amesh);
+  ~MeshTopology ();
+
+  void SetBuildEdges (bool be)
+  { buildedges = be; }
+  void SetBuildFaces (bool bf)
+  { buildfaces = bf; }
+
+  bool HasEdges () const
+  { return buildedges; }
+  bool HasFaces () const
+  { return buildfaces; }
+
+  void Update();
+
+
+  int GetNEdges () const { return edge2vert.Size(); }
+  int GetNFaces () const { return face2vert.Size(); }
+
+  static inline int GetNVertices (ELEMENT_TYPE et);
+  static inline int GetNPoints (ELEMENT_TYPE et);
+  static inline int GetNEdges (ELEMENT_TYPE et);
+  static inline int GetNFaces (ELEMENT_TYPE et);
+
+  static const Point3d * GetVertices (ELEMENT_TYPE et);
+  inline static const ELEMENT_EDGE * GetEdges1 (ELEMENT_TYPE et);
+  inline static const ELEMENT_EDGE * GetEdges0 (ELEMENT_TYPE et);
+  inline static const ELEMENT_FACE * GetFaces1 (ELEMENT_TYPE et);
+  inline static const ELEMENT_FACE * GetFaces0 (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, bool withorientation = false) 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 enr, int & v1, int & v2) const;
+  const int * GetEdgeVerticesPtr (int enr) const { return &edge2vert[enr][0]; }
+  const int * GetFaceVerticesPtr (int fnr) const { return &face2vert[fnr][0]; }
+  void GetFaceEdges (int fnr, Array<int> & edges, bool withorientation = false) 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;
+
+  const int * GetElementEdgesPtr (int elnr) const { return &edges[elnr][0]; }
+  const int * GetSurfaceElementEdgesPtr (int selnr) const { return &surfedges[selnr][0]; }
+  const int * GetSegmentElementEdgesPtr (int selnr) const { return &segedges[selnr]; }
+
+  const int * GetElementFacesPtr (int elnr) const { return &faces[elnr][0]; }
+  const int * GetSurfaceElementFacesPtr (int selnr) const { return &surffaces[selnr]; }
+
+
+  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;
+
+  void GetVertexSurfaceElements( int vnr, Array<int>& elements ) const;
+  FlatArray<int> GetVertexSurfaceElements (int vnr) const;
+
+
+  
+  int GetVerticesEdge ( int v1, int v2) const;
+  void GetSegmentVolumeElements ( int segnr, Array<int> & els ) const;
+  void GetSegmentSurfaceElements ( int segnr, Array<int> & els ) const;
+};
+
+
+
+
+
+
+
+
+
+
+int MeshTopology :: GetNVertices (ELEMENT_TYPE et)
+{
+  switch (et)
+    {
+    case SEGMENT:
+    case SEGMENT3:
+      return 2;
+
+    case TRIG:
+    case TRIG6:
+      return 3;
+
+    case QUAD:
+    case QUAD6:
+    case QUAD8:
+      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 :: GetNPoints (ELEMENT_TYPE et)
+{
+  switch (et)
+    {
+    case SEGMENT:
+      return 2;
+    case SEGMENT3:
+      return 3;
+
+    case TRIG:
+      return 3;
+    case TRIG6:
+      return 6;
+
+    case QUAD:
+    case QUAD6:
+    case QUAD8:
+      return 4;
+
+    case TET:
+      return 4;
+    case TET10:
+      return 10;
+
+    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:
+    case QUAD8:
+      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:
+    case QUAD8:
+      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 ELEMENT_EDGE * MeshTopology :: GetEdges1 (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:
+    case QUAD8:
+      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_EDGE * MeshTopology :: GetEdges0 (ELEMENT_TYPE et)
+{
+  static int segm_edges[1][2] =
+    { { 0, 1 }};
+
+  static int trig_edges[3][2] =
+    { { 2, 0 },
+      { 1, 2 },        
+      { 0, 1 }};
+
+  static int quad_edges[4][2] =
+    { { 0, 1 },
+      { 2, 3 },
+      { 3, 0 },
+      { 1, 2 }};
+
+
+  static int tet_edges[6][2] =
+    { { 3, 0 },
+      { 3, 1 },
+      { 3, 2 }, 
+      { 0, 1 },
+      { 0, 2 },
+      { 1, 2 }};
+
+  static int prism_edges[9][2] =
+    { { 2, 0 },
+      { 0, 1 },
+      { 2, 1 },
+      { 5, 3 },
+      { 3, 4 },
+      { 5, 4 },
+      { 2, 5 },
+      { 0, 3 },
+      { 1, 4 }};
+
+  static int pyramid_edges[8][2] =
+    { { 0, 1 },
+      { 1, 2 },
+      { 0, 3 },
+      { 3, 2 },
+      { 0, 4 },
+      { 1, 4 },
+      { 2, 4 },
+      { 3, 4 }};
+
+  static int hex_edges[12][2] =
+    {
+      { 0, 1 },
+      { 2, 3 },
+      { 3, 0 },
+      { 1, 2 },
+      { 4, 5 },
+      { 6, 7 },
+      { 7, 4 },
+      { 5, 6 },
+      { 0, 4 },
+      { 1, 5 },
+      { 2, 6 },
+      { 3, 7 },
+    };
+
+  switch (et)
+    {
+    case SEGMENT:
+    case SEGMENT3:
+      return segm_edges;
+
+    case TRIG:
+    case TRIG6:
+      return trig_edges;
+
+    case QUAD:
+    case QUAD6:
+    case QUAD8:
+      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 :: GetFaces1 (ELEMENT_TYPE et)
+{
+  static const int trig_faces[1][4] = 
+    { { 1, 2, 3, 0 } };
+  static const int quad_faces[1][4] = 
+    { { 1, 2, 3, 4 } };
+
+  static const int tet_faces[4][4] =
+    { { 4, 2, 3, 0 },
+      { 4, 3, 1, 0 },
+      { 4, 1, 2, 0 },
+      { 1, 3, 2, 0 } };
+  
+  static const int prism_faces[5][4] =
+    {
+      { 1, 3, 2, 0 },
+      { 4, 5, 6, 0 },
+      { 3, 1, 4, 6 },
+      { 1, 2, 5, 4 },
+      { 2, 3, 6, 5 } 
+    };
+
+  static const int pyramid_faces[5][4] =
+    {
+      { 1, 2, 5, 0 },
+      { 2, 3, 5, 0 },
+      { 3, 4, 5, 0 },
+      { 4, 1, 5, 0 },
+      { 1, 4, 3, 2 } 
+    };
+
+  static const int hex_faces[6][4] =
+    {
+      { 1, 4, 3, 2 },
+      { 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:
+    case QUAD8:
+      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;
+}
+
+
+
+
+
+const ELEMENT_FACE * MeshTopology :: GetFaces0 (ELEMENT_TYPE et)
+{
+  static const int trig_faces[1][4] = 
+    { { 0, 1, 2, -1 } };
+  static const int quad_faces[1][4] = 
+    { { 0, 1, 2, 3 } };
+
+  static const int tet_faces[4][4] =
+    { { 3, 1, 2, -1 },
+      { 3, 2, 0, -1 },
+      { 3, 0, 1, -1 },
+      { 0, 2, 1, -1 } };
+  
+  static const int prism_faces[5][4] =
+    {
+      { 0, 2, 1, -1 },
+      { 3, 4, 5, -1 },
+      { 2, 0, 3, 5 },
+      { 0, 1, 4, 3 },
+      { 1, 2, 5, 4 } 
+    };
+
+  static const int pyramid_faces[5][4] =
+    {
+      { 0, 1, 4, -1 },
+      { 1, 2, 4, -1 },
+      { 2, 3, 4, -1 },
+      { 3, 0, 4, -1 },
+      { 0, 3, 2, 1 } 
+    };
+
+  static const int hex_faces[6][4] =
+    {
+      { 0, 3, 2, 1 },
+      { 4, 5, 6, 7 },
+      { 0, 1, 5, 4 },
+      { 1, 2, 6, 5 },
+      { 2, 3, 7, 6 },
+      { 3, 0, 4, 7 }
+    };
+
+
+  
+  switch (et)
+    {
+    case TRIG:
+    case TRIG6:
+      return trig_faces;
+
+    case QUAD:
+    case QUAD6:
+    case QUAD8:
+      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;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#endif
diff --git a/contrib/Netgen/libsrc/meshing/triarls.cpp b/contrib/Netgen/libsrc/meshing/triarls.cpp
new file mode 100644
index 0000000000..d82806e9bc
--- /dev/null
+++ b/contrib/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 X2, 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/contrib/Netgen/libsrc/meshing/validate.cpp b/contrib/Netgen/libsrc/meshing/validate.cpp
new file mode 100644
index 0000000000..44b983cca0
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/validate.cpp
@@ -0,0 +1,591 @@
+
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+
+namespace netgen
+{
+  void GetPureBadness(Mesh & mesh, Array<double> & pure_badness,
+		      const BitArray & isnewpoint)
+  {
+    //const int ne = mesh.GetNE();
+    const int np = mesh.GetNP();
+
+    pure_badness.SetSize(np+PointIndex::BASE+1);
+    pure_badness = -1;
+
+    Array< Point<3>* > backup(np);
+
+    for(int i=0; i<np; i++)
+      {
+	backup[i] = new Point<3>(mesh.Point(i+1));
+
+	if(isnewpoint.Test(i+PointIndex::BASE) &&
+	   mesh.mlbetweennodes[i+PointIndex::BASE][0] > 0)
+	  {
+	    mesh.Point(i+1) = Center(mesh.Point(mesh.mlbetweennodes[i+PointIndex::BASE][0]),
+				     mesh.Point(mesh.mlbetweennodes[i+PointIndex::BASE][1]));
+	  }
+      }
+    for (ElementIndex i = 0; i < mesh.GetNE(); i++)
+      {
+	double bad = mesh[i].CalcJacobianBadness (mesh.Points());
+	for(int j=0; j<mesh[i].GetNP(); j++)
+	  if(bad > pure_badness[mesh[i][j]])
+	    pure_badness[mesh[i][j]] = bad;
+
+	// save maximum
+	if(bad > pure_badness.Last())
+	  pure_badness.Last() = bad; 
+      }
+    
+    for(int i=0; i<np; i++)
+      {
+	mesh.Point(i+1) = *backup[i];
+	delete backup[i];
+      }
+  }
+
+
+  double Validate(const Mesh & mesh, Array<ElementIndex> & bad_elements,
+		  const Array<double> & pure_badness,
+		  double max_worsening, const bool uselocalworsening,
+		  Array<double> * quality_loss)
+  {
+    PrintMessage(3,"!!!! Validating !!!!");
+    //if(max_worsening > 0)
+    //  (*testout) << "badness " << counter++ << endl;
+
+    bad_elements.SetSize(0);
+
+    double loc_pure_badness = -1;
+
+    if(!uselocalworsening)
+      loc_pure_badness = pure_badness.Last(); // maximum is saved at last position
+
+
+    double worsening = -1;
+    ElementIndex ind;
+
+    if(quality_loss != NULL)
+      quality_loss->SetSize(mesh.GetNE());
+
+    for (ElementIndex i = 0; i < mesh.GetNE(); i++)
+      {
+	if(uselocalworsening)
+	  {
+	    loc_pure_badness = -1;
+	    for(int j=0; j<mesh[i].GetNP(); j++)
+	      if(pure_badness[mesh[i][j]] > loc_pure_badness)
+		loc_pure_badness = pure_badness[mesh[i][j]];
+	  }
+
+
+	double bad = mesh[i].CalcJacobianBadness (mesh.Points());
+	if (bad > 1e10 || 
+	    (max_worsening > 0 && bad > loc_pure_badness*max_worsening))
+	  bad_elements.Append(i);
+	  
+
+	if(max_worsening > 0)
+	  {
+	    double actw = bad/loc_pure_badness;
+	    if(quality_loss != NULL)
+	      (*quality_loss)[i] = actw;
+
+	    if(actw > worsening)
+	      {
+		worsening = actw;
+		ind = i;
+	      }
+	  }
+      }
+    return worsening;
+  }
+
+
+  void GetWorkingArea(BitArray & working_elements, BitArray & working_points,
+		      const Mesh & mesh, const Array<ElementIndex> & bad_elements,
+		      const int width)
+  {
+    working_elements.Clear();
+    working_points.Clear();
+
+    for(int i=0; i<bad_elements.Size(); i++)
+      {
+	working_elements.Set(bad_elements[i]);
+	const Element & el = mesh[bad_elements[i]];
+	for(int j=1; j<=el.GetNP(); j++)
+	  working_points.Set(el.PNum(j));
+      }
+    
+
+    for(int i=0; i<width; i++)
+      {
+	for(ElementIndex j=0; j<mesh.GetNE(); j++)
+	  {
+	    if(!working_elements.Test(j))
+	      {  
+		const Element & el = mesh[j];
+		bool set_active = false;
+		
+		for(int k=1; !set_active && k<=el.GetNP(); k++)
+		  set_active = working_points.Test(el.PNum(k));
+		
+		if(set_active)
+		  working_elements.Set(j);
+	      }
+	  }
+
+	for(ElementIndex j=0; j<mesh.GetNE(); j++)
+	  {
+	    if(working_elements.Test(j))
+	      {
+		const Element & el = mesh[j];
+		for(int k=1; k<=el.GetNP(); k++)
+		  working_points.Set(el.PNum(k));
+	      }
+	  }
+      }
+  }
+
+
+
+  void RepairBisection(Mesh & mesh, Array<ElementIndex> & bad_elements, 
+		       const BitArray & isnewpoint, const Refinement & refinement,
+		       const Array<double> & pure_badness, 
+		       double max_worsening, const bool uselocalworsening,
+		       const Array< Array<int,PointIndex::BASE>* > & idmaps)
+  {
+    ostringstream ostrstr;
+
+    const int maxtrials = 100;
+
+    //bool doit;
+    //cout << "DOIT: " << flush;
+    //cin >> doit;
+
+    int ne = mesh.GetNE();
+    int np = mesh.GetNP();
+
+    int numbadneighbours = 3;
+    const int numtopimprove = 3;
+
+    PrintMessage(1,"repairing");
+
+    PushStatus("Repair Bisection");
+
+    Array<Point<3>* > should(np);
+    Array<Point<3>* > can(np);
+    Array<Vec<3>* > nv(np);
+    for(int i=0; i<np; i++)
+      {
+	nv[i] = new Vec<3>;
+	should[i] = new Point<3>;
+	can[i] = new Point<3>;
+      }
+    
+    BitArray isboundarypoint(np),isedgepoint(np);
+    isboundarypoint.Clear();
+    isedgepoint.Clear();
+
+    for(int i = 1; i <= mesh.GetNSeg(); i++)
+      {
+	const Segment & seg = mesh.LineSegment(i);
+	isedgepoint.Set(seg[0]);
+	isedgepoint.Set(seg[1]);
+      }
+
+    Array<int> surfaceindex(np);
+    surfaceindex = -1;
+    
+    for (int i = 1; i <= mesh.GetNSE(); i++)
+      {
+	const Element2d & sel = mesh.SurfaceElement(i);
+	for (int j = 1; j <= sel.GetNP(); j++)
+	  if(!isedgepoint.Test(sel.PNum(j)))
+	    {
+	      isboundarypoint.Set(sel.PNum(j));
+	      surfaceindex[sel.PNum(j) - PointIndex::BASE] = 
+		mesh.GetFaceDescriptor(sel.GetIndex()).SurfNr();
+	    }
+      }
+
+
+
+    Validate(mesh,bad_elements,pure_badness,
+	     ((uselocalworsening) ?  (0.8*(max_worsening-1.) + 1.) : (0.1*(max_worsening-1.) + 1.)),
+	     uselocalworsening); // -> larger working area
+    BitArray working_elements(ne);
+    BitArray working_points(np);
+
+    GetWorkingArea(working_elements,working_points,mesh,bad_elements,numbadneighbours);
+    //working_elements.Set();
+    //working_points.Set();
+
+    ostrstr.str("");
+    ostrstr << "worsening: " <<
+      Validate(mesh,bad_elements,pure_badness,max_worsening,uselocalworsening);
+    PrintMessage(4,ostrstr.str());
+
+    
+
+    int auxnum=0;
+    for(int i=1; i<=np; i++)
+      if(working_points.Test(i))
+	auxnum++;
+    
+    ostrstr.str("");
+    ostrstr << "Percentage working points: " << 100.*double(auxnum)/np;
+    PrintMessage(5,ostrstr.str());
+    
+
+    BitArray isworkingboundary(np);
+    for(int i=1; i<=np; i++)
+      if(working_points.Test(i) && isboundarypoint.Test(i))
+	isworkingboundary.Set(i);
+      else
+	isworkingboundary.Clear(i);
+
+
+    for(int i=0; i<np; i++)
+      *should[i] = mesh.Point(i+1);
+
+    
+    for(int i=0; i<np; i++)
+      {
+	if(isnewpoint.Test(i+PointIndex::BASE) && 
+	   //working_points.Test(i+PointIndex::BASE) && 
+	   mesh.mlbetweennodes[i+PointIndex::BASE][0] > 0)
+	  *can[i] = Center(*can[mesh.mlbetweennodes[i+PointIndex::BASE][0]-PointIndex::BASE],
+			   *can[mesh.mlbetweennodes[i+PointIndex::BASE][1]-PointIndex::BASE]);
+	else
+	  *can[i] = mesh.Point(i+1);
+      }
+
+
+    int cnttrials = 1;
+    
+    double lamedge = 0.5;
+    double lamface = 0.5;
+    
+    double facokedge = 0;
+    double facokface = 0;
+    double factryedge;
+    double factryface = 0;
+
+    double oldlamedge,oldlamface;
+
+    MeshOptimize2d * optimizer2d = refinement.Get2dOptimizer();
+    if(!optimizer2d)
+      {
+	cerr << "No 2D Optimizer!" << endl;
+	return;
+      }    
+
+    while ((facokedge < 1.-1e-8 || facokface < 1.-1e-8) && 
+	   cnttrials < maxtrials &&
+	   multithread.terminate != 1)
+      {
+	(*testout) << "   facokedge " << facokedge << " facokface " << facokface << " cnttrials " << cnttrials << endl
+		   << " perc. " << 95. * max2( min2(facokedge,facokface),
+					       double(cnttrials)/double(maxtrials)) << endl;
+
+	SetThreadPercent(95. * max2( min2(facokedge,facokface),
+				     double(cnttrials)/double(maxtrials)));
+
+	ostrstr.str("");
+	ostrstr << "max. worsening " << max_worsening;
+	PrintMessage(5,ostrstr.str());
+	oldlamedge = lamedge;
+	lamedge *= 6;
+	if (lamedge > 2)
+	  lamedge = 2;
+	   
+	if(1==1 || facokedge < 1.-1e-8)
+	  {
+	    for(int i=0; i<nv.Size(); i++)
+	      *nv[i] = Vec<3>(0,0,0);
+	    for (int i = 1; i <= mesh.GetNSE(); i++)
+	      {
+		const Element2d & sel = mesh.SurfaceElement(i);
+		Vec<3> auxvec = Cross(mesh.Point(sel.PNum(2))-mesh.Point(sel.PNum(1)),
+                                      mesh.Point(sel.PNum(3))-mesh.Point(sel.PNum(1)));
+		auxvec.Normalize();
+		for (int j = 1; j <= sel.GetNP(); j++)
+		  if(!isedgepoint.Test(sel.PNum(j)))
+		    *nv[sel.PNum(j) - PointIndex::BASE] += auxvec;
+	      }
+	    for(int i=0; i<nv.Size(); i++)
+	      nv[i]->Normalize();
+	    
+	    
+	    do  // move edges
+	      {
+		lamedge *= 0.5;
+		cnttrials++;
+		if(cnttrials % 10 == 0)
+		  max_worsening *= 1.1;
+		
+		
+		factryedge = lamedge + (1.-lamedge) * facokedge;
+
+		ostrstr.str("");
+		ostrstr << "lamedge = " << lamedge << ", trying: " << factryedge;
+		PrintMessage(5,ostrstr.str());
+		
+
+		for (int i = 1; i <= np; i++)
+		  {
+		    if (isedgepoint.Test(i))
+		      {
+			for (int j = 0; j < 3; j++)
+			  mesh.Point(i)(j) = 
+			    lamedge * (*should.Get(i))(j) +
+			    (1.-lamedge) * (*can.Get(i))(j);
+		      }
+		    else
+		      mesh.Point(i) = *can.Get(i);
+		  }
+		if(facokedge < 1.-1e-8)
+		  {
+		    ostrstr.str("");
+		    ostrstr << "worsening: " <<
+		      Validate(mesh,bad_elements,pure_badness,max_worsening,uselocalworsening);
+
+		    PrintMessage(5,ostrstr.str());
+		  }
+		else
+		  Validate(mesh,bad_elements,pure_badness,-1,uselocalworsening);
+
+
+		ostrstr.str("");
+		ostrstr << bad_elements.Size() << " bad elements";
+		PrintMessage(5,ostrstr.str());
+	      }
+	    while (bad_elements.Size() > 0 && 
+		   cnttrials < maxtrials &&
+		   multithread.terminate != 1);
+	  }
+
+	if(cnttrials < maxtrials &&
+	   multithread.terminate != 1)
+	  {
+	    facokedge = factryedge;
+	    
+	    // smooth faces
+	    mesh.CalcSurfacesOfNode();
+	    
+	    MeshingParameters dummymp;
+	    mesh.ImproveMeshJacobianOnSurface(dummymp,isworkingboundary,nv,OPT_QUALITY, &idmaps);
+	    
+	    for (int i = 1; i <= np; i++)
+	      *can.Elem(i) = mesh.Point(i);
+	    
+	    if(optimizer2d)
+	      optimizer2d->ProjectBoundaryPoints(surfaceindex,can,should);
+	  }
+
+
+	oldlamface = lamface;
+	lamface *= 6;
+	if (lamface > 2)
+	  lamface = 2;
+
+
+	if(cnttrials < maxtrials &&
+	   multithread.terminate != 1)
+	  {
+
+	    do  // move faces
+	      {
+		lamface *= 0.5;
+		cnttrials++;
+		if(cnttrials % 10 == 0)
+		  max_worsening *= 1.1;
+		factryface = lamface + (1.-lamface) * facokface;
+
+		ostrstr.str("");
+		ostrstr << "lamface = " << lamface << ", trying: " << factryface;
+		PrintMessage(5,ostrstr.str());
+		
+		
+		for (int i = 1; i <= np; i++)
+		  {
+		    if (isboundarypoint.Test(i))
+		      {
+			for (int j = 0; j < 3; j++)
+			  mesh.Point(i)(j) = 
+			    lamface * (*should.Get(i))(j) +
+			    (1.-lamface) * (*can.Get(i))(j);
+		      }
+		    else
+		      mesh.Point(i) = *can.Get(i);
+		  }
+
+		ostrstr.str("");
+		ostrstr << "worsening: " <<
+		  Validate(mesh,bad_elements,pure_badness,max_worsening,uselocalworsening);
+		PrintMessage(5,ostrstr.str());
+	
+
+		ostrstr.str("");
+		ostrstr << bad_elements.Size() << " bad elements";
+		PrintMessage(5,ostrstr.str());
+	      }
+	    while (bad_elements.Size() > 0 && 
+		   cnttrials < maxtrials &&
+		   multithread.terminate != 1);
+	  }
+
+
+
+	if(cnttrials < maxtrials &&
+	   multithread.terminate != 1)
+	  {
+	    facokface = factryface;
+	    // smooth interior
+	    
+	    mesh.CalcSurfacesOfNode();
+	    
+	    MeshingParameters dummymp;
+	    mesh.ImproveMeshJacobian (dummymp, OPT_QUALITY,&working_points);
+	    //mesh.ImproveMeshJacobian (OPT_WORSTCASE,&working_points);
+	  
+
+	    for (int i = 1; i <= np; i++)
+	      *can.Elem(i) = mesh.Point(i);
+	  }
+	  
+	//!
+	if((facokedge < 1.-1e-8 || facokface < 1.-1e-8) && 
+	   cnttrials < maxtrials &&
+	   multithread.terminate != 1)
+	  {
+	    MeshingParameters dummymp;
+	    MeshOptimize3d optmesh(dummymp);
+	    for(int i=0; i<numtopimprove; i++)
+	      {
+		optmesh.SwapImproveSurface(mesh,OPT_QUALITY,&working_elements,&idmaps);
+		optmesh.SwapImprove(mesh,OPT_QUALITY,&working_elements);
+		
+	      }	    
+
+	    //	    mesh.mglevels = 1;
+	    
+		
+	    ne = mesh.GetNE();
+	    working_elements.SetSize(ne);
+	    
+	    
+	    for (int i = 1; i <= np; i++)
+	      mesh.Point(i) = *should.Elem(i);
+	    
+	    Validate(mesh,bad_elements,pure_badness,
+		     ((uselocalworsening) ?  (0.8*(max_worsening-1.) + 1.) : (0.1*(max_worsening-1.) + 1.)),
+		     uselocalworsening);
+	    
+	    if(lamedge < oldlamedge || lamface < oldlamface)
+	      numbadneighbours++;
+	    GetWorkingArea(working_elements,working_points,mesh,bad_elements,numbadneighbours);
+	    for(int i=1; i<=np; i++)
+	      if(working_points.Test(i) && isboundarypoint.Test(i))
+		isworkingboundary.Set(i);
+	      else
+		isworkingboundary.Clear(i);
+	    auxnum=0;
+	    for(int i=1; i<=np; i++)
+	      if(working_points.Test(i))
+		auxnum++;
+
+	    
+	    ostrstr.str("");
+	    ostrstr << "Percentage working points: " << 100.*double(auxnum)/np;
+	    PrintMessage(5,ostrstr.str());
+	    
+	    for (int i = 1; i <= np; i++)
+	      mesh.Point(i) = *can.Elem(i);
+	  }
+	//!
+
+      }
+
+    MeshingParameters dummymp;
+    MeshOptimize3d optmesh(dummymp);
+    for(int i=0; i<numtopimprove && multithread.terminate != 1; i++)
+      {
+	optmesh.SwapImproveSurface(mesh,OPT_QUALITY,NULL,&idmaps);
+	optmesh.SwapImprove(mesh,OPT_QUALITY);
+	//mesh.UpdateTopology();
+      }
+    mesh.UpdateTopology();
+    /*
+    if(cnttrials < 100)
+      {
+	nv = Vec3d(0,0,0);
+	for (int i = 1; i <= mesh.GetNSE(); i++)
+	  {
+	    const Element2d & sel = mesh.SurfaceElement(i);
+	    Vec3d auxvec = Cross(mesh.Point(sel.PNum(2))-mesh.Point(sel.PNum(1)),
+				 mesh.Point(sel.PNum(3))-mesh.Point(sel.PNum(1)));
+	    auxvec.Normalize();
+	    for (int j = 1; j <= sel.GetNP(); j++)
+	      if(!isedgepoint.Test(sel.PNum(j)))
+		nv[sel.PNum(j) - PointIndex::BASE] += auxvec;
+	  }
+	for(int i=0; i<nv.Size(); i++)
+	  nv[i].Normalize();
+	
+
+	mesh.ImproveMeshJacobianOnSurface(isboundarypoint,nv,OPT_QUALITY);
+	mesh.CalcSurfacesOfNode();
+	    // smooth interior
+	    
+	
+	for (int i = 1; i <= np; i++)
+	  if(isboundarypoint.Test(i))
+	    can.Elem(i) = mesh.Point(i);
+	    
+	if(optimizer2d)
+	  optimizer2d->ProjectBoundaryPoints(surfaceindex,can,should);
+
+	
+	for (int i = 1; i <= np; i++)
+	  if(isboundarypoint.Test(i))
+	    for(int j=1; j<=3; j++)
+	      mesh.Point(i).X(j) = should.Get(i).X(j);
+      }
+    */
+
+
+    if(cnttrials == maxtrials)
+      {
+	for (int i = 1; i <= np; i++)
+	  mesh.Point(i) = *should.Get(i);
+
+	Validate(mesh,bad_elements,pure_badness,max_worsening,uselocalworsening);
+	
+	for(int i=0; i<bad_elements.Size(); i++)
+	  {
+	    ostrstr.str("");
+	    ostrstr << "bad element:" << endl
+		    << mesh[bad_elements[i]][0] << ": " << mesh.Point(mesh[bad_elements[i]][0]) << endl
+		    << mesh[bad_elements[i]][1] << ": " << mesh.Point(mesh[bad_elements[i]][1]) << endl
+		    << mesh[bad_elements[i]][2] << ": " << mesh.Point(mesh[bad_elements[i]][2]) << endl
+		    << mesh[bad_elements[i]][3] << ": " << mesh.Point(mesh[bad_elements[i]][3]);
+	    PrintMessage(5,ostrstr.str());
+	  }
+	for (int i = 1; i <= np; i++)
+	  mesh.Point(i) = *can.Get(i);
+      }
+
+    for(int i=0; i<np; i++)
+      {
+	delete nv[i];
+	delete can[i];
+	delete should[i];
+      }
+
+    PopStatus();
+  }
+}
diff --git a/contrib/Netgen/libsrc/meshing/validate.hpp b/contrib/Netgen/libsrc/meshing/validate.hpp
new file mode 100644
index 0000000000..1cc01bec77
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/validate.hpp
@@ -0,0 +1,21 @@
+#ifndef VALIDATE_HPP
+#define VALIDATE_HPP
+
+namespace netgen
+{
+  
+  void GetPureBadness(Mesh & mesh, Array<double> & pure_badness,
+		      const BitArray & isnewpoint);
+  double Validate(const Mesh & mesh, Array<ElementIndex> & bad_elements,
+		  const Array<double> & pure_badness, 
+		  double max_worsening, const bool uselocalworsening,
+		  Array<double> * quality_loss = NULL);
+  void RepairBisection(Mesh & mesh, Array<ElementIndex> & bad_elements, 
+		       const BitArray & isnewpoint, const Refinement & refinement,
+		       const Array<double> & pure_badness, 
+		       double max_worsening, const bool uselocalworsening,
+		       const Array< Array<int,PointIndex::BASE>* > & idmaps);
+
+}
+
+#endif // VALIDATE_HPP
diff --git a/contrib/Netgen/libsrc/meshing/zrefine.cpp b/contrib/Netgen/libsrc/meshing/zrefine.cpp
new file mode 100644
index 0000000000..0032528e2b
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/zrefine.cpp
@@ -0,0 +1,740 @@
+#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)
+  {
+    // edges selected in csg input file
+    for (int i = 1; i <= geom.singedges.Size(); i++)
+      {
+	//if(geom.singedges.Get(i)->maxhinit > 0)
+	//  continue; //!!!!
+
+	const SingularEdge & se = *geom.singedges.Get(i);
+	for (int j = 1; j <= se.segms.Size(); j++)
+	  {
+	    INDEX_2 i2 = se.segms.Get(j);
+	    singedges.Set (i2, 1);
+	  }
+      }
+
+    // edges interactively selected
+    for (int i = 1; i <= mesh.GetNSeg(); i++)
+      {
+	const Segment & seg = mesh.LineSegment(i);
+	if (seg.singedge_left || seg.singedge_right)
+	  {
+	    INDEX_2 i2(seg[0], seg[1]);
+	    i2.Sort();
+	    singedges.Set (i2, 1);
+	  }
+      }
+  }
+
+
+  /**
+     Convert elements (vol-tets, surf-trigs) into prisms/quads
+  */
+  void MakePrismsSingEdge (Mesh & mesh, INDEX_2_HASHTABLE<int> & singedges)
+  {
+    // volume elements
+    for (int i = 1; i <= mesh.GetNE(); i++)
+      {
+	Element & el = mesh.VolumeElement(i);
+	if (el.GetType() != TET) continue;
+
+	for (int j = 1; j <= 3; j++)
+	  for (int 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 (int i = 1; i <= mesh.GetNSE(); i++)
+      {
+	Element2d & el = mesh.SurfaceElement(i);
+	if (el.GetType() != TRIG) continue;
+
+	for (int j = 1; j <= 3; j++)
+	  {
+	    int 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)[0] :
+	      mesh.LineSegment(i)[1];
+	    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;
+    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(0);
+	      
+		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();
+		    //(*testout) << "idnr " << idnr << " i " << i << endl;
+		    //(*testout) << "slices " << slices << endl;
+		    double slicefac = slices.Get(slicenr);
+		    double slicefaclast = 
+		      (slicenr == slices.Size()) ? 1 : slices.Get(slicenr+1);
+		    
+		    Point3d np = p1 + (slicefac / slicefaclast) * (p2-p1);
+		    //(*testout) << "slicenr " << slicenr << " slicefac " << slicefac << " quot " << (slicefac / slicefaclast) << " np " << np << endl;
+		    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[0], el[1]);
+	    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[0]),
+		// 				  mesh.Point (el[1]),
+		// 				  el.surfnr1, el.surfnr2,
+		// 				  el.epgeominfo[0], el.epgeominfo[1],
+		// 				  pb, ngi);
+		// 	      */
+		// 	      pb = Center (mesh.Point (el[0]), mesh.Point (el[1]));
+
+		// 	      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[1] = pnew;
+	    ns1.epgeominfo[1] = ngi;
+	    ns2[0] = 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 NetgenGeometry * hgeom,
+		    ZRefinementOptions & opt)
+  {
+    const CSGeometry * geom = dynamic_cast<const CSGeometry*> (hgeom);
+    if (!geom) return;
+
+    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/contrib/Netgen/libsrc/occ/Makefile.am b/contrib/Netgen/libsrc/occ/Makefile.am
new file mode 100644
index 0000000000..a3c7bd4b37
--- /dev/null
+++ b/contrib/Netgen/libsrc/occ/Makefile.am
@@ -0,0 +1,28 @@
+noinst_HEADERS = occgeom.hpp occmeshsurf.hpp \
+Partition_Inter2d.hxx Partition_Loop2d.hxx Partition_Loop.hxx \
+Partition_Inter3d.hxx Partition_Loop3d.hxx Partition_Spliter.hxx \
+Partition_Inter2d.ixx Partition_Loop2d.ixx Partition_Loop.ixx \
+Partition_Inter3d.ixx Partition_Loop3d.ixx Partition_Spliter.ixx \
+Partition_Inter2d.jxx Partition_Loop2d.jxx Partition_Loop.jxx \
+Partition_Inter3d.jxx Partition_Loop3d.jxx Partition_Spliter.jxx \
+utilities.h
+
+
+AM_CPPFLAGS = -I$(top_srcdir)/libsrc/include  $(OCCFLAGS) $(TCL_INCLUDES)
+
+# $(OCC_INC_FLAG)
+
+METASOURCES = AUTO
+
+lib_LTLIBRARIES = libocc.la liboccvis.la
+
+libocc_la_SOURCES = Partition_Inter2d.cxx Partition_Inter3d.cxx \
+	Partition_Loop.cxx Partition_Loop2d.cxx Partition_Loop3d.cxx Partition_Spliter.cxx \
+	occconstruction.cpp occgenmesh.cpp occgeom.cpp occmeshsurf.cpp
+
+libocc_la_LIBADD = $(OCCLIBS)
+
+liboccvis_la_SOURCES = occpkg.cpp vsocc.cpp
+liboccvis_la_LIBADD = libocc.la
+
+
diff --git a/contrib/Netgen/libsrc/occ/Partition_Inter2d.cxx b/contrib/Netgen/libsrc/occ/Partition_Inter2d.cxx
new file mode 100644
index 0000000000..700955276f
--- /dev/null
+++ b/contrib/Netgen/libsrc/occ/Partition_Inter2d.cxx
@@ -0,0 +1,678 @@
+#ifdef OCCGEOMETRY
+
+//  GEOM PARTITION : partition algorithm
+//
+//  Copyright (C) 2003  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
+//  CEDRAT, EDF R& D, LEG, PRINCIPIA R& D, BUREAU VERITAS
+//
+//  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.
+//
+//  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
+//
+//  See http://www.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org
+//
+//
+//
+//  File   : Partition_Inter2d.cxx
+//  Author : Benedicte MARTIN
+//  Module : GEOM
+//  $Header: /cvs/netgen/netgen/libsrc/occ/Partition_Inter2d.cxx,v 1.5 2008/03/31 14:20:28 wabro Exp $
+
+//using namespace std;
+
+#include "Partition_Inter2d.ixx"
+
+#include "utilities.h"
+
+#include <BRepAdaptor_Curve.hxx>
+#include <BRepAlgo_AsDes.hxx>
+#include <BRepLib_MakeVertex.hxx>
+#include <BRep_Builder.hxx>
+#include <BRep_Tool.hxx>
+#include <Geom_Surface.hxx>
+#include <Precision.hxx>
+#include <TopExp.hxx>
+#include <TopExp_Explorer.hxx>
+#include <TopOpeBRepDS_Transition.hxx>
+#include <TopOpeBRep_EdgesIntersector.hxx>
+#include <TopOpeBRep_Point2d.hxx>
+#include <TopTools_ListIteratorOfListOfShape.hxx>
+#include <TopTools_ListOfShape.hxx>
+#include <TopTools_MapIteratorOfMapOfShape.hxx>
+#include <TopTools_MapOfShape.hxx>
+#include <TopoDS.hxx>
+#include <TopoDS_Edge.hxx>
+#include <TopoDS_Vertex.hxx>
+#include <gp_Pnt.hxx>
+
+#ifdef DEB
+static Standard_Boolean TestEdges = 0;
+static Standard_Integer NbF2d = 0;
+static Standard_Integer NbE2d = 0;
+#endif
+
+//=======================================================================
+//function : getOtherShape
+//purpose  :
+//=======================================================================
+
+static TopoDS_Shape getOtherShape(const TopoDS_Shape&         theS,
+                                  const TopTools_ListOfShape& theSList)
+{
+  TopTools_ListIteratorOfListOfShape anIt( theSList );
+  for ( ; anIt.More(); anIt.Next() )
+    if (!theS.IsSame( anIt.Value() ))
+      return anIt.Value();
+
+  return TopoDS_Shape();
+}
+
+//=======================================================================
+//function : findVOnE
+//purpose  : on theE, find a vertex close to theV, such that an edge
+//           passing through it is an itersection of theF1 and theF2.
+//           theE intersects theE2 at theV
+//=======================================================================
+
+static Standard_Boolean findVOnE(const TopoDS_Vertex &         theV,
+                                 const TopoDS_Edge&            theE,
+                                 const TopoDS_Edge&            theE2,
+                                 const TopoDS_Shape&           theF1,
+                                 const TopoDS_Shape&           theF2,
+                                 const Handle(BRepAlgo_AsDes)& theAsDes,
+                                 TopoDS_Vertex &               theFoundV)
+{
+  Standard_Real MinDist2 = ::RealLast();
+  gp_Pnt P;
+
+  // check all vertices on theE
+  const TopTools_ListOfShape& aVList = theAsDes->Descendant( theE );
+  TopTools_ListIteratorOfListOfShape anIt( aVList );
+  if (anIt.More())
+    P = BRep_Tool::Pnt( theV );
+  for ( ; anIt.More(); anIt.Next() )
+  {
+    // check by distance
+    TopoDS_Vertex & V = TopoDS::Vertex( anIt.Value() );
+    Standard_Real dist2 = P.SquareDistance( BRep_Tool::Pnt( V ));
+    if (dist2 < MinDist2)
+      MinDist2 = dist2;
+    else
+      continue;
+
+    // V is a candidate if among edges passing through V there is one
+    // which is an intersection of theF1 and theF2
+    TopTools_ListIteratorOfListOfShape anEIt( theAsDes->Ascendant( V ));
+    Standard_Boolean isOk = Standard_False;
+    for (  ; !isOk && anEIt.More(); anEIt.Next() )
+    {
+      const TopoDS_Shape & E2 = anEIt.Value();
+      if ( theE2.IsSame( E2 ))
+        continue;
+      const TopTools_ListOfShape & aFList = theAsDes->Ascendant( E2 );
+      if (aFList.IsEmpty())
+        continue;
+      if ( theF1.IsSame( aFList.First() ))
+        isOk = theF2.IsSame( aFList.Last() );
+      else
+        isOk = theF2.IsSame( aFList.First() ) && theF1.IsSame( aFList.Last() );
+    }
+    if (isOk)
+      theFoundV = V;
+  }
+
+  if (theFoundV.IsNull())
+    return Standard_False;
+
+  // check that MinDist2 is not too large
+  Standard_Real f, l;
+  TopLoc_Location L;
+  Handle(Geom_Curve) aCurve = BRep_Tool::Curve( theE, L, f, l );
+  gp_Pnt P1 = aCurve->Value( f );
+  gp_Pnt P2 = aCurve->Value( 0.3 * f + 0.7 * l );
+  //gp_Pnt P2 = aCurve->Value( 0.5 * ( f + l ));
+  if (MinDist2 > P1.SquareDistance( P2 ))
+    return Standard_False;
+
+#ifdef DEB
+  MESSAGE("findVOnE: found MinDist = " << sqrt (MinDist2));
+#endif
+
+  return Standard_True;
+}
+
+//=======================================================================
+//function : AddVonE
+//purpose  : Put V in AsDes as intersection of E1 and E2.
+//           Check that vertex equal to V already exists on one
+//           of edges, in  such  a  case,  V  is  not added but
+//           existing vertex is updated to  be on E1 and E2 and
+//           is returned insead of V.
+//=======================================================================
+
+TopoDS_Vertex Partition_Inter2d::AddVonE(const TopoDS_Vertex& theV,
+                                         const TopoDS_Edge&   E1,
+                                         const TopoDS_Edge&   E2,
+                                         const Handle(BRepAlgo_AsDes)& AsDes,
+                                         const TopoDS_Face&   theF)
+
+{
+  //-------------------------------------------------------------
+  // test if the points of intersection already exist. If not,
+  // add as descendants of the edges.
+  // nb: theses points are only vertices of intersection.
+  //-------------------------------------------------------------
+  const TopTools_ListOfShape& VOnE1 = AsDes->Descendant(E1);
+  const TopTools_ListOfShape& VOnE2 = AsDes->Descendant(E2);
+  gp_Pnt                      P1,P2;
+  TopoDS_Vertex               V1,V2;
+  TopTools_ListIteratorOfListOfShape it;
+  BRep_Builder                       B;
+  TopAbs_Orientation                 O1,O2;
+  Standard_Real                      U1,U2;
+  Standard_Real                      Tol,Tol1,Tol2;
+  Standard_Boolean                   OnE1,OnE2;
+
+  TopoDS_Vertex V    = theV;
+
+  U1 = BRep_Tool::Parameter(V,E1);
+  U2 = BRep_Tool::Parameter(V,E2);
+  O1 = V.Orientation();
+  O2 = O1;
+  P1  = BRep_Tool::Pnt(V);
+  Tol = BRep_Tool::Tolerance( V );
+  OnE1 = OnE2 = Standard_False;
+
+  //-----------------------------------------------------------------
+  // Search if the point of intersection is a vertex of E1.
+  //-----------------------------------------------------------------
+  for (it.Initialize(VOnE1); it.More(); it.Next()) {
+    const TopoDS_Vertex& CV = TopoDS::Vertex( it.Value() );
+    if (V.IsSame( CV )) {
+      V1   = V;
+      OnE1 = Standard_True;
+      break;
+    }
+    P2 = BRep_Tool::Pnt( CV );
+    Tol1 = 1.1*(Tol + BRep_Tool::Tolerance( CV ));
+    if (P1.SquareDistance(P2) <= Tol1*Tol1) {
+      V    = CV;
+      V1   = V;
+      OnE1 = Standard_True;
+      break;
+    }
+  }
+  if (OnE1) {
+    //-----------------------------------------------------------------
+    // Search if the vertex found is still on E2.
+    //-----------------------------------------------------------------
+    for (it.Initialize(VOnE2); it.More(); it.Next()) {
+      if (V.IsSame( it.Value() )) {
+        OnE2 = Standard_True;
+        V2   = V;
+        break;
+      }
+    }
+  }
+  if (!OnE2) {
+    for (it.Initialize(VOnE2); it.More(); it.Next()) {
+      //-----------------------------------------------------------------
+      // Search if the point of intersection is a vertex of E2.
+      //-----------------------------------------------------------------
+      const TopoDS_Vertex& CV = TopoDS::Vertex( it.Value() );
+      P2 = BRep_Tool::Pnt( CV );
+      Tol2 = 1.1*(Tol + BRep_Tool::Tolerance( CV ));
+      if (P1.SquareDistance(P2) <= Tol2*Tol2) {
+        V  = CV;
+        V2 = V;
+        OnE2 = Standard_True;
+        break;
+      }
+    }
+  }
+
+
+  if (!OnE1 && !OnE2 && !theF.IsNull())
+  {
+    // if 3 faces intersects each others, 3 new edges on them must pass
+    // through one vertex but real intersection points of each
+    // pair of edges are sometimes more far than a tolerance.
+    // Try to analitically find vertices that E1 and E2 must pass trough
+
+    TopoDS_Shape F1 = getOtherShape( theF, AsDes->Ascendant( E1 ));
+    TopoDS_Shape F2 = getOtherShape( theF, AsDes->Ascendant( E2 ));
+    if (!F1.IsNull() && !F2.IsNull() && !F1.IsSame( F2 ))
+    {
+      OnE1 = findVOnE ( theV, E1, E2, F1, F2, AsDes, V1 );
+      OnE2 = findVOnE ( theV, E2, E1, F1, F2, AsDes, V2 );
+      if (OnE2) V = V2;
+      if (OnE1) V = V1;
+    }
+  }
+
+  if (OnE1 && OnE2) {
+    if (!V1.IsSame(V2)) {
+      // replace V1 with V2 on all edges V1 is on
+      Standard_Real UV1;
+      TopoDS_Edge   EWE1;
+      TopoDS_Vertex VI;
+      const TopTools_ListOfShape& EdgeWithV1 = AsDes->Ascendant(V1);
+
+      for (it.Initialize(EdgeWithV1); it.More(); it.Next()) {
+        EWE1  = TopoDS::Edge(it.Value());
+        VI = V1;
+        VI.Orientation(TopAbs_INTERNAL);
+        UV1 = BRep_Tool::Parameter(VI,EWE1);
+        VI = V2;
+        VI.Orientation(TopAbs_INTERNAL);
+        B.UpdateVertex( VI, UV1, EWE1, GetTolerance( VI, UV1, EWE1, AsDes));
+      }
+      AsDes->Replace(V1,V2);
+      V = V2;
+    }
+  }
+
+  // add existing vertices instead of new ones
+  if (!OnE1) {
+    if (OnE2) {
+      V.Orientation(TopAbs_INTERNAL);
+      B.UpdateVertex (V, U1, E1, GetTolerance( V, U1, E1, AsDes));
+    }
+    V.Orientation(O1);
+    AsDes->Add(E1,V);
+  }
+  if (!OnE2) {
+    if (OnE1) {
+      V.Orientation(TopAbs_INTERNAL);
+      B.UpdateVertex (V, U2, E2, GetTolerance( V, U2, E2, AsDes ));
+    }
+    V.Orientation(O2);
+    AsDes->Add(E2,V);
+  }
+
+  return V;
+}
+
+//=======================================================================
+//function : FindEndVertex
+//purpose  : Returns a vertex  from  <VertList> having parameter on
+//           <E>  closest  to  <f>  or  <l>.  <isFirst>  is True if
+//           found vertex is closer  to <f>. <DU> returns parameter
+//           difference.
+//=======================================================================
+
+TopoDS_Vertex Partition_Inter2d::FindEndVertex(const TopTools_ListOfShape& LV,
+                                               const Standard_Real f,
+                                               const Standard_Real l,
+                                               const TopoDS_Edge&  E,
+                                               Standard_Boolean&   isFirst,
+                                               Standard_Real&      minDU)
+{
+  TopoDS_Vertex endV;
+  Standard_Real U, endU, min;
+  minDU = 1.e10;
+
+  TopTools_ListIteratorOfListOfShape it;
+  it.Initialize(LV);
+  for (; it.More(); it.Next()) {
+    const TopoDS_Vertex& v = TopoDS::Vertex(it.Value());
+    U = BRep_Tool::Parameter(v, E);
+    min = Min( Abs(U-f), Abs(U-l) );
+    if (min < minDU) {
+      endV = v;
+      endU = U;
+      minDU = min;
+    }
+  }
+  if (Abs(endU-f) < Abs(endU-l))
+    isFirst = Standard_True;
+  else
+    isFirst = Standard_False;
+
+  return endV;
+}
+
+//=======================================================================
+//function : treatClosed
+//purpose  : add second vertex to closed edge. Vertex is one of <LV1>
+//=======================================================================
+
+static void treatClosed (const TopoDS_Edge& E1,
+                          const Standard_Real f,
+                          const Standard_Real l,
+                          TopTools_ListOfShape& LV1,
+                          TopTools_ListOfShape& /*LV2*/)
+{
+  Standard_Boolean isFirst=0;
+  Standard_Real    minDU = 1.e10;
+  TopoDS_Vertex endV;
+  endV = Partition_Inter2d::FindEndVertex(LV1, f,l, E1, isFirst,minDU);
+
+  if (minDU > Precision::PConfusion())
+    return; // not end point
+
+  Standard_Real newU;
+  if (isFirst)
+    newU = f + (l - f);
+  else
+    newU = l - (l - f);
+
+  // update end parameter
+  BRep_Builder B;
+  endV.Orientation(TopAbs_INTERNAL);
+  B.UpdateVertex(endV,newU,E1,BRep_Tool::Tolerance(endV));
+}
+
+//=======================================================================
+//function : EdgesPartition
+//purpose  :
+//=======================================================================
+
+static void EdgesPartition(const TopoDS_Face&            F,
+                           const TopoDS_Edge&            E1,
+                           const TopoDS_Edge&            E2,
+                           const Handle(BRepAlgo_AsDes)& AsDes,
+                           const TopTools_MapOfShape&    NewEdges,
+                           const Standard_Boolean        WithOri)
+{
+
+  Standard_Real f[3],l[3];
+  Standard_Real MilTol2;
+  Standard_Real Tol = Max (BRep_Tool::Tolerance(E1),
+                           BRep_Tool::Tolerance(E2));
+  MilTol2 = Tol * Tol * 10;
+
+  BRep_Tool::Range(E1, f[1], l[1]);
+  BRep_Tool::Range(E2, f[2], l[2]);
+
+  BRepAdaptor_Curve CE1(E1,F);
+  BRepAdaptor_Curve CE2(E2,F);
+
+  TopoDS_Edge                 EI[3]; EI[1] = E1; EI[2] = E2;
+  TopTools_ListOfShape        LV1; // new vertices at intersections on E1
+  TopTools_ListOfShape        LV2; // ... on E2
+  BRep_Builder                B;
+
+  // if E1 and E2 are results of intersection of F and two connex faces then
+  // no need to intersect edges, they can contact by vertices only
+  // (encounted an exception in TopOpeBRep_EdgesIntersector in such a case)
+  Standard_Boolean intersect = Standard_True;
+  TopTools_IndexedMapOfShape ME;
+  TopExp::MapShapes(F, TopAbs_EDGE, ME);
+  if (!ME.Contains(E1) && ! ME.Contains(E2)) { // if E1 and E2 are new on F
+    TopoDS_Shape F1, F2;
+    const TopTools_ListOfShape& LF1 = AsDes->Ascendant( E1 );
+    F1 = F.IsSame( LF1.First() ) ? LF1.Last() : LF1.First();
+    const TopTools_ListOfShape& LF2 = AsDes->Ascendant( E2 );
+    F2 = F.IsSame( LF2.First() ) ? LF2.Last() : LF2.First();
+    if (!F.IsSame(F2) && !F.IsSame(F1) ) {
+      TopExp_Explorer exp(F2, TopAbs_EDGE);
+      TopExp::MapShapes(F1, TopAbs_EDGE, ME);
+      for (; exp.More(); exp.Next()) {
+        if (ME.Contains( exp.Current())) {
+          intersect = Standard_False;
+          break;
+        }
+      }
+    }
+  }
+
+  if (intersect) {
+    //------------------------------------------------------
+    // compute the points of Intersection in 2D
+    //-----------------------------------------------------
+    // i.e. fill LV1 and LV2
+    TopOpeBRep_EdgesIntersector EInter;
+    EInter.SetFaces(F,F);
+    Standard_Real TolDub = 1.e-7;
+    EInter.ForceTolerances(TolDub,TolDub);
+    Standard_Boolean reducesegments = Standard_False;
+    EInter.Perform (E1,E2,reducesegments);
+
+    Standard_Boolean rejectreducedsegmentpoints = Standard_False;
+    EInter.InitPoint(rejectreducedsegmentpoints);
+    for ( ; EInter.MorePoint(); EInter.NextPoint() )
+    {
+      const TopOpeBRep_Point2d& P2D = EInter.Point();
+      const gp_Pnt&    P    = P2D.Value();
+      TopoDS_Vertex    V    = BRepLib_MakeVertex(P);
+
+      //-------------------------
+      // control the point found.
+      //-------------------------
+      gp_Pnt P1 = CE1.Value(P2D.Parameter(1));
+      gp_Pnt P2 = CE2.Value(P2D.Parameter(2));
+      Standard_Real sqd1 = P1.SquareDistance(P);
+      Standard_Real sqd2 = P2.SquareDistance(P);
+      if (sqd1 > MilTol2 || sqd2 > MilTol2  )
+        continue;
+
+      // add a new vertex to the both edges
+      Standard_Real toler = Max( Tol, sqrt( Max( sqd1, sqd2 )));
+      Standard_Integer i;
+      for (i = 1; i <= 2; i++) {
+        Standard_Real U = P2D.Parameter(i);
+        V.Orientation(TopAbs_INTERNAL);
+        B.UpdateVertex( V,U,EI[i], toler);
+        TopAbs_Orientation OO = TopAbs_REVERSED;
+        if (WithOri) {
+          if (P2D.IsVertex(i))
+            OO = P2D.Vertex(i).Orientation();
+          else if (P2D.Transition(i).Before() == TopAbs_OUT) {
+            OO = TopAbs_FORWARD;
+          }
+          V.Orientation(OO);
+          if (i == 1) LV1.Append(V);
+          else        LV2.Append(V);
+        }
+      }
+    }
+  } // if (intersect)
+
+  //----------------------------------
+  // Test the extremities of the edges.
+  //----------------------------------
+  // add to LV* vertices for vertex-vertex closeness
+  Standard_Real U1,U2;
+  Standard_Real TolConf2, TolConf;
+  TopoDS_Vertex V1[2],V2[2];
+  TopExp::Vertices(E1,V1[0],V1[1]);
+  TopExp::Vertices(E2,V2[0],V2[1]);
+
+  Standard_Integer i,j,k;
+  for (j = 0; j < 2; j++) {
+    if (V1[j].IsNull()) continue;
+    for ( k = 0; k < 2; k++) {
+      if (V2[k].IsNull()) continue;
+      gp_Pnt P1 = BRep_Tool::Pnt(V1[j]);
+      gp_Pnt P2 = BRep_Tool::Pnt(V2[k]);
+      TolConf = BRep_Tool::Tolerance(V1[j]) + BRep_Tool::Tolerance(V2[k]);
+      TolConf = Max (Tol, TolConf);
+      TolConf2 = TolConf * TolConf;
+      if (!intersect)
+        TolConf2 *= 100;
+      Standard_Real SqDist = P1.SquareDistance(P2);
+
+      if (SqDist <= TolConf2) {
+        TopoDS_Vertex V = BRepLib_MakeVertex(P1);
+        V.Orientation(TopAbs_INTERNAL);
+        U1 = (j == 0) ? f[1] : l[1];
+        U2 = (k == 0) ? f[2] : l[2];
+        B.UpdateVertex(V,U1,E1,TolConf);
+        B.UpdateVertex(V,U2,E2,TolConf);
+        LV1.Prepend(V.Oriented(V1[j].Orientation()));
+        LV2.Prepend(V.Oriented(V2[k].Orientation()));
+      }
+    }
+  }
+
+  Standard_Boolean AffichPurge = Standard_False;
+
+  if ( LV1.IsEmpty()) return;
+
+  //----------------------------------
+  // Purge of all the vertices.
+  //----------------------------------
+  // remove one of close vertices
+  TopTools_ListIteratorOfListOfShape it1LV1,it1LV2,it2LV1;
+  gp_Pnt P1,P2;
+  Standard_Boolean Purge = Standard_True;
+
+  while (Purge) {
+    i = 1;
+    Purge = Standard_False;
+    for (it1LV1.Initialize(LV1),it1LV2.Initialize(LV2);
+         it1LV1.More();
+         it1LV1.Next(),it1LV2.Next()) {
+      j = 1;
+      it2LV1.Initialize(LV1);
+      while (j < i) {
+        const TopoDS_Vertex& VE1 = TopoDS::Vertex(it1LV1.Value());
+        const TopoDS_Vertex& VE2 = TopoDS::Vertex(it2LV1.Value());
+        Standard_Real Tol1 = BRep_Tool::Tolerance( VE1 );
+        Standard_Real Tol2 = BRep_Tool::Tolerance( VE2 );
+        P1 = BRep_Tool::Pnt( VE1 );
+        P2 = BRep_Tool::Pnt( VE2 );
+        if (P1.IsEqual(P2, Tol1 + Tol2)) {
+          LV1.Remove(it1LV1);
+          LV2.Remove(it1LV2);
+          Purge = Standard_True;
+          break;
+        }
+        j++;
+        it2LV1.Next();
+      }
+      if (Purge) break;
+      i++;
+    }
+  }
+
+  // care of new closed edges, they always intersect with seam at end
+  if (V1[0].IsSame( V1[1] ) && NewEdges.Contains(E1) )
+    treatClosed (E1, f[1], l[1], LV1, LV2);
+  if (V2[0].IsSame( V2[1] ) && NewEdges.Contains(E2) )
+    treatClosed (E2, f[2], l[2], LV2, LV1);
+
+  //----------------
+  // Stocking vertex
+  //----------------
+
+  for ( it1LV1.Initialize( LV1 ); it1LV1.More(); it1LV1.Next())
+    Partition_Inter2d::AddVonE (TopoDS::Vertex( it1LV1.Value()),
+                                E1, E2, AsDes, F);
+}
+
+//=======================================================================
+//function : CompletPart2d
+//purpose  : Computes the intersections between the edges stored
+//           is AsDes as descendants of <F> . Intersections is computed
+//           between two edges if one of them is bound in NewEdges.
+//=======================================================================
+
+void Partition_Inter2d::CompletPart2d (const Handle(BRepAlgo_AsDes)&   AsDes,
+                                       const TopoDS_Face&              F,
+                                       const TopTools_MapOfShape&      NewEdges)
+{
+
+#ifdef DEB
+  NbF2d++;
+  NbE2d = 0;
+#endif
+
+  //Do not intersect the edges of a face
+  TopTools_IndexedMapOfShape EdgesOfFace;
+  TopExp::MapShapes( F, TopAbs_EDGE , EdgesOfFace);
+
+  //-------------------------------------------------------------------
+  // compute the intersection2D on the faces touched by the intersection3D
+  //-------------------------------------------------------------------
+  TopTools_ListIteratorOfListOfShape it1LE ;
+  TopTools_ListIteratorOfListOfShape it2LE ;
+
+  //-----------------------------------------------
+  // Intersection edge-edge.
+  //-----------------------------------------------
+  const TopTools_ListOfShape&        LE = AsDes->Descendant(F);
+  TopoDS_Vertex                      V1,V2;
+  Standard_Integer                   j, i = 1;
+
+  TopoDS_Face FF = F;
+  FF.Orientation(TopAbs_FORWARD);
+
+  for ( it1LE.Initialize(LE) ; it1LE.More(); it1LE.Next()) {
+    const TopoDS_Edge& E1 = TopoDS::Edge(it1LE.Value());
+    j = 1;
+    it2LE.Initialize(LE);
+
+    while (j < i && it2LE.More()) {
+      const TopoDS_Edge& E2 = TopoDS::Edge(it2LE.Value());
+      //----------------------------------------------------------
+      // Intersections of the new edges obtained by intersection
+      // between them and with the restrictions edges
+      //----------------------------------------------------------
+      if ( (!EdgesOfFace.Contains(E1) || !EdgesOfFace.Contains(E2)) &&
+           (NewEdges.Contains(E1) || NewEdges.Contains(E2)) ) {
+        EdgesPartition(FF,E1,E2,AsDes,NewEdges,Standard_True);
+      }
+      it2LE.Next();
+      j++;
+    }
+    i++;
+  }
+}
+
+//=======================================================================
+//function : GetTolerance
+//purpose  : Returns  tolerance  theV   must   have  atfer  its
+//           addition to theE with  theU parameter. theAsDes is
+//           used to find pcurves of theE
+//=======================================================================
+
+Standard_Real Partition_Inter2d::GetTolerance
+                         (const TopoDS_Vertex &         theV,
+                          const Standard_Real           theU,
+                          const TopoDS_Edge &           theE,
+                          const Handle(BRepAlgo_AsDes)& theAsDes)
+{
+  Standard_Real aTol = BRep_Tool::Tolerance( theV );
+  gp_Pnt aPnt = BRep_Tool::Pnt( theV );
+
+  // check point on 3D curve
+  Standard_Real f,l;
+  Handle(Geom_Curve) C = BRep_Tool::Curve( theE, f, l );
+  if (!C.IsNull())
+    aTol = Max ( aTol, aPnt.Distance( C->Value( theU )));
+
+  // check points on pcurves
+  const TopTools_ListOfShape& aFList = theAsDes->Ascendant( theE );
+  TopTools_ListIteratorOfListOfShape aFIt( aFList );
+  for (  ; aFIt.More(); aFIt.Next() )
+  {
+    const TopoDS_Face& F = TopoDS::Face( aFIt.Value() );
+    Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( theE, F, f, l );
+    if (!pcurve.IsNull())
+    {
+      gp_Pnt2d aPnt2d = pcurve->Value( theU );
+      TopLoc_Location L;
+      Handle(Geom_Surface) S = BRep_Tool::Surface( F, L );
+      gp_Pnt aPntOnS = S->Value( aPnt2d.X(), aPnt2d.Y() );
+      if (!L.IsIdentity())
+        aPntOnS.Transform( L.Transformation() );
+      aTol = Max ( aTol, aPnt.Distance( aPntOnS ));
+    }
+  }
+
+  return aTol;
+}
+
+#endif
diff --git a/contrib/Netgen/libsrc/occ/Partition_Inter2d.hxx b/contrib/Netgen/libsrc/occ/Partition_Inter2d.hxx
new file mode 100644
index 0000000000..cfd4a9ac0a
--- /dev/null
+++ b/contrib/Netgen/libsrc/occ/Partition_Inter2d.hxx
@@ -0,0 +1,110 @@
+//  GEOM PARTITION : partition algorithm
+//
+//  Copyright (C) 2003  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
+//  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS 
+// 
+//  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. 
+// 
+//  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 
+// 
+//  See http://www.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org 
+//
+//
+//
+//  File   : Partition_Inter2d.hxx
+//  Module : GEOM
+
+#ifndef _Partition_Inter2d_HeaderFile
+#define _Partition_Inter2d_HeaderFile
+
+#ifndef _Handle_BRepAlgo_AsDes_HeaderFile
+#include <Handle_BRepAlgo_AsDes.hxx>
+#endif
+#ifndef _Standard_Real_HeaderFile
+#include <Standard_Real.hxx>
+#endif
+#ifndef _Standard_Boolean_HeaderFile
+#include <Standard_Boolean.hxx>
+#endif
+class BRepAlgo_AsDes;
+class TopoDS_Face;
+class TopTools_MapOfShape;
+class TopoDS_Vertex;
+class TopTools_ListOfShape;
+class TopoDS_Edge;
+
+
+#ifndef _Standard_HeaderFile
+#include <Standard.hxx>
+#endif
+#ifndef _Standard_Macro_HeaderFile
+#include <Standard_Macro.hxx>
+#endif
+
+class Partition_Inter2d  {
+
+public:
+
+   void* operator new(size_t,void* anAddress) 
+   {
+      return anAddress;
+   }
+   void* operator new(size_t size) 
+   { 
+      return Standard::Allocate(size); 
+   }
+   void  operator delete(void *anAddress) 
+   { 
+      if (anAddress) Standard::Free((Standard_Address&)anAddress); 
+   }
+   // Methods PUBLIC
+   // 
+   static  void CompletPart2d(const Handle(BRepAlgo_AsDes)& AsDes,const TopoDS_Face& F,const TopTools_MapOfShape& NewEdges) ;
+   static  TopoDS_Vertex FindEndVertex(const TopTools_ListOfShape& VertList,const Standard_Real f,const Standard_Real l,const TopoDS_Edge& E,Standard_Boolean& First,Standard_Real& DU) ;
+   static  TopoDS_Vertex AddVonE(const TopoDS_Vertex& V,const TopoDS_Edge& E1,const TopoDS_Edge& E2,const Handle(BRepAlgo_AsDes)& AsDes,const TopoDS_Face& F) ;
+   static  Standard_Real GetTolerance(const TopoDS_Vertex& theV,const Standard_Real theU,const TopoDS_Edge& theE,const Handle(BRepAlgo_AsDes)& theAsDes) ;
+
+
+
+
+protected:
+
+   // Methods PROTECTED
+   // 
+
+
+   // Fields PROTECTED
+   //
+
+
+private: 
+
+   // Methods PRIVATE
+   // 
+
+
+   // Fields PRIVATE
+   //
+
+
+};
+
+
+
+
+
+// other Inline functions and methods (like "C++: function call" methods)
+//
+
+
+#endif
diff --git a/contrib/Netgen/libsrc/occ/Partition_Inter2d.ixx b/contrib/Netgen/libsrc/occ/Partition_Inter2d.ixx
new file mode 100644
index 0000000000..5dbe719329
--- /dev/null
+++ b/contrib/Netgen/libsrc/occ/Partition_Inter2d.ixx
@@ -0,0 +1,32 @@
+//  GEOM PARTITION : partition algorithm
+//
+//  Copyright (C) 2003  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
+//  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS 
+// 
+//  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. 
+// 
+//  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 
+// 
+//  See http://www.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org 
+//
+//
+//
+//  File   : Partition_Inter2d.ixx
+//  Module : GEOM
+
+#include <climits>
+#include "Partition_Inter2d.jxx"
+
+ 
+
+
diff --git a/contrib/Netgen/libsrc/occ/Partition_Inter2d.jxx b/contrib/Netgen/libsrc/occ/Partition_Inter2d.jxx
new file mode 100644
index 0000000000..2d08527511
--- /dev/null
+++ b/contrib/Netgen/libsrc/occ/Partition_Inter2d.jxx
@@ -0,0 +1,50 @@
+//  GEOM PARTITION : partition algorithm
+//
+//  Copyright (C) 2003  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
+//  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS 
+// 
+//  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. 
+// 
+//  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 
+// 
+//  See http://www.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org 
+//
+//
+//
+//  File   : Partition_Inter2d.jxx
+//  Module : GEOM
+
+#include <mystdlib.h>  // netgen headers
+
+
+#ifndef _BRepAlgo_AsDes_HeaderFile
+#include <BRepAlgo_AsDes.hxx>
+#endif
+#ifndef _TopoDS_Face_HeaderFile
+#include <TopoDS_Face.hxx>
+#endif
+#ifndef _TopTools_MapOfShape_HeaderFile
+#include <TopTools_MapOfShape.hxx>
+#endif
+#ifndef _TopoDS_Vertex_HeaderFile
+#include <TopoDS_Vertex.hxx>
+#endif
+#ifndef _TopTools_ListOfShape_HeaderFile
+#include <TopTools_ListOfShape.hxx>
+#endif
+#ifndef _TopoDS_Edge_HeaderFile
+#include <TopoDS_Edge.hxx>
+#endif
+#ifndef _Partition_Inter2d_HeaderFile
+#include "Partition_Inter2d.hxx"
+#endif
diff --git a/contrib/Netgen/libsrc/occ/Partition_Inter3d.cxx b/contrib/Netgen/libsrc/occ/Partition_Inter3d.cxx
new file mode 100644
index 0000000000..a47ff2dff5
--- /dev/null
+++ b/contrib/Netgen/libsrc/occ/Partition_Inter3d.cxx
@@ -0,0 +1,947 @@
+#ifdef OCCGEOMETRY
+
+//  GEOM PARTITION : partition algorithm
+//
+//  Copyright (C) 2003  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
+//  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS 
+// 
+//  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. 
+// 
+//  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 
+// 
+//  See http://www.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org 
+//
+//
+//
+//  File   : Partition_Inter3d.cxx
+//  Author : Benedicte MARTIN
+//  Module : GEOM
+//  $Header: /cvs/netgen/netgen/libsrc/occ/Partition_Inter3d.cxx,v 1.6 2008/03/31 14:20:28 wabro Exp $
+
+//using namespace std;
+#include <climits>
+
+#include "Partition_Inter2d.hxx"
+#include "Partition_Inter3d.ixx"
+#include "utilities.h"
+
+#include <BRepAlgo_AsDes.hxx>
+#include <BRepAlgo_Image.hxx>
+#include <BRepLib.hxx>
+#include <BRepOffset_Tool.hxx>
+#include <BRep_Builder.hxx>
+#include <BRep_Tool.hxx>
+
+#include <TopExp.hxx>
+#include <TopExp_Explorer.hxx>
+
+#include <TopOpeBRepTool_BoxSort.hxx>
+#include <TopTools_DataMapIteratorOfDataMapOfShapeListOfShape.hxx>
+#include <TopTools_ListIteratorOfListOfShape.hxx>
+#include <TopTools_ListOfShape.hxx>
+#include <TopoDS.hxx>
+#include <TopoDS_Compound.hxx>
+#include <TopoDS_Edge.hxx>
+#include <TopoDS_Face.hxx>
+#include <TopoDS_Vertex.hxx>
+
+#ifdef DEB
+#include <DBRep.hxx>
+#endif
+
+#include <BRepLib_MakeVertex.hxx>
+#include <BRepTools.hxx>
+#include <Extrema_ExtPS.hxx>
+#include <Extrema_POnSurf.hxx>
+#include <Geom2dAPI_ProjectPointOnCurve.hxx>
+#include <Geom2d_Curve.hxx>
+#include <GeomAPI_ProjectPointOnCurve.hxx>
+#include <GeomAdaptor_Surface.hxx>
+#include <Geom_Curve.hxx>
+#include <Geom_RectangularTrimmedSurface.hxx>
+#include <Geom_SphericalSurface.hxx>
+#include <Geom_Surface.hxx>
+#include <Geom_TrimmedCurve.hxx>
+#include <Precision.hxx>
+#include <TColStd_MapOfInteger.hxx>
+#include <TopOpeBRepBuild_Builder.hxx>
+#include <TopOpeBRepDS_BuildTool.hxx>
+#include <TopOpeBRepDS_CurveExplorer.hxx>
+#include <TopOpeBRepDS_HDataStructure.hxx>
+#include <TopOpeBRepDS_Interference.hxx>
+#include <TopOpeBRepDS_PointIterator.hxx>
+#include <TopOpeBRepDS_Transition.hxx>
+#include <TopOpeBRepTool_CurveTool.hxx>
+#include <TopOpeBRepTool_GeomTool.hxx>
+#include <TopOpeBRepTool_OutCurveType.hxx>
+#include <TopOpeBRep_DSFiller.hxx>
+#include <TopTools_DataMapIteratorOfDataMapOfShapeShape.hxx>
+#include <stdio.h>
+
+//=======================================================================
+//function : Partition_Inter3d
+//purpose  : 
+//=======================================================================
+
+Partition_Inter3d::Partition_Inter3d()
+{
+}
+//=======================================================================
+//function : Partition_Inter3d
+//purpose  : 
+//=======================================================================
+
+Partition_Inter3d::Partition_Inter3d(const Handle(BRepAlgo_AsDes)& AsDes)
+  :myAsDes(AsDes)
+{
+  mySectionEdgesAD = new BRepAlgo_AsDes;
+}
+
+//=======================================================================
+//function : CompletPart3d
+//purpose  : FaceShapeMap is just to know the shape a face belongs to
+//=======================================================================
+
+void Partition_Inter3d::CompletPart3d(const TopTools_ListOfShape& SetOfFaces1,
+				      const TopTools_DataMapOfShapeShape& FaceShapeMap)
+{
+  if (myAsDes.IsNull())
+    myAsDes = new BRepAlgo_AsDes;
+  
+  TopTools_ListIteratorOfListOfShape it;
+
+  //---------------------------------------------------------------
+  // Construction of bounding boxes.
+  //---------------------------------------------------------------
+
+  BRep_Builder B;
+  TopoDS_Compound CompOS;
+  B.MakeCompound(CompOS);
+  for (it.Initialize(SetOfFaces1); it.More(); it.Next())
+    B.Add(CompOS, it.Value());
+    
+  TopOpeBRepTool_BoxSort BOS;
+  BOS.AddBoxesMakeCOB(CompOS,TopAbs_FACE);
+
+  for (it.Initialize(SetOfFaces1); it.More(); it.Next()) {
+    TopoDS_Face F1 = TopoDS::Face(it.Value());
+    
+    // avoid intersecting faces of one shape
+    TopoDS_Shape S1;
+    if (FaceShapeMap.IsBound(F1)) S1 = FaceShapeMap.Find(F1);
+
+    // to filter faces sharing an edge
+    TopTools_IndexedMapOfShape EM;
+    TopExp::MapShapes( F1, TopAbs_EDGE, EM);
+    
+    TColStd_ListIteratorOfListOfInteger itLI = BOS.Compare(F1);
+    for (; itLI.More(); itLI.Next()) {
+      TopoDS_Face F2 = TopoDS::Face(BOS.TouchedShape(itLI));
+      if (F1.IsSame(F2) || IsDone(F1,F2))
+	continue;
+
+      TopoDS_Shape S2;
+      if (FaceShapeMap.IsBound(F2)) S2 = FaceShapeMap.Find(F2);
+      if (!S1.IsNull() && S1.IsSame(S2))
+	continue; // descendants of one shape
+
+      TopExp_Explorer expE (F2, TopAbs_EDGE);
+      for ( ; expE.More(); expE.Next())
+	if (EM.Contains( expE.Current() ))
+	  break;
+      if (expE.More())
+      {
+        // faces have a common edge, check if they are a tool and a face
+        // generated by the tool in another shape; in that case they are
+        // to be intersected
+        TopLoc_Location L1, L2;
+        Handle(Geom_Surface) S1 = BRep_Tool::Surface( F1, L1 );
+        Handle(Geom_Surface) S2 = BRep_Tool::Surface( F2, L2 );
+        if ( S1 != S2 || L1 != L2 )
+          continue;
+      }
+
+      F1.Orientation(TopAbs_FORWARD);
+      F2.Orientation(TopAbs_FORWARD);
+      FacesPartition(F1,F2);	  
+    }
+
+    // mark as modified a face which has at least one new edge
+    if (!myAsDes->HasDescendant( F1 ))
+      continue;
+    TopTools_ListIteratorOfListOfShape itE (myAsDes->Descendant( F1 ));
+    for ( ; itE.More(); itE.Next()) {
+      if (myNewEdges.Contains( itE.Value())) {
+	myTouched.Add( F1 );
+	break;
+      }
+    }
+  }
+}
+
+//=======================================================================
+//function : PutInBounds
+//purpose  : 
+//=======================================================================
+
+static void PutInBounds (const TopoDS_Face&          F,
+			 const TopoDS_Edge&          E,
+			 Handle(Geom2d_Curve)&       C2d)
+{
+  Standard_Real   umin,umax,vmin,vmax;
+  Standard_Real   f,l;
+  BRep_Tool::Range(E,f,l);
+
+  TopLoc_Location L; // Recup S avec la location pour eviter la copie.
+  Handle (Geom_Surface) S   = BRep_Tool::Surface(F,L);
+
+  if (S->IsKind(STANDARD_TYPE(Geom_RectangularTrimmedSurface))) {
+    S = (*(Handle_Geom_RectangularTrimmedSurface*)&S)->BasisSurface();
+  }
+  if (!S->IsUPeriodic() && !S->IsVPeriodic())
+    return;
+
+  BRepTools::UVBounds(F,umin,umax,vmin,vmax);
+
+  gp_Pnt2d Pf = C2d->Value(f);
+  gp_Pnt2d Pl = C2d->Value(l);
+  const Standard_Real Um = 0.34*f + 0.66*l;
+  gp_Pnt2d Pm = C2d->Value( Um );
+
+  // sometimes on shpere, pcurve is out of domain by V though S is
+  // UPeriodic, sometimes it is in domain but nontheless it has
+  // wrong position.
+  // Check pcurve position by 3D point
+  if (S->IsKind(STANDARD_TYPE( Geom_SphericalSurface )))
+  {
+    // get point on the surface
+    gp_Pnt Ps = S->Value( Pm.X(), Pm.Y() );
+    // get point on the edge
+    Handle(Geom_Curve) C = BRep_Tool::Curve( E, f, l );
+    gp_Pnt Pc = C->Value( Um );
+    // compare points
+    Standard_Real TolE = BRep_Tool::Tolerance( E );
+    if ( Pc.SquareDistance( Ps ) * 0.95 < TolE * TolE )
+      return; // OK
+
+    // find good UV for Pc: project Pc on S
+    GeomAdaptor_Surface  SA (S);
+    Extrema_ExtPS anExtPS (Pc, SA,
+                           SA.UResolution( TolE ), SA.VResolution( TolE ));
+    if (anExtPS.IsDone())
+    {
+      Standard_Integer i, nbExt = anExtPS.NbExt();
+      Extrema_POnSurf aPOnSurf;
+      for (i = 1; i <= nbExt; ++i )
+	if (anExtPS.Value( i ) <= TolE)               // V6.3
+	  // if (anExtPS.SquareDistance( i ) <= TolE)   // V6.5
+	  {
+          aPOnSurf = anExtPS.Point( i );
+          break;
+        }
+      if (i <= nbExt) {
+        // a point found
+        Standard_Real u, v;
+        aPOnSurf.Parameter( u, v );
+        gp_Pnt2d aGoodPm ( u, v );
+        C2d->Translate( Pm , aGoodPm );
+      }
+    }
+  }
+
+  //---------------
+  // Recadre en U.
+  //---------------
+  if (S->IsUPeriodic()) {
+    Standard_Real period  = S->UPeriod();
+    Standard_Real eps     = period*1.e-6;
+    Standard_Real minC    = Min(Pf.X(),Pl.X()); minC = Min(minC,Pm.X());
+    Standard_Real maxC    = Max(Pf.X(),Pl.X()); maxC = Max(maxC,Pm.X());
+    Standard_Real du = 0.;
+    if (minC< umin - eps) {
+      du = (int((umin - minC)/period) + 1)*period;
+    }
+    if (minC > umax + eps) {
+      du = -(int((minC - umax)/period) + 1)*period;
+    }
+    if (du != 0) {
+      gp_Vec2d T1(du,0.);
+      C2d->Translate(T1);
+      minC += du; maxC += du;
+    }
+    // Ajuste au mieux la courbe dans le domaine.
+    if (maxC > umax +100*eps) {
+      Standard_Real d1 = maxC - umax;
+      Standard_Real d2 = umin - minC + period;
+      if (d2 < d1) du =-period;
+      if ( du != 0.) {
+	gp_Vec2d T2(du,0.);
+	C2d->Translate(T2);
+      }
+    }
+  }
+  //------------------
+  // Recadre en V.
+  //------------------
+  if (S->IsVPeriodic()) {
+    Standard_Real period  = S->VPeriod();
+    Standard_Real eps     = period*1.e-6;
+    Standard_Real minC    = Min(Pf.Y(),Pl.Y()); minC = Min(minC,Pm.Y());
+    Standard_Real maxC    = Max(Pf.Y(),Pl.Y()); maxC = Max(maxC,Pm.Y());
+    Standard_Real dv = 0.;
+    if (minC< vmin - eps) {
+      dv = (int((vmin - minC)/period) + 1)*period;
+    }
+    if (minC > vmax + eps) {
+      dv = -(int((minC - vmax)/period) + 1)*period;
+    }
+    if (dv != 0) {
+      gp_Vec2d T1(0.,dv);
+      C2d->Translate(T1);
+      minC += dv; maxC += dv;
+    }
+    // Ajuste au mieux la courbe dans le domaine.
+    if (maxC > vmax +100*eps) {
+      Standard_Real d1 = maxC - vmax;
+      Standard_Real d2 = vmin - minC + period;
+      if (d2 < d1) dv =-period;
+      if ( dv != 0.) {
+	gp_Vec2d T2(0.,dv);
+	C2d->Translate(T2);
+      }
+    }
+  }
+}
+
+//=======================================================================
+//function : Inter3D
+//purpose  : 
+//=======================================================================
+
+void Partition_Inter3d::Inter3D(const TopoDS_Face& F1,
+				const TopoDS_Face& F2,
+				TopTools_ListOfShape& L)
+{
+  BRep_Builder B;
+  
+  // fill the data Structure
+  Handle(TopOpeBRepDS_HDataStructure) DatStr = new TopOpeBRepDS_HDataStructure();
+  TopOpeBRep_DSFiller DSFiller;
+  DSFiller.Insert(F1,F2,DatStr);
+
+  // define the GeomTool used by the DSFiller :
+  // compute BSpline of degree 1 on intersection curves.
+  Standard_Real tol3dAPPROX = 1e-7;
+  Standard_Real tol2dAPPROX = 1e-7;
+  TopOpeBRepTool_GeomTool GT2 (TopOpeBRepTool_APPROX);  
+  GT2.SetTolerances(tol3dAPPROX,tol2dAPPROX);
+  TopOpeBRepDS_BuildTool  BT(GT2);
+
+  // Perform Section
+  TopOpeBRepBuild_Builder TopB(BT);
+  TopB.Perform(DatStr);
+
+  // ===============
+  // Store new edges
+  // ===============
+  
+  L.Clear();
+  TopOpeBRepDS_CurveExplorer cex(DatStr->DS());
+  for (; cex.More(); cex.Next()) {
+    const TopOpeBRepDS_Curve& CDS = cex.Curve();
+    Standard_Integer ic = cex.Index();
+    Handle(Geom2d_Curve) pc1 = CDS.Curve1();
+    Handle(Geom2d_Curve) pc2 = CDS.Curve2();
+    
+    TopTools_ListIteratorOfListOfShape itLE = TopB.NewEdges(ic);
+    while (itLE.More()) {
+      TopoDS_Edge E = TopoDS::Edge(itLE.Value());
+      
+      PutInBounds (F1,E,pc1);
+      PutInBounds (F2,E,pc2);
+      
+      B.UpdateEdge (E,pc1,F1,0.);
+      B.UpdateEdge (E,pc2,F2,0.);
+      
+      L.Append (E);
+      
+      itLE.Next();
+      if (itLE.More()) {
+	pc1 = Handle(Geom2d_Curve)::DownCast(pc1->Copy());
+	pc2 = Handle(Geom2d_Curve)::DownCast(pc2->Copy());
+      }
+    }
+  }
+
+  // ========================
+  // store same domain faces 
+  // ========================
+
+
+  if ( DatStr->HasSameDomain( F1 ))
+  {
+    TopTools_ListOfShape emptyList;
+    if (!mySameDomainFM.IsBound(F1))
+      mySameDomainFM.Bind(F1,emptyList);
+    if (!mySameDomainFM.IsBound(F2))
+      mySameDomainFM.Bind(F2,emptyList);
+    mySameDomainFM(F1).Append(F2);
+    mySameDomainFM(F2).Append(F1);
+  }
+
+  // ====================
+  // Store section edges
+  // ====================
+
+  const TopOpeBRepDS_DataStructure& DS = DatStr->DS();
+  Standard_Integer j,i,nse = DS.NbSectionEdges();
+  if (nse == 0) return;
+
+    
+  TopoDS_Vertex V, sdeV1, sdeV2;
+  TopTools_MapOfShape MV;
+  TopTools_ListOfShape LSE; // list of section edges
+  TopoDS_Face dummyF;
+  
+  for (i = 1; i <= nse; i++)
+  {
+    const TopoDS_Edge & se = DS.SectionEdge(i);
+    if (! TopB.IsSplit(se,TopAbs_ON))
+      continue;
+    LSE.Append( se );
+
+    // add vertices where section edges interferes with other
+    // edges as its descendant in myAsDes
+    
+    TopoDS_Edge sde, oe; // same domain, other edge
+    if (DatStr->HasSameDomain(se)) {
+      sde = TopoDS::Edge( DatStr->SameDomain(se).Value() );
+      TopExp::Vertices( sde, sdeV1, sdeV2);
+    }
+    TColStd_MapOfInteger MIV; // indices of added edges
+    TopOpeBRepDS_PointIterator itP (DS.ShapeInterferences( se ));
+    itP.SupportKind( TopOpeBRepDS_EDGE );
+    // loop on intersections of se
+    for (; itP.More(); itP.Next()) {
+      oe = TopoDS::Edge( DS.Shape( itP.Support()));
+      if (itP.IsVertex()) {
+        // there is a vertex at intersection
+	if ( !MIV.Add( itP.Current() ))
+	  continue;
+	V = TopoDS::Vertex( DS.Shape( itP.Current()));
+	if ( !sde.IsNull() && (V.IsSame(sdeV1) || V.IsSame(sdeV2)) )
+	  oe = sde;
+	V = ReplaceSameDomainV( V , oe );
+	V.Orientation( TopAbs_INTERNAL);
+	B.UpdateVertex( V, itP.Parameter(), se, 0.); // AddVonE() sets real U
+      }
+      else {
+        // create a new vertex at the intersection point
+	const TopOpeBRepDS_Point& DSP = DS.Point( itP.Current());
+	V = BRepLib_MakeVertex( DSP.Point() );
+	V.Orientation( TopAbs_INTERNAL);
+	B.UpdateVertex( V, itP.Parameter(), se, DSP.Tolerance());
+	// make V be on the other edge
+	TopOpeBRepDS_PointIterator itOP (DS.ShapeInterferences( oe ));
+	for (; itOP.More(); itOP.Next()) {
+	  const TopOpeBRepDS_Point& ODSP = DS.Point( itOP.Current());
+	  if ( DSP.IsEqual (ODSP)) {
+	    B.UpdateVertex( V, itOP.Parameter(), TopoDS::Edge(oe), ODSP.Tolerance());
+	    break;
+	  }
+	}
+      }
+      // add V on the both intersecting edges
+      TopoDS_Vertex addedV = Partition_Inter2d::AddVonE( V,se,oe,myAsDes,dummyF);
+      if (!addedV.IsSame( V ))
+	mySameDomainVM.Bind (V, addedV); // equal vertex is already there
+
+      MV.Add( addedV ); // to ease storage of vertices of ON splits
+    }
+  }
+
+  // add section edge to the face it intersects and find
+  // splits ON that do not have same domain pair
+  
+  TopB.SplitSectionEdges(); // let TopB find ON splits
+
+  TopTools_MapOfShape SPM; // map of ON splits
+  TopTools_IndexedMapOfShape ME[2];
+  TopExp::MapShapes( F1, TopAbs_EDGE, ME[1]);
+  TopExp::MapShapes( F2, TopAbs_EDGE, ME[0]);
+
+  TopTools_ListIteratorOfListOfShape itSP, itLSE (LSE);
+  while ( itLSE.More() ) {
+
+    TopoDS_Edge se = TopoDS::Edge( itLSE.Value() );
+
+    // move itLSE to the next se
+    Standard_Integer ancRank = DS.AncestorRank(se);
+    if (ME[ancRank-1].Contains( se ))
+    {
+      LSE.Remove( itLSE ); // se is an edge of face it intersects
+      continue;
+    }
+    else
+    {
+      itLSE.Next();
+    }
+
+    const TopoDS_Face& F = (ancRank == 1) ? F2 : F1;
+
+    // add se to face but dont add twice
+    TopTools_ListIteratorOfListOfShape itE( myAsDes->Descendant( F ));
+    if (myAsDes->HasDescendant( F )) {
+      for ( ; itE.More(); itE.Next())
+	if (se.IsSame( itE.Value() ))
+	  break;
+    }
+    if (!itE.More())
+    {
+      myAsDes->Add( F, se );
+
+      // check se pcurve on F
+      Standard_Real tol, f,l, umin=1e100, umax=-1e100;
+      Handle(Geom2d_Curve) pc = BRep_Tool::CurveOnSurface( se, F, f,l);
+      if (pc.IsNull()) {
+	itSP.Initialize( TopB.Splits(se,TopAbs_ON) );
+	for ( ; itSP.More(); itSP.Next()) {
+	  const TopoDS_Edge& E = TopoDS::Edge ( itSP.Value());
+	  BRep_Tool::Range(E, f, l);
+	  umin = Min( umin, f);
+	  umax = Max( umax, l);
+	}
+	Handle(Geom_Curve) C3d = BRep_Tool::Curve( se, f, l);
+	if (umin < umax) // sometimes umin == umax for closed edge
+	  C3d = new Geom_TrimmedCurve( C3d, umin, umax);
+	pc = TopOpeBRepTool_CurveTool::MakePCurveOnFace (F,C3d,tol);
+	if (pc.IsNull()) {
+	  MESSAGE (" CANT BUILD PCURVE ");
+	}
+	B.UpdateEdge( se, pc, F, tol);
+      }
+    }
+
+    // to detect splits that do not have same domain pair
+    // ie which split a face into parts and not pass by its boundary
+    itSP.Initialize( TopB.Splits(se,TopAbs_ON) );
+    for ( ; itSP.More(); itSP.Next()) {
+      const TopoDS_Shape& SP = itSP.Value();
+      if (!SPM.Add( SP ))
+	SPM.Remove( SP );
+    }
+  }
+
+  // store vertices of ON splits and bind section edges to faces
+  
+  for (itLSE.Initialize (LSE); itLSE.More(); itLSE.Next())
+  {
+    const TopoDS_Shape& se = itLSE.Value();
+
+    Standard_Integer ancRank = DS.AncestorRank(se);
+    TopoDS_Face F = (ancRank == 1) ? F2 : F1;
+
+    // add vertices of ON splits which have no same domain pair
+    Standard_Boolean added = Standard_False;
+    itSP.Initialize( TopB.Splits(se,TopAbs_ON) );
+    for ( ; itSP.More(); itSP.Next())
+    {
+      if (!SPM.Contains( itSP.Value() ))
+	continue;
+      
+      const TopoDS_Edge& S = TopoDS::Edge ( itSP.Value());
+
+      added = Standard_True;
+      mySectionEdgesAD->Add( F, se );
+      
+      TopoDS_Vertex VS[2];
+      TopExp::Vertices (S, VS[0], VS[1]);
+      for (j=0; j<2; ++j)
+      {
+	if (mySameDomainVM.IsBound( VS[j] ))
+	  VS[j] = TopoDS::Vertex( mySameDomainVM( VS[j] ));
+	if ( !MV.Contains( VS[j] )) {
+	  // find equal vertex on se - point interference
+	  gp_Pnt P1 = BRep_Tool::Pnt( VS[j] );
+	  TopTools_ListIteratorOfListOfShape itV( myAsDes->Descendant(se) );
+	  for (; itV.More(); itV.Next()) {
+	    V = TopoDS::Vertex( itV.Value() );
+            if ( V.IsSame( VS[j] ))
+              break;
+	    gp_Pnt P2 = BRep_Tool::Pnt( V );
+	    if (P1.IsEqual( P2, Precision::Confusion())) {
+	      mySameDomainVM.Bind (VS[j], V);
+	      VS[j] = V;
+	      break;
+	    }
+	  }
+	  if (!itV.More())  // no interferences with edges
+	    myAsDes->Add( se, VS[j]);
+	}
+
+        // add ends of ON splits to F in order to detect later
+        // if a split is on face in IsSplitOn()
+	mySectionEdgesAD->Add( F, VS[j]);
+      }
+      // in the descendants of F, first go ends of an ON split and
+      // then a split itself
+      mySectionEdgesAD->Add( F, S );
+    }
+    if (!added)
+      mySectionEdgesAD->Add( F, se );
+    
+    myNewEdges.Add( se );
+  }
+}
+
+//=======================================================================
+//function : FacesPartition
+//purpose  : 
+//=======================================================================
+
+void Partition_Inter3d::FacesPartition(const TopoDS_Face& F1,
+				       const TopoDS_Face& F2)
+     //(const TopTools_DataMapOfShapeListOfShape& /*SetOfFaces2*/)
+{
+  TopTools_ListOfShape LInt;
+
+  Inter3D (F1,F2,LInt);
+  
+  StorePart3d (F1,F2,LInt);
+}
+
+//=======================================================================
+//function : SetDone
+//purpose  : 
+//=======================================================================
+
+void Partition_Inter3d::SetDone(const TopoDS_Face& F1, 
+				const TopoDS_Face& F2)
+{
+  if (!myDone.IsBound(F1)) {
+    TopTools_ListOfShape emptyList;
+    myDone.Bind(F1,emptyList);
+  }
+  myDone(F1).Append(F2);
+  if (!myDone.IsBound(F2)) {
+    TopTools_ListOfShape emptyList;
+    myDone.Bind(F2,emptyList);
+  }
+  myDone(F2).Append(F1);
+}
+
+//=======================================================================
+//function : IsDone
+//purpose  : 
+//=======================================================================
+
+Standard_Boolean Partition_Inter3d::IsDone(const TopoDS_Face& F1, 
+					   const TopoDS_Face& F2) 
+
+  const 
+{
+  if (myDone.IsBound(F1)) {
+    TopTools_ListIteratorOfListOfShape it (myDone(F1));
+    for (; it.More(); it.Next()) {
+      if (it.Value().IsSame(F2)) return Standard_True;
+    }
+  }
+  return Standard_False;
+}
+
+//=======================================================================
+//function : StorePart3d
+//purpose  : 
+//=======================================================================
+
+void Partition_Inter3d::StorePart3d(const TopoDS_Face& F1, 
+				    const TopoDS_Face& F2, 
+				    const TopTools_ListOfShape& LInt)
+{
+  if (!LInt.IsEmpty()) {
+    myAsDes->Add( F1,LInt);
+    myAsDes->Add( F2,LInt);
+
+    TopTools_ListIteratorOfListOfShape it(LInt);
+    for (; it.More(); it.Next()) {
+
+      TopoDS_Edge E = TopoDS::Edge(it.Value());
+
+      BRep_Builder B;
+      B.SameParameter(E,Standard_False);
+      BRepLib::SameParameter(E,1.0e-7);
+      
+      myNewEdges.Add(E);
+    }
+  }
+  SetDone(F1,F2);
+}
+
+//=======================================================================
+//function : TouchedFaces
+//purpose  : 
+//=======================================================================
+
+TopTools_MapOfShape& Partition_Inter3d::TouchedFaces()
+{
+  return myTouched;
+}
+
+//=======================================================================
+//function : AsDes
+//purpose  : 
+//=======================================================================
+
+Handle(BRepAlgo_AsDes) Partition_Inter3d::AsDes() const 
+{
+  return myAsDes;
+}
+
+//=======================================================================
+//function : NewEdges
+//purpose  : 
+//=======================================================================
+
+TopTools_MapOfShape& Partition_Inter3d::NewEdges() 
+{
+  return myNewEdges;
+}
+
+//=======================================================================
+//function : Affiche
+//purpose  : 
+//=======================================================================
+
+void Partition_Inter3d::Affiche(const TopTools_ListOfShape& SetOfFaces) const
+{
+#ifdef DEB
+  char PSection[1024];
+  char *section=PSection;
+  Standard_Integer i = 0;
+  Standard_Real j=1;
+  TopTools_ListOfShape aList;
+  TopTools_ListIteratorOfListOfShape it;
+  for (it.Initialize(SetOfFaces); it.More(); it.Next()) {
+    const TopoDS_Shape& OS = it.Value();
+    aList=myAsDes->Descendant(OS);
+    MESSAGE ( " the number of items stored in the list " << j << " :  " << aList.Extent() )
+    j++;
+    TopTools_ListIteratorOfListOfShape itaList;
+    for (itaList.Initialize(aList); itaList.More(); itaList.Next()) {
+      const TopoDS_Shape& SS = itaList.Value();
+      i++;
+      sprintf(PSection,"section_%d",i);
+      DBRep::Set(section,SS);  
+    }
+  }
+#endif
+}
+
+//=======================================================================
+//function : SameDomain
+//purpose  : 
+//=======================================================================
+
+const TopTools_ListOfShape& Partition_Inter3d::SameDomain(const TopoDS_Face& F) const
+{
+  if (mySameDomainFM.IsBound( F ))
+    return mySameDomainFM (F);
+
+  static TopTools_ListOfShape emptyList;
+  return emptyList;
+}
+
+//=======================================================================
+//function : HasSameDomainF
+//purpose  : Return true if F has same domain faces
+//=======================================================================
+
+Standard_Boolean Partition_Inter3d::HasSameDomainF(const TopoDS_Shape& F) const
+{
+  return mySameDomainFM.IsBound( F );
+}
+
+//=======================================================================
+//function : IsSameDomain
+//purpose  : Return true if F1 and F2 are same domain faces
+//=======================================================================
+
+Standard_Boolean Partition_Inter3d::IsSameDomainF(const TopoDS_Shape& F1,
+						 const TopoDS_Shape& F2) const
+{
+  if (mySameDomainFM.IsBound( F1 )) {
+    TopTools_ListIteratorOfListOfShape it (mySameDomainFM( F1 ));
+    for (; it.More(); it.Next()) 
+      if (F2.IsSame( it.Value()))
+	return Standard_True;
+  }
+  return F1.IsSame( F2 );
+}
+
+//=======================================================================
+//function : ReplaceSameDomainV
+//purpose  : return same domain vertex of  V if it was replaced
+//           and make this vertex to be on E too, else return V
+//=======================================================================
+
+TopoDS_Vertex Partition_Inter3d::ReplaceSameDomainV(const TopoDS_Vertex& V,
+						    const TopoDS_Edge&   E) const
+{
+  TopoDS_Vertex SDV = V;
+  if (mySameDomainVM.IsBound( V )) {
+
+    TopoDS_Vertex V1,V2;
+    TopExp::Vertices(E,V1,V2);
+    Standard_Boolean isClosed = V1.IsSame( V2 ) && V.IsSame(V1);
+
+    SDV = TopoDS::Vertex( mySameDomainVM(V) );
+    Standard_Real tol = BRep_Tool::Tolerance( V );
+    BRep_Builder B;
+    SDV.Orientation( V.Orientation());
+
+    if (isClosed) {
+      Standard_Real f, l;
+      BRep_Tool::Range (E, f, l);
+      Standard_Boolean isFirst = IsEqual( BRep_Tool::Parameter(V,E), f );
+      B.UpdateVertex(SDV, (isFirst ? f : l), E, tol);
+      SDV.Reverse();
+      B.UpdateVertex(SDV, (isFirst ? l : f), E, tol);
+    }
+    else
+      B.UpdateVertex (SDV, BRep_Tool::Parameter(V,E), E, tol);
+      
+  }
+  return SDV;
+}
+
+//=======================================================================
+//function : SectionEdgesAD
+//purpose  : 
+//=======================================================================
+
+Handle(BRepAlgo_AsDes) Partition_Inter3d::SectionEdgesAD() const
+{
+  return mySectionEdgesAD;
+}
+
+//=======================================================================
+//function : IsSectionEdge
+//purpose  : return True if  E  is  an  edge  of  a face and it
+//           intersects an other face
+//=======================================================================
+
+Standard_Boolean
+  Partition_Inter3d::IsSectionEdge(const TopoDS_Edge& E) const
+{
+  return mySectionEdgesAD->HasAscendant(E);
+}
+
+//=======================================================================
+//function : HasSectionEdge
+//purpose  : return True if an  edge  of  F intersects an other
+//           face or F is intersected by edge of an other face
+//=======================================================================
+
+Standard_Boolean
+  Partition_Inter3d::HasSectionEdge(const TopoDS_Face& F) const
+{
+  return mySectionEdgesAD->HasDescendant(F);
+}
+
+//=======================================================================
+//function : IsSplitOn
+//purpose  : return True if NewE is split of OldE on F
+//=======================================================================
+
+Standard_Boolean
+  Partition_Inter3d::IsSplitOn(const TopoDS_Edge& NewE,
+			       const TopoDS_Edge& OldE,
+			       const TopoDS_Face& F) const
+{
+  if (! mySectionEdgesAD->HasDescendant(F))
+    return Standard_False;
+
+  TopTools_ListIteratorOfListOfShape itE ( mySectionEdgesAD->Descendant(F) );
+  for ( ; itE.More(); itE.Next()) {
+    if ( itE.Value().ShapeType() != TopAbs_EDGE ||
+	! OldE.IsSame ( itE.Value() ))
+      continue;
+    // an edge encountered, its vertices and a split come next
+    itE.Next();
+    if (!itE.More()) break;
+    const TopoDS_Shape& V3 = itE.Value();
+    if (V3.ShapeType() != TopAbs_VERTEX) continue;
+    itE.Next();
+    if (!itE.More()) break;
+    const TopoDS_Shape& V4 = itE.Value();
+    if (V4.ShapeType() != TopAbs_VERTEX) continue;
+
+    TopoDS_Vertex V1, V2;
+    TopExp::Vertices( OldE, V1, V2);
+    
+    if ( V1.IsSame(V2) &&
+	(V1.IsSame(V3) || V1.IsSame(V4)) ) {
+      // closed old edge; use the split for the test 
+      itE.Next();
+      if (!itE.More()) break;
+      const TopoDS_Edge& split = TopoDS::Edge( itE.Value() );
+      // check distance at middle point of NewE
+      Standard_Real f1,l1, f2,l2;
+      Handle(Geom2d_Curve) PC1 = BRep_Tool::CurveOnSurface( split, F ,f1,l1);
+      if (!PC1.IsNull()) {
+	Handle(Geom2d_Curve) PC2 = BRep_Tool::CurveOnSurface(NewE, F ,f2,l2);
+	gp_Pnt2d P = PC2->Value( 0.5*(f2+l2) );
+	Geom2dAPI_ProjectPointOnCurve proj (P, PC1, f1, l1);
+	if (proj.NbPoints() &&
+	    proj.LowerDistance() <= Precision::Confusion())
+	  return Standard_True;
+      }
+      else {
+        Handle(Geom_Curve) C1 = BRep_Tool::Curve( split ,f1,l1);
+	Handle(Geom_Curve) C2 = BRep_Tool::Curve( NewE  ,f2,l2);
+	gp_Pnt P = C2->Value( 0.5*(f2+l2) );
+	GeomAPI_ProjectPointOnCurve proj (P, C1, f1, l1);
+	if (proj.NbPoints() &&
+	    proj.LowerDistance() <= Precision::Confusion())
+	  return Standard_True;
+      }
+    }
+    else {
+      Standard_Real u3 = BRep_Tool::Parameter( TopoDS::Vertex(V3), OldE);
+      Standard_Real u4 = BRep_Tool::Parameter( TopoDS::Vertex(V4), OldE);
+
+      Standard_Real f,l, u;
+      BRep_Tool::Range( NewE, f,l);
+      u = 0.5*(f+l);
+      f = Min(u3,u4);
+      l = Max(u3,u4);
+
+      if (u <= l && u >= f)
+        return Standard_True;
+    }
+  }
+  return Standard_False;
+}
+
+//=======================================================================
+//function : SectionEdgeFaces
+//purpose  : return faces cut by section edge
+//=======================================================================
+
+const TopTools_ListOfShape&
+  Partition_Inter3d::SectionEdgeFaces(const TopoDS_Edge& SecE) const
+{
+  return mySectionEdgesAD->Ascendant( SecE );
+}
+
+#endif
diff --git a/contrib/Netgen/libsrc/occ/Partition_Inter3d.hxx b/contrib/Netgen/libsrc/occ/Partition_Inter3d.hxx
new file mode 100644
index 0000000000..d8be2c5983
--- /dev/null
+++ b/contrib/Netgen/libsrc/occ/Partition_Inter3d.hxx
@@ -0,0 +1,143 @@
+//  GEOM PARTITION : partition algorithm
+//
+//  Copyright (C) 2003  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
+//  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS 
+// 
+//  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. 
+// 
+//  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 
+// 
+//  See http://www.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org 
+//
+//
+//
+//  File   : Partition_Inter3d.hxx
+//  Module : GEOM
+
+#ifndef _Partition_Inter3d_HeaderFile
+#define _Partition_Inter3d_HeaderFile
+
+#ifndef _Handle_BRepAlgo_AsDes_HeaderFile
+#include <Handle_BRepAlgo_AsDes.hxx>
+#endif
+#ifndef _TopTools_DataMapOfShapeListOfShape_HeaderFile
+#include <TopTools_DataMapOfShapeListOfShape.hxx>
+#endif
+#ifndef _TopTools_MapOfShape_HeaderFile
+#include <TopTools_MapOfShape.hxx>
+#endif
+#ifndef _TopTools_DataMapOfShapeShape_HeaderFile
+#include <TopTools_DataMapOfShapeShape.hxx>
+#endif
+#ifndef _Standard_Boolean_HeaderFile
+#include <Standard_Boolean.hxx>
+#endif
+class BRepAlgo_AsDes;
+class TopTools_ListOfShape;
+class TopTools_DataMapOfShapeShape;
+class TopoDS_Face;
+class TopTools_MapOfShape;
+class TopoDS_Shape;
+class TopoDS_Vertex;
+class TopoDS_Edge;
+
+
+#ifndef _Standard_HeaderFile
+#include <Standard.hxx>
+#endif
+#ifndef _Standard_Macro_HeaderFile
+#include <Standard_Macro.hxx>
+#endif
+
+class Partition_Inter3d  {
+
+public:
+
+   void* operator new(size_t,void* anAddress) 
+   {
+      return anAddress;
+   }
+   void* operator new(size_t size) 
+   { 
+      return Standard::Allocate(size); 
+   }
+   void  operator delete(void *anAddress) 
+   { 
+      if (anAddress) Standard::Free((Standard_Address&)anAddress); 
+   }
+   // Methods PUBLIC
+   // 
+   Partition_Inter3d();
+   Partition_Inter3d(const Handle(BRepAlgo_AsDes)& AsDes);
+   void CompletPart3d(const TopTools_ListOfShape& SetOfFaces1,const TopTools_DataMapOfShapeShape& FaceShapeMap) ;
+   void FacesPartition(const TopoDS_Face& F1,const TopoDS_Face& F2) ;
+   Standard_Boolean IsDone(const TopoDS_Face& F1,const TopoDS_Face& F2) const;
+   TopTools_MapOfShape& TouchedFaces() ;
+   Handle_BRepAlgo_AsDes AsDes() const;
+   TopTools_MapOfShape& NewEdges() ;
+   Standard_Boolean HasSameDomainF(const TopoDS_Shape& F) const;
+   Standard_Boolean IsSameDomainF(const TopoDS_Shape& F1,const TopoDS_Shape& F2) const;
+   const TopTools_ListOfShape& SameDomain(const TopoDS_Face& F) const;
+   TopoDS_Vertex ReplaceSameDomainV(const TopoDS_Vertex& V,const TopoDS_Edge& E) const;
+   Handle_BRepAlgo_AsDes SectionEdgesAD() const;
+   Standard_Boolean IsSectionEdge(const TopoDS_Edge& E) const;
+   Standard_Boolean HasSectionEdge(const TopoDS_Face& F) const;
+   Standard_Boolean IsSplitOn(const TopoDS_Edge& NewE,const TopoDS_Edge& OldE,const TopoDS_Face& F) const;
+   const TopTools_ListOfShape& SectionEdgeFaces(const TopoDS_Edge& SecE) const;
+
+
+
+
+
+protected:
+
+   // Methods PROTECTED
+   // 
+
+
+   // Fields PROTECTED
+   //
+
+
+private: 
+
+   // Methods PRIVATE
+   // 
+   void Inter3D(const TopoDS_Face& F1,const TopoDS_Face& F2,TopTools_ListOfShape& LInt) ;
+   void StorePart3d(const TopoDS_Face& F1,const TopoDS_Face& F2,const TopTools_ListOfShape& LInt1) ;
+   void SetDone(const TopoDS_Face& F1,const TopoDS_Face& F2) ;
+   void Affiche(const TopTools_ListOfShape& SetOfFaces) const;
+
+
+   // Fields PRIVATE
+   //
+   Handle_BRepAlgo_AsDes myAsDes;
+   TopTools_DataMapOfShapeListOfShape myDone;
+   TopTools_MapOfShape myTouched;
+   TopTools_MapOfShape myNewEdges;
+   Handle_BRepAlgo_AsDes mySectionEdgesAD;
+   TopTools_DataMapOfShapeListOfShape mySameDomainFM;
+   TopTools_DataMapOfShapeShape mySameDomainVM;
+
+
+};
+
+
+
+
+
+// other Inline functions and methods (like "C++: function call" methods)
+//
+
+
+#endif
diff --git a/contrib/Netgen/libsrc/occ/Partition_Inter3d.ixx b/contrib/Netgen/libsrc/occ/Partition_Inter3d.ixx
new file mode 100644
index 0000000000..0775cc99c9
--- /dev/null
+++ b/contrib/Netgen/libsrc/occ/Partition_Inter3d.ixx
@@ -0,0 +1,31 @@
+//  GEOM PARTITION : partition algorithm
+//
+//  Copyright (C) 2003  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
+//  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS 
+// 
+//  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. 
+// 
+//  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 
+// 
+//  See http://www.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org 
+//
+//
+//
+//  File   : Partition_Inter3d.ixx
+//  Module : GEOM
+
+#include "Partition_Inter3d.jxx"
+
+ 
+
+
diff --git a/contrib/Netgen/libsrc/occ/Partition_Inter3d.jxx b/contrib/Netgen/libsrc/occ/Partition_Inter3d.jxx
new file mode 100644
index 0000000000..5804ba81e8
--- /dev/null
+++ b/contrib/Netgen/libsrc/occ/Partition_Inter3d.jxx
@@ -0,0 +1,53 @@
+//  GEOM PARTITION : partition algorithm
+//
+//  Copyright (C) 2003  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
+//  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS 
+// 
+//  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. 
+// 
+//  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 
+// 
+//  See http://www.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org 
+//
+//
+//
+//  File   : Partition_Inter3d.jxx
+//  Module : GEOM
+
+#ifndef _BRepAlgo_AsDes_HeaderFile
+#include <BRepAlgo_AsDes.hxx>
+#endif
+#ifndef _TopTools_ListOfShape_HeaderFile
+#include <TopTools_ListOfShape.hxx>
+#endif
+#ifndef _TopTools_DataMapOfShapeShape_HeaderFile
+#include <TopTools_DataMapOfShapeShape.hxx>
+#endif
+#ifndef _TopoDS_Face_HeaderFile
+#include <TopoDS_Face.hxx>
+#endif
+#ifndef _TopTools_MapOfShape_HeaderFile
+#include <TopTools_MapOfShape.hxx>
+#endif
+#ifndef _TopoDS_Shape_HeaderFile
+#include <TopoDS_Shape.hxx>
+#endif
+#ifndef _TopoDS_Vertex_HeaderFile
+#include <TopoDS_Vertex.hxx>
+#endif
+#ifndef _TopoDS_Edge_HeaderFile
+#include <TopoDS_Edge.hxx>
+#endif
+#ifndef _Partition_Inter3d_HeaderFile
+#include "Partition_Inter3d.hxx"
+#endif
diff --git a/contrib/Netgen/libsrc/occ/Partition_Loop.cxx b/contrib/Netgen/libsrc/occ/Partition_Loop.cxx
new file mode 100644
index 0000000000..0511bfd2eb
--- /dev/null
+++ b/contrib/Netgen/libsrc/occ/Partition_Loop.cxx
@@ -0,0 +1,473 @@
+#ifdef OCCGEOMETRY
+
+//  GEOM PARTITION : partition algorithm
+//
+//  Copyright (C) 2003  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
+//  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS 
+// 
+//  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. 
+// 
+//  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 
+// 
+//  See http://www.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org 
+//
+//
+//
+//  File   : Partition_Loop.cxx
+//  Author : Benedicte MARTIN
+//  Module : GEOM
+//  $Header: /cvs/netgen/netgen/libsrc/occ/Partition_Loop.cxx,v 1.6 2008/03/31 14:20:28 wabro Exp $
+
+//using namespace std;
+#include <cstdio>
+#include <climits>
+
+#include "Partition_Loop.ixx"
+
+#include "utilities.h"
+
+#include <BRep_Builder.hxx>
+#include <BRepAlgo_FaceRestrictor.hxx>
+#include <BRep_Tool.hxx>
+
+#include <Geom2d_Curve.hxx>
+#include <Geom_Surface.hxx>
+
+#include <TopTools_SequenceOfShape.hxx>
+#include <TopTools_ListIteratorOfListOfShape.hxx>
+#include <TopTools_MapOfShape.hxx>
+#include <TopTools_MapIteratorOfMapOfShape.hxx>
+#include <TopTools_MapOfOrientedShape.hxx>
+#include <TopTools_DataMapOfShapeShape.hxx>
+#include <TopTools_DataMapIteratorOfDataMapOfShapeListOfShape.hxx>
+
+#include <gp_Pnt.hxx>
+#include <gp_Pnt2d.hxx>
+
+#include <TopoDS.hxx>
+#include <TopoDS_Vertex.hxx>
+#include <TopoDS_Wire.hxx>
+#include <TopoDS_Iterator.hxx>
+
+#include <Precision.hxx>
+#include <BRep_TVertex.hxx>
+#include <BRep_TEdge.hxx>
+
+#include <TopExp.hxx>
+#include <TopExp_Explorer.hxx>
+
+static char* name = new char[100];
+static int nbe = 0;
+
+//=======================================================================
+//function : Partition_Loop
+//purpose  : 
+//=======================================================================
+Partition_Loop::Partition_Loop()
+{
+}
+
+//=======================================================================
+//function : Init
+//purpose  : 
+//=======================================================================
+void Partition_Loop::Init(const TopoDS_Face& F)
+{
+  myConstEdges.Clear(); 
+  myNewWires  .Clear();
+  myNewFaces  .Clear();
+  myFace = F;
+}
+
+//=======================================================================
+//function : AddConstEdge
+//purpose  : 
+//=======================================================================
+void Partition_Loop::AddConstEdge (const TopoDS_Edge& E)
+{
+  myConstEdges.Append(E);
+}
+
+
+//=======================================================================
+//function : FindDelta
+//purpose  : 
+//=======================================================================
+static Standard_Real FindDelta(TopTools_ListOfShape& LE,
+			       const TopoDS_Face& F)
+{
+  Standard_Real dist, f, l;
+  Standard_Real d = Precision::Infinite();
+  TopTools_ListIteratorOfListOfShape itl;
+
+  for ( itl.Initialize(LE); itl.More(); itl.Next()) {
+    const TopoDS_Edge& E = TopoDS::Edge(itl.Value());
+    Handle(Geom2d_Curve) C = BRep_Tool::CurveOnSurface(E,F,f,l);
+    gp_Pnt2d p = C->Value(f);
+    gp_Pnt2d pp = C->Value(l);
+    Standard_Real d1 = p.Distance(pp);
+    if (d1<d) { d=d1;}
+  }
+  dist = d ;
+  return dist;
+}
+
+//=======================================================================
+//function : SelectEdge
+//purpose  : Find the edge <NE> connected <CE> by the vertex <CV> in the list <LE>.
+//           <NE> Is erased  of the list. If <CE> is too in the list <LE> 
+//			 with the same orientation, it's erased of the list 
+//=======================================================================
+static Standard_Boolean  SelectEdge(const TopoDS_Face&    F,
+				    const TopoDS_Edge&    CE,
+				    const TopoDS_Vertex&  CV,
+				    TopoDS_Edge&          NE,
+				    TopTools_ListOfShape& LE)
+{
+  TopTools_ListIteratorOfListOfShape itl;
+  NE.Nullify();
+  for ( itl.Initialize(LE); itl.More(); itl.Next()) {
+    if (itl.Value().IsEqual(CE)) {
+      LE.Remove(itl);
+      break;
+    }
+  }
+
+  if (LE.Extent() > 1) {
+    //--------------------------------------------------------------
+    // Several possible edges.   
+    // - Test the edges differents of CE 
+    //--------------------------------------------------------------
+    Standard_Real   cf, cl, f, l;
+    TopoDS_Face FForward = F;
+    Handle(Geom2d_Curve) Cc, C;
+    FForward.Orientation(TopAbs_FORWARD);
+			
+    Cc = BRep_Tool::CurveOnSurface(CE,FForward,cf,cl);
+    Standard_Real dist,distmin  = 100*BRep_Tool::Tolerance(CV);
+    Standard_Real uc,u;
+    if (CE.Orientation () == TopAbs_FORWARD) uc = cl;
+    else                                     uc = cf;
+
+    gp_Pnt2d P2,PV = Cc->Value(uc); 
+
+    Standard_Real delta = FindDelta(LE,FForward);
+
+    for ( itl.Initialize(LE); itl.More(); itl.Next()) {
+      const TopoDS_Edge& E = TopoDS::Edge(itl.Value());
+      if (!E.IsSame(CE)) {
+	C = BRep_Tool::CurveOnSurface(E,FForward,f,l);
+	if (E.Orientation () == TopAbs_FORWARD) u = f;
+	else                                    u = l;
+	P2 = C->Value(u);
+	dist = PV.Distance(P2);
+	if (dist <= distmin){
+	  distmin = dist;
+	}
+				
+      }
+    }
+
+    Standard_Real anglemax = - PI;
+    TopoDS_Edge   SelectedEdge;	
+    for ( itl.Initialize(LE); itl.More(); itl.Next()) {
+      const TopoDS_Edge& E = TopoDS::Edge(itl.Value());
+      if (!E.IsSame(CE)) {
+	C = BRep_Tool::CurveOnSurface(E,FForward,f,l);
+	if (E.Orientation () == TopAbs_FORWARD) u = f;
+	else                                    u = l;
+	P2 = C->Value(u);
+	dist = PV.Distance(P2);
+	if (dist <= distmin + (1./3)*delta){ 
+	  gp_Pnt2d PC, P;
+	  gp_Vec2d CTg1, CTg2, Tg1, Tg2;
+	  Cc->D2(uc, PC, CTg1, CTg2);
+	  C->D2(u, P, Tg1, Tg2);
+
+	  Standard_Real angle;
+
+	  if (CE.Orientation () == TopAbs_REVERSED && E.Orientation () == TopAbs_FORWARD) {
+	    angle = CTg1.Angle(Tg1.Reversed());
+	  }
+	  else if (CE.Orientation () == TopAbs_FORWARD && E.Orientation () == TopAbs_REVERSED) {
+	    angle = (CTg1.Reversed()).Angle(Tg1);
+	  }
+	  else if (CE.Orientation () == TopAbs_REVERSED && E.Orientation () == TopAbs_REVERSED) {
+	    angle = CTg1.Angle(Tg1);
+	  }
+	  else if (CE.Orientation () == TopAbs_FORWARD && E.Orientation () == TopAbs_FORWARD) {
+	    angle = (CTg1.Reversed()).Angle(Tg1.Reversed());
+	  }
+	  if (angle >= anglemax) {
+	    anglemax = angle ;
+	    SelectedEdge = E;	
+	  }
+	}
+      }
+    }
+    for ( itl.Initialize(LE); itl.More(); itl.Next()) {
+      const TopoDS_Edge& E = TopoDS::Edge(itl.Value());
+      if (E.IsEqual(SelectedEdge)) {
+	NE = TopoDS::Edge(E);
+	LE.Remove(itl);
+	break;
+      }
+    }					
+  }
+  else if (LE.Extent() == 1) {
+    NE = TopoDS::Edge(LE.First());
+    LE.RemoveFirst();
+  }
+  else {
+    return Standard_False;
+  }
+  return Standard_True;
+}
+
+//=======================================================================
+//function : SamePnt2d
+//purpose  : 
+//=======================================================================
+static Standard_Boolean  SamePnt2d(TopoDS_Vertex  V,
+				   TopoDS_Edge&   E1,
+				   TopoDS_Edge&   E2,
+				   TopoDS_Face&   F)
+{
+  Standard_Real   f1,f2,l1,l2;
+  gp_Pnt2d        P1,P2;
+  TopoDS_Shape aLocalF = F.Oriented(TopAbs_FORWARD);
+  TopoDS_Face FF = TopoDS::Face(aLocalF);
+  Handle(Geom2d_Curve) C1 = BRep_Tool::CurveOnSurface(E1,FF,f1,l1);  
+  Handle(Geom2d_Curve) C2 = BRep_Tool::CurveOnSurface(E2,FF,f2,l2);  
+  if (E1.Orientation () == TopAbs_FORWARD) P1 = C1->Value(f1);
+  else                                     P1 = C1->Value(l1);
+  
+  if (E2.Orientation () == TopAbs_FORWARD) P2 = C2->Value(l2);
+  else                                     P2 = C2->Value(f2);
+  Standard_Real Tol  = 100*BRep_Tool::Tolerance(V);
+  Standard_Real Dist = P1.Distance(P2);
+  return Dist < Tol; 
+}
+
+//=======================================================================
+//function : PurgeNewEdges
+//purpose  : 
+//=======================================================================
+static void  PurgeNewEdges(TopTools_ListOfShape& ConstEdges,
+			   const TopTools_MapOfOrientedShape&          UsedEdges)
+{
+  TopTools_ListIteratorOfListOfShape it(ConstEdges);
+  while ( it.More()) {
+    const TopoDS_Shape& NE = it.Value();
+    if (!UsedEdges.Contains(NE)) {
+      ConstEdges.Remove(it);
+    }
+    else {
+      it.Next();
+    }
+  }  
+}
+
+//=======================================================================
+//function : StoreInMVE
+//purpose  : 
+//=======================================================================
+static void StoreInMVE (const TopoDS_Face& F,
+			TopoDS_Edge& E,
+			TopTools_DataMapOfShapeListOfShape& MVE )
+
+{ 
+  TopoDS_Vertex V1, V2;
+  TopTools_ListOfShape Empty;
+
+  TopExp::Vertices(E,V1,V2);
+  if (!MVE.IsBound(V1)) {
+    MVE.Bind(V1,Empty);
+  }
+  MVE(V1).Append(E);
+	
+  if (!MVE.IsBound(V2)) {
+    MVE.Bind(V2,Empty);
+  }
+  MVE(V2).Append(E);
+}
+
+//=======================================================================
+//function : Perform
+//purpose  : 
+//=======================================================================
+void Partition_Loop::Perform()
+{
+
+  TopTools_DataMapOfShapeListOfShape MVE;
+  TopTools_DataMapIteratorOfDataMapOfShapeListOfShape Mapit, Mapit1;  
+  TopTools_ListIteratorOfListOfShape                  itl;
+  TopoDS_Vertex                                       V1,V2;
+
+  //-----------------------------------
+  // Construction map vertex => edges
+  //-----------------------------------
+  for (itl.Initialize(myConstEdges); itl.More(); itl.Next()) {
+    TopoDS_Edge& E = TopoDS::Edge(itl.Value());
+    StoreInMVE(myFace,E,MVE);
+  }
+
+  //----------------------------------------------
+  // Construction of all the wires and of all the new faces. 
+  //----------------------------------------------
+  TopTools_MapOfOrientedShape UsedEdges;
+
+  while (!MVE.IsEmpty()) {
+    TopoDS_Vertex    VF,CV;
+    TopoDS_Edge      CE,NE,EF;
+    TopoDS_Wire      NW;
+    BRep_Builder     B;
+    Standard_Boolean End= Standard_False;
+
+    B.MakeWire(NW);
+    //--------------------------------
+    // EF first edge.
+    //--------------------------------
+    Mapit.Initialize(MVE);
+    EF = CE = TopoDS::Edge(Mapit.Value().First());
+
+    TopExp::Vertices(CE,V1,V2);
+    //--------------------------------
+    // VF first vertex 
+    //--------------------------------
+    if (CE.Orientation() == TopAbs_FORWARD) { 
+      CV = VF = V1;
+    }
+    else  { 
+      CV = VF = V2;
+    }
+    if (!MVE.IsBound(CV)) continue;
+    for ( itl.Initialize(MVE(CV)); itl.More(); itl.Next()) {
+      if (itl.Value().IsEqual(CE)) {
+	MVE(CV).Remove(itl);
+	break;
+      }
+    }
+
+    int i = 0;
+    while (!End) { 
+      //-------------------------------
+      // Construction of a wire.
+      //-------------------------------
+      TopExp::Vertices(CE,V1,V2);
+      if (!CV.IsSame(V1)) CV = V1; else CV = V2; 
+      B.Add (NW,CE);
+      UsedEdges.Add(CE);
+
+      //--------------
+      // stop test
+      //--------------			
+      if (!MVE.IsBound(CV) || MVE(CV).IsEmpty() || CV.IsSame(VF) ) {
+	if (CV.IsSame(VF)) {
+	  if (MVE(CV).Extent() == 1 ) MVE.UnBind(CV);
+	  else {
+	    for ( itl.Initialize(MVE(CV)); itl.More(); itl.Next()) {
+	      if (itl.Value().IsEqual(CE)) {
+		MVE(CV).Remove(itl);
+		break;
+	      }
+	    }
+	  }
+	}
+	End=Standard_True;
+      } 
+
+      //--------------
+      // select edge
+      //--------------
+      else {
+	Standard_Boolean find = SelectEdge(myFace,CE,CV,NE,MVE(CV));
+	if (find) {
+	  CE=NE;
+	  if (MVE(CV).IsEmpty()) MVE.UnBind(CV);
+	  if (CE.IsNull() ) {
+	    MESSAGE ( " CE is  NULL !!! " )
+	    End=Standard_True;
+	  }
+	}
+	else {
+	  MESSAGE ( " edge doesn't exist " )
+	  End=Standard_True;
+	}
+      }
+    }
+
+    //-----------------------------
+    // Test if the wire is closed  
+    //-----------------------------
+    if (VF.IsSame(CV) && SamePnt2d(VF,EF,CE,myFace)) {
+    }
+    else{
+      MESSAGE ( "wire not closed" )
+    }
+    myNewWires.Append (NW);			
+  }
+
+  PurgeNewEdges(myConstEdges,UsedEdges);
+
+}
+
+
+//=======================================================================
+//function : NewWires
+//purpose  : 
+//=======================================================================
+const TopTools_ListOfShape&  Partition_Loop::NewWires() const 
+{  
+  return myNewWires;
+}
+
+//=======================================================================
+//function : NewFaces
+//purpose  : 
+//=======================================================================
+const TopTools_ListOfShape&  Partition_Loop::NewFaces() const 
+{  
+  return myNewFaces;
+}
+ 
+//=======================================================================
+//function : WiresToFaces
+//purpose  : 
+//=======================================================================
+void  Partition_Loop::WiresToFaces() 
+{  
+  if (!myNewWires.IsEmpty()) {
+    BRepAlgo_FaceRestrictor FR;
+
+    TopAbs_Orientation OriF = myFace.Orientation();
+    TopoDS_Shape aLocalS = myFace.Oriented(TopAbs_FORWARD);
+
+    FR.Init (TopoDS::Face(aLocalS),Standard_False);
+    TopTools_ListIteratorOfListOfShape it(myNewWires);
+    for (; it.More(); it.Next()) {
+      FR.Add(TopoDS::Wire(it.Value()));
+    }
+
+    FR.Perform();
+    
+    if (FR.IsDone()) {
+      for (; FR.More(); FR.Next()) {
+	myNewFaces.Append(FR.Current().Oriented(OriF));
+      }
+    }
+  }
+}
+
+
+#endif
diff --git a/contrib/Netgen/libsrc/occ/Partition_Loop.hxx b/contrib/Netgen/libsrc/occ/Partition_Loop.hxx
new file mode 100644
index 0000000000..56e05e260b
--- /dev/null
+++ b/contrib/Netgen/libsrc/occ/Partition_Loop.hxx
@@ -0,0 +1,118 @@
+//  GEOM PARTITION : partition algorithm
+//
+//  Copyright (C) 2003  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
+//  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS 
+// 
+//  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. 
+// 
+//  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 
+// 
+//  See http://www.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org 
+//
+//
+//
+//  File   : Partition_Loop.hxx
+//  Module : GEOM
+
+#ifndef _Partition_Loop_HeaderFile
+#define _Partition_Loop_HeaderFile
+
+#ifndef _TopoDS_Face_HeaderFile
+#include <TopoDS_Face.hxx>
+#endif
+#ifndef _TopTools_ListOfShape_HeaderFile
+#include <TopTools_ListOfShape.hxx>
+#endif
+#ifndef _TopTools_DataMapOfShapeListOfShape_HeaderFile
+#include <TopTools_DataMapOfShapeListOfShape.hxx>
+#endif
+class TopoDS_Face;
+class TopoDS_Edge;
+class TopTools_ListOfShape;
+
+
+#ifndef _Standard_HeaderFile
+#include <Standard.hxx>
+#endif
+#ifndef _Standard_Macro_HeaderFile
+#include <Standard_Macro.hxx>
+#endif
+
+class Partition_Loop  {
+
+public:
+
+   inline void* operator new(size_t,void* anAddress) 
+   {
+      return anAddress;
+   }
+   inline void* operator new(size_t size) 
+   { 
+      return Standard::Allocate(size); 
+   }
+   inline void  operator delete(void *anAddress) 
+   { 
+      if (anAddress) Standard::Free((Standard_Address&)anAddress); 
+   }
+   //    inline void  operator delete(void *anAddress, size_t size) 
+   //      { 
+   //        if (anAddress) Standard::Free((Standard_Address&)anAddress,size); 
+   //      }
+   // Methods PUBLIC
+   // 
+   Partition_Loop();
+   void Init(const TopoDS_Face& F) ;
+   void AddConstEdge(const TopoDS_Edge& E) ;
+   void Perform() ;
+   const TopTools_ListOfShape& NewWires() const;
+   void WiresToFaces() ;
+   const TopTools_ListOfShape& NewFaces() const;
+
+
+
+
+protected:
+
+   // Methods PROTECTED
+   // 
+
+
+   // Fields PROTECTED
+   //
+
+
+private: 
+
+   // Methods PRIVATE
+   // 
+
+
+   // Fields PRIVATE
+   //
+   TopoDS_Face myFace;
+   TopTools_ListOfShape myConstEdges;
+   TopTools_ListOfShape myNewWires;
+   TopTools_ListOfShape myNewFaces;
+
+
+};
+
+
+
+
+
+// other inline functions and methods (like "C++: function call" methods)
+//
+
+
+#endif
diff --git a/contrib/Netgen/libsrc/occ/Partition_Loop.ixx b/contrib/Netgen/libsrc/occ/Partition_Loop.ixx
new file mode 100644
index 0000000000..1c40e72540
--- /dev/null
+++ b/contrib/Netgen/libsrc/occ/Partition_Loop.ixx
@@ -0,0 +1,31 @@
+//  GEOM PARTITION : partition algorithm
+//
+//  Copyright (C) 2003  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
+//  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS 
+// 
+//  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. 
+// 
+//  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 
+// 
+//  See http://www.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org 
+//
+//
+//
+//  File   : Partition_Loop.ixx
+//  Module : GEOM
+
+#include "Partition_Loop.jxx"
+
+ 
+
+
diff --git a/contrib/Netgen/libsrc/occ/Partition_Loop.jxx b/contrib/Netgen/libsrc/occ/Partition_Loop.jxx
new file mode 100644
index 0000000000..dd86f05c3d
--- /dev/null
+++ b/contrib/Netgen/libsrc/occ/Partition_Loop.jxx
@@ -0,0 +1,41 @@
+//  GEOM PARTITION : partition algorithm
+//
+//  Copyright (C) 2003  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
+//  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS 
+// 
+//  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. 
+// 
+//  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 
+// 
+//  See http://www.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org 
+//
+//
+//
+//  File   : Partition_Loop.jxx
+//  Module : GEOM
+
+#ifndef _TopoDS_Face_HeaderFile
+#include <TopoDS_Face.hxx>
+#endif
+#ifndef _TopoDS_Edge_HeaderFile
+#include <TopoDS_Edge.hxx>
+#endif
+#ifndef _TopTools_ListOfShape_HeaderFile
+#include <TopTools_ListOfShape.hxx>
+#endif
+#ifndef _TopTools_DataMapOfShapeShape_HeaderFile
+#include <TopTools_DataMapOfShapeShape.hxx>
+#endif
+#ifndef _Partition_Loop_HeaderFile
+#include "Partition_Loop.hxx"
+#endif
diff --git a/contrib/Netgen/libsrc/occ/Partition_Loop2d.cxx b/contrib/Netgen/libsrc/occ/Partition_Loop2d.cxx
new file mode 100644
index 0000000000..40872bd930
--- /dev/null
+++ b/contrib/Netgen/libsrc/occ/Partition_Loop2d.cxx
@@ -0,0 +1,1145 @@
+#ifdef OCCGEOMETRY
+
+//  GEOM PARTITION : partition algorithm
+//
+//  Copyright (C) 2003  CEA/DEN, EDF R& D
+//
+//
+//
+//  File   : Partition_Loop2d.cxx
+//  Author : Benedicte MARTIN
+//  Module : GEOM
+//  $Header: /cvs/netgen/netgen/libsrc/occ/Partition_Loop2d.cxx,v 1.6 2008/03/31 14:20:28 wabro Exp $
+
+//using namespace std;
+#include <climits>
+#include "Partition_Loop2d.ixx"
+
+#include "utilities.h"
+#include <stdio.h>
+
+#include <BRepAdaptor_Curve2d.hxx>
+#include <BRepAdaptor_Surface.hxx>
+#include <BRepAlgo_AsDes.hxx>
+#include <BRepAlgo_FaceRestrictor.hxx>
+#include <BRepOffset_DataMapOfShapeReal.hxx>
+#include <BRepTopAdaptor_FClass2d.hxx>
+#include <BRep_Builder.hxx>
+#include <BRep_Tool.hxx>
+#include <Geom2dInt_GInter.hxx>
+#include <Geom2d_Curve.hxx>
+#include <IntRes2d_IntersectionPoint.hxx>
+#include <Precision.hxx>
+#include <TColStd_MapOfInteger.hxx>
+#include <TColStd_SequenceOfReal.hxx>
+#include <TopExp.hxx>
+#include <TopExp_Explorer.hxx>
+#include <TopTools_DataMapIteratorOfDataMapOfShapeListOfShape.hxx>
+#include <TopTools_DataMapIteratorOfDataMapOfShapeShape.hxx>
+#include <TopTools_DataMapOfShapeInteger.hxx>
+// #include <TopTools_DataMapOfShapeReal.hxx>    V6.5
+#include <TopTools_DataMapOfShapeShape.hxx>
+#include <TopTools_IndexedMapOfShape.hxx>
+#include <TopTools_ListIteratorOfListOfShape.hxx>
+#include <TopTools_MapIteratorOfMapOfShape.hxx>
+#include <TopTools_MapOfOrientedShape.hxx>
+#include <TopTools_MapOfShape.hxx>
+#include <TopTools_SequenceOfShape.hxx>
+#include <TopoDS.hxx>
+#include <TopoDS_Iterator.hxx>
+#include <TopoDS_Vertex.hxx>
+#include <TopoDS_Wire.hxx>
+#include <gp_Pnt.hxx>
+#include <gp_Pnt2d.hxx>
+
+//=======================================================================
+//function : Partition_Loop2d
+//purpose  :
+//=======================================================================
+
+Partition_Loop2d::Partition_Loop2d()
+{
+}
+
+//=======================================================================
+//function : Init
+//purpose  : Init with <F> the set of edges must have
+//           pcurves on <F>.
+//=======================================================================
+
+void Partition_Loop2d::Init(const TopoDS_Face& F)
+{
+  myConstEdges.Clear();
+  myNewWires  .Clear();
+  myNewFaces  .Clear();
+  myFace = F;
+  myFaceOri = myFace.Orientation();
+  myFace.Orientation( TopAbs_FORWARD );
+}
+
+//=======================================================================
+//function : AddConstEdge
+//purpose  : Add <E> as unique edge in the result.
+//=======================================================================
+
+void Partition_Loop2d::AddConstEdge (const TopoDS_Edge& E)
+{
+#ifdef DEB
+  Standard_Real f,l;
+  Handle(Geom2d_Curve) pc = BRep_Tool::CurveOnSurface( E, myFace, f,l);
+  if (pc.IsNull()) {
+    INFOS( "AddConstEdge(): EDGE W/O PCURVE on FACE");
+  } else
+#endif
+  {
+    myConstEdges.Append(E);
+  }
+}
+
+void Partition_Loop2d::AddSectionEdge (const TopoDS_Edge& E)
+{
+#ifdef DEB
+  Standard_Real f,l;
+  Handle(Geom2d_Curve) pc = BRep_Tool::CurveOnSurface( E, myFace, f,l);
+  if (pc.IsNull())
+    pc = BRep_Tool::CurveOnSurface( E, myFace, f,l);
+  gp_Vec2d Tg1;
+  gp_Pnt2d PC;
+  pc->D1(0.5*(f+l), PC, Tg1);
+  if (Tg1.Magnitude()  <= gp::Resolution()) {
+    MESSAGE ("");
+  }
+  if (pc.IsNull()) {
+    INFOS( "AddConstEdge(): EDGE W/O PCURVE on FACE");
+  } else
+#endif
+  {
+    myConstEdges.Append(E);
+    myConstEdges.Append(E.Reversed());
+    mySectionEdges.Add( E );
+  }
+}
+
+//=======================================================================
+//function : preciseU
+//purpose  : find u such that the 3D point on theE is just out of tolerance
+//           of theV
+//=======================================================================
+
+static Standard_Real preciseU (const BRepAdaptor_Surface&  theSurf,
+                               const TopoDS_Edge&          theE,
+                               const TopoDS_Vertex&        theV,
+                               const Handle(Geom2d_Curve)& theC,
+                               const Standard_Boolean      theFirstEnd)
+{
+  Standard_Boolean isForward = ( theE.Orientation () == TopAbs_FORWARD );
+  if (theFirstEnd) isForward = !isForward;
+
+  // find the first point in 2d and 3d
+  Standard_Real f,l;
+  BRep_Tool::Range( theE, f, l );
+  Standard_Real u0 = isForward ? l : f;
+  gp_Pnt2d aP2d0 = theC->Value( u0 );
+  gp_Pnt aPnt0 = theSurf.Value( aP2d0.X(), aP2d0.Y() );
+
+  // shift in 2d and 3d
+  Standard_Real du = ( l - f ) / 100, du3d = 0;
+  if (isForward)
+    du = -du;
+
+  // target parameter
+  Standard_Real u;
+
+  while (du3d < ::RealSmall())
+  {
+    // u for test
+    u = u0 + du;
+    du *= 10; // for the next iteration: increase du untill du3d is large enough
+
+    // find out how u is far from u0 in 3D
+    gp_Pnt2d aP2d  = theC->Value( u );
+    gp_Pnt aPnt  = theSurf.Value( aP2d.X(), aP2d.Y() );
+    du3d = aPnt0.Distance( aPnt );
+  }
+
+  // find u such that the 3D point is just out of tolerance of theV
+  Standard_Real tolV = BRep_Tool::Tolerance( theV ) + Precision::Confusion();
+  u = u0 + du * tolV / du3d;
+
+  // check that u is within the range
+  if ( isForward ? (u < f) : (u > l) )
+    u = u0 + du;
+
+  return u;
+}
+
+//=======================================================================
+//function : SelectEdge
+//purpose  : Find in the list <LE> the edge <NE> connected with <CE> by
+//           the vertex <CV>.
+//           <NE> is removed from the list. If <CE> is in <LE>
+//           with the same orientation, it's removed from the list
+//=======================================================================
+
+static Standard_Boolean  SelectEdge(const BRepAdaptor_Surface& Surf,
+                                    const TopoDS_Edge&    CE,
+                                    const TopoDS_Vertex&  CV,
+                                    TopoDS_Edge&          NE,
+                                    const TopTools_ListOfShape& LE)
+{
+  NE.Nullify();
+
+  if (LE.Extent() > 1) {
+    //--------------------------------------------------------------
+    // Several possible edges.
+    // - Test the edges differents of CE
+    //--------------------------------------------------------------
+    TopoDS_Face FForward = Surf.Face();
+    TopoDS_Edge aPrevNE;
+
+    gp_Vec2d CTg1, Tg1, CTg2, Tg2;
+    gp_Pnt2d PC, P;
+
+    Standard_Real f, l;
+    Handle(Geom2d_Curve) Cc, C;
+    Cc = BRep_Tool::CurveOnSurface(CE,FForward,f,l);
+
+    Standard_Boolean isForward = ( CE.Orientation () == TopAbs_FORWARD );
+    Standard_Real uc, u, du = Precision::PConfusion();
+    uc = isForward ? ( l - du ) : ( f + du );
+    Cc->D1(uc, PC, CTg1);
+    if (!isForward) CTg1.Reverse();
+
+    Standard_Real anglemin = 3 * PI, tolAng = 1.e-8;
+
+    // select an edge whose first derivative is most left of CTg1
+    // ie an angle between Tg1 and CTg1 is least
+    TopTools_ListIteratorOfListOfShape itl;
+    for ( itl.Initialize(LE); itl.More(); itl.Next()) {
+      const TopoDS_Edge& E = TopoDS::Edge(itl.Value());
+      if (E.IsSame(CE))
+        continue;
+      if (! CV.IsSame( TopExp::FirstVertex( E, Standard_True )))
+        continue;
+
+      isForward = ( E.Orientation () == TopAbs_FORWARD );
+
+      // get E curve
+      C = BRep_Tool::CurveOnSurface(E,FForward,f,l);
+      // get the first derivative Tg1
+      u = isForward ? ( f + du ) : ( l - du );
+      C->D1(u, P, Tg1);
+      if (!isForward) Tg1.Reverse();
+
+      // -PI < angle < PI
+      Standard_Real angle = Tg1.Angle(CTg1);
+
+      if (PI - Abs(angle) <= tolAng)
+      {
+        // an angle is too close to PI; assure that an angle sign really
+        // reflects an edge position: +PI - an edge is worst,
+        // -PI - an edge is best.
+        u = preciseU( Surf, CE, CV, Cc, Standard_False);
+        gp_Vec2d CTg;
+        Cc->D1(u, PC, CTg);
+        if (CE.Orientation() == TopAbs_REVERSED) CTg.Reverse();
+
+        u = preciseU( Surf, E, CV, C, Standard_True);
+        C->D1(u, P, Tg1);
+        if (!isForward) Tg1.Reverse();
+
+        angle = Tg1.Angle(CTg);
+      }
+
+      Standard_Boolean isClose = ( Abs( angle - anglemin ) <= tolAng );
+      if (angle <= anglemin) {
+        if (isClose)
+          aPrevNE = NE;
+        else
+          aPrevNE.Nullify();
+        anglemin = angle ;
+        NE = E;
+      }
+      else
+        if (isClose)
+          aPrevNE = E;
+
+    }
+    if (!aPrevNE.IsNull()) {
+      // select one of close edges, the most left one.
+      Cc = BRep_Tool::CurveOnSurface( NE, FForward, f, l );
+      uc = preciseU( Surf, NE, CV, Cc, Standard_True);
+      Cc->D1(uc, PC, CTg1);
+      if (NE.Orientation() != TopAbs_FORWARD) CTg1.Reverse();
+      
+      u = preciseU( Surf, aPrevNE, CV, C, Standard_True);
+      C->D1(u, P, Tg1);
+      if (aPrevNE.Orientation() != TopAbs_FORWARD) Tg1.Reverse();
+
+      if ( Tg1.Angle(CTg1) < 0)
+        NE = aPrevNE;
+    }
+  }
+  else if (LE.Extent() == 1) {
+    NE = TopoDS::Edge(LE.First());
+  }
+  else {
+    return Standard_False;
+  }
+  return !NE.IsNull();
+}
+
+//=======================================================================
+//function : SamePnt2d
+//purpose  :
+//=======================================================================
+
+static Standard_Boolean  SamePnt2d(const TopoDS_Vertex& V1,
+                                   const TopoDS_Edge&   E1,
+                                   const TopoDS_Vertex& V2,
+                                   const TopoDS_Edge&   E2,
+                                   const TopoDS_Face&   F)
+{
+  Standard_Real   f1,f2,l1,l2;
+  Handle(Geom2d_Curve) C1 = BRep_Tool::CurveOnSurface(E1,F,f1,l1);
+  Handle(Geom2d_Curve) C2 = BRep_Tool::CurveOnSurface(E2,F,f2,l2);
+
+  gp_Pnt2d P1 = C1->Value( BRep_Tool::Parameter(V1,E1));
+  gp_Pnt2d P2 = C2->Value( BRep_Tool::Parameter(V2,E2));
+
+  Standard_Real Tol  = 100 * BRep_Tool::Tolerance(V1);
+  Standard_Real Dist = P1.Distance(P2);
+  return Dist < Tol;
+}
+
+
+//=======================================================================
+//function : StoreInMVE
+//purpose  :
+//=======================================================================
+
+static void StoreInMVE (const TopoDS_Face& /*F*/,
+                        TopoDS_Edge& E,
+                        TopTools_DataMapOfShapeListOfShape& MVE )
+
+{
+  TopoDS_Vertex V1, V2;
+  TopTools_ListOfShape Empty;
+
+  TopExp::Vertices(E,V1,V2);
+  if (!MVE.IsBound(V1)) {
+    MVE.Bind(V1,Empty);
+  }
+  MVE(V1).Append(E);
+
+  if (!MVE.IsBound(V2)) {
+    MVE.Bind(V2,Empty);
+  }
+  MVE(V2).Append(E);
+}
+
+//=======================================================================
+//function : RemoveFromMVE
+//purpose  :
+//=======================================================================
+
+static void RemoveFromMVE(const TopoDS_Edge& E,
+                          TopTools_DataMapOfShapeListOfShape& MVE)
+{
+  TopTools_ListIteratorOfListOfShape itl;
+  TopoDS_Vertex  V1,V2;
+  TopExp::Vertices (E,V1,V2);
+  if (MVE.IsBound(V1))
+    for ( itl.Initialize(MVE(V1)); itl.More(); itl.Next()) {
+      if (itl.Value().IsEqual(E)) {
+        MVE(V1).Remove(itl);
+        break;
+      }
+    }
+  if (MVE.IsBound(V2))
+    for ( itl.Initialize(MVE(V2)); itl.More(); itl.Next()) {
+      if (itl.Value().IsEqual(E)) {
+        MVE(V2).Remove(itl);
+        break;
+      }
+    }
+}
+//=======================================================================
+//function : addConnected
+//purpose  : add to <EM> all edges reachable from <E>
+//=======================================================================
+
+static void addConnected(const TopoDS_Shape& E,
+                         TopTools_MapOfShape& EM,
+                         TopTools_MapOfShape& VM,
+                         const TopTools_DataMapOfShapeListOfShape& MVE)
+{
+  // Loop on vertices of E
+  TopoDS_Iterator itV ( E );
+  for ( ; itV.More(); itV.Next()) {
+
+    if ( ! VM.Add ( itV.Value() )) continue;
+
+    // Loop on edges sharing V
+    TopTools_ListIteratorOfListOfShape itE( MVE( itV.Value() ) );
+    for (; itE.More(); itE.Next()) {
+      if ( EM.Add( itE.Value() ))
+        addConnected ( itE.Value(), EM, VM, MVE );
+    }
+  }
+}
+//=======================================================================
+//function : canPassToOld
+//purpose  :
+//=======================================================================
+
+// static Standard_Boolean canPassToOld (const TopoDS_Shape& V,
+//                                    TopTools_MapOfShape& UsedShapesMap,
+//                                    const TopTools_DataMapOfShapeListOfShape& MVE,
+//                                    const TopTools_MapOfShape& SectionEdgesMap)
+// {
+//   TopTools_ListIteratorOfListOfShape itE( MVE(V) );
+//   // Loop on edges sharing V
+//   for (; itE.More(); itE.Next()) {
+//     if ( !UsedShapesMap.Add( itE.Value() ))
+//       continue; // already checked
+
+//     if ( !SectionEdgesMap.Contains( itE.Value() ))
+//       return Standard_True; // WE PASSED
+
+//     TopoDS_Iterator itV( itE.Value() );
+//     // Loop on vertices of an edge
+//     for (; itV.More(); itV.Next()) {
+//       if ( !UsedShapesMap.Add( itV.Value() ))
+//      continue; // already checked
+//       else
+//      return canPassToOld( itV.Value(), UsedShapesMap, MVE, SectionEdgesMap);
+//     }
+//   }
+//   return Standard_False;
+// }
+
+//=======================================================================
+//function : MakeDegenAndSelect
+//purpose  : Find parameter of intersection of <CE> with <DE> and
+//           select an edge with its parameter closest to found one.
+//           Return new degenerated edge trimming <DE> by found parameters
+//=======================================================================
+
+static TopoDS_Edge MakeDegenAndSelect(const TopoDS_Edge& CE,
+                                      const TopoDS_Vertex& CV,
+                                      TopoDS_Edge& NE,
+                                      TopTools_SequenceOfShape& EdgesSeq,
+                                      TColStd_SequenceOfReal& USeq,
+                                      const TopoDS_Edge& DE)
+{
+  if (EdgesSeq.Length() < 3) {
+    if (CE == EdgesSeq.First())
+      NE = TopoDS::Edge( EdgesSeq.Last() );
+    else
+      NE = TopoDS::Edge( EdgesSeq.First() );
+    return DE;
+  }
+
+  // find parameter on DE where it intersects CE
+
+  Standard_Real U1;
+  Standard_Integer i, nb = EdgesSeq.Length();
+  for (i=1; i<= nb; ++i) {
+    if (CE == EdgesSeq(i)) {
+      U1 = USeq(i);
+      break;
+    }
+  }
+
+  // select NE with param closest to U1 thus finding U2 for a new degen edge
+
+  Standard_Real U2, dU, dUmin = 1.e100;
+  Standard_Boolean isReversed = ( DE.Orientation() == TopAbs_REVERSED );
+  for (i=1; i<= nb; ++i) {
+    dU = USeq(i) - U1;
+    if (isReversed ? (dU > 0) : (dU < 0))
+        continue;
+    dU = Abs( dU );
+    if ( dU  > dUmin || IsEqual( dU, 0.))
+      continue;
+    const TopoDS_Edge& E = TopoDS::Edge ( EdgesSeq(i) );
+    if ( ! CV.IsSame( TopExp::FirstVertex( E , Standard_True )))
+      continue;
+    NE = E;
+    dUmin = dU + Epsilon(dU);
+    U2 = USeq(i);
+  }
+
+  // make a new degenerated edge
+  TopoDS_Edge NewDegen = TopoDS::Edge ( DE.EmptyCopied() );
+
+  Standard_Real Tol = BRep_Tool::Tolerance( CV );
+  TopoDS_Vertex V = CV;
+
+  BRep_Builder B;
+  V.Orientation( NewDegen.Orientation() );
+  B.UpdateVertex( V, U1, NewDegen, Tol);
+  B.Add ( NewDegen , V );
+
+  V.Reverse();
+  B.UpdateVertex( V, U2, NewDegen, Tol);
+  B.Add ( NewDegen , V );
+
+  return NewDegen;
+}
+
+//=======================================================================
+//function : prepareDegen
+//purpose  : Intersect <DegEdge> with edges bound to its vertex in <MVE>
+//           and store intersection parameter on <DegEdge> in
+//           <USeq> as well as the edges them-self in <EdgesSeq>.
+//           Bind <DegEdgeIndex> to vertex of <DegEdge> in <MVDEI>
+//=======================================================================
+
+static void prepareDegen (const TopoDS_Edge&                        DegEdge,
+                          const TopoDS_Face&                        F,
+                          const TopTools_DataMapOfShapeListOfShape& MVE,
+                          TopTools_SequenceOfShape&                 EdgesSeq,
+                          TColStd_SequenceOfReal&                   USeq,
+                          TopTools_DataMapOfShapeInteger&           MVDEI,
+                          const Standard_Integer                    DegEdgeIndex)
+{
+  const TopoDS_Vertex& V = TopExp::FirstVertex ( DegEdge );
+  MVDEI.Bind ( V, DegEdgeIndex );
+
+  const TopTools_ListOfShape& EdgesList = MVE ( V );
+  // if only 2 edges come to degenerated one, no pb in selection and
+  // no need to intersect them, just simulate asked data
+  Standard_Boolean doIntersect =  ( EdgesList.Extent() > 2 );
+
+  BRepAdaptor_Curve2d DC, C;
+  Geom2dInt_GInter InterCC;
+  Standard_Real Tol = Precision::PConfusion();
+  if ( doIntersect )
+    DC.Initialize( DegEdge, F );
+
+  // avoid intersecting twice the same edge
+  BRepOffset_DataMapOfShapeReal EUMap ( EdgesList.Extent() );
+  // TopTools_DataMapOfShapeReal EUMap ( EdgesList.Extent() );   // V6.5
+
+  Standard_Real U, f, l;
+  BRep_Tool::Range (DegEdge, f, l);
+
+  TopTools_ListIteratorOfListOfShape itE (EdgesList);
+  for (; itE.More(); itE.Next()) {
+
+    const TopoDS_Edge& E = TopoDS::Edge ( itE.Value() );
+
+    if ( !doIntersect) {
+      U = 0.; // it won't be used
+    }
+    else if ( BRep_Tool::IsClosed( E, F )) {
+      // seam edge: select U among f and l
+      Standard_Boolean first = Standard_True;
+      if ( V.IsSame ( TopExp::FirstVertex( E, Standard_True ) ))
+        first = Standard_False;
+      if ( DegEdge.Orientation() == TopAbs_REVERSED )
+        first = !first;
+      U = first ? f : l;
+    }
+    else if ( EUMap.IsBound( E ) ) {
+      // same edge already bound
+      U = EUMap( E );
+    }
+    else {
+      // intersect 2d curves
+      C.Initialize( E, F );
+      InterCC.Perform ( DC, C , Tol, Tol );
+      if (! InterCC.IsDone() || InterCC.NbPoints() == 0) {
+        MESSAGE ( "NO 2d INTERSECTION ON DEGENERATED EDGE" );
+        continue;
+      }
+      // hope there is only one point of intersection
+      U = InterCC.Point( 1 ).ParamOnFirst();
+    }
+    USeq.Append ( U );
+    EdgesSeq.Append ( E );
+  }
+}
+//=======================================================================
+//function : Perform
+//purpose  : Make loops.
+//=======================================================================
+
+void Partition_Loop2d::Perform()
+{
+
+  Standard_Integer NbConstEdges = myConstEdges.Extent();
+  TopTools_DataMapOfShapeListOfShape MVE(NbConstEdges) , MVE2(NbConstEdges);
+  TopTools_DataMapIteratorOfDataMapOfShapeListOfShape Mapit;
+  TopTools_ListIteratorOfListOfShape itl;
+  TopoDS_Vertex V1,V2;
+  BRepAdaptor_Surface Surface ( myFace, Standard_False );
+
+  // degenerated edges and parameters of their 2d intersection with other edges
+  TopoDS_Edge                    DE [2];
+  TopTools_SequenceOfShape       SEID [2]; // seq of edges intersecting degenerated
+  TColStd_SequenceOfReal         SeqU [2]; // n-th U corresponds to n-th edge in SEID
+  TopTools_DataMapOfShapeInteger MVDEI(2); // map vertex - degenerated edge index
+  Standard_Integer               iDeg = 0; // index of degenerated edge [0,1]
+
+  //---------------------------------------------------------
+  // Construction map vertex => edges, find degenerated edges
+  //---------------------------------------------------------
+  for (itl.Initialize(myConstEdges); itl.More(); itl.Next()) {
+    TopoDS_Edge& E = TopoDS::Edge(itl.Value());
+    if ( BRep_Tool::Degenerated( E )) {
+      if (DE[0].IsNull()) DE[0] = E;
+      else                DE[1] = E;
+    }
+    else
+      StoreInMVE(myFace,E,MVE);
+  }
+
+  // fill data for degenerated edges
+  if ( ! DE[0].IsNull() )
+    prepareDegen ( DE[0], myFace, MVE, SEID[0], SeqU[0], MVDEI, 0);
+  if ( ! DE[1].IsNull() )
+    prepareDegen ( DE[1], myFace, MVE, SEID[1], SeqU[1], MVDEI, 1);
+
+
+  // to detect internal wires
+  Standard_Boolean isInternCW = 0;
+  MVE2 = MVE;
+
+
+  //------------------------------
+  // Construction of all the wires
+  //------------------------------
+  // first, we collect wire edges in WEL list looking for same edges that
+  // will be then removed possibly exploding a wire into parts;
+  // second, build wire(s)
+
+  while (!MVE.IsEmpty()) {
+
+    TopoDS_Vertex    VF,CV;
+    TopoDS_Edge      CE,NE,EF;
+    TopoDS_Wire      NW;
+    BRep_Builder     B;
+    Standard_Boolean End = Standard_False;
+    TopTools_ListOfShape WEL;
+
+    Mapit.Initialize(MVE);
+    if (Mapit.Value().IsEmpty()) {
+      MVE.UnBind(Mapit.Key());
+      continue;
+    }
+
+    // EF first edge.
+    EF = CE = TopoDS::Edge(Mapit.Value().First());
+    // VF first vertex
+    VF = TopExp::FirstVertex( CE, Standard_True);
+
+    isInternCW = Standard_True;
+
+    TopTools_MapOfShape addedEM  (NbConstEdges); // map of edges added to WEL
+    TopTools_MapOfShape doubleEM (NbConstEdges); // edges encountered twice in WEL
+
+    //-------------------------------
+    // Construction of a wire.
+    //-------------------------------
+    while (!End) {
+
+      // only a seam is allowed twice in a wire, the others should be removed
+      if (addedEM.Add ( CE ) || BRep_Tool::IsClosed( CE, myFace ) )
+        WEL.Append( CE );
+      else {
+        doubleEM.Add( CE );
+        RemoveFromMVE (CE,MVE2);
+        TopoDS_Edge CERev = CE;
+        CERev.Reverse();
+        RemoveFromMVE (CERev,MVE2);
+      }
+
+      RemoveFromMVE (CE,MVE);
+
+      CV = TopExp::LastVertex( CE, Standard_True);
+
+      if (isInternCW && !mySectionEdges.Contains(CE))
+        // wire is internal if all edges are section ones
+        isInternCW = Standard_False;
+
+      if (MVDEI.IsBound( CV )) { // CE comes to the degeneration
+        iDeg = MVDEI( CV );
+        TopoDS_Edge NewDegen;
+        NewDegen = MakeDegenAndSelect( CE, CV, NE, SEID[iDeg], SeqU[iDeg], DE[iDeg]);
+        WEL.Append( NewDegen );
+        CE = NE;
+        End = CV.IsSame( VF );
+        continue;
+      }
+
+      //--------------
+      // stop test
+      //--------------
+      if (MVE(CV).IsEmpty()) {
+        End=Standard_True;
+        MVE.UnBind(CV);
+      }
+      else if (CV.IsSame(VF) && SamePnt2d(CV,CE, VF,EF, myFace) ) {
+        End = Standard_True;
+      }
+      else {
+        //----------------------------
+        // select new current edge
+        //----------------------------
+        if (! SelectEdge (Surface,CE,CV,NE,MVE(CV))) {
+          MESSAGE ( " NOT CLOSED WIRE " );
+          End=Standard_True;
+        }
+        else
+          CE = NE;
+      }
+    } // while ( !End )
+
+
+    // WEL is built, built wire(s)
+
+
+    itl.Initialize( WEL );
+    if ( doubleEM.IsEmpty()) { // no double edges
+      B.MakeWire( NW );
+      for (; itl.More(); itl.Next())
+        B.Add ( NW, itl.Value());
+      if (isInternCW) myInternalWL.Append(NW);
+      else            myNewWires.Append  (NW);
+    }
+
+    else {
+      // remove double and degenerated edges from WEL
+      while (itl.More()) {
+        const TopoDS_Edge& E = TopoDS::Edge ( itl.Value() );
+        if ( doubleEM.Contains( E ) || BRep_Tool::Degenerated( E ))
+          WEL.Remove( itl );
+        else
+           itl.Next();
+      }
+      if ( WEL.IsEmpty())
+        continue;
+      // remove double edges from SEID and SeqU
+      Standard_Integer i,j;
+      for (j=0; j<2; ++j) {
+        for (i=1; i<=SEID[j].Length(); ++i) {
+          if (doubleEM.Contains( SEID[j].Value(i))) {
+            SEID[j].Remove( i );
+            SeqU[j].Remove( i-- );
+          }
+        }
+      }
+      // removal of doulbe edges can explode a wire into parts,
+      // make new wires of them.
+      // A Loop like previous one but without 2d check
+      while ( !WEL.IsEmpty() ) {
+        CE = TopoDS::Edge( WEL.First() );
+        WEL.RemoveFirst();
+        B.MakeWire( NW );
+        VF = TopExp::FirstVertex ( CE, Standard_True);
+
+        End = Standard_False;
+        while ( !End) {
+          B.Add( NW, CE );
+          CV = TopExp::LastVertex  ( CE, Standard_True);
+
+          if (MVDEI.IsBound( CV )) {   // CE comes to the degeneration
+            iDeg = MVDEI( CV );
+            TopoDS_Edge NewDegen;
+            NewDegen = MakeDegenAndSelect( CE, CV, NE, SEID[iDeg], SeqU[iDeg], DE[iDeg]);
+            B.Add( NW, NewDegen );
+            End = CV.IsSame( VF );
+            CE = NE;
+            if (!NE.IsNull()) { // remove NE from WEL
+              for (itl.Initialize( WEL ); itl.More(); itl.Next())
+                if ( NE == itl.Value()) {
+                  WEL.Remove( itl );
+                  break;
+                }
+            }
+          }  // end degeneration
+
+          else {
+            if (CV.IsSame( VF )) {
+              End = Standard_True;
+              continue;
+            }
+            // edges in WEL most often are well ordered
+            // so try to iterate until the End
+            Standard_Boolean add = Standard_False;
+            itl.Initialize(WEL);
+            while ( itl.More() && !End) {
+              NE = TopoDS::Edge( itl.Value() );
+              if ( CV.IsSame( TopExp::FirstVertex( NE, Standard_True ))) {
+                WEL.Remove( itl );
+                if (add)
+                  B.Add( NW, CE );
+                CE = NE;
+                add = Standard_True;
+                CV = TopExp::LastVertex( CE, Standard_True);
+                if (MVDEI.IsBound( CV ) || CV.IsSame( VF ))
+                  break;
+              }
+              else
+                itl.Next();
+            }
+            if (!add)
+              End = Standard_True;
+          }
+        } // !End
+
+        myInternalWL.Append( NW );
+      }
+    } // end building new wire(s) from WEL
+
+  } // end Loop on MVE
+
+  // all wires are built
+
+
+  // ============================================================
+  // select really internal wires i.e. those from which we can`t
+  // pass to an old (not section) edge
+  // ============================================================
+
+  Standard_Integer nbIW = myInternalWL.Extent();
+  if (nbIW == 0)
+    return;
+
+  if ( myNewWires.Extent() != 1 && nbIW > 1) {
+    TopTools_MapOfShape outerEM (NbConstEdges); // edges connected to non-section ones
+    TopTools_MapOfShape visitedVM (NbConstEdges);
+    for ( itl.Initialize( myConstEdges ); itl.More(); itl.Next()) {
+      if ( ! mySectionEdges.Contains( itl.Value() ))
+        addConnected (itl.Value(), outerEM, visitedVM, MVE2);
+    }
+    // if an edge of a wire is in <outerEM>, the wire is not internal
+    TopExp_Explorer expIWE;
+    TopTools_ListIteratorOfListOfShape itIW ( myInternalWL );
+    while (itIW.More()) {
+      expIWE.Init ( itIW.Value() , TopAbs_EDGE );
+      if ( outerEM.Contains( expIWE.Current() )) {
+        myNewWires.Append ( itIW.Value() );
+        myInternalWL.Remove( itIW ); // == itIW.Next()
+      }
+      else
+        itIW.Next();
+    }
+  }
+}
+//=======================================================================
+//function : isHole
+//purpose  :
+//=======================================================================
+
+static Standard_Boolean isHole (const TopoDS_Wire& W,
+                                const TopoDS_Face& F)
+{
+  BRep_Builder B;
+  TopoDS_Shape newFace = F.EmptyCopied();
+  B.Add(newFace,W.Oriented(TopAbs_FORWARD));
+  BRepTopAdaptor_FClass2d classif (TopoDS::Face(newFace),
+                                   Precision::PConfusion());
+  return (classif.PerformInfinitePoint() == TopAbs_IN);
+}
+
+//=======================================================================
+//function : IsInside
+//purpose  : check if W1 is inside W2. Suppose W2 is not a hole !!!!
+//=======================================================================
+
+static Standard_Boolean isInside(const TopoDS_Face& F,
+                                 const TopoDS_Wire& W1,
+                                 const TopoDS_Wire& W2)
+{
+  // make a face with wire W2
+  BRep_Builder B;
+  TopoDS_Shape aLocalShape = F.EmptyCopied();
+  TopoDS_Face newFace = TopoDS::Face(aLocalShape);
+  B.Add(newFace,W2);
+
+  // get any 2d point of W1
+  TopExp_Explorer exp(W1,TopAbs_EDGE);
+  if (BRep_Tool::Degenerated( TopoDS::Edge( exp.Current() )))
+    exp.Next();
+  const TopoDS_Edge& e = TopoDS::Edge(exp.Current());
+  Standard_Real f,l;
+  Handle(Geom2d_Curve) C2d = BRep_Tool::CurveOnSurface(e,F,f,l);
+  gp_Pnt2d pt2d(C2d->Value( 0.5 * ( f + l )));
+
+  BRepTopAdaptor_FClass2d classif(newFace,Precision::PConfusion());
+  return (classif.Perform(pt2d) == TopAbs_IN);
+}
+
+//=======================================================================
+//function : NewWires
+//purpose  : Returns the list of wires performed.
+//           can be an empty list.
+//=======================================================================
+
+const TopTools_ListOfShape&  Partition_Loop2d::NewWires() const
+{
+  return myNewWires;
+}
+
+//=======================================================================
+//function : NewFaces
+//purpose  : Returns the list of faces.
+//Warning  : The method <WiresToFaces> as to be called before.
+//           can be an empty list.
+//=======================================================================
+
+const TopTools_ListOfShape&  Partition_Loop2d::NewFaces() const
+{
+  return myNewFaces;
+}
+
+//=======================================================================
+//function : findEqual
+//purpose  : move wires form <WL> to <EqWL> pairs of wires build of the same edges
+//=======================================================================
+
+static void findEqual (TopTools_ListOfShape& WL,
+                       TopTools_DataMapOfShapeShape& EqWM,
+                       const TopoDS_Face& F)
+{
+  TopTools_ListIteratorOfListOfShape it1, it2;
+  Standard_Integer i,j;
+  TColStd_MapOfInteger IndMap;
+  for (it1.Initialize(WL), i=1;  it1.More();  it1.Next(), i++) {
+
+    if (IndMap.Contains(i)) continue;
+    const TopoDS_Wire& Wire1 = TopoDS::Wire( it1.Value());
+
+    for (it2.Initialize(WL), j=1;  it2.More();  it2.Next(), j++) {
+
+      if (j <= i || IndMap.Contains(j)) continue;
+
+      TopTools_IndexedMapOfShape EdgesMap;
+      TopExp::MapShapes (Wire1, TopAbs_EDGE, EdgesMap);
+
+      const TopoDS_Shape& Wire2 = it2.Value();
+      TopoDS_Iterator itE ( Wire2);
+      for (; itE.More(); itE.Next()) {
+        if ( !EdgesMap.Contains( itE.Value()) )
+          break;
+      }
+      if (!itE.More()) { // all edges are same
+        if (isHole( Wire1, F)) {
+          EqWM.Bind ( Wire1, Wire2 );
+        }
+        else {
+          EqWM.Bind ( Wire2, Wire1 );
+        }
+        IndMap.Add(i);
+        IndMap.Add(j);
+        break;
+      }
+    }
+  }
+  // clear WL
+  it1.Initialize(WL);
+  i=1;
+  while (it1.More()) {
+    if (IndMap.Contains(i))
+      WL.Remove(it1); // next node becomes current and with Next() we would miss it
+    else
+      it1.Next();
+    i++;
+  }
+}
+
+//=======================================================================
+//function : classify
+//purpose  : bind to a wire a list of internal wires
+//=======================================================================
+
+static void classify(const TopTools_DataMapOfShapeShape& EqWM,
+                     BRepAlgo_AsDes& OuterInner,
+                     const TopoDS_Face& F)
+{
+  TopTools_DataMapIteratorOfDataMapOfShapeShape it1, it2;
+
+  for (it1.Initialize(EqWM);  it1.More();  it1.Next()) {
+    // find next after it1.Value()
+    for (it2.Initialize(EqWM);  it2.More();  it2.Next())
+      if (it1.Value().IsSame( it2.Value() ))
+      {
+        it2.Next();
+        break;
+      }
+    for ( ;  it2.More();  it2.Next()) {
+      const TopoDS_Wire& Wire1 = TopoDS::Wire( it1.Value() );
+      const TopoDS_Wire& Wire2 = TopoDS::Wire( it2.Value() );
+      if (isInside(F, Wire1, Wire2))
+        OuterInner.Add (Wire2, Wire1);
+      else if (isInside(F, Wire2, Wire1))
+        OuterInner.Add (Wire1, Wire2);
+    }
+  }
+}
+//=======================================================================
+//function : WiresToFaces
+//purpose  : Build faces from the wires result.
+//           <EdgeImage> serves to  find  original edge by new
+//           one. <Section> contains edges resulting from face
+//           intersections
+//=======================================================================
+
+void  Partition_Loop2d::WiresToFaces(const BRepAlgo_Image& )
+{
+  Standard_Integer nbW = myNewWires.Extent() + myInternalWL.Extent();
+  if (nbW==0)
+    return;
+
+  BRepAlgo_FaceRestrictor FR;
+  FR.Init (myFace,Standard_False);
+
+  // FaceRestrictor is instable in rather simple cases
+  // (ex. a single face of bellecoque.brep splited by 10 planes:
+  // sometimes 1-2 faces are missing ).
+  // So we use it as less as possible: no holes -> make faces by hands
+
+
+  // are there holes in myFace ?
+  Standard_Boolean hasOldHoles = Standard_False;
+  TopoDS_Iterator itOldW (myFace);
+  if ( itOldW.More()) {
+    const TopoDS_Wire& FirstOldWire = TopoDS::Wire( itOldW.Value() );
+    itOldW.Next();
+    hasOldHoles = itOldW.More() || isHole( FirstOldWire, myFace);
+  }
+  if (myInternalWL.IsEmpty() && !hasOldHoles) {
+    // each wire bounds one face
+    BRep_Builder B;
+    TopTools_ListIteratorOfListOfShape itNW (myNewWires);
+    for (; itNW.More(); itNW.Next()) {
+      TopoDS_Face NF = TopoDS::Face ( myFace.EmptyCopied() );
+      B.Add ( NF, itNW.Value() );
+      NF.Orientation( myFaceOri);
+      myNewFaces.Append ( NF );
+    }
+    return;
+  }
+
+  // FaceRestrictor can't classify wires build on all the same edges
+  // and gives incorrect result in such cases (ex. a plane cut into 2 parts by cylinder)
+  // We must make faces of equal wires separately. One of equal wires makes a
+  // hole in a face and should come together with outer wires of face.
+  // The other of a wires pair bounds a face that may have holes in turn.
+
+  // Find equal wires among internal wires
+  TopTools_DataMapOfShapeShape EqWM; // key is a hole part of a pair of equal wires
+  findEqual (myInternalWL, EqWM, myFace);
+
+  if (!EqWM.IsEmpty()) { // there are equal wires
+
+    if (hasOldHoles)
+      myInternalWL.Append( myNewWires ); // an old wire can be inside an equal wire
+
+    // classify equal wire pairs
+    BRepAlgo_AsDes OuterInner;
+    classify (EqWM,OuterInner,myFace);
+
+    // make face of most internal of equal wires and its inner wires
+    while ( !EqWM.IsEmpty()) {
+
+      TopTools_ListOfShape prevHolesL; // list of hole-part of previous most internal equal wires
+
+      // find most internal wires among pairs (key - hole, value - outer part)
+      TopTools_DataMapIteratorOfDataMapOfShapeShape it(EqWM);
+      Standard_Integer nbEqW = EqWM.Extent(); // protection against infinite loop
+      for ( ; it.More(); it.Next()) {
+
+        TopoDS_Wire outerW = TopoDS::Wire ( it.Value() );
+        if (  OuterInner.HasDescendant( outerW ) && // has internal
+             ! OuterInner.Descendant( outerW ).IsEmpty() )
+          continue;
+
+        FR.Add( outerW );
+
+        // add internal wires that are inside of outerW
+        TopTools_ListIteratorOfListOfShape itIW (myInternalWL);
+        while ( itIW.More()) {
+          TopoDS_Wire IW = TopoDS::Wire ( itIW.Value() );
+          if ( isInside (myFace, IW, outerW)) {
+            FR.Add (IW);
+            myInternalWL.Remove( itIW ); // == itIW.Next() !!!
+          }
+          else
+            itIW.Next();
+        }
+
+        // the hole-part of current pair of equal wires will be in the next new face
+        prevHolesL.Append ( it.Key() );
+
+      } // Loop on map of equal pairs searching for innermost wires
+
+      // make faces
+      FR.Perform();
+      if (FR.IsDone()) {
+        for (; FR.More(); FR.Next())
+          myNewFaces.Append(FR.Current());
+      }
+
+      FR.Clear();
+
+      // add hole-parts to FaceRestrictor,
+      // remove them from the EqWM,
+      // remove found wires as internal of resting classified wires
+      Standard_Boolean clearOuterInner =  ( prevHolesL.Extent() < EqWM.Extent() );
+      TopTools_ListIteratorOfListOfShape itPrev (prevHolesL);
+      for (; itPrev.More(); itPrev.Next()) {
+        TopoDS_Wire& Hole = TopoDS::Wire ( itPrev.Value() );
+        FR.Add ( Hole );
+        if (clearOuterInner) {
+          const TopoDS_Wire& outerW = TopoDS::Wire ( EqWM.Find( Hole ) );
+          // Loop on wires including outerW
+          TopTools_ListIteratorOfListOfShape itO( OuterInner.Ascendant( outerW ));
+          for (; itO.More(); itO.Next()) {
+            TopTools_ListOfShape& innerL = OuterInner.ChangeDescendant( itO.Value() );
+            TopTools_ListIteratorOfListOfShape itI (innerL);
+            // Loop on internal wires of current including wire
+            for (; itI.More(); itI.Next())
+              if ( outerW.IsSame( itI.Value() )) {
+                innerL.Remove( itI );   break;
+              }
+          }
+        }
+        EqWM.UnBind ( Hole );
+      }
+
+      if (nbEqW == EqWM.Extent())
+      {
+        // error: pb with wires classification
+#ifdef DEB
+        MESSAGE("Partition_Loop2d::WiresToFaces(), pb with wires classification");
+#endif
+        break;
+      }
+
+    } // while (!EqWM.IsEmpty)
+
+  } //  if !EqWM.IsEmpty()
+
+  myNewWires.Append ( myInternalWL );
+
+  TopTools_ListIteratorOfListOfShape itW (myNewWires);
+  for (; itW.More(); itW.Next()) {
+    TopoDS_Wire& W = TopoDS::Wire ( itW.Value() );
+    FR.Add(W);
+  }
+  FR.Perform();
+  for (; FR.IsDone() && FR.More(); FR.Next())
+    myNewFaces.Append(FR.Current());
+
+
+  TopTools_ListIteratorOfListOfShape itNF (myNewFaces);
+  for (; itNF.More(); itNF.Next())
+    itNF.Value().Orientation( myFaceOri );
+}
+
+#endif
diff --git a/contrib/Netgen/libsrc/occ/Partition_Loop2d.hxx b/contrib/Netgen/libsrc/occ/Partition_Loop2d.hxx
new file mode 100644
index 0000000000..bdf1c2531d
--- /dev/null
+++ b/contrib/Netgen/libsrc/occ/Partition_Loop2d.hxx
@@ -0,0 +1,106 @@
+//  GEOM PARTITION : partition algorithm
+//
+//  Copyright (C) 2003  CEA/DEN, EDF R&D
+//
+//
+//
+//  File   : Partition_Loop2d.hxx
+//  Module : GEOM
+
+#ifndef _Partition_Loop2d_HeaderFile
+#define _Partition_Loop2d_HeaderFile
+
+#ifndef _TopoDS_Face_HeaderFile
+#include <TopoDS_Face.hxx>
+#endif
+#ifndef _TopAbs_Orientation_HeaderFile
+#include <TopAbs_Orientation.hxx>
+#endif
+#ifndef _TopTools_ListOfShape_HeaderFile
+#include <TopTools_ListOfShape.hxx>
+#endif
+#ifndef _TopTools_MapOfShape_HeaderFile
+#include <TopTools_MapOfShape.hxx>
+#endif
+class TopoDS_Face;
+class TopoDS_Edge;
+class TopTools_ListOfShape;
+class BRepAlgo_Image;
+
+
+#ifndef _Standard_HeaderFile
+#include <Standard.hxx>
+#endif
+#ifndef _Standard_Macro_HeaderFile
+#include <Standard_Macro.hxx>
+#endif
+
+class Partition_Loop2d  {
+
+public:
+
+   void* operator new(size_t,void* anAddress) 
+   {
+      return anAddress;
+   }
+   void* operator new(size_t size) 
+   { 
+      return Standard::Allocate(size); 
+   }
+   void  operator delete(void *anAddress) 
+   { 
+      if (anAddress) Standard::Free((Standard_Address&)anAddress); 
+   }
+   // Methods PUBLIC
+   // 
+   Partition_Loop2d();
+   void Init(const TopoDS_Face& F) ;
+   void AddConstEdge(const TopoDS_Edge& E) ;
+   void AddSectionEdge(const TopoDS_Edge& E) ;
+   void Perform() ;
+   const TopTools_ListOfShape& NewWires() const;
+   void WiresToFaces(const BRepAlgo_Image& EdgeImage) ;
+   const TopTools_ListOfShape& NewFaces() const;
+
+
+
+
+
+protected:
+
+   // Methods PROTECTED
+   // 
+
+
+   // Fields PROTECTED
+   //
+
+
+private: 
+
+   // Methods PRIVATE
+   // 
+
+
+   // Fields PRIVATE
+   //
+   TopoDS_Face myFace;
+   TopAbs_Orientation myFaceOri;
+   TopTools_ListOfShape myConstEdges;
+   TopTools_ListOfShape myNewWires;
+   TopTools_ListOfShape myNewFaces;
+   TopTools_ListOfShape myInternalWL;
+   TopTools_MapOfShape mySectionEdges;
+
+
+};
+
+
+
+
+
+// other Inline functions and methods (like "C++: function call" methods)
+//
+
+
+#endif
diff --git a/contrib/Netgen/libsrc/occ/Partition_Loop2d.ixx b/contrib/Netgen/libsrc/occ/Partition_Loop2d.ixx
new file mode 100644
index 0000000000..2d35fd5c71
--- /dev/null
+++ b/contrib/Netgen/libsrc/occ/Partition_Loop2d.ixx
@@ -0,0 +1,14 @@
+//  GEOM PARTITION : partition algorithm
+//
+//  Copyright (C) 2003  CEA/DEN, EDF R&D
+//
+//
+//
+//  File   : Partition_Loop2d.ixx
+//  Module : GEOM
+
+#include "Partition_Loop2d.jxx"
+
+ 
+
+
diff --git a/contrib/Netgen/libsrc/occ/Partition_Loop2d.jxx b/contrib/Netgen/libsrc/occ/Partition_Loop2d.jxx
new file mode 100644
index 0000000000..555c16c809
--- /dev/null
+++ b/contrib/Netgen/libsrc/occ/Partition_Loop2d.jxx
@@ -0,0 +1,24 @@
+//  GEOM PARTITION : partition algorithm
+//
+//  Copyright (C) 2003  CEA/DEN, EDF R&D
+//
+//
+//
+//  File   : Partition_Loop2d.jxx
+//  Module : GEOM
+
+#ifndef _TopoDS_Face_HeaderFile
+#include <TopoDS_Face.hxx>
+#endif
+#ifndef _TopoDS_Edge_HeaderFile
+#include <TopoDS_Edge.hxx>
+#endif
+#ifndef _TopTools_ListOfShape_HeaderFile
+#include <TopTools_ListOfShape.hxx>
+#endif
+#ifndef _BRepAlgo_Image_HeaderFile
+#include <BRepAlgo_Image.hxx>
+#endif
+#ifndef _Partition_Loop2d_HeaderFile
+#include "Partition_Loop2d.hxx"
+#endif
diff --git a/contrib/Netgen/libsrc/occ/Partition_Loop3d.cxx b/contrib/Netgen/libsrc/occ/Partition_Loop3d.cxx
new file mode 100644
index 0000000000..3e9acc3ccb
--- /dev/null
+++ b/contrib/Netgen/libsrc/occ/Partition_Loop3d.cxx
@@ -0,0 +1,356 @@
+#ifdef OCCGEOMETRY
+
+//  GEOM PARTITION : partition algorithm
+//
+//  Copyright (C) 2003  CEA/DEN, EDF R&D
+//
+//
+//
+//  File   : Partition_Loop3d.cxx
+//  Module : GEOM
+
+//using namespace std;
+#include <climits>
+#include "Partition_Loop3d.ixx"
+
+#include <TopExp_Explorer.hxx>
+#include <TopExp.hxx>
+#include <BRep_Builder.hxx>
+#include <TopTools_MapOfShape.hxx>
+#include <TopTools_ListIteratorOfListOfShape.hxx>
+#include <TopoDS_Shell.hxx>
+#include <TopoDS_Iterator.hxx>
+#include <TopoDS.hxx>
+#include <TopTools_MapIteratorOfMapOfShape.hxx>
+#include <gp_Vec.hxx>
+#include <gp_Pnt.hxx>
+#include <Geom2d_Curve.hxx>
+#include <BRep_Tool.hxx>
+#include <Geom_Surface.hxx>
+#include <gp_Pnt2d.hxx>
+#include <gp_Vec2d.hxx>
+#include <gp_Dir2d.hxx>
+#include <Geom_Curve.hxx>
+
+//=======================================================================
+//function : Partition_Loop3d
+//purpose  : 
+//=======================================================================
+
+Partition_Loop3d::Partition_Loop3d()
+{
+}
+
+//=======================================================================
+//function : AddConstFaces
+//purpose  : Add faces of <S> as unique faces in the result.
+//=======================================================================
+
+void Partition_Loop3d::AddConstFaces(const TopoDS_Shape& S) 
+{
+  TopExp_Explorer FaceExp(S, TopAbs_FACE);
+  for (; FaceExp.More(); FaceExp.Next())
+    myFaces.Append( FaceExp.Current() );
+
+  TopExp::MapShapesAndAncestors(S, TopAbs_EDGE, TopAbs_FACE, myEFMap);
+}
+
+//=======================================================================
+//function : AddSectionFaces
+//purpose  : Add faces of <S> as double faces in the result.
+//=======================================================================
+
+void Partition_Loop3d::AddSectionFaces(const TopoDS_Shape& S) 
+{
+  AddConstFaces( S );
+  AddConstFaces( S.Reversed() );
+}
+
+//=======================================================================
+//function : MakeShells
+//purpose  : Make and return shells. 
+//           <AvoidFacesMap> can contain faces that must not be
+//           added to result shells.
+//=======================================================================
+
+const TopTools_ListOfShape&
+  Partition_Loop3d::MakeShells (const TopTools_MapOfOrientedShape& AvoidFacesMap)
+{
+  myNewShells.Clear();
+  
+  BRep_Builder Builder;
+  TopTools_MapOfShape CheckedEdgesMap;
+  TopTools_MapOfOrientedShape AddedFacesMap;
+  
+  TopTools_ListIteratorOfListOfShape itF (myFaces);
+  for (; itF.More(); itF.Next())
+  {
+    const TopoDS_Shape& FF = itF.Value();
+    if (AvoidFacesMap.Contains( FF ) ||
+	! AddedFacesMap.Add( FF ) )
+      continue;
+
+    // make a new shell
+    TopoDS_Shell Shell;
+    Builder.MakeShell(Shell);
+    Builder.Add(Shell,FF);
+
+    // clear the maps from shapes added to previous Shell
+    TopTools_MapIteratorOfMapOfShape itEM (CheckedEdgesMap);
+    for (; itEM.More(); itEM.Next()) {
+      TopTools_ListOfShape& FL = myEFMap.ChangeFromKey( itEM.Key());
+      TopTools_ListIteratorOfListOfShape it (FL);
+      while ( it.More()) {
+        if (AddedFacesMap.Contains( it.Value()))
+          FL.Remove( it );
+        else
+          it.Next();
+      }
+    }
+    CheckedEdgesMap.Clear();
+
+    
+    // loop on faces added to Shell; add their neighbor faces to Shell and so on
+    TopoDS_Iterator itAddedF (Shell);
+    for (; itAddedF.More(); itAddedF.Next())
+    {
+      const TopoDS_Face& F = TopoDS::Face (itAddedF.Value());
+
+      // loop on edges of F; find a good neighbor face of F by E
+      TopExp_Explorer EdgeExp(F, TopAbs_EDGE);
+      for (; EdgeExp.More(); EdgeExp.Next())
+      {
+        const TopoDS_Edge& E = TopoDS::Edge( EdgeExp.Current());
+	if (! CheckedEdgesMap.Add( E ))
+	  continue;
+
+	// candidate faces list
+        const TopTools_ListOfShape& FL = myEFMap.ChangeFromKey(E);
+        if (FL.IsEmpty())
+          continue;
+	// select one of neighbors
+        TopoDS_Face SelF;
+        if (FL.Extent() == 2) {
+          if (! F.IsSame( FL.First() ))
+            SelF = TopoDS::Face( FL.First() );
+          else if (!F.IsSame( FL.Last() ))
+            SelF = TopoDS::Face( FL.Last() );
+        }
+        else {
+          // check if a face already added to Shell shares E
+	  TopTools_ListIteratorOfListOfShape it (FL);
+          Standard_Boolean found = Standard_False;
+          for (; !found && it.More(); it.Next())
+            if (F != it.Value())
+              found = AddedFacesMap.Contains( it.Value() );
+          if (found)
+            continue;
+          // select basing on geometrical check
+          Standard_Boolean GoodOri, inside;
+          Standard_Real dot, MaxDot = -100;
+          TopTools_ListOfShape TangFL; // tangent faces
+          for ( it.Initialize( FL ) ; it.More(); it.Next()) {
+            const TopoDS_Face& NeighborF = TopoDS::Face( it.Value());
+            if (NeighborF.IsSame( F ))
+              continue;
+            inside = Partition_Loop3d::IsInside( E, F, NeighborF, 1, dot, GoodOri);
+            if (!GoodOri)
+              continue;
+            if (!inside)
+              dot = -dot - 3;
+            if (dot < MaxDot)
+              continue;
+            if ( IsEqual( dot, MaxDot))
+              TangFL.Append(SelF);
+            else
+              TangFL.Clear();
+            MaxDot = dot;
+            SelF = NeighborF;
+          }
+          if (!TangFL.IsEmpty()) {
+            for (it.Initialize( TangFL ); it.More(); it.Next()) {
+              const TopoDS_Face& NeighborF = TopoDS::Face( it.Value());
+              if (Partition_Loop3d:: IsInside( E, SelF , NeighborF, 0, dot, GoodOri))
+                SelF = NeighborF;
+            }
+          }
+        }
+        if (!SelF.IsNull() &&
+	    AddedFacesMap.Add( SelF ) &&
+	    !AvoidFacesMap.Contains( SelF )) 
+          Builder.Add( Shell, SelF);
+
+      } // loop on edges of F
+      
+    } // loop on the faces added to Shell
+
+    // Shell is complete
+    myNewShells.Append( Shell );
+
+  } // loop on myFaces
+
+
+  // prepare to the next call
+  myFaces.Clear();
+  myEFMap.Clear();
+
+  return myNewShells;
+}
+
+
+
+//=======================================================================
+//function : Normal
+//purpose  : 
+//=======================================================================
+
+gp_Vec Partition_Loop3d::Normal(const TopoDS_Edge& E,
+				const TopoDS_Face& F)
+{
+  gp_Vec Norm, V1, V2;
+  Standard_Real First, Last;
+  gp_Pnt Ps;
+
+  Handle(Geom2d_Curve) C2d = BRep_Tool::CurveOnSurface (E, F, First, Last);
+  Handle(Geom_Surface) Sf = BRep_Tool::Surface(F);
+
+  gp_Pnt2d p = C2d->Value( 0.5*(First+Last) );
+  Sf->D1(p.X(), p.Y(), Ps, V1, V2);
+  Norm = V1.Crossed(V2);
+
+  if (F.Orientation() == TopAbs_REVERSED ) 
+    Norm.Reverse();
+
+  return Norm;
+}
+
+//=======================================================================
+//function : NextNormal
+//purpose  : find normal to F at point a little inside F near the middle of E
+//warning  : E must be properly oriented in F.
+//=======================================================================
+
+static gp_Vec NextNormal(const TopoDS_Edge& E,
+			 const TopoDS_Face& F)
+{
+  Standard_Real First, Last;
+
+  Handle(Geom2d_Curve) C2d = BRep_Tool::CurveOnSurface (E, F, First, Last);
+  Handle(Geom_Surface) Sf = BRep_Tool::Surface(F);
+
+  gp_Pnt2d p;
+  gp_Vec2d v;
+  C2d->D1( 0.5*(First+Last), p, v);
+  if (E.Orientation() != F.Orientation())
+    v.Reverse();
+  gp_Dir2d dir( -v.Y(), v.X() ); // dir inside F
+  
+  Standard_Real duv = 1e-6; // this is not Ok and may give incorrect result if
+  // resolutionUV of compared faces is very different. To have a good result,
+  //it is necessary to get normal to faces at points equidistant from E in 3D
+  
+  p.SetX( p.X() + dir.X()*duv );
+  p.SetY( p.Y() + dir.Y()*duv );
+  
+  gp_Pnt Ps;
+  gp_Vec Norm, V1, V2, VV1, VV2;
+  Sf->D1( p.X(), p.Y(), Ps, V1, V2);
+  Norm = V1.Crossed(V2);
+
+  if (F.Orientation() == TopAbs_REVERSED ) 
+    Norm.Reverse();
+
+  return Norm;
+}
+
+
+//=======================================================================
+//function : FindEinF
+//purpose  : find E in F
+//=======================================================================
+
+static TopoDS_Edge FindEinF(const TopoDS_Edge& E,
+			    const TopoDS_Face& F)
+{
+  TopExp_Explorer expl (F, TopAbs_EDGE);
+  for (; expl.More(); expl.Next()) 
+    if( E.IsSame( expl.Current() ))
+      return TopoDS::Edge(expl.Current());
+  TopoDS_Edge nullE;
+  return nullE;
+}
+
+//=======================================================================
+//function : IsInside
+//purpose  : check if <F2> is inside <F1> by edge <E>.
+//           if <CountDot>, compute <Dot>: scalar production of
+//           normalized  vectors  pointing  inside  faces,  and
+//           check if faces are oriented well for sewing
+//=======================================================================
+
+Standard_Boolean Partition_Loop3d::IsInside(const TopoDS_Edge& E,
+					    const TopoDS_Face& F1,
+					    const TopoDS_Face& F2,
+					    const Standard_Boolean CountDot,
+					    Standard_Real& Dot,
+					    Standard_Boolean& GoodOri) 
+{
+  Standard_Real f, l;
+  gp_Pnt P;
+  gp_Vec Vc1, Vc2, Vin1, Vin2, Nf1, Nf2;
+  Handle(Geom_Curve) Curve = BRep_Tool::Curve(E,f,l);
+  Curve->D1( 0.5*(f + l), P, Vc2);
+  TopoDS_Edge E1, E2 = FindEinF (E, F2);
+  if (E2.Orientation() == TopAbs_REVERSED ) Vc2.Reverse();
+
+  Nf1 = Normal(E,F1);
+  Nf2 = Normal(E,F2);
+
+  Standard_Real sin =
+    Nf1.CrossSquareMagnitude(Nf2) / Nf1.SquareMagnitude() / Nf2.SquareMagnitude();
+  Standard_Boolean tangent = sin < 0.001;
+
+  Standard_Boolean inside = 0;
+  if (tangent) {
+    E1 = FindEinF (E, F1);
+    gp_Vec NNf1 = NextNormal(E1,F1);
+    gp_Vec NNf2 = NextNormal(E2,F2);
+    Vin2 = NNf2.Crossed(Vc2);
+    inside = Vin2 * NNf1 < 0;
+  }
+  else {
+    Vin2 = Nf2.Crossed(Vc2);
+    inside = Vin2 * Nf1 < 0;
+  }
+  
+  if (!CountDot) return inside;
+
+  if (tangent)
+    Vin2 = Nf2.Crossed(Vc2);
+  else
+    E1 = FindEinF (E, F1);
+    
+  Vc1 = Vc2;
+  if (E1.Orientation() != E2.Orientation()) 
+    Vc1.Reverse();
+  Vin1 = Nf1.Crossed(Vc1);
+
+  if (tangent) {
+    Standard_Real N1N2 = Nf1 * Nf2;
+    GoodOri = (Vin2 * Vin1 < 0) ? N1N2 > 0 : N1N2 < 0;
+  }
+  else {
+    Standard_Real V1N2 = Vin1 * Nf2;
+    GoodOri = ( inside ? V1N2 <= 0 : V1N2 >= 0);
+  }
+
+  Vin1.Normalize();
+  Vin2.Normalize();
+  
+  Dot = Vin2 * Vin1;
+  
+  return inside;
+}
+
+
+#endif
diff --git a/contrib/Netgen/libsrc/occ/Partition_Loop3d.hxx b/contrib/Netgen/libsrc/occ/Partition_Loop3d.hxx
new file mode 100644
index 0000000000..52abd115e9
--- /dev/null
+++ b/contrib/Netgen/libsrc/occ/Partition_Loop3d.hxx
@@ -0,0 +1,102 @@
+//  GEOM PARTITION : partition algorithm
+//
+//  Copyright (C) 2003  CEA/DEN, EDF R&D
+//
+//
+//
+//  File   : Partition_Loop3d.hxx
+//  Module : GEOM
+
+#ifndef _Partition_Loop3d_HeaderFile
+#define _Partition_Loop3d_HeaderFile
+
+#ifndef _TopTools_ListOfShape_HeaderFile
+#include <TopTools_ListOfShape.hxx>
+#endif
+#ifndef _TopTools_IndexedDataMapOfShapeListOfShape_HeaderFile
+#include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
+#endif
+#ifndef _Standard_Boolean_HeaderFile
+#include <Standard_Boolean.hxx>
+#endif
+#ifndef _Standard_Real_HeaderFile
+#include <Standard_Real.hxx>
+#endif
+class TopoDS_Shape;
+class TopTools_ListOfShape;
+class TopTools_MapOfOrientedShape;
+class TopoDS_Edge;
+class TopoDS_Face;
+class gp_Vec;
+
+
+#ifndef _Standard_HeaderFile
+#include <Standard.hxx>
+#endif
+#ifndef _Standard_Macro_HeaderFile
+#include <Standard_Macro.hxx>
+#endif
+
+class Partition_Loop3d  {
+
+public:
+
+   void* operator new(size_t,void* anAddress) 
+   {
+      return anAddress;
+   }
+   void* operator new(size_t size) 
+   { 
+      return Standard::Allocate(size); 
+   }
+   void  operator delete(void *anAddress) 
+   { 
+      if (anAddress) Standard::Free((Standard_Address&)anAddress); 
+   }
+   // Methods PUBLIC
+   // 
+   Partition_Loop3d();
+   void AddConstFaces(const TopoDS_Shape& S) ;
+   void AddSectionFaces(const TopoDS_Shape& S) ;
+   const TopTools_ListOfShape& MakeShells(const TopTools_MapOfOrientedShape& AvoidFacesMap) ;
+   static  Standard_Boolean IsInside(const TopoDS_Edge& E,const TopoDS_Face& F1,const TopoDS_Face& F2,const Standard_Boolean CountDot,Standard_Real& Dot,Standard_Boolean& GoodOri) ;
+   static  gp_Vec Normal(const TopoDS_Edge& E,const TopoDS_Face& F) ;
+
+
+
+
+
+protected:
+
+   // Methods PROTECTED
+   // 
+
+
+   // Fields PROTECTED
+   //
+
+
+private: 
+
+   // Methods PRIVATE
+   // 
+
+
+   // Fields PRIVATE
+   //
+   TopTools_ListOfShape myNewShells;
+   TopTools_ListOfShape myFaces;
+   TopTools_IndexedDataMapOfShapeListOfShape myEFMap;
+
+
+};
+
+
+
+
+
+// other Inline functions and methods (like "C++: function call" methods)
+//
+
+
+#endif
diff --git a/contrib/Netgen/libsrc/occ/Partition_Loop3d.ixx b/contrib/Netgen/libsrc/occ/Partition_Loop3d.ixx
new file mode 100644
index 0000000000..a661b3242d
--- /dev/null
+++ b/contrib/Netgen/libsrc/occ/Partition_Loop3d.ixx
@@ -0,0 +1,14 @@
+//  GEOM PARTITION : partition algorithm
+//
+//  Copyright (C) 2003  CEA/DEN, EDF R&D
+//
+//
+//
+//  File   : Partition_Loop3d.ixx
+//  Module : GEOM
+
+#include "Partition_Loop3d.jxx"
+
+ 
+
+
diff --git a/contrib/Netgen/libsrc/occ/Partition_Loop3d.jxx b/contrib/Netgen/libsrc/occ/Partition_Loop3d.jxx
new file mode 100644
index 0000000000..9b654f41bb
--- /dev/null
+++ b/contrib/Netgen/libsrc/occ/Partition_Loop3d.jxx
@@ -0,0 +1,30 @@
+//  GEOM PARTITION : partition algorithm
+//
+//  Copyright (C) 2003  CEA/DEN, EDF R&D
+//
+//
+//
+//  File   : Partition_Loop3d.jxx
+//  Module : GEOM
+
+#ifndef _TopoDS_Shape_HeaderFile
+#include <TopoDS_Shape.hxx>
+#endif
+#ifndef _TopTools_ListOfShape_HeaderFile
+#include <TopTools_ListOfShape.hxx>
+#endif
+#ifndef _TopTools_MapOfOrientedShape_HeaderFile
+#include <TopTools_MapOfOrientedShape.hxx>
+#endif
+#ifndef _TopoDS_Edge_HeaderFile
+#include <TopoDS_Edge.hxx>
+#endif
+#ifndef _TopoDS_Face_HeaderFile
+#include <TopoDS_Face.hxx>
+#endif
+#ifndef _gp_Vec_HeaderFile
+#include <gp_Vec.hxx>
+#endif
+#ifndef _Partition_Loop3d_HeaderFile
+#include "Partition_Loop3d.hxx"
+#endif
diff --git a/contrib/Netgen/libsrc/occ/Partition_Spliter.cxx b/contrib/Netgen/libsrc/occ/Partition_Spliter.cxx
new file mode 100644
index 0000000000..97bd8e3322
--- /dev/null
+++ b/contrib/Netgen/libsrc/occ/Partition_Spliter.cxx
@@ -0,0 +1,2168 @@
+#ifdef OCCGEOMETRY
+
+//  GEOM PARTITION : partition algorithm
+//
+//  Copyright (C) 2003  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
+//  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS 
+// 
+//  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. 
+// 
+//  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 
+// 
+//  See http://www.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org 
+//
+//
+//
+//  File   : Partition_Spliter.cxx
+//  Author : Benedicte MARTIN
+//  Module : GEOM
+//  $Header: /cvs/netgen/netgen/libsrc/occ/Partition_Spliter.cxx,v 1.7 2008/03/31 14:20:28 wabro Exp $
+
+//using namespace std;
+#include <climits>
+#include "Partition_Inter2d.hxx"
+#include "Partition_Inter3d.hxx"
+#include "Partition_Loop2d.hxx"
+#include "Partition_Loop3d.hxx"
+#include "Partition_Spliter.ixx"
+
+#include "utilities.h"
+
+#include <Precision.hxx>
+#include <TopAbs_Orientation.hxx>
+#include <TopExp.hxx>
+#include <TopExp_Explorer.hxx>
+
+#include <TopTools_DataMapIteratorOfDataMapOfShapeListOfShape.hxx>
+#include <TopTools_DataMapOfShapeListOfShape.hxx>
+#include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
+#include <TopTools_IndexedMapOfShape.hxx>
+#include <TopTools_ListIteratorOfListOfShape.hxx>
+#include <TopTools_ListOfShape.hxx>
+#include <TopTools_MapIteratorOfMapOfShape.hxx>
+#include <TopTools_SequenceOfShape.hxx>
+
+#include <Geom2d_Curve.hxx>
+#include <Geom_Curve.hxx>
+#include <Geom_Surface.hxx>
+#include <Geom_TrimmedCurve.hxx>
+#include <gp_Pnt.hxx>
+#include <gp_Pnt2d.hxx>
+#include <gp_Vec.hxx>
+
+#include <TopoDS.hxx>
+#include <TopoDS_Compound.hxx>
+#include <TopoDS_Edge.hxx>
+#include <TopoDS_Face.hxx>
+#include <TopoDS_Iterator.hxx>
+#include <TopoDS_Shell.hxx>
+#include <TopoDS_Solid.hxx>
+#include <TopoDS_Vertex.hxx>
+#include <TopoDS_Wire.hxx>
+
+#include <BRepBndLib.hxx>
+#include <BRepClass3d_SolidClassifier.hxx>
+#include <BRepLib.hxx>
+#include <BRep_Tool.hxx>
+
+#include <Extrema_ExtPC.hxx>
+#include <GeomAdaptor_Curve.hxx>
+#include <TopOpeBRepTool_CurveTool.hxx>
+
+#ifdef DEB
+//# define PART_PERF
+#endif
+
+#ifdef PART_PERF
+# include <OSD_Chronometer.hxx>
+#endif
+
+//=======================================================================
+//function : isClosed
+//purpose  : check id a shape is closed, ie is a solid or a closed shell
+//=======================================================================
+
+static Standard_Boolean isClosed(const TopoDS_Shape& theShape)
+{
+  Standard_Boolean isClosed = (theShape.ShapeType() == TopAbs_SOLID);
+
+  if (!isClosed && theShape.ShapeType() == TopAbs_SHELL) {
+    TopTools_IndexedDataMapOfShapeListOfShape MEF;
+    TopExp::MapShapesAndAncestors(theShape, TopAbs_EDGE, TopAbs_FACE, MEF);
+    for (Standard_Integer i=1;  isClosed && i<=MEF.Extent();  ++i)
+      isClosed = ( MEF(i).Extent() != 1 );
+  }
+  
+  return isClosed;
+}
+
+//=======================================================================
+//function : Partition_Spliter
+//purpose  : constructor
+//=======================================================================
+
+Partition_Spliter::Partition_Spliter()
+{
+  myAsDes = new BRepAlgo_AsDes;
+  Clear();
+}
+
+//=======================================================================
+//function : AddTool
+//purpose  : add cutting tool that will _NOT_ be in result
+//=======================================================================
+
+void Partition_Spliter::AddTool(const TopoDS_Shape& S)
+{
+  if (S.ShapeType() < TopAbs_SOLID) { // compound or compsolid
+    TopoDS_Iterator it (S);
+    for (; it.More(); it.Next())
+    {
+      AddTool( it.Value());
+      myFaceShapeMap.Bind( it.Value(), S ); // to know compound by shape
+    }
+    return;
+  }
+
+  for (TopExp_Explorer exp(S,TopAbs_FACE); exp.More(); exp.Next())
+  {
+    myMapTools.Add(exp.Current());
+    myFaceShapeMap.Bind( exp.Current(), S );
+  }
+  if (isClosed( S ))
+    myClosedShapes.Add( S );
+}
+
+//=======================================================================
+//function : AddShape
+//purpose  : add object Shape to be splited
+//=======================================================================
+
+void Partition_Spliter::AddShape(const TopoDS_Shape& S)
+{
+  if (S.ShapeType() < TopAbs_SOLID) { // compound or compsolid
+    TopoDS_Iterator it (S);
+    for (; it.More(); it.Next())
+    {
+      AddShape( it.Value());
+      myFaceShapeMap.Bind( it.Value(), S ); // to know compound by shape
+    }
+    return;
+  }
+
+  TopExp_Explorer exp(S,TopAbs_FACE);
+  if (!exp.More()) { // do not split edges and vertices
+    //myBuilder.Add( myShape, S );
+    return;
+  }
+
+  Standard_Integer nbFacesBefore = myMapFaces.Extent(); // not to add twice the same S
+  for (; exp.More(); exp.Next()) {
+    const TopoDS_Shape & aFace = exp.Current();
+    if ( ! myFaceShapeMap.IsBound( aFace )) // keep shape of tool face added as object
+      myFaceShapeMap.Bind( aFace, S );
+    if (myMapFaces.Add( aFace ))
+      myImagesFaces.SetRoot( aFace );
+  }
+
+  if (nbFacesBefore == myMapFaces.Extent())
+    return;
+
+  // solids must be processed before all
+  if (S.ShapeType() == TopAbs_SOLID)
+    myListShapes.Prepend(S);
+  else
+    myListShapes.Append(S);
+
+  if (isClosed( S ))
+    myClosedShapes.Add( S );
+
+}
+
+//=======================================================================
+//function : Shape
+//purpose  : return resulting compound
+//=======================================================================
+
+TopoDS_Shape Partition_Spliter::Shape() const
+{
+  return myShape;
+}
+
+//=======================================================================
+//function : Clear
+//purpose  : clear fields
+//=======================================================================
+
+void Partition_Spliter::Clear()
+{
+  myDoneStep = TopAbs_SHAPE;
+  
+  myListShapes.Clear();
+  myMapFaces.Clear();
+  myMapTools.Clear();
+  myEqualEdges.Clear();
+  myNewSection.Clear();
+  myClosedShapes.Clear();
+  mySharedFaces.Clear();
+  myWrappingSolid.Clear();
+  myFaceShapeMap.Clear();
+  
+  myInternalFaces.Clear();
+  myIntNotClFaces.Clear();
+  
+  myAsDes->Clear();
+  myImagesFaces.Clear();
+  myImagesEdges.Clear();
+  myImageShape.Clear();
+  
+  //  myInter3d = Partition_Inter3d(myAsDes);
+  Partition_Inter3d hinter3d (myAsDes);
+  myInter3d = hinter3d;
+  
+  myAddedFacesMap.Clear();
+
+}
+
+//=======================================================================
+//function : Compute
+//purpose  : produce a result
+//=======================================================================
+
+void Partition_Spliter::Compute(const TopAbs_ShapeEnum Limit)
+{
+  if ((Limit != TopAbs_SHAPE && myDoneStep == Limit) ||
+      (Limit == TopAbs_SHAPE && myDoneStep == TopAbs_SOLID))
+    return;
+  
+  myBuilder.MakeCompound( myShape );
+  
+  TopTools_MapIteratorOfMapOfShape it;
+  TopTools_ListIteratorOfListOfShape itl;
+  TopExp_Explorer exp;
+
+#ifdef PART_PERF
+  OSD_Chronometer aCron;
+#endif
+
+  if (myDoneStep > TopAbs_VERTEX) {
+
+    TopTools_ListOfShape aListFaces;
+    aListFaces = myImagesFaces.Roots();
+    for (it.Initialize(myMapTools); it.More(); it.Next())
+      aListFaces.Append(it.Key());
+
+#ifdef PART_PERF
+    aCron.Start();
+#endif
+
+    //-----------------------------------------------
+    // Intersection between faces
+    //-----------------------------------------------
+    // result is in myAsDes as a map Face - list of new edges;
+    // special care is done for section edges, same domain faces and vertices:
+    // data about them is inside myInter3d
+    myInter3d.CompletPart3d(aListFaces, myFaceShapeMap);
+
+#ifdef PART_PERF
+    MESSAGE("+++ CompletPart3d()");
+    aCron.Show( cout );
+    aCron.Reset();
+    aCron.Start();
+#endif
+    //-----------------------------------------------
+    // Intersection of edges
+    //-----------------------------------------------
+
+    // add tool faces which must be reconstructed to myMapFaces too
+    FindToolsToReconstruct();
+
+#ifdef PART_PERF
+    MESSAGE("+++ FindToolsToReconstruct()");
+    aCron.Show( cout );
+    aCron.Reset();
+    aCron.Start();
+#endif
+
+    // add existing vertices to edges of object faces in myAsDes
+    TopTools_MapOfShape DoneEM;
+    for ( it.Initialize(myMapFaces); it.More(); it.Next()) {
+      const TopoDS_Shape& F  = it.Key();
+      TopoDS_Face FForward = TopoDS::Face(F.Oriented(TopAbs_FORWARD));
+      for (exp.Init(FForward,TopAbs_EDGE); exp.More(); exp.Next()) {
+        const TopoDS_Edge& E = TopoDS::Edge( exp.Current() );
+        myAsDes->Add(FForward,E);
+        if (DoneEM.Add(E)) {
+          TopoDS_Iterator itV(E);
+          for (; itV.More(); itV.Next()) {
+            const TopoDS_Vertex& V = TopoDS::Vertex( itV.Value());
+            myAsDes->Add(E, myInter3d.ReplaceSameDomainV( V, E ));
+          }
+        }
+      }
+    }
+
+    // intersect edges that are descendants of a face in myAsDes
+    TopTools_MapOfShape& Modif = myInter3d.TouchedFaces();
+    for ( it.Initialize(Modif); it.More(); it.Next()) {
+      const TopoDS_Face& F  = TopoDS::Face(it.Key());
+      Partition_Inter2d::CompletPart2d (myAsDes, F, myInter3d.NewEdges());
+    }
+    // now myAsDes contains also new vertices made at edge intersection as
+    // descendant of edges both new and old
+
+    myDoneStep = TopAbs_VERTEX;
+    
+#ifdef PART_PERF
+    MESSAGE("+++ CompletPart2d()");
+    aCron.Show( cout );
+    aCron.Reset();
+    aCron.Start();
+#endif
+  } //   if (myDoneStep > TopAbs_VERTEX)
+  
+  if (Limit == TopAbs_VERTEX) {
+    // add new vertices to myShape
+    for ( it.Initialize( myInter3d.NewEdges() ); it.More(); it.Next()) {
+      if (! myAsDes->HasDescendant( it.Key() ))
+        continue;
+      itl.Initialize( myAsDes->Descendant( it.Key() ));
+      for (; itl.More(); itl.Next()) 
+        myBuilder.Add ( myShape, itl.Value() );
+    }
+    return;
+  }
+  
+
+  if (myDoneStep > TopAbs_EDGE) {
+
+    //-----------------------------------------------
+    //-----------------------------------------------
+    // ------- Reconstruction of all the edges.------
+    //-----------------------------------------------
+    //-----------------------------------------------
+
+    // ==============
+    // cut new edges
+    // ==============
+    TopTools_ListOfShape LSE; // all edge splits
+    for ( it.Initialize(myInter3d.NewEdges()); it.More(); it.Next()) {
+
+      TopoDS_Vertex V1,V2;
+      TopoDS_Edge EE = TopoDS::Edge(it.Key());
+
+      TopTools_ListOfShape aListV, aListF;
+      aListV = myAsDes->Descendant(EE); // intersection vertices
+      aListF = myAsDes->Ascendant(EE);  // intersected faces
+
+      if (aListV.IsEmpty())
+        continue;  // new edge does not intersect any other edge
+
+      // Add end vertices to new edges only if 
+      // one face is Tool and the other is Shape
+      Standard_Boolean isTool1 = ! myMapFaces.Contains( aListF.First() );
+      Standard_Boolean isTool2 = ! myMapFaces.Contains( aListF.Last() );
+      if (isTool1 || isTool2)
+      {
+        TopExp::Vertices(EE,V1,V2);
+	Standard_Real Tol = Max (BRep_Tool::Tolerance( V1 ),
+				 BRep_Tool::Tolerance( V2 ));
+
+        gp_Pnt P1 = BRep_Tool::Pnt(V1);
+        gp_Pnt P2 = BRep_Tool::Pnt(V2);
+        Standard_Boolean AddV1 = Standard_True;
+        Standard_Boolean AddV2 = Standard_True;
+
+        // add only if there is no intersection at end vertex
+        for (itl.Initialize(aListV); itl.More(); itl.Next()) {
+          const TopoDS_Vertex& Ve = TopoDS::Vertex(itl.Value()) ;
+          Standard_Real Tol2 = Max ( Tol, BRep_Tool::Tolerance( Ve ));
+          Tol2 *= Tol2;
+          gp_Pnt P = BRep_Tool::Pnt(Ve);
+          if (AddV1 && P.SquareDistance(P1) <= Tol2)
+            AddV1 = Standard_False;
+
+          if (AddV2 && P.SquareDistance(P2) <= Tol2) 
+            AddV2 = Standard_False;
+        }
+
+        if (AddV1) {
+          aListV.Append(V1);
+          myAsDes->Add(EE,V1);
+        }
+
+        if (AddV2) {
+          aListV.Append(V2);
+          myAsDes->Add(EE,V2);
+        }
+      }
+
+      // cut new edges
+      Standard_Integer NbV=aListV.Extent() ;
+      if (NbV>1 || (NbV==1 && V1.IsSame(V2)) ) {
+        TopTools_ListOfShape LNE;
+        MakeEdges (EE,aListV, LNE);
+        myImagesEdges.Bind(EE,LNE);
+	LSE.Append( LNE );
+      }
+    }
+
+    // ==============
+    // cut old edges
+    // ==============
+    for ( it.Initialize(myMapFaces); it.More(); it.Next()) {
+      for (exp.Init( it.Key(), TopAbs_EDGE); exp.More(); exp.Next()) {
+        const TopoDS_Edge& EE = TopoDS::Edge( exp.Current() );
+        if ( myImagesEdges.HasImage( EE ))
+          continue;
+        TopTools_ListOfShape  LNE;
+        const TopTools_ListOfShape& aListVV = myAsDes->Descendant(EE);
+        MakeEdges (EE, aListVV, LNE);
+        myImagesEdges.Bind(EE,LNE);
+	LSE.Append( LNE );
+      }
+    }
+#ifdef PART_PERF
+    MESSAGE("+++ Cut Edges");
+    aCron.Show( cout );
+    aCron.Reset();
+    aCron.Start();
+#endif
+
+    // process same domain section edges
+    MergeEqualEdges( LSE );
+    
+    myDoneStep = TopAbs_EDGE;
+    
+#ifdef PART_PERF
+    MESSAGE("+++ MergeEqualEdges()");
+    aCron.Show( cout );
+    aCron.Reset();
+    aCron.Start();
+#endif
+  }  //   if (myDoneStep > TopAbs_EDGE) 
+
+  if (Limit == TopAbs_EDGE) {
+    // add splits of old edges
+    TopTools_ListIteratorOfListOfShape itNE;
+    for (itl.Initialize( myListShapes );itl.More();itl.Next()) {
+      if (myMapTools.Contains( itl.Value() ))
+        continue; // skip tool faces
+      for ( exp.Init( itl.Value(), TopAbs_EDGE ); exp.More(); exp.Next()) {
+	itNE.Initialize( myImagesEdges.Image( exp.Current() ));
+	for ( ; itNE.More(); itNE.Next())
+	  myBuilder.Add ( myShape, itNE.Value() );
+      }
+    }
+    // add splits of new edges
+    for ( it.Initialize( myInter3d.NewEdges() ); it.More(); it.Next()) {
+      itNE.Initialize( myImagesEdges.Image( it.Key() ));
+      for (; itNE.More(); itNE.Next())
+        myBuilder.Add ( myShape, itNE.Value() );
+    }
+    return;
+  }
+  
+  
+  //-----------------------------------------------
+  // split faces
+  //-----------------------------------------------
+
+  if (myDoneStep > TopAbs_FACE) {
+    
+    for (itl.Initialize(myListShapes);itl.More();itl.Next()) {
+      TopoDS_Shape FacesComp = MakeFaces ( itl.Value());
+      // there is a cunning here: myImagesFaces keeps faces made by Loop2d
+      // but some of them may be replaced with splits of same domain face
+      // and myImageShape keeps ultimate result
+      myImageShape.Bind( itl.Value(), FacesComp );
+    }
+    
+    myDoneStep = TopAbs_FACE;
+#ifdef PART_PERF
+    MESSAGE("+++ MakeFaces()");
+    aCron.Show( cout );
+    aCron.Reset();
+    aCron.Start();
+#endif
+  }
+  
+  if (Limit == TopAbs_WIRE ||
+      Limit == TopAbs_FACE)   {
+    for (itl.Initialize(myListShapes);itl.More();itl.Next()) {
+      if ( myMapTools.Contains( itl.Value() ))
+	continue; // no result needed for a tool face
+      const TopoDS_Shape& FacesComp = myImageShape.Image( itl.Value() ).First();
+      for ( exp.Init( FacesComp, Limit); exp.More(); exp.Next())
+	myBuilder.Add ( myShape, exp.Current());
+    }
+    return;
+  }
+
+  
+  //-----------------------------------------------
+  // split and add solids and shells
+  //-----------------------------------------------
+
+  Standard_Boolean makeSolids = (Limit == TopAbs_SHAPE ||
+				 Limit < TopAbs_SHELL);
+  for (itl.Initialize(myListShapes);itl.More();itl.Next())
+  {
+    const TopoDS_Shape & S = itl.Value();
+    if (S.ShapeType() > TopAbs_SHELL)
+      continue;
+
+    TopTools_ListOfShape NSL; // new shape list
+    MakeShells (S , NSL);
+    if (makeSolids && S.ShapeType() == TopAbs_SOLID )
+      MakeSolids( S, NSL );
+
+    // store new shells or solids
+    TopTools_ListIteratorOfListOfShape itNSL (NSL);
+    for ( ; itNSL.More(); itNSL.Next()) 
+      myBuilder.Add (myShape, itNSL.Value());
+  }
+#ifdef PART_PERF
+    MESSAGE("+++ MakeShells()");
+    aCron.Show( cout );
+#endif
+
+  //-----------------------------------------------
+  // add split faces
+  //-----------------------------------------------
+
+  for (itl.Initialize(myListShapes);itl.More();itl.Next())
+  {
+    const TopoDS_Shape & S = itl.Value();
+    if (S.ShapeType() != TopAbs_FACE ||
+        myMapTools.Contains( S ))
+      continue; 
+    TopoDS_Iterator itS( myImageShape.Image(S).First() );
+    for (; itS.More(); itS.Next())
+      if (! myAddedFacesMap.Contains( itS.Value() ))
+        myBuilder.Add (myShape, itS.Value());
+  }
+
+  myDoneStep = makeSolids ? TopAbs_SOLID : TopAbs_SHELL;
+  
+}
+
+//=======================================================================
+//function : MakeSolids
+//purpose  : make solids out of Shells
+//=======================================================================
+
+void Partition_Spliter::MakeSolids(const TopoDS_Shape &   theSolid,
+                                   TopTools_ListOfShape & theShellList)
+{
+  // for a solid wrapping other shells or solids without intersection,
+  // it is necessary to find shells making holes in it
+
+  TopTools_ListOfShape aNewSolids; // result
+  TopTools_ListOfShape aHoleShells;
+  TopoDS_Shape anInfinitePointShape;
+
+  Standard_Boolean isWrapping = myWrappingSolid.Contains( theSolid );
+  if (!isWrapping && !theShellList.IsEmpty())
+  {
+    // check if theSolid initially has internal shells
+    TopoDS_Iterator aShellExp (theSolid);
+    aShellExp.Next();
+    isWrapping = aShellExp.More();
+  }
+  
+  TopTools_ListIteratorOfListOfShape aShellIt(theShellList);
+  for ( ; aShellIt.More(); aShellIt.Next())
+  {
+    const TopoDS_Shape & aShell = aShellIt.Value();
+
+    // check if a shell is a hole
+    if (isWrapping && IsInside (anInfinitePointShape, aShell))
+      aHoleShells.Append( aShell );
+    else
+    {
+      // make a solid from a shell
+      TopoDS_Solid Solid;
+      myBuilder.MakeSolid( Solid );
+      myBuilder.Add (Solid, aShell);
+
+      aNewSolids.Append (Solid);
+    }
+  }
+
+  // find an outer shell most close to each hole shell
+  TopTools_DataMapOfShapeShape aInOutMap;
+  for (aShellIt.Initialize( aHoleShells ); aShellIt.More(); aShellIt.Next())
+  {
+    const TopoDS_Shape & aHole = aShellIt.Value();
+    TopTools_ListIteratorOfListOfShape aSolisIt (aNewSolids);
+    for ( ; aSolisIt.More(); aSolisIt.Next())
+    {
+      const TopoDS_Shape & aSolid = aSolisIt.Value();
+      if (! IsInside( aHole, aSolid ))
+        continue;
+
+      if ( aInOutMap.IsBound (aHole))
+      {
+        const TopoDS_Shape & aSolid2 = aInOutMap( aHole );
+        if ( IsInside( aSolid, aSolid2 ))
+        {
+          aInOutMap.UnBind( aHole );
+          aInOutMap.Bind ( aHole, aSolid );
+        }
+      }
+      else
+        aInOutMap.Bind ( aHole, aSolid );
+    }
+
+    // add aHole to a solid
+    if (aInOutMap.IsBound( aHole ))
+      myBuilder.Add ( aInOutMap( aHole ), aHole );
+  }
+
+  theShellList.Clear();
+  theShellList.Append( aNewSolids );
+}
+ 
+//=======================================================================
+//function : FindFacesInside
+//purpose  : return compound of faces  of other shapes that are
+//           inside <theShape>. 
+//           <theShape> is an object shape.
+//           <CheckClosed> makes avoid faces that do not form a
+//           closed shell
+//           <All> makes return already added faces
+//=======================================================================
+
+TopoDS_Shape Partition_Spliter::FindFacesInside(const TopoDS_Shape& theShape,
+						const Standard_Boolean CheckClosed,
+						const Standard_Boolean All)
+{
+  // ================================================
+  // check if internal faces have been already found
+  // ================================================
+  TopExp_Explorer expl;
+  if (myInternalFaces.IsBound( theShape ))
+  {
+    TopoDS_Shape aIntFComp = myInternalFaces.Find ( theShape );
+    TopoDS_Shape aIntRemFComp = myIntNotClFaces.Find ( theShape );
+
+    expl.Init( aIntRemFComp, TopAbs_FACE);
+    if (CheckClosed || !expl.More())
+      return aIntFComp;
+
+    TopoDS_Compound C;
+    myBuilder.MakeCompound( C );
+    // add removed faces
+    for (; expl.More(); expl.Next())
+      myBuilder.Add( C, expl.Current() );
+    // add good internal faces
+    for (expl.Init( aIntFComp, TopAbs_FACE); expl.More(); expl.Next())
+      myBuilder.Add( C, expl.Current() );
+    return C;
+  }
+
+  // ===================================
+  // get data for internal faces search
+  // ===================================
+
+  // compound of split faces of theShape 
+  const TopoDS_Shape& CSF = myImageShape.Image(theShape).First();
+
+  TopTools_MapOfShape MSE, MFP;
+  TopTools_DataMapOfShapeListOfShape DMSEFP;
+  TopTools_MapIteratorOfMapOfShape itm;
+  TopTools_ListOfShape EmptyL;
+
+  // MSE filling: map of new section edges of CSF
+  for (expl.Init(CSF,TopAbs_EDGE); expl.More(); expl.Next()) {
+    const TopoDS_Shape & resE = expl.Current() ;
+    if (myNewSection.Contains( resE )) // only new edges
+      MSE.Add(resE);
+  }
+
+  // DMEF: map edge of CSF - faces of CSF
+  TopTools_IndexedDataMapOfShapeListOfShape DMEF;
+  TopExp::MapShapesAndAncestors(CSF, TopAbs_EDGE, TopAbs_FACE, DMEF);
+
+  // Fill
+  // 1.  MFP - a map of faces to process: map of resulting faces except
+  // those of theShape; we`ll add to C those of them which are inside CSF
+  // 2.  DMSEFP - edge of MSE => faces of MFP
+  TopTools_ListIteratorOfListOfShape itl;
+  for (itl.Initialize(myListShapes);itl.More();itl.Next()) {
+    const TopoDS_Shape& aShape = itl.Value();
+    if ( theShape.IsSame( aShape )) continue;
+    // fill maps
+    // iterate on split faces of aShape
+    TopoDS_Iterator itF ( myImageShape.Image(aShape).First() );
+    for ( ; itF.More(); itF.Next()) {
+      const TopoDS_Shape& sf = itF.Value();
+      MFP.Add(sf);
+      // iterate on edges of split faces of aShape,
+      // add to DMSEFP edges that are new
+      for (expl.Init( sf, TopAbs_EDGE ); expl.More(); expl.Next()) {
+	TopoDS_Shape se = expl.Current();
+	if ( MSE.Contains(se)) {// section edge
+	  if (!DMSEFP.IsBound(se)) 
+	    DMSEFP.Bind(se,EmptyL);
+	  DMSEFP(se).Append(sf);
+	}
+      }
+    }
+  }
+
+  // add tool faces having section edges on faces of theShape to MFP and DMSEFP;
+  // such tool faces need not to be reconstructed and so they are not in myListShapes
+  for (itm.Initialize(myMapTools); itm.More(); itm.Next())
+  {
+    const TopoDS_Shape & aToolFace = itm.Key();
+    if (myMapFaces.Contains( aToolFace ))
+      continue;
+    MFP.Add(aToolFace);
+    for (expl.Init( aToolFace, TopAbs_EDGE ); expl.More(); expl.Next()) {
+      TopoDS_Shape se = expl.Current();
+      if ( MSE.Contains( se )) {// section edge
+        if (!DMSEFP.IsBound( se )) 
+          DMSEFP.Bind( se, EmptyL );
+        DMSEFP( se ).Append( aToolFace );
+      }
+    }
+  }
+  
+
+  // ===========================
+  // find faces inside theShape
+  // ===========================
+
+  Standard_Boolean skipAlreadyAdded = Standard_False;
+  Standard_Boolean GoodOri, inside;
+  Standard_Real dot;
+  TopTools_ListOfShape KeepFaces;
+  TopTools_DataMapIteratorOfDataMapOfShapeListOfShape Mapit;
+
+  // iterate on section edges, check faces of other shapes
+  // sharing section edges and put internal faces to KeepFaces
+  for (Mapit.Initialize(DMSEFP); Mapit.More() ; Mapit.Next() ) {
+    // a new edge of theShape
+    const TopoDS_Edge& E = TopoDS::Edge (Mapit.Key());
+    // an original edge of which E is a split
+    const TopoDS_Edge& OrigE = TopoDS::Edge ( myImagesEdges.Root( E ));
+    // does OrigE itself splits a face
+    Standard_Boolean isSectionE = myInter3d.IsSectionEdge ( OrigE );
+
+    // split faces of other shapes sharing E
+    TopTools_ListOfShape& LSF = DMSEFP.ChangeFind(E);
+    itl.Initialize( LSF );
+    while (itl.More()) {
+      // a split faces of other shape
+      TopoDS_Face aFace1 = TopoDS::Face(itl.Value());
+      // remove aFace1 form DMSEFP and MFP
+      LSF.Remove( itl ); // == itl.Next();
+      if (!MFP.Remove( aFace1 ))
+	continue; // was not is MFP ( i.e already checked)
+      // check if aFace1 was already added to 2 shells
+      if (!All &&
+	  myAddedFacesMap.Contains( aFace1 ) &&
+	  myAddedFacesMap.Contains( aFace1.Reversed() )) {
+	skipAlreadyAdded = Standard_True;
+	continue;
+      }
+
+      // find another face which originates from the same face as aFace1:
+      // usually aFace2 is internal if aFace1 is not and vice versa
+
+      TopoDS_Shape anOrigFace = aFace1;
+      if (myImagesFaces.IsImage(aFace1))
+        anOrigFace = myImagesFaces.Root(aFace1);
+      TopoDS_Shape aFace2;
+      if ( !isSectionE ) {
+        while (itl.More()) {
+          aFace2 = itl.Value();
+          if (!MFP.Contains( aFace2 )) {
+            LSF.Remove( itl );
+            continue;
+          }
+          if (anOrigFace.IsSame( myImagesFaces.Root( aFace2 )))
+            break;
+          itl.Next();
+        }
+        if (itl.More()) { // aFace2 found, remove it from maps
+          LSF.Remove( itl );
+          MFP.Remove(aFace2);
+        }
+        else
+          aFace2.Nullify();
+        itl.Initialize( LSF );
+      }
+
+      // check that anOrigFace is not same domain with CSF faces it intersects
+
+      const TopTools_ListOfShape& FL = DMEF.FindFromKey(E); //faces of CSF sharing E
+      const TopoDS_Shape& origF1 = myImagesFaces.Root(FL.First());
+      const TopoDS_Shape& origF2 = myImagesFaces.Root(FL.Last());
+      Standard_Boolean sameDom1 = anOrigFace.IsSame( origF1 );
+      Standard_Boolean sameDom2 = anOrigFace.IsSame( origF2 );
+      if (!(sameDom1 || sameDom2) && myInter3d.HasSameDomainF( anOrigFace )) {
+	sameDom1 = myInter3d.IsSameDomainF( anOrigFace, origF1);
+        if (origF1 == origF2)
+          sameDom2 = sameDom1;
+        else
+          myInter3d.IsSameDomainF( anOrigFace, origF2);
+      }
+      if (sameDom1 && sameDom2)
+	continue;
+      if ((sameDom1 || sameDom2)) {
+	inside = Partition_Loop3d::IsInside (E,
+					     TopoDS::Face(FL.First()),
+					     TopoDS::Face(FL.Last()),
+					     1, dot, GoodOri);
+	if (inside || (dot + Precision::Angular() >= 1.0))
+	  continue; // E is convex between origF1 and origF2 or they are tangent
+      }
+
+
+      // keep one of found faces
+
+      //face of CSF sharing E
+      const TopoDS_Shape& aShapeFace = sameDom1 ? FL.Last() : FL.First();
+      // analyse aFace1 state
+      inside = Partition_Loop3d::IsInside (E, TopoDS::Face(aShapeFace), aFace1,
+					   1, dot, GoodOri);
+      if (inside && isSectionE)
+      {
+        // aFace1 must be tested with both adjacent faces of CSF
+        const TopoDS_Shape& aShapeFace2 = sameDom1 ? FL.First() : FL.Last();
+        if (aShapeFace2 != aShapeFace)
+          inside = Partition_Loop3d::IsInside (E, TopoDS::Face(aShapeFace2), aFace1,
+                                               1, dot, GoodOri);
+      }
+
+      // store internal face
+      if (inside)
+        KeepFaces.Append(aFace1);
+
+      else if (!aFace2.IsNull())
+      {
+        if (dot + Precision::Angular() >= 1.0)
+        {
+          // aFace2 state is not clear, it will be analysed alone,
+          // put it back to the maps
+          MFP.Add( aFace2 );
+          LSF.Append( aFace2 );
+        }
+        else
+          KeepFaces.Append(aFace2);
+      }
+    }
+  }
+
+  // ===================================================
+  // add not distributed faces connected with KeepFaces
+  // ===================================================
+
+  // ultimate list of internal faces
+  TopTools_ListOfShape KeptFaces;
+
+  // add to MFP not split tool faces as well, they may be connected with
+  // tool faces interfering with theShape
+  for ( itm.Initialize(myMapTools); itm.More(); itm.Next() ) {
+    const TopoDS_Shape& aToolFace = itm.Key();
+    if (!myImageShape.HasImage(aToolFace))
+      MFP.Add (aToolFace);
+  }
+
+  if (MFP.IsEmpty())
+    KeptFaces.Append (KeepFaces);
+
+  while (!KeepFaces.IsEmpty())
+  {
+    // KeepEdges : map of edges of faces kept last time
+    TopTools_IndexedMapOfShape KeepEdges;
+    for ( itl.Initialize(KeepFaces); itl.More(); itl.Next() ) {
+      TopExp::MapShapes( itl.Value(), TopAbs_EDGE, KeepEdges);
+      KeptFaces.Append( itl.Value() );
+    }
+
+    KeepFaces.Clear();
+
+    // keep faces connected with already kept faces by KeepEdges
+    for ( itm.Initialize(MFP); itm.More(); itm.Next() ) {
+      const TopoDS_Shape& FP = itm.Key();
+      for (expl.Init(FP,TopAbs_EDGE); expl.More(); expl.Next()) {
+        const TopoDS_Shape& se = expl.Current();
+        if (!MSE.Contains(se) && KeepEdges.Contains(se) ) {
+          KeepFaces.Append(FP);
+          MFP.Remove(FP);
+          break;
+        }
+      }
+    }
+  }
+
+  // ===============================================================
+  // here MFP contains faces outer of theShape and those of shapes
+  // which do not interfere with theShape at all and between which
+  // there may be those wrapped by theShape and whose faces may be
+  // needed to be returned as well
+  // ===============================================================
+
+  Standard_Boolean isSolid = (theShape.ShapeType() == TopAbs_SOLID);
+  if (All || isSolid)  // All is for sub-result removal
+  {
+    // loop on not used faces; checked faces will be removed from MFP
+    // during the loop
+    for ( itm.Initialize( MFP ); itm.More(); itm.Next() ) {
+      const TopoDS_Shape & aFace = itm.Key();
+
+      // a shape which aFace originates from
+      TopoDS_Shape anOrigShape = GetOriginalShape( aFace );
+
+      // find out if all split faces of anOrigShape are not in MFP
+      // and by the way remove them from MFP
+      Standard_Boolean isAllOut = Standard_True;
+      TopoDS_Shape aSplitFaces = anOrigShape;
+      if (myImageShape.HasImage(anOrigShape))
+        aSplitFaces = myImageShape.Image(anOrigShape).First();
+
+      TopTools_ListOfShape aSplitFaceL; // faces candidate to be kept
+      for (expl.Init( aSplitFaces, TopAbs_FACE ); expl.More(); expl.Next())
+      {
+        const TopoDS_Shape & aSpFace = expl.Current();
+        // a tool face which became object has image but the whole tool shape has not
+        if (myImageShape.HasImage( aSpFace ))
+        {
+          TopExp_Explorer exF (myImageShape.Image( aSpFace ).First(), TopAbs_FACE );
+          for ( ; exF.More(); exF.Next() )
+          {
+            aSplitFaceL.Append( exF.Current() );
+            if ( ! MFP.Remove( exF.Current() ) && isAllOut )
+              // a shared face might be removed from MFP during a prev loop
+              isAllOut = mySharedFaces.Contains( exF.Current() );
+          }
+        }
+        else
+        {
+          aSplitFaceL.Append( aSpFace );
+          if ( ! MFP.Remove( aSpFace ) && isAllOut)
+            // a shared face might be removed from MFP during a prev loop
+            isAllOut = mySharedFaces.Contains( aSpFace );
+        }
+      }
+      itm.Initialize( MFP ); // iterate remaining faces
+      if ( !isAllOut )
+        continue;
+
+      // classify anOrigShape against theShape
+      if (IsInside (anOrigShape, theShape))
+      {
+        if (isSolid && myClosedShapes.Contains( anOrigShape ))
+          // to make a special care at solid reconstruction
+          myWrappingSolid.Add ( theShape );
+
+        // keep faces of an internal shape anOrigShape
+        KeptFaces.Append( aSplitFaceL );
+      }
+    }
+  }
+
+  // ====================================================
+  // check if kept faces form a shell without free edges
+  // ====================================================
+
+  DMEF.Clear();  // edge - kept faces
+  MFP.Clear(); // reuse it for wrong faces
+  if (CheckClosed) {
+    for (itl.Initialize(KeptFaces); itl.More(); itl.Next() ) 
+      TopExp::MapShapesAndAncestors(itl.Value(), TopAbs_EDGE, TopAbs_FACE, DMEF);
+
+    Standard_Integer i, nb = DMEF.Extent();
+    Standard_Boolean isClosed = Standard_False;
+    while (!isClosed) {
+      isClosed = Standard_True;
+      for (i=1;  isClosed && i<=nb;  ++i) {
+        const TopoDS_Shape& E = DMEF.FindKey( i );
+        if (! BRep_Tool::Degenerated( TopoDS::Edge( E )) &&
+            ! MSE.Contains( E ))
+          isClosed = ( DMEF(i).Extent() != 1 );
+      }
+      if (!isClosed) {
+        const TopoDS_Shape& F = DMEF.FindFromIndex( i-1 ).First(); // bad face
+        MFP.Add( F ); 
+        // remove bad face from DMEF
+        for (expl.Init( F, TopAbs_EDGE); expl.More(); expl.Next()) {
+	  const TopoDS_Shape& E = expl.Current();
+          TopTools_ListOfShape& FL = DMEF.ChangeFromKey( E );
+          for (itl.Initialize( FL ); itl.More(); itl.Next() ) {
+            if ( F.IsSame( itl.Value() )) {
+              FL.Remove( itl );
+              break;
+            }
+          }
+        }
+      }
+    }
+  }
+
+  // ==============
+  // make a result
+  // ==============
+
+  TopoDS_Compound C;
+  // compound of removed internal faces
+  TopoDS_Compound CNotCl;
+
+  myBuilder.MakeCompound(C);
+  myBuilder.MakeCompound(CNotCl);
+
+  // add to compounds
+  for (itl.Initialize(KeptFaces); itl.More(); itl.Next() )
+  {
+    TopoDS_Shape & aIntFace = itl.Value();
+    if (! MFP.Contains( aIntFace ))
+      myBuilder.Add( C, aIntFace);
+    else
+      myBuilder.Add( CNotCl, aIntFace);
+  }
+
+  if (!skipAlreadyAdded && CheckClosed)
+  {
+    myInternalFaces.Bind( theShape, C );
+    myIntNotClFaces.Bind( theShape, CNotCl );
+  }
+
+  return C;
+}
+
+//=======================================================================
+//function : MakeShell
+//purpose  : split S into compound of shells
+//=======================================================================
+
+void Partition_Spliter::MakeShells(const TopoDS_Shape& S,
+                                   TopTools_ListOfShape& NS)
+{
+  Partition_Loop3d ShellMaker;
+  // get compound of split faces of S
+  const TopoDS_Shape& FacesComp = myImageShape.Image(S).First();
+  ShellMaker.AddConstFaces( FacesComp );
+  // add split faces inside S
+  if (myClosedShapes.Contains( S )) {
+    TopoDS_Shape InternalFacesComp = FindFacesInside(S, Standard_True);
+    ShellMaker.AddSectionFaces( InternalFacesComp );
+  }
+  
+  NS = ShellMaker.MakeShells( myAddedFacesMap );
+
+  // Add faces added to new shell to myAddedFacesMap:
+  // avoid rebuilding twice commont part of 2 solids.
+  TopTools_ListIteratorOfListOfShape itS(NS);
+  while ( itS.More()) {
+    TopExp_Explorer expF (itS.Value(), TopAbs_FACE);
+    for (; expF.More(); expF.Next())
+      myAddedFacesMap.Add (expF.Current());
+    
+    itS.Next();
+  }
+}
+
+//=======================================================================
+//function : findEqual
+//purpose  : compare edges of EL1 against edges of EL2,
+//           Result is in EMM binding EL1 edges to list of equal edges.
+//           Edges are considered equall only if they have same vertices.
+//           <addSame>==True makes consider same edges as equal
+//           Put in <AllEqMap> all equal edges
+//=======================================================================
+
+static void findEqual (const TopTools_ListOfShape& EL1,
+		       const TopTools_ListOfShape& EL2,
+		       const Standard_Boolean addSame,
+		       TopTools_DataMapOfShapeListOfShape& EEM,
+		       TopTools_MapOfShape& AllEqMap)
+{
+  // map vertices to edges for EL2
+  TopTools_DataMapOfShapeListOfShape VEM;
+  TopTools_ListIteratorOfListOfShape itE1, itE2(EL2);
+  TopoDS_Iterator itV;
+  TopTools_ListOfShape emptyL;
+  for (; itE2.More(); itE2.Next()) {
+    for (itV.Initialize( itE2.Value() ); itV.More(); itV.Next()) {
+      const TopoDS_Shape& V = itV.Value(); 
+      if (! VEM.IsBound( V ) )
+	VEM.Bind( V, emptyL);
+      VEM( V ).Append( itE2.Value());
+    }
+  }
+
+  gp_Vec D1, D2;
+  gp_Pnt P;
+  Standard_Real f,l,u,tol;
+  Handle(Geom_Curve) C1, C2;
+  Extrema_ExtPC Extrema;
+  TopoDS_Vertex V1, V2, V3, V4;
+
+  AllEqMap.Clear();
+  
+  for (itE1.Initialize(EL1); itE1.More(); itE1.Next()) {
+    const TopoDS_Edge& E1 = TopoDS::Edge( itE1.Value());
+    if (BRep_Tool::Degenerated( E1 ) || AllEqMap.Contains (E1))
+      continue;
+    TopExp::Vertices( E1, V1, V2 );
+
+    if (VEM.IsBound(V1))
+      itE2.Initialize( VEM(V1) );
+    for (; itE2.More(); itE2.Next()) {
+      const TopoDS_Edge& E2 = TopoDS::Edge( itE2.Value());
+      if (BRep_Tool::Degenerated( E2 ) || AllEqMap.Contains (E2))
+        continue;
+
+      if (E1.IsSame(E2)) {
+	if (!addSame)
+	  continue;
+      }
+      else {
+	TopExp::Vertices( E2, V3, V4);
+	if (!V2.IsSame(V4) && !V2.IsSame(V3))
+	  continue;
+	// E1 and E2 have same vertices
+	// check D1 at end points.
+        C2 = BRep_Tool::Curve( E2, f,l);
+        C1 = BRep_Tool::Curve( E1, f,l);
+	u = BRep_Tool::Parameter(V1,E1);
+        C1->D1(u, P, D1);
+	u = BRep_Tool::Parameter(V1.IsSame(V3) ? V3 : V4, E2);
+	C2->D1(u, P, D2);
+        D1.Normalize(); D2.Normalize();
+        if (Abs(D1*D2) + Precision::Angular() < 1.0)
+          continue;
+	if (! V1.IsSame(V2)) {
+	  u = BRep_Tool::Parameter(V2,E1);
+	  C1->D1(u, P, D1);
+	  u = BRep_Tool::Parameter(V2.IsSame(V3) ? V3 : V4, E2);
+	  C2->D1(u, P, D2);
+	  D1.Normalize(); D2.Normalize();
+	  if (Abs(D1*D2) + Precision::Angular() < 1.0)
+	    continue;
+	}
+        // check distance at a couple of internal points
+        tol = Max(BRep_Tool::Tolerance(E1),
+                  BRep_Tool::Tolerance(E2));
+        GeomAdaptor_Curve AC1(C1);
+        Extrema.Initialize(AC1,f,l);
+	Standard_Boolean ok = Standard_True, hasMin = Standard_False;
+	BRep_Tool::Range( E2, f, l);
+        Standard_Integer i=1, nbi=3;
+        for (; i<nbi && ok; ++i) {
+          Extrema.Perform( C2->Value( f+(l-f)*i/nbi ));
+          Standard_Integer j=1, nbj=Extrema.NbExt();
+          for (; j<=nbj && ok; ++j) {
+            if (Extrema.IsMin(j)) {
+	      hasMin = Standard_True;
+	      ok = Extrema.Value(j) <= tol;  // V6.3
+	      // ok = Extrema.SquareDistance(j) <= tol;  // V6.5
+	    }
+          }
+        }
+        if ( !hasMin || !ok)
+          continue;
+      }
+      // bind E2 to E1 in EEM
+      if (!EEM.IsBound(E1)) {
+        EEM.Bind (E1, emptyL);
+	AllEqMap.Add (E1);
+      }
+      EEM(E1).Append(E2);
+      AllEqMap.Add (E2);
+    }
+  }
+}
+
+//=======================================================================
+//function : MakeFaces
+//purpose  : split faces of S, return compound of new faces
+//=======================================================================
+
+TopoDS_Shape Partition_Spliter::MakeFaces (const TopoDS_Shape& S)
+{
+  TopoDS_Compound C;
+  myBuilder.MakeCompound(C);
+  
+  TopTools_ListIteratorOfListOfShape itl, itNE;
+  
+  TopExp_Explorer exp(S,TopAbs_FACE);
+  for (; exp.More(); exp.Next()) {
+
+    const TopoDS_Face& F = TopoDS::Face(exp.Current());
+
+    TopTools_ListOfShape LNF;
+    
+    if (myImagesFaces.HasImage( F )) {
+      myImagesFaces.LastImage( F, LNF );
+      TopAbs_Orientation oriF = F.Orientation();
+      for ( itl.Initialize( LNF ); itl.More(); itl.Next())
+	itl.Value().Orientation( oriF );
+    }
+    else {
+
+      Partition_Loop2d loops;
+      loops.Init(F);
+
+      TopTools_IndexedMapOfShape EM;
+      TopExp::MapShapes( F, TopAbs_EDGE, EM);
+
+      TopTools_MapOfShape AddedEqualM, EqualSeamM;
+      Standard_Boolean needRebuild = Standard_False;
+
+      // add splits to loops
+
+      // LE: old edges + new not splitted edges
+      const TopTools_ListOfShape& LE = myAsDes->Descendant(F);
+      for (itl.Initialize(LE); itl.More(); itl.Next()) {
+	const TopoDS_Edge& E = TopoDS::Edge( itl.Value() );
+
+	Standard_Boolean isSectionE = myInter3d.IsSectionEdge(E);
+	Standard_Boolean isNewE = !EM.Contains( E );
+
+	// LSE: list of split edges
+	TopTools_ListOfShape LSE;
+	myImagesEdges.LastImage(E,LSE); // splits of E or E itself
+
+	for (itNE.Initialize(LSE); itNE.More(); itNE.Next()) {
+
+	  TopoDS_Edge NE = TopoDS::Edge( itNE.Value() );
+	  Standard_Boolean isSameE = NE.IsSame ( E );
+	  
+	  if ( isNewE || isSectionE || !isSameE) {
+	    if (AddedEqualM.Contains( NE )) {
+              // a seam must be twice in a loop
+              if (!BRep_Tool::IsClosed( E, F ) || !EqualSeamM.Add( NE ))
+                continue;
+            }
+
+	    if (isNewE) {
+	      if (isSectionE) {
+		if ( ! myInter3d.IsSplitOn( NE, E, F) )
+		  continue;
+	      }
+	      else {
+		TopoDS_Vertex V1,V2;
+		TopExp::Vertices(NE,V1,V2);
+		const TopTools_ListOfShape& EL1 = myAsDes->Ascendant(V1);
+		const TopTools_ListOfShape& EL2 = myAsDes->Ascendant(V2);
+		if ( EL1.Extent() < 2 && EL2.Extent() < 2 )
+		  continue;
+	      }
+	    }
+	    else {
+	      NE.Orientation( E.Orientation());
+	      if (!isSameE) {
+		// orient NE because it may be a split of other edge
+		Standard_Real f,l,u;
+		Handle(Geom_Curve) C3d  = BRep_Tool::Curve( E,f,l );
+		Handle(Geom_Curve) NC3d = BRep_Tool::Curve( NE,f,l);
+		if ( C3d != NC3d) {
+		  gp_Vec D1, ND1;  gp_Pnt P;
+		  TopoDS_Vertex V = TopExp::FirstVertex(NE);
+		  u = BRep_Tool::Parameter(V,NE);
+		  NC3d->D1 (u, P, ND1);
+		  u = BRep_Tool::Parameter(V,E);
+		  C3d ->D1 (u, P, D1);
+		  if (ND1.Dot(D1) < 0)
+		    NE.Reverse();
+		}
+	      }
+	    }
+	    if (myEqualEdges.Contains( NE ))
+              AddedEqualM.Add( NE );
+
+	    needRebuild = Standard_True;
+	  }
+
+	  if (isNewE || isSectionE)
+	    myNewSection.Add( NE );
+
+	  if (isNewE) 
+	    loops.AddSectionEdge(NE);
+	  else
+	    loops.AddConstEdge(NE);
+	}
+      }
+
+      //-------------------
+      // Build the faces.
+      //-------------------
+      
+      if (needRebuild) {
+	
+        loops.Perform();
+        loops.WiresToFaces(myImagesEdges);
+
+        LNF = loops.NewFaces();
+
+        myImagesFaces.Bind(F,LNF);
+
+        // replace the result faces that have already been built
+        // during same domain faces reconstruction done earlier
+        if (myInter3d.HasSameDomainF( F ))
+        {
+          // build map edge to same domain faces: EFM
+          TopTools_IndexedDataMapOfShapeListOfShape EFM;
+          TopTools_MapOfShape SDFM; // avoid doubling
+          itl.Initialize( myInter3d.SameDomain( F ));
+          for (; itl.More(); itl.Next()) {
+            if ( !myImagesFaces.HasImage( itl.Value() ))
+              continue;
+            // loop on splits of a SD face
+            TopTools_ListIteratorOfListOfShape itNF;
+            itNF.Initialize (myImagesFaces.Image( itl.Value() ));
+            for ( ; itNF.More(); itNF.Next()) {
+              TopoDS_Shape SDF = itNF.Value();
+              if (myImagesFaces.HasImage( SDF )) // already replaced
+                SDF = myImagesFaces.Image( SDF ).First();
+              if (SDFM.Add (SDF))
+                TopExp::MapShapesAndAncestors(SDF, TopAbs_EDGE, TopAbs_FACE, EFM);
+            }
+          }
+          // do replace faces in the LNF
+          TopTools_ListOfShape LOF;
+          if ( !EFM.IsEmpty() )
+            itl.Initialize( LNF );
+          while (itl.More()) {
+            const TopoDS_Shape& NF = itl.Value();
+            TopExp_Explorer expE ( NF, TopAbs_EDGE );
+            const TopoDS_Edge& E  = TopoDS::Edge (expE.Current());
+            if (EFM.Contains( E )) {
+              const TopTools_ListOfShape& SDFL = EFM.FindFromKey( E );
+              TopoDS_Shape SDF = SDFL.First();
+              Standard_Boolean GoodOri;
+              Standard_Real dot;
+              Partition_Loop3d::IsInside (E, TopoDS::Face(NF), TopoDS::Face(SDF),
+                                          1, dot, GoodOri);
+              if (dot < 0)
+              {
+                // NF and SDF are on different side of E
+                if (SDFL.Extent() == 1) {
+                  itl.Next();
+                  continue;
+                }
+                else
+                  SDF = SDFL.Last(); // next face must be on the same side
+              }
+              gp_Vec V1 = Partition_Loop3d::Normal( E, TopoDS::Face( NF ));
+              gp_Vec V2 = Partition_Loop3d::Normal( E, TopoDS::Face( SDF ));
+              if (V1*V2 < 0)
+                SDF.Reverse();
+
+              if (!myImagesFaces.HasImage( NF ))
+                myImagesFaces.Bind( NF, SDF );
+
+              // mySharedFaces is used in FindFacesInside()
+              mySharedFaces.Add( SDF );
+
+              LOF.Prepend ( SDF );
+              LNF.Remove (itl);
+            }
+            else
+              itl.Next();
+          }
+
+          LNF.Append (LOF);
+        }
+      } // if (needRebuild)
+      
+      else {
+	LNF.Append( F );
+	myImagesFaces.Bind(F,LNF);
+      }
+    } // if (myImagesFaces.HasImage( F ))
+
+    // fill the resulting compound
+    for (itl.Initialize(LNF); itl.More(); itl.Next())
+      myBuilder.Add ( C, itl.Value());
+    
+  } // loop on faces of S
+
+  return C;
+}
+
+
+//=======================================================================
+//function : Tri
+//purpose  : 
+//=======================================================================
+
+static void Tri(const TopoDS_Edge&        E,
+		TopTools_SequenceOfShape& Seq,
+                const Partition_Inter3d & theInter3d)
+{
+  Standard_Boolean Invert   = Standard_True;
+  Standard_Real    U1,U2;
+  TopoDS_Vertex    V1,V2;
+
+  while (Invert) {
+    Invert = Standard_False;
+    for ( Standard_Integer i = 1; i < Seq.Length(); i++) {
+      
+      V1 = TopoDS::Vertex(Seq.Value(i));
+      V2 = TopoDS::Vertex(Seq.Value(i+1));
+      
+      V1.Orientation(TopAbs_INTERNAL);
+      V2.Orientation(TopAbs_INTERNAL);
+      
+      U1 = BRep_Tool::Parameter(V1,E);
+      U2 = BRep_Tool::Parameter(V2,E);
+      
+      if (IsEqual(U1,U2)) {
+        if (theInter3d.ReplaceSameDomainV( V1, E ).IsSame( V1 ))
+          Seq.Remove(i+1); // remove V2
+        else
+          Seq.Remove(i);
+	i--;
+	continue;
+      }
+      if (U2 < U1) {
+	Seq.Exchange(i,i+1);
+	Invert = Standard_True;
+      }
+    }
+  }
+}
+
+//=======================================================================
+//function : MakeEdges
+//purpose  : cut E by vertices VOnE, return list of new edges NE
+//=======================================================================
+
+void Partition_Spliter::MakeEdges (const TopoDS_Edge& E,
+                                   const TopTools_ListOfShape& VOnE,
+                                   TopTools_ListOfShape& NE   ) const
+{
+  TopoDS_Edge WE = E;
+  WE.Orientation(TopAbs_FORWARD);
+
+  Standard_Real    U1,U2, f, l;
+  TopoDS_Vertex    V1,V2,VF,VL;
+
+  BRep_Tool::Range(WE,f,l);
+  TopExp::Vertices(WE,VF,VL);
+
+  if (VOnE.Extent() < 3) { // do not rebuild not cut edge
+    if (( VF.IsSame( VOnE.First() ) && VL.IsSame( VOnE.Last() )) ||
+	VL.IsSame( VOnE.First() ) && VF.IsSame( VOnE.Last() )  ) {
+      NE.Append( E );
+      return;
+    }
+  }
+
+  TopTools_SequenceOfShape SV;
+  TopTools_ListIteratorOfListOfShape itv(VOnE);
+  TopTools_MapOfOrientedShape VM( VOnE.Extent() );
+  for (; itv.More(); itv.Next())
+    if ( VM.Add( itv.Value() ))
+      SV.Append(itv.Value());
+
+  Tri( WE, SV, myInter3d );
+
+  if (SV.Length() < 3) { // do not rebuild not cut edge
+    if (( VF.IsSame( SV.First() ) && VL.IsSame( SV.Last() )) ||
+	VL.IsSame( SV.First() ) && VF.IsSame( SV.Last() )  ) {
+      NE.Append( E );
+      return;
+    }
+  }
+
+  Standard_Integer iVer, NbVer = SV.Length();
+
+
+  //----------------------------------------------------------------
+  // Construction of the new edges .
+  //----------------------------------------------------------------
+
+  if (VF.IsSame(VL)) { // closed edge
+    if (NbVer==1) 
+      SV.Append( SV.First() );
+    else if (!SV.First().IsSame(SV.Last())) {
+      Standard_Boolean isFirst=0;
+      Standard_Real    minDU = 1.e10;
+      TopoDS_Vertex endV = Partition_Inter2d::FindEndVertex(VOnE, f,l, E, isFirst,minDU);
+      if (endV.IsSame(SV.First()))
+	SV.Append(endV);
+      else if (endV.IsSame(SV.Last()))
+	SV.Prepend(endV);
+      else
+	MESSAGE ("END VERTEX IS IN SEQUNCE MIDDLE");
+    }
+    NbVer = SV.Length();
+  }
+
+  for (iVer=1; iVer < NbVer; iVer++) {
+    V1  = TopoDS::Vertex(SV(iVer));
+    V2  = TopoDS::Vertex(SV(iVer+1));
+    
+    TopoDS_Shape NewEdge = WE.EmptyCopied();
+    V1.Orientation(TopAbs_FORWARD);
+    myBuilder.Add  (NewEdge,V1);
+    V2.Orientation(TopAbs_REVERSED);
+    myBuilder.Add  (NewEdge,V2);
+    
+    if (iVer==1)
+      U1 = f;
+    else 	{
+      V1.Orientation(TopAbs_INTERNAL);
+      U1=BRep_Tool::Parameter(V1,WE);
+    }
+    if (iVer+1 == NbVer)
+      U2 = l;
+    else	{
+      V2.Orientation(TopAbs_INTERNAL);
+      U2=BRep_Tool::Parameter(V2,WE);
+    }
+    if (Abs(U1-U2) <= Precision::PConfusion()) {
+      MESSAGE( "MakeEdges(), EQUAL PARAMETERS OF DIFFERENT VERTICES");
+      continue;
+    }
+    TopoDS_Edge EE=TopoDS::Edge(NewEdge);
+    myBuilder.Range (EE,U1,U2);
+
+    TopoDS_Edge NEdge = TopoDS::Edge(NewEdge);
+    myBuilder.SameParameter(NEdge,Standard_False);
+
+    Standard_Real tol = 1.0e-2;
+    Standard_Boolean flag = BRep_Tool::SameParameter(NEdge);
+    if (!flag) {
+      BRepLib::SameParameter(NEdge,tol);
+    }
+    NE.Append(NEdge.Oriented(E.Orientation()));
+  }
+}
+
+//=======================================================================
+//function : MergeEqualEdges
+//purpose  : find equal edges,  choose  ones  to  keep and make
+//           them have pcurves on all faces they are shared by
+//=======================================================================
+
+void Partition_Spliter::MergeEqualEdges (const TopTools_ListOfShape& LSE)
+{
+  // find equal edges
+  // map: edge - equal edges
+  TopTools_DataMapOfShapeListOfShape EEM( LSE.Extent() );
+  findEqual (LSE, LSE, 0, EEM, myEqualEdges);
+
+  TopTools_ListOfShape EEL; // list of equal edges
+  TopTools_DataMapIteratorOfDataMapOfShapeListOfShape itM (EEM);
+  for ( ; itM.More(); itM.Next()) {
+    EEL = itM.Value();
+    EEL.Append( itM.Key() );
+
+    // choose an edge to keep, section edges have priority
+    TopoDS_Edge EKeep;
+    TopTools_ListIteratorOfListOfShape itEE (EEL);
+    for (; itEE.More(); itEE.Next()) {
+      EKeep = TopoDS::Edge( itEE.Value() );
+      const TopoDS_Edge& EKeepOrig = TopoDS::Edge( myImagesEdges.Root( EKeep ));
+      if (myInter3d.IsSectionEdge( EKeepOrig ))
+        break;
+    }
+
+    // update edge images and build pcurves
+    Standard_Real f,l, tol;
+    for (itEE.Initialize (EEL); itEE.More(); itEE.Next()) {
+      const TopoDS_Edge& E = TopoDS::Edge( itEE.Value() );
+      if ( E.IsSame( EKeep )) 
+        continue;
+
+      // 1. build pcurves of the kept edge on faces where replaced edges exist
+      const TopoDS_Edge& EReplOrig = TopoDS::Edge( myImagesEdges.Root( E ));
+      TopTools_ListOfShape FL;
+      FL = myAsDes->Ascendant( EReplOrig );
+      Standard_Integer iFace, iFirstSectionFace = FL.Extent() + 1;
+      // add faces where the replaced edge is a section edge
+      if (myInter3d.IsSectionEdge( EReplOrig )) {
+        TopTools_ListIteratorOfListOfShape seIt;
+        seIt.Initialize( myInter3d.SectionEdgeFaces ( EReplOrig ));
+        for ( ; seIt.More(); seIt.Next())
+          FL.Append( seIt.Value() );
+      }
+      // loop on faces
+      TopTools_ListIteratorOfListOfShape itF (FL);
+      for ( iFace = 1 ; itF.More(); itF.Next(), ++iFace ) {
+        const TopoDS_Face& F = TopoDS::Face( itF.Value());
+
+        Handle(Geom2d_Curve) pc = BRep_Tool::CurveOnSurface( EKeep, F, f,l);
+        if (pc.IsNull()) {
+          Handle(Geom_Curve) C3d = BRep_Tool::Curve( EKeep, f, l);
+          C3d = new Geom_TrimmedCurve( C3d, f,l);
+          pc = TopOpeBRepTool_CurveTool::MakePCurveOnFace (F,C3d,tol);
+          if (pc.IsNull()) {
+            MESSAGE (" CANT BUILD PCURVE ");
+          }
+          myBuilder.UpdateEdge( EKeep, pc, F, tol);
+        }
+
+        if (iFace >= iFirstSectionFace ||
+            !BRep_Tool::IsClosed( EReplOrig, F ))
+          continue;
+
+        // build the second pcurve for a seam
+        TopoDS_Vertex V = TopExp::FirstVertex( EKeep );
+        Standard_Real Ukeep = BRep_Tool::Parameter( V, EKeep );
+        Standard_Real Urepl = BRep_Tool::Parameter( V, E );
+
+        TopoDS_Edge EReplRev = E;
+        EReplRev.Reverse();
+        Handle(Geom2d_Curve) pcRepl1 = BRep_Tool::CurveOnSurface( E, F, f,l);
+        Handle(Geom2d_Curve) pcRepl2 = BRep_Tool::CurveOnSurface( EReplRev, F, f,l);
+
+        gp_Pnt2d p1r, p2r, pk;
+        p1r = pcRepl1->Value( Urepl );
+        p2r = pcRepl2->Value( Urepl );
+        pk  = pc->Value( Ukeep );
+
+        // suppose that pk is equal to either p1r or p2r
+        Standard_Boolean isUPeriod =
+          ( Abs( p1r.X() - p2r.X() ) > Abs( p1r.Y() - p2r.Y() ));
+        Standard_Boolean is1Equal;
+        if (isUPeriod)
+          is1Equal = ( Abs( p1r.X() - pk.X() ) < Abs( p2r.X() - pk.X() ));
+        else
+          is1Equal = ( Abs( p1r.Y() - pk.Y() ) < Abs( p2r.Y() - pk.Y() ));
+
+        Handle(Geom2d_Curve) pc2 = Handle(Geom2d_Curve)::DownCast
+          ( pc->Translated( pk, is1Equal ? p2r : p1r ) );
+
+        if (E.Orientation() == TopAbs_REVERSED)
+          is1Equal = !is1Equal;
+
+        if (is1Equal)
+          myBuilder.UpdateEdge( EKeep, pc, pc2, F, tol);
+        else
+          myBuilder.UpdateEdge( EKeep, pc2, pc, F, tol);
+
+      } // loop on a Faces where a replaced edge exists
+
+
+      // 2. update edge images according to replacement
+      if (myImagesEdges.HasImage( E ))
+        myImagesEdges.Remove( E );
+      myImagesEdges.Bind( E, EKeep );
+
+    } // loop on a list of equal edges EEL
+  } // loop on a map of equal edges EEM
+}
+
+//=======================================================================
+//function : KeepShapesInside
+//purpose  : remove shapes that are outside of S from resul
+//=======================================================================
+
+void Partition_Spliter::KeepShapesInside (const TopoDS_Shape& S)
+{
+  TopoDS_Iterator it;
+  if (S.ShapeType() < TopAbs_SOLID) { // compound or compsolid
+    for (it.Initialize( S ); it.More(); it.Next())
+      KeepShapesInside( it.Value());
+    return;
+  }
+
+  Standard_Boolean isTool = Standard_False;
+  if (!myImageShape.HasImage( S )) {
+    isTool = CheckTool( S );
+    if (!isTool) return;
+  }
+
+  // build map of internal faces
+  TopTools_IndexedMapOfShape MIF;
+  TopoDS_Shape IntFacesComp = FindFacesInside( S, Standard_False, Standard_True);
+  TopExp::MapShapes( IntFacesComp, TopAbs_FACE, MIF );
+
+  TopoDS_Compound C;
+  myBuilder.MakeCompound(C);
+
+  TopAbs_ShapeEnum anInternalShapeType = TopAbs_SHAPE;
+  if (!MIF.IsEmpty())
+  {
+    // leave in the result only those shapes having a face in MIF
+    for (it.Initialize( myShape ); it.More(); it.Next()) {
+      const TopoDS_Shape & aResShape = it.Value();
+      TopExp_Explorer expResF( aResShape, TopAbs_FACE );
+      for (; expResF.More(); expResF.Next()) {
+        if ( MIF.Contains( expResF.Current())) {
+          myBuilder.Add( C, aResShape );
+          if (aResShape.ShapeType() < anInternalShapeType)
+            anInternalShapeType = aResShape.ShapeType();
+          break;
+        }
+      }
+    }
+  }
+
+  // may be S was not split by internal faces then it is missing
+  // in myShape, add it
+  if (!isTool &&
+      (anInternalShapeType > TopAbs_SOLID || S.ShapeType() > TopAbs_SOLID))
+  {
+    TopTools_IndexedMapOfShape MSF; // map of split faces of S
+    TopExp::MapShapes( myImageShape.Image(S).First(), TopAbs_FACE, MSF);
+
+    // find a shape having all faces in MSF
+    for (it.Initialize( myShape ); it.More(); it.Next()) {
+      TopExp_Explorer expResF( it.Value(), TopAbs_FACE );
+      for (; expResF.More(); expResF.Next()) {
+        if (! MSF.Contains( expResF.Current())) 
+          break;
+      }
+      if (! expResF.More()) {
+        myBuilder.Add( C, it.Value() );
+        break;
+      }
+    }
+  }
+
+  myShape = C;
+}
+
+//=======================================================================
+//function : RemoveShapesInside
+//purpose  : remove shapes that are inside S from resul
+//=======================================================================
+
+void Partition_Spliter::RemoveShapesInside (const TopoDS_Shape& S)
+{
+  TopoDS_Iterator it;
+  if (S.ShapeType() < TopAbs_SOLID) { // compound or compsolid
+    for (it.Initialize( S ); it.More(); it.Next())
+      RemoveShapesInside( it.Value());
+    return;
+  }
+  Standard_Boolean isTool = Standard_False;
+  if (!myImageShape.HasImage( S )) {
+    isTool = CheckTool( S );
+    if (!isTool) return;
+  }
+
+  TopoDS_Shape IntFacesComp = FindFacesInside( S, Standard_False, Standard_True);
+  TopTools_IndexedMapOfShape MIF; // map of internal faces
+  TopExp::MapShapes( IntFacesComp, TopAbs_FACE, MIF);
+
+  if (MIF.IsEmpty()) return;
+
+  // add to MIF split faces of S
+  if (myImageShape.HasImage(S))
+    TopExp::MapShapes( myImageShape.Image(S).First(), TopAbs_FACE, MIF);
+
+  // leave in the result only those shapes not having all face in MIF
+  
+  TopoDS_Compound C;
+  myBuilder.MakeCompound(C);
+
+  // RMF : faces of removed shapes that encounter once
+  TopTools_MapOfShape RFM;
+  
+  for (it.Initialize( myShape ); it.More(); it.Next()) {
+    
+    TopExp_Explorer expResF( it.Value(), TopAbs_FACE );
+    for (; expResF.More(); expResF.Next())
+      if (!MIF.Contains( expResF.Current()))
+	break;
+
+    if (expResF.More())
+      // add shape to result
+      myBuilder.Add( C, it.Value() );
+    else 
+      // add faces of a removed shape to RFM
+      for (expResF.ReInit(); expResF.More(); expResF.Next()) {
+	const TopoDS_Shape& F = expResF.Current();
+	if ( ! RFM.Remove ( F ))
+	  RFM.Add( F );
+      }
+  }
+
+  if (!isTool) {
+
+    // rebuild S, it must remain in the result
+
+    Standard_Boolean isClosed = Standard_False;
+    switch (S.ShapeType()) {
+    case TopAbs_SOLID :
+      isClosed = Standard_True; break;
+    case TopAbs_SHELL: {
+      TopTools_IndexedDataMapOfShapeListOfShape MEF;
+      TopExp::MapShapesAndAncestors(S, TopAbs_EDGE, TopAbs_FACE, MEF);
+      Standard_Integer i;
+      for (i=1;  isClosed && i<=MEF.Extent();  ++i) 
+        isClosed = ( MEF(i).Extent() != 1 );
+      break;
+    }
+    default:
+      isClosed = Standard_False;
+    }
+    if (isClosed) {
+
+      // add to a new shape external faces of removed shapes, ie those in RFM
+
+      TopoDS_Shell Shell;
+      myBuilder.MakeShell( Shell );
+
+      // exclude redundant internal face with edges encounterd only once
+      TopTools_IndexedDataMapOfShapeListOfShape MEF;
+      TopTools_MapIteratorOfMapOfShape itF (RFM);
+      for ( ; itF.More(); itF.Next()) 
+        TopExp::MapShapesAndAncestors(itF.Key(), TopAbs_EDGE, TopAbs_FACE, MEF);
+
+      // add only faces forming a closed shell
+      for (itF.Reset() ; itF.More(); itF.Next())
+      {
+        TopExp_Explorer expE (itF.Key(), TopAbs_EDGE);
+        for (; expE.More(); expE.Next())
+          if (MEF.FindFromKey(expE.Current()).Extent() == 1)
+            break;
+        if (!expE.More())
+          myBuilder.Add( Shell, itF.Key());
+      }
+
+      if (S.ShapeType() == TopAbs_SOLID) {
+        TopoDS_Solid Solid;
+        myBuilder.MakeSolid( Solid );
+        myBuilder.Add (Solid, Shell);
+        myBuilder.Add (C, Solid);
+      }
+      else
+        myBuilder.Add (C, Shell);
+    }
+    else {
+      if (myImageShape.HasImage( S )) {
+        for (it.Initialize( myImageShape.Image(S).First()); it.More(); it.Next())
+          myBuilder.Add (C, it.Value());
+      }
+    }
+  }
+  
+  myShape = C;
+}
+
+//=======================================================================
+//function : CheckTool
+//purpose  : Return True if <S>  is  a tool shape. Prepare tool
+//           faces of <S> for the search of internal faces.
+//=======================================================================
+
+Standard_Boolean Partition_Spliter::CheckTool(const TopoDS_Shape& S)
+{
+  // suppose S has not an image
+  
+  Standard_Boolean isTool = Standard_False;
+  TopoDS_Compound C;
+  myBuilder.MakeCompound( C );
+
+  TopExp_Explorer expF( S, TopAbs_FACE);
+  for (; expF.More(); expF.Next()) {
+
+    const TopoDS_Face& F = TopoDS::Face( expF.Current() );
+    if (myMapTools.Contains( F ))
+      isTool = Standard_True;
+    else
+      continue;
+
+    if (myImagesFaces.HasImage( F )) {
+      // F has been reconstructed
+      TopAbs_Orientation Fori = F.Orientation();
+      TopTools_ListOfShape LNF;
+      myImagesFaces.LastImage( F, LNF);
+      TopTools_ListIteratorOfListOfShape itF (LNF);
+      for ( ; itF.More(); itF.Next())
+	myBuilder.Add( C, itF.Value().Oriented(Fori) );
+      continue;
+    }
+    
+    Standard_Boolean hasSectionE = myInter3d.HasSectionEdge( F );
+    Standard_Boolean hasNewE     = myAsDes->HasDescendant( F );
+    if (!hasSectionE && !hasNewE)
+    {
+      // F intersects nothing
+      myBuilder.Add( C, F );
+      continue;
+    }
+    
+    // make an image for F
+    
+    TopoDS_Face NF = F;
+    NF.Orientation(TopAbs_FORWARD);
+    NF = TopoDS::Face( NF.EmptyCopied() ); // make a copy
+    TopoDS_Wire NW;
+    myBuilder.MakeWire( NW );
+
+    // add edges, as less as possible
+    TopTools_ListOfShape NEL;
+    TopTools_ListIteratorOfListOfShape itNE;
+    if (hasSectionE) {
+      // add section edges
+      TopExp_Explorer expE;
+      for ( ; expE.More(); expE.Next()) {
+	if (! myImagesEdges.HasImage( expE.Current() ))
+	  continue;
+	myImagesEdges.LastImage( expE.Current(), NEL );
+	for ( itNE.Initialize( NEL ); itNE.More(); itNE.Next())
+	  myBuilder.Add ( NW, itNE.Value());
+      }
+    }
+    if (hasNewE) {
+      // add new adges
+      NEL = myAsDes->Descendant( F );
+      for ( itNE.Initialize( NEL ); itNE.More(); itNE.Next()) {
+	TopTools_ListOfShape SEL; // splits
+	myImagesEdges.LastImage( itNE.Value(), SEL );
+	TopTools_ListIteratorOfListOfShape itSE (SEL);
+	for ( ; itSE.More(); itSE.Next()) 
+	  myBuilder.Add ( NW, itSE.Value());
+      }
+    }
+    myBuilder.Add( NF, NW );
+    myBuilder.Add (C, NF);
+    
+    NF.Orientation( F.Orientation() ); // NF is most probably invalid
+    myImagesFaces.Bind (F, NF);
+  }
+  if (isTool)
+    myImageShape.Bind (S, C);
+
+  return isTool;
+}
+
+//=======================================================================
+//function : IsInside
+//purpose  : Return True if the first vertex of S1 inside S2.
+//           If S1.IsNull(), check infinite point against S2.
+//=======================================================================
+
+Standard_Boolean Partition_Spliter::IsInside (const TopoDS_Shape& theS1,
+                                              const TopoDS_Shape& theS2)
+{
+  BRepClass3d_SolidClassifier aClassifier( theS2 );
+
+  TopExp_Explorer expl( theS1, TopAbs_VERTEX );
+  if (!expl.More())
+    aClassifier.PerformInfinitePoint( ::RealSmall());
+  else
+  {
+    const TopoDS_Vertex & aVertex = TopoDS::Vertex( expl.Current() );
+    aClassifier.Perform (BRep_Tool::Pnt( aVertex ),
+                         BRep_Tool::Tolerance( aVertex ));
+  }
+
+  return ( aClassifier.State() == TopAbs_IN );
+}
+
+//=======================================================================
+//function : GetOriginalShape
+//purpose  : Return the  shape  aShape  originates from. aShape
+//           should be a face or more complex result shape
+//=======================================================================
+
+TopoDS_Shape Partition_Spliter::GetOriginalShape(const TopoDS_Shape& theShape) const
+{
+  TopoDS_Shape anOrigShape;
+
+  TopExp_Explorer expl( theShape, TopAbs_FACE);
+  if (expl.More())
+  {
+
+    TopoDS_Shape aFace = expl.Current();
+    if (myImagesFaces.IsImage( aFace ))
+      aFace = myImagesFaces.Root( aFace );
+    anOrigShape = myFaceShapeMap.Find( aFace );
+  }
+  return anOrigShape;
+}
+
+//=======================================================================
+//function : FindToolsToReconstruct
+//purpose  : find and store  as  objects  tools which interfere
+//           with  solids   or   are   inside   solids  without
+//           an interference
+//=======================================================================
+
+void Partition_Spliter::FindToolsToReconstruct()
+{
+  if (myMapTools.IsEmpty())
+    return;
+
+  Standard_Integer nbFoundTools = 0;
+
+  // build edge - face map in order to detect interference with section edges
+  TopTools_IndexedDataMapOfShapeListOfShape EFM;
+  TopTools_MapIteratorOfMapOfShape aMapIt;
+  for (aMapIt.Initialize(myMapTools); aMapIt.More(); aMapIt.Next())
+    TopExp::MapShapesAndAncestors( aMapIt.Key(), TopAbs_EDGE, TopAbs_FACE, EFM);
+  for (aMapIt.Initialize(myMapFaces); aMapIt.More(); aMapIt.Next())
+    TopExp::MapShapesAndAncestors( aMapIt.Key(), TopAbs_EDGE, TopAbs_FACE, EFM);
+
+  TopTools_MapOfShape aCurrentSolids, aCheckedShapes;
+
+  // faces cut by new edges
+  TopTools_MapOfShape & aSectionFaces = myInter3d.TouchedFaces();
+
+  // keep solids interfering with each other in aCurrentSolids map
+  // and add tool faces intersecting solids as object shapes
+
+  TopTools_ListIteratorOfListOfShape itS, itF, itCF, itE;
+  for (itS.Initialize( myListShapes ); itS.More(); itS.Next()) {
+    TopExp_Explorer expSo (itS.Value(), TopAbs_SOLID);
+    for (; expSo.More(); expSo.Next()) {
+
+      // check if a solid has been already processed
+      const TopoDS_Shape & aSo = expSo.Current();
+      if (!aCheckedShapes.Add( aSo ))
+        continue;
+      aCurrentSolids.Add( aSo );
+
+      // faces to check
+      TopTools_ListOfShape aFacesToCheck;
+      TopExp_Explorer exp( aSo, TopAbs_FACE );
+      for ( ; exp.More(); exp.Next())
+        aFacesToCheck.Append ( exp.Current());
+
+      // add other shapes interefering with a solid.
+      // iterate faces to check while appending new ones
+      for (itCF.Initialize (aFacesToCheck) ; itCF.More(); itCF.Next())
+      {
+        const TopoDS_Shape& aCheckFace = itCF.Value();
+//         if (!aCheckedShapes.Add( aCheckFace ))
+//           continue;
+
+        // find faces interfering with aCheckFace
+        TopTools_ListOfShape anIntFaces;
+
+        // ** 1. faces intersecting aCheckFace with creation of new edges on it
+        if ( myAsDes->HasDescendant( aCheckFace ))
+        {
+          // new edges on aCheckFace
+          const TopTools_ListOfShape& NEL = myAsDes->Descendant( aCheckFace );
+          for (itE.Initialize( NEL); itE.More(); itE.Next())
+          {
+            const TopoDS_Shape & aNewEdge = itE.Value();
+            if (!aCheckedShapes.Add( aNewEdge ))
+              continue;
+
+            // faces interfering by aNewEdge
+            itF.Initialize (myAsDes->Ascendant( aNewEdge ));
+            for (; itF.More(); itF.Next())
+              if (aCheckFace != itF.Value())
+                anIntFaces.Append( itF.Value() );
+
+            // ** 2. faces having section edge aNewEdge on aFacesToCheck
+            if (EFM.Contains( aNewEdge))
+            {
+              itF.Initialize ( EFM.FindFromKey (itE.Value()));
+              for (; itF.More(); itF.Next())
+                if (aCheckFace != itF.Value())
+                  anIntFaces.Append( itF.Value() );
+            }
+          }
+        }
+
+        // ** 3. faces cut by edges of aCheckFace
+        TopExp_Explorer expE (aCheckFace, TopAbs_EDGE);
+        for ( ; expE.More(); expE.Next())
+        {
+          const TopoDS_Shape & aCheckEdge = expE.Current();
+          if (aCheckedShapes.Add( aCheckEdge ) &&
+              myInter3d.IsSectionEdge( TopoDS::Edge( aCheckEdge )))
+          {
+            itF.Initialize( myInter3d.SectionEdgeFaces( TopoDS::Edge( aCheckEdge )));
+            for (; itF.More(); itF.Next()) 
+              if (aCheckFace != itF.Value())
+                anIntFaces.Append( itF.Value() );
+          }
+        }
+
+        // process faces interfering with aCheckFace and shapes they
+        // belong to
+        for (itF.Initialize (anIntFaces); itF.More(); itF.Next())
+        {
+          const TopoDS_Shape & F = itF.Value();
+          if (! aCheckedShapes.Add( F ))
+            continue;
+
+          Standard_Boolean isTool = myMapTools.Contains( F );
+          if (isTool && 
+              myFaceShapeMap( aCheckFace ).ShapeType() == TopAbs_SOLID )
+          {
+            // a tool interfering with a solid
+            if (aSectionFaces.Contains( F ))
+              AddShape( F );
+            ++ nbFoundTools;
+            if (nbFoundTools == myMapTools.Extent())
+              return;
+          }
+
+          const TopoDS_Shape & S = myFaceShapeMap( F );
+          if (aCheckedShapes.Add( S ))
+          {
+            // a new shape interefering with aCurrentSolids is found
+            if (!isTool && S.ShapeType() == TopAbs_SOLID)
+              aCurrentSolids.Add ( S );
+            // add faces to aFacesToCheck list
+            for ( exp.Init( S, TopAbs_FACE ); exp.More(); exp.Next())
+              aFacesToCheck.Append ( exp.Current() );
+          }
+        }
+      } // loop on aFacesToCheck
+
+      // Here aCurrentSolids contains all solids interfering with each other.
+      // aCheckedShapes contains all faces belonging to shapes included
+      // in or interfering with aCurrentSolids or previously checked solids.
+      // Test if tool faces that do not interefere with other shapes are
+      // wrapped by any of aCurrentSolids
+
+      TopTools_MapIteratorOfMapOfShape aSolidIt (aCurrentSolids);
+      for ( ; aSolidIt.More(); aSolidIt.Next())
+      {
+        const TopoDS_Shape & aSolid = aSolidIt.Key();
+        TopTools_MapOfShape aCheckedTools( myMapTools.Extent() );
+
+        TopTools_MapIteratorOfMapOfShape aToolIt (myMapTools);
+        for ( ; aToolIt.More(); aToolIt.Next())
+        {
+          const TopoDS_Shape & aToolFace = aToolIt.Key();
+          if (aCheckedShapes.Contains( aToolFace ) || // already found
+              aCheckedTools.Contains( aToolFace ))    // checked against aSolid
+            continue;
+
+          const TopoDS_Shape & aToolShape = myFaceShapeMap( aToolFace );
+          TopExp_Explorer aToolFaceIt( aToolShape, TopAbs_FACE );
+          
+          Standard_Boolean isInside = IsInside( aToolShape, aSolid );
+          for ( ; aToolFaceIt.More(); aToolFaceIt.Next() )
+          {
+            const TopoDS_Shape & aTool = aToolFaceIt.Current();
+            aCheckedTools.Add( aTool );
+            if (isInside)
+            {
+              if (aSectionFaces.Contains( aTool ))
+                AddShape( aTool );
+              ++ nbFoundTools;
+              if (nbFoundTools == myMapTools.Extent())
+                return;
+              aCheckedShapes.Add( aTool );
+            }
+          }
+        }
+      }
+      
+    } // loop on solid shapes
+  }
+}
+
+#endif
diff --git a/contrib/Netgen/libsrc/occ/Partition_Spliter.hxx b/contrib/Netgen/libsrc/occ/Partition_Spliter.hxx
new file mode 100644
index 0000000000..f29917a3e1
--- /dev/null
+++ b/contrib/Netgen/libsrc/occ/Partition_Spliter.hxx
@@ -0,0 +1,150 @@
+//  GEOM PARTITION : partition algorithm
+//
+//  Copyright (C) 2003  CEA/DEN, EDF R&D
+//
+//
+//
+//  File   : Partition_Spliter.hxx
+//  Module : GEOM
+
+#ifndef _Partition_Spliter_HeaderFile
+#define _Partition_Spliter_HeaderFile
+
+#ifndef _TopAbs_ShapeEnum_HeaderFile
+#include <TopAbs_ShapeEnum.hxx>
+#endif
+#ifndef _TopoDS_Compound_HeaderFile
+#include <TopoDS_Compound.hxx>
+#endif
+#ifndef _BRep_Builder_HeaderFile
+#include <BRep_Builder.hxx>
+#endif
+#ifndef _TopTools_ListOfShape_HeaderFile
+#include <TopTools_ListOfShape.hxx>
+#endif
+#ifndef _TopTools_MapOfShape_HeaderFile
+#include <TopTools_MapOfShape.hxx>
+#endif
+#ifndef _TopTools_DataMapOfShapeShape_HeaderFile
+#include <TopTools_DataMapOfShapeShape.hxx>
+#endif
+#ifndef _Handle_BRepAlgo_AsDes_HeaderFile
+#include <Handle_BRepAlgo_AsDes.hxx>
+#endif
+#ifndef _BRepAlgo_Image_HeaderFile
+#include <BRepAlgo_Image.hxx>
+#endif
+#ifndef _Partition_Inter3d_HeaderFile
+#include "Partition_Inter3d.hxx"
+#endif
+#ifndef _TopTools_MapOfOrientedShape_HeaderFile
+#include <TopTools_MapOfOrientedShape.hxx>
+#endif
+#ifndef _Standard_Boolean_HeaderFile
+#include <Standard_Boolean.hxx>
+#endif
+class BRepAlgo_AsDes;
+class TopoDS_Shape;
+class TopTools_ListOfShape;
+class TopoDS_Edge;
+
+
+#ifndef _Standard_HeaderFile
+#include <Standard.hxx>
+#endif
+#ifndef _Standard_Macro_HeaderFile
+#include <Standard_Macro.hxx>
+#endif
+
+class Partition_Spliter  {
+
+public:
+
+   void* operator new(size_t,void* anAddress) 
+   {
+      return anAddress;
+   }
+   void* operator new(size_t size) 
+   { 
+      return Standard::Allocate(size); 
+   }
+   void  operator delete(void *anAddress) 
+   { 
+      if (anAddress) Standard::Free((Standard_Address&)anAddress); 
+   }
+   // Methods PUBLIC
+   // 
+   Partition_Spliter();
+   void AddShape(const TopoDS_Shape& S) ;
+   void AddTool(const TopoDS_Shape& S) ;
+   void Compute(const TopAbs_ShapeEnum Limit = TopAbs_SHAPE) ;
+   void KeepShapesInside(const TopoDS_Shape& S) ;
+   void RemoveShapesInside(const TopoDS_Shape& S) ;
+   TopoDS_Shape Shape() const;
+   void Clear() ;
+
+
+
+
+
+protected:
+
+   // Methods PROTECTED
+   // 
+
+
+   // Fields PROTECTED
+   //
+
+
+private: 
+
+   // Methods PRIVATE
+   // 
+   void MakeSolids(const TopoDS_Shape& Solid,TopTools_ListOfShape& Shells) ;
+   void MakeShells(const TopoDS_Shape& S,TopTools_ListOfShape& NS) ;
+   TopoDS_Shape MakeFaces(const TopoDS_Shape& S) ;
+   void MakeEdges(const TopoDS_Edge& E,const TopTools_ListOfShape& VOnE,TopTools_ListOfShape& NE) const;
+   TopoDS_Shape FindFacesInside(const TopoDS_Shape& S,const Standard_Boolean CheckClosed = Standard_False,const Standard_Boolean All = Standard_False) ;
+   Standard_Boolean CheckTool(const TopoDS_Shape& S) ;
+   void MergeEqualEdges(const TopTools_ListOfShape& LE) ;
+   static  Standard_Boolean IsInside(const TopoDS_Shape& S1,const TopoDS_Shape& S2) ;
+   TopoDS_Shape GetOriginalShape(const TopoDS_Shape& aShape) const;
+   void FindToolsToReconstruct() ;
+
+
+   // Fields PRIVATE
+   //
+   TopAbs_ShapeEnum myDoneStep;
+   TopoDS_Compound myShape;
+   BRep_Builder myBuilder;
+   TopTools_ListOfShape myListShapes;
+   TopTools_MapOfShape myMapFaces;
+   TopTools_MapOfShape myMapTools;
+   TopTools_MapOfShape myEqualEdges;
+   TopTools_MapOfShape myNewSection;
+   TopTools_MapOfShape myClosedShapes;
+   TopTools_MapOfShape mySharedFaces;
+   TopTools_MapOfShape myWrappingSolid;
+   TopTools_DataMapOfShapeShape myFaceShapeMap;
+   TopTools_DataMapOfShapeShape myInternalFaces;
+   TopTools_DataMapOfShapeShape myIntNotClFaces;
+   Handle_BRepAlgo_AsDes myAsDes;
+   BRepAlgo_Image myImagesFaces;
+   BRepAlgo_Image myImagesEdges;
+   BRepAlgo_Image myImageShape;
+   Partition_Inter3d myInter3d;
+   TopTools_MapOfOrientedShape myAddedFacesMap;
+
+
+};
+
+
+
+
+
+// other Inline functions and methods (like "C++: function call" methods)
+//
+
+
+#endif
diff --git a/contrib/Netgen/libsrc/occ/Partition_Spliter.ixx b/contrib/Netgen/libsrc/occ/Partition_Spliter.ixx
new file mode 100644
index 0000000000..ee82594685
--- /dev/null
+++ b/contrib/Netgen/libsrc/occ/Partition_Spliter.ixx
@@ -0,0 +1,31 @@
+//  GEOM PARTITION : partition algorithm
+//
+//  Copyright (C) 2003  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
+//  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS 
+// 
+//  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. 
+// 
+//  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 
+// 
+//  See http://www.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org 
+//
+//
+//
+//  File   : Partition_Spliter.ixx
+//  Module : GEOM
+
+#include "Partition_Spliter.jxx"
+
+ 
+
+
diff --git a/contrib/Netgen/libsrc/occ/Partition_Spliter.jxx b/contrib/Netgen/libsrc/occ/Partition_Spliter.jxx
new file mode 100644
index 0000000000..bf8622c93a
--- /dev/null
+++ b/contrib/Netgen/libsrc/occ/Partition_Spliter.jxx
@@ -0,0 +1,41 @@
+//  GEOM PARTITION : partition algorithm
+//
+//  Copyright (C) 2003  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
+//  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS 
+// 
+//  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. 
+// 
+//  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 
+// 
+//  See http://www.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org 
+//
+//
+//
+//  File   : Partition_Spliter.jxx
+//  Module : GEOM
+
+#ifndef _BRepAlgo_AsDes_HeaderFile
+#include <BRepAlgo_AsDes.hxx>
+#endif
+#ifndef _TopoDS_Shape_HeaderFile
+#include <TopoDS_Shape.hxx>
+#endif
+#ifndef _TopTools_ListOfShape_HeaderFile
+#include <TopTools_ListOfShape.hxx>
+#endif
+#ifndef _TopoDS_Edge_HeaderFile
+#include <TopoDS_Edge.hxx>
+#endif
+#ifndef _Partition_Spliter_HeaderFile
+#include "Partition_Spliter.hxx"
+#endif
diff --git a/contrib/Netgen/libsrc/occ/occconstruction.cpp b/contrib/Netgen/libsrc/occ/occconstruction.cpp
new file mode 100644
index 0000000000..2945a1470a
--- /dev/null
+++ b/contrib/Netgen/libsrc/occ/occconstruction.cpp
@@ -0,0 +1,157 @@
+
+#ifdef OCCGEOMETRY
+
+#include <mystdlib.h>
+#include <occgeom.hpp>  
+#include "ShapeAnalysis_ShapeTolerance.hxx"
+#include "ShapeAnalysis_ShapeContents.hxx"
+#include "ShapeAnalysis_CheckSmallFace.hxx"
+#include "ShapeAnalysis_DataMapOfShapeListOfReal.hxx"
+#include "BRepAlgoAPI_Fuse.hxx"
+#include "BRepCheck_Analyzer.hxx"
+#include "BRepLib.hxx"
+#include "ShapeBuild_ReShape.hxx"
+#include "ShapeFix.hxx"
+#include "ShapeFix_FixSmallFace.hxx"
+#include "Partition_Spliter.hxx"
+//#include "VrmlAPI.hxx"
+//#include "StlAPI.hxx"
+
+
+#include <GC_MakeSegment.hxx>
+#include <BRepBuilderAPI_MakeEdge.hxx>
+#include <BRepBuilderAPI_MakeWire.hxx>
+#include <BRepPrimAPI_MakeBox.hxx>
+// #include <BRep_Builder.hxx>
+#include <TopoDS_Builder.hxx>
+#include <BRepAlgoAPI_Cut.hxx>
+#include <BRepAlgoAPI_Common.hxx>
+#include <BRepAlgoAPI_Fuse.hxx>
+#include <BRepAlgoAPI_Section.hxx>
+#include <BRepOffsetAPI_Sewing.hxx>
+//#include <BRepAlgo_Sewing.hxx>
+#include <BRepOffsetAPI_MakeOffsetShape.hxx>
+#include <ShapeFix_Shape.hxx>
+namespace netgen
+{
+
+  void OCCConstructGeometry (OCCGeometry & geom)
+  {
+#ifdef NOTHING
+    cout << "OCC construction" << endl;
+
+    BRep_Builder builder;
+    BRepPrimAPI_MakeBox mbox(gp_Pnt(-10e5, -15e5, 0), gp_Pnt(20e5, 15e5, 10e5));
+
+
+    /*
+    TopoDS_Shape air = TopoDS_Solid (mbox);
+    air = BRepAlgoAPI_Cut (air, geom.somap(1));
+    air = BRepAlgoAPI_Cut (air, geom.somap(2));
+    air = BRepAlgoAPI_Cut (air, geom.somap(3));
+    air = BRepAlgoAPI_Cut (air, geom.somap(4));
+    air = BRepAlgoAPI_Cut (air, geom.somap(5));
+    air = BRepAlgoAPI_Cut (air, geom.somap(6));
+    air = BRepAlgoAPI_Cut (air, geom.somap(7));
+    // air = BRepAlgoAPI_Cut (air, geom.somap(8));
+    air = BRepAlgoAPI_Cut (air, geom.somap(9));
+    // air = BRepAlgoAPI_Cut (air, geom.somap(10));
+    */
+
+    /*
+    BRepOffsetAPI_MakeOffsetShape dom8plus (geom.somap(8), 1e4, 1e-6);
+    BRepOffsetAPI_MakeOffsetShape dom6plus (geom.somap(6), 1e4, 1e-6);
+    dom8plus.Build();
+    ShapeFix_Shape fixshape(dom8plus.Shape());
+    fixshape.Perform();
+    
+    ShapeFix_Shape fix_dom2(geom.somap(2));
+    fix_dom2.Perform();
+
+
+    BRepAlgoAPI_Cut dom2m8(fix_dom2.Shape(), fixshape.Shape());
+    ShapeFix_Shape fix_dom2m8 (dom2m8);
+    fix_dom2m8.Perform();
+
+    builder.Add (geom.shape, 
+		 BRepAlgoAPI_Cut 
+		 (BRepAlgoAPI_Cut (geom.somap(2), dom6plus),
+		  dom8plus));
+    // builder.Add (geom.shape, fix_dom2m8.Shape());
+    //     builder.Add (geom.shape, fixshape.Shape());
+    */
+
+    TopoDS_Shape my_fuse;
+    int cnt = 0;
+    for (TopExp_Explorer exp_solid(geom.shape, TopAbs_SOLID); exp_solid.More(); exp_solid.Next())
+      {
+	if (cnt == 0)
+	  my_fuse = exp_solid.Current();
+	else
+	  {
+	    cout << "fuse, cnt = " << cnt << endl;
+	    if (cnt != 7 && cnt != 9)
+	      my_fuse = BRepAlgoAPI_Fuse (my_fuse, exp_solid.Current());
+	  }
+	cnt++;
+      }
+    builder.Add (geom.shape, my_fuse);
+
+    /*
+    ShapeUpgrade_ShellSewing ss;
+    ss.ApplySewing(geom.shape,1e5);
+    */
+
+    /*
+    BRepAlgo_Sewing sewing(1.e5);
+    
+    int cnt = 0;
+    for (TopExp_Explorer exp_solid(geom.shape, TopAbs_SOLID); exp_solid.More(); exp_solid.Next())
+      {
+	cout << "swe, cnt = " << cnt << endl;
+	if (cnt != 7 && cnt != 9)
+	  sewing.Add (exp_solid.Current());
+	cnt++;
+      }
+
+    sewing.Perform();
+    builder.Add (geom.shape, sewing.SewedShape());
+    */
+
+
+    /*
+    cout << "build air domain" << endl;
+    TopoDS_Shape air = BRepAlgoAPI_Cut (TopoDS_Solid (mbox), my_fuse);
+
+    cnt = 0;
+    for (TopExp_Explorer exp_solid(geom.shape, TopAbs_SOLID); exp_solid.More(); exp_solid.Next())
+      {
+	cout << "section, cnt = " << cnt << endl;
+	if (cnt == 7)
+	  {
+	    builder.Add (geom.shape, 
+			 BRepAlgoAPI_Section (air, exp_solid.Current()));
+	  }
+	cnt++;
+      }
+    */
+
+
+
+    //    builder.Add (geom.shape, air);
+    for (int i = 1; i <= 10; i++)
+      builder.Remove (geom.shape, geom.somap(i));
+
+
+
+
+    geom.BuildFMap();
+    geom.BuildVisualizationMesh();
+    geom.changed = 1;
+#endif
+
+  }
+}
+
+
+#endif
diff --git a/contrib/Netgen/libsrc/occ/occgenmesh.cpp b/contrib/Netgen/libsrc/occ/occgenmesh.cpp
new file mode 100644
index 0000000000..aefec84412
--- /dev/null
+++ b/contrib/Netgen/libsrc/occ/occgenmesh.cpp
@@ -0,0 +1,1460 @@
+#ifdef OCCGEOMETRY
+
+#include <mystdlib.h>
+#include <occgeom.hpp>
+#include <meshing.hpp>
+
+
+namespace netgen
+{
+
+#include "occmeshsurf.hpp"
+
+#define TCL_OK 0
+#define TCL_ERROR 1
+
+#define DIVIDEEDGESECTIONS 1000
+#define IGNORECURVELENGTH 1e-4
+#define VSMALL 1e-10
+
+
+   bool merge_solids = 1;
+
+
+  // can you please explain what you intend to compute here (JS) !!!
+   double Line :: Dist (Line l)
+   {
+      Vec<3> n = p1-p0;
+      Vec<3> q = l.p1-l.p0;
+      double nq = n*q;
+
+      Point<3> p = p0 + 0.5*n;
+      double lambda = (p-l.p0)*n / (nq + VSMALL);
+
+      if (lambda >= 0 && lambda <= 1)
+      {
+         double d = (p-l.p0-lambda*q).Length();
+         //        if (d < 1e-3) d = 1e99;
+         return d;
+      }
+      else
+         return 1e99;
+   }
+
+
+
+   double Line :: Length ()
+   {
+      return (p1-p0).Length();
+   }
+
+
+
+   inline Point<3> occ2ng (const gp_Pnt & p)
+   {
+      return  Point<3> (p.X(), p.Y(), p.Z());
+   }
+
+
+
+   double ComputeH (double kappa)
+   {
+      double hret;
+      kappa *= mparam.curvaturesafety;
+
+      if (mparam.maxh * kappa < 1)
+         hret = mparam.maxh;
+      else
+         hret = 1 / (kappa + VSMALL);
+
+      if (mparam.maxh < hret)
+         hret = mparam.maxh;
+
+      return (hret);
+   }
+
+
+
+
+   void RestrictHTriangle (gp_Pnt2d & par0, gp_Pnt2d & par1, gp_Pnt2d & par2,
+                           BRepLProp_SLProps * prop, Mesh & mesh, int depth, double h = 0)
+   {
+      int ls = -1;
+
+      gp_Pnt pnt0,pnt1,pnt2;
+
+      prop->SetParameters (par0.X(), par0.Y());
+      pnt0 = prop->Value();
+
+      prop->SetParameters (par1.X(), par1.Y());
+      pnt1 = prop->Value();
+
+      prop->SetParameters (par2.X(), par2.Y());
+      pnt2 = prop->Value();
+
+      double aux;
+      double maxside = pnt0.Distance(pnt1);
+      ls = 2;
+      aux = pnt1.Distance(pnt2);
+      if(aux > maxside)
+      {
+         maxside = aux;
+         ls = 0;
+      }
+      aux = pnt2.Distance(pnt0);
+      if(aux > maxside)
+      {
+         maxside = aux;
+         ls = 1;
+      }
+
+
+
+      gp_Pnt2d parmid;
+
+      parmid.SetX( (par0.X()+par1.X()+par2.X()) / 3 );
+      parmid.SetY( (par0.Y()+par1.Y()+par2.Y()) / 3 );
+
+      if (depth%3 == 0)
+      {
+         double curvature = 0;
+
+         prop->SetParameters (parmid.X(), parmid.Y());
+         if (!prop->IsCurvatureDefined())
+         {
+            (*testout) << "curvature not defined!" << endl;
+            return;
+         }
+         curvature = max(fabs(prop->MinCurvature()),
+            fabs(prop->MaxCurvature()));
+
+         prop->SetParameters (par0.X(), par0.Y());
+         if (!prop->IsCurvatureDefined())
+         {
+            (*testout) << "curvature not defined!" << endl;
+            return;
+         }
+         curvature = max(curvature,max(fabs(prop->MinCurvature()),
+            fabs(prop->MaxCurvature())));
+
+         prop->SetParameters (par1.X(), par1.Y());
+         if (!prop->IsCurvatureDefined())
+         {
+            (*testout) << "curvature not defined!" << endl;
+            return;
+         }
+         curvature = max(curvature,max(fabs(prop->MinCurvature()),
+            fabs(prop->MaxCurvature())));
+
+         prop->SetParameters (par2.X(), par2.Y());
+         if (!prop->IsCurvatureDefined())
+         {
+            (*testout) << "curvature not defined!" << endl;
+            return;
+         }
+         curvature = max(curvature,max(fabs(prop->MinCurvature()),
+            fabs(prop->MaxCurvature())));
+
+         //(*testout) << "curvature " << curvature << endl;
+
+         if (curvature < 1e-3)
+         {
+            //(*testout) << "curvature too small (" << curvature << ")!" << endl;
+            return;
+            // return war bis 10.2.05 auskommentiert
+         }
+
+
+
+         h = ComputeH (curvature+1e-10);
+
+         if(h < 1e-4*maxside)
+            return;
+
+
+         if (h > 30) return;
+      }
+
+      if (h < maxside && depth < 10)
+      {
+         //cout << "\r h " << h << flush;
+         gp_Pnt2d pm;
+
+         //cout << "h " << h << " maxside " << maxside << " depth " << depth << endl;
+         //cout << "par0 " << par0.X() << " " << par0.Y()
+         //<< " par1 " << par1.X() << " " << par1.Y()
+         //   << " par2 " << par2.X() << " " << par2.Y()<< endl;
+
+         if(ls == 0)
+         {
+            pm.SetX(0.5*(par1.X()+par2.X())); pm.SetY(0.5*(par1.Y()+par2.Y()));
+            RestrictHTriangle(pm, par2, par0, prop, mesh, depth+1, h);
+            RestrictHTriangle(pm, par0, par1, prop, mesh, depth+1, h);
+         }
+         else if(ls == 1)
+         {
+            pm.SetX(0.5*(par0.X()+par2.X())); pm.SetY(0.5*(par0.Y()+par2.Y()));
+            RestrictHTriangle(pm, par1, par2, prop, mesh, depth+1, h);
+            RestrictHTriangle(pm, par0, par1, prop, mesh, depth+1, h);
+         }
+         else if(ls == 2)
+         {
+            pm.SetX(0.5*(par0.X()+par1.X())); pm.SetY(0.5*(par0.Y()+par1.Y()));
+            RestrictHTriangle(pm, par1, par2, prop, mesh, depth+1, h);
+            RestrictHTriangle(pm, par2, par0, prop, mesh, depth+1, h);
+         }
+
+      }
+      else
+      {
+         gp_Pnt pnt;
+         Point3d p3d;
+
+         prop->SetParameters (parmid.X(), parmid.Y());
+         pnt = prop->Value();
+         p3d = Point3d(pnt.X(), pnt.Y(), pnt.Z());
+         mesh.RestrictLocalH (p3d, h);
+
+         p3d = Point3d(pnt0.X(), pnt0.Y(), pnt0.Z());
+         mesh.RestrictLocalH (p3d, h);
+
+         p3d = Point3d(pnt1.X(), pnt1.Y(), pnt1.Z());
+         mesh.RestrictLocalH (p3d, h);
+
+         p3d = Point3d(pnt2.X(), pnt2.Y(), pnt2.Z());
+         mesh.RestrictLocalH (p3d, h);
+
+         //(*testout) << "p = " << p3d << ", h = " << h << ", maxside = " << maxside << endl;
+
+      }
+   }
+
+
+
+   void DivideEdge (TopoDS_Edge & edge, Array<MeshPoint> & ps,
+                    Array<double> & params, Mesh & mesh)
+   {
+      double s0, s1;
+      double maxh = mparam.maxh;
+      int nsubedges = 1;
+      gp_Pnt pnt, oldpnt;
+      double svalue[DIVIDEEDGESECTIONS];
+
+      GProp_GProps system;
+      BRepGProp::LinearProperties(edge, system);
+      double L = system.Mass();
+
+      Handle(Geom_Curve) c = BRep_Tool::Curve(edge, s0, s1);
+
+      double hvalue[DIVIDEEDGESECTIONS+1];
+      hvalue[0] = 0;
+      pnt = c->Value(s0);
+
+      double olddist = 0;
+      double dist = 0;
+
+      int tmpVal = (int)(DIVIDEEDGESECTIONS);
+
+      for (int i = 1; i <= tmpVal; i++)
+      {
+         oldpnt = pnt;
+         pnt = c->Value(s0+(i/double(DIVIDEEDGESECTIONS))*(s1-s0));
+         hvalue[i] = hvalue[i-1] +
+            1.0/mesh.GetH(Point3d(pnt.X(), pnt.Y(), pnt.Z()))*
+            pnt.Distance(oldpnt);
+
+         //(*testout) << "mesh.GetH(Point3d(pnt.X(), pnt.Y(), pnt.Z())) " << mesh.GetH(Point3d(pnt.X(), pnt.Y(), pnt.Z()))
+         //	   <<  " pnt.Distance(oldpnt) " << pnt.Distance(oldpnt) << endl;
+
+         olddist = dist;
+         dist = pnt.Distance(oldpnt);
+      }
+
+      //  nsubedges = int(ceil(hvalue[DIVIDEEDGESECTIONS]));
+      nsubedges = max (1, int(floor(hvalue[DIVIDEEDGESECTIONS]+0.5)));
+
+      ps.SetSize(nsubedges-1);
+      params.SetSize(nsubedges+1);
+
+      int i = 1;
+      int i1 = 0;
+      do
+      {
+         if (hvalue[i1]/hvalue[DIVIDEEDGESECTIONS]*nsubedges >= i)
+         {
+            params[i] = s0+(i1/double(DIVIDEEDGESECTIONS))*(s1-s0);
+            pnt = c->Value(params[i]);
+            ps[i-1] = MeshPoint (Point3d(pnt.X(), pnt.Y(), pnt.Z()));
+            i++;
+         }
+         i1++;
+         if (i1 > DIVIDEEDGESECTIONS)
+         {
+            nsubedges = i;
+            ps.SetSize(nsubedges-1);
+            params.SetSize(nsubedges+1);
+            cout << "divide edge: local h too small" << endl;
+         }
+      } while (i < nsubedges);
+
+      params[0] = s0;
+      params[nsubedges] = s1;
+
+      if (params[nsubedges] <= params[nsubedges-1])
+      {
+         cout << "CORRECTED" << endl;
+         ps.SetSize (nsubedges-2);
+         params.SetSize (nsubedges);
+         params[nsubedges] = s1;
+      }
+   }
+
+
+
+
+   void OCCFindEdges (OCCGeometry & geom, Mesh & mesh)
+   {
+      const char * savetask = multithread.task;
+      multithread.task = "Edge meshing";
+
+      (*testout) << "edge meshing" << endl;
+
+      int nvertices = geom.vmap.Extent();
+      int nedges = geom.emap.Extent();
+
+      (*testout) << "nvertices = " << nvertices << endl;
+      (*testout) << "nedges = " << nedges << endl;
+
+      double eps = 1e-6 * geom.GetBoundingBox().Diam();
+
+      for (int i = 1; i <= nvertices; i++)
+      {
+         gp_Pnt pnt = BRep_Tool::Pnt (TopoDS::Vertex(geom.vmap(i)));
+         MeshPoint mp( Point<3>(pnt.X(), pnt.Y(), pnt.Z()) );
+
+         bool exists = 0;
+         if (merge_solids)
+            for (PointIndex pi = 1; pi <= mesh.GetNP(); pi++)
+               if ( Dist2 (mesh[pi], Point<3>(mp)) < eps*eps)
+               {
+                  exists = 1;
+                  break;
+               }
+
+               if (!exists)
+                  mesh.AddPoint (mp);
+      }
+
+      (*testout) << "different vertices = " << mesh.GetNP() << endl;
+
+
+      int first_ep = mesh.GetNP()+1;
+
+      Array<int> face2solid[2];
+      for (int i = 0; i<2; i++)
+      {
+         face2solid[i].SetSize (geom.fmap.Extent());
+         face2solid[i] = 0;
+      }
+
+      int solidnr = 0;
+      for (TopExp_Explorer exp0(geom.shape, TopAbs_SOLID); exp0.More(); exp0.Next())
+      {
+         solidnr++;
+         for (TopExp_Explorer exp1(exp0.Current(), TopAbs_FACE); exp1.More(); exp1.Next())
+         {
+            TopoDS_Face face = TopoDS::Face(exp1.Current());
+            int facenr = geom.fmap.FindIndex(face);
+
+            if (face2solid[0][facenr-1] == 0)
+               face2solid[0][facenr-1] = solidnr;
+            else
+               face2solid[1][facenr-1] = solidnr;
+         }
+      }
+
+
+      int total = 0;
+      for (int i3 = 1; i3 <= geom.fmap.Extent(); i3++)
+         for (TopExp_Explorer exp2(geom.fmap(i3), TopAbs_WIRE); exp2.More(); exp2.Next())
+            for (TopExp_Explorer exp3(exp2.Current(), TopAbs_EDGE); exp3.More(); exp3.Next())
+               total++;
+
+
+      int facenr = 0;
+      int edgenr = 0;
+
+
+      (*testout) << "faces = " << geom.fmap.Extent() << endl;
+      int curr = 0;
+
+      for (int i3 = 1; i3 <= geom.fmap.Extent(); i3++)
+      {
+         TopoDS_Face face = TopoDS::Face(geom.fmap(i3));
+         facenr = geom.fmap.FindIndex (face);       // sollte doch immer == i3 sein ??? JS
+
+         int solidnr0 = face2solid[0][i3-1];
+         int solidnr1 = face2solid[1][i3-1];
+
+         /* auskommentiert am 3.3.05 von robert
+         for (exp2.Init (geom.somap(solidnr0), TopAbs_FACE); exp2.More(); exp2.Next())
+         {
+         TopoDS_Face face2 = TopoDS::Face(exp2.Current());
+         if (geom.fmap.FindIndex(face2) == facenr)
+         {
+         //		      if (face.Orientation() != face2.Orientation()) swap (solidnr0, solidnr1);
+         }
+         }
+         */
+
+         mesh.AddFaceDescriptor (FaceDescriptor(facenr, solidnr0, solidnr1, 0));
+
+         // Philippose - 06/07/2009
+         // Add the face colour to the mesh data
+         Quantity_Color face_colour;
+
+         if(!(geom.face_colours.IsNull())
+            && (geom.face_colours->GetColor(face,XCAFDoc_ColorSurf,face_colour)))
+         {
+            mesh.GetFaceDescriptor(facenr).SetSurfColour(Vec3d(face_colour.Red(),face_colour.Green(),face_colour.Blue()));
+         }
+         else
+         {
+            mesh.GetFaceDescriptor(facenr).SetSurfColour(Vec3d(0.0,1.0,0.0));
+         }
+         // ACHTUNG! STIMMT NICHT ALLGEMEIN (RG)
+
+
+         Handle(Geom_Surface) occface = BRep_Tool::Surface(face);
+
+         for (TopExp_Explorer exp2 (face, TopAbs_WIRE); exp2.More(); exp2.Next())
+         {
+            TopoDS_Shape wire = exp2.Current();
+
+            for (TopExp_Explorer exp3 (wire, TopAbs_EDGE); exp3.More(); exp3.Next())
+            {
+               curr++;
+               (*testout) << "edge nr " << curr << endl;
+
+               multithread.percent = 100 * curr / double (total);
+               if (multithread.terminate) return;
+
+               TopoDS_Edge edge = TopoDS::Edge (exp3.Current());
+               if (BRep_Tool::Degenerated(edge))
+               {
+                  //(*testout) << "ignoring degenerated edge" << endl;
+                  continue;
+               }
+
+               if (geom.vmap.FindIndex(TopExp::FirstVertex (edge)) ==
+                  geom.vmap.FindIndex(TopExp::LastVertex (edge)))
+               {
+                  GProp_GProps system;
+                  BRepGProp::LinearProperties(edge, system);
+
+                  if (system.Mass() < eps)
+                  {
+                     cout << "ignoring edge " << geom.emap.FindIndex (edge)
+                        << ". closed edge with length < " << eps << endl;
+                     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);
+
+               if (!merge_solids)
+               {
+                  pnums[0] = geom.vmap.FindIndex (TopExp::FirstVertex (edge));
+                  pnums[pnums.Size()-1] = geom.vmap.FindIndex (TopExp::LastVertex (edge));
+               }
+               else
+               {
+                  Point<3> fp = occ2ng (BRep_Tool::Pnt (TopExp::FirstVertex (edge)));
+                  Point<3> lp = occ2ng (BRep_Tool::Pnt (TopExp::LastVertex (edge)));
+
+                  pnums[0] = -1;
+                  pnums.Last() = -1;
+                  for (PointIndex pi = 1; pi < first_ep; pi++)
+                  {
+                     if (Dist2 (mesh[pi], fp) < eps*eps) pnums[0] = pi;
+                     if (Dist2 (mesh[pi], lp) < eps*eps) pnums.Last() = pi;
+                  }
+               }
+
+
+               for (int i = 1; i <= mp.Size(); i++)
+               {
+                  bool exists = 0;
+                  int j;
+                  for (j = first_ep; j <= mesh.GetNP(); j++)
+                     if ((mesh.Point(j)-Point<3>(mp[i-1])).Length() < eps)
+                     {
+                        exists = 1;
+                        break;
+                     }
+
+                     if (exists)
+                        pnums[i] = j;
+                     else
+                     {
+                        mesh.AddPoint (mp[i-1]);
+                        (*testout) << "add meshpoint " << mp[i-1] << endl;
+                        pnums[i] = mesh.GetNP();
+                     }
+               }
+               (*testout) << "NP = " << mesh.GetNP() << endl;
+
+               //(*testout) << pnums[pnums.Size()-1] << endl;
+
+               for (int i = 1; i <= mp.Size()+1; i++)
+               {
+                  edgenr++;
+                  Segment seg;
+
+                  seg[0] = pnums[i-1];
+                  seg[1] = 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]);
+                  //			if (i == 1) p2d = cof->Value(s0);
+                  seg.epgeominfo[0].u = p2d.X();
+                  seg.epgeominfo[0].v = p2d.Y();
+                  p2d = cof->Value(params[i]);
+                  //			if (i == mp.Size()+1) p2d = cof -> Value(s1);
+                  seg.epgeominfo[1].u = p2d.X();
+                  seg.epgeominfo[1].v = p2d.Y();
+
+                  /*
+                  if (occface->IsUPeriodic())
+                  {
+                  cout << "U Periodic" << endl;
+                  if (fabs(seg.epgeominfo[1].u-seg.epgeominfo[0].u) >
+                  fabs(seg.epgeominfo[1].u-
+                  (seg.epgeominfo[0].u-occface->UPeriod())))
+                  seg.epgeominfo[0].u = p2d.X()+occface->UPeriod();
+
+                  if (fabs(seg.epgeominfo[1].u-seg.epgeominfo[0].u) >
+                  fabs(seg.epgeominfo[1].u-
+                  (seg.epgeominfo[0].u+occface->UPeriod())))
+                  seg.epgeominfo[0].u = p2d.X()-occface->UPeriod();
+                  }
+
+                  if (occface->IsVPeriodic())
+                  {
+                  cout << "V Periodic" << endl;
+                  if (fabs(seg.epgeominfo[1].v-seg.epgeominfo[0].v) >
+                  fabs(seg.epgeominfo[1].v-
+                  (seg.epgeominfo[0].v-occface->VPeriod())))
+                  seg.epgeominfo[0].v = p2d.Y()+occface->VPeriod();
+
+                  if (fabs(seg.epgeominfo[1].v-seg.epgeominfo[0].v) >
+                  fabs(seg.epgeominfo[1].v-
+                  (seg.epgeominfo[0].v+occface->VPeriod())))
+                  seg.epgeominfo[0].v = p2d.Y()-occface->VPeriod();
+                  }
+                  */
+
+                  if (edge.Orientation() == TopAbs_REVERSED)
+                  {
+                     swap (seg[0], seg[1]);
+                     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);
+
+                  //edgesegments[geomedgenr-1]->Append(mesh.GetNSeg());
+
+               }
+            }
+         }
+      }
+
+      //	for(i=1; i<=mesh.GetNSeg(); i++)
+      //		(*testout) << "edge " << mesh.LineSegment(i).edgenr << " face " << mesh.LineSegment(i).si
+      //				<< " p1 " << mesh.LineSegment(i)[0] << " p2 " << mesh.LineSegment(i)[1] << endl;
+      //	exit(10);
+
+      mesh.CalcSurfacesOfNode();
+      multithread.task = savetask;
+   }
+
+
+
+
+   void OCCMeshSurface (OCCGeometry & geom, Mesh & mesh, int perfstepsend)
+   {
+      int i, j, k;
+      int changed;
+
+      const char * savetask = multithread.task;
+      multithread.task = "Surface meshing";
+
+      geom.facemeshstatus = 0;
+
+      int noldp = mesh.GetNP();
+
+      double starttime = GetTime();
+
+      Array<int> glob2loc(noldp);
+
+      //int projecttype = PARAMETERSPACE;
+
+      int projecttype = PARAMETERSPACE;
+
+      int notrys = 1;
+
+      int surfmesherror = 0;
+
+      for (k = 1; k <= mesh.GetNFD(); k++)
+      {
+         if(1==0 && !geom.fvispar[k-1].IsDrawable())
+         {
+            (*testout) << "ignoring face " << k << endl;
+            cout << "ignoring face " << k << endl;
+            continue;
+         }
+
+         (*testout) << "mesh face " << k << endl;
+         multithread.percent = 100 * k / (mesh.GetNFD() + VSMALL);
+         geom.facemeshstatus[k-1] = -1;
+
+
+         /*
+         if (k != 42)
+         {
+         cout << "skipped" << endl;
+         continue;
+         }
+         */
+
+
+         FaceDescriptor & fd = mesh.GetFaceDescriptor(k);
+
+         int oldnf = mesh.GetNSE();
+
+         Box<3> bb = geom.GetBoundingBox();
+
+         //      int projecttype = PLANESPACE;
+
+         Meshing2OCCSurfaces meshing(TopoDS::Face(geom.fmap(k)), bb, projecttype);
+
+         if (meshing.GetProjectionType() == PLANESPACE)
+            PrintMessage (2, "Face ", k, " / ", mesh.GetNFD(), " (plane space projection)");
+         else
+            PrintMessage (2, "Face ", k, " / ", mesh.GetNFD(), " (parameter space projection)");
+
+         if (surfmesherror)
+            cout << "Surface meshing error occured before (in " << surfmesherror << " faces)" << endl;
+
+         //      Meshing2OCCSurfaces meshing(f2, bb);
+         meshing.SetStartTime (starttime);
+
+         //(*testout) << "Face " << k << endl << endl;
+
+
+         if (meshing.GetProjectionType() == PLANESPACE)
+         {
+            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[0] : seg[1];
+                     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[0]), glob2loc.Get(seg[1]), gi0, gi1);
+                  //(*testout) << gi0.u << " " << gi0.v << endl;
+                  //(*testout) << gi1.u << " " << gi1.v << endl;
+               }
+            }
+         }
+         else
+         {
+            int cntp = 0;
+
+            for (i = 1; i <= mesh.GetNSeg(); i++)
+               if (mesh.LineSegment(i).si == k)
+                  cntp+=2;
+
+
+            Array< PointGeomInfo > gis;
+
+            gis.SetAllocSize (cntp);
+            gis.SetSize (0);
+
+            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;
+
+                  int locpnum[2] = {0, 0};
+
+                  for (j = 0; j < 2; j++)
+                  {
+                     PointGeomInfo gi = (j == 0) ? gi0 : gi1;
+
+                     int l;
+                     for (l = 0; l < gis.Size() && locpnum[j] == 0; l++)
+                     {
+                        double dist = sqr (gis[l].u-gi.u)+sqr(gis[l].v-gi.v);
+
+                        if (dist < 1e-10)
+                           locpnum[j] = l+1;
+                     }
+
+                     if (locpnum[j] == 0)
+                     {
+                        int pi = (j == 0) ? seg[0] : seg[1];
+                        meshing.AddPoint (mesh.Point(pi), pi);
+
+                        gis.SetSize (gis.Size()+1);
+                        gis[l] = gi;
+                        locpnum[j] = l+1;
+                     }
+                  }
+
+                  meshing.AddBoundaryElement (locpnum[0], locpnum[1], gi0, gi1);
+                  //(*testout) << gi0.u << " " << gi0.v << endl;
+                  //(*testout) << gi1.u << " " << gi1.v << endl;
+
+               }
+            }
+         }
+
+
+
+
+
+         // Philippose - 15/01/2009
+         double maxh = geom.face_maxh[k-1];
+         //double maxh = mparam.maxh;
+         mparam.checkoverlap = 0;
+         //      int noldpoints = mesh->GetNP();
+         int noldsurfel = mesh.GetNSE();
+
+         GProp_GProps sprops;
+         BRepGProp::SurfaceProperties(TopoDS::Face(geom.fmap(k)),sprops);
+         meshing.SetMaxArea(2.*sprops.Mass());
+
+         MESHING2_RESULT res;
+
+         try {
+	   res = meshing.GenerateMesh (mesh, mparam, maxh, k);
+         }
+
+         catch (SingularMatrixException)
+         {
+            (*myerr) << "Singular Matrix" << endl;
+            res = MESHING2_GIVEUP;
+         }
+
+         catch (UVBoundsException)
+         {
+            (*myerr) << "UV bounds exceeded" << endl;
+            res = MESHING2_GIVEUP;
+         }
+
+         projecttype = PARAMETERSPACE;
+
+         if (res != MESHING2_OK)
+         {
+            if (notrys == 1)
+            {
+               for (int i = noldsurfel+1; i <= mesh.GetNSE(); i++)
+                  mesh.DeleteSurfaceElement (i);
+
+               mesh.Compress();
+
+               cout << "retry Surface " << k << endl;
+
+               k--;
+               projecttype*=-1;
+               notrys++;
+               continue;
+            }
+            else
+            {
+               geom.facemeshstatus[k-1] = -1;
+               PrintError ("Problem in Surface mesh generation");
+               surfmesherror++;
+               //	      throw NgException ("Problem in Surface mesh generation");
+            }
+         }
+         else
+         {
+            geom.facemeshstatus[k-1] = 1;
+         }
+
+         notrys = 1;
+
+         for (i = oldnf+1; i <= mesh.GetNSE(); i++)
+            mesh.SurfaceElement(i).SetIndex (k);
+
+      }
+
+//      ofstream problemfile("occmesh.rep");
+
+//      problemfile << "SURFACEMESHING" << endl << endl;
+
+      if (surfmesherror)
+      {
+         cout << "WARNING! NOT ALL FACES HAVE BEEN MESHED" << endl;
+         cout << "SURFACE MESHING ERROR OCCURED IN " << surfmesherror << " FACES:" << endl;
+         for (int i = 1; i <= geom.fmap.Extent(); i++)
+            if (geom.facemeshstatus[i-1] == -1)
+            {
+               cout << "Face " << i << endl;
+//               problemfile << "problem with face " << i << endl;
+//               problemfile << "vertices: " << endl;
+               TopExp_Explorer exp0,exp1,exp2;
+               for ( exp0.Init(TopoDS::Face (geom.fmap(i)), TopAbs_WIRE); exp0.More(); exp0.Next() )
+               {
+                  TopoDS_Wire wire = TopoDS::Wire(exp0.Current());
+                  for ( exp1.Init(wire,TopAbs_EDGE); exp1.More(); exp1.Next() )
+                  {
+                     TopoDS_Edge edge = TopoDS::Edge(exp1.Current());
+                     for ( exp2.Init(edge,TopAbs_VERTEX); exp2.More(); exp2.Next() )
+                     {
+                        TopoDS_Vertex vertex = TopoDS::Vertex(exp2.Current());
+                        gp_Pnt point = BRep_Tool::Pnt(vertex);
+//                        problemfile << point.X() << " " << point.Y() << " " << point.Z() << endl;
+                     }
+                  }
+               }
+//               problemfile << endl;
+
+            }
+            cout << endl << endl;
+            cout << "for more information open IGES/STEP Topology Explorer" << endl;
+//            problemfile.close();
+            throw NgException ("Problem in Surface mesh generation");
+      }
+      else
+      {
+//         problemfile << "OK" << endl << endl;
+//         problemfile.close();
+      }
+
+
+
+
+      if (multithread.terminate || perfstepsend < MESHCONST_OPTSURFACE)
+         return;
+
+      multithread.task = "Optimizing surface";
+
+      static int timer_opt2d = NgProfiler::CreateTimer ("Optimization 2D");
+      NgProfiler::StartTimer (timer_opt2d);
+
+      for (k = 1; k <= mesh.GetNFD(); k++)
+      {
+         //      if (k != 42) continue;
+         //      if (k != 36) continue;
+
+         //      (*testout) << "optimize face " << k << endl;
+         multithread.percent = 100 * k / (mesh.GetNFD() + VSMALL);
+
+         FaceDescriptor & fd = mesh.GetFaceDescriptor(k);
+
+         PrintMessage (1, "Optimize Surface ", k);
+         for (i = 1; i <= mparam.optsteps2d; i++)
+         {
+            //	  (*testout) << "optstep " << i << endl;
+            if (multithread.terminate) return;
+
+            {
+               MeshOptimize2dOCCSurfaces meshopt(geom);
+               meshopt.SetFaceIndex (k);
+               meshopt.SetImproveEdges (0);
+               meshopt.SetMetricWeight (mparam.elsizeweight);
+               //meshopt.SetMetricWeight (0.2);
+               meshopt.SetWriteStatus (0);
+
+               //	    (*testout) << "EdgeSwapping (mesh, (i > mparam.optsteps2d/2))" << endl;
+               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.SetMetricWeight (mparam.elsizeweight);
+               meshopt.SetWriteStatus (0);
+
+               //	    (*testout) << "ImproveMesh (mesh)" << endl;
+               meshopt.ImproveMesh (mesh, mparam);
+            }
+
+            {
+               MeshOptimize2dOCCSurfaces meshopt(geom);
+               meshopt.SetFaceIndex (k);
+               meshopt.SetImproveEdges (0);
+               //meshopt.SetMetricWeight (0.2);
+               meshopt.SetMetricWeight (mparam.elsizeweight);
+               meshopt.SetWriteStatus (0);
+
+               //	    (*testout) << "CombineImprove (mesh)" << endl;
+               meshopt.CombineImprove (mesh);
+            }
+
+            if (multithread.terminate) return;
+            {
+               MeshOptimize2dOCCSurfaces meshopt(geom);
+               meshopt.SetFaceIndex (k);
+               meshopt.SetImproveEdges (0);
+               //meshopt.SetMetricWeight (0.2);
+               meshopt.SetMetricWeight (mparam.elsizeweight);
+               meshopt.SetWriteStatus (0);
+
+               //	    (*testout) << "ImproveMesh (mesh)" << endl;
+               meshopt.ImproveMesh (mesh, mparam);
+            }
+         }
+
+      }
+
+
+      mesh.CalcSurfacesOfNode();
+      mesh.Compress();
+
+      NgProfiler::StopTimer (timer_opt2d);
+
+      multithread.task = savetask;
+   }
+
+
+
+   void OCCSetLocalMeshSize(OCCGeometry & geom, Mesh & mesh)
+   {
+      mesh.SetGlobalH (mparam.maxh);
+      mesh.SetMinimalH (mparam.minh);
+
+      Array<double> maxhdom;
+      maxhdom.SetSize (geom.NrSolids());
+      maxhdom = mparam.maxh;
+
+      mesh.SetMaxHDomain (maxhdom);
+
+      Box<3> bb = geom.GetBoundingBox();
+      bb.Increase (bb.Diam()/10);
+
+      mesh.SetLocalH (bb.PMin(), bb.PMax(), 0.5);
+
+      if (mparam.uselocalh)
+      {
+         const char * savetask = multithread.task;
+         multithread.percent = 0;
+
+         mesh.SetLocalH (bb.PMin(), bb.PMax(), mparam.grading);
+
+         int nedges = geom.emap.Extent();
+
+         double maxedgelen = 0;
+         double minedgelen = 1e99;
+
+         multithread.task = "Setting local mesh size (elements per edge)";
+
+         // setting elements per edge
+
+         for (int i = 1; i <= nedges && !multithread.terminate; i++)
+         {
+            TopoDS_Edge e = TopoDS::Edge (geom.emap(i));
+            multithread.percent = 100 * (i-1)/double(nedges);
+            if (BRep_Tool::Degenerated(e)) continue;
+
+            GProp_GProps system;
+            BRepGProp::LinearProperties(e, system);
+            double len = system.Mass();
+
+            if (len < IGNORECURVELENGTH)
+            {
+               (*testout) << "ignored" << endl;
+               continue;
+            }
+
+            double localh = len/mparam.segmentsperedge;
+            double s0, s1;
+
+            // Philippose - 23/01/2009
+            // Find all the parent faces of a given edge
+            // and limit the mesh size of the edge based on the
+            // mesh size limit of the face
+            TopTools_IndexedDataMapOfShapeListOfShape edge_face_map;
+            edge_face_map.Clear();
+
+            TopExp::MapShapesAndAncestors(geom.shape, TopAbs_EDGE, TopAbs_FACE, edge_face_map);
+            const TopTools_ListOfShape& parent_faces = edge_face_map.FindFromKey(e);
+
+            TopTools_ListIteratorOfListOfShape parent_face_list;
+
+            for(parent_face_list.Initialize(parent_faces); parent_face_list.More(); parent_face_list.Next())
+            {
+               TopoDS_Face parent_face = TopoDS::Face(parent_face_list.Value());
+
+               int face_index = geom.fmap.FindIndex(parent_face);
+
+               if(face_index >= 1) localh = min(localh,geom.face_maxh[face_index - 1]);
+            }
+
+            Handle(Geom_Curve) c = BRep_Tool::Curve(e, s0, s1);
+
+            maxedgelen = max (maxedgelen, len);
+            minedgelen = min (minedgelen, len);
+
+            // Philippose - 23/01/2009
+            // Modified the calculation of maxj, because the
+            // method used so far always results in maxj = 2,
+            // which causes the localh to be set only at the
+            // starting, mid and end of the edge.
+            // Old Algorithm:
+            // int maxj = 2 * (int) ceil (localh/len);
+            int maxj = max((int) ceil(len/localh), 2);
+
+            for (int j = 0; j <= maxj; j++)
+            {
+               gp_Pnt pnt = c->Value (s0+double(j)/maxj*(s1-s0));
+               mesh.RestrictLocalH (Point3d(pnt.X(), pnt.Y(), pnt.Z()), localh);
+            }
+         }
+
+         multithread.task = "Setting local mesh size (edge curvature)";
+
+         // setting edge curvature
+
+         int nsections = 20;
+
+         for (int i = 1; i <= nedges && !multithread.terminate; i++)
+         {
+            double maxcur = 0;
+            multithread.percent = 100 * (i-1)/double(nedges);
+            TopoDS_Edge edge = TopoDS::Edge (geom.emap(i));
+            if (BRep_Tool::Degenerated(edge)) continue;
+            double s0, s1;
+            Handle(Geom_Curve) c = BRep_Tool::Curve(edge, s0, s1);
+            BRepAdaptor_Curve brepc(edge);
+            BRepLProp_CLProps prop(brepc, 2, 1e-5);
+
+            for (int j = 1; j <= nsections; j++)
+            {
+               double s = s0 + j/(double) nsections * (s1-s0);
+               prop.SetParameter (s);
+               double curvature = prop.Curvature();
+               if(curvature> maxcur) maxcur = curvature;
+
+               if (curvature >= 1e99)
+                  continue;
+
+               gp_Pnt pnt = c->Value (s);
+
+               mesh.RestrictLocalH (Point3d(pnt.X(), pnt.Y(), pnt.Z()), ComputeH (fabs(curvature)));
+            }
+            // (*testout) << "edge " << i << " max. curvature: " << maxcur << endl;
+         }
+
+         multithread.task = "Setting local mesh size (face curvature)";
+
+         // setting face curvature
+
+         int nfaces = geom.fmap.Extent();
+
+         for (int i = 1; i <= nfaces && !multithread.terminate; i++)
+         {
+            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);
+
+            if (triangulation.IsNull()) continue;
+
+            BRepAdaptor_Surface sf(face, Standard_True);
+            BRepLProp_SLProps prop(sf, 2, 1e-5);
+
+            int ntriangles = triangulation -> NbTriangles();
+            for (int j = 1; j <= ntriangles; j++)
+            {
+               gp_Pnt p[3];
+               gp_Pnt2d par[3];
+
+               for (int k = 1; k <=3; k++)
+               {
+                  int n = triangulation->Triangles()(j)(k);
+                  p[k-1] = triangulation->Nodes()(n).Transformed(loc);
+                  par[k-1] = triangulation->UVNodes()(n);
+               }
+
+               //double maxside = 0;
+               //maxside = max (maxside, p[0].Distance(p[1]));
+               //maxside = max (maxside, p[0].Distance(p[2]));
+               //maxside = max (maxside, p[1].Distance(p[2]));
+               //cout << "\rFace " << i << " pos11 ntriangles " << ntriangles << " maxside " << maxside << flush;
+
+               RestrictHTriangle (par[0], par[1], par[2], &prop, mesh, 0);
+               //cout << "\rFace " << i << " pos12 ntriangles " << ntriangles << flush;
+            }
+         }
+
+         // setting close edges
+
+         if (occparam.resthcloseedgeenable)
+         {
+            multithread.task = "Setting local mesh size (close edges)";
+
+            int sections = 100;
+
+            Array<Line> lines(sections*nedges);
+
+            Box3dTree* searchtree =
+               new Box3dTree (bb.PMin(), bb.PMax());
+
+            int nlines = 0;
+            for (int i = 1; i <= nedges && !multithread.terminate; i++)
+            {
+               TopoDS_Edge edge = TopoDS::Edge (geom.emap(i));
+               if (BRep_Tool::Degenerated(edge)) continue;
+
+               double s0, s1;
+               Handle(Geom_Curve) c = BRep_Tool::Curve(edge, s0, s1);
+               BRepAdaptor_Curve brepc(edge);
+               BRepLProp_CLProps prop(brepc, 1, 1e-5);
+               prop.SetParameter (s0);
+
+               gp_Vec d0 = prop.D1().Normalized();
+               double s_start = s0;
+               int count = 0;
+               for (int j = 1; j <= sections; j++)
+               {
+                  double s = s0 + (s1-s0)*(double)j/(double)sections;
+                  prop.SetParameter (s);
+                  gp_Vec d1 = prop.D1().Normalized();
+                  double cosalpha = fabs(d0*d1);
+                  if ((j == sections) || (cosalpha < cos(10.0/180.0*M_PI)))
+                  {
+                     count++;
+                     gp_Pnt p0 = c->Value (s_start);
+                     gp_Pnt p1 = c->Value (s);
+                     lines[nlines].p0 = Point<3> (p0.X(), p0.Y(), p0.Z());
+                     lines[nlines].p1 = Point<3> (p1.X(), p1.Y(), p1.Z());
+
+                     Box3d box;
+                     box.SetPoint (Point3d(lines[nlines].p0));
+                     box.AddPoint (Point3d(lines[nlines].p1));
+
+                     searchtree->Insert (box.PMin(), box.PMax(), nlines+1);
+                     nlines++;
+
+                     s_start = s;
+                     d0 = d1;
+                  }
+               }
+            }
+
+            Array<int> linenums;
+
+            for (int i = 0; i < nlines; i++)
+            {
+               multithread.percent = (100*i)/double(nlines);
+               Line & line = lines[i];
+
+               Box3d box;
+               box.SetPoint (Point3d(line.p0));
+               box.AddPoint (Point3d(line.p1));
+               double maxhline = max (mesh.GetH(box.PMin()),
+                  mesh.GetH(box.PMax()));
+               box.Increase(maxhline);
+
+               double mindist = 1e99;
+               linenums.SetSize(0);
+               searchtree->GetIntersecting(box.PMin(),box.PMax(),linenums);
+
+               for (int j = 0; j < linenums.Size(); j++)
+               {
+                  int num = linenums[j]-1;
+                  if (i == num) continue;
+                  if ((line.p0-lines[num].p0).Length2() < 1e-15) continue;
+                  if ((line.p0-lines[num].p1).Length2() < 1e-15) continue;
+                  if ((line.p1-lines[num].p0).Length2() < 1e-15) continue;
+                  if ((line.p1-lines[num].p1).Length2() < 1e-15) continue;
+                  mindist = min (mindist, line.Dist(lines[num]));
+               }
+
+               mindist /= (occparam.resthcloseedgefac + VSMALL);
+
+               if (mindist < 1e-3)
+               {
+                  (*testout) << "extremely small local h: " << mindist
+                     << " --> setting to 1e-3" << endl;
+                  (*testout) << "somewhere near " << line.p0 << " - " << line.p1 << endl;
+                  mindist = 1e-3;
+               }
+
+               mesh.RestrictLocalHLine(line.p0, line.p1, mindist);
+            }
+         }
+
+         multithread.task = savetask;
+
+      }
+
+      // Philippose - 09/03/2009
+      // Added the capability to load the mesh size from a 
+      // file also for OpenCascade Geometry
+      // Note: 
+      // ** If the "uselocalh" option is ticked in 
+      // the "mesh options...insider" menu, the mesh 
+      // size will be further modified by the topology 
+      // analysis routines.
+      // ** To use the mesh size file as the sole source 
+      // for defining the mesh size, uncheck the "uselocalh"
+      // option.
+      mesh.LoadLocalMeshSize (mparam.meshsizefilename);
+   }
+
+
+
+  int OCCGenerateMesh (OCCGeometry & geom, Mesh *& mesh, MeshingParameters & mparam,
+		       int perfstepsstart, int perfstepsend)
+   {
+      multithread.percent = 0;
+
+      if (perfstepsstart <= MESHCONST_ANALYSE)
+      {
+         delete mesh;
+         mesh = new Mesh();
+         mesh->geomtype = Mesh::GEOM_OCC;
+
+         OCCSetLocalMeshSize(geom,*mesh);
+      }
+
+      if (multithread.terminate || perfstepsend <= MESHCONST_ANALYSE)
+         return TCL_OK;
+
+      if (perfstepsstart <= MESHCONST_MESHEDGES)
+      {
+         OCCFindEdges (geom, *mesh);
+
+         /*
+         cout << "Removing redundant points" << endl;
+
+         int i, j;
+         int np = mesh->GetNP();
+         Array<int> equalto;
+
+         equalto.SetSize (np);
+         equalto = 0;
+
+         for (i = 1; i <= np; i++)
+         {
+         for (j = i+1; j <= np; j++)
+         {
+         if (!equalto[j-1] && (Dist2 (mesh->Point(i), mesh->Point(j)) < 1e-12))
+         equalto[j-1] = i;
+         }
+         }
+
+         for (i = 1; i <= np; i++)
+         if (equalto[i-1])
+         {
+         cout << "Point " << i << " is equal to Point " << equalto[i-1] << endl;
+         for (j = 1; j <= mesh->GetNSeg(); j++)
+         {
+         Segment & seg = mesh->LineSegment(j);
+         if (seg[0] == i) seg[0] = equalto[i-1];
+         if (seg[1] == i) seg[1] = equalto[i-1];
+         }
+         }
+
+         cout << "Removing degenerated segments" << endl;
+         for (j = 1; j <= mesh->GetNSeg(); j++)
+         {
+         Segment & seg = mesh->LineSegment(j);
+         if (seg[0] == seg[1])
+         {
+         mesh->DeleteSegment(j);
+         cout << "Deleting Segment " << j << endl;
+         }
+         }
+
+         mesh->Compress();
+         */
+
+         /*
+         for (int i = 1; i <= geom.fmap.Extent(); i++)
+         {
+         Handle(Geom_Surface) hf1 =
+         BRep_Tool::Surface(TopoDS::Face(geom.fmap(i)));
+         for (int j = i+1; j <= geom.fmap.Extent(); j++)
+         {
+         Handle(Geom_Surface) hf2 =
+         BRep_Tool::Surface(TopoDS::Face(geom.fmap(j)));
+         if (hf1 == hf2) cout << "face " << i << " and face " << j << " lie on same surface" << endl;
+         }
+         }
+         */
+
+#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);
+
+/*
+         ofstream problemfile("occmesh.rep",ios_base::app);
+
+         problemfile << "VOLUMEMESHING" << endl << endl;
+         if(res != MESHING3_OK)
+            problemfile << "ERROR" << endl << endl;
+         else
+            problemfile << "OK" << endl
+            << mesh->GetNE() << " elements" << endl << endl;
+
+         problemfile.close();
+*/
+
+         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);
+         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 (int i = 1; i <= mesh->GetNP(); i++)
+         (*testout) << mesh->Point(i) << endl;
+
+      (*testout) << endl << "NSegments: " << mesh->GetNSeg() << endl;
+      for (int i = 1; i <= mesh->GetNSeg(); i++)
+         (*testout) << mesh->LineSegment(i) << endl;
+
+      return TCL_OK;
+   }
+}
+
+#endif
diff --git a/contrib/Netgen/libsrc/occ/occgeom.cpp b/contrib/Netgen/libsrc/occ/occgeom.cpp
new file mode 100644
index 0000000000..a363607b64
--- /dev/null
+++ b/contrib/Netgen/libsrc/occ/occgeom.cpp
@@ -0,0 +1,1608 @@
+
+#ifdef OCCGEOMETRY
+
+#include <mystdlib.h>
+#include <occgeom.hpp>
+#include "ShapeAnalysis_ShapeTolerance.hxx"
+#include "ShapeAnalysis_ShapeContents.hxx"
+#include "ShapeAnalysis_CheckSmallFace.hxx"
+#include "ShapeAnalysis_DataMapOfShapeListOfReal.hxx"
+#include "ShapeAnalysis_Surface.hxx"
+#include "BRepAlgoAPI_Fuse.hxx"
+#include "BRepCheck_Analyzer.hxx"
+#include "BRepLib.hxx"
+#include "ShapeBuild_ReShape.hxx"
+#include "ShapeFix.hxx"
+#include "ShapeFix_FixSmallFace.hxx"
+#include "Partition_Spliter.hxx"
+
+
+namespace netgen
+{
+   void OCCGeometry :: PrintNrShapes ()
+   {
+      TopExp_Explorer e;
+      int count = 0;
+      for (e.Init(shape, TopAbs_COMPSOLID); e.More(); e.Next()) count++;
+      cout << "CompSolids: " << count << endl;
+
+      cout << "Solids    : " << somap.Extent() << endl;
+      cout << "Shells    : " << shmap.Extent() << endl;
+      cout << "Faces     : " << fmap.Extent() << endl;
+      cout << "Edges     : " << emap.Extent() << endl;
+      cout << "Vertices  : " << vmap.Extent() << endl;
+   }
+
+
+
+
+   void PrintContents (OCCGeometry * geom)
+   {
+      ShapeAnalysis_ShapeContents cont;
+      cont.Clear();
+      cont.Perform(geom->shape);
+
+      (*testout) << "OCC CONTENTS" << endl;
+      (*testout) << "============" << endl;
+      (*testout) << "SOLIDS   : " << cont.NbSolids() << endl;
+      (*testout) << "SHELLS   : " << cont.NbShells() << endl;
+      (*testout) << "FACES    : " << cont.NbFaces() << endl;
+      (*testout) << "WIRES    : " << cont.NbWires() << endl;
+      (*testout) << "EDGES    : " << cont.NbEdges() << endl;
+      (*testout) << "VERTICES : " << cont.NbVertices() << endl;
+
+      TopExp_Explorer e;
+      int count = 0;
+      for (e.Init(geom->shape, TopAbs_COMPOUND); e.More(); e.Next())
+         count++;
+      (*testout) << "Compounds: " << count << endl;
+
+      count = 0;
+      for (e.Init(geom->shape, TopAbs_COMPSOLID); e.More(); e.Next())
+         count++;
+      (*testout) << "CompSolids: " << count << endl;
+
+      (*testout) << endl;
+
+      cout << "Highest entry in topology hierarchy: " << endl;
+      if (count)
+         cout << count << " composite solid(s)" << endl;
+      else
+         if (geom->somap.Extent())
+            cout << geom->somap.Extent() << " solid(s)" << endl;
+         else
+            if (geom->shmap.Extent())
+               cout << geom->shmap.Extent() << " shells(s)" << endl;
+            else
+               if (geom->fmap.Extent())
+                  cout << geom->fmap.Extent() << " face(s)" << endl;
+               else
+                  if (geom->wmap.Extent())
+                     cout << geom->wmap.Extent() << " wire(s)" << endl;
+                  else
+                     if (geom->emap.Extent())
+                        cout << geom->emap.Extent() << " edge(s)" << endl;
+                     else
+                        if (geom->vmap.Extent())
+                           cout << geom->vmap.Extent() << " vertices(s)" << endl;
+                        else
+                           cout << "no entities" << endl;
+
+   }
+
+
+
+   void OCCGeometry :: HealGeometry ()
+   {
+      int nrc = 0, nrcs = 0,
+         nrso = somap.Extent(),
+         nrsh = shmap.Extent(),
+         nrf = fmap.Extent(),
+         nrw = wmap.Extent(),
+         nre = emap.Extent(),
+         nrv = vmap.Extent();
+
+      TopExp_Explorer exp0;
+      TopExp_Explorer exp1;
+
+
+      for (exp0.Init(shape, TopAbs_COMPOUND); exp0.More(); exp0.Next()) nrc++;
+      for (exp0.Init(shape, TopAbs_COMPSOLID); exp0.More(); exp0.Next()) nrcs++;
+
+      double surfacecont = 0;
+
+      {
+         Handle_ShapeBuild_ReShape rebuild = new ShapeBuild_ReShape;
+         rebuild->Apply(shape);
+         for (exp1.Init (shape, TopAbs_EDGE); exp1.More(); exp1.Next())
+         {
+            TopoDS_Edge edge = TopoDS::Edge(exp1.Current());
+            if ( BRep_Tool::Degenerated(edge) )
+               rebuild->Remove(edge, false);
+         }
+         shape = rebuild->Apply(shape);
+      }
+
+      BuildFMap();
+
+
+      for (exp0.Init (shape, TopAbs_FACE); exp0.More(); exp0.Next())
+      {
+         TopoDS_Face face = TopoDS::Face(exp0.Current());
+
+         GProp_GProps system;
+         BRepGProp::SurfaceProperties(face, system);
+         surfacecont += system.Mass();
+      }
+
+
+      cout << "Starting geometry healing procedure (tolerance: " << tolerance << ")" << endl
+         << "-----------------------------------" << endl;
+
+      {
+         cout << endl << "- repairing faces" << endl;
+
+         Handle(ShapeFix_Face) sff;
+         Handle_ShapeBuild_ReShape rebuild = new ShapeBuild_ReShape;
+         rebuild->Apply(shape);
+
+
+         for (exp0.Init (shape, TopAbs_FACE); exp0.More(); exp0.Next())
+         {
+            // Variable to hold the colour (if there exists one) of 
+            // the current face being processed
+            Quantity_Color face_colour;
+
+            TopoDS_Face face = TopoDS::Face (exp0.Current());
+
+            if(face_colours.IsNull()
+               || (!(face_colours->GetColor(face,XCAFDoc_ColorSurf,face_colour))))
+            {
+               // Set the default face colour to green (Netgen Standard)
+               // if no colour has been defined for the face
+               face_colour = Quantity_Color(0.0,1.0,0.0,Quantity_TOC_RGB);
+            }
+
+            sff = new ShapeFix_Face (face);
+            sff->FixAddNaturalBoundMode() = Standard_True;
+            sff->FixSmallAreaWireMode() = Standard_True;
+            sff->Perform();
+
+            if(sff->Status(ShapeExtend_DONE1) ||
+               sff->Status(ShapeExtend_DONE2) ||
+               sff->Status(ShapeExtend_DONE3) ||
+               sff->Status(ShapeExtend_DONE4) ||
+               sff->Status(ShapeExtend_DONE5))
+            {
+               cout << "repaired face " << fmap.FindIndex(face) << " ";
+               if(sff->Status(ShapeExtend_DONE1))
+                  cout << "(some wires are fixed)" <<endl;
+               else if(sff->Status(ShapeExtend_DONE2))
+                  cout << "(orientation of wires fixed)" <<endl;
+               else if(sff->Status(ShapeExtend_DONE3))
+                  cout << "(missing seam added)" <<endl;
+               else if(sff->Status(ShapeExtend_DONE4))
+                  cout << "(small area wire removed)" <<endl;
+               else if(sff->Status(ShapeExtend_DONE5))
+                  cout << "(natural bounds added)" <<endl;
+               TopoDS_Face newface = sff->Face();
+
+               rebuild->Replace(face, newface, Standard_False);
+            }
+
+            // Set the original colour of the face to the newly created 
+            // face (after the healing process)
+            face = TopoDS::Face (exp0.Current());
+            face_colours->SetColor(face,face_colour,XCAFDoc_ColorSurf);
+         }
+         shape = rebuild->Apply(shape);
+      }
+
+
+      {
+         Handle_ShapeBuild_ReShape rebuild = new ShapeBuild_ReShape;
+         rebuild->Apply(shape);
+         for (exp1.Init (shape, TopAbs_EDGE); exp1.More(); exp1.Next())
+         {
+            TopoDS_Edge edge = TopoDS::Edge(exp1.Current());
+            if ( BRep_Tool::Degenerated(edge) )
+               rebuild->Remove(edge, false);
+         }
+         shape = rebuild->Apply(shape);
+      }
+
+
+      if (fixsmalledges)
+      {
+         cout << endl << "- fixing small edges" << endl;
+
+         Handle(ShapeFix_Wire) sfw;
+         Handle_ShapeBuild_ReShape rebuild = new ShapeBuild_ReShape;
+         rebuild->Apply(shape);
+
+
+         for (exp0.Init (shape, TopAbs_FACE); exp0.More(); exp0.Next())
+         {
+            TopoDS_Face face = TopoDS::Face(exp0.Current());
+
+            for (exp1.Init (face, TopAbs_WIRE); exp1.More(); exp1.Next())
+            {
+               TopoDS_Wire oldwire = TopoDS::Wire(exp1.Current());
+               sfw = new ShapeFix_Wire (oldwire, face ,tolerance);
+               sfw->ModifyTopologyMode() = Standard_True;
+
+               sfw->ClosedWireMode() = Standard_True;
+
+               bool replace = false;
+
+               replace = sfw->FixReorder() || replace;
+
+               replace = sfw->FixConnected() || replace;
+
+
+
+               if (sfw->FixSmall (Standard_False, tolerance) && ! (sfw->StatusSmall(ShapeExtend_FAIL1) ||
+                  sfw->StatusSmall(ShapeExtend_FAIL2) ||
+                  sfw->StatusSmall(ShapeExtend_FAIL3)))
+               {
+                  cout << "Fixed small edge in wire " << wmap.FindIndex (oldwire) << endl;
+                  replace = true;
+
+               }
+               else if (sfw->StatusSmall(ShapeExtend_FAIL1))
+                  cerr << "Failed to fix small edge in wire " << wmap.FindIndex (oldwire)
+                  << ", edge cannot be checked (no 3d curve and no pcurve)" << endl;
+               else if (sfw->StatusSmall(ShapeExtend_FAIL2))
+                  cerr << "Failed to fix small edge in wire " << wmap.FindIndex (oldwire)
+                  << ", edge is null-length and has different vertives at begin and end, and lockvtx is True or ModifiyTopologyMode is False" << endl;
+               else if (sfw->StatusSmall(ShapeExtend_FAIL3))
+                  cerr << "Failed to fix small edge in wire " << wmap.FindIndex (oldwire)
+                  << ", CheckConnected has failed" << endl;
+
+               replace = sfw->FixEdgeCurves() || replace;
+
+               replace = sfw->FixDegenerated() || replace;
+
+               replace = sfw->FixSelfIntersection() || replace;
+
+               replace = sfw->FixLacking(Standard_True) || replace;
+
+               if(replace)
+               {
+                  TopoDS_Wire newwire = sfw->Wire();
+                  rebuild->Replace(oldwire, newwire, Standard_False);
+               }
+
+               //delete sfw; sfw = NULL;
+
+            }
+         }
+
+         shape = rebuild->Apply(shape);
+
+
+
+         {
+            BuildFMap();
+            Handle_ShapeBuild_ReShape rebuild = new ShapeBuild_ReShape;
+            rebuild->Apply(shape);
+
+            for (exp1.Init (shape, TopAbs_EDGE); exp1.More(); exp1.Next())
+            {
+               TopoDS_Edge edge = TopoDS::Edge(exp1.Current());
+               if (vmap.FindIndex(TopExp::FirstVertex (edge)) ==
+                  vmap.FindIndex(TopExp::LastVertex (edge)))
+               {
+                  GProp_GProps system;
+                  BRepGProp::LinearProperties(edge, system);
+                  if (system.Mass() < tolerance)
+                  {
+                     cout << "removing degenerated edge " << emap.FindIndex(edge)
+                        << " from vertex " << vmap.FindIndex(TopExp::FirstVertex (edge))
+                        << " to vertex " << vmap.FindIndex(TopExp::LastVertex (edge)) << endl;
+                     rebuild->Remove(edge, false);
+                  }
+               }
+            }
+            shape = rebuild->Apply(shape);
+
+            //delete rebuild; rebuild = NULL;
+         }
+
+
+
+         {
+            Handle_ShapeBuild_ReShape rebuild = new ShapeBuild_ReShape;
+            rebuild->Apply(shape);
+            for (exp1.Init (shape, TopAbs_EDGE); exp1.More(); exp1.Next())
+            {
+               TopoDS_Edge edge = TopoDS::Edge(exp1.Current());
+               if ( BRep_Tool::Degenerated(edge) )
+                  rebuild->Remove(edge, false);
+            }
+            shape = rebuild->Apply(shape);
+         }
+
+
+
+
+         Handle(ShapeFix_Wireframe) sfwf = new ShapeFix_Wireframe;
+         sfwf->SetPrecision(tolerance);
+         sfwf->Load (shape);
+         sfwf->ModeDropSmallEdges() = Standard_True;
+
+         sfwf->SetPrecision(boundingbox.Diam());
+
+         if (sfwf->FixWireGaps())
+         {
+            cout << endl << "- fixing wire gaps" << endl;
+            if (sfwf->StatusWireGaps(ShapeExtend_OK)) cout << "no gaps found" << endl;
+            if (sfwf->StatusWireGaps(ShapeExtend_DONE1)) cout << "some 2D gaps fixed" << endl;
+            if (sfwf->StatusWireGaps(ShapeExtend_DONE2)) cout << "some 3D gaps fixed" << endl;
+            if (sfwf->StatusWireGaps(ShapeExtend_FAIL1)) cout << "failed to fix some 2D gaps" << endl;
+            if (sfwf->StatusWireGaps(ShapeExtend_FAIL2)) cout << "failed to fix some 3D gaps" << endl;
+         }
+
+         sfwf->SetPrecision(tolerance);
+
+
+         {
+            for (exp1.Init (shape, TopAbs_EDGE); exp1.More(); exp1.Next())
+            {
+               TopoDS_Edge edge = TopoDS::Edge(exp1.Current());
+               if ( BRep_Tool::Degenerated(edge) )
+                  cout << "degenerated edge at position 4" << endl;
+            }
+         }
+
+
+
+         if (sfwf->FixSmallEdges())
+         {
+            cout << endl << "- fixing wire frames" << endl;
+            if (sfwf->StatusSmallEdges(ShapeExtend_OK)) cout << "no small edges found" << endl;
+            if (sfwf->StatusSmallEdges(ShapeExtend_DONE1)) cout << "some small edges fixed" << endl;
+            if (sfwf->StatusSmallEdges(ShapeExtend_FAIL1)) cout << "failed to fix some small edges" << endl;
+         }
+
+
+
+         shape = sfwf->Shape();
+
+         //delete sfwf; sfwf = NULL;
+         //delete rebuild; rebuild = NULL;
+
+      }
+
+
+
+
+
+      {
+         for (exp1.Init (shape, TopAbs_EDGE); exp1.More(); exp1.Next())
+         {
+            TopoDS_Edge edge = TopoDS::Edge(exp1.Current());
+            if ( BRep_Tool::Degenerated(edge) )
+               cout << "degenerated edge at position 5" << endl;
+         }
+      }
+
+
+
+
+      if (fixspotstripfaces)
+      {
+
+         cout << endl << "- fixing spot and strip faces" << endl;
+         Handle(ShapeFix_FixSmallFace) sffsm = new ShapeFix_FixSmallFace();
+         sffsm -> Init (shape);
+         sffsm -> SetPrecision (tolerance);
+         sffsm -> Perform();
+
+         shape = sffsm -> FixShape();
+         //delete sffsm; sffsm = NULL;
+      }
+
+
+      {
+         for (exp1.Init (shape, TopAbs_EDGE); exp1.More(); exp1.Next())
+         {
+            TopoDS_Edge edge = TopoDS::Edge(exp1.Current());
+            if ( BRep_Tool::Degenerated(edge) )
+               cout << "degenerated edge at position 6" << endl;
+         }
+      }
+
+
+
+      if (sewfaces)
+      {
+         cout << endl << "- sewing faces" << endl;
+
+         BRepOffsetAPI_Sewing sewedObj(tolerance);
+
+         for (exp0.Init (shape, TopAbs_FACE); exp0.More(); exp0.Next())
+         {
+            TopoDS_Face face = TopoDS::Face (exp0.Current());
+            sewedObj.Add (face);
+         }
+
+         sewedObj.Perform();
+
+         if (!sewedObj.SewedShape().IsNull())
+            shape = sewedObj.SewedShape();
+         else
+            cout << " not possible";
+      }
+
+
+
+      {
+         Handle_ShapeBuild_ReShape rebuild = new ShapeBuild_ReShape;
+         rebuild->Apply(shape);
+         for (exp1.Init (shape, TopAbs_EDGE); exp1.More(); exp1.Next())
+         {
+            TopoDS_Edge edge = TopoDS::Edge(exp1.Current());
+            if ( BRep_Tool::Degenerated(edge) )
+               rebuild->Remove(edge, false);
+         }
+         shape = rebuild->Apply(shape);
+      }
+
+
+      if (makesolids)
+      {
+         cout << endl << "- making solids" << endl;
+
+         BRepBuilderAPI_MakeSolid ms;
+         int count = 0;
+         for (exp0.Init(shape, TopAbs_SHELL); exp0.More(); exp0.Next())
+         {
+            count++;
+            ms.Add (TopoDS::Shell(exp0.Current()));
+         }
+
+         if (!count)
+         {
+            cout << " not possible (no shells)" << endl;
+         }
+         else
+         {
+            BRepCheck_Analyzer ba(ms);
+            if (ba.IsValid ())
+            {
+               Handle(ShapeFix_Shape) sfs = new ShapeFix_Shape;
+               sfs->Init (ms);
+               sfs->SetPrecision(tolerance);
+               sfs->SetMaxTolerance(tolerance);
+               sfs->Perform();
+               shape = sfs->Shape();
+
+               for (exp0.Init(shape, TopAbs_SOLID); exp0.More(); exp0.Next())
+               {
+                  TopoDS_Solid solid = TopoDS::Solid(exp0.Current());
+                  TopoDS_Solid newsolid = solid;
+                  BRepLib::OrientClosedSolid (newsolid);
+                  Handle_ShapeBuild_ReShape rebuild = new ShapeBuild_ReShape;
+                  //		  rebuild->Apply(shape);
+                  rebuild->Replace(solid, newsolid, Standard_False);
+                  TopoDS_Shape newshape = rebuild->Apply(shape, TopAbs_COMPSOLID);//, 1);
+                  //		  TopoDS_Shape newshape = rebuild->Apply(shape);
+                  shape = newshape;
+               }
+
+               //delete sfs; sfs = NULL;
+            }
+            else
+               cout << " not possible" << endl;
+         }
+      }
+
+
+
+      if (splitpartitions)
+      {
+         cout << "- running SALOME partition splitter" << endl;
+
+         TopExp_Explorer e2;
+         Partition_Spliter ps;
+         int count = 0;
+
+         for (e2.Init (shape, TopAbs_SOLID);
+            e2.More(); e2.Next())
+         {
+            count++;
+            ps.AddShape (e2.Current());
+         }
+
+         ps.Compute();
+         shape = ps.Shape();
+
+         cout << " before: " << count << " solids" << endl;
+
+         count = 0;
+         for (e2.Init (shape, TopAbs_SOLID);
+            e2.More(); e2.Next()) count++;
+
+            cout << " after : " << count << " solids" << endl;
+      }
+
+      BuildFMap();
+
+
+
+      {
+         for (exp1.Init (shape, TopAbs_EDGE); exp1.More(); exp1.Next())
+         {
+            TopoDS_Edge edge = TopoDS::Edge(exp1.Current());
+            if ( BRep_Tool::Degenerated(edge) )
+               cout << "degenerated edge at position 8" << endl;
+         }
+      }
+
+
+      double newsurfacecont = 0;
+
+
+      for (exp0.Init (shape, TopAbs_FACE); exp0.More(); exp0.Next())
+      {
+         TopoDS_Face face = TopoDS::Face(exp0.Current());
+         GProp_GProps system;
+         BRepGProp::SurfaceProperties(face, system);
+         newsurfacecont += system.Mass();
+      }
+
+
+      int nnrc = 0, nnrcs = 0,
+         nnrso = somap.Extent(),
+         nnrsh = shmap.Extent(),
+         nnrf = fmap.Extent(),
+         nnrw = wmap.Extent(),
+         nnre = emap.Extent(),
+         nnrv = vmap.Extent();
+
+      for (exp0.Init(shape, TopAbs_COMPOUND); exp0.More(); exp0.Next()) nnrc++;
+      for (exp0.Init(shape, TopAbs_COMPSOLID); exp0.More(); exp0.Next()) nnrcs++;
+
+      cout << "-----------------------------------" << endl;
+      cout << "Compounds       : " << nnrc << " (" << nrc << ")" << endl;
+      cout << "Composite solids: " << nnrcs << " (" << nrcs << ")" << endl;
+      cout << "Solids          : " << nnrso << " (" << nrso << ")" << endl;
+      cout << "Shells          : " << nnrsh << " (" << nrsh << ")" << endl;
+      cout << "Wires           : " << nnrw << " (" << nrw << ")" << endl;
+      cout << "Faces           : " << nnrf << " (" << nrf << ")" << endl;
+      cout << "Edges           : " << nnre << " (" << nre << ")" << endl;
+      cout << "Vertices        : " << nnrv << " (" << nrv << ")" << endl;
+      cout << endl;
+      cout << "Totol surface area : " << newsurfacecont << " (" << surfacecont << ")" << endl;
+      cout << endl;
+   }
+
+
+
+
+   void OCCGeometry :: BuildFMap()
+   {
+      somap.Clear();
+      shmap.Clear();
+      fmap.Clear();
+      wmap.Clear();
+      emap.Clear();
+      vmap.Clear();
+
+      TopExp_Explorer exp0, exp1, exp2, exp3, exp4, exp5;
+
+      for (exp0.Init(shape, TopAbs_COMPOUND);
+         exp0.More(); exp0.Next())
+      {
+         TopoDS_Compound compound = TopoDS::Compound (exp0.Current());
+         (*testout) << "compound" << endl;
+         int i = 0;
+         for (exp1.Init(compound, TopAbs_SHELL);
+            exp1.More(); exp1.Next())
+         {
+            (*testout) << "shell " << ++i << endl;
+         }
+      }
+
+      for (exp0.Init(shape, TopAbs_SOLID);
+         exp0.More(); exp0.Next())
+      {
+         TopoDS_Solid solid = TopoDS::Solid (exp0.Current());
+
+         if (somap.FindIndex(solid) < 1)
+         {
+            somap.Add (solid);
+
+            for (exp1.Init(solid, TopAbs_SHELL);
+               exp1.More(); exp1.Next())
+            {
+               TopoDS_Shell shell = TopoDS::Shell (exp1.Current());
+               if (shmap.FindIndex(shell) < 1)
+               {
+                  shmap.Add (shell);
+
+                  for (exp2.Init(shell, TopAbs_FACE);
+                     exp2.More(); exp2.Next())
+                  {
+                     TopoDS_Face face = TopoDS::Face(exp2.Current());
+                     if (fmap.FindIndex(face) < 1)
+                     {
+                        fmap.Add (face);
+                        (*testout) << "face " << fmap.FindIndex(face) << " ";
+                        (*testout) << ((face.Orientation() == TopAbs_REVERSED) ? "-" : "+") << ", ";
+                        (*testout) << ((exp2.Current().Orientation() == TopAbs_REVERSED) ? "-" : "+") << endl;
+                        for (exp3.Init(exp2.Current(), TopAbs_WIRE);
+                           exp3.More(); exp3.Next())
+                        {
+                           TopoDS_Wire wire = TopoDS::Wire (exp3.Current());
+                           if (wmap.FindIndex(wire) < 1)
+                           {
+                              wmap.Add (wire);
+
+                              for (exp4.Init(exp3.Current(), TopAbs_EDGE);
+                                 exp4.More(); exp4.Next())
+                              {
+                                 TopoDS_Edge edge = TopoDS::Edge(exp4.Current());
+                                 if (emap.FindIndex(edge) < 1)
+                                 {
+                                    emap.Add (edge);
+                                    for (exp5.Init(exp4.Current(), TopAbs_VERTEX);
+                                       exp5.More(); exp5.Next())
+                                    {
+                                       TopoDS_Vertex vertex = TopoDS::Vertex(exp5.Current());
+                                       if (vmap.FindIndex(vertex) < 1)
+                                          vmap.Add (vertex);
+                                    }
+                                 }
+                              }
+                           }
+                        }
+                     }
+                  }
+               }
+            }
+         }
+      }
+
+      // Free Shells
+      for (exp1.Init(shape, TopAbs_SHELL, TopAbs_SOLID); exp1.More(); exp1.Next())
+      {
+         TopoDS_Shell shell = TopoDS::Shell(exp1.Current());
+         if (shmap.FindIndex(shell) < 1)
+         {
+            shmap.Add (shell);
+
+            (*testout) << "shell " << shmap.FindIndex(shell) << " ";
+            (*testout) << ((shell.Orientation() == TopAbs_REVERSED) ? "-" : "+") << ", ";
+            (*testout) << ((exp1.Current().Orientation() == TopAbs_REVERSED) ? "-" : "+") << endl;
+
+            for (exp2.Init(shell, TopAbs_FACE); exp2.More(); exp2.Next())
+            {
+               TopoDS_Face face = TopoDS::Face(exp2.Current());
+               if (fmap.FindIndex(face) < 1)
+               {
+                  fmap.Add (face);
+
+                  for (exp3.Init(face, TopAbs_WIRE); exp3.More(); exp3.Next())
+                  {
+                     TopoDS_Wire wire = TopoDS::Wire (exp3.Current());
+                     if (wmap.FindIndex(wire) < 1)
+                     {
+                        wmap.Add (wire);
+
+                        for (exp4.Init(wire, TopAbs_EDGE); exp4.More(); exp4.Next())
+                        {
+                           TopoDS_Edge edge = TopoDS::Edge(exp4.Current());
+                           if (emap.FindIndex(edge) < 1)
+                           {
+                              emap.Add (edge);
+                              for (exp5.Init(edge, TopAbs_VERTEX); exp5.More(); exp5.Next())
+                              {
+                                 TopoDS_Vertex vertex = TopoDS::Vertex(exp5.Current());
+                                 if (vmap.FindIndex(vertex) < 1)
+                                    vmap.Add (vertex);
+                              }
+                           }
+                        }
+                     }
+                  }
+               }
+            }
+         }
+      }
+
+
+      // Free Faces
+
+      for (exp2.Init(shape, TopAbs_FACE, TopAbs_SHELL); exp2.More(); exp2.Next())
+      {
+         TopoDS_Face face = TopoDS::Face(exp2.Current());
+         if (fmap.FindIndex(face) < 1)
+         {
+            fmap.Add (face);
+
+            for (exp3.Init(exp2.Current(), TopAbs_WIRE); exp3.More(); exp3.Next())
+            {
+               TopoDS_Wire wire = TopoDS::Wire (exp3.Current());
+               if (wmap.FindIndex(wire) < 1)
+               {
+                  wmap.Add (wire);
+
+                  for (exp4.Init(exp3.Current(), TopAbs_EDGE); exp4.More(); exp4.Next())
+                  {
+                     TopoDS_Edge edge = TopoDS::Edge(exp4.Current());
+                     if (emap.FindIndex(edge) < 1)
+                     {
+                        emap.Add (edge);
+                        for (exp5.Init(exp4.Current(), TopAbs_VERTEX); exp5.More(); exp5.Next())
+                        {
+                           TopoDS_Vertex vertex = TopoDS::Vertex(exp5.Current());
+                           if (vmap.FindIndex(vertex) < 1)
+                              vmap.Add (vertex);
+                        }
+                     }
+                  }
+               }
+            }
+         }
+      }
+
+
+      // Free Wires
+
+      for (exp3.Init(shape, TopAbs_WIRE, TopAbs_FACE); exp3.More(); exp3.Next())
+      {
+         TopoDS_Wire wire = TopoDS::Wire (exp3.Current());
+         if (wmap.FindIndex(wire) < 1)
+         {
+            wmap.Add (wire);
+
+            for (exp4.Init(exp3.Current(), TopAbs_EDGE); exp4.More(); exp4.Next())
+            {
+               TopoDS_Edge edge = TopoDS::Edge(exp4.Current());
+               if (emap.FindIndex(edge) < 1)
+               {
+                  emap.Add (edge);
+                  for (exp5.Init(exp4.Current(), TopAbs_VERTEX); exp5.More(); exp5.Next())
+                  {
+                     TopoDS_Vertex vertex = TopoDS::Vertex(exp5.Current());
+                     if (vmap.FindIndex(vertex) < 1)
+                        vmap.Add (vertex);
+                  }
+               }
+            }
+         }
+      }
+
+
+      // Free Edges
+
+      for (exp4.Init(shape, TopAbs_EDGE, TopAbs_WIRE); exp4.More(); exp4.Next())
+      {
+         TopoDS_Edge edge = TopoDS::Edge(exp4.Current());
+         if (emap.FindIndex(edge) < 1)
+         {
+            emap.Add (edge);
+            for (exp5.Init(exp4.Current(), TopAbs_VERTEX); exp5.More(); exp5.Next())
+            {
+               TopoDS_Vertex vertex = TopoDS::Vertex(exp5.Current());
+               if (vmap.FindIndex(vertex) < 1)
+                  vmap.Add (vertex);
+            }
+         }
+      }
+
+
+      // Free Vertices
+
+      for (exp5.Init(shape, TopAbs_VERTEX, TopAbs_EDGE); exp5.More(); exp5.Next())
+      {
+         TopoDS_Vertex vertex = TopoDS::Vertex(exp5.Current());
+         if (vmap.FindIndex(vertex) < 1)
+            vmap.Add (vertex);
+      }
+
+
+
+
+      facemeshstatus.DeleteAll();
+      facemeshstatus.SetSize (fmap.Extent());
+      facemeshstatus = 0;
+
+      // Philippose - 15/01/2009
+      face_maxh.DeleteAll();
+      face_maxh.SetSize (fmap.Extent());
+      face_maxh = mparam.maxh;
+
+      // Philippose - 15/01/2010      
+      face_maxh_modified.DeleteAll();      
+      face_maxh_modified.SetSize(fmap.Extent());      
+      face_maxh_modified = 0;
+      
+
+      // Philippose - 17/01/2009
+      face_sel_status.DeleteAll();
+      face_sel_status.SetSize (fmap.Extent());
+      face_sel_status = 0;
+
+      fvispar.SetSize (fmap.Extent());
+      evispar.SetSize (emap.Extent());
+      vvispar.SetSize (vmap.Extent());
+
+      fsingular.SetSize (fmap.Extent());
+      esingular.SetSize (emap.Extent());
+      vsingular.SetSize (vmap.Extent());
+
+      fsingular = esingular = vsingular = false;
+   }
+
+
+
+   void OCCGeometry :: SewFaces ()
+   {
+      (*testout) << "Trying to sew faces ..." << endl;
+      cout << "Trying to sew faces ..." << flush;
+
+      BRepOffsetAPI_Sewing sewedObj(1);
+ 
+      for (int i = 1; i <= fmap.Extent(); i++)
+      {
+         TopoDS_Face face = TopoDS::Face (fmap(i));
+         sewedObj.Add (face);
+      }
+
+      sewedObj.Perform();
+
+      if (!sewedObj.SewedShape().IsNull())
+      {
+         shape = sewedObj.SewedShape();
+         cout << " done" << endl;
+      }
+      else
+         cout << " not possible";
+   }
+
+
+
+
+
+   void OCCGeometry :: MakeSolid ()
+   {
+      TopExp_Explorer exp0;
+
+      (*testout) << "Trying to build solids ..." << endl;
+      cout << "Trying to build solids ..." << flush;
+
+      BRepBuilderAPI_MakeSolid ms;
+      int count = 0;
+      for (exp0.Init(shape, TopAbs_SHELL); exp0.More(); exp0.Next())
+      {
+         count++;
+         ms.Add (TopoDS::Shell(exp0.Current()));
+      }
+
+      if (!count)
+      {
+         cout << " not possible (no shells)" << endl;
+         return;
+      }
+
+      BRepCheck_Analyzer ba(ms);
+      if (ba.IsValid ())
+      {
+         Handle(ShapeFix_Shape) sfs = new ShapeFix_Shape;
+         sfs->Init (ms);
+
+         sfs->SetPrecision(1e-5);
+         sfs->SetMaxTolerance(1e-5);
+
+         sfs->Perform();
+
+         shape = sfs->Shape();
+
+         for (exp0.Init(shape, TopAbs_SOLID); exp0.More(); exp0.Next())
+         {
+            TopoDS_Solid solid = TopoDS::Solid(exp0.Current());
+            TopoDS_Solid newsolid = solid;
+            BRepLib::OrientClosedSolid (newsolid);
+            Handle_ShapeBuild_ReShape rebuild = new ShapeBuild_ReShape;
+            rebuild->Replace(solid, newsolid, Standard_False);
+
+            TopoDS_Shape newshape = rebuild->Apply(shape, TopAbs_SHAPE, 1);
+            shape = newshape;
+         }
+
+         cout << " done" << endl;
+      }
+      else
+         cout << " not possible" << endl;
+   }
+
+
+
+
+   void OCCGeometry :: BuildVisualizationMesh (double deflection)
+   {
+      cout << "Preparing visualization (deflection = " << deflection << ") ... " << flush;
+
+      BRepTools::Clean (shape);
+      // BRepMesh_IncrementalMesh::
+      BRepMesh_IncrementalMesh (shape, deflection, true);
+      cout << "done" << endl;
+   }
+
+
+
+
+   void OCCGeometry :: CalcBoundingBox ()
+   {
+      Bnd_Box bb;
+      BRepBndLib::Add (shape, bb);
+
+      double x1,y1,z1,x2,y2,z2;
+      bb.Get (x1,y1,z1,x2,y2,z2);
+      Point<3> p1 = Point<3> (x1,y1,z1);
+      Point<3> p2 = Point<3> (x2,y2,z2);
+
+      (*testout) << "Bounding Box = [" << p1 << " - " << p2 << "]" << endl;
+      boundingbox = Box<3> (p1,p2);
+      SetCenter();
+   }
+
+
+
+
+   void OCCGeometry :: 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));
+
+      double u,v;
+      Handle( Geom_Surface ) thesurf = BRep_Tool::Surface(TopoDS::Face(fmap(surfi)));
+      Handle( ShapeAnalysis_Surface ) su = new ShapeAnalysis_Surface( thesurf );
+      gp_Pnt2d suval = su->ValueOfUV ( pnt, BRep_Tool::Tolerance( TopoDS::Face(fmap(surfi)) ) );
+      suval.Coord( u, v);
+      pnt = thesurf->Value( u, v );
+
+
+      p = Point<3> (pnt.X(), pnt.Y(), pnt.Z());
+
+   }
+
+
+
+
+   bool OCCGeometry :: FastProject (int surfi, Point<3> & ap, double& u, double& v) const
+   {
+      gp_Pnt p(ap(0), ap(1), ap(2));
+
+      Handle(Geom_Surface) surface = BRep_Tool::Surface(TopoDS::Face(fmap(surfi)));
+
+      gp_Pnt x = surface->Value (u,v);
+
+      if (p.SquareDistance(x) <= sqr(PROJECTION_TOLERANCE)) return true;
+
+      gp_Vec du, dv;
+
+      surface->D1(u,v,x,du,dv);
+
+      int count = 0;
+
+      gp_Pnt xold;
+      gp_Vec n;
+      double det, lambda, mu;
+
+      do {
+         count++;
+
+         n = du^dv;
+
+         det = Det3 (n.X(), du.X(), dv.X(),
+            n.Y(), du.Y(), dv.Y(),
+            n.Z(), du.Z(), dv.Z());
+
+         if (det < 1e-15) return false;
+
+         lambda = Det3 (n.X(), p.X()-x.X(), dv.X(),
+            n.Y(), p.Y()-x.Y(), dv.Y(),
+            n.Z(), p.Z()-x.Z(), dv.Z())/det;
+
+         mu     = Det3 (n.X(), du.X(), p.X()-x.X(),
+            n.Y(), du.Y(), p.Y()-x.Y(),
+            n.Z(), du.Z(), p.Z()-x.Z())/det;
+
+         u += lambda;
+         v += mu;
+
+         xold = x;
+         surface->D1(u,v,x,du,dv);
+
+      } while (xold.SquareDistance(x) > sqr(PROJECTION_TOLERANCE) && count < 50);
+
+      //    (*testout) << "FastProject count: " << count << endl;
+
+      if (count == 50) return false;
+
+      ap = Point<3> (x.X(), x.Y(), x.Z());
+
+      return true;
+   }
+
+
+
+
+   void OCCGeometry :: WriteOCC_STL(char * filename)
+   {
+      cout << "writing stl..."; cout.flush();
+      StlAPI_Writer writer;
+      writer.RelativeMode() = Standard_False;
+
+      writer.SetDeflection(0.02);
+      writer.Write(shape,filename);
+
+      cout << "done" << endl;
+   }
+
+
+
+   // Philippose - 23/02/2009
+   /* Special IGES File load function including the ability
+   to extract individual surface colours via the extended
+   OpenCascade XDE and XCAF Feature set.
+   */
+   OCCGeometry *LoadOCC_IGES(const char *filename)
+   {
+      OCCGeometry *occgeo;
+      occgeo = new OCCGeometry;
+
+      // Initiate a dummy XCAF Application to handle the IGES XCAF Document
+      static Handle_XCAFApp_Application dummy_app = XCAFApp_Application::GetApplication();
+
+      // Create an XCAF Document to contain the IGES file itself
+      Handle_TDocStd_Document iges_doc;
+
+      // Check if a IGES File is already open under this handle, if so, close it to prevent
+      // Segmentation Faults when trying to create a new document
+      if(dummy_app->NbDocuments() > 0)
+      {
+         dummy_app->GetDocument(1,iges_doc);
+         dummy_app->Close(iges_doc);
+      }
+      dummy_app->NewDocument ("IGES-XCAF",iges_doc);
+
+      IGESCAFControl_Reader reader;
+
+      Standard_Integer stat = reader.ReadFile((char*)filename);
+
+      if(stat != IFSelect_RetDone)
+      {
+         delete occgeo;
+         return NULL;
+      }
+
+      // Enable transfer of colours
+      reader.SetColorMode(Standard_True);
+
+      reader.Transfer(iges_doc);
+
+      // Read in the shape(s) and the colours present in the IGES File
+      Handle_XCAFDoc_ShapeTool iges_shape_contents = XCAFDoc_DocumentTool::ShapeTool(iges_doc->Main());
+      Handle_XCAFDoc_ColorTool iges_colour_contents = XCAFDoc_DocumentTool::ColorTool(iges_doc->Main());
+
+      TDF_LabelSequence iges_shapes;
+      iges_shape_contents->GetShapes(iges_shapes);
+
+      // List out the available colours in the IGES File as Colour Names
+      TDF_LabelSequence all_colours;
+      iges_colour_contents->GetColors(all_colours);
+      PrintMessage(1,"Number of colours in IGES File: ",all_colours.Length());
+      for(int i = 1; i <= all_colours.Length(); i++)
+      {
+         Quantity_Color col;
+         stringstream col_rgb;
+         iges_colour_contents->GetColor(all_colours.Value(i),col);
+         col_rgb << " : (" << col.Red() << "," << col.Green() << "," << col.Blue() << ")";
+         PrintMessage(1, "Colour [", i, "] = ",col.StringName(col.Name()),col_rgb.str());
+      }
+
+
+      // For the IGES Reader, all the shapes can be exported as one compund shape 
+      // using the "OneShape" member
+      occgeo->shape = reader.OneShape();
+      occgeo->face_colours = iges_colour_contents;
+      occgeo->changed = 1;
+      occgeo->BuildFMap();
+
+      occgeo->CalcBoundingBox();
+      PrintContents (occgeo);
+
+      return occgeo;
+   }
+
+
+
+
+
+   // Philippose - 29/01/2009
+   /* Special STEP File load function including the ability
+   to extract individual surface colours via the extended
+   OpenCascade XDE and XCAF Feature set.
+   */
+   OCCGeometry * LoadOCC_STEP (const char * filename)
+   {
+      OCCGeometry * occgeo;
+      occgeo = new OCCGeometry;
+
+      // Initiate a dummy XCAF Application to handle the STEP XCAF Document
+      static Handle_XCAFApp_Application dummy_app = XCAFApp_Application::GetApplication();
+
+      // Create an XCAF Document to contain the STEP file itself
+      Handle_TDocStd_Document step_doc;
+
+      // Check if a STEP File is already open under this handle, if so, close it to prevent
+      // Segmentation Faults when trying to create a new document
+      if(dummy_app->NbDocuments() > 0)
+      {
+         dummy_app->GetDocument(1,step_doc);
+         dummy_app->Close(step_doc);
+      }
+      dummy_app->NewDocument ("STEP-XCAF",step_doc);
+
+      STEPCAFControl_Reader reader;
+
+      // Enable transfer of colours
+      reader.SetColorMode(Standard_True);
+
+      Standard_Integer stat = reader.ReadFile((char*)filename);
+
+      if(stat != IFSelect_RetDone)
+      {
+         delete occgeo;
+         return NULL;
+      }
+
+      reader.Transfer(step_doc);
+
+      // Read in the shape(s) and the colours present in the STEP File
+      Handle_XCAFDoc_ShapeTool step_shape_contents = XCAFDoc_DocumentTool::ShapeTool(step_doc->Main());
+      Handle_XCAFDoc_ColorTool step_colour_contents = XCAFDoc_DocumentTool::ColorTool(step_doc->Main());
+
+      TDF_LabelSequence step_shapes;
+      step_shape_contents->GetShapes(step_shapes);
+
+      // List out the available colours in the STEP File as Colour Names
+      TDF_LabelSequence all_colours;
+      step_colour_contents->GetColors(all_colours);
+      PrintMessage(1,"Number of colours in STEP File: ",all_colours.Length());
+      for(int i = 1; i <= all_colours.Length(); i++)
+      {
+         Quantity_Color col;
+         stringstream col_rgb;
+         step_colour_contents->GetColor(all_colours.Value(i),col);
+         col_rgb << " : (" << col.Red() << "," << col.Green() << "," << col.Blue() << ")";
+         PrintMessage(1, "Colour [", i, "] = ",col.StringName(col.Name()),col_rgb.str());
+      }
+
+
+      // For the STEP File Reader in OCC, the 1st Shape contains the entire 
+      // compound geometry as one shape
+      occgeo->shape = step_shape_contents->GetShape(step_shapes.Value(1));
+      occgeo->face_colours = step_colour_contents;
+      occgeo->changed = 1;
+      occgeo->BuildFMap();
+
+      occgeo->CalcBoundingBox();
+      PrintContents (occgeo);
+
+      return occgeo;
+   }
+
+
+
+
+   OCCGeometry *LoadOCC_BREP (const char *filename)
+   {
+      OCCGeometry * occgeo;
+      occgeo = new OCCGeometry;
+
+      BRep_Builder aBuilder;
+      Standard_Boolean result = BRepTools::Read(occgeo->shape, const_cast<char*> (filename),aBuilder);
+
+      if(!result)
+      {
+         delete occgeo;
+         return NULL;
+      }
+
+      // Philippose - 23/02/2009
+      // Fixed a bug in the OpenCascade XDE Colour handling when 
+      // opening BREP Files, since BREP Files have no colour data.
+      // Hence, the face_colours Handle needs to be created as a NULL handle.
+      occgeo->face_colours = Handle_XCAFDoc_ColorTool();
+      occgeo->face_colours.Nullify();
+      occgeo->changed = 1;
+      occgeo->BuildFMap();
+
+      occgeo->CalcBoundingBox();
+      PrintContents (occgeo);
+
+      return occgeo;
+   }
+
+
+  void OCCGeometry :: Save (string sfilename) const
+  {
+    const char * filename = sfilename.c_str();
+    if (strlen(filename) < 4) 
+      throw NgException ("illegal filename");
+    
+    if (strcmp (&filename[strlen(filename)-3], "igs") == 0)
+      {
+	IGESControl_Writer writer("millimeters", 1);
+	writer.AddShape (shape);
+	writer.Write (filename);
+      }
+    else if (strcmp (&filename[strlen(filename)-3], "stp") == 0)
+      {
+	STEPControl_Writer writer;
+	writer.Transfer (shape, STEPControl_AsIs);
+	writer.Write (filename);
+      }
+    else if (strcmp (&filename[strlen(filename)-3], "stl") == 0)
+      {
+	StlAPI_Writer writer;
+	writer.ASCIIMode() = Standard_True;
+	writer.Write (shape, filename);
+      }
+    else if (strcmp (&filename[strlen(filename)-4], "stlb") == 0)
+      {
+	StlAPI_Writer writer;
+	writer.ASCIIMode() = Standard_False;
+	writer.Write (shape, filename);
+      }
+  }
+
+
+
+  const char * shapesname[] =
+   {" ", "CompSolids", "Solids", "Shells",
+
+   "Faces", "Wires", "Edges", "Vertices"};
+
+  const char * shapename[] =
+   {" ", "CompSolid", "Solid", "Shell",
+   "Face", "Wire", "Edge", "Vertex"};
+
+  const char * orientationstring[] =
+     {"+", "-"};
+
+
+
+
+   void OCCGeometry :: RecursiveTopologyTree (const TopoDS_Shape & sh,
+      stringstream & str,
+      TopAbs_ShapeEnum l,
+      bool isfree,
+      const char * lname)
+   {
+      if (l > TopAbs_VERTEX) return;
+
+      TopExp_Explorer e;
+      int count = 0;
+      int count2 = 0;
+
+      if (isfree)
+         e.Init(sh, l, TopAbs_ShapeEnum(l-1));
+      else
+         e.Init(sh, l);
+
+      for (; e.More(); e.Next())
+      {
+         count++;
+
+         stringstream lname2;
+         lname2 << lname << "/" << shapename[l] << count;
+         str << lname2.str() << " ";
+
+         switch (e.Current().ShapeType())
+	   {
+	   case TopAbs_SOLID:
+	     count2 = somap.FindIndex(TopoDS::Solid(e.Current())); break;
+	   case TopAbs_SHELL:
+	     count2 = shmap.FindIndex(TopoDS::Shell(e.Current())); break;
+	   case TopAbs_FACE:
+	     count2 = fmap.FindIndex(TopoDS::Face(e.Current())); break;
+	   case TopAbs_WIRE:
+	     count2 = wmap.FindIndex(TopoDS::Wire(e.Current())); break;
+	   case TopAbs_EDGE:
+	     count2 = emap.FindIndex(TopoDS::Edge(e.Current())); break;
+	   case TopAbs_VERTEX:
+	     count2 = vmap.FindIndex(TopoDS::Vertex(e.Current())); break;
+	   default:
+	     cout << "RecursiveTopologyTree: Case " << e.Current().ShapeType() << " not handeled" << endl;
+         }
+
+         int nrsubshapes = 0;
+
+         if (l <= TopAbs_WIRE)
+         {
+            TopExp_Explorer e2;
+            for (e2.Init (e.Current(), TopAbs_ShapeEnum (l+1));
+               e2.More(); e2.Next())
+               nrsubshapes++;
+         }
+
+         str << "{" << shapename[l] << " " << count2;
+
+         if (l <= TopAbs_EDGE)
+         {
+            str << " (" << orientationstring[e.Current().Orientation()];
+            if (nrsubshapes != 0) str << ", " << nrsubshapes;
+            str << ") } ";
+         }
+         else
+            str << " } ";
+
+         RecursiveTopologyTree (e.Current(), str, TopAbs_ShapeEnum (l+1),
+            false, (char*)lname2.str().c_str());
+
+      }
+   }
+
+
+
+
+   void OCCGeometry :: GetTopologyTree (stringstream & str)
+   {
+      cout << "Building topology tree ... " << flush;
+      RecursiveTopologyTree (shape, str, TopAbs_COMPSOLID, false, "CompSolids");
+      RecursiveTopologyTree (shape, str, TopAbs_SOLID, true, "FreeSolids");
+      RecursiveTopologyTree (shape, str, TopAbs_SHELL, true, "FreeShells");
+      RecursiveTopologyTree (shape, str, TopAbs_FACE, true, "FreeFaces");
+      RecursiveTopologyTree (shape, str, TopAbs_WIRE, true, "FreeWires");
+      RecursiveTopologyTree (shape, str, TopAbs_EDGE, true, "FreeEdges");
+      RecursiveTopologyTree (shape, str, TopAbs_VERTEX, true, "FreeVertices");
+      str << flush;
+      //  cout << "done" << endl;
+   }
+
+
+
+
+   void OCCGeometry :: CheckIrregularEntities(stringstream & str)
+   {
+      ShapeAnalysis_CheckSmallFace csm;
+
+      csm.SetTolerance (1e-6);
+
+      TopTools_DataMapOfShapeListOfShape mapEdges;
+      ShapeAnalysis_DataMapOfShapeListOfReal mapParam;
+      TopoDS_Compound theAllVert;
+
+      int spotfaces = 0;
+      int stripsupportfaces = 0;
+      int singlestripfaces = 0;
+      int stripfaces = 0;
+      int facessplitbyvertices = 0;
+      int stretchedpinfaces = 0;
+      int smoothpinfaces = 0;
+      int twistedfaces = 0;
+      // int edgessamebutnotidentified = 0;
+
+      cout << "checking faces ... " << flush;
+
+      int i;
+      for (i = 1; i <= fmap.Extent(); i++)
+      {
+         TopoDS_Face face = TopoDS::Face (fmap(i));
+         TopoDS_Edge e1, e2;
+
+         if (csm.CheckSpotFace (face))
+         {
+            if (!spotfaces++)
+               str << "SpotFace {Spot face} ";
+
+            (*testout) << "Face " << i << " is a spot face" << endl;
+            str << "SpotFace/Face" << i << " ";
+            str << "{Face " << i << " } ";
+         }
+
+         if (csm.IsStripSupport (face))
+         {
+            if (!stripsupportfaces++)
+               str << "StripSupportFace {Strip support face} ";
+
+            (*testout) << "Face " << i << " has strip support" << endl;
+            str << "StripSupportFace/Face" << i << " ";
+            str << "{Face " << i << " } ";
+         }
+
+         if (csm.CheckSingleStrip(face, e1, e2))
+         {
+            if (!singlestripfaces++)
+               str << "SingleStripFace {Single strip face} ";
+
+            (*testout) << "Face " << i << " is a single strip (edge " << emap.FindIndex(e1)
+               << " and edge " << emap.FindIndex(e2) << " are identical)" << endl;
+            str << "SingleStripFace/Face" << i << " ";
+            str << "{Face " << i << " (edge " << emap.FindIndex(e1)
+               << " and edge " << emap.FindIndex(e2) << " are identical)} ";
+         }
+
+         if (csm.CheckStripFace(face, e1, e2))
+         {
+            if (!stripfaces++)
+               str << "StripFace {Strip face} ";
+
+            (*testout) << "Face " << i << " is a strip (edge " << emap.FindIndex(e1)
+               << " and edge " << emap.FindIndex(e2)
+               << " are identical)" << endl;
+            str << "StripFace/Face" << i << " ";
+            str << "{Face " << i << " (edge " << emap.FindIndex(e1)
+               << " and edge " << emap.FindIndex(e2) << " are identical)} ";
+         }
+
+         if (int count = csm.CheckSplittingVertices(face, mapEdges, mapParam, theAllVert))
+         {
+            if (!facessplitbyvertices++)
+               str << "FaceSplitByVertices {Face split by vertices} ";
+
+            (*testout) << "Face " << i << " is split by " << count
+               << " vertex/vertices " << endl;
+            str << "FaceSplitByVertices/Face" << i << " ";
+            str << "{Face " << i << " (split by " << count << "vertex/vertices)} ";
+         }
+
+         int whatrow, sens;
+         if (int type = csm.CheckPin (face, whatrow, sens))
+         {
+            if (type == 1)
+            {
+               if (!smoothpinfaces++)
+                  str << "SmoothPinFace {Smooth pin face} ";
+
+               (*testout) << "Face " << i << " is a smooth pin" << endl;
+               str << "SmoothPinFace/Face" << i << " ";
+               str << "{Face " << i << " } ";
+            }
+            else
+            {
+               if (!stretchedpinfaces++)
+                  str << "StretchedPinFace {Stretched pin face} ";
+
+               (*testout) << "Face " << i << " is a streched pin" << endl;
+               str << "StretchedPinFace/Face" << i << " ";
+               str << "{Face " << i << " } ";
+            }
+         }
+
+         double paramu, paramv;
+         if (csm.CheckTwisted (face, paramu, paramv))
+         {
+            if (!twistedfaces++)
+               str << "TwistedFace {Twisted face} ";
+
+            (*testout) << "Face " << i << " is twisted" << endl;
+            str << "TwistedFace/Face" << i << " ";
+            str << "{Face " << i << " } ";
+         }
+      }
+
+      cout << "done" << endl;
+      cout << "checking edges ... " << flush;
+
+      // double dmax;
+      // int cnt = 0;
+      Array <double> edgeLengths;
+      Array <int> order;
+      edgeLengths.SetSize (emap.Extent());
+      order.SetSize (emap.Extent());
+
+      for (i = 1; i <= emap.Extent(); i++)
+      {
+         TopoDS_Edge edge1 = TopoDS::Edge (emap(i));
+         GProp_GProps system;
+         BRepGProp::LinearProperties(edge1, system);
+         edgeLengths[i-1] = system.Mass();
+      }
+
+      Sort (edgeLengths, order);
+
+      str << "ShortestEdges {Shortest edges} ";
+      for (i = 1; i <= min(20, emap.Extent()); i++)
+      {
+         str << "ShortestEdges/Edge" << i;
+         str << " {Edge " << order[i-1] << " (L=" << edgeLengths[order[i-1]-1] << ")} ";
+      }
+
+      str << flush;
+
+      cout << "done" << endl;
+   }
+
+
+
+
+   void OCCGeometry :: GetUnmeshedFaceInfo (stringstream & str)
+   {
+      for (int i = 1; i <= fmap.Extent(); i++)
+      {
+         if (facemeshstatus[i-1] == -1)
+            str << "Face" << i << " {Face " << i << " } ";
+      }
+      str << flush;
+   }
+
+
+
+
+   void OCCGeometry :: GetNotDrawableFaces (stringstream & str)
+   {
+      for (int i = 1; i <= fmap.Extent(); i++)
+      {
+         if (!fvispar[i-1].IsDrawable())
+            str << "Face" << i << " {Face " << i << " } ";
+      }
+      str << flush;
+   }
+
+
+
+
+   bool OCCGeometry :: ErrorInSurfaceMeshing ()
+   {
+      for (int i = 1; i <= fmap.Extent(); i++)
+         if (facemeshstatus[i-1] == -1)
+            return true;
+
+      return false;
+   }
+
+
+
+
+  int OCCGeometry :: GenerateMesh (Mesh*& mesh, MeshingParameters & mparam,
+      int perfstepsstart, int perfstepsend)
+   {
+     return OCCGenerateMesh (*this, mesh, mparam, perfstepsstart, perfstepsend);
+   }
+
+
+
+
+   const Refinement & OCCGeometry :: GetRefinement () const
+   {
+      return * new OCCRefinementSurfaces (*this);
+   }
+
+
+
+
+   OCCParameters :: OCCParameters()
+   {
+      resthcloseedgefac = 1;
+      resthcloseedgeenable = 1;
+   }
+
+
+
+
+   void OCCParameters :: Print(ostream & ost) const
+   {
+      ost << "OCC Parameters:" << endl
+         << "close edges: " << resthcloseedgeenable
+         << ", fac = " << resthcloseedgefac << endl;
+   }
+
+
+
+
+   OCCParameters occparam;
+
+}
+
+
+#endif
diff --git a/contrib/Netgen/libsrc/occ/occgeom.hpp b/contrib/Netgen/libsrc/occ/occgeom.hpp
new file mode 100644
index 0000000000..16b2f761fc
--- /dev/null
+++ b/contrib/Netgen/libsrc/occ/occgeom.hpp
@@ -0,0 +1,451 @@
+#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 "TopoDS_Solid.hxx"
+#include "TopExp_Explorer.hxx"
+#include "TopTools_ListIteratorOfListOfShape.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_CLProps.hxx"
+#include "BRepLProp_SLProps.hxx"
+#include "BRepAdaptor_Surface.hxx"
+#include "BRepAdaptor_Curve.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 "TopoDS_Shape.hxx"
+#include "TopoDS_Face.hxx"
+#include "IGESToBRep_Reader.hxx"
+#include "Interface_Static.hxx"
+#include "GeomAPI_ExtremaCurveCurve.hxx"
+#include "Standard_ErrorHandler.hxx"
+#include "Standard_Failure.hxx"
+#include "ShapeUpgrade_ShellSewing.hxx"
+#include "ShapeFix_Shape.hxx"
+#include "ShapeFix_Wireframe.hxx"
+#include "BRepMesh.hxx"
+#include "BRepMesh_IncrementalMesh.hxx"
+#include "BRepBndLib.hxx"
+#include "Bnd_Box.hxx"
+#include "ShapeAnalysis.hxx"
+#include "ShapeBuild_ReShape.hxx"
+
+
+// Philippose - 29/01/2009
+// OpenCascade XDE Support
+// Include support for OpenCascade XDE Features
+#include "TDocStd_Document.hxx"
+#include "Quantity_Color.hxx"
+#include "XCAFApp_Application.hxx"
+#include "XCAFDoc_ShapeTool.hxx"
+#include "XCAFDoc_Color.hxx"
+#include "XCAFDoc_ColorTool.hxx"
+#include "XCAFDoc_ColorType.hxx"
+#include "XCAFDoc_LayerTool.hxx"
+#include "XCAFDoc_DimTolTool.hxx"
+#include "XCAFDoc_MaterialTool.hxx"
+#include "XCAFDoc_DocumentTool.hxx"
+#include "TDF_Label.hxx"
+#include "TDF_LabelSequence.hxx"
+#include "STEPCAFControl_Reader.hxx"
+#include "STEPCAFControl_Writer.hxx"
+#include "IGESCAFControl_Reader.hxx"
+#include "IGESCAFControl_Writer.hxx"
+
+#include "IGESControl_Reader.hxx"
+#include "STEPControl_Reader.hxx"
+#include "IGESControl_Writer.hxx"
+#include "STEPControl_Writer.hxx"
+
+#include "StlAPI_Writer.hxx"
+#include "STEPControl_StepModelType.hxx"
+
+namespace netgen
+{
+#include "occmeshsurf.hpp"
+
+  extern DLL_HEADER MeshingParameters mparam;
+
+#define PROJECTION_TOLERANCE 1e-10
+
+#define ENTITYISVISIBLE 1
+#define ENTITYISHIGHLIGHTED 2
+#define ENTITYISDRAWABLE 4
+
+#define OCCGEOMETRYVISUALIZATIONNOCHANGE   0
+#define OCCGEOMETRYVISUALIZATIONFULLCHANGE 1  // Compute transformation matrices and redraw
+#define OCCGEOMETRYVISUALIZATIONHALFCHANGE 2  // Redraw
+
+
+
+   class EntityVisualizationCode
+   {
+      int code;
+
+   public:
+
+      EntityVisualizationCode()
+      {  code = ENTITYISVISIBLE + !ENTITYISHIGHLIGHTED + ENTITYISDRAWABLE;}
+
+      int IsVisible ()
+      {  return code & ENTITYISVISIBLE;}
+
+      int IsHighlighted ()
+      {  return code & ENTITYISHIGHLIGHTED;}
+
+      int IsDrawable ()
+      {  return code & ENTITYISDRAWABLE;}
+
+      void Show ()
+      {  code |= ENTITYISVISIBLE;}
+
+      void Hide ()
+      {  code &= ~ENTITYISVISIBLE;}
+
+      void Highlight ()
+      {  code |= ENTITYISHIGHLIGHTED;}
+
+      void Lowlight ()
+      {  code &= ~ENTITYISHIGHLIGHTED;}
+
+      void SetDrawable ()
+      {  code |= ENTITYISDRAWABLE;}
+
+      void SetNotDrawable ()
+      {  code &= ~ENTITYISDRAWABLE;}
+   };
+
+
+
+   class Line
+   {
+   public:
+      Point<3> p0, p1;
+
+      double Dist (Line l);
+
+      double Length ();
+   };
+
+
+
+   inline double Det3 (double a00, double a01, double a02,
+      double a10, double a11, double a12,
+      double a20, double a21, double a22)
+   {
+      return a00*a11*a22 + a01*a12*a20 + a10*a21*a02 - a20*a11*a02 - a10*a01*a22 - a21*a12*a00;
+   }
+
+
+
+
+   class OCCGeometry : public NetgenGeometry
+   {
+      Point<3> center;
+
+   public:
+      TopoDS_Shape shape;
+      TopTools_IndexedMapOfShape fmap, emap, vmap, somap, shmap, wmap;
+      Array<bool> fsingular, esingular, vsingular;
+      Box<3> boundingbox;
+
+      // Philippose - 29/01/2009
+      // OpenCascade XDE Support
+      // XCAF Handle to make the face colours available to the rest of
+      // the system
+      Handle_XCAFDoc_ColorTool face_colours;
+
+     mutable int changed;
+      Array<int> facemeshstatus;
+
+      // Philippose - 15/01/2009
+      // Maximum mesh size for a given face
+      // (Used to explicitly define mesh size limits on individual faces)
+      Array<double> face_maxh;
+      
+      // Philippose - 14/01/2010
+      // Boolean array to detect whether a face has been explicitly modified 
+      // by the user or not
+      Array<bool> face_maxh_modified;
+
+      // Philippose - 15/01/2009
+      // Indicates which faces have been selected by the user in geometry mode
+      // (Currently handles only selection of one face at a time, but an array would
+      //  help to extend this to multiple faces)
+      Array<bool> face_sel_status;
+
+      Array<EntityVisualizationCode> fvispar, evispar, vvispar;
+
+      double tolerance;
+      bool fixsmalledges;
+      bool fixspotstripfaces;
+      bool sewfaces;
+      bool makesolids;
+      bool splitpartitions;
+
+      OCCGeometry()
+      {
+         somap.Clear();
+         shmap.Clear();
+         fmap.Clear();
+         wmap.Clear();
+         emap.Clear();
+         vmap.Clear();
+      }
+
+
+     virtual void Save (string filename) const;
+
+
+      void BuildFMap();
+
+      Box<3> GetBoundingBox()
+      {  return boundingbox;}
+
+      int NrSolids()
+      {  return somap.Extent();}
+
+      // Philippose - 17/01/2009
+      // Total number of faces in the geometry
+      int NrFaces()
+      {  return fmap.Extent();}
+
+      void SetCenter()
+      {  center = boundingbox.Center();}
+
+      Point<3> Center()
+      {  return center;}
+
+      void Project (int surfi, Point<3> & p) const;
+      bool FastProject (int surfi, Point<3> & ap, double& u, double& v) const;
+
+      OCCSurface GetSurface (int surfi)
+      {
+         cout << "OCCGeometry::GetSurface using PLANESPACE" << endl;
+         return OCCSurface (TopoDS::Face(fmap(surfi)), PLANESPACE);
+      }
+
+      void CalcBoundingBox ();
+      void BuildVisualizationMesh (double deflection);
+
+      void RecursiveTopologyTree (const TopoDS_Shape & sh,
+         stringstream & str,
+         TopAbs_ShapeEnum l,
+         bool free,
+         const char * lname);
+
+      void GetTopologyTree (stringstream & str);
+
+      void PrintNrShapes ();
+
+      void CheckIrregularEntities (stringstream & str);
+
+      void SewFaces();
+
+      void MakeSolid();
+
+      void HealGeometry();
+
+      // Philippose - 15/01/2009
+      // Sets the maximum mesh size for a given face
+      // (Note: Local mesh size limited by the global max mesh size)
+      void SetFaceMaxH(int facenr, double faceh)
+      {
+         if((facenr> 0) && (facenr <= fmap.Extent()))
+         {
+	   face_maxh[facenr-1] = min(mparam.maxh,faceh);
+            
+            // Philippose - 14/01/2010
+            // If the face maxh is greater than or equal to the 
+            // current global maximum, then identify the face as 
+            // not explicitly controlled by the user any more
+            if(faceh >= mparam.maxh)
+            {
+               face_maxh_modified[facenr-1] = 0;
+            }
+            else
+            {
+               face_maxh_modified[facenr-1] = 1;
+            }
+         }
+      }
+
+      // Philippose - 15/01/2009
+      // Returns the local mesh size of a given face
+      double GetFaceMaxH(int facenr)
+      {
+         if((facenr> 0) && (facenr <= fmap.Extent()))
+         {
+            return face_maxh[facenr-1];
+         }
+         else
+         {
+            return 0.0;
+         }
+      }
+      
+      // Philippose - 14/01/2010
+      // Returns the flag whether the given face 
+      // has a mesh size controlled by the user or not
+      bool GetFaceMaxhModified(int facenr)
+      {
+         return face_maxh_modified[facenr-1];
+      }
+      
+      // Philippose - 17/01/2009
+      // Returns the index of the currently selected face
+      int SelectedFace()
+      {
+         int i;
+
+         for(i = 1; i <= fmap.Extent(); i++)
+         {
+            if(face_sel_status[i-1])
+            {
+               return i;
+            }
+         }
+
+         return 0;
+      }
+
+      // Philippose - 17/01/2009
+      // Sets the currently selected face
+      void SetSelectedFace(int facenr)
+      {
+         face_sel_status = 0;
+
+         if((facenr >= 1) && (facenr <= fmap.Extent()))
+         {
+            face_sel_status[facenr-1] = 1;
+         }
+      }
+
+      void LowLightAll()
+      {
+         for (int i = 1; i <= fmap.Extent(); i++)
+            fvispar[i-1].Lowlight();
+         for (int i = 1; i <= emap.Extent(); i++)
+            evispar[i-1].Lowlight();
+         for (int i = 1; i <= vmap.Extent(); i++)
+            vvispar[i-1].Lowlight();
+      }
+
+      void GetUnmeshedFaceInfo (stringstream & str);
+      void GetNotDrawableFaces (stringstream & str);
+      bool ErrorInSurfaceMeshing ();
+
+     void WriteOCC_STL(char * filename);
+
+     virtual int GenerateMesh (Mesh*& mesh, MeshingParameters & mparam, 
+         int perfstepsstart, int perfstepsend);
+
+      virtual const Refinement & GetRefinement () const;
+   };
+
+
+
+   class OCCParameters
+   {
+   public:
+
+      /// Factor for meshing close edges 
+      double resthcloseedgefac;
+
+
+      /// Enable / Disable detection of close edges
+      int resthcloseedgeenable;
+
+
+
+      /*!
+         Default Constructor for the OpenCascade
+         Mesh generation parameter set
+      */
+      OCCParameters();
+
+
+      /*!
+         Dump all the OpenCascade specific meshing parameters 
+         to console
+      */
+      void Print (ostream & ost) const;
+   };
+   
+
+   void PrintContents (OCCGeometry * geom);
+
+   OCCGeometry * LoadOCC_IGES (const char * filename);
+   OCCGeometry * LoadOCC_STEP (const char * filename);
+   OCCGeometry * LoadOCC_BREP (const char * filename);
+
+   extern OCCParameters occparam;
+
+
+   // Philippose - 31.09.2009
+   // External access to the mesh generation functions within the OCC
+   // subsystem (Not sure if this is the best way to implement this....!!)
+   extern int OCCGenerateMesh (OCCGeometry & occgeometry, Mesh*& mesh,
+			       MeshingParameters & mparam,
+			       int perfstepsstart, int perfstepsend);
+
+  extern void OCCSetLocalMeshSize(OCCGeometry & geom, Mesh & mesh);
+
+   extern void OCCMeshSurface (OCCGeometry & geom, Mesh & mesh, int perfstepsend);
+
+   extern void OCCFindEdges (OCCGeometry & geom, Mesh & mesh);
+}
+
+#endif
+
+#endif
diff --git a/contrib/Netgen/libsrc/occ/occmeshsurf.cpp b/contrib/Netgen/libsrc/occ/occmeshsurf.cpp
new file mode 100644
index 0000000000..a1f60db678
--- /dev/null
+++ b/contrib/Netgen/libsrc/occ/occmeshsurf.cpp
@@ -0,0 +1,735 @@
+#ifdef OCCGEOMETRY
+
+#include <mystdlib.h>
+
+#include <occgeom.hpp>
+#include <meshing.hpp>
+#include <GeomLProp_SLProps.hxx>
+#include <ShapeAnalysis_Surface.hxx>
+
+
+namespace netgen
+{
+#include "occmeshsurf.hpp"
+
+
+  bool glob_testout(false);
+
+  void OCCSurface :: GetNormalVector (const Point<3> & p, 
+				      const PointGeomInfo & geominfo,
+				      Vec<3> & n) const
+  {
+    gp_Pnt pnt;
+    gp_Vec du, dv;
+
+    /*
+      double gu = geominfo.u;
+      double gv = geominfo.v;
+
+      if (fabs (gu) < 1e-3) gu = 0;
+      if (fabs (gv) < 1e-3) gv = 0;
+
+      occface->D1(gu,gv,pnt,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();
+    */
+
+
+
+    GeomLProp_SLProps lprop(occface,geominfo.u,geominfo.v,1,1e-5);
+    double setu=geominfo.u,setv=geominfo.v;
+
+    if(lprop.D1U().Magnitude() < 1e-5 || lprop.D1V().Magnitude() < 1e-5)
+      {
+	double ustep = 0.01*(umax-umin);
+	double vstep = 0.01*(vmax-vmin);
+
+	n=0;
+
+	while(setu < umax && (lprop.D1U().Magnitude() < 1e-5 || lprop.D1V().Magnitude() < 1e-5))
+	  setu += ustep;
+	if(setu < umax)
+	  {
+	    lprop.SetParameters(setu,setv);
+	    n(0)+=lprop.Normal().X();
+	    n(1)+=lprop.Normal().Y();
+	    n(2)+=lprop.Normal().Z();
+	  }
+	setu = geominfo.u;
+	while(setu > umin && (lprop.D1U().Magnitude() < 1e-5 || lprop.D1V().Magnitude() < 1e-5))
+	  setu -= ustep;
+	if(setu > umin)
+	  {
+	    lprop.SetParameters(setu,setv);
+	    n(0)+=lprop.Normal().X();
+	    n(1)+=lprop.Normal().Y();
+	    n(2)+=lprop.Normal().Z();
+	  }
+	setu = geominfo.u;
+
+	while(setv < vmax && (lprop.D1U().Magnitude() < 1e-5 || lprop.D1V().Magnitude() < 1e-5))
+	  setv += ustep;
+	if(setv < vmax)
+	  {
+	    lprop.SetParameters(setu,setv);
+	    n(0)+=lprop.Normal().X();
+	    n(1)+=lprop.Normal().Y();
+	    n(2)+=lprop.Normal().Z();
+	  }
+	setv = geominfo.v;
+	while(setv > vmin && (lprop.D1U().Magnitude() < 1e-5 || lprop.D1V().Magnitude() < 1e-5))
+	  setv -= ustep;
+	if(setv > vmin)
+	  {
+	    lprop.SetParameters(setu,setv);
+	    n(0)+=lprop.Normal().X();
+	    n(1)+=lprop.Normal().Y();
+	    n(2)+=lprop.Normal().Z();
+	  }
+	setv = geominfo.v;
+
+	n.Normalize();
+      }
+    else
+      {
+	n(0)=lprop.Normal().X();
+	n(1)=lprop.Normal().Y();
+	n(2)=lprop.Normal().Z();
+      }
+
+    if(glob_testout)
+      {
+	(*testout) << "u " << geominfo.u << " v " << geominfo.v 
+		   << " du " << lprop.D1U().X() << " "<< lprop.D1U().Y() << " "<< lprop.D1U().Z()
+		   << " dv " << lprop.D1V().X() << " "<< lprop.D1V().Y() << " "<< lprop.D1V().Z() << endl;
+      }
+
+
+
+    if (orient == TopAbs_REVERSED) n = -1*n;
+    //  (*testout) << "GetNormalVector" << endl;
+  }
+
+
+  void OCCSurface :: DefineTangentialPlane (const Point<3> & ap1,
+					    const PointGeomInfo & geominfo1,
+					    const Point<3> & ap2,
+					    const PointGeomInfo & geominfo2)
+  {
+    if (projecttype == PLANESPACE)
+      {
+	p1 = ap1; p2 = ap2;
+
+	//cout << "p1 = " << p1 << endl;
+	//cout << "p2 = " << p2 << endl;
+      
+	GetNormalVector (p1, geominfo1, ez);
+      
+	ex = p2 - p1;
+	ex -= (ex * ez) * ez;
+	ex.Normalize();
+	ey = Cross (ez, ex); 
+
+	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;
+	//cout << "ex " << ex << " ey " << ey << " ez " << ez << endl;
+      }
+    else
+      {
+	if ( (geominfo1.u < umin) ||
+	     (geominfo1.u > umax) ||
+	     (geominfo2.u < umin) ||
+	     (geominfo2.u > umax) ||
+	     (geominfo1.v < vmin) ||
+	     (geominfo1.v > vmax) ||
+	     (geominfo2.v < vmin) ||
+	     (geominfo2.v > vmax) ) throw UVBoundsException();
+	  
+
+	p1 = ap1; p2 = ap2;
+	psp1 = Point<2>(geominfo1.u, geominfo1.v);
+	psp2 = Point<2>(geominfo2.u, geominfo2.v);
+      
+	Vec<3> n;
+	GetNormalVector (p1, geominfo1, n);
+
+	gp_Pnt pnt;
+	gp_Vec du, dv;
+	occface->D1 (geominfo1.u, geominfo1.v, pnt, du, dv);
+
+	DenseMatrix D1(3,2), D1T(2,3), DDTinv(2,2);
+	D1(0,0) = du.X(); D1(1,0) = du.Y(); D1(2,0) = du.Z();
+	D1(0,1) = dv.X(); D1(1,1) = dv.Y(); D1(2,1) = dv.Z();
+
+	/*
+	  (*testout) << "DefineTangentialPlane" << endl
+	  << "---------------------" << endl;
+	  (*testout) << "D1 = " << endl << D1 << endl;
+	*/
+
+	Transpose (D1, D1T);
+	DenseMatrix D1TD1(3,3);
+
+	D1TD1 = D1T*D1;
+	if (D1TD1.Det() == 0) throw SingularMatrixException();
+      
+	CalcInverse (D1TD1, DDTinv);
+	DenseMatrix Y(3,2);
+	Vec<3> y1 = (ap2-ap1).Normalize();
+	Vec<3> y2 = Cross(n, y1).Normalize();
+	for (int i = 0; i < 3; i++)
+	  {
+	    Y(i,0) = y1(i);
+	    Y(i,1) = y2(i);
+	  }
+
+	DenseMatrix A(2,2);
+	A = DDTinv * D1T * Y;
+	DenseMatrix Ainv(2,2);
+
+	if (A.Det() == 0) throw SingularMatrixException();
+
+	CalcInverse (A, Ainv);
+
+	for (int i = 0; i < 2; i++)
+	  for (int j = 0; j < 2; j++)
+	    {
+	      Amat(i,j) = A(i,j);
+	      Amatinv(i,j) = Ainv(i,j);
+	    }
+
+	Vec<2> temp = Amatinv * (psp2-psp1);
+      
+
+	double r = temp.Length();
+	//      double alpha = -acos (temp(0)/r);
+	double alpha = -atan2 (temp(1),temp(0));
+	DenseMatrix R(2,2);
+	R(0,0) = cos (alpha);
+	R(1,0) = -sin (alpha);
+	R(0,1) = sin (alpha);
+	R(1,1) = cos (alpha);
+
+
+	A = A*R;
+
+	if (A.Det() == 0) throw SingularMatrixException();
+
+	CalcInverse (A, Ainv);
+    
+
+	for (int i = 0; i < 2; i++)
+	  for (int j = 0; j < 2; j++)
+	    {
+	      Amat(i,j) = A(i,j);
+	      Amatinv(i,j) = Ainv(i,j);
+	    }
+
+	temp = Amatinv * (psp2-psp1);
+      
+      };
+ 
+  }
+
+
+  void OCCSurface :: ToPlane (const Point<3> & p3d,
+			      const PointGeomInfo & geominfo,
+			      Point<2> & pplane, 
+			      double h, int & zone) const
+  {
+    if (projecttype == PLANESPACE)
+      {
+	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;
+
+	/*
+	  if(zone == -1)
+	  {
+	  (*testout) << "zone = -1 for " << p3d << " 2D: " << pplane << " n " << n << " nmid " << nmid << endl;
+	  glob_testout = true;
+	  GetNormalVector (p3d, geominfo, n);
+	  glob_testout = false;
+	  }
+	*/
+      }
+    else
+      {
+	pplane = Point<2>(geominfo.u, geominfo.v);
+	//      (*testout) << "(u,v) = " << geominfo.u << ", " << geominfo.v << endl;
+	pplane = Point<2> (1/h * (Amatinv * (pplane-psp1)));
+	//      pplane = Point<2> (h * (Amatinv * (pplane-psp1)));
+	//      pplane = Point<2> (1/h * ((pplane-psp1)));
+
+	zone = 0;
+      };
+  }	
+
+
+  void OCCSurface :: FromPlane (const Point<2> & pplane, 
+				Point<3> & p3d,
+				PointGeomInfo & gi,
+				double h) 
+  { 
+    if (projecttype == PLANESPACE)
+      {
+	//      cout << "2d   : " << pplane << endl;
+	p3d = p1 + (h * pplane(0)) * ex + (h * pplane(1)) * ey;
+	//      cout << "3d   : " << p3d << endl;
+	Project (p3d, gi);  
+	//      cout << "proj : " << p3d << endl;
+      }
+    else
+      {
+	//      Point<2> pspnew = Point<2>(1/h * (Amat * Vec<2>(pplane)) + Vec<2>(psp1));
+	Point<2> pspnew = Point<2>(h * (Amat * Vec<2>(pplane)) + Vec<2>(psp1));
+	//      Point<2> pspnew = Point<2>(h * (Vec<2>(pplane)) + Vec<2>(psp1));
+	gi.u = pspnew(0);
+	gi.v = pspnew(1);
+	gi.trignum = 1;
+	gp_Pnt val = occface->Value (gi.u, gi.v);
+	p3d = Point<3> (val.X(), val.Y(), val.Z());
+      };
+  }
+
+
+
+  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));
+
+    //(*testout) << "pnt = " << pnt.X() << ", " << pnt.Y() << ", " << pnt.Z() << endl;
+
+
+    /*
+    GeomAPI_ProjectPointOnSurf proj(pnt, occface, umin, umax, vmin, vmax);
+
+    if (!proj.NbPoints())
+      {
+	cout << "Project Point on Surface FAIL" << endl;
+	throw UVBoundsException();
+      }
+    */
+
+    
+
+
+
+    /*
+      cout << "NP = " << proj.NbPoints() << endl;
+
+      for (int i = 1; i <= proj.NbPoints(); i++)
+      {
+      gp_Pnt pnt2 = proj.Point(i);
+      Point<3> p2 = Point<3> (pnt2.X(), pnt2.Y(), pnt2.Z());
+      cout << i << ". p = " << p2 << ", dist = " << (p2-p).Length() << endl;
+      }
+    */
+
+    /*
+    pnt = proj.NearestPoint();
+    proj.LowerDistanceParameters (gi.u, gi.v);
+    */
+
+    double u,v;
+    Handle( ShapeAnalysis_Surface ) su = new ShapeAnalysis_Surface( occface );
+    gp_Pnt2d suval = su->ValueOfUV ( pnt, BRep_Tool::Tolerance( topods_face ) );
+    suval.Coord( u, v);
+    pnt = occface->Value( u, v );
+    
+    //(*testout) << "pnt(proj) = " << pnt.X() << ", " << pnt.Y() << ", " << pnt.Z() << endl;
+    gi.u = u;
+    gi.v = v;
+    
+
+    gi.trignum = 1;
+
+    p = Point<3> (pnt.X(), pnt.Y(), pnt.Z());
+  } 
+
+
+  Meshing2OCCSurfaces :: Meshing2OCCSurfaces (const TopoDS_Shape & asurf,
+					      const Box<3> & abb, int aprojecttype)
+    : Meshing2(mparam, Box<3>(abb.PMin(), abb.PMax())), surface(TopoDS::Face(asurf), aprojecttype)
+  {
+    ;
+  }
+
+
+  void Meshing2OCCSurfaces :: DefineTransformation (const Point3d & p1, const 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, Point<3> & p) const
+  {
+    geometry.Project (surfind, p);
+  }
+
+
+  int MeshOptimize2dOCCSurfaces :: ProjectPointGI (INDEX surfind, Point<3> & p, PointGeomInfo & gi) const
+  {
+    double u = gi.u;
+    double v = gi.v;
+
+    Point<3> hp = p;
+    if (geometry.FastProject (surfind, hp, u, v))
+      {
+	p = hp;
+	return 1;
+      }
+    ProjectPoint (surfind, p); 
+    return CalcPointGeomInfo (surfind, gi, p); 
+  }
+
+
+  void MeshOptimize2dOCCSurfaces :: ProjectPoint2 (INDEX surfind, INDEX surfind2, 
+						   Point<3> & p) const
+  {
+    TopExp_Explorer exp0, exp1;
+    bool done = false;
+    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 = true;
+	      double s0, s1;
+	      c = BRep_Tool::Curve(TopoDS::Edge(exp0.Current()), s0, s1);
+	    }
+	}
+  
+    gp_Pnt pnt(p(0), p(1), p(2));
+    GeomAPI_ProjectPointOnCurve proj(pnt, c);
+    pnt = proj.NearestPoint();  
+    p(0) = pnt.X();
+    p(1) = pnt.Y();
+    p(2) = pnt.Z();
+	
+  }
+
+  void MeshOptimize2dOCCSurfaces :: 
+  GetNormalVector(INDEX surfind, const Point<3> & p, PointGeomInfo & geominfo, Vec<3> & 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 Point<3> & p, Vec<3> & n) const
+  {
+    //  static int cnt = 0;
+    //  if (cnt++ % 1000 == 0) cout << "GetNV cnt = " << cnt << endl;
+    Standard_Real u,v;
+
+    gp_Pnt pnt(p(0), p(1), p(2));
+
+    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);
+    */
+    
+    Handle( ShapeAnalysis_Surface ) su = new ShapeAnalysis_Surface( occface );
+    gp_Pnt2d suval = su->ValueOfUV ( pnt, BRep_Tool::Tolerance( TopoDS::Face(geometry.fmap(surfind)) ) );
+    suval.Coord( u, v);
+    pnt = occface->Value( 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 Point<3> & p) const
+  {
+    Standard_Real u,v;
+
+    gp_Pnt pnt(p(0), p(1), p(2));
+
+    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);  
+    */
+
+    Handle( ShapeAnalysis_Surface ) su = new ShapeAnalysis_Surface( occface );
+    gp_Pnt2d suval = su->ValueOfUV ( pnt, BRep_Tool::Tolerance( TopoDS::Face(geometry.fmap(surfind)) ) );
+    suval.Coord( u, v);
+    //pnt = occface->Value( u, v );
+    
+
+    gi.u = u;
+    gi.v = v;
+    return 1;
+  }
+
+
+
+
+
+
+  OCCRefinementSurfaces :: OCCRefinementSurfaces (const OCCGeometry & ageometry)
+    : Refinement(), geometry(ageometry)
+  {
+    ;
+  }
+
+  OCCRefinementSurfaces :: ~OCCRefinementSurfaces ()
+  {
+    ;
+  }
+
+  /*
+    inline double Det3 (double a00, double a01, double a02,
+    double a10, double a11, double a12,
+    double a20, double a21, double a22)
+    {
+    return a00*a11*a22 + a01*a12*a20 + a10*a21*a02 - a20*a11*a02 - a10*a01*a22 - a21*a12*a00;
+    }
+
+    bool ProjectToSurface (gp_Pnt & p, Handle(Geom_Surface) surface, double& u, double& v)
+    {
+    gp_Pnt x = surface->Value (u,v);
+
+    if (p.SquareDistance(x) <= sqr(PROJECTION_TOLERANCE)) return true;
+
+    gp_Vec du, dv;
+
+    surface->D1(u,v,x,du,dv);
+
+    int count = 0;
+
+    gp_Pnt xold;
+    gp_Vec n;
+    double det, lambda, mu;
+
+    do {
+    count++;
+
+    n = du^dv;
+
+    det = Det3 (n.X(), du.X(), dv.X(),
+    n.Y(), du.Y(), dv.Y(),
+    n.Z(), du.Z(), dv.Z());
+
+    if (det < 1e-15) return false; 
+
+    lambda = Det3 (n.X(), p.X()-x.X(), dv.X(),
+    n.Y(), p.Y()-x.Y(), dv.Y(),
+    n.Z(), p.Z()-x.Z(), dv.Z())/det;
+
+    mu     = Det3 (n.X(), du.X(), p.X()-x.X(),
+    n.Y(), du.Y(), p.Y()-x.Y(),
+    n.Z(), du.Z(), p.Z()-x.Z())/det;
+  
+    u += lambda;
+    v += mu;
+
+    xold = x;
+    surface->D1(u,v,x,du,dv);
+
+    } while (xold.SquareDistance(x) > sqr(PROJECTION_TOLERANCE) || count > 50);
+
+    if (count > 50) return false;
+
+    p = x;
+
+    return true;
+    }
+  */
+
+  void OCCRefinementSurfaces :: 
+  PointBetween (const Point<3> & p1, const Point<3> & p2, double secpoint,
+		int surfi, 
+		const PointGeomInfo & gi1, 
+		const PointGeomInfo & gi2,
+		Point<3> & newp, PointGeomInfo & newgi) const
+  {
+    Point<3> hnewp;
+    hnewp = p1+secpoint*(p2-p1);
+
+    if (surfi > 0)
+      {
+      
+	double u = gi1.u+secpoint*(gi2.u-gi1.u);
+	double v = gi1.v+secpoint*(gi2.v-gi1.v);
+ 
+	if (!geometry.FastProject (surfi, hnewp, u, v))
+	  {
+	  //  cout << "Fast projection to surface fails! Using OCC projection" << endl;
+	    geometry.Project (surfi, hnewp);
+	  }
+
+	newgi.trignum = 1;
+        newgi.u = u;
+        newgi.v = v;
+      }
+  
+    newp = hnewp;
+  }
+
+
+  void OCCRefinementSurfaces :: 
+  PointBetween (const Point<3> & p1, const Point<3> & p2, double secpoint,
+		int surfi1, int surfi2, 
+		const EdgePointGeomInfo & ap1, 
+		const EdgePointGeomInfo & ap2,
+		Point<3> & newp, EdgePointGeomInfo & newgi) const
+  {
+    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;
+    newgi = ap1;
+  };
+
+
+  void OCCRefinementSurfaces :: ProjectToSurface (Point<3> & p, int surfi) const
+  {
+    if (surfi > 0)
+      geometry.Project (surfi, p);
+  };
+
+  void OCCRefinementSurfaces :: ProjectToSurface (Point<3> & p, int surfi, PointGeomInfo & gi) const
+  {
+    if (surfi > 0)
+      if (!geometry.FastProject (surfi, p, gi.u, gi.v))
+	{
+	  cout << "Fast projection to surface fails! Using OCC projection" << endl;
+	  geometry.Project (surfi, p);
+	}
+  };
+
+
+
+}
+
+
+#endif
diff --git a/contrib/Netgen/libsrc/occ/occmeshsurf.hpp b/contrib/Netgen/libsrc/occ/occmeshsurf.hpp
new file mode 100644
index 0000000000..198ade67ce
--- /dev/null
+++ b/contrib/Netgen/libsrc/occ/occmeshsurf.hpp
@@ -0,0 +1,203 @@
+#ifdef OCCGEOMETRY
+
+#ifndef FILE_OCCMESHSURF
+#define FILE_OCCMESHSURF
+
+#include "occgeom.hpp"
+
+#define PARAMETERSPACE -1
+#define PLANESPACE     1
+
+class OCCGeometry;
+
+class SingularMatrixException
+{};
+
+class UVBoundsException
+{};
+
+class OCCSurface
+{
+public:
+  TopoDS_Face topods_face;
+  Handle(Geom_Surface) occface;
+  TopAbs_Orientation orient;
+  int projecttype;
+
+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;
+
+  // UV Bounds
+  double umin, umax, vmin, vmax;
+
+public:
+  OCCSurface (const TopoDS_Face & aface, int aprojecttype)
+  {
+    topods_face = aface;
+    occface = BRep_Tool::Surface(topods_face);
+    orient = topods_face.Orientation();
+    projecttype = aprojecttype;
+    ShapeAnalysis::GetFaceUVBounds (topods_face, umin, umax, vmin, vmax);
+    umin -= fabs(umax-umin)/100.0;
+    vmin -= fabs(vmax-vmin)/100.0;
+    umax += fabs(umax-umin)/100.0;
+    vmax += fabs(vmax-vmin)/100.0;
+    // projecttype = PLANESPACE;
+    /*
+    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, int aprojecttype);
+
+  ///
+  int GetProjectionType ()
+  { return surface.projecttype; }
+
+protected:
+  ///
+  virtual void DefineTransformation (const Point3d & p1, const 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, Point<3> & p) const;
+    ///
+    virtual void ProjectPoint2 (INDEX surfind, INDEX surfind2, Point<3> & p) const;
+    ///
+    virtual int ProjectPointGI (INDEX surfind, Point<3> & p, PointGeomInfo & gi) const;
+    ///
+    virtual void GetNormalVector(INDEX surfind, const Point<3> & p, Vec<3> & n) const;
+    ///
+    virtual void GetNormalVector(INDEX surfind, const Point<3> & p, PointGeomInfo & gi, Vec<3> & n) const;
+    
+    virtual int CalcPointGeomInfo(int surfind, PointGeomInfo& gi, const Point<3> & p3) const;
+};
+
+
+
+class OCCGeometry;
+
+
+class OCCRefinementSurfaces : public Refinement
+{
+  const OCCGeometry & geometry;
+
+public:
+  OCCRefinementSurfaces (const OCCGeometry & ageometry);
+  virtual ~OCCRefinementSurfaces ();
+  
+  virtual void PointBetween (const Point<3> & p1, const Point<3> & p2, double secpoint,
+			     int surfi, 
+			     const PointGeomInfo & gi1, 
+			     const PointGeomInfo & gi2,
+			     Point<3> & newp, PointGeomInfo & newgi) const;
+
+  virtual void PointBetween (const Point<3> & p1, const Point<3> & p2, double secpoint,
+			     int surfi1, int surfi2, 
+			     const EdgePointGeomInfo & ap1, 
+			     const EdgePointGeomInfo & ap2,
+			     Point<3> & newp, EdgePointGeomInfo & newgi) const;
+
+  virtual void ProjectToSurface (Point<3> & p, int surfi) const;
+
+  virtual void ProjectToSurface (Point<3> & p, int surfi, PointGeomInfo & gi) const;
+};
+
+
+
+#endif
+
+
+
+#endif
diff --git a/contrib/Netgen/libsrc/occ/occpkg.cpp b/contrib/Netgen/libsrc/occ/occpkg.cpp
new file mode 100644
index 0000000000..aeb691e595
--- /dev/null
+++ b/contrib/Netgen/libsrc/occ/occpkg.cpp
@@ -0,0 +1,1020 @@
+#ifdef OCCGEOMETRY
+
+#include <mystdlib.h>
+#include <myadt.hpp>
+#include <linalg.hpp>
+#include <csg.hpp>
+#include <occgeom.hpp>
+
+
+#include <incvis.hpp>
+#include <visual.hpp>
+
+#include "../meshing/bcfunctions.hpp"
+
+#include "vsocc.hpp"
+
+
+extern "C" int Ng_occ_Init (Tcl_Interp * interp);
+
+
+
+namespace netgen
+{
+  extern NetgenGeometry * ng_geometry;
+  extern AutoPtr<Mesh> mesh;
+ 
+  char * err_needsoccgeometry = (char*) "This operation needs an OCC geometry";
+  extern char * err_needsmesh;
+  extern char * err_jobrunning;
+
+
+
+                          
+  class OCCGeometryRegister : public GeometryRegister
+  {
+  public:
+    virtual NetgenGeometry * Load (string filename) const;
+    virtual VisualScene * GetVisualScene (const NetgenGeometry * geom) const;
+
+    virtual void SetParameters (Tcl_Interp * interp) 
+    {
+      occparam.resthcloseedgefac =
+	atof (Tcl_GetVar (interp, "::stloptions.resthcloseedgefac", 0));
+      occparam.resthcloseedgeenable =
+	atoi (Tcl_GetVar (interp, "::stloptions.resthcloseedgeenable", 0));
+    }
+  };
+
+
+
+
+  int Ng_SetOCCVisParameters  (ClientData clientData,
+			       Tcl_Interp * interp,
+			       int argc, tcl_const char *argv[])
+  {
+#ifdef OCCGEOMETRY
+    int showvolume;
+    OCCGeometry * occgeometry = dynamic_cast<OCCGeometry*> (ng_geometry);
+
+    showvolume = atoi (Tcl_GetVar (interp, "::occoptions.showvolumenr", 0));
+
+    if (occgeometry)
+      if (showvolume != vispar.occshowvolumenr)
+	{
+	  if (showvolume < 0 || showvolume > occgeometry->NrSolids())
+	    {
+	      char buf[20];
+	      sprintf (buf, "%5i", vispar.occshowvolumenr);
+	      Tcl_SetVar (interp, "::occoptions.showvolumenr", buf, 0);
+	    }
+	  else
+	    {
+	      vispar.occshowvolumenr = showvolume;
+	      if (occgeometry)
+		occgeometry -> changed = OCCGEOMETRYVISUALIZATIONHALFCHANGE;
+	    }
+	}
+    
+    int temp;
+
+    temp = atoi (Tcl_GetVar (interp, "::occoptions.visproblemfaces", 0));
+
+    if ((bool) temp != vispar.occvisproblemfaces)
+      {
+	vispar.occvisproblemfaces = temp;
+	if (occgeometry)
+	  occgeometry -> changed = OCCGEOMETRYVISUALIZATIONHALFCHANGE;
+      }
+
+    vispar.occshowsurfaces = atoi (Tcl_GetVar (interp, "::occoptions.showsurfaces", 0));
+    vispar.occshowedges = atoi (Tcl_GetVar (interp, "::occoptions.showedges", 0));
+    vispar.occzoomtohighlightedentity = atoi (Tcl_GetVar (interp, "::occoptions.zoomtohighlightedentity", 0));
+    vispar.occdeflection = pow(10.0,-1-atof (Tcl_GetVar (interp, "::occoptions.deflection", 0)));
+
+#endif
+
+
+
+
+
+#ifdef ACIS
+    vispar.ACISshowfaces = atoi (Tcl_GetVar (interp, "::occoptions.showsurfaces", 0));
+    vispar.ACISshowedges = atoi (Tcl_GetVar (interp, "::occoptions.showedges", 0));
+    vispar.ACISshowsolidnr = atoi (Tcl_GetVar (interp, "::occoptions.showsolidnr", 0));
+    vispar.ACISshowsolidnr2 = atoi (Tcl_GetVar (interp, "::occoptions.showsolidnr2", 0));
+
+#endif
+
+
+
+    return TCL_OK;
+  }  
+
+
+
+
+  int Ng_GetOCCData (ClientData clientData,
+		     Tcl_Interp * interp,
+		     int argc, tcl_const char *argv[])
+  {
+#ifdef OCCGEOMETRY
+    OCCGeometry * occgeometry = dynamic_cast<OCCGeometry*> (ng_geometry);
+
+    static char buf[1000];
+    buf[0] = 0;
+    stringstream str;
+
+    if (argc >= 2)
+      {
+	if (strcmp (argv[1], "getentities") == 0)
+	  {
+	    if (occgeometry)
+	      {
+		occgeometry->GetTopologyTree(str);
+	      }
+	  }
+      }
+
+    Tcl_SetResult (interp, (char*)str.str().c_str(), TCL_VOLATILE);
+
+#endif
+    return TCL_OK;
+  }
+
+  
+
+  int Ng_OCCCommand (ClientData clientData,
+		     Tcl_Interp * interp,
+		     int argc, tcl_const char *argv[])
+  {
+#ifdef OCCGEOMETRY
+    OCCGeometry * occgeometry = dynamic_cast<OCCGeometry*> (ng_geometry);
+
+    stringstream str;
+    if (argc >= 2)
+      {
+	if (strcmp (argv[1], "isoccgeometryloaded") == 0)
+	  {
+	    if (occgeometry)
+	      str << "1 " << flush;
+	    else str << "0 " << flush;
+
+	    Tcl_SetResult (interp, (char*)str.str().c_str(), TCL_VOLATILE);
+	  }
+	if (occgeometry)
+	  {
+	    if (strcmp (argv[1], "buildvisualizationmesh") == 0)
+	      {
+		occgeometry->BuildVisualizationMesh(vispar.occdeflection);
+		occgeometry->changed = OCCGEOMETRYVISUALIZATIONHALFCHANGE;
+	      }
+	    if (strcmp (argv[1], "mesherror") == 0)
+	      {
+		if (occgeometry->ErrorInSurfaceMeshing())
+		  str << 1;
+		else
+		  str << 0;
+	      }
+	    if (strcmp (argv[1], "sewfaces") == 0)
+	      {
+		cout << "Before operation:" << endl;
+		occgeometry->PrintNrShapes();
+		occgeometry->SewFaces();
+		occgeometry->BuildFMap();
+		cout << endl << "After operation:" << endl;
+		occgeometry->PrintNrShapes();
+		occgeometry->BuildVisualizationMesh(vispar.occdeflection);
+		occgeometry->changed = OCCGEOMETRYVISUALIZATIONHALFCHANGE;
+	      }
+	    if (strcmp (argv[1], "makesolid") == 0)
+	      {
+		cout << "Before operation:" << endl;
+		occgeometry->PrintNrShapes();
+		occgeometry->MakeSolid();
+		occgeometry->BuildFMap();
+		cout << endl << "After operation:" << endl;
+		occgeometry->PrintNrShapes();
+		occgeometry->BuildVisualizationMesh(vispar.occdeflection);
+		occgeometry->changed = OCCGEOMETRYVISUALIZATIONHALFCHANGE;
+	      }
+	    if (strcmp (argv[1], "upgradetopology") == 0)
+	      {
+		cout << "Before operation:" << endl;
+		occgeometry->PrintNrShapes();
+		occgeometry->SewFaces();
+		occgeometry->MakeSolid();
+		occgeometry->BuildFMap();
+		cout << endl << "After operation:" << endl;
+		occgeometry->PrintNrShapes();
+		occgeometry->BuildVisualizationMesh(vispar.occdeflection);
+		occgeometry->changed = OCCGEOMETRYVISUALIZATIONHALFCHANGE;
+	      }
+	    if (strcmp (argv[1], "shapehealing") == 0)
+	      {
+		occgeometry->tolerance =
+		  atof (Tcl_GetVar (interp, "::occoptions.tolerance", 0));
+		occgeometry->fixsmalledges =
+		  atoi (Tcl_GetVar (interp, "::occoptions.fixsmalledges", 0));
+		occgeometry->fixspotstripfaces =
+		  atoi (Tcl_GetVar (interp, "::occoptions.fixspotstripfaces", 0));
+		occgeometry->sewfaces =
+		  atoi (Tcl_GetVar (interp, "::occoptions.sewfaces", 0));
+		occgeometry->makesolids =
+		  atoi (Tcl_GetVar (interp, "::occoptions.makesolids", 0));
+		occgeometry->splitpartitions =
+		  atoi (Tcl_GetVar (interp, "::occoptions.splitpartitions", 0));
+
+		//	      cout << "Before operation:" << endl;
+		//	      occgeometry->PrintNrShapes();
+		occgeometry->HealGeometry();
+		occgeometry->BuildFMap();
+		//	      cout << endl << "After operation:" << endl;
+		//	      occgeometry->PrintNrShapes();
+		occgeometry->BuildVisualizationMesh(vispar.occdeflection);
+		occgeometry->changed = OCCGEOMETRYVISUALIZATIONHALFCHANGE;
+	      }
+
+
+	    if (strcmp (argv[1], "highlightentity") == 0)
+	      {
+		if (strcmp (argv[2], "Face") == 0)
+		  {
+		    int nr = atoi (argv[3]);
+		    occgeometry->LowLightAll();
+
+		    occgeometry->fvispar[nr-1].Highlight();
+		    if (vispar.occzoomtohighlightedentity)
+		      occgeometry->changed = OCCGEOMETRYVISUALIZATIONFULLCHANGE;
+		    else
+		      occgeometry->changed = OCCGEOMETRYVISUALIZATIONHALFCHANGE;
+		  }
+		if (strcmp (argv[2], "Shell") == 0)
+		  {
+		    int nr = atoi (argv[3]);
+		    occgeometry->LowLightAll();
+
+		    TopExp_Explorer exp;
+		    for (exp.Init (occgeometry->shmap(nr), TopAbs_FACE);
+			 exp.More(); exp.Next())
+		      {
+			int i = occgeometry->fmap.FindIndex (TopoDS::Face(exp.Current()));
+			occgeometry->fvispar[i-1].Highlight();
+		      }
+		    if (vispar.occzoomtohighlightedentity)
+		      occgeometry->changed = OCCGEOMETRYVISUALIZATIONFULLCHANGE;
+		    else
+		      occgeometry->changed = OCCGEOMETRYVISUALIZATIONHALFCHANGE;
+		  }
+		if (strcmp (argv[2], "Solid") == 0)
+		  {
+		    int nr = atoi (argv[3]);
+		    occgeometry->LowLightAll();
+
+		    TopExp_Explorer exp;
+		    for (exp.Init (occgeometry->somap(nr), TopAbs_FACE);
+			 exp.More(); exp.Next())
+		      {
+			int i = occgeometry->fmap.FindIndex (TopoDS::Face(exp.Current()));
+			occgeometry->fvispar[i-1].Highlight();
+		      }
+		    if (vispar.occzoomtohighlightedentity)
+		      occgeometry->changed = OCCGEOMETRYVISUALIZATIONFULLCHANGE;
+		    else
+		      occgeometry->changed = OCCGEOMETRYVISUALIZATIONHALFCHANGE;
+		  }
+		/*
+		  if (strcmp (argv[2], "CompSolid") == 0)
+		  {
+		  int nr = atoi (argv[3]);
+		  occgeometry->LowLightAll();
+
+		  TopExp_Explorer exp;
+		  for (exp.Init (occgeometry->cmap(nr), TopAbs_FACE);
+		  exp.More(); exp.Next())
+		  {
+		  int i = occgeometry->fmap.FindIndex (TopoDS::Face(exp.Current()));
+		  occgeometry->fvispar[i-1].Highlight();
+		  }
+		  occgeometry->changed = OCCGEOMETRYVISUALIZATIONHALFCHANGE;
+		  }
+		*/
+
+		if (strcmp (argv[2], "Edge") == 0)
+		  {
+		    int nr = atoi (argv[3]);
+		    occgeometry->LowLightAll();
+
+		    occgeometry->evispar[nr-1].Highlight();
+		    if (vispar.occzoomtohighlightedentity)
+		      occgeometry->changed = OCCGEOMETRYVISUALIZATIONFULLCHANGE;
+		    else
+		      occgeometry->changed = OCCGEOMETRYVISUALIZATIONHALFCHANGE;
+		  }
+		if (strcmp (argv[2], "Wire") == 0)
+		  {
+		    int nr = atoi (argv[3]);
+		    occgeometry->LowLightAll();
+
+		    TopExp_Explorer exp;
+		    for (exp.Init (occgeometry->wmap(nr), TopAbs_EDGE);
+			 exp.More(); exp.Next())
+		      {
+			int i = occgeometry->emap.FindIndex (TopoDS::Edge(exp.Current()));
+			occgeometry->evispar[i-1].Highlight();
+		      }
+		    if (vispar.occzoomtohighlightedentity)
+		      occgeometry->changed = OCCGEOMETRYVISUALIZATIONFULLCHANGE;
+		    else
+		      occgeometry->changed = OCCGEOMETRYVISUALIZATIONHALFCHANGE;
+		  }
+
+		if (strcmp (argv[2], "Vertex") == 0)
+		  {
+		    int nr = atoi (argv[3]);
+		    occgeometry->LowLightAll();
+
+		    occgeometry->vvispar[nr-1].Highlight();
+		    if (vispar.occzoomtohighlightedentity)
+		      occgeometry->changed = OCCGEOMETRYVISUALIZATIONFULLCHANGE;
+		    else
+		      occgeometry->changed = OCCGEOMETRYVISUALIZATIONHALFCHANGE;
+		  }
+
+	      }
+
+
+
+	    if (strcmp (argv[1], "show") == 0)
+	      {
+		int nr = atoi (argv[3]);
+		occgeometry->changed = OCCGEOMETRYVISUALIZATIONHALFCHANGE;
+
+		if (strcmp (argv[2], "Face") == 0)
+		  {
+		    occgeometry->fvispar[nr-1].Show();
+		  }
+		if (strcmp (argv[2], "Shell") == 0)
+		  {
+		    TopExp_Explorer exp;
+		    for (exp.Init (occgeometry->shmap(nr), TopAbs_FACE);
+			 exp.More(); exp.Next())
+		      {
+			int i = occgeometry->fmap.FindIndex (TopoDS::Face(exp.Current()));
+			occgeometry->fvispar[i-1].Show();
+		      }
+		  }
+		if (strcmp (argv[2], "Solid") == 0)
+		  {
+		    TopExp_Explorer exp;
+		    for (exp.Init (occgeometry->somap(nr), TopAbs_FACE);
+			 exp.More(); exp.Next())
+		      {
+			int i = occgeometry->fmap.FindIndex (TopoDS::Face(exp.Current()));
+			occgeometry->fvispar[i-1].Show();
+		      }
+		  }
+		if (strcmp (argv[2], "Edge") == 0)
+		  {
+		    occgeometry->evispar[nr-1].Show();
+		  }
+		if (strcmp (argv[2], "Wire") == 0)
+		  {
+		    TopExp_Explorer exp;
+		    for (exp.Init (occgeometry->wmap(nr), TopAbs_EDGE);
+			 exp.More(); exp.Next())
+		      {
+			int i = occgeometry->emap.FindIndex (TopoDS::Edge(exp.Current()));
+			occgeometry->evispar[i-1].Show();
+		      }
+		  }
+	      }
+
+
+	    if (strcmp (argv[1], "hide") == 0)
+	      {
+		int nr = atoi (argv[3]);
+		occgeometry->changed = OCCGEOMETRYVISUALIZATIONHALFCHANGE;
+
+		if (strcmp (argv[2], "Face") == 0)
+		  {
+		    occgeometry->fvispar[nr-1].Hide();
+		  }
+		if (strcmp (argv[2], "Shell") == 0)
+		  {
+		    TopExp_Explorer exp;
+		    for (exp.Init (occgeometry->shmap(nr), TopAbs_FACE);
+			 exp.More(); exp.Next())
+		      {
+			int i = occgeometry->fmap.FindIndex (TopoDS::Face(exp.Current()));
+			occgeometry->fvispar[i-1].Hide();
+		      }
+		  }
+		if (strcmp (argv[2], "Solid") == 0)
+		  {
+		    TopExp_Explorer exp;
+		    for (exp.Init (occgeometry->somap(nr), TopAbs_FACE);
+			 exp.More(); exp.Next())
+		      {
+			int i = occgeometry->fmap.FindIndex (TopoDS::Face(exp.Current()));
+			occgeometry->fvispar[i-1].Hide();
+		      }
+		  }
+		if (strcmp (argv[2], "Edge") == 0)
+		  {
+		    occgeometry->evispar[nr-1].Hide();
+		  }
+		if (strcmp (argv[2], "Wire") == 0)
+		  {
+		    TopExp_Explorer exp;
+		    for (exp.Init (occgeometry->wmap(nr), TopAbs_EDGE);
+			 exp.More(); exp.Next())
+		      {
+			int i = occgeometry->emap.FindIndex (TopoDS::Edge(exp.Current()));
+			occgeometry->evispar[i-1].Hide();
+		      }
+		  }
+	      }
+
+
+
+	    if (strcmp (argv[1], "findsmallentities") == 0)
+	      {
+		stringstream str("");
+		occgeometry->CheckIrregularEntities(str);
+		Tcl_SetResult (interp, (char*)str.str().c_str(), TCL_VOLATILE);
+	      }
+	    if (strcmp (argv[1], "getunmeshedfaceinfo") == 0)
+	      {
+		occgeometry->GetUnmeshedFaceInfo(str);
+		Tcl_SetResult (interp, (char*)str.str().c_str(), TCL_VOLATILE);
+	      }
+	    if (strcmp (argv[1], "getnotdrawablefaces") == 0)
+	      {
+		occgeometry->GetNotDrawableFaces(str);
+		Tcl_SetResult (interp, (char*)str.str().c_str(), TCL_VOLATILE);
+	      }
+	    if (strcmp (argv[1], "redrawstatus") == 0)
+	      {
+		int i = atoi (argv[2]);
+		occgeometry->changed = i;
+	      }
+	    if (strcmp (argv[1], "swaporientation") == 0)
+	      {
+		IGESControl_Writer writer("millimeters", 1);
+		writer.AddShape (occgeometry->shape);
+		writer.Write ("1.igs");
+		/*
+		  int nr = atoi (argv[3]);
+
+		  //	      const_cast<TopoDS_Shape&> (occgeometry->fmap(nr)).Reverse();
+
+		  Handle_ShapeBuild_ReShape rebuild = new ShapeBuild_ReShape;
+		  rebuild->Apply(occgeometry->shape);
+
+		  TopoDS_Shape sh;
+
+		  //	      if (strcmp (argv[2], "CompSolid") == 0) sh = occgeometry->cmap(nr);
+		  if (strcmp (argv[2], "Solid") == 0) sh = occgeometry->somap(nr);
+		  if (strcmp (argv[2], "Shell") == 0) sh = occgeometry->shmap(nr);
+		  if (strcmp (argv[2], "Face") == 0) sh = occgeometry->fmap(nr);
+		  if (strcmp (argv[2], "Wire") == 0) sh = occgeometry->wmap(nr);
+		  if (strcmp (argv[2], "Edge") == 0) sh = occgeometry->emap(nr);
+
+		  rebuild->Replace(sh, sh.Reversed(), Standard_False);
+
+		  TopoDS_Shape newshape = rebuild->Apply(occgeometry->shape, TopAbs_SHELL, 1);
+		  occgeometry->shape = newshape;
+
+		  occgeometry->BuildFMap();
+		  occgeometry->BuildVisualizationMesh();
+		  occgeometry->changed = OCCGEOMETRYVISUALIZATIONHALFCHANGE;
+		*/
+	      }
+	    if (strcmp (argv[1], "marksingular") == 0)
+	      {
+		int nr = atoi (argv[3]);
+		cout << "marking " << argv[2] << " " << nr << endl;
+		char buf[2]; buf[0] = '0'; buf[1] = 0;
+		bool sing = false;
+		if (strcmp (argv[2], "Face") == 0)
+		  sing = occgeometry->fsingular[nr-1] = !occgeometry->fsingular[nr-1];
+		if (strcmp (argv[2], "Edge") == 0)
+		  sing = occgeometry->esingular[nr-1] = !occgeometry->esingular[nr-1];
+		if (strcmp (argv[2], "Vertex") == 0)
+		  sing = occgeometry->vsingular[nr-1] = !occgeometry->vsingular[nr-1];
+
+		if (sing) buf[0] = '1';
+
+                Tcl_SetVar (interp, "::ismarkedsingular", buf, 0);
+
+		stringstream str;
+		occgeometry->GetTopologyTree (str);
+
+		char* cstr = (char*)str.str().c_str();
+
+		(*testout) << cstr << endl;
+
+		char helpstr[1000];
+
+		while (strchr (cstr, '}'))
+		  {
+		    strncpy (helpstr, cstr+2, strlen(strchr(cstr+2, '}')));
+		    (*testout) << "***" << cstr << "***" << endl;
+		    cstr = strchr (cstr, '}');
+		  } 
+	      }
+	  }
+      }
+
+#endif
+    return TCL_OK;
+  }
+
+
+
+#ifdef OCCGEOMETRY
+  /*
+  void OCCConstructGeometry (OCCGeometry & geom);
+
+  int Ng_OCCConstruction (ClientData clientData,
+			  Tcl_Interp * interp,
+			  int argc, tcl_const char *argv[])
+  {
+    if (occgeometry)
+      OCCConstructGeometry (*occgeometry);
+    return TCL_OK;
+  }
+  */
+#endif
+
+
+
+
+  // Philippose - 30/01/2009
+  // TCL interface function for the Local Face Mesh size
+  // definition functionality
+  int Ng_SurfaceMeshSize (ClientData clientData,
+		                    Tcl_Interp * interp,
+		                    int argc, tcl_const char *argv[])
+  {
+#ifdef OCCGEOMETRY
+
+    static char buf[100];
+
+    if (argc < 2)
+    {
+	   Tcl_SetResult (interp, (char *)"Ng_SurfaceMeshSize needs arguments", TCL_STATIC);
+	   return TCL_ERROR;
+    }
+
+    OCCGeometry * occgeometry = dynamic_cast<OCCGeometry*> (ng_geometry);
+    if (!occgeometry)
+    {
+      Tcl_SetResult (interp, (char *)"Ng_SurfaceMeshSize currently supports only OCC (STEP/IGES) Files", TCL_STATIC);
+	   return TCL_ERROR;
+    }
+
+    // Update the face mesh sizes to reflect the global maximum mesh size
+    for(int i = 1; i <= occgeometry->NrFaces(); i++)
+    {
+           if(!occgeometry->GetFaceMaxhModified(i))
+           {
+              occgeometry->SetFaceMaxH(i, mparam.maxh);
+           }   
+    }
+
+    if (strcmp (argv[1], "setsurfms") == 0)
+    {
+	   int facenr = atoi (argv[2]);
+	   double surfms = atof (argv[3]);
+	   if (occgeometry && facenr >= 1 && facenr <= occgeometry->NrFaces())
+	     occgeometry->SetFaceMaxH(facenr, surfms);
+
+    }
+
+    if (strcmp (argv[1], "setall") == 0)
+    {
+	   double surfms = atof (argv[2]);
+	   if (occgeometry)
+	   {
+	     int nrFaces = occgeometry->NrFaces();
+	     for (int i = 1; i <= nrFaces; i++)
+	      occgeometry->SetFaceMaxH(i, surfms);
+	   }
+    }
+
+    if (strcmp (argv[1], "getsurfms") == 0)
+    {
+	   int facenr = atoi (argv[2]);
+	   if (occgeometry && facenr >= 1 && facenr <= occgeometry->NrFaces())
+	   {
+	     sprintf (buf, "%5.2f", occgeometry->GetFaceMaxH(facenr));
+	   }
+	   else
+	   {
+	     sprintf (buf, "%5.2f", mparam.maxh);
+	   }
+	   Tcl_SetResult (interp, buf, TCL_STATIC);
+    }
+
+    if (strcmp (argv[1], "getactive") == 0)
+    {
+	   sprintf (buf, "%d", occgeometry->SelectedFace());
+	   Tcl_SetResult (interp, buf, TCL_STATIC);
+    }
+
+    if (strcmp (argv[1], "setactive") == 0)
+    {
+	   int facenr = atoi (argv[2]);
+	   if (occgeometry && facenr >= 1 && facenr <= occgeometry->NrFaces())
+	   {
+	     occgeometry->SetSelectedFace (facenr);
+
+        occgeometry->LowLightAll();
+        occgeometry->fvispar[facenr-1].Highlight();
+        occgeometry->changed = OCCGEOMETRYVISUALIZATIONHALFCHANGE;
+	   }
+    }
+
+    if (strcmp (argv[1], "getnfd") == 0)
+    {
+	   if (occgeometry)
+	     sprintf (buf, "%d", occgeometry->NrFaces());
+	   else
+	     sprintf (buf, "0");
+	   Tcl_SetResult (interp, buf, TCL_STATIC);
+    }
+    return TCL_OK;
+#else // No OCCGEOMETRY 
+
+    Tcl_SetResult (interp, (char *)"Ng_SurfaceMeshSize currently supports only OCC (STEP/IGES) Files", TCL_STATIC);
+    return TCL_ERROR;
+    
+#endif // OCCGEOMETRY
+  }
+
+
+
+  // Philippose - 25/07/2010
+  // TCL interface function for extracting and eventually 
+  // setting or editing the current colours present in the mesh
+  int Ng_CurrentFaceColours (ClientData clientData,
+                             Tcl_Interp * interp,
+                             int argc, tcl_const char *argv[])
+  {
+     if(argc < 1)
+     {
+        Tcl_SetResult (interp, (char *)"Ng_GetCurrentFaceColours needs arguments", TCL_STATIC);
+        return TCL_ERROR;
+     }
+
+     if(!mesh.Ptr())
+     {
+        Tcl_SetResult (interp, (char *)"Ng_GetCurrentFaceColours: Valid netgen mesh required...please mesh the Geometry first", TCL_STATIC);
+	     return TCL_ERROR;
+     }
+
+     if(strcmp(argv[1], "getcolours") == 0)
+     {
+        stringstream outVar;
+        Array<Vec3d> face_colours;
+        GetFaceColours(*mesh, face_colours);
+
+        for(int i = 0; i < face_colours.Size();i++)
+        {
+           outVar << "{ " << face_colours[i].X(1)
+                  << " "  << face_colours[i].X(2)
+                  << " "  << face_colours[i].X(3)
+                  << " } ";
+        }
+
+        tcl_const char * valuevar = argv[2];
+        Tcl_SetVar  (interp, valuevar, (char*)outVar.str().c_str(), 0);
+     }
+
+     if(strcmp(argv[1], "showalso") == 0)
+     {
+        Array<Vec3d> face_colours;
+        GetFaceColours(*mesh,face_colours);
+
+        int colourind = atoi (argv[2]);
+
+        for(int i = 1; i <= mesh->GetNFD(); i++)
+        {
+           Array<SurfaceElementIndex> surfElems;
+           mesh->GetSurfaceElementsOfFace(i,surfElems);
+
+           if(ColourMatch(face_colours[colourind],mesh->GetFaceDescriptor(i).SurfColour()))
+           {
+              for(int j = 0; j < surfElems.Size(); j++)
+              {
+                 mesh->SurfaceElement(surfElems[j]).Visible(1);
+              }
+           }
+        }
+
+        mesh->SetNextTimeStamp();
+     }
+
+     if(strcmp(argv[1], "hidealso") == 0)
+     {
+        Array<Vec3d> face_colours;
+        GetFaceColours(*mesh,face_colours);
+
+        int colourind = atoi (argv[2]);
+
+        for(int i = 1; i <= mesh->GetNFD(); i++)
+        {
+           Array<SurfaceElementIndex> surfElems;
+           mesh->GetSurfaceElementsOfFace(i,surfElems);
+
+           if(ColourMatch(face_colours[colourind],mesh->GetFaceDescriptor(i).SurfColour()))
+           {
+              for(int j = 0; j < surfElems.Size(); j++)
+              {
+                 mesh->SurfaceElement(surfElems[j]).Visible(0);
+              }
+           }
+        }
+
+        mesh->SetNextTimeStamp();
+     }
+
+     if(strcmp(argv[1], "showonly") == 0)
+     {
+        Array<Vec3d> face_colours;
+        GetFaceColours(*mesh,face_colours);
+
+        int colourind = atoi (argv[2]);
+
+        for(int i = 1; i <= mesh->GetNFD(); i++)
+        {
+           Array<SurfaceElementIndex> surfElems;
+           mesh->GetSurfaceElementsOfFace(i,surfElems);
+
+           if(ColourMatch(face_colours[colourind],mesh->GetFaceDescriptor(i).SurfColour()))
+           {
+              for(int j = 0; j < surfElems.Size(); j++)
+              {
+                 mesh->SurfaceElement(surfElems[j]).Visible(1);
+              }
+           }
+           else
+           {
+              for(int j = 0; j < surfElems.Size(); j++)
+              {
+                 mesh->SurfaceElement(surfElems[j]).Visible(0);
+              }
+           }
+        }
+
+        mesh->SetNextTimeStamp();
+     }
+
+     if(strcmp(argv[1], "hideonly") == 0)
+     {
+        Array<Vec3d> face_colours;
+        GetFaceColours(*mesh,face_colours);
+
+        int colourind = atoi (argv[2]);
+
+        for(int i = 1; i <= mesh->GetNFD(); i++)
+        {
+           Array<SurfaceElementIndex> surfElems;
+           mesh->GetSurfaceElementsOfFace(i,surfElems);
+
+           if(ColourMatch(face_colours[colourind],mesh->GetFaceDescriptor(i).SurfColour()))
+           {
+              for(int j = 0; j < surfElems.Size(); j++)
+              {
+                 mesh->SurfaceElement(surfElems[j]).Visible(0);
+              }
+           }
+           else
+           {
+              for(int j = 0; j < surfElems.Size(); j++)
+              {
+                 mesh->SurfaceElement(surfElems[j]).Visible(1);
+              }
+           }
+        }
+
+        mesh->SetNextTimeStamp();
+     }
+
+     if(strcmp(argv[1], "showall") == 0)
+     {
+        for(int i = 1; i <= mesh->GetNSE(); i++)
+        {
+           mesh->SurfaceElement(i).Visible(1);
+        }
+
+        mesh->SetNextTimeStamp();
+     }
+
+     if(strcmp(argv[1], "hideall") == 0)
+     {
+        for(int i = 1; i <= mesh->GetNSE(); i++)
+        {
+           mesh->SurfaceElement(i).Visible(0);
+        }
+
+        mesh->SetNextTimeStamp();
+     }
+
+     return TCL_OK;
+  }
+
+
+
+
+  // Philippose - 10/03/2009
+  // TCL interface function for the Automatic Colour-based
+  // definition of boundary conditions for OCC Geometry
+  int Ng_AutoColourBcProps (ClientData clientData,
+		                      Tcl_Interp * interp,
+		                      int argc, tcl_const char *argv[])
+  {
+     if(argc < 1)
+     {
+        Tcl_SetResult (interp, (char *)"Ng_AutoColourBcProps needs arguments", TCL_STATIC);
+        return TCL_ERROR;
+     }
+
+     if(!mesh.Ptr())
+     {
+        Tcl_SetResult (interp, (char *)"Ng_AutoColourBcProps: Valid netgen mesh required...please mesh the Geometry first", TCL_STATIC);
+	     return TCL_ERROR;
+     }
+
+     if(strcmp(argv[1], "auto") == 0)
+     {
+        AutoColourBcProps(*mesh, 0);
+     }
+
+     if(strcmp(argv[1], "profile") == 0)
+     {
+        AutoColourBcProps(*mesh, argv[2]);
+     }
+
+     return TCL_OK;
+  }
+
+
+  int Ng_SetOCCParameters  (ClientData clientData,
+			    Tcl_Interp * interp,
+			    int argc, tcl_const char *argv[])
+  {
+    OCCGeometryRegister reg;
+    reg.SetParameters (interp);
+    /*
+    occparam.resthcloseedgefac =
+      atof (Tcl_GetVar (interp, "::stloptions.resthcloseedgefac", 0));
+
+    occparam.resthcloseedgeenable =
+      atoi (Tcl_GetVar (interp, "::stloptions.resthcloseedgeenable", 0));
+    */
+    return TCL_OK;
+  }
+
+
+
+
+  NetgenGeometry *  OCCGeometryRegister :: Load (string filename) const
+  {
+    const char * lgfilename = filename.c_str();
+
+
+    /*
+    if (strcmp (&cfilename[strlen(cfilename)-3], "geo") == 0)
+      {
+	PrintMessage (1, "Load OCCG geometry file ", cfilename);
+	
+	extern OCCGeometry * ParseOCCG (istream & istr);
+
+	ifstream infile(cfilename);
+
+	OCCGeometry * hgeom = ParseOCCG (infile);
+	if (!hgeom)
+	  throw NgException ("geo-file should start with 'algebraic3d'");
+
+	hgeom -> FindIdenticSurfaces(1e-8 * hgeom->MaxSize()); 
+	return hgeom;
+      }
+    */
+
+
+    if ((strcmp (&lgfilename[strlen(lgfilename)-4], "iges") == 0) ||
+	(strcmp (&lgfilename[strlen(lgfilename)-3], "igs") == 0) ||
+	(strcmp (&lgfilename[strlen(lgfilename)-3], "IGS") == 0) ||
+	(strcmp (&lgfilename[strlen(lgfilename)-4], "IGES") == 0))
+      {
+	PrintMessage (1, "Load IGES geometry file ", lgfilename);
+	OCCGeometry * occgeometry = LoadOCC_IGES (lgfilename);
+	return occgeometry;
+      }
+
+    else if ((strcmp (&lgfilename[strlen(lgfilename)-4], "step") == 0) ||
+		     (strcmp (&lgfilename[strlen(lgfilename)-3], "stp") == 0) ||
+		     (strcmp (&lgfilename[strlen(lgfilename)-3], "STP") == 0) ||
+		     (strcmp (&lgfilename[strlen(lgfilename)-4], "STEP") == 0))
+      {
+	PrintMessage (1, "Load STEP geometry file ", lgfilename);
+	OCCGeometry * occgeometry = LoadOCC_STEP (lgfilename);
+	return occgeometry;    
+      }
+    else if ((strcmp (&lgfilename[strlen(lgfilename)-4], "brep") == 0) ||
+	     (strcmp (&lgfilename[strlen(lgfilename)-4], "Brep") == 0) ||
+	     (strcmp (&lgfilename[strlen(lgfilename)-4], "BREP") == 0))
+      {
+	PrintMessage (1, "Load BREP geometry file ", lgfilename);
+	OCCGeometry * occgeometry = LoadOCC_BREP (lgfilename);
+	return occgeometry;
+      }
+    
+    return NULL;
+  }
+
+
+  static VisualSceneOCCGeometry vsoccgeom;
+
+  VisualScene * OCCGeometryRegister :: GetVisualScene (const NetgenGeometry * geom) const
+  {
+    OCCGeometry * geometry = dynamic_cast<OCCGeometry*> (ng_geometry);
+    if (geometry)
+      {
+	vsoccgeom.SetGeometry (geometry);
+	return &vsoccgeom;
+      }
+    return NULL;
+  }
+
+
+
+}
+
+
+
+using namespace netgen;
+
+int Ng_occ_Init (Tcl_Interp * interp)
+{
+  geometryregister.Append (new OCCGeometryRegister);
+
+
+    Tcl_CreateCommand (interp, "Ng_SetOCCVisParameters",
+		       Ng_SetOCCVisParameters,
+		       (ClientData)NULL,
+		       (Tcl_CmdDeleteProc*) NULL);
+
+    Tcl_CreateCommand (interp, "Ng_GetOCCData",
+		       Ng_GetOCCData,
+		       (ClientData)NULL,
+		       (Tcl_CmdDeleteProc*) NULL);
+
+    /*
+#ifdef OCCGEOMETRY
+    Tcl_CreateCommand (interp, "Ng_OCCConstruction",
+		       Ng_OCCConstruction,
+		       (ClientData)NULL,
+		       (Tcl_CmdDeleteProc*) NULL);
+#endif
+    */
+
+    Tcl_CreateCommand (interp, "Ng_OCCCommand",
+		       Ng_OCCCommand,
+		       (ClientData)NULL,
+		       (Tcl_CmdDeleteProc*) NULL);
+
+
+    Tcl_CreateCommand (interp, "Ng_SetOCCParameters", Ng_SetOCCParameters,
+		       (ClientData)NULL,
+		       (Tcl_CmdDeleteProc*) NULL);
+
+
+
+    // Philippose - 30/01/2009
+    // Register the TCL Interface Command for local face mesh size
+    // definition
+    Tcl_CreateCommand (interp, "Ng_SurfaceMeshSize", Ng_SurfaceMeshSize,
+		       (ClientData)NULL,
+		       (Tcl_CmdDeleteProc*) NULL);
+
+    Tcl_CreateCommand (interp, "Ng_AutoColourBcProps", Ng_AutoColourBcProps,
+		       (ClientData)NULL,
+		       (Tcl_CmdDeleteProc*) NULL);
+
+    // Philippose - 25/07/2010
+    // Register the TCL Interface Command for handling the face colours 
+    // present in the mesh
+    Tcl_CreateCommand(interp, "Ng_CurrentFaceColours", Ng_CurrentFaceColours,
+                      (ClientData)NULL,
+                      (Tcl_CmdDeleteProc*) NULL);
+
+
+  return TCL_OK;
+}
+
+#endif
+
diff --git a/contrib/Netgen/libsrc/occ/utilities.h b/contrib/Netgen/libsrc/occ/utilities.h
new file mode 100644
index 0000000000..8cb9e3055e
--- /dev/null
+++ b/contrib/Netgen/libsrc/occ/utilities.h
@@ -0,0 +1,112 @@
+//  SALOME Utils : general SALOME's definitions and tools
+//
+//  Copyright (C) 2003  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
+//  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS 
+// 
+//  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. 
+// 
+//  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 
+// 
+//  See http://www.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org 
+//
+//
+//
+//  File   : utilities.h
+//  Author : Antoine YESSAYAN, Paul RASCLE, EDF
+//  Module : SALOME
+//  $Header: /cvs/netgen/netgen/libsrc/occ/utilities.h,v 1.3 2008/03/31 14:20:28 wabro Exp $
+
+/* ---  Definition macros file to print informations if _DEBUG_ is defined --- */
+
+#ifndef UTILITIES_H
+#define UTILITIES_H
+
+#include <string>
+#include <iostream>
+#include <cstdlib>
+// #include "SALOME_Log.hxx"
+
+/* ---  INFOS is always defined (without _DEBUG_): to be used for warnings, with release version --- */
+
+#define INFOS(msg)    {SLog->putMessage(*SLog<<__FILE__<<" ["<<__LINE__<<"] : "<<msg<<endl);}
+#define PYSCRIPT(msg) {SLog->putMessage(*SLog<<"---PYSCRIPT--- "<<msg<<endl);}
+
+/* --- To print date and time of compilation of current source --- */
+
+#if defined ( __GNUC__ )
+#define COMPILER		"g++" 
+#elif defined ( __sun )
+#define COMPILER		"CC" 
+#elif defined ( __KCC )
+#define COMPILER		"KCC" 
+#elif defined ( __PGI )
+#define COMPILER		"pgCC" 
+#elif defined ( __alpha )
+#define COMPILER		"cxx" 
+#else
+#define COMPILER		"undefined" 
+#endif
+
+#ifdef INFOS_COMPILATION
+#error INFOS_COMPILATION already defined
+#endif
+
+#define INFOS_COMPILATION { \
+			   SLog->putMessage(\
+					   *SLog<<__FILE__<<" ["<< __LINE__<<"] : "\
+					   << "COMPILED with " << COMPILER \
+					   << ", " << __DATE__ \
+					   << " at " << __TIME__ <<endl); }
+
+#ifdef _DEBUG_
+
+/* --- the following MACROS are useful at debug time --- */
+
+#define MYTRACE *SLog << "- Trace " << __FILE__ << " [" << __LINE__ << "] : " 
+
+#define MESSAGE(msg) {SLog->putMessage( MYTRACE <<msg<<endl<<ends); }
+#define SCRUTE(var)  {SLog->putMessage( MYTRACE << #var << "=" << var <<endl<<ends); }
+
+#define REPERE *SLog << "   --------------" << endl 
+#define BEGIN_OF(msg) {REPERE;MYTRACE<<"Begin of: "     <<msg<<endl;REPERE;} 
+#define END_OF(msg)   {REPERE;MYTRACE<<"Normal end of: "<<msg<<endl;REPERE;} 
+
+#define HERE {cout<<flush ;cerr<<"- Trace "<<__FILE__<<" ["<<__LINE__<<"] : "<<flush ;}
+
+#define INTERRUPTION(code) {HERE;cerr<<"INTERRUPTION return code= "<<code<< endl;std::exit(code);}
+
+#ifndef ASSERT
+#define ASSERT(condition) \
+        if (!(condition)){HERE;cerr<<"CONDITION "<<#condition<<" NOT VERIFIED"<<endl;INTERRUPTION(1);}
+#endif /* ASSERT */
+
+
+#else /* ifdef _DEBUG_*/
+
+#define HERE 
+#define SCRUTE(var) {}
+#define MESSAGE(msg) {}
+#define REPERE
+#define BEGIN_OF(msg) {}
+#define END_OF(msg) {}
+
+#define INTERRUPTION(code) {}
+
+#ifndef ASSERT
+#define ASSERT(condition) {}
+#endif /* ASSERT */
+
+
+#endif /* ifdef _DEBUG_*/
+
+#endif /* ifndef UTILITIES_H */
diff --git a/contrib/Netgen/libsrc/occ/vsocc.cpp b/contrib/Netgen/libsrc/occ/vsocc.cpp
new file mode 100644
index 0000000000..64a07dffc6
--- /dev/null
+++ b/contrib/Netgen/libsrc/occ/vsocc.cpp
@@ -0,0 +1,764 @@
+#ifndef NOTCL
+
+#ifdef OCCGEOMETRY
+
+#include <mystdlib.h>
+#include <myadt.hpp>
+#include <meshing.hpp>
+
+#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 "Poly_Polygon3D.hxx"
+#include "Poly_PolygonOnTriangulation.hxx"
+
+#include <visual.hpp>
+
+#include "vsocc.hpp"
+
+namespace netgen
+{
+  // extern OCCGeometry * occgeometry;
+
+   /* *********************** Draw OCC Geometry **************** */
+
+   VisualSceneOCCGeometry :: VisualSceneOCCGeometry ()
+   : VisualScene()
+   {
+      trilists.SetSize(0);
+      linelists.SetSize(1);
+
+   }
+
+   VisualSceneOCCGeometry :: ~VisualSceneOCCGeometry ()
+   {
+      ;
+   }
+
+   void VisualSceneOCCGeometry :: DrawScene ()
+   {
+      if ( occgeometry->changed )
+      {
+         BuildScene();
+         occgeometry -> changed = 0;
+      }
+
+      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);
+      
+      //  glEnable (GL_LIGHTING);
+
+      double shine = vispar.shininess;
+      // double transp = vispar.transp;
+
+      glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, shine);
+      glLogicOp (GL_COPY);
+
+      glEnable (GL_NORMALIZE);
+
+      float mat_col[] = {  0.2f, 0.2f, 0.8f, 1.0f};
+      glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_col);
+
+      glPolygonOffset (1, 1);
+      glEnable (GL_POLYGON_OFFSET_FILL);
+
+      // Philippose - 30/01/2009
+      // Added clipping planes to Geometry view
+      SetClippingPlane();
+
+      GLfloat matcoledge[] = {  0, 0, 1, 1};
+      GLfloat matcolhiedge[] = {  1, 0, 0, 1};
+
+      glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, matcoledge);
+      glLineWidth (1.0f);
+
+      if (vispar.occshowedges) glCallList (linelists.Get(1));
+      if (vispar.occshowsurfaces) glCallList (trilists.Get(1));
+
+      glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, matcolhiedge);
+      glLineWidth (5.0f);
+
+      if (vispar.occshowedges) glCallList (linelists.Get(2));
+
+      for (int i = 1; i <= occgeometry->vmap.Extent(); i++)
+      if (occgeometry->vvispar[i-1].IsHighlighted())
+      {
+         glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, matcolhiedge);
+         glLineWidth (5.0f);
+
+         glBegin (GL_LINES);
+
+         gp_Pnt p = BRep_Tool::Pnt(TopoDS::Vertex(occgeometry->vmap(i)));
+         double d = rad/100;
+         glVertex3f (p.X()-d, p.Y(), p.Z());
+         glVertex3f (p.X()+d, p.Y(), p.Z());
+         glVertex3f (p.X(), p.Y()-d, p.Z());
+         glVertex3f (p.X(), p.Y()+d, p.Z());
+         glVertex3f (p.X(), p.Y(), p.Z()-d);
+         glVertex3f (p.X(), p.Y(), p.Z()+d);
+         glEnd();
+      }
+
+      glDisable (GL_POLYGON_OFFSET_FILL);
+
+      glPopMatrix();
+      //  DrawCoordinateCross ();
+      //  DrawNetgenLogo ();
+      glFinish();
+
+      glDisable (GL_POLYGON_OFFSET_FILL);
+   }
+
+   /*
+    void VisualSceneOCCGeometry :: BuildScene (int zoomall)
+    {
+    int i = 0, j, k;
+
+    TopExp_Explorer ex, ex_edge;
+
+    if (vispar.occvisproblemfaces || (occgeometry -> changed != 2))
+    {
+    Box<3> bb = occgeometry -> GetBoundingBox();
+
+    center = bb.Center();
+    rad = bb.Diam() / 2;
+
+
+
+    if (vispar.occvisproblemfaces)
+    {
+    for (i = 1; i <= occgeometry->fmap.Extent(); i++)
+    if (occgeometry->facemeshstatus[i-1] == -1)
+    {
+    GProp_GProps system;
+    BRepGProp::LinearProperties(occgeometry->fmap(i), system);
+    gp_Pnt pnt = system.CentreOfMass();
+    center = Point<3> (pnt.X(), pnt.Y(), pnt.Z());
+    cout << "Setting center to mid of face " << i << " = " << center << endl;
+    }
+    }
+
+
+    CalcTransformationMatrices();
+    }
+
+
+    for (i = 1; i <= linelists.Size(); i++)
+    glDeleteLists (linelists.Elem(i), 1);
+    linelists.SetSize(0);
+
+    linelists.Append (glGenLists (1));
+    glNewList (linelists.Last(), GL_COMPILE);
+
+    i = 0;
+    for (ex_edge.Init(occgeometry -> shape, TopAbs_EDGE);
+    ex_edge.More(); ex_edge.Next())
+    {
+    if (BRep_Tool::Degenerated(TopoDS::Edge(ex_edge.Current()))) continue;
+    i++;
+
+
+    TopoDS_Edge edge = TopoDS::Edge(ex_edge.Current());
+
+    Handle(Poly_PolygonOnTriangulation) aEdgePoly;
+    Handle(Poly_Triangulation) T;
+    TopLoc_Location aEdgeLoc;
+    BRep_Tool::PolygonOnTriangulation(edge, aEdgePoly, T, aEdgeLoc);
+
+    if(aEdgePoly.IsNull())
+    {
+    cout << "cannot visualize edge " << i << endl;
+    continue;
+    }
+
+    glBegin (GL_LINE_STRIP);
+
+    int nbnodes = aEdgePoly -> NbNodes();
+    for (j = 1; j <= nbnodes; j++)
+    {
+    gp_Pnt p = (T -> Nodes())(aEdgePoly->Nodes()(j)).Transformed(aEdgeLoc);
+    glVertex3f (p.X(), p.Y(), p.Z());
+    }
+
+    glEnd ();
+
+
+    }
+
+    glEndList ();
+
+    for (i = 1; i <= trilists.Size(); i++)
+    glDeleteLists (trilists.Elem(i), 1);
+    trilists.SetSize(0);
+
+
+    trilists.Append (glGenLists (1));
+    glNewList (trilists.Last(), GL_COMPILE);
+
+    i = 0;
+
+    TopExp_Explorer exp0, exp1, exp2, exp3;
+    int shapenr = 0;
+    for (exp0.Init(occgeometry -> shape, TopAbs_SOLID); exp0.More(); exp0.Next())
+    {
+    shapenr++;
+
+    if (vispar.occshowvolumenr != 0 &&
+    vispar.occshowvolumenr != shapenr) continue;
+
+    float mat_col[4];
+    mat_col[3] = 1;
+    switch (shapenr)
+    {
+    case 1:
+    mat_col[0] = 0.2;
+    mat_col[1] = 0.2;
+    mat_col[2] = 0.8;
+    break;
+    case 2:
+    mat_col[0] = 0.8;
+    mat_col[1] = 0.2;
+    mat_col[2] = 0.8;
+    break;
+    case 3:
+    mat_col[0] = 0.2;
+    mat_col[1] = 0.8;
+    mat_col[2] = 0.8;
+    break;
+    case 4:
+    mat_col[0] = 0.8;
+    mat_col[1] = 0.2;
+    mat_col[2] = 0.2;
+    break;
+    case 5:
+    mat_col[0] = 0.8;
+    mat_col[1] = 0.8;
+    mat_col[2] = 0.8;
+    break;
+    case 6:
+    mat_col[0] = 0.6;
+    mat_col[1] = 0.6;
+    mat_col[2] = 0.6;
+    break;
+    case 7:
+    mat_col[0] = 0.2;
+    mat_col[1] = 0.8;
+    mat_col[2] = 0.2;
+    break;
+    case 8:
+    mat_col[0] = 0.8;
+    mat_col[1] = 0.8;
+    mat_col[2] = 0.2;
+    break;
+    default:
+    //	  mat_col[0] = 1-(1.0/double(shapenr));
+    //	  mat_col[1] = 0.5;
+    mat_col[0] = 0.5+double((shapenr*shapenr*shapenr*shapenr) % 10)/20.0;
+    mat_col[1] = 0.5+double(int(shapenr*shapenr*shapenr*shapenr*sin(double(shapenr))) % 10)/20.0;
+    mat_col[2] = 0.5+double((shapenr*shapenr*shapenr) % 10)/20.0;
+    }
+
+    glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_col);
+
+    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()));
+
+    i = occgeometry->fmap.FindIndex(face);
+
+    TopLoc_Location loc;
+    Handle(Geom_Surface) surf = BRep_Tool::Surface (face);
+    BRepAdaptor_Surface sf(face, Standard_False);
+    BRepLProp_SLProps prop(sf, 1, 1e-5);
+    Handle(Poly_Triangulation) triangulation = BRep_Tool::Triangulation (face, loc);
+
+    if (triangulation.IsNull())
+    {
+    cout << "cannot visualize face " << i << endl;
+    continue;
+    }
+
+    if (vispar.occvisproblemfaces)
+    {
+    switch (occgeometry->facemeshstatus[i-1])
+    {
+    case 0:
+    mat_col[0] = 0.2;
+    mat_col[1] = 0.2;
+    mat_col[2] = 0.8;
+    break;
+    case 1:
+    mat_col[0] = 0.2;
+    mat_col[1] = 0.8;
+    mat_col[2] = 0.2;
+    break;
+    case -1:
+    mat_col[0] = 0.8;
+    mat_col[1] = 0.2;
+    mat_col[2] = 0.2;
+    break;
+    }
+    glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_col);
+
+    }
+    glBegin (GL_TRIANGLES);
+
+    int ntriangles = triangulation -> NbTriangles();
+    for (j = 1; j <= ntriangles; j++)
+    {
+    Poly_Triangle triangle = (triangulation -> Triangles())(j);
+    for (k = 1; k <= 3; k++)
+    {
+    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);
+
+    if (face.Orientation() == TopAbs_REVERSED) n *= -1;
+    glNormal3f (n.X(), n.Y(), n.Z());
+    glVertex3f (pnt.X(), pnt.Y(), pnt.Z());
+    }
+    }
+    glEnd ();
+
+    }
+    }
+
+
+    glEndList ();
+
+    }
+    */
+
+   void VisualSceneOCCGeometry :: BuildScene (int zoomall)
+   {
+     if (occgeometry -> changed == OCCGEOMETRYVISUALIZATIONFULLCHANGE)
+       {
+         occgeometry -> BuildVisualizationMesh (vispar.occdeflection);
+
+         center = occgeometry -> Center();
+         rad = occgeometry -> GetBoundingBox().Diam() / 2;
+
+         if (vispar.occzoomtohighlightedentity)
+         {
+            bool hilite = false;
+            bool hiliteonepoint = false;
+            Bnd_Box bb;
+
+            for (int i = 1; i <= occgeometry->fmap.Extent(); i++)
+            if (occgeometry->fvispar[i-1].IsHighlighted())
+            {
+               hilite = true;
+               BRepBndLib::Add (occgeometry->fmap(i), bb);
+            }
+
+            for (int i = 1; i <= occgeometry->emap.Extent(); i++)
+            if (occgeometry->evispar[i-1].IsHighlighted())
+            {
+               hilite = true;
+               BRepBndLib::Add (occgeometry->emap(i), bb);
+            }
+
+            for (int i = 1; i <= occgeometry->vmap.Extent(); i++)
+            if (occgeometry->vvispar[i-1].IsHighlighted())
+            {
+               hiliteonepoint = true;
+               BRepBndLib::Add (occgeometry->vmap(i), bb);
+            }
+
+            if (hilite || hiliteonepoint)
+            {
+               double x1,y1,z1,x2,y2,z2;
+               bb.Get (x1,y1,z1,x2,y2,z2);
+               Point<3> p1 = Point<3> (x1,y1,z1);
+               Point<3> p2 = Point<3> (x2,y2,z2);
+               Box<3> boundingbox(p1,p2);
+
+               center = boundingbox.Center();
+               if (hiliteonepoint)
+               rad = occgeometry -> GetBoundingBox().Diam() / 100;
+               else
+               rad = boundingbox.Diam() / 2;
+            }
+         }
+
+         CalcTransformationMatrices();
+      }
+
+      // Clear lists
+
+      for (int i = 1; i <= linelists.Size(); i++)
+      glDeleteLists (linelists.Elem(i), 1);
+      linelists.SetSize(0);
+
+      for (int i = 1; i <= trilists.Size(); i++)
+      glDeleteLists (trilists.Elem(i), 1);
+      trilists.SetSize(0);
+
+      // Total wireframe
+
+      linelists.Append (glGenLists (1));
+      glNewList (linelists.Last(), GL_COMPILE);
+
+      for (int i = 1; i <= occgeometry->emap.Extent(); i++)
+      {
+         TopoDS_Edge edge = TopoDS::Edge(occgeometry->emap(i));
+         if (BRep_Tool::Degenerated(edge)) continue;
+         if (occgeometry->evispar[i-1].IsHighlighted()) continue;
+
+         Handle(Poly_PolygonOnTriangulation) aEdgePoly;
+         Handle(Poly_Triangulation) T;
+         TopLoc_Location aEdgeLoc;
+         BRep_Tool::PolygonOnTriangulation(edge, aEdgePoly, T, aEdgeLoc);
+
+         if(aEdgePoly.IsNull())
+         {
+            (*testout) << "visualizing edge " << occgeometry->emap.FindIndex (edge)
+            << " without using the occ visualization triangulation" << endl;
+
+            double s0, s1;
+            Handle(Geom_Curve) c = BRep_Tool::Curve(edge, s0, s1);
+
+            glBegin (GL_LINE_STRIP);
+            for (int i = 0; i<=50; i++)
+            {
+               gp_Pnt p = c->Value (s0 + i*(s1-s0)/50.0);
+               glVertex3f (p.X(),p.Y(),p.Z());
+            }
+            glEnd ();
+
+            continue;
+         }
+
+         int nbnodes = aEdgePoly -> NbNodes();
+         glBegin (GL_LINE_STRIP);
+         for (int j = 1; j <= nbnodes; j++)
+         {
+            gp_Pnt p = (T -> Nodes())(aEdgePoly->Nodes()(j)).Transformed(aEdgeLoc);
+            glVertex3f (p.X(), p.Y(), p.Z());
+         }
+         glEnd ();
+      }
+
+      glEndList ();
+
+      // Highlighted edge list
+
+      linelists.Append (glGenLists (1));
+      glNewList (linelists.Last(), GL_COMPILE);
+
+      for (int i = 1; i <= occgeometry->emap.Extent(); i++)
+      if (occgeometry->evispar[i-1].IsHighlighted())
+      {
+         TopoDS_Edge edge = TopoDS::Edge(occgeometry->emap(i));
+         if (BRep_Tool::Degenerated(edge)) continue;
+
+         Handle(Poly_PolygonOnTriangulation) aEdgePoly;
+         Handle(Poly_Triangulation) T;
+         TopLoc_Location aEdgeLoc;
+         BRep_Tool::PolygonOnTriangulation(edge, aEdgePoly, T, aEdgeLoc);
+
+         if(aEdgePoly.IsNull())
+         {
+            (*testout) << "visualizing edge " << occgeometry->emap.FindIndex (edge)
+            << " without using the occ visualization triangulation" << endl;
+
+            double s0, s1;
+            Handle(Geom_Curve) c = BRep_Tool::Curve(edge, s0, s1);
+
+            glBegin (GL_LINE_STRIP);
+            for (int i = 0; i<=50; i++)
+            {
+               gp_Pnt p = c->Value (s0 + i*(s1-s0)/50.0);
+               glVertex3f (p.X(),p.Y(),p.Z());
+            }
+            glEnd ();
+
+            continue;
+         }
+
+         int nbnodes = aEdgePoly -> NbNodes();
+         glBegin (GL_LINE_STRIP);
+         for (int j = 1; j <= nbnodes; j++)
+         {
+            gp_Pnt p = (T -> Nodes())(aEdgePoly->Nodes()(j)).Transformed(aEdgeLoc);
+            glVertex3f (p.X(), p.Y(), p.Z());
+         }
+         glEnd ();
+      }
+
+      glEndList ();
+
+      // display faces
+
+      trilists.Append (glGenLists (1));
+      glNewList (trilists.Last(), GL_COMPILE);
+
+      for (int i = 1; i <= occgeometry->fmap.Extent(); i++)
+      {
+         if (!occgeometry->fvispar[i-1].IsVisible()) continue;
+
+         glLoadName (i);
+         float mat_col[4];
+         mat_col[3] = 1;
+
+         TopoDS_Face face = TopoDS::Face(occgeometry->fmap(i));
+
+         if (!occgeometry->fvispar[i-1].IsHighlighted())
+         {
+            // Philippose - 30/01/2009
+            // OpenCascade XDE Support
+            Quantity_Color face_colour;
+            // Philippose - 23/02/2009
+            // Check to see if colours have been extracted first!!
+            // Forum bug-fox (Jean-Yves - 23/02/2009)
+            if(!(occgeometry->face_colours.IsNull())
+               && (occgeometry->face_colours->GetColor(face,XCAFDoc_ColorSurf,face_colour)))
+            {
+               mat_col[0] = face_colour.Red();
+               mat_col[1] = face_colour.Green();
+               mat_col[2] = face_colour.Blue();
+            }
+            else
+            {
+               mat_col[0] = 0.0;
+               mat_col[1] = 1.0;
+               mat_col[2] = 0.0;
+            }
+         }
+         else
+         {
+            mat_col[0] = 0.8;
+            mat_col[1] = 0.2;
+            mat_col[2] = 0.2;
+         }
+
+         glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_col);
+
+         TopLoc_Location loc;
+         Handle(Geom_Surface) surf = BRep_Tool::Surface (face);
+         BRepAdaptor_Surface sf(face, Standard_False);
+         BRepLProp_SLProps prop(sf, 1, 1e-5);
+         Handle(Poly_Triangulation) triangulation = BRep_Tool::Triangulation (face, loc);
+
+         if (triangulation.IsNull())
+         {
+            cout << "cannot visualize face " << i << endl;
+            occgeometry->fvispar[i-1].SetNotDrawable();
+            continue;
+         }
+
+         gp_Pnt2d uv;
+         gp_Pnt pnt;
+         gp_Vec n;
+
+         glBegin (GL_TRIANGLES);
+
+         int ntriangles = triangulation -> NbTriangles();
+         for (int j = 1; j <= ntriangles; j++)
+         {
+            Poly_Triangle triangle = (triangulation -> Triangles())(j);
+            gp_Pnt p[3];
+            for (int k = 1; k <= 3; k++)
+            p[k-1] = (triangulation -> Nodes())(triangle(k)).Transformed(loc);
+
+            for (int k = 1; k <= 3; k++)
+            {
+               uv = (triangulation -> UVNodes())(triangle(k));
+               prop.SetParameters (uv.X(), uv.Y());
+
+               //	      surf->D0 (uv.X(), uv.Y(), pnt);
+
+               if (prop.IsNormalDefined())
+               n = prop.Normal();
+               else
+               {
+                  (*testout) << "Visualization of face " << i
+                  << ": Normal vector not defined" << endl;
+                  //		  n = gp_Vec (0,0,0);
+                  gp_Vec a(p[0],p[1]);
+                  gp_Vec b(p[0],p[2]);
+                  n = b^a;
+               }
+
+               if (face.Orientation() == TopAbs_REVERSED) n *= -1;
+               glNormal3f (n.X(), n.Y(), n.Z());
+               glVertex3f (p[k-1].X(), p[k-1].Y(), p[k-1].Z());
+            }
+         }
+         glEnd ();
+
+      }
+      glEndList ();
+
+   }
+
+   void SelectFaceInOCCDialogTree (int facenr);
+
+   void VisualSceneOCCGeometry :: MouseDblClick (int px, int py)
+   {
+      int 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);
+
+      glDisable(GL_CLIP_PLANE0);
+
+      // Philippose - 30/01/2009
+      // Enable clipping planes for Selection mode in OCC Geometry
+      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 ();
+      }
+
+      glCallList (trilists.Get(1));
+
+      glDisable (GL_POLYGON_OFFSET_FILL);
+
+      glPopName();
+
+      glMatrixMode (GL_PROJECTION);
+      glPopMatrix();
+
+      glMatrixMode (GL_MODELVIEW);
+      glPopMatrix();
+
+      glFlush();
+
+      hits = glRenderMode (GL_RENDER);
+
+      int minname = 0;
+      GLuint mindepth = 0;
+
+      // find clippingplane
+      GLuint clipdepth = 0; // GLuint(-1);
+
+      for (int i = 0; i < hits; i++)
+      {
+         int curname = selbuf[4*i+3];
+         if (!curname) clipdepth = selbuf[4*i+1];
+      }
+
+      for (int i = 0; i < hits; i++)
+      {
+         int curname = selbuf[4*i+3];
+         GLuint curdepth = selbuf[4*i+1];
+         if (curname && (curdepth> clipdepth) &&
+               (curdepth < mindepth || !minname))
+         {
+            mindepth = curdepth;
+            minname = curname;
+         }
+      }
+
+      occgeometry->LowLightAll();
+
+      if (minname)
+      {
+         occgeometry->fvispar[minname-1].Highlight();
+
+         if (vispar.occzoomtohighlightedentity)
+         occgeometry->changed = OCCGEOMETRYVISUALIZATIONFULLCHANGE;
+         else
+         occgeometry->changed = OCCGEOMETRYVISUALIZATIONHALFCHANGE;
+         cout << "Selected face: " << minname << endl;
+      }
+      else
+      {
+         occgeometry->changed = OCCGEOMETRYVISUALIZATIONHALFCHANGE;
+      }
+
+      glDisable(GL_CLIP_PLANE0);
+
+      SelectFaceInOCCDialogTree (minname);
+
+      // Philippose - 30/01/2009
+      // Set the currently selected face in the array
+      // for local face mesh size definition
+      occgeometry->SetSelectedFace(minname);
+
+      //  selecttimestamp = NextTimeStamp();
+   }
+
+}
+
+#endif
+
+#endif // NOTCL
diff --git a/contrib/Netgen/libsrc/occ/vsocc.hpp b/contrib/Netgen/libsrc/occ/vsocc.hpp
new file mode 100644
index 0000000000..3021fe7c70
--- /dev/null
+++ b/contrib/Netgen/libsrc/occ/vsocc.hpp
@@ -0,0 +1,33 @@
+#ifndef FILE_VSOCC
+#define FILE_VSOCC
+
+/**************************************************************************/
+/* File:   vsocc.hpp                                                      */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   05. Jan. 2011                                                  */
+/**************************************************************************/
+
+namespace netgen
+{
+
+  class VisualSceneOCCGeometry : public VisualScene
+  {
+    Array<int> trilists;
+    Array<int> linelists;
+    int selsurf;
+    class OCCGeometry * occgeometry;
+  public:
+    VisualSceneOCCGeometry ();
+    virtual ~VisualSceneOCCGeometry ();
+    void SetGeometry (class OCCGeometry * ageom) { occgeometry = ageom; }
+
+    virtual void BuildScene (int zoomall = 0);
+    virtual void DrawScene ();
+    virtual void MouseDblClick (int px, int py);
+  };
+
+
+
+}
+
+#endif
diff --git a/contrib/Netgen/libsrc/stlgeom/Makefile.am b/contrib/Netgen/libsrc/stlgeom/Makefile.am
new file mode 100644
index 0000000000..c8ea07aaa5
--- /dev/null
+++ b/contrib/Netgen/libsrc/stlgeom/Makefile.am
@@ -0,0 +1,15 @@
+noinst_HEADERS = meshstlsurface.hpp stlgeom.hpp stlline.hpp \
+stltool.hpp stltopology.hpp vsstl.hpp
+
+AM_CPPFLAGS = -I$(top_srcdir)/libsrc/include $(TCL_INCLUDES)
+METASOURCES = AUTO
+
+lib_LTLIBRARIES = libstl.la libstlvis.la
+
+libstl_la_SOURCES = meshstlsurface.cpp stlgeom.cpp stlgeomchart.cpp \
+	stlgeommesh.cpp stlline.cpp stltool.cpp stltopology.cpp
+
+
+libstlvis_la_SOURCES = stlpkg.cpp vsstl.cpp
+libstlvis_la_LIBADD = libstl.la $(top_builddir)/libsrc/linalg/libla.la 
+
diff --git a/contrib/Netgen/libsrc/stlgeom/meshstlsurface.cpp b/contrib/Netgen/libsrc/stlgeom/meshstlsurface.cpp
new file mode 100644
index 0000000000..fcbb1e021b
--- /dev/null
+++ b/contrib/Netgen/libsrc/stlgeom/meshstlsurface.cpp
@@ -0,0 +1,1133 @@
+#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;
+  double h;
+
+  h = mparam.maxh;
+
+  // mark edge points:
+  //int ngp = geom.GetNP();
+
+  geom.RestrictLocalH(mesh, h);
+  
+  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
+  int pim;
+  for (i = 1; i <= meshpoints.Size(); i++)
+    {
+      geom.meshpoints.Append(meshpoints.Get(i)); //testing
+
+      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[0] = p1;
+	  seg[1] = 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[0]);
+	  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[1]);
+	  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[0]), mesh.Point(seg[1])) < 1e-10)
+	    {
+	      (*testout) << "ERROR: Line segment of length 0" << endl;
+	      (*testout) << "pi1, 2 = " << seg[0] << ", " << seg[1] << endl;
+	      (*testout) << "p1, 2 = " << mesh.Point(seg[0])
+			 << ", " << mesh.Point(seg[1]) << endl;
+	      throw NgException ("Line segment of length 0");
+	    }
+	  
+	  mesh.AddSegment (seg);
+
+
+	  Segment seg2;
+	  seg2[0] = p2;
+	  seg2[1] = 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[0]);
+	  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[1]);
+	  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[0]),mesh.Point(seg[1]));
+		    }
+
+		  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, mparam);
+		}
+
+	      mesh.Compress();
+	      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[0], seg[1]);
+		  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[0], seg[1]);
+		  i2.Sort();
+		  if (openseght.Used (i2))
+		    {
+		      // segment will be split
+		      PrintMessage(7,"Split segment ", int(seg[0]), "-", int(seg[1]));
+	      
+		      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[1] = newpi;
+		      nseg1.epgeominfo[1] = newgi;
+		      
+		      nseg2[0] = newpi;
+		      nseg2.epgeominfo[0] = newgi;
+		      
+		      mesh.LineSegment(i) = nseg1;
+		      mesh.AddSegment (nseg2);
+		      
+		      mesh.RestrictLocalH (Center (mesh.Point(nseg1[0]),
+						   mesh.Point(nseg1[1])),
+					   Dist (mesh.Point(nseg1[0]),
+						 mesh.Point(nseg1[1])));
+		      mesh.RestrictLocalH (Center (mesh.Point(nseg2[0]),
+						   mesh.Point(nseg2[1])),
+					   Dist (mesh.Point(nseg2[0]),
+						 mesh.Point(nseg2[1])));
+		    }
+		}
+
+	    }
+
+	  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
+	  if(mesh.CheckOverlappingBoundary())
+	    {
+	      return MESHING3_BADSURFACEMESH;
+	    }
+
+
+	  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;
+  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, mparam);
+	
+	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[0], seg[1], seg.geominfo[0], seg.geominfo[1]);
+	}
+      
+      
+      PrintMessage(3,"start meshing, trialcnt = ", retrynr);
+
+      /*
+      (*testout) << "start meshing with h = " << h << endl;
+      */
+      meshing.GenerateMesh (mesh, mparam, h, fnr);  // face index
+
+      extern void Render();
+      Render();
+    }    
+      
+  
+  mesh.CalcSurfacesOfNode();
+}
+
+
+
+void STLSurfaceOptimization (STLGeometry & geom,
+			     class Mesh & mesh,
+			     MeshingParameters & meshparam)
+{
+  PrintFnStart("optimize STL Surface");
+
+
+  MeshOptimizeSTLSurface optmesh(geom);
+  //
+
+  int i;
+  /*
+  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 (meshparam.elsizeweight);
+
+  PrintMessage(5,"optimize string = ", meshparam.optimize2d, " elsizew = ", meshparam.elsizeweight);
+
+  for (i = 1; i <= meshparam.optsteps2d; i++)
+    for (size_t j = 1; j <= strlen(meshparam.optimize2d); j++)
+      {
+	if (multithread.terminate)
+	  break;
+
+	//(*testout) << "optimize, before, step = " << meshparam.optimize2d[j-1] << mesh.Point (3679) << endl;
+
+	mesh.CalcSurfacesOfNode();
+	switch (meshparam.optimize2d[j-1])
+	  {
+	  case 's': 
+	    {
+	      optmesh.EdgeSwapping (mesh, 0);
+	      break;
+	    }
+	  case 'S': 
+	    {
+	      optmesh.EdgeSwapping (mesh, 1);
+	      break;
+	    }
+	  case 'm': 
+	    {
+	      optmesh.ImproveMesh(mesh, mparam);
+	      break;
+	    }
+	  case 'c': 
+	    {
+	      optmesh.CombineImprove (mesh);
+	      break;
+	    }
+	  }
+	//(*testout) << "optimize, after, step = " << meshparam.optimize2d[j-1] << mesh.Point (3679) << endl;
+      }
+
+  geom.surfaceoptimized = 1;
+
+  mesh.Compress();
+  mesh.CalcSurfacesOfNode();
+
+
+}
+
+
+
+MeshingSTLSurface :: MeshingSTLSurface (STLGeometry & ageom,
+					const MeshingParameters & mp)
+  : Meshing2(mp, ageom.GetBoundingBox()), geom(ageom)
+{
+  ;
+}
+
+void MeshingSTLSurface :: DefineTransformation (const Point3d & p1, const 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 Point<3> & p,
+						     const PointGeomInfo & gi)
+{
+  //  (*testout) << "sel char: " << gi.trignum << endl;
+  
+  geom.SelectChartOfTriangle (gi.trignum);
+  //  geom.SelectChartOfPoint (p);
+}
+
+
+void MeshOptimizeSTLSurface :: ProjectPoint (INDEX surfind, Point<3> & p) const
+{
+  if (!geom.Project (p))
+    {
+      PrintMessage(7,"project failed");
+      
+      if (!geom.ProjectOnWholeSurface(p)) 
+	{
+	  PrintMessage(7, "project on whole surface failed");
+	}
+    }
+
+  //  geometry.GetSurface(surfind)->Project (p);
+}
+
+void MeshOptimizeSTLSurface :: ProjectPoint2 (INDEX surfind, INDEX surfind2, Point<3> & p) const
+{
+  /*
+  ProjectToEdge ( geometry.GetSurface(surfind), 
+		  geometry.GetSurface(surfind2), p);
+  */
+}
+
+int  MeshOptimizeSTLSurface :: CalcPointGeomInfo(PointGeomInfo& gi, const Point<3> & p3) const
+{
+  Point<3> hp = p3;
+  gi.trignum = geom.Project (hp);
+
+  if (gi.trignum)
+    {
+      return 1;
+    }
+
+  return 0;
+  
+}
+
+void MeshOptimizeSTLSurface :: GetNormalVector(INDEX surfind, const Point<3> & p, Vec<3> & 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 Point<3> & p1, const Point<3> & p2, double secpoint,
+	       int surfi, 
+	       const PointGeomInfo & gi1, 
+	       const PointGeomInfo & gi2,
+	       Point<3> & newp, PointGeomInfo & newgi) const
+{
+  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 Point<3> & p1, const Point<3> & p2, double secpoint,
+	      int surfi1, int surfi2, 
+	      const EdgePointGeomInfo & gi1, 
+	      const EdgePointGeomInfo & gi2,
+	      Point<3> & newp, EdgePointGeomInfo & newgi) const
+{
+  /*
+  (*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) const
+{
+  cout << "RefinementSTLGeometry :: ProjectToSurface not implemented!" << endl;
+};
+
+
+void RefinementSTLGeometry :: ProjectToSurface (Point<3> & p, int surfi,
+						PointGeomInfo & gi) const
+{
+  ((STLGeometry&)geom).SelectChartOfTriangle (gi.trignum);
+  gi.trignum = geom.Project (p);
+  //  if (!gi.trignum) 
+  //    cout << "projectSTL failed" << endl;
+};
+
+ 
+}
diff --git a/contrib/Netgen/libsrc/stlgeom/meshstlsurface.hpp b/contrib/Netgen/libsrc/stlgeom/meshstlsurface.hpp
new file mode 100644
index 0000000000..4e678439b4
--- /dev/null
+++ b/contrib/Netgen/libsrc/stlgeom/meshstlsurface.hpp
@@ -0,0 +1,121 @@
+#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, const MeshingParameters & mp);
+
+protected:
+  ///
+  virtual void DefineTransformation (const Point3d & p1, const 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 Point<3> & p,
+				       const PointGeomInfo & gi);
+    ///
+    virtual void ProjectPoint (INDEX surfind, Point<3> & p) const;
+    ///
+    virtual void ProjectPoint2 (INDEX surfind, INDEX surfind2, Point<3> & p) const;
+    ///
+    virtual int CalcPointGeomInfo(PointGeomInfo& gi, const Point<3> & p3) const;
+    ///
+    virtual void GetNormalVector(INDEX surfind, const Point<3> & p, Vec<3> & n) const;
+};
+
+
+
+
+class RefinementSTLGeometry : public Refinement
+{
+  const STLGeometry & geom;
+
+public:
+  RefinementSTLGeometry (const STLGeometry & ageom);
+  virtual ~RefinementSTLGeometry ();
+  
+  virtual void PointBetween (const Point<3> & p1, const Point<3> & p2, double secpoint,
+			     int surfi, 
+			     const PointGeomInfo & gi1, 
+			     const PointGeomInfo & gi2,
+			     Point<3> & newp, PointGeomInfo & newgi) const;
+
+  virtual void PointBetween (const Point<3> & p1, const Point<3> & p2, double secpoint,
+			     int surfi1, int surfi2, 
+			     const EdgePointGeomInfo & ap1, 
+			     const EdgePointGeomInfo & ap2,
+			     Point<3> & newp, EdgePointGeomInfo & newgi) const;
+
+  virtual void ProjectToSurface (Point<3> & p, int surfi) const;
+  virtual void ProjectToSurface (Point<3> & p, int surfi, PointGeomInfo & gi) const;
+};
+
+
+
+#endif
+
diff --git a/contrib/Netgen/libsrc/stlgeom/stlgeom.cpp b/contrib/Netgen/libsrc/stlgeom/stlgeom.cpp
new file mode 100644
index 0000000000..b0cfe87aa5
--- /dev/null
+++ b/contrib/Netgen/libsrc/stlgeom/stlgeom.cpp
@@ -0,0 +1,3506 @@
+#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();
+
+  mesh.ClearFaceDescriptors();
+  for (int 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(), selectedmultiedge()
+  */
+{
+	edgedata = new STLEdgeDataList(*this);
+  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()
+{
+  delete edgedata;
+}
+
+void STLGeometry :: Save (string filename) const
+{
+  const char  * cfilename = filename.c_str();
+  if (strlen(cfilename) < 4) 
+    throw NgException ("illegal filename");
+
+  if (strlen(cfilename) > 3 &&
+      strcmp (&cfilename[strlen(cfilename)-3], "stl") == 0)
+    {
+      STLTopology::Save (cfilename);
+    }
+  else if (strlen(cfilename) > 4 &&
+	   strcmp (&cfilename[strlen(cfilename)-4], "stlb") == 0)
+    {
+      SaveBinary (cfilename,"Binary STL Geometry");
+      
+    }
+  else if (strlen(cfilename) > 4 &&
+	   strcmp (&cfilename[strlen(cfilename)-4], "stle") == 0)
+    {
+      SaveSTLE (cfilename);
+    }
+}
+
+
+
+int STLGeometry :: GenerateMesh (Mesh*& mesh, MeshingParameters & mparam,
+				 int perfstepsstart, int perfstepsend)
+{
+  return STLMeshingDummy (this, mesh, mparam, perfstepsstart, perfstepsend);
+}
+
+
+const Refinement & STLGeometry :: GetRefinement () const
+{
+  return RefinementSTLGeometry (*this);
+}
+
+
+
+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 lp1,lp2;
+  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)), lp1, lp2);
+	      if (!IsEdge(lp1,lp2))
+		{
+		  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(k) = 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(k) = 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(0), sol(1), sol(2));
+      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 ap1, int ap2)
+{
+  STLEdge e(ap1,ap2);
+  e.SetLeftTrig(GetLeftTrig(ap1,ap2));
+  e.SetRightTrig(GetRightTrig(ap1,ap2));
+  return edges.Append(e);
+}
+
+void STLGeometry :: STLDoctorConfirmEdge()
+{
+  StoreEdgeData();
+  if (GetSelectTrig() >= 1 && GetSelectTrig() <= GetNT() && GetNodeOfSelTrig())
+    {
+      if (stldoctor.selectmode == 1)
+	{
+	  int ap1 = GetTriangle(GetSelectTrig()).PNum(GetNodeOfSelTrig());
+	  int ap2 = GetTriangle(GetSelectTrig()).PNumMod(GetNodeOfSelTrig()+1);
+	  edgedata->Elem(edgedata->GetEdgeNum(ap1,ap2)).SetStatus (ED_CONFIRMED);
+	}
+      else if (stldoctor.selectmode == 3 || stldoctor.selectmode == 4)
+	{
+	  int i;
+	  for (i = 1; i <= selectedmultiedge.Size(); i++)
+	    {
+	      int ap1 = selectedmultiedge.Get(i).i1;
+	      int ap2 = selectedmultiedge.Get(i).i2;
+	      edgedata->Elem(edgedata->GetEdgeNum(ap1,ap2)).SetStatus (ED_CONFIRMED);
+	    }
+	}
+    }
+}
+
+void STLGeometry :: STLDoctorCandidateEdge()
+{
+  StoreEdgeData();
+  if (GetSelectTrig() >= 1 && GetSelectTrig() <= GetNT() && GetNodeOfSelTrig())
+    {
+      if (stldoctor.selectmode == 1)
+	{
+	  int ap1 = GetTriangle(GetSelectTrig()).PNum(GetNodeOfSelTrig());
+	  int ap2 = GetTriangle(GetSelectTrig()).PNumMod(GetNodeOfSelTrig()+1);
+	  edgedata->Elem(edgedata->GetEdgeNum(ap1,ap2)).SetStatus (ED_CANDIDATE);
+	}
+      else if (stldoctor.selectmode == 3 || stldoctor.selectmode == 4)
+	{
+	  int i;
+	  for (i = 1; i <= selectedmultiedge.Size(); i++)
+	    {
+	      int ap1 = selectedmultiedge.Get(i).i1;
+	      int ap2 = selectedmultiedge.Get(i).i2;
+	      edgedata->Elem(edgedata->GetEdgeNum(ap1,ap2)).SetStatus (ED_CANDIDATE);
+	    }
+	}
+    }
+}
+
+void STLGeometry :: STLDoctorExcludeEdge()
+{
+  StoreEdgeData();
+  if (GetSelectTrig() >= 1 && GetSelectTrig() <= GetNT() && GetNodeOfSelTrig())
+    {
+      if (stldoctor.selectmode == 1)
+	{
+	  int ap1 = GetTriangle(GetSelectTrig()).PNum(GetNodeOfSelTrig());
+	  int ap2 = GetTriangle(GetSelectTrig()).PNumMod(GetNodeOfSelTrig()+1);
+	  edgedata->Elem(edgedata->GetEdgeNum(ap1,ap2)).SetStatus(ED_EXCLUDED);
+	}
+      else if (stldoctor.selectmode == 3 || stldoctor.selectmode == 4)
+	{
+	  int i;
+	  for (i = 1; i <= selectedmultiedge.Size(); i++)
+	    {
+	      int ap1 = selectedmultiedge.Get(i).i1;
+	      int ap2 = selectedmultiedge.Get(i).i2;
+	      edgedata->Elem(edgedata->GetEdgeNum(ap1,ap2)).SetStatus(ED_EXCLUDED);
+	    }
+	}
+    }
+}
+
+void STLGeometry :: STLDoctorUndefinedEdge()
+{
+  StoreEdgeData();
+  if (GetSelectTrig() >= 1 && GetSelectTrig() <= GetNT() && GetNodeOfSelTrig())
+    {
+      if (stldoctor.selectmode == 1)
+	{
+	  int ap1 = GetTriangle(GetSelectTrig()).PNum(GetNodeOfSelTrig());
+	  int ap2 = GetTriangle(GetSelectTrig()).PNumMod(GetNodeOfSelTrig()+1);
+	  edgedata->Elem(edgedata->GetEdgeNum(ap1,ap2)).SetStatus(ED_UNDEFINED);
+	}
+      else if (stldoctor.selectmode == 3 || stldoctor.selectmode == 4)
+	{
+	  int i;
+	  for (i = 1; i <= selectedmultiedge.Size(); i++)
+	    {
+	      int ap1 = selectedmultiedge.Get(i).i1;
+	      int ap2 = selectedmultiedge.Get(i).i2;
+	      edgedata->Elem(edgedata->GetEdgeNum(ap1,ap2)).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 ptree (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);
+      ptree.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);
+	  
+      ptree.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);
+
+	  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 ptree (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;
+      ptree.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);
+	  
+      ptree.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 ap1 = GetTriangle(GetSelectTrig()).PNum(GetNodeOfSelTrig());
+      int ap2 = GetTriangle(GetSelectTrig()).PNumMod(GetNodeOfSelTrig()+1);
+      if (!IsExternalEdge(ap1,ap2)) {AddExternalEdge(ap1,ap2);}
+    }
+}
+
+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 ap1 = l->PNum(j);
+	      int ap2 = l->PNum(j+1);
+
+	      if (!IsExternalEdge(ap1,ap2)) {AddExternalEdge(ap1,ap2);}	      
+	    }
+	}
+    }
+}
+
+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 ap1 = l->PNum(j);
+	      int ap2 = l->PNum(j+1);
+
+	      if (!IsExternalEdge(ap1,ap2)) {AddExternalEdge(ap1,ap2);}	      
+	    }
+	}
+    }
+}
+
+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 ap1 = l->PNum(j);
+	      int ap2 = l->PNum(j+1);
+
+	      if (!IsExternalEdge(ap1,ap2)) {AddExternalEdge(ap1,ap2);}	      
+	    }
+	}
+    }
+}
+
+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 ap1 = l->PNum(j);
+	      int ap2 = l->PNum(j+1);
+
+	      if (IsExternalEdge(ap1,ap2)) {DeleteExternalEdge(ap1,ap2);}	      
+	    }
+	}
+    }
+}
+
+void STLGeometry :: AddExternalEdgesFromGeomLine()
+{
+  StoreExternalEdges();
+  if (GetSelectTrig() >= 1 && GetSelectTrig() <= GetNT())
+    {
+      int ap1 = GetTriangle(GetSelectTrig()).PNum(GetNodeOfSelTrig());
+      int ap2 = GetTriangle(GetSelectTrig()).PNumMod(GetNodeOfSelTrig()+1);
+
+      if (IsEdge(ap1,ap2))
+	{
+	  int edgenum = IsEdgeNum(ap1,ap2);
+	  if (!IsExternalEdge(ap1,ap2)) {AddExternalEdge(ap1,ap2);}
+	  
+	  int noend = 1;
+	  int startp = ap1;
+	  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 = ap2;
+	  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 ap1 = GetTriangle(GetSelectTrig()).PNum(GetNodeOfSelTrig());
+      int ap2 = GetTriangle(GetSelectTrig()).PNumMod(GetNodeOfSelTrig()+1);
+      if (IsExternalEdge(ap1,ap2)) {DeleteExternalEdge(ap1,ap2);}
+    }
+}
+
+void STLGeometry :: DeleteExternalEdgeInVicinity()
+{
+  StoreExternalEdges();
+  if (!stldoctor.showvicinity || vicinity.Size() != GetNT()) {return;}
+
+  int i, j, ap1, ap2;
+  
+  for (i = 1; i <= GetNT(); i++)
+    {
+      if (vicinity.Elem(i))
+	{
+	  for (j = 1; j <= 3; j++)
+	    {
+	      ap1 = GetTriangle(i).PNum(j);
+	      ap2 = GetTriangle(i).PNumMod(j+1);
+
+	      if (IsExternalEdge(ap1,ap2))
+		{
+		  DeleteExternalEdge(ap1,ap2);
+		}
+	    }
+	}
+    }
+}
+
+void STLGeometry :: BuildExternalEdgesFromEdges()
+{
+  StoreExternalEdges();
+
+  if (GetNE() == 0) {PrintWarning("Edges possibly not generated!");}
+
+  int i;
+  externaledges.SetSize(0);
+
+  for (i = 1; i <= GetNE(); i++)
+    {
+      STLEdge e = GetEdge(i);
+      AddExternalEdge(e.PNum(1), e.PNum(2));
+    }
+
+}
+
+
+void STLGeometry :: AddExternalEdge(int ap1, int ap2)
+{
+  externaledges.Append(twoint(ap1,ap2));
+}
+
+void STLGeometry :: DeleteExternalEdge(int ap1, int ap2)
+{
+
+  int i;
+  int found = 0;
+  for (i = 1; i <= NOExternalEdges(); i++)
+    {
+      if ((GetExternalEdge(i).i1 == ap1 && GetExternalEdge(i).i2 == ap2) ||
+	  (GetExternalEdge(i).i1 == ap2 && GetExternalEdge(i).i2 == ap1)) {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 ap1, int ap2)
+{
+  int i;
+  for (i = 1; i <= NOExternalEdges(); i++)
+    {
+      if ((GetExternalEdge(i).i1 == ap1 && GetExternalEdge(i).i2 == ap2) ||
+	  (GetExternalEdge(i).i1 == ap2 && GetExternalEdge(i).i2 == ap1)) {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& ap1 = GetPoint(tr.PNum(1));
+      const Point3d& ap2 = GetPoint(tr.PNum(2));
+      const Point3d& ap3 = GetPoint(tr.PNum(3));
+
+      Vec3d normal = Cross (ap2-ap1, ap3-ap1);
+      
+      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) 
+    {
+ 
+      Point<3> ap1, ap2;
+      for (i = 1; i <= n; i++)
+	{
+	  fin >> ap1(0); fin >> ap1(1); fin >> ap1(2);
+	  fin >> ap2(0); fin >> ap2(1); fin >> ap2(2);
+	  AddMarkedSeg(ap1,ap2);      
+	}
+    }
+}
+
+void STLGeometry :: SaveMarkedTrigs()
+{
+  PrintFnStart("save marked trigs to file 'markedtrigs.ng'");
+  ofstream fout("markedtrigs.ng");
+
+  int n = GetNT();
+  fout << n << endl;
+
+  int i;
+  for (i = 1; i <= n; i++)
+    {
+      fout << IsMarkedTrig(i) << "\n";
+    }
+
+  n = GetNMarkedSegs();
+  fout << n << endl;
+
+  Point<3> ap1,ap2;
+  for (i = 1; i <= n; i++)
+    {
+      GetMarkedSeg(i,ap1,ap2);
+      fout << ap1(0) << " " << ap1(1) << " " << ap1(2) << "  ";
+      fout << ap2(0) << " " << ap2(1) << " " << ap2(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 ap1, ap2;
+  for (j = 1; j <= NONeighbourTrigs(i); j++)
+    {
+      GetTriangle(i).GetNeighbourPoints(GetTriangle(NeighbourTrig(i,j)), ap1, ap2);
+      
+      if (!IsEdge(ap1,ap2) && 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 ap1, ap2;
+  for (i = 1; i <= GetNT(); i++)
+    {
+      found = 0;
+      for (j = 1; j <= NONeighbourTrigs(i); j++)
+	{
+	  GetTriangle(i).GetNeighbourPoints(GetTriangle(NeighbourTrig(i,j)), ap1, ap2);
+
+	  if (!IsEdge(ap1,ap2))
+	    {
+              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 ap1, ap2;
+  
+  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)),ap1,ap2);
+		      if (Dist(GetPoint(ap1),GetPoint(ap2)) >= maxlen)
+			{
+			  foundtrig = NeighbourTrig(i,j);
+			  maxlen = Dist(GetPoint(ap1),GetPoint(ap2));
+			}
+		    }
+		}
+	      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, 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 Point<3> *trip1[3], *trip2[3];	
+	  Point<3> 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 ap1, int ap2)
+{
+  int i,j;
+  for (i = 1; i <= GetNEPP(ap1); i++)
+    {
+      for (j = 1; j <= GetNEPP(ap2); j++)
+	{
+	  if (GetEdgePP(ap1,i) == GetEdgePP(ap2,j)) {return 1;}
+	}
+    }
+  return 0;
+}
+
+int STLGeometry :: IsEdgeNum(int ap1, int ap2)
+{
+  int i,j;
+  for (i = 1; i <= GetNEPP(ap1); i++)
+    {
+      for (j = 1; j <= GetNEPP(ap2); j++)
+	{
+	  if (GetEdgePP(ap1,i) == GetEdgePP(ap2,j)) {return GetEdgePP(ap1,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;
+  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");
+
+  int i;
+
+  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;
+  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, ap1, ap2;
+  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),ap1,ap2);
+		    AddEdge(ap1,ap2);
+		    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(0);
+  int edgecnt = 0;
+  int found;
+  int rev(0); //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 ap1, ap2;
+	  line->GetSeg(ii,ap1,ap2);
+	  //	  (*mycout) << "SEG " << p1 << " - " << p2 << endl;
+	}
+    }
+
+  PopStatus();
+}
+
+int STLGeometry :: GetNOBodys()
+{
+  int markedtrigs1 = 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 (markedtrigs1 < 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++;
+      markedtrigs1++;
+      bodynum.Elem(starttrig) = bodycnt;
+      todolist.Append(starttrig);
+
+      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;
+		      markedtrigs1++;
+		    }
+		}
+	    }
+	  
+	  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 markedtrigs1 = 0;
+  int starttrig(0);
+  int laststarttrig = 1;
+  int i, k, nnt;
+  facecnt = 0;
+
+
+  for (i = 1; i <= GetNT(); i++)
+    GetTriangle(i).SetFaceNum(0);
+
+
+  while (markedtrigs1 < 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++;
+      markedtrigs1++;
+      GetTriangle(starttrig).SetFaceNum(facecnt);
+      todolist.Append(starttrig);
+      int ap1, ap2;
+
+      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,ap1,ap2);
+		      if (!IsEdge(ap1,ap2))
+			{
+			  nextlist.Append(nnt);
+			  nt.SetFaceNum(facecnt);
+			  markedtrigs1++;
+			}
+		    }
+		}
+	    }
+	  
+	  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);
+      
+      ng1 = trig.GeomNormal(points);
+      ng1 /= (ng1.Length() + 1e-24);
+
+      for (j = 1; j <= 3; j++)
+	{ 
+	  int nbt = NeighbourTrig (i, j);
+	  
+	  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 ap1, ap2, 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, ap1, ap2);
+		      if (IsEdge(ap1,ap2)) 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, ap1, ap2);
+			  if (IsEdge(ap1,ap2)) 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(ap1,ap2);
+				  se.SetLeftTrig(tn1);
+				  se.SetRightTrig(tn2);
+				  int edgenum = AddEdge(se);
+				  AddEdgePP(ap1,edgenum);
+				  AddEdgePP(ap2,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, ap1, ap2);
+		      if (IsEdge(ap1,ap2)) 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, ap1, ap2);
+			if (IsEdge(ap1,ap2)) 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(ap1,ap2);
+				se.SetLeftTrig(tn1);
+				se.SetRightTrig(tn2);
+				int edgenum = AddEdge(se);
+				AddEdgePP(ap1,edgenum);
+				AddEdgePP(ap2,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)), ap1, ap2);
+			  if (IsEdge(ap1,ap2)) {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, ap1, ap2, locindex1(0), locindex2(0);
+
+  //(*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, ap1, ap2);
+	      if (ap2 == p) {Swap(ap1,ap2);}
+	      if (ap1 != p) {PrintSysError("In GetSortedTrianglesAroundPoint!!!");}
+	      
+	      for (j = 1; j <= 3; j++) 
+		{
+		  if (at.PNum(j) == ap1) {locindex1 = j;};
+		  if (at.PNum(j) == ap2) {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;
+  
+  double maxerr0, maxerr;
+
+  for (i = 1; i <= GetNP(); 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/contrib/Netgen/libsrc/stlgeom/stlgeom.hpp b/contrib/Netgen/libsrc/stlgeom/stlgeom.hpp
new file mode 100644
index 0000000000..05c7b014fb
--- /dev/null
+++ b/contrib/Netgen/libsrc/stlgeom/stlgeom.hpp
@@ -0,0 +1,459 @@
+#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 <meshing.hpp>
+
+
+namespace netgen
+{
+  extern int IsInArray(int n, const Array<int>& ia);
+  extern int AddIfNotExists(Array<int>& list, int x);
+  
+  extern DLL_HEADER MeshingParameters mparam;
+  
+
+
+#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, public NetgenGeometry
+  {
+    // 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();
+
+    virtual void Save (string filename) const;
+
+
+    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> & ap1, const Point<3> & ap2) 
+    {
+      markedsegs.Append(ap1);markedsegs.Append(ap2);
+    }
+
+    void GetMarkedSeg(int i, Point<3> & ap1, Point<3> & ap2) 
+    {
+      ap1=markedsegs.Get(i*2-1); 
+      ap2=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;
+
+
+    virtual int GenerateMesh (Mesh*& mesh, MeshingParameters & mparam,
+			      int perfstepsstart, int perfstepsend);
+    
+    virtual const Refinement & GetRefinement () const;
+  };
+ 
+
+#include "meshstlsurface.hpp"
+
+
+
+  extern int STLMeshingDummy (STLGeometry* stlgeometry, Mesh*& mesh, MeshingParameters & mparam,
+			      int perfstepsstart, int perfstepsend);
+
+
+}
+#endif
diff --git a/contrib/Netgen/libsrc/stlgeom/stlgeomchart.cpp b/contrib/Netgen/libsrc/stlgeom/stlgeomchart.cpp
new file mode 100644
index 0000000000..105ba8c641
--- /dev/null
+++ b/contrib/Netgen/libsrc/stlgeom/stlgeomchart.cpp
@@ -0,0 +1,798 @@
+//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(Mesh & mesh)
+{
+
+  double h, h2;
+
+  h = mparam.maxh;
+   
+
+  PushStatusF("Make Atlas");
+
+  int i,j,k,l;
+
+  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 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++)
+    {
+      //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 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);
+  mesh.SetMinimalH(mparam.minh);
+  
+  
+  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;
+  
+  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 ap1, ap2, 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;
+
+	      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, ap1, ap2);
+		  if (IsEdge(ap1,ap2)) 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, ap1, ap2);
+		  if (IsEdge(ap1,ap2)) 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/contrib/Netgen/libsrc/stlgeom/stlgeommesh.cpp b/contrib/Netgen/libsrc/stlgeom/stlgeommesh.cpp
new file mode 100644
index 0000000000..c20c6acfc3
--- /dev/null
+++ b/contrib/Netgen/libsrc/stlgeom/stlgeommesh.cpp
@@ -0,0 +1,1590 @@
+//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> & ap1, int t1, 
+				     const Point<3> & ap2, 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(ap1,pbtw);
+	
+	  edgepoints.Add1(edgecnt,pbtw);
+	  edgepointdists.Add1(edgecnt,Dist(pbtw,ap1));
+	  edgepointorigines.Add1(edgecnt,0);
+	  edgepointoriginps.Add1(edgecnt,0);
+	}
+    }
+
+  int finished = 0;
+  int endpointorigine = 0;
+  int endpointoriginp = 0;
+  double endpointmindist = 1E50;
+
+  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;
+		  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(0);
+	      for (m = 1; m <= divisions; m++)
+		{
+		  const Point3d& p = edgepoints.Get(en,m);
+		  if (Dist(ap2,p) + edgepointdists.Get(en,m) < mindist)
+		    {mindist = Dist(ap2,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(ap2);
+  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(ap1);
+
+  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(ap1,ap2);}
+
+  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 > & apoints,
+					Array<Point3d > & points3d,
+					Array<INDEX_2> & alines, double h)
+{
+  int i, j;
+  twoint seg, newseg;
+  int zone;
+  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);
+	      apoints.Append (p2d);
+	      
+	      lpi = apoints.Size();
+	      ha_points.Elem(pi) = lpi;
+	    }
+	  else
+	    lpi = ha_points.Get(pi);
+
+	  i2.I(j) = lpi;
+	}
+      alines.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;
+
+  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;
+	  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;
+  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;
+  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 = 0.0;
+
+  //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 ap1,ap2,p3,p4;
+  Point<3> p1p, p2p, p3p, p4p;
+  Vec<3> n, ntn;
+  double rzyl, 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,ap1,ap2,p3);	    	    
+	      
+	      //checken, ob ap1-ap2 eine Kante sind
+	      if (IsEdge(ap1,ap2)) continue;
+	      
+	      p4 = trig.PNum(1) + trig.PNum(2) + trig.PNum(3) - ap1 - ap2;
+	      
+	      p1p = GetPoint(ap1); p2p = GetPoint(ap2); 
+	      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(ap1) = min2(minh.Elem(ap1),localh);
+		  minh.Elem(ap2) = min2(minh.Elem(ap2),localh);
+		}
+	      
+	      mesh.RestrictLocalHLine(p1p, p2p, localh);
+	    }
+	  
+	}
+    }
+  PrintMessage(5, "done\nATLAS H: nmin local h=", mincalch);
+  PrintMessage(5, "ATLAS H: max local h=", maxcalch);
+  PrintMessage(5, "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 ap1,ap2,p3,p4;
+  Point3d p1p, p2p, p3p, p4p;
+  Vec3d n, ntn;
+  double rzyl, 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,ap1,ap2,p3);	    	    
+	      
+	      //checken, ob ap1-ap2 eine Kante sind
+	      if (IsEdge(ap1,ap2)) continue;
+	      
+	      p4 = trig.PNum(1) + trig.PNum(2) + trig.PNum(3) - ap1 - ap2;
+	      
+	      p1p = GetPoint(ap1); p2p = GetPoint(ap2); 
+	      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(ap1) = min2(minh.Elem(ap1),localh);
+		  minh.Elem(ap2) = min2(minh.Elem(ap2),localh);
+		}
+	      
+	      //if (localh < 0.2) {localh = 0.2;}
+
+	      if(localh < objectsize)
+		mesh.RestrictLocalHLine(p1p, p2p, localh);
+	      (*testout) << "restrict h along " << p1p << " - " << p2p << " to " << localh << endl;
+	      
+	      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;
+      double mindist = 1E50;
+      
+      PrintMessage(7,"build search tree...");
+      Box3dTree* lsearchtree = 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);
+
+	  lsearchtree->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);
+	  lsearchtree->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 lp1, lp2;
+      Vec3d v1,v2;
+      mincalch = 1E50;
+      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& pp1 = GetPoint(GetLine(i)->StartP());
+	  const Point3d& pp2 = GetPoint(GetLine(i)->EndP());
+	  
+	  if (l != 0)
+	    {
+	      minhl = min2(minhl,l*linefact);
+	      
+	      mesh.RestrictLocalH(pp1, l*linefact);
+	      mesh.RestrictLocalH(pp2, 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 & ap1 = plimes1.Get(j);
+	  double boxs = mesh.GetH (plimes1.Get(j)) * limessafety;
+
+	  Point3d pmin = ap1 - Vec3d (boxs, boxs, boxs);
+	  Point3d pmax = ap1 + 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 & ap1 = plimes1.Get(j);
+	    double his = mesh.GetH (plimes1.Get(j));
+
+	    double xmin = ap1.X() - his * limessafety;
+	    double xmax = ap1.X() + his * limessafety;	      
+	    double ymin = ap1.Y() - his * limessafety;
+	    double ymax = ap1.Y() + his * limessafety;	      
+	    double zmin = ap1.Z() - his * limessafety;
+	    double zmax = ap1.Z() + his * limessafety;	      
+
+	    for (k = 1; k <= plimes2.Size(); k++)
+	    {
+	    const Point3d & ap2 = plimes2.Get(k);
+	    if (ap2.X() >= xmin && ap2.X() <= xmax &&
+	    ap2.Y() >= ymin && ap2.Y() <= ymax &&
+	    ap2.Z() >= zmin && ap2.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;}
+	    }
+	}
+    }
+
+}
+
+
+int STLMeshingDummy (STLGeometry* stlgeometry, Mesh*& mesh, MeshingParameters & mparam,
+			    int perfstepsstart, int perfstepsend)
+{
+  if (perfstepsstart > perfstepsend) return 0;
+
+  multithread.terminate = 0;
+  int success = 1;
+  //int trialcntouter = 0;
+
+  if (perfstepsstart <= MESHCONST_MESHEDGES)
+    {
+
+      mesh = new Mesh();
+      mesh->geomtype = Mesh::GEOM_STL;
+
+      mesh -> SetGlobalH (mparam.maxh);
+      mesh -> SetLocalH (stlgeometry->GetBoundingBox().PMin() - Vec3d(10, 10, 10),
+			 stlgeometry->GetBoundingBox().PMax() + Vec3d(10, 10, 10),
+			 mparam.grading);
+      mesh -> LoadLocalMeshSize (mparam.meshsizefilename);
+      
+      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 -> LoadLocalMeshSize (mparam.meshsizefilename);	      
+	      mesh -> CalcLocalHFromSurfaceCurvature (mparam.grading, 
+						      stlparam.resthsurfmeshcurvfac);
+	      mparam.optimize2d = "cmsmSm";
+	      STLSurfaceOptimization (*stlgeometry, *mesh, mparam);
+#ifdef STAT_STREAM
+	      (*statout) << GetTime() << " & ";
+#endif
+
+	      extern void Render();
+	      Render();
+	    }
+	  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 -> LoadLocalMeshSize (mparam.meshsizefilename);
+	      mesh -> CalcLocalH (mparam.grading);
+	    }
+	  
+	  
+	  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);
+	  
+#ifdef STAT_STREAM
+	  (*statout) << GetTime() << " & " << endl;
+	  (*statout) << mesh->GetNE() << " & " << endl
+		     << mesh->GetNP() << " " << '\\' << '\\' << " \\" << "hline" << endl;
+#endif
+
+	  extern void Render();
+	  Render();
+	}
+    }
+  
+
+  return 0;
+}
+
+
+
+}
diff --git a/contrib/Netgen/libsrc/stlgeom/stlline.cpp b/contrib/Netgen/libsrc/stlgeom/stlline.cpp
new file mode 100644
index 0000000000..15226edaf8
--- /dev/null
+++ b/contrib/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(0), en, pnew(0), ennew(0);
+  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(0), en;
+  int j, i, k;
+  int oldend;
+  int newend = 1;
+  int pnew, ennew(0);
+
+  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/contrib/Netgen/libsrc/stlgeom/stlline.hpp b/contrib/Netgen/libsrc/stlgeom/stlline.hpp
new file mode 100644
index 0000000000..06ce585709
--- /dev/null
+++ b/contrib/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/contrib/Netgen/libsrc/stlgeom/stlpkg.cpp b/contrib/Netgen/libsrc/stlgeom/stlpkg.cpp
new file mode 100644
index 0000000000..4282633a4c
--- /dev/null
+++ b/contrib/Netgen/libsrc/stlgeom/stlpkg.cpp
@@ -0,0 +1,622 @@
+#include <mystdlib.h>
+#include <myadt.hpp>
+#include <linalg.hpp>
+#include <csg.hpp>
+
+#include <meshing.hpp>
+
+
+#include <incvis.hpp>
+#include <visual.hpp>
+
+#include <stlgeom.hpp>
+
+#include "vsstl.hpp"
+
+extern "C" int Ng_STL_Init (Tcl_Interp * interp);
+
+
+
+namespace netgen
+{
+  extern NetgenGeometry * ng_geometry;
+  extern AutoPtr<Mesh> mesh;
+
+  static VisualSceneSTLGeometry vsstlgeom;
+  static VisualSceneSTLMeshing vsstlmeshing;
+
+  char * err_needsstlgeometry = (char*) "This operation needs an STL geometry";
+
+
+
+
+
+  class STLGeometryRegister : public GeometryRegister
+  {
+  public:
+    virtual NetgenGeometry * Load (string filename) const;
+    virtual VisualScene * GetVisualScene (const NetgenGeometry * geom) const;
+    virtual void SetParameters (Tcl_Interp * interp) 
+    {
+      stlparam.yangle =
+	atof (Tcl_GetVar (interp, "::stloptions.yangle", 0));
+      stlparam.contyangle =
+	atof (Tcl_GetVar (interp, "::stloptions.contyangle", 0));
+      stlparam.edgecornerangle =
+	atof (Tcl_GetVar (interp, "::stloptions.edgecornerangle", 0));
+      stlparam.chartangle =
+	atof (Tcl_GetVar (interp, "::stloptions.chartangle", 0));
+      stlparam.outerchartangle =
+	atof (Tcl_GetVar (interp, "::stloptions.outerchartangle", 0));
+
+      stlparam.usesearchtree =
+	atoi (Tcl_GetVar (interp, "::stloptions.usesearchtree", 0));
+
+
+      stlparam.atlasminh =
+	atof (Tcl_GetVar (interp, "::stloptions.atlasminh", 0));
+
+      stlparam.resthsurfcurvfac =
+	atof (Tcl_GetVar (interp, "::stloptions.resthsurfcurvfac", 0));
+      stlparam.resthsurfcurvenable =
+	atoi (Tcl_GetVar (interp, "::stloptions.resthsurfcurvenable", 0));
+
+      stlparam.resthatlasfac =
+	atof (Tcl_GetVar (interp, "::stloptions.resthatlasfac", 0));
+      stlparam.resthatlasenable =
+	atoi (Tcl_GetVar (interp, "::stloptions.resthatlasenable", 0));
+
+      stlparam.resthchartdistfac =
+	atof (Tcl_GetVar (interp, "::stloptions.resthchartdistfac", 0));
+      stlparam.resthchartdistenable =
+	atoi (Tcl_GetVar (interp, "::stloptions.resthchartdistenable", 0));
+
+      stlparam.resthlinelengthfac =
+	atof (Tcl_GetVar (interp, "::stloptions.resthlinelengthfac", 0));
+      stlparam.resthlinelengthenable =
+	atoi (Tcl_GetVar (interp, "::stloptions.resthlinelengthenable", 0));
+
+      stlparam.resthcloseedgefac =
+	atof (Tcl_GetVar (interp, "::stloptions.resthcloseedgefac", 0));
+      stlparam.resthcloseedgeenable =
+	atoi (Tcl_GetVar (interp, "::stloptions.resthcloseedgeenable", 0));
+
+      stlparam.resthedgeanglefac =
+	atof (Tcl_GetVar (interp, "::stloptions.resthedgeanglefac", 0));
+      stlparam.resthedgeangleenable =
+	atoi (Tcl_GetVar (interp, "::stloptions.resthedgeangleenable", 0));
+
+      stlparam.resthsurfmeshcurvfac =
+	atof (Tcl_GetVar (interp, "::stloptions.resthsurfmeshcurvfac", 0));
+      stlparam.resthsurfmeshcurvenable =
+	atoi (Tcl_GetVar (interp, "::stloptions.resthsurfmeshcurvenable", 0));
+
+      stlparam.recalc_h_opt =
+	atoi (Tcl_GetVar (interp, "::stloptions.recalchopt", 0));
+      //  stlparam.Print (cout);      
+    }
+  };
+
+
+
+  int Ng_SetSTLParameters  (ClientData clientData,
+			    Tcl_Interp * interp,
+			    int argc, tcl_const char *argv[])
+  {
+    STLGeometryRegister reg;
+    reg.SetParameters (interp);
+
+    return TCL_OK;
+  }
+
+  
+
+
+
+
+
+
+  int Ng_STLDoctor (ClientData clientData,
+		    Tcl_Interp * interp,
+		    int argc, tcl_const char *argv[])
+  {
+    //cout << "STL doctor" << endl;
+    STLGeometry * stlgeometry = 
+      dynamic_cast<STLGeometry*> (ng_geometry);
+      
+
+    stldoctor.drawmeshededges =
+      atoi (Tcl_GetVar (interp, "::stldoctor.drawmeshededges", 0));
+
+    stldoctor.geom_tol_fact =
+      atof (Tcl_GetVar (interp, "::stldoctor.geom_tol_fact", 0));
+
+
+    stldoctor.useexternaledges =
+      atoi (Tcl_GetVar (interp, "::stldoctor.useexternaledges", 0));
+
+    stldoctor.showfaces =
+      atoi (Tcl_GetVar (interp, "::stldoctor.showfaces", 0));
+
+    stldoctor.conecheck =
+      atoi (Tcl_GetVar (interp, "::stldoctor.conecheck", 0));
+
+    stldoctor.spiralcheck =
+      atoi (Tcl_GetVar (interp, "::stldoctor.spiralcheck", 0));
+
+    stldoctor.selectwithmouse =
+      atoi (Tcl_GetVar (interp, "::stldoctor.selectwithmouse", 0));
+
+    stldoctor.showedgecornerpoints =
+      atoi (Tcl_GetVar (interp, "::stldoctor.showedgecornerpoints", 0));
+
+    stldoctor.showmarkedtrigs =
+      atoi (Tcl_GetVar (interp, "::stldoctor.showmarkedtrigs", 0));
+
+    stldoctor.showtouchedtrigchart =
+      atoi (Tcl_GetVar (interp, "::stldoctor.showtouchedtrigchart", 0));
+
+    //cout << "smt=" << stldoctor.showmarkedtrigs << endl;
+
+    stldoctor.dirtytrigfact =
+      atof (Tcl_GetVar (interp, "::stldoctor.dirtytrigfact", 0));
+
+    stldoctor.smoothnormalsweight =
+      atof (Tcl_GetVar (interp, "::stldoctor.smoothnormalsweight", 0));
+
+    stldoctor.smoothangle =
+      atof (Tcl_GetVar (interp, "::stldoctor.smoothangle", 0));
+
+    stldoctor.selectmode =
+      atoi (Tcl_GetVar (interp, "::stldoctor.selectmode", 0));
+
+    stldoctor.edgeselectmode =
+      atoi (Tcl_GetVar (interp, "::stldoctor.edgeselectmode", 0));
+
+    stldoctor.longlinefact =
+      atoi (Tcl_GetVar (interp, "::stldoctor.longlinefact", 0));
+
+    stldoctor.showexcluded =
+      atoi (Tcl_GetVar (interp, "::stldoctor.showexcluded", 0));
+
+
+
+    if (!stldoctor.selectwithmouse)
+      {
+	stldoctor.selecttrig =
+	  atoi (Tcl_GetVar (interp, "::stldoctor.selecttrig", 0));
+
+	stldoctor.nodeofseltrig =
+	  atoi (Tcl_GetVar (interp, "::stldoctor.nodeofseltrig", 0));
+      }
+
+    stldoctor.showvicinity =
+      atoi (Tcl_GetVar (interp, "::stldoctor.showvicinity", 0));
+
+    stldoctor.vicinity =
+      atoi (Tcl_GetVar (interp, "::stldoctor.vicinity", 0));
+
+
+    if (argc >= 2)
+      {
+	if (!stlgeometry)
+	  {
+	    Tcl_SetResult (interp, err_needsstlgeometry, TCL_STATIC);
+	    return TCL_ERROR;
+	  }
+
+	if (strcmp (argv[1], "destroy0trigs") == 0)
+	  {
+	    stlgeometry->DestroyDirtyTrigs();
+	  }
+	else if (strcmp (argv[1], "movepointtomiddle") == 0)
+	  {
+	    stlgeometry->MoveSelectedPointToMiddle();
+	  }
+	else if (strcmp (argv[1], "calcnormals") == 0)
+	  {
+	    stlgeometry->CalcNormalsFromGeometry();
+	  }
+	else if (strcmp (argv[1], "showchartnum") == 0)
+	  {
+	    stlgeometry->ShowSelectedTrigChartnum();
+	  }
+	else if (strcmp (argv[1], "showcoords") == 0)
+	  {
+	    stlgeometry->ShowSelectedTrigCoords();
+	  }
+	else if (strcmp (argv[1], "loadmarkedtrigs") == 0)
+	  {
+	    stlgeometry->LoadMarkedTrigs();
+	  }
+	else if (strcmp (argv[1], "savemarkedtrigs") == 0)
+	  {
+	    stlgeometry->SaveMarkedTrigs();
+	  }
+	else if (strcmp (argv[1], "neighbourangles") == 0)
+	  {
+	    stlgeometry->NeighbourAnglesOfSelectedTrig();
+	  }
+	else if (strcmp (argv[1], "vicinity") == 0)
+	  {
+	    stlgeometry->CalcVicinity(stldoctor.selecttrig);
+	  }
+	else if (strcmp (argv[1], "markdirtytrigs") == 0)
+	  {
+	    stlgeometry->MarkDirtyTrigs();
+	  }
+	else if (strcmp (argv[1], "smoothdirtytrigs") == 0)
+	  {
+	    stlgeometry->SmoothDirtyTrigs();
+	  }
+	else if (strcmp (argv[1], "smoothrevertedtrigs") == 0)
+	  {
+	    stlgeometry->GeomSmoothRevertedTrigs();
+	  }
+	else if (strcmp (argv[1], "invertselectedtrig") == 0)
+	  {
+	    stlgeometry->InvertTrig(stlgeometry->GetSelectTrig());
+	  }
+	else if (strcmp (argv[1], "deleteselectedtrig") == 0)
+	  {
+	    stlgeometry->DeleteTrig(stlgeometry->GetSelectTrig());
+	  }
+	else if (strcmp (argv[1], "smoothgeometry") == 0)
+	  {
+	    stlgeometry->SmoothGeometry();
+	  }
+	else if (strcmp (argv[1], "orientafterselectedtrig") == 0)
+	  {
+	    stlgeometry->OrientAfterTrig(stlgeometry->GetSelectTrig());
+	  }
+	else if (strcmp (argv[1], "marktoperrortrigs") == 0)
+	  {
+	    stlgeometry->MarkTopErrorTrigs();
+	  }
+	else if (strcmp (argv[1], "exportedges") == 0)
+	  {
+	    stlgeometry->ExportEdges();
+	  }
+	else if (strcmp (argv[1], "importedges") == 0)
+	  {
+	    stlgeometry->ImportEdges();
+	  }
+	else if (strcmp (argv[1], "importexternaledges") == 0)
+	  {
+	    stlgeometry->ImportExternalEdges(argv[2]);
+	  }
+	else if (strcmp (argv[1], "loadedgedata") == 0)
+	  {
+	    if (argc >= 3)
+	      {
+		stlgeometry->LoadEdgeData(argv[2]);
+	      }
+	  }
+	else if (strcmp (argv[1], "saveedgedata") == 0)
+	  {
+	    if (argc >= 3)
+	      {
+		stlgeometry->SaveEdgeData(argv[2]);
+	      }
+	  }
+
+	else if (strcmp (argv[1], "buildexternaledges") == 0)
+	  {
+	    stlgeometry->BuildExternalEdgesFromEdges();
+	  }
+	else if (strcmp (argv[1], "smoothnormals") == 0)
+	  {
+	    stlgeometry->SmoothNormals();
+	  }
+	else if (strcmp (argv[1], "marknonsmoothnormals") == 0)
+	  {
+	    stlgeometry->MarkNonSmoothNormals();
+	  }
+	else if (strcmp (argv[1], "addexternaledge") == 0)
+	  {
+	    stlgeometry->AddExternalEdgeAtSelected();
+	  }
+	else if (strcmp (argv[1], "addgeomline") == 0)
+	  {
+	    stlgeometry->AddExternalEdgesFromGeomLine();
+	  }
+	else if (strcmp (argv[1], "addlonglines") == 0)
+	  {
+	    stlgeometry->AddLongLinesToExternalEdges();
+	  }
+	else if (strcmp (argv[1], "addclosedlines") == 0)
+	  {
+	    stlgeometry->AddClosedLinesToExternalEdges();
+	  }
+	else if (strcmp (argv[1], "addnotsinglelines") == 0)
+	  {
+	    stlgeometry->AddAllNotSingleLinesToExternalEdges();
+	  }
+	else if (strcmp (argv[1], "deletedirtyexternaledges") == 0)
+	  {
+	    stlgeometry->DeleteDirtyExternalEdges();
+	  }
+	else if (strcmp (argv[1], "deleteexternaledge") == 0)
+	  {
+	    stlgeometry->DeleteExternalEdgeAtSelected();
+	  }
+	else if (strcmp (argv[1], "deletevicexternaledge") == 0)
+	  {
+	    stlgeometry->DeleteExternalEdgeInVicinity();
+	  }
+
+	else if (strcmp (argv[1], "addlonglines") == 0)
+	  {
+	    stlgeometry->STLDoctorLongLinesToCandidates();
+	  }
+	else if (strcmp (argv[1], "deletedirtyedges") == 0)
+	  {
+	    stlgeometry->STLDoctorDirtyEdgesToCandidates();
+	  }
+	else if (strcmp (argv[1], "undoedgechange") == 0)
+	  {
+	    stlgeometry->UndoEdgeChange();
+	  }
+	else if (strcmp (argv[1], "buildedges") == 0)
+	  {
+	    stlgeometry->STLDoctorBuildEdges();
+	  }
+	else if (strcmp (argv[1], "confirmedge") == 0)
+	  {
+	    stlgeometry->STLDoctorConfirmEdge();
+	  }
+	else if (strcmp (argv[1], "candidateedge") == 0)
+	  {
+	    stlgeometry->STLDoctorCandidateEdge();
+	  }
+	else if (strcmp (argv[1], "excludeedge") == 0)
+	  {
+	    stlgeometry->STLDoctorExcludeEdge();
+	  }
+	else if (strcmp (argv[1], "undefinededge") == 0)
+	  {
+	    stlgeometry->STLDoctorUndefinedEdge();
+	  }
+	else if (strcmp (argv[1], "setallundefinededges") == 0)
+	  {
+	    stlgeometry->STLDoctorSetAllUndefinedEdges();
+	  }
+	else if (strcmp (argv[1], "erasecandidateedges") == 0)
+	  {
+	    stlgeometry->STLDoctorEraseCandidateEdges();
+	  }
+	else if (strcmp (argv[1], "confirmcandidateedges") == 0)
+	  {
+	    stlgeometry->STLDoctorConfirmCandidateEdges();
+	  }
+	else if (strcmp (argv[1], "confirmedtocandidateedges") == 0)
+	  {
+	    stlgeometry->STLDoctorConfirmedToCandidateEdges();
+	  }
+      }
+
+    return TCL_OK;
+  }
+
+
+
+
+
+
+
+
+
+  NetgenGeometry *  STLGeometryRegister :: Load (string filename) const
+  {
+    const char * cfilename = filename.c_str();
+
+    if (strcmp (&cfilename[strlen(cfilename)-3], "stl") == 0)
+      {
+	PrintMessage (1, "Load STL geometry file ", cfilename);
+
+	ifstream infile(cfilename);
+
+	STLGeometry * hgeom = STLGeometry :: Load (infile);
+	hgeom -> edgesfound = 0;
+	return hgeom;
+      }
+    else if (strcmp (&cfilename[strlen(cfilename)-4], "stlb") == 0)
+      {
+	PrintMessage (1, "Load STL binary geometry file ", cfilename);
+
+	ifstream infile(cfilename);
+
+	STLGeometry * hgeom = STLGeometry :: LoadBinary (infile);
+	hgeom -> edgesfound = 0;
+	return hgeom;
+      }
+    else if (strcmp (&cfilename[strlen(cfilename)-3], "nao") == 0)
+      {
+	PrintMessage (1, "Load naomi (F. Kickinger) geometry file ", cfilename);
+
+	ifstream infile(cfilename);
+
+	STLGeometry * hgeom = STLGeometry :: LoadNaomi (infile);
+	hgeom -> edgesfound = 0;
+	return hgeom;
+      }
+
+    
+    return NULL;
+  }
+
+
+
+
+
+
+
+
+
+  int Ng_STLInfo  (ClientData clientData,
+		   Tcl_Interp * interp,
+		   int argc, tcl_const char *argv[])
+  {
+    double data[10];
+    static char buf[20];
+
+    STLGeometry * stlgeometry = dynamic_cast<STLGeometry*> (ng_geometry);
+
+    if (!stlgeometry)
+      {
+	Tcl_SetResult (interp, err_needsstlgeometry, TCL_STATIC);
+	return TCL_ERROR;
+      }
+
+
+
+    if (stlgeometry)
+      {
+	stlgeometry->STLInfo(data);
+	//      cout << "NT=" << data[0] << endl;
+
+	if (argc == 2)
+	  {
+	    if (strcmp (argv[1], "status") == 0)
+	      {
+		switch (stlgeometry->GetStatus())
+		  {
+		  case STLGeometry::STL_GOOD:
+		    strcpy (buf, "GOOD"); break;
+		  case STLGeometry::STL_WARNING:
+		    strcpy (buf, "WARNING"); break;
+		  case STLGeometry::STL_ERROR:
+		    strcpy (buf, "ERROR"); break;
+		  }
+		Tcl_SetResult (interp, buf, TCL_STATIC);
+		return TCL_OK;
+	      }
+	    if (strcmp (argv[1], "statustext") == 0)
+	      {
+		Tcl_SetResult (interp, (char*)stlgeometry->GetStatusText().c_str(), TCL_STATIC);
+		return TCL_OK;
+	      }
+	    if (strcmp (argv[1], "topology_ok") == 0)
+	      {
+		sprintf (buf, "%d", stlgeometry->Topology_Ok());
+		Tcl_SetResult (interp, buf, TCL_STATIC);
+	      }
+	    if (strcmp (argv[1], "orientation_ok") == 0)
+	      {
+		sprintf (buf, "%d", stlgeometry->Orientation_Ok());
+		Tcl_SetResult (interp, buf, TCL_STATIC);
+	      }
+	  }
+      }
+    else
+      {
+	data[0] = 0;
+	data[1] = 0;
+	data[2] = 0;
+	data[3] = 0;
+	data[4] = 0;
+	data[5] = 0;
+	data[6] = 0;
+	data[7] = 0;
+      }
+
+
+
+
+    sprintf (buf, "%i", (int)data[0]);
+    Tcl_SetVar (interp, argv[1], buf, 0);
+
+    sprintf (buf, "%5.3g", data[1]);
+    Tcl_SetVar (interp, argv[2], buf, 0);
+    sprintf (buf, "%5.3g", data[2]);
+    Tcl_SetVar (interp, argv[3], buf, 0);
+    sprintf (buf, "%5.3g", data[3]);
+    Tcl_SetVar (interp, argv[4], buf, 0);
+
+    sprintf (buf, "%5.3g", data[4]);
+    Tcl_SetVar (interp, argv[5], buf, 0);
+    sprintf (buf, "%5.3g", data[5]);
+    Tcl_SetVar (interp, argv[6], buf, 0);
+    sprintf (buf, "%5.3g", data[6]);
+    Tcl_SetVar (interp, argv[7], buf, 0);
+
+    sprintf (buf, "%i", (int)data[7]);
+    Tcl_SetVar (interp, argv[8], buf, 0);
+
+    return TCL_OK;
+  }
+
+
+
+  extern int Ng_SetMeshingParameters  (ClientData clientData,
+				       Tcl_Interp * interp,
+				       int argc, tcl_const char *argv[]);
+
+  int Ng_STLCalcLocalH  (ClientData clientData,    
+			 Tcl_Interp * interp,
+			 int argc, tcl_const char *argv[])
+  {
+    for (int i = 0; i < geometryregister.Size(); i++)
+      geometryregister[i] -> SetParameters (interp);
+
+
+    Ng_SetMeshingParameters (clientData, interp, argc, argv);
+
+    STLGeometry * stlgeometry = dynamic_cast<STLGeometry*> (ng_geometry);
+    if (mesh.Ptr() && stlgeometry)
+      {
+	mesh -> SetLocalH (stlgeometry->GetBoundingBox().PMin() - Vec3d(10, 10, 10),
+			   stlgeometry->GetBoundingBox().PMax() + Vec3d(10, 10, 10),
+			   mparam.grading);
+	stlgeometry -> RestrictLocalH(*mesh, mparam.maxh);
+
+	if (stlparam.resthsurfmeshcurvenable)
+	  mesh -> CalcLocalHFromSurfaceCurvature (mparam.grading, 
+						  stlparam.resthsurfmeshcurvfac);
+      }
+
+    return TCL_OK;
+  }
+
+
+
+
+  VisualScene * STLGeometryRegister :: GetVisualScene (const NetgenGeometry * geom) const
+  {
+    STLGeometry * geometry = dynamic_cast<STLGeometry*> (ng_geometry);
+    if (geometry)
+      {
+	vsstlmeshing.SetGeometry (geometry);
+	return &vsstlmeshing;
+      }
+    return NULL;
+  }
+}
+
+
+using namespace netgen;
+
+extern "C" int Ng_stl_Init (Tcl_Interp * interp);
+int Ng_stl_Init (Tcl_Interp * interp)
+{
+  geometryregister.Append (new STLGeometryRegister);
+
+  Tcl_CreateCommand (interp, "Ng_SetSTLParameters", Ng_SetSTLParameters,
+		     (ClientData)NULL,
+		     (Tcl_CmdDeleteProc*) NULL);
+  
+  Tcl_CreateCommand (interp, "Ng_STLDoctor", Ng_STLDoctor,
+		     (ClientData)NULL,
+		     (Tcl_CmdDeleteProc*) NULL);
+
+  Tcl_CreateCommand (interp, "Ng_STLInfo", Ng_STLInfo,
+		     (ClientData)NULL,
+		     (Tcl_CmdDeleteProc*) NULL);
+  
+  Tcl_CreateCommand (interp, "Ng_STLCalcLocalH", Ng_STLCalcLocalH,
+		     (ClientData)NULL,
+		     (Tcl_CmdDeleteProc*) NULL);
+
+  
+  return TCL_OK;
+}
diff --git a/contrib/Netgen/libsrc/stlgeom/stltool.cpp b/contrib/Netgen/libsrc/stlgeom/stltool.cpp
new file mode 100644
index 0000000000..ee06157b08
--- /dev/null
+++ b/contrib/Netgen/libsrc/stlgeom/stltool.cpp
@@ -0,0 +1,1287 @@
+#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 = 0.0;
+      double nearest = 1E50;
+      //int fi = 0;
+      for (int 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 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/contrib/Netgen/libsrc/stlgeom/stltool.hpp b/contrib/Netgen/libsrc/stlgeom/stltool.hpp
new file mode 100644
index 0000000000..ca3d6e2f14
--- /dev/null
+++ b/contrib/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/contrib/Netgen/libsrc/stlgeom/stltopology.cpp b/contrib/Netgen/libsrc/stlgeom/stltopology.cpp
new file mode 100644
index 0000000000..8547034f08
--- /dev/null
+++ b/contrib/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), 
+    trigsperpoint(), neighbourtrigs()
+{
+  ;
+}
+
+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) const
+{
+  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) const
+{
+  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) const
+{ 
+  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)
+{
+  size_t 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;
+
+      size_t 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, 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(0);
+	      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> & btrias) const
+{
+  if (searchtree)
+
+    searchtree -> GetIntersecting (box.PMin(), box.PMax(), btrias);
+  
+  else
+    {    
+      int i;
+      Box<3> box1 = box;
+      box1.Increase (1e-4);
+
+      btrias.SetSize(0);
+   
+      int nt = GetNT();
+      for (i = 1; i <= nt; i++)
+	{
+	  if (box1.Intersect (GetTriangle(i).box))
+	    {
+	      btrias.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 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/contrib/Netgen/libsrc/stlgeom/stltopology.hpp b/contrib/Netgen/libsrc/stlgeom/stltopology.hpp
new file mode 100644
index 0000000000..fbb2394fd8
--- /dev/null
+++ b/contrib/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) const;
+  void SaveBinary (const char* filename, const char* aname) const;
+  void SaveSTLE (const char * filename) const; // 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/contrib/Netgen/libsrc/stlgeom/vsstl.cpp b/contrib/Netgen/libsrc/stlgeom/vsstl.cpp
new file mode 100644
index 0000000000..338c305ddf
--- /dev/null
+++ b/contrib/Netgen/libsrc/stlgeom/vsstl.cpp
@@ -0,0 +1,1212 @@
+#include <mystdlib.h>
+#include <myadt.hpp>
+
+#include <linalg.hpp>
+#include <stlgeom.hpp>
+
+#include <meshing.hpp>
+#include <visual.hpp>
+
+
+#include "vsstl.hpp"
+
+
+namespace netgen
+{
+
+/*
+//mmm
+#include "stlgeom/modeller.hpp"
+*/
+
+/* *********************** Draw STL Geometry **************** */
+
+extern STLGeometry * stlgeometry;
+extern AutoPtr<Mesh> mesh;
+
+
+// #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 = 0.0, hmax = 1.0;
+
+  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.9f, 0.0f, 0.0f, 1.0f };
+  float mat_colgreen[]  = { 0.0f, 0.9f, 0.0f, 1.0f };
+  float mat_colblue[]   = { 0.1f, 0.1f, 1.0f, 1.0f };
+
+  float mat_colbluegreen[] = { 0.1f, 0.5f, 0.9f, 1.0f };
+  // float mat_colpink[]      = { 1.0f, 0.1f, 0.5f, 1.0f };
+  float mat_colviolet[]    = { 1.0f, 0.1f, 1.0f, 1.0f };
+  float mat_colbrown[]     = { 0.8f, 0.6f, 0.1f, 1.0f };
+  // float mat_colorange[]    = { 0.9f, 0.7f, 0.1f, 1.0f };
+  // float mat_colturquis[]   = { 0.0f, 1.0f, 0.8f, 1.0f };
+
+  float mat_colgrey[] = { 0.3f, 0.3f, 0.3f, 1.0f };
+
+  float mat_collred[]   = { 1.0f, 0.5f, 0.5f, 1.0f };
+  float mat_collgreen[] = { 0.2f, 1.9f, 0.2f, 1.0f };
+  float mat_collbrown[] = { 1.0f, 0.8f, 0.3f, 1.0f };
+
+  float mat_collgrey[] = { 0.8f, 0.8f, 0.8f, 1.0f };
+  // float mat_colmgrey[] = { 0.4f, 0.4f, 0.4f, 1.0f };
+
+  float mat_colstlbody[] = { 0.0f, 0.0f, 0.8f, 1.0f };
+  float mat_colseltrig[] = { 0.7f, 0.7f, 0.3f, 1.0f };
+  float mat_colseledge[] = { 0.7f, 0.7f, 1.0f, 1.0f };
+
+  glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_colblue);
+
+  float pgoff = 0.5f;
+
+  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.2f, 0.2f, 0.2f, 1.f };
+	  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)
+{
+  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;
+
+
+
+
+
+  /* *********************** Draw STL Geometry **************** */
+
+
+  VisualSceneSTLGeometry :: VisualSceneSTLGeometry ()
+    : VisualScene()
+  {
+    ;
+  }
+
+  VisualSceneSTLGeometry :: ~VisualSceneSTLGeometry ()
+  {
+    ;
+  }
+
+  void VisualSceneSTLGeometry :: DrawScene ()
+  {
+    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.2f, 0.2f, 0.8f, 1.0f};
+    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.2f, 0.2f, 0.2f, 1.0f };
+	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)
+  {
+    //  cout << "rebuild stl geometry scene" << endl;
+
+    center = stlgeometry -> GetBoundingBox().Center();
+    rad = stlgeometry -> GetBoundingBox().Diam() / 2;
+
+
+    CalcTransformationMatrices();
+
+    for (int 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 (int j = 1; j <= stlgeometry -> GetNT(); j++)
+      {
+	const Vec3d & n = stlgeometry->GetTriangle(j).Normal();
+	glNormal3f (n.X(), n.Y(), n.Z());
+      
+	for (int k = 1; k <= 3; k++)
+	  {
+	    const Point3d & p = 
+	      stlgeometry->GetPoint (stlgeometry -> GetTriangle(j).PNum(k));
+	    glVertex3f (p.X(),p.Y(), p.Z());
+	  }
+      }    
+    glEnd ();
+      
+    glEndList ();
+  }
+ 
+}
diff --git a/contrib/Netgen/libsrc/stlgeom/vsstl.hpp b/contrib/Netgen/libsrc/stlgeom/vsstl.hpp
new file mode 100644
index 0000000000..d3841c8174
--- /dev/null
+++ b/contrib/Netgen/libsrc/stlgeom/vsstl.hpp
@@ -0,0 +1,53 @@
+#ifndef FILE_VSSTL
+#define FILE_VSSTL
+
+/**************************************************************************/
+/* File:   vsstl.hpp                                                      */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   05. Jan. 2011                                                  */
+/**************************************************************************/
+
+namespace netgen
+{
+
+ class VisualSceneSTLGeometry : public VisualScene
+  {
+    Array<int> trilists;
+    class STLGeometry * stlgeometry;
+
+  public:
+    VisualSceneSTLGeometry ();
+    virtual ~VisualSceneSTLGeometry ();
+    void SetGeometry (class STLGeometry * astlgeometry) { stlgeometry = astlgeometry; }
+
+    virtual void BuildScene (int zoomall = 0);
+    virtual void DrawScene ();
+  };
+
+
+  class VisualSceneSTLMeshing : public VisualScene
+  {
+    Array<int> trilists;
+    int selecttrig, nodeofseltrig;
+    class STLGeometry * stlgeometry;
+
+  public:
+    VisualSceneSTLMeshing ();
+    virtual ~VisualSceneSTLMeshing ();
+
+    void SetGeometry (class STLGeometry * astlgeometry) { stlgeometry = astlgeometry; }
+
+    virtual void BuildScene (int zoomall = 0);
+    virtual void DrawScene ();
+    virtual void MouseDblClick (int px, int py);
+
+    int seltria;
+  };
+
+
+
+}
+
+
+
+#endif
diff --git a/contrib/Netgen/libsrc/visualization/Makefile.am b/contrib/Netgen/libsrc/visualization/Makefile.am
new file mode 100644
index 0000000000..5f2dff7eba
--- /dev/null
+++ b/contrib/Netgen/libsrc/visualization/Makefile.am
@@ -0,0 +1,11 @@
+noinst_HEADERS = meshdoc.hpp mvdraw.hpp vispar.hpp \
+visual.hpp vssolution.hpp
+
+include_HEADERS = soldata.hpp
+
+AM_CPPFLAGS =  $(MPI_INCLUDES) -I$(top_srcdir)/libsrc/include  -DOPENGL -D$(TOGL_WINDOWINGSYSTEM) $(OCCFLAGS)    $(TCL_INCLUDES)
+METASOURCES = AUTO
+noinst_LIBRARIES = libvisual.a
+libvisual_a_SOURCES = meshdoc.cpp mvdraw.cpp \
+	vsfieldlines.cpp vsmesh.cpp vssolution.cpp importsolution.cpp
+AM_CXXFLAGS = -DOPENGL
diff --git a/contrib/Netgen/libsrc/visualization/importsolution.cpp b/contrib/Netgen/libsrc/visualization/importsolution.cpp
new file mode 100644
index 0000000000..cf182d7120
--- /dev/null
+++ b/contrib/Netgen/libsrc/visualization/importsolution.cpp
@@ -0,0 +1,129 @@
+//
+//  Read solution file
+//
+
+
+#include <mystdlib.h>
+
+
+#include <myadt.hpp>
+#include <linalg.hpp>
+#include <csg.hpp>
+#include <meshing.hpp>
+
+#include <nginterface.h>
+
+namespace netgen
+{
+
+
+
+void ImportSolution (const char * filename)
+{
+  ifstream inf (filename);
+  char buf[100], name[1000];
+  int i, 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;
+          soldata.draw_surface = 1;
+          soldata.draw_volume = 1;
+	  if (strcmp (type, "element") == 0)
+            {
+              soldata.soltype = NG_SOLUTION_ELEMENT;
+              soldata.draw_surface = 0;
+            }
+	  if (strcmp (type, "surfaceelement") == 0)
+            {
+              soldata.soltype = NG_SOLUTION_SURFACE_ELEMENT;
+              soldata.draw_volume = 0;
+            }
+	  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/contrib/Netgen/libsrc/visualization/meshdoc.cpp b/contrib/Netgen/libsrc/visualization/meshdoc.cpp
new file mode 100644
index 0000000000..c2df277e10
--- /dev/null
+++ b/contrib/Netgen/libsrc/visualization/meshdoc.cpp
@@ -0,0 +1,614 @@
+#ifndef NOTCL
+
+#include <mystdlib.h>
+
+#include <meshing.hpp>
+
+// #include "incvis.hpp"
+
+
+#include <visual.hpp>
+
+
+namespace netgen
+{
+  // #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 ()
+{
+  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;
+ 
+  
+  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);
+  
+  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[0]);
+      const Point3d & p2 = mesh->Point(seg[1]);
+
+      if (edgedist.Get(seg[0]) <= markedgedist &&
+	  edgedist.Get(seg[1]) <= 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, 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[0] == selpoint && seg[1] == selpoint2) ||
+           (seg[1] == selpoint && seg[0] == 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[0]), edgedist.Get(seg[1]));
+	  edist++;
+
+	  if (edgedist.Get(seg[0]) > edist)
+	    {
+	      edgedist.Elem(seg[0]) = edist;
+	      changed = 1;
+	    }
+	  if (edgedist.Get(seg[1]) > edist)
+	    {
+	      edgedist.Elem(seg[1]) = edist;
+	      changed = 1;
+	    }
+	}	    
+    }
+  while (changed);
+}
+
+int VisualSceneMeshDoctor :: IsSegmentMarked (int segnr) const
+{
+  const Segment & seg = mesh->LineSegment(segnr);
+  return (edgedist.Get(seg[0]) <= markedgedist &&
+	  edgedist.Get(seg[1]) <= markedgedist);
+}
+}
+
+
+#endif // NOTCL
diff --git a/contrib/Netgen/libsrc/visualization/meshdoc.hpp b/contrib/Netgen/libsrc/visualization/meshdoc.hpp
new file mode 100644
index 0000000000..65763385f1
--- /dev/null
+++ b/contrib/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/contrib/Netgen/libsrc/visualization/mvdraw.cpp b/contrib/Netgen/libsrc/visualization/mvdraw.cpp
new file mode 100644
index 0000000000..d348fc7b66
--- /dev/null
+++ b/contrib/Netgen/libsrc/visualization/mvdraw.cpp
@@ -0,0 +1,806 @@
+#include <mystdlib.h>
+#include <myadt.hpp>
+#include <meshing.hpp>
+
+#include <visual.hpp>
+// #include <parallel.hpp>
+
+
+
+#ifndef WIN32
+#define GLX_GLXEXT_LEGACY
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xatom.h>  /* for XA_RGB_DEFAULT_MAP atom */
+// #include <GL/glx.h>    // for parallel GL ???
+#endif
+
+
+
+
+
+namespace netgen
+{
+  DLL_HEADER Point3d VisualScene :: center;
+  DLL_HEADER double VisualScene :: rad;
+  DLL_HEADER GLdouble VisualScene :: backcolor;
+
+  /*
+#if TOGL_MAJOR_VERSION!=2
+  GLuint VisualScene :: fontbase = 0;
+#else
+  Tcl_Obj * VisualScene :: fontbase = NULL;
+  Togl * VisualScene :: globtogl;
+#endif
+  */
+
+  // texture for color decoding
+  // GLubyte * VisualScene :: colortexture = NULL;
+  GLuint VisualScene :: coltexname = 1;
+  int VisualScene :: ntexcols = -1;
+
+
+  float VisualScene :: lookatmat[16];
+  float VisualScene :: transmat[16];
+  float VisualScene :: rotmat[16];
+  float VisualScene :: centermat[16];
+  float VisualScene :: transformationmat[16];
+
+  int VisualScene :: selface;
+  int VisualScene :: selelement;
+  int VisualScene :: selpoint;
+  int VisualScene :: selpoint2;
+  int VisualScene :: locpi;
+  int VisualScene :: seledge;
+
+  int VisualScene :: selecttimestamp;
+
+
+  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");
+
+    use_center_coords = false;
+  };
+  VisualizationParameters vispar;
+
+
+
+  double dist = 0;
+  // double dist = 6;
+  // vorher: pnear = 2;
+  // double pnear = 0.1;
+  // double pfar = 10;
+
+
+
+  VisualScene :: VisualScene ()
+  {
+    changeval = -1;
+    backcolor = 0;
+  }
+
+
+  VisualScene :: ~VisualScene()
+  {
+    ;
+  }
+
+
+  extern DLL_HEADER void Render();
+  DLL_HEADER void Render ()
+  {
+    multithread.redraw = 1;
+  }
+
+
+  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);
+
+    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 :: ArbitraryRotation (const Array<double> & alpha, const Array<Vec3d> & vec)
+  {
+    glPushMatrix();
+
+    glLoadIdentity();
+
+    for(int i=0; i<alpha.Size() && i<vec.Size(); i++)
+      {
+	glRotatef(alpha[i], vec[i].X(), vec[i].Y(), vec[i].Z());
+      }
+
+    glGetFloatv (GL_MODELVIEW_MATRIX, rotmat);
+
+    glLoadIdentity();
+    glMultMatrixf (lookatmat);
+    glMultMatrixf (transmat);
+    glMultMatrixf (rotmat);
+    glMultMatrixf (centermat);
+    glGetFloatv (GL_MODELVIEW_MATRIX, transformationmat);
+  
+    glPopMatrix();
+  } 
+
+
+
+  void VisualScene :: ArbitraryRotation (const double alpha, const Vec3d & vec)
+  {
+    Array<double> a(1); a[0] = alpha;
+    Array<Vec3d> v(1); v[0] = vec;
+
+    ArbitraryRotation(a,v);
+  } 
+
+  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.99; //  0.95;
+	  GLdouble pvx2 = deltax, pvy2 = -deltay, pvz2 = 0.99; // 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);
+
+	  // cout << "deltay = " << deltay << endl;
+	  // cout << "float_bug = " << (float(deltay)/100) << endl;   gives wrong result with icc 9.0.021
+	  glScaled (exp (double (-deltay)/100), 
+		    exp (double (-deltay)/100), 
+		    exp (double (-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 val, double valmin, double valmax,
+				     int logscale)
+  {
+    double value;
+
+    if (!logscale)
+      value = (val - valmin) / (valmax - valmin);
+    else
+      {
+	if (valmax <= 0) valmax = 1;
+	if (valmin <= 0) valmin = 1e-4 * valmax;
+	value = (log(fabs(val)) - log(valmin)) / (log(valmax) - log(valmin));
+      }
+
+    if (!invcolor)
+      value = 1 - value;
+
+    glTexCoord1f ( 0.998 * value + 0.001);
+    // glTexCoord1f ( val ); 
+
+    glTexCoord2f ( 0.998 * value + 0.001, 1.5);
+    // glTexCoord1f ( value ); 
+
+    if (value > 1) value = 1;
+    if (value < 0) value = 0;
+
+    value *= 4;
+
+    static 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];
+    for (int 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 typ)
+  {
+    if (linear) ncols = 32;
+    else   ncols = 8;
+
+
+    if (ntexcols != ncols) 
+      {
+	ntexcols = ncols;
+      
+	GLubyte colortexture[4*32];
+
+	const double colp[][3] =
+	  {
+	    { 1, 0, 0 },
+	    { 1, 1, 0 },
+	    { 0, 1, 0 },
+	    { 0, 1, 1 },
+	    { 0, 0, 1 },
+	  };
+  
+	for (int i = 0; i < ncols; i++)
+	  {
+	    double value = 4.0 * i / (ncols-1);
+
+	    int iv = int(value);
+	    double r = value - iv;
+
+	    GLdouble col[3];
+
+	    if(r > 1e-3)
+	      for (int j = 0; j < 3; j++)
+		col[j] = (1.-r) * colp[iv][j] + r * colp[iv+1][j];
+	    else
+	      for (int j = 0; j < 3; j++)
+		col[j] = colp[iv][j];
+
+	    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);
+
+     	glTexImage1D (GL_TEXTURE_1D, 0, 4, ncols, 0, GL_RGBA, GL_UNSIGNED_BYTE, colortexture);
+	glTexImage2D (GL_TEXTURE_2D, 0, 4, ncols, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, colortexture);
+
+	glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, typ);  // DECAL or MODULATE
+	
+	GLfloat bcol[] = { 1, 1, 1, 1.0 };
+	glTexParameterfv (GL_TEXTURE_1D, GL_TEXTURE_BORDER_COLOR, bcol);
+	glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+
+	glTexParameterfv (GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, bcol);
+	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+	
+	if (linear)
+	  {
+	    glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+	    glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+	    glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+	    glTexParameteri (GL_TEXTURE_2D, 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);
+
+	    glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+	    glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+	  }
+      }
+  }
+  
+
+
+
+  void VisualScene :: DrawColorBar (double minval, double maxval, int logscale, bool linear)
+  {
+    if (!vispar.drawcolorbar) return;
+
+    CreateTexture (8, linear, GL_DECAL);
+
+    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;
+
+    glDisable (GL_LIGHTING);
+    glEnable (GL_COLOR_MATERIAL);
+    glEnable (GL_TEXTURE_1D);
+    glNormal3d (0, 0, 1);
+    glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
+    
+    glDisable (GL_DEPTH_TEST);
+    glBegin (GL_QUAD_STRIP);
+
+    for (double x = minx; x <= maxx; x += (maxx - minx) / 50)
+      {
+	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 (int i = 0; i <= 4; i++)
+      {
+	double 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 (GLsizei(strlen (buf)), GL_UNSIGNED_BYTE, buf);
+	MyOpenGLText (buf);
+      }
+
+    glPopAttrib ();
+    glEnable (GL_DEPTH_TEST);
+  }
+
+
+  void VisualScene :: DrawCoordinateCross ()
+  {
+    if (!vispar.drawcoordinatecross) return;
+
+    glDisable (GL_DEPTH_TEST);
+    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);
+
+    glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
+
+    GLfloat textcol[3] = { 1 - backcolor,
+			   1 - backcolor,
+			   1 - backcolor };
+    glColor3fv (textcol);
+
+    glLineWidth (1.0f);
+
+    double len = 1;
+
+    glBegin(GL_LINES);
+    glVertex3d (0, 0, 0);
+    glVertex3d (len, 0, 0);
+    glVertex3d (0.0f, 0.0f, 0.0f);
+    glVertex3d (0.0f, len, 0.0f);
+    glVertex3d (0.0f, 0.0f, 0.0f);
+    glVertex3d (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 (GLsizei(strlen (buf)), GL_UNSIGNED_BYTE, buf);
+    MyOpenGLText (buf);
+    glRasterPos3d (0.0f, len, 0.0f);
+    sprintf (buf, "y");
+    // glCallLists (GLsizei(strlen (buf)), GL_UNSIGNED_BYTE, buf);
+    MyOpenGLText (buf);
+    glRasterPos3d (0.0f, 0.0f, len);
+    sprintf (buf, "z");
+    // glCallLists (GLsizei(strlen (buf)), GL_UNSIGNED_BYTE, buf);
+    MyOpenGLText (buf);
+
+    glPopAttrib ();
+
+    glEnable (GL_LIGHTING);
+
+    glMatrixMode (GL_PROJECTION); 
+    glPopMatrix();
+    glMatrixMode (GL_MODELVIEW); 
+    glPopMatrix();
+    glEnable (GL_DEPTH_TEST);
+  }
+
+
+  void VisualScene :: DrawNetgenLogo ()
+  {
+    if (!vispar.drawnetgenlogo) return;
+
+    glDisable (GL_DEPTH_TEST);
+    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 (-7.0, 2.0, 0.0);
+
+    glDisable (GL_CLIP_PLANE0);
+    glDisable (GL_LIGHTING);
+
+    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[] = "Netgen " PACKAGE_VERSION;
+
+    glRasterPos3d (0.0f, 0.0f, 0.0f);
+    // glCallLists (GLsizei(strlen (buf)), GL_UNSIGNED_BYTE, buf);
+    MyOpenGLText (buf);
+
+    glPopAttrib ();
+
+    glEnable (GL_LIGHTING);
+    glMatrixMode (GL_PROJECTION); 
+    glPopMatrix();
+    glMatrixMode (GL_MODELVIEW); 
+    glPopMatrix();
+    glEnable (GL_DEPTH_TEST);
+  }
+
+
+
+
+
+
+
+#ifdef PARALLELGL
+  void VisualScene :: InitParallelGL ()
+  {
+    static int init = 0;
+
+    if (!init)
+      {
+	init = 1;
+
+	if (id == 0)
+	  {
+	    string displname;
+	    
+	    Display * dpy = glXGetCurrentDisplay();
+	    GLXDrawable drawable = glXGetCurrentDrawable();
+	    GLXContext ctx = glXGetCurrentContext();
+	    GLXContextID xid = glXGetContextIDEXT (ctx);
+	    
+	    displname = XDisplayName (0);
+	    /*
+
+	    cout << "Init Parallel GL" << endl;
+	    cout << "DisplayName = " << displname << endl;
+	    cout << "current display = " << dpy << endl;
+	    cout << "current drawable = " << drawable << endl;                  
+	    cout << "current context = " << ctx << endl;                  
+	    
+	    cout << "contextid = " << xid << endl;
+	    cout << "isdirect = " << glXIsDirect ( dpy, ctx ) << endl;                  
+	    cout << "extensionstring = " << glXQueryExtensionsString( dpy, 0 ) << endl;
+	    */
+
+	    MyMPI_SendCmd ("redraw");
+	    MyMPI_SendCmd ("init");
+		
+	    for (int dest = 1; dest < ntasks; dest++)
+	      {
+		MyMPI_Send (displname, dest, MPI_TAG_VIS);
+		MyMPI_Send (int (drawable), dest, MPI_TAG_VIS);
+		MyMPI_Send (int (xid), dest, MPI_TAG_VIS);
+	      } 
+	  }
+      }
+  }
+
+
+  void VisualScene :: Broadcast ()
+  {
+    if (ntasks == 1) return;
+
+    if (id == 0)
+      {
+	/*
+	for (int dest = 1; dest < ntasks; dest++)
+	  {
+	    MyMPI_Send ("redraw", dest, MPI_TAG_CMD);
+	    MyMPI_Send ("broadcast", dest, MPI_TAG_VIS);
+	  }
+	*/
+
+	MyMPI_SendCmd ("redraw");
+	MyMPI_SendCmd ("broadcast");
+      }
+
+    MyMPI_Bcast (selface);
+
+    vssolution.Broadcast ();
+  }
+#endif 
+
+}
diff --git a/contrib/Netgen/libsrc/visualization/mvdraw.hpp b/contrib/Netgen/libsrc/visualization/mvdraw.hpp
new file mode 100644
index 0000000000..211227cdec
--- /dev/null
+++ b/contrib/Netgen/libsrc/visualization/mvdraw.hpp
@@ -0,0 +1,245 @@
+#ifndef FILE_MVDRAW
+#define FILE_MVDRAW
+
+
+namespace netgen
+{
+
+  /*
+  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 DLL_HEADER Point3d center;
+    static DLL_HEADER double rad;
+
+    static float lookatmat[16];
+    static float transmat[16];
+    static float rotmat[16];
+    static float centermat[16];
+    static DLL_HEADER float transformationmat[16];
+
+    GLdouble clipplane[4];
+
+    int changeval;
+    static DLL_HEADER GLdouble backcolor;
+
+    static int selface;
+    static int selelement;
+    static int selpoint;
+    static int selpoint2;
+    static int locpi;
+    static int seledge;
+
+    static int selecttimestamp;
+
+  public:
+
+    // static GLubyte * colortexture;
+    static GLuint coltexname;
+    static int ntexcols;
+    // static bool linear_colors;
+    int invcolor;
+
+
+  public:
+    DLL_HEADER VisualScene ();
+    DLL_HEADER virtual ~VisualScene();
+
+    DLL_HEADER virtual void BuildScene (int zoomall = 0);
+    DLL_HEADER virtual void DrawScene ();
+  
+    DLL_HEADER void CalcTransformationMatrices();
+    DLL_HEADER void StandardRotation (const char * dir);
+    DLL_HEADER void ArbitraryRotation (const Array<double> & alpha, const Array<Vec3d> & vec);
+    DLL_HEADER void ArbitraryRotation (const double alpha, const Vec3d & vec);
+
+    DLL_HEADER void MouseMove(int oldx, int oldy,
+                   int newx, int newy,
+                   char mode);
+
+    DLL_HEADER void LookAt (const Point<3> & cam, const Point<3> & obj,
+                 const Point<3> & camup);
+
+    DLL_HEADER void SetClippingPlane ();
+
+    DLL_HEADER virtual void MouseDblClick (int px, int py);
+
+    DLL_HEADER void SetLight ();
+    static void SetBackGroundColor (double col)
+    { backcolor = col; }
+
+    DLL_HEADER void CreateTexture (int ncols, int linear, int typ = GL_DECAL);
+    DLL_HEADER void DrawColorBar (double minval, double maxval, int logscale = 0, bool linear = 1);
+    DLL_HEADER void DrawCoordinateCross ();
+    DLL_HEADER void DrawNetgenLogo ();
+    DLL_HEADER void SetOpenGlColor(double val, double valmin, double valmax, int logscale = 0);
+
+
+#ifdef PARALLELGL
+    DLL_HEADER void InitParallelGL ();
+    DLL_HEADER void Broadcast ();
+#endif 
+  };
+
+
+  extern void MyOpenGLText (const char * text);
+
+
+
+
+
+
+
+
+
+
+
+  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 edgelist;
+    int pointnumberlist;
+
+    int tetlist;
+    int prismlist;
+    int pyramidlist;
+    int hexlist;
+
+    int badellist;
+    int identifiedlist;
+    int domainsurflist;
+
+    int vstimestamp;//, selecttimestamp;
+    int filledtimestamp;
+    int linetimestamp;
+    int edgetimestamp;
+    int pointnumbertimestamp;
+
+    int tettimestamp;
+    int prismtimestamp;
+    int pyramidtimestamp;
+    int hextimestamp;
+
+    int badeltimestamp;
+    int identifiedtimestamp;
+    int domainsurftimestamp;
+
+
+#ifdef PARALLELGL
+    Array<int> par_linelists;
+    Array<int> par_filledlists;
+#endif
+
+
+    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; }
+    void BuildFilledList (bool names);
+    // private:
+    void BuildLineList();
+    void BuildEdgeList();
+    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);
+
+
+  void MouseDblClickSelect (const int px, const int py,
+                            const GLdouble * clipplane, const GLdouble backcolor,
+                            const float * transformationmat,
+                            const Point3d & center,
+                            const double rad,
+                            const int displaylist,
+                            int & selelement, int & selface, int & seledge, int & selpoint,
+                            int & selpoint2, int & locpi);
+
+
+}
+
+
+#endif
+
diff --git a/contrib/Netgen/libsrc/visualization/soldata.hpp b/contrib/Netgen/libsrc/visualization/soldata.hpp
new file mode 100644
index 0000000000..65d05ddafc
--- /dev/null
+++ b/contrib/Netgen/libsrc/visualization/soldata.hpp
@@ -0,0 +1,111 @@
+#ifndef FILE_SOLDATA
+#define FILE_SOLDATA
+
+
+namespace netgen
+{
+
+  using namespace std;
+
+  class DLL_HEADER SolutionData
+  {
+  protected:
+
+    string name;
+    int components;
+    bool iscomplex;
+
+    int multidimcomponent;
+
+  public:
+    SolutionData (const 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 false; 
+    }
+
+    virtual bool GetValue (int selnr,
+                           const double xref[], const double x[], const double dxdxref[],
+                           double * values)
+    {
+      return GetValue (selnr, xref[0], xref[1], xref[2], values); 
+    }
+
+    virtual bool GetMultiValue (int elnr, int npts,
+				const double * xref, int sxref,
+				const double * x, int sx,
+				const double * dxdxref, int sdxdxref,
+				double * values, int svalues)
+    {
+      bool res = false;
+      for (int i = 0; i < npts; i++)
+	res = GetValue (elnr, &xref[i*sxref], &x[i*sx], &dxdxref[i*sdxdxref], &values[i*svalues]);
+      return res;
+    }
+
+
+
+    virtual bool GetSurfValue (int /* selnr */,
+                               double /* lam1 */, double /* lam2 */, 
+                               double * /* values */)
+    { 
+      return false; 
+    }
+
+
+    virtual bool GetSurfValue (int selnr,
+                               const double xref[], const double x[], const double dxdxref[],
+                               double * values)
+    { 
+      return GetSurfValue (selnr, xref[0], xref[1], values); 
+    }
+
+
+    virtual bool GetMultiSurfValue (int selnr, int npts,
+                                    const double * xref, int sxref,
+                                    const double * x, int sx,
+                                    const double * dxdxref, int sdxdxref,
+                                    double * values, int svalues)
+    {
+      bool res = false;
+      for (int i = 0; i < npts; i++)
+	res = GetSurfValue (selnr, &xref[i*sxref], &x[i*sx], &dxdxref[i*sdxdxref], &values[i*svalues]);
+      return res;
+    }
+
+
+    virtual int GetNumMultiDimComponents ()
+    {
+      return 1;
+    }
+
+    void SetMultiDimComponent (int mc)
+    { 
+      if (mc >= GetNumMultiDimComponents()) mc = GetNumMultiDimComponents()-1;
+      if (mc < 0) mc = 0;
+      multidimcomponent = mc; 
+    }
+  };
+}
+
+#endif
+
diff --git a/contrib/Netgen/libsrc/visualization/stlmeshing.cpp b/contrib/Netgen/libsrc/visualization/stlmeshing.cpp
new file mode 100644
index 0000000000..452dbd928b
--- /dev/null
+++ b/contrib/Netgen/libsrc/visualization/stlmeshing.cpp
@@ -0,0 +1,1076 @@
+#include <mystdlib.h>
+#include <myadt.hpp>
+
+#include <linalg.hpp>
+#include <stlgeom.hpp>
+
+#include <meshing.hpp>
+#ifndef NOTCL
+#include <visual.hpp>
+#endif
+
+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 = 0.0, hmax = 1.0;
+
+  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.9f, 0.0f, 0.0f, 1.0f };
+  float mat_colgreen[]  = { 0.0f, 0.9f, 0.0f, 1.0f };
+  float mat_colblue[]   = { 0.1f, 0.1f, 1.0f, 1.0f };
+
+  float mat_colbluegreen[] = { 0.1f, 0.5f, 0.9f, 1.0f };
+  // float mat_colpink[]      = { 1.0f, 0.1f, 0.5f, 1.0f };
+  float mat_colviolet[]    = { 1.0f, 0.1f, 1.0f, 1.0f };
+  float mat_colbrown[]     = { 0.8f, 0.6f, 0.1f, 1.0f };
+  // float mat_colorange[]    = { 0.9f, 0.7f, 0.1f, 1.0f };
+  // float mat_colturquis[]   = { 0.0f, 1.0f, 0.8f, 1.0f };
+
+  float mat_colgrey[] = { 0.3f, 0.3f, 0.3f, 1.0f };
+
+  float mat_collred[]   = { 1.0f, 0.5f, 0.5f, 1.0f };
+  float mat_collgreen[] = { 0.2f, 1.9f, 0.2f, 1.0f };
+  float mat_collbrown[] = { 1.0f, 0.8f, 0.3f, 1.0f };
+
+  float mat_collgrey[] = { 0.8f, 0.8f, 0.8f, 1.0f };
+  // float mat_colmgrey[] = { 0.4f, 0.4f, 0.4f, 1.0f };
+
+  float mat_colstlbody[] = { 0.0f, 0.0f, 0.8f, 1.0f };
+  float mat_colseltrig[] = { 0.7f, 0.7f, 0.3f, 1.0f };
+  float mat_colseledge[] = { 0.7f, 0.7f, 1.0f, 1.0f };
+
+  glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_colblue);
+
+  float pgoff = 0.5f;
+
+  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.2f, 0.2f, 0.2f, 1.f };
+	  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)
+{
+  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/contrib/Netgen/libsrc/visualization/vispar.hpp b/contrib/Netgen/libsrc/visualization/vispar.hpp
new file mode 100644
index 0000000000..da13982633
--- /dev/null
+++ b/contrib/Netgen/libsrc/visualization/vispar.hpp
@@ -0,0 +1,106 @@
+#ifndef FILE_VISPAR
+#define FILE_VISPAR
+
+namespace netgen
+{
+
+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 clipdomain;
+  int donotclipdomain;
+
+  int drawededges;
+  int drawedpoints;
+  int drawedpointnrs;
+  int drawedtangents;
+  int drawededgenrs;
+  int drawmetispartition;
+
+  int drawcurveproj;
+  int drawcurveprojedge;
+  
+
+  int centerpoint;
+  int drawelement;
+
+  // stl:
+  int stlshowtrias;
+  int stlshowfilledtrias;
+  int stlshowedges;
+  int stlshowmarktrias;
+  int stlshowactivechart;
+  int stlchartnumber;
+  int stlchartnumberoffset;
+
+  // occ:
+  int occshowvolumenr;
+  bool occshowsurfaces;
+  bool occshowedges;
+  bool occvisproblemfaces;
+  bool occzoomtohighlightedentity;
+  double occdeflection;
+
+  // ACIS
+
+  bool ACISshowfaces;
+  bool ACISshowedges;
+  int ACISshowsolidnr;
+  int ACISshowsolidnr2;
+
+  bool whitebackground;
+  int stereo;
+  bool usedispllists;
+  bool drawcoordinatecross;
+  bool drawcolorbar;
+  bool drawnetgenlogo;
+
+  bool use_center_coords;
+  double centerx,centery,centerz;
+
+  bool drawspecpoint;
+  double specpointx,specpointy,specpointz;
+
+  
+public:
+  VisualizationParameters();
+};
+extern VisualizationParameters vispar;
+}
+
+#endif
diff --git a/contrib/Netgen/libsrc/visualization/visual.hpp b/contrib/Netgen/libsrc/visualization/visual.hpp
new file mode 100644
index 0000000000..405c5b6be3
--- /dev/null
+++ b/contrib/Netgen/libsrc/visualization/visual.hpp
@@ -0,0 +1,35 @@
+#ifndef FILE_VISUAL
+#define FILE_VISUAL
+
+/* *************************************************************************/
+/* File:   visual.hpp                                                       */
+/* Author: Joachim Schoeberl                                               */
+/* Date:   02. Dec. 01                                                     */
+/* *************************************************************************/
+
+/* 
+
+Visualization
+
+*/
+
+#ifdef PARALLEL
+#define PARALLELGL
+#endif
+
+#include "../include/incvis.hpp"
+
+#include "vispar.hpp"
+#include "mvdraw.hpp"
+#include "soldata.hpp"
+
+#include <complex>
+
+namespace netgen
+{
+#include "vssolution.hpp"
+#include "meshdoc.hpp"
+}
+
+
+#endif
diff --git a/contrib/Netgen/libsrc/visualization/vscsg.cpp b/contrib/Netgen/libsrc/visualization/vscsg.cpp
new file mode 100644
index 0000000000..f4ef67d7c5
--- /dev/null
+++ b/contrib/Netgen/libsrc/visualization/vscsg.cpp
@@ -0,0 +1,272 @@
+#ifndef NOTCL
+
+#include <mystdlib.h>
+#include "incvis.hpp"
+
+#include <myadt.hpp>
+#include <meshing.hpp>
+#include <csg.hpp>
+#include <stlgeom.hpp>
+
+#include <visual.hpp>
+
+
+namespace netgen
+{
+
+/* *********************** Draw Geometry **************** */
+
+  extern Array<Point<3> > project1, project2;
+
+
+extern AutoPtr<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);
+
+  /*
+  cout << "draw " << project1.Size() << " lines " << endl;
+  glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
+  glLineWidth (1.0f);
+  glEnable (GL_COLOR_MATERIAL);
+
+  glColor3f (1.0f, 0.0f, 0.0f);
+
+  glBegin (GL_LINES);
+  for (int i = 0; i < project1.Size(); i++)
+    {
+      glVertex3dv (project1[i]);
+      glVertex3dv (project2[i]);
+    }
+  glEnd();
+  */
+
+
+  glPopMatrix();
+  glDisable(GL_CLIP_PLANE0);
+ 
+
+
+  /*
+  glFlush();
+  
+  int err;
+  do
+    {
+      err = glGetError();
+      // cout << "glerr,1 = " << err << endl;
+    }
+  while (err != GL_NO_ERROR);
+
+
+  // CreateTexture (0, 1, GL_DECAL);
+  CreateTexture (0, 1, GL_MODULATE);
+  glEnable (GL_TEXTURE_1D);
+
+  float mat_col[] = { 1.0, 1.0, 1.0 }; 
+  glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_col);
+
+  glDisable (GL_BLEND);
+  glDisable (GL_COLOR_MATERIAL);
+  glEnable (GL_NORMALIZE);
+
+  if (geometry->GetNTopLevelObjects())
+    {
+      cout << "call list" << endl;
+      glCallList (trilists[0]);
+    }
+
+  glColor3d (1.0, 1.0, 1.0);
+  
+  glBegin (GL_TRIANGLES);
+  glNormal3f (0, 0, 1);
+  SetOpenGlColor  (-1.0, 0, 1, 0);
+  glVertex3f (0.0, 0.0, 0.0);
+  SetOpenGlColor  (0.5, 0, 1, 0);
+  glNormal3f (0, 0, 1);
+  glVertex3f (1.0, 0.0, 0.0);
+  SetOpenGlColor  (2.0, 0, 1, 0);
+  glNormal3f (0, 0, 1);
+  glVertex3f (0.0, 1.0, 0.0);
+
+  glEnd ();
+
+  cout << "trig drawn" << endl;
+
+  glDisable (GL_TEXTURE_1D);
+  glDisable (GL_COLOR_MATERIAL);
+  glFlush();
+
+  cout << "glerr,2 = " << glGetError() << endl;
+  */
+
+
+
+  DrawCoordinateCross ();
+  DrawNetgenLogo ();  
+
+  glFinish();  
+}
+
+
+void VisualSceneGeometry :: BuildScene (int zoomall)
+{
+  Box<3> box;
+  int hasp = 0;
+  for (int i = 0; i < geometry->GetNTopLevelObjects(); i++)
+    {
+      const TriangleApproximation & ta =
+	*geometry->GetTriApprox(i);
+      if (!&ta) continue;
+
+      for (int 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 (int i = 0; i < trilists.Size(); i++)
+    glDeleteLists (trilists[i], 1);
+  trilists.SetSize(0);
+
+  for (int 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 (int j = 0; j < ta.GetNT(); j++)
+	    {
+	      for (int k = 0; k < 3; k++)
+		{
+		  int pi = ta.GetTriangle(j)[k];
+		  glNormal3dv (ta.GetNormal (pi));
+		  glVertex3dv (ta.GetPoint(pi));
+		}
+	    }
+	  glEnd ();
+	}
+      glEndList ();
+    }
+
+}
+
+
+
+
+
+}
+
+
+#endif // NOTCL
diff --git a/contrib/Netgen/libsrc/visualization/vsfieldlines.cpp b/contrib/Netgen/libsrc/visualization/vsfieldlines.cpp
new file mode 100644
index 0000000000..e7201a483d
--- /dev/null
+++ b/contrib/Netgen/libsrc/visualization/vsfieldlines.cpp
@@ -0,0 +1,729 @@
+#ifndef NOTCL
+
+#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;
+
+
+  
+  RKStepper :: ~RKStepper() 
+  {
+    delete a;
+  }
+    
+  RKStepper :: RKStepper(int type) : a(NULL), tolerance(1e100)
+  {
+    notrestarted = 0;
+
+    if (type == 0) // explicit Euler
+      {
+	c.SetSize(1); c[0] = 0;
+	b.SetSize(1); b[0] = 1;
+	steps = order = 1;
+      }
+    else if (type == 1) // Euler-Cauchy
+      {
+	c.SetSize(2); c[0] = 0; c[1] = 0.5;
+	b.SetSize(2); b[0] = 0; b[1] = 1;
+	Array<int> size(2);
+	size[0] = 0; size[1] = 1;
+	a = new TABLE<double>(size);
+	a->Set(2,1,0.5);  // Set, Get: 1-based!
+	steps = order = 2;
+      }
+    else if (type == 2) // Simpson
+      {
+	c.SetSize(3); c[0] = 0; c[1] = 1; c[2] = 0.5;
+	b.SetSize(3); b[0] = b[1] = 1./6.; b[2] = 2./3.;
+	Array<int> size(3);
+	size[0] = 0; size[1] = 1; size[2] = 2;
+	a = new TABLE<double>(size);
+	a->Set(2,1,1);
+	a->Set(3,1,0.25); a->Set(3,2,0.25); 
+	steps = order = 3;
+      }
+    else if (type == 3) // classical Runge-Kutta
+      {
+	c.SetSize(4); c[0] = 0; c[1] = c[2] = 0.5; c[3] = 1;
+	b.SetSize(4); b[0] = b[3] = 1./6.; b[1] = b[2] = 1./3.;
+	Array<int> size(4);
+	size[0] = 0; size[1] = 1; size[2] = 2; size[3] = 3;
+	a = new TABLE<double>(size);
+	a->Set(2,1,0.5);
+	a->Set(3,1,0); a->Set(3,2,0.5); 
+	a->Set(4,1,0); a->Set(4,2,0); a->Set(4,3,1); 
+	steps = order = 4;
+      }
+    
+    K.SetSize(steps);
+  }
+
+  void RKStepper :: StartNextValCalc(const Point3d & astartval, const double astartt, const double ah, const bool aadaptive)
+  {
+    //cout << "Starting RK-Step with h=" << ah << endl;
+
+    stepcount = 0;
+    h = ah;
+    startt = astartt;
+    startval = astartval;
+    adaptive = aadaptive;
+    adrun = 0;
+  }
+
+  bool RKStepper :: GetNextData(Point3d & val, double & t, double & ah)
+  {
+    bool finished(false);
+    
+    
+    //cout << "stepcount " << stepcount << endl;
+    
+    if(stepcount <= steps)
+      {
+	t = startt + c[stepcount-1]*h;
+	val = startval;
+	for(int i=0; i<stepcount-1; i++)
+	  val += h * a->Get(stepcount,i+1) * K[i];
+      }
+    
+    
+    if(stepcount == steps)
+      {
+	val = startval;
+	for(int i=0; i<steps; i++)
+	  val += h * b[i] * K[i];
+	
+	if(adaptive)
+	  {
+	    if(adrun == 0)
+	      {
+		stepcount = 0;
+		h *= 0.5;
+		adrun = 1;
+		valh = val;
+	      }
+	    else if (adrun == 1)
+	      {
+		stepcount = 0;
+		startval_bak = startval;
+		startval = val;
+		startt_bak = startt;
+		startt += h;//0.5*h;
+		adrun = 2;
+	      }
+	    else if (adrun == 2)
+	      {
+		Point3d valh2 = val;
+		val = valh2 + 1./(pow(2.,order)-1.) * (valh2 - valh);
+		Vec3d errvec = val - valh;
+		
+		double err = errvec.Length();
+		
+		double fac = 0.7 * pow(tolerance/err,1./(order+1.));
+		if(fac > 1.3) fac = 1.3;
+		
+		if(fac < 1 || notrestarted >= 2)
+		  ah = 2.*h * fac;
+		
+		if(err < tolerance) 
+		  {
+		    finished = true;
+		    notrestarted++;
+		    //(*testout) << "finished RK-Step, new h=" << ah << " tolerance " << tolerance << " err " << err << endl;
+		  }
+		else
+		  {
+		    //ah *= 0.9;
+		    notrestarted = 0;
+		    //(*testout) << "restarting h " << 2.*h << " ah " << ah << " tolerance " << tolerance << " err " << err << endl;
+		    StartNextValCalc(startval_bak,startt_bak, ah, adaptive);
+		  }
+	      }
+	  }
+	else 
+	  {
+	    t = startt + h;
+	    finished = true;
+	  }
+	
+      }
+    
+    if(stepcount == 0)
+      {
+	t = startt + c[stepcount]*h;
+	val = startval;
+	for(int i=0; i<stepcount; i++)
+	  val += h * a->Get(stepcount,i) * K[i];
+      }
+    
+    return finished;
+  }
+
+
+  bool RKStepper :: FeedNextF(const Vec3d & f)
+  {
+    K[stepcount] = f;
+    stepcount++;
+    return true;
+  }
+  
+
+
+  void FieldLineCalc :: GenerateFieldLines(Array<Point3d> & potential_startpoints, const int numlines, const int gllist,
+					   const double minval, const double maxval, const int logscale, double phaser, double phasei)
+  {
+
+    
+    Array<Point3d> points;
+    Array<double> values;
+    Array<bool> drawelems;
+    Array<int> dirstart;
+
+
+    if(vsol -> iscomplex)
+      SetPhase(phaser,phasei);
+
+    double crit = 1.0;
+
+    if(randomized)
+      {
+	double sum = 0;
+	double lami[3];
+	double values[6];
+	Vec3d v;
+	
+	for(int i=0; i<potential_startpoints.Size(); i++)
+	  {
+	    int elnr = mesh.GetElementOfPoint(potential_startpoints[i],lami,true) - 1;
+	    if(elnr == -1)
+	      continue;
+
+	    mesh.SetPointSearchStartElement(elnr);
+	    
+	    if (mesh.GetDimension()==3)
+              vss.GetValues ( vsol, elnr, lami[0], lami[1], lami[2], values);
+            else
+              vss.GetSurfValues ( vsol, elnr, lami[0], lami[1], values);
+              
+	    
+	    VisualSceneSolution::RealVec3d ( values, v, vsol->iscomplex, phaser, phasei);
+	    
+	    sum += v.Length();
+	  }
+
+	crit = sum/double(numlines);
+      }
+
+
+    int calculated = 0;
+
+    cout << endl;
+
+
+
+
+    for(int i=0; i<potential_startpoints.Size(); i++)
+      {
+	cout << "\rFieldline Calculation " << int(100.*i/potential_startpoints.Size()) << "%"; cout.flush();
+
+	if(randomized)
+	  SetCriticalValue((double(rand())/RAND_MAX)*crit);
+
+	if(calculated >= numlines) break;
+
+	Calc(potential_startpoints[i],points,values,drawelems,dirstart);
+
+	bool usable = false;
+
+	for(int j=1; j<dirstart.Size(); j++)
+	  for(int k=dirstart[j-1]; k<dirstart[j]-1; k++)
+	    {
+	      if(!drawelems[k] || !drawelems[k+1]) continue;
+	     
+	      usable = true;
+ 
+	      // vss.SetOpenGlColor  (0.5*(values[k]+values[k+1]), minval, maxval, logscale);
+              
+              /*
+              if (vss.usetexture == 1)
+                glTexCoord1f ( 0.5*(values[k]+values[k+1]) );
+              else
+              */
+              vss.SetOpenGlColor  (0.5*(values[k]+values[k+1]) );
+	      vss.DrawCylinder (points[k], points[k+1], thickness);
+	    }
+
+	if(usable) calculated++;
+      }
+    cout << "\rFieldline Calculation " << 100 << "%" << endl;
+    
+  }
+
+
+
+  FieldLineCalc :: FieldLineCalc(const Mesh & amesh, VisualSceneSolution & avss, const VisualSceneSolution::SolData * solution, 
+				 const double rel_length, const int amaxpoints, 
+				 const double rel_thickness, const double rel_tolerance, const int rk_type, const int adirection) :
+    mesh(amesh), vss(avss), vsol(solution), stepper(rk_type)
+  {
+    mesh.GetBox (pmin, pmax);
+    rad = 0.5 * Dist (pmin, pmax);
+    
+
+    maxlength = (rel_length > 0) ? rel_length : 0.5;
+    maxlength *= 2.*rad;
+
+    thickness = (rel_thickness > 0) ? rel_thickness : 0.0015;
+    thickness *= 2.*rad;
+    
+    double auxtolerance = (rel_tolerance > 0) ? rel_tolerance : 1.5e-3;
+    auxtolerance *= 2.*rad;
+
+    stepper.SetTolerance(auxtolerance);
+    
+    direction = adirection;
+    
+    
+    maxpoints = amaxpoints;
+
+    if(direction == 0)
+      {
+	maxlength *= 0.5;
+	maxpoints /= 2;
+      }
+    
+
+    phaser = 1;
+    phasei = 0;
+    
+    critical_value = -1;
+
+    randomized = false;
+    
+  }
+  
+
+
+  
+  void FieldLineCalc :: Calc(const Point3d & startpoint, Array<Point3d> & points, Array<double> & vals, Array<bool> & drawelems, Array<int> & dirstart)
+  {
+    double lami[3], startlami[3];
+    double values[6];
+    double dummyt(0);
+    Vec3d v;
+    Vec3d startv;
+    Point3d newp;
+    double h;
+    
+    double startval;
+    bool startdraw;
+    bool drawelem = false;
+    int elnr;
+
+    for (int i=0; i<6; i++) values[i]=0.0;
+    for (int i=0; i<3; i++) lami[i]=0.0;
+    for (int i=0; i<3; i++) startlami[i]=0.0;
+    
+    points.SetSize(0);
+    vals.SetSize(0);
+    drawelems.SetSize(0);
+
+    dirstart.SetSize(0);
+    dirstart.Append(0);
+
+
+    int startelnr = mesh.GetElementOfPoint(startpoint,startlami,true) - 1;
+    (*testout) << "p = " << startpoint << "; elnr = " << startelnr << endl;
+    if (startelnr == -1)
+      return;
+      
+    mesh.SetPointSearchStartElement(startelnr);
+
+    if (mesh.GetDimension()==3)
+      startdraw = vss.GetValues ( vsol, startelnr, startlami[0], startlami[1], startlami[2], values);
+    else
+      startdraw = vss.GetSurfValues ( vsol, startelnr, startlami[0], startlami[1], values);
+
+    VisualSceneSolution::RealVec3d ( values, startv, vsol->iscomplex, phaser, phasei);
+
+    startval = startv.Length();
+
+    if(critical_value > 0 && fabs(startval) < critical_value)
+      return;
+
+    //cout << "p = " << startpoint << "; elnr = " << startelnr << endl;
+
+
+      
+    for(int dir = 1; dir >= -1; dir -= 2)
+      {
+	if(dir*direction < 0) continue;
+	  
+	points.Append(startpoint);
+	vals.Append(startval);
+	drawelems.Append(startdraw);
+	  
+	h = 0.001*rad/startval; // otherwise no nice lines; should be made accessible from outside
+	
+	v = startv;
+	if(dir == -1) v *= -1.;
+
+	elnr = startelnr;
+	lami[0] = startlami[0]; lami[1] = startlami[1]; lami[2] = startlami[2]; 
+	  
+
+	for(double length = 0; length < maxlength; length += h*vals.Last())
+	  {
+	    if(v.Length() < 1e-12*rad)
+	      {
+		(*testout) << "Current fieldlinecalculation came to a stillstand at " << points.Last() << endl;
+		break;
+	      }
+
+	    stepper.StartNextValCalc(points.Last(),dummyt,h,true);
+	    stepper.FeedNextF(v);
+
+	    while(!stepper.GetNextData(newp,dummyt,h) && elnr != -1)
+	      {
+		elnr = mesh.GetElementOfPoint(newp,lami,true) - 1;
+		if(elnr != -1)
+		  {
+		    mesh.SetPointSearchStartElement(elnr);
+                    if (mesh.GetDimension()==3)
+                        drawelem = vss.GetValues (vsol, elnr, lami[0], lami[1], lami[2], values);
+                    else
+                      drawelem = vss.GetSurfValues (vsol, elnr, lami[0], lami[1], values);
+
+		    VisualSceneSolution::RealVec3d (values, v, vsol->iscomplex, phaser, phasei);
+		    if(dir == -1) v *= -1.;
+		    stepper.FeedNextF(v);
+		  }
+	      }
+
+	    if (elnr == -1)
+	      {
+		//cout << "direction " <<dir << " reached the wall." << endl;
+		break;
+	      }
+
+	    points.Append(newp);
+	    vals.Append(v.Length());
+	    drawelems.Append(drawelem);
+
+	    if(points.Size() % 40 == 0 && points.Size() > 1)
+	      (*testout) << "Points in current fieldline: " << points.Size() << ", current position: " << newp << endl;
+
+	    if(maxpoints > 0 && points.Size() >= maxpoints)
+	      {
+		break;
+	      }
+
+	    //cout << "length " << length << " h " << h << " vals.Last() " << vals.Last()  << " maxlength " << maxlength << endl;
+	  }
+	dirstart.Append(points.Size());
+      }
+  }
+
+
+
+
+  
+  void VisualSceneSolution :: BuildFieldLinesFromBox(Array<Point3d> & startpoints)
+  {
+    if(fieldlines_startarea_parameter[0] > fieldlines_startarea_parameter[3] ||
+       fieldlines_startarea_parameter[1] > fieldlines_startarea_parameter[4] ||
+       fieldlines_startarea_parameter[2] > fieldlines_startarea_parameter[5])
+      {
+	Point3d pmin, pmax;
+	mesh->GetBox (pmin, pmax);
+	
+	fieldlines_startarea_parameter[0] = pmin.X();	
+	fieldlines_startarea_parameter[1] = pmin.Y();
+	fieldlines_startarea_parameter[2] = pmin.Z();
+	fieldlines_startarea_parameter[3] = pmax.X();	
+	fieldlines_startarea_parameter[4] = pmax.Y();
+	fieldlines_startarea_parameter[5] = pmax.Z();
+      }
+    
+    for (int i = 1; i <= startpoints.Size(); i++)
+      {
+	Point3d p (fieldlines_startarea_parameter[0] + double (rand()) / RAND_MAX * (fieldlines_startarea_parameter[3]-fieldlines_startarea_parameter[0]),
+		   fieldlines_startarea_parameter[1] + double (rand()) / RAND_MAX * (fieldlines_startarea_parameter[4]-fieldlines_startarea_parameter[1]),
+		   fieldlines_startarea_parameter[2] + double (rand()) / RAND_MAX * (fieldlines_startarea_parameter[5]-fieldlines_startarea_parameter[2]));
+	
+	startpoints[i-1] = p;
+      }
+  }
+
+  void VisualSceneSolution :: BuildFieldLinesFromLine(Array<Point3d> & startpoints)
+  {
+    for (int i = 1; i <= startpoints.Size(); i++)
+      {
+	double s = double (rand()) / RAND_MAX;
+
+	Point3d p (fieldlines_startarea_parameter[0] + s * (fieldlines_startarea_parameter[3]-fieldlines_startarea_parameter[0]),
+		   fieldlines_startarea_parameter[1] + s * (fieldlines_startarea_parameter[4]-fieldlines_startarea_parameter[1]),
+		   fieldlines_startarea_parameter[2] + s * (fieldlines_startarea_parameter[5]-fieldlines_startarea_parameter[2]));
+	
+	startpoints[i-1] = p;
+      }
+  }
+
+
+  void VisualSceneSolution :: BuildFieldLinesFromFile(Array<Point3d> & startpoints)
+  {
+    ifstream * infile;
+
+    infile = new ifstream(fieldlines_filename.c_str());
+
+    //cout << "reading from file " << fieldlines_filename << endl;
+
+    int numpoints = 0;
+
+    string keyword;
+
+    
+    double dparam;
+    int iparam;
+
+    while(infile->good())
+      {
+	(*infile) >> keyword;
+
+	if(keyword == "point") numpoints++;
+	else if(keyword == "line" || keyword == "box")
+	  {
+	    for(int i=0; i<6; i++) (*infile) >> dparam;
+	    (*infile) >> iparam;
+	    numpoints += iparam;
+	  }
+      }
+
+    delete infile;
+
+
+    //cout << numpoints << " startpoints" << endl;
+
+    startpoints.SetSize(numpoints);
+    
+    infile = new ifstream(fieldlines_filename.c_str());
+
+    numpoints = 0;
+
+    while(infile->good())
+      {
+	(*infile) >> keyword;
+
+	if (keyword == "point")
+	  {
+	    (*infile) >> startpoints[numpoints].X(); (*infile) >> startpoints[numpoints].Y(); (*infile) >> startpoints[numpoints].Z();
+	    numpoints++;
+	  }
+	else if (keyword == "line" || keyword == "box")
+	  {
+	    for(int i=0; i<6; i++) (*infile) >> fieldlines_startarea_parameter[i];
+	    (*infile) >> iparam;
+
+	    Array<Point3d> auxpoints(iparam);
+	    
+	    if (keyword == "box")
+	      BuildFieldLinesFromBox(auxpoints);
+	    else if (keyword == "line")
+	      BuildFieldLinesFromLine(auxpoints);
+	    
+	    for(int i=0; i<iparam; i++)
+	      {
+		startpoints[numpoints] = auxpoints[i];
+		numpoints++;
+	      }
+	  }
+
+	//cout << "startpoints " << startpoints << endl;
+      }
+
+    delete infile;
+    
+    
+
+    
+  }
+
+  
+  void VisualSceneSolution :: BuildFieldLinesFromFace(Array<Point3d> & startpoints)
+  {
+    Array<SurfaceElementIndex> elements_2d;
+    
+    //cout << "fieldlines_startface " << fieldlines_startface << endl;
+    mesh->GetSurfaceElementsOfFace(fieldlines_startface,elements_2d);
+    if(elements_2d.Size() == 0)
+      {
+	cerr << "No Elements on selected face (?)" << endl;
+	return;
+      }
+    Vec3d v1,v2,cross;
+    
+    double area = 0;
+
+	int i;
+    for(i=0; i<elements_2d.Size(); i++)
+      {
+	const Element2d & elem = mesh->SurfaceElement(elements_2d[i]);
+	
+	v1 = mesh->Point(elem[1]) - mesh->Point(elem[0]);
+	v2 = mesh->Point(elem[2]) - mesh->Point(elem[0]);
+	cross = Cross(v1,v2);
+	area += cross.Length();
+	
+	if(elem.GetNV() == 4)
+	  {
+	    v1 = mesh->Point(elem[2]) - mesh->Point(elem[0]);
+	    v2 = mesh->Point(elem[3]) - mesh->Point(elem[0]);
+	    cross = Cross(v1,v2);
+	    area += cross.Length();
+	  }
+      }
+    
+    int startpointsp = 0;
+    i = 0;
+    
+    while(startpointsp < startpoints.Size())
+      {
+	const Element2d & elem = mesh->SurfaceElement(elements_2d[i]);
+	
+	int numtri = (elem.GetNV() == 3) ? 1 : 2;
+	
+	for(int tri = 0; startpointsp < startpoints.Size() && tri<numtri; tri++)
+	  {
+	    
+	    if(tri == 0)
+	      {
+		v1 = mesh->Point(elem[1]) - mesh->Point(elem[0]);
+		v2 = mesh->Point(elem[2]) - mesh->Point(elem[0]);
+		cross = Cross(v1,v2);
+	      }
+	    else if(tri == 1)
+	      {
+		v1 = mesh->Point(elem[2]) - mesh->Point(elem[0]);
+		v2 = mesh->Point(elem[3]) - mesh->Point(elem[0]);
+		cross = Cross(v1,v2);
+	      }
+	    
+	    double thisarea = cross.Length();
+	    
+	    int numloc = int(startpoints.Size()*thisarea/area);
+	    if(double (rand()) / RAND_MAX < startpoints.Size()*thisarea/area - numloc)
+	      numloc++;
+	    
+	    for(int j=0; startpointsp < startpoints.Size() && j<numloc; j++)
+	      {
+		double s = double (rand()) / RAND_MAX;
+		double t = double (rand()) / RAND_MAX;
+		if(s+t > 1)
+		  {
+		    s = 1.-s; t = 1.-t;
+		  }
+		startpoints[startpointsp] = mesh->Point(elem[0]) + s*v1 +t*v2;
+		startpointsp++;
+	      }
+	  }
+	i++;
+	if(i == elements_2d.Size()) i = 0;
+      } 
+    
+  }
+
+
+  void VisualSceneSolution :: BuildFieldLinesPlot ()
+  {
+    if (fieldlinestimestamp >= solutiontimestamp) 
+      return;
+    fieldlinestimestamp = solutiontimestamp;
+    
+
+    if (fieldlineslist)
+      glDeleteLists (fieldlineslist, num_fieldlineslists);
+
+    if (vecfunction == -1)
+      return;
+
+    const SolData * vsol = soldata[fieldlines_vecfunction];
+
+    num_fieldlineslists = (vsol -> iscomplex && !fieldlines_fixedphase) ? 100 : 1;
+   
+
+    FieldLineCalc linecalc(*mesh,*this,vsol,
+			   fieldlines_rellength,fieldlines_maxpoints,fieldlines_relthickness,fieldlines_reltolerance,fieldlines_rktype);
+
+    if(fieldlines_randomstart) 
+      linecalc.Randomized();
+
+    fieldlineslist = glGenLists (num_fieldlineslists);
+
+    int num_startpoints = num_fieldlines / num_fieldlineslists;
+    if (num_fieldlines % num_fieldlineslists != 0) num_startpoints++;
+
+    if(fieldlines_randomstart)
+      num_startpoints *= 10;
+
+    
+    Array<Point3d> startpoints(num_startpoints);
+    
+
+    for (int ln = 0; ln < num_fieldlineslists; ln++)
+      {
+	if(fieldlines_startarea == 0)
+	  BuildFieldLinesFromBox(startpoints);
+	else if(fieldlines_startarea == 1)
+	  BuildFieldLinesFromFile(startpoints);
+	else if(fieldlines_startarea == 2)
+	  BuildFieldLinesFromFace(startpoints);
+
+
+	    
+	double phi;
+	
+	if(vsol -> iscomplex)
+	  {
+	    if(fieldlines_fixedphase)
+	      phi = fieldlines_phase;
+	    else
+	      phi = 2*M_PI*ln / num_fieldlineslists;
+	  }
+	else
+	  phi = 0;
+
+	cout << "phi = " << phi << endl;
+
+	double phaser = cos(phi), phasei = sin(phi);
+	
+
+        glNewList(fieldlineslist+ln, GL_COMPILE);
+        
+        SetTextureMode (usetexture);
+	linecalc.GenerateFieldLines(startpoints,num_fieldlines / num_fieldlineslists+1,
+				    fieldlineslist+ln,minval,maxval,logscale,phaser,phasei);
+
+        glEndList ();
+
+      }
+  }
+
+
+
+  
+}
+
+
+#endif // NOTCL
diff --git a/contrib/Netgen/libsrc/visualization/vsmesh.cpp b/contrib/Netgen/libsrc/visualization/vsmesh.cpp
new file mode 100644
index 0000000000..240a7e738a
--- /dev/null
+++ b/contrib/Netgen/libsrc/visualization/vsmesh.cpp
@@ -0,0 +1,3445 @@
+#include <mystdlib.h>
+
+#include <myadt.hpp>
+#include <meshing.hpp>
+// #include <csg.hpp>
+
+#ifdef STLGEOM
+#include <stlgeom.hpp>
+#endif
+
+
+// #include <parallel.hpp>
+
+#include <visual.hpp>
+
+namespace netgen
+{
+  extern AutoPtr<Mesh> mesh;
+  extern NetgenGeometry * ng_geometry;
+
+  VisualSceneMesh vsmesh;
+
+  VisualSceneMesh :: VisualSceneMesh ()
+    : VisualScene()
+  {
+    filledlist = 0;
+    linelist = 0;
+    edgelist = 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();
+    edgetimestamp = 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;
+
+    minh = 0.0;
+    maxh = 0.0;
+  }
+
+  VisualSceneMesh :: ~VisualSceneMesh ()
+  {
+    ;
+  }
+
+
+  void VisualSceneMesh :: DrawScene ()
+  {
+    if (!mesh)
+      {
+	VisualScene::DrawScene();
+	return;
+      }
+
+    lock = NULL;
+
+    static int timer = NgProfiler::CreateTimer ("VSMesh::DrawScene");
+
+    NgProfiler::RegionTimer reg (timer);
+
+    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);
+
+
+#ifdef PARALLEL
+    glEnable (GL_BLEND);
+    glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+#endif
+
+
+    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,10);
+    glPolygonOffset (2,2);
+    glEnable (GL_POLYGON_OFFSET_FILL);
+
+    SetClippingPlane ();
+
+    if (vispar.drawfilledtrigs)
+      {
+	if (filledtimestamp < mesh->GetTimeStamp () ||
+            filledtimestamp < selecttimestamp)
+	  {
+            BuildFilledList (false);
+	  }
+
+
+#ifdef PARALLELGL
+	if (ntasks > 1 && vispar.drawtetsdomain > 0 && vispar.drawtetsdomain < ntasks)
+	  glCallList (par_filledlists[vispar.drawtetsdomain]);
+	else
+#endif
+	  glCallList (filledlist);
+      }
+
+    if (vispar.drawbadels)
+      glCallList (badellist);
+
+    if (vispar.drawprisms)
+      {
+	BuildPrismList ();
+	glCallList (prismlist);
+      }
+
+    if (vispar.drawpyramids)
+      {
+	BuildPyramidList ();
+	glCallList (pyramidlist);
+      }
+
+    if (vispar.drawhexes)
+      {
+	BuildHexList ();
+	glCallList (hexlist);
+      }
+
+    if (vispar.drawtets)
+      {
+	BuildTetList ();
+	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);
+
+	if (linetimestamp < mesh->GetTimeStamp ())
+	  BuildLineList ();
+
+#ifdef PARALLELGL
+	if (ntasks > 1 && vispar.drawtetsdomain > 0 && vispar.drawtetsdomain < ntasks)
+	  // for (int dest = 1; dest < ntasks; dest++)
+	  // if (vispar.drawtetsdomain == dest)
+	  glCallList (par_linelists[vispar.drawtetsdomain]);
+	else
+#endif
+	  glCallList (linelist);
+
+
+	glDisable (GL_POLYGON_OFFSET_LINE);
+      }
+
+
+    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)
+      {
+	BuildEdgeList();
+	glCallList (edgelist);
+      }
+
+    if (selpoint > 0 && selpoint <= mesh->GetNP())
+      {
+	/*
+	  glPointSize (3.0);
+	  glColor3d (0, 0, 1);
+	  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();
+	*/
+
+	glColor3d (0, 0, 1);
+
+	static GLubyte cross[] =
+	  {
+            0xc6, 0xee, 0x7c, 0x38, 0x7c, 0xee, 0xc6
+	  };
+	glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+
+	glDisable (GL_COLOR_MATERIAL);
+	glDisable (GL_LIGHTING);
+	glDisable (GL_CLIP_PLANE0);
+
+	const Point3d p = mesh->Point(selpoint);
+	glRasterPos3d (p.X(), p.Y(), p.Z());
+	glBitmap (7, 7, 3, 3, 0, 0, &cross[0]);
+      }
+
+
+    glDisable(GL_CLIP_PLANE0);
+
+    glPopMatrix();
+
+    if (vispar.colormeshsize)
+      DrawColorBar (minh, maxh, 1);
+
+    DrawCoordinateCross ();
+    DrawNetgenLogo ();
+
+
+    if (lock)
+      {
+	lock -> UnLock();
+	delete lock;
+	lock = NULL;
+      }
+    
+    glFinish();
+  }
+
+
+  void VisualSceneMesh :: BuildScene (int zoomall)
+  {
+    if (!mesh)
+      {
+	VisualScene::BuildScene (zoomall);
+	return;
+      }
+
+    if (!lock)
+      {
+	lock = new NgLock (mesh->Mutex());
+	lock -> Lock();
+      }
+
+    static int timer = NgProfiler::CreateTimer ("VSMesh::BuildScene");
+    NgProfiler::RegionTimer reg (timer);
+
+
+
+    Point3d pmin, pmax;
+    static double oldrad = 0;
+
+    Array<Element2d> faces;
+
+    int meshtimestamp = mesh->GetTimeStamp();
+    if (meshtimestamp > vstimestamp || zoomall)
+      {
+	if (mesh->GetDimension() == 2)
+	  {
+            // works in NGSolve, mesh view
+            mesh->GetBox (pmin, pmax);
+	  }
+	else
+	  {
+            // otherwise strange zooms douring mesh generation
+            mesh->GetBox (pmin, pmax, SURFACEPOINT);
+	  }
+
+	if (vispar.use_center_coords && zoomall == 2)
+	  {
+            center.X() = vispar.centerx; center.Y() = vispar.centery; center.Z() = vispar.centerz;
+	  }
+	else 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 == 0) rad = 1e-6;
+
+	if (rad > 1.2 * oldrad ||
+            mesh->GetMajorTimeStamp() > vstimestamp ||
+            zoomall)
+	  {
+            CalcTransformationMatrices();
+            oldrad = rad;
+	  }
+      }
+
+    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 (int 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);
+	      MyOpenGLText (buf);
+            }
+
+	if (vispar.drawedgenumbers)
+	  {
+	    /*
+	      for (SegmentIndex i = 0; i < mesh->GetNSeg(); i++)
+	      {
+	      const Segment & seg = (*mesh)[i];
+
+	      const Point3d & p1 = mesh->Point(seg[0]);
+	      const Point3d & p2 = mesh->Point(seg[1]);
+	      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);
+	      }
+	    */
+
+	    const MeshTopology & top = mesh->GetTopology();
+	    for (int 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);
+		MyOpenGLText (buf);
+
+	      }
+
+	  }
+
+
+	if (vispar.drawfacenumbers)
+	  {
+	    const MeshTopology & top = mesh->GetTopology();
+	    Array<int> v;
+	    for (int 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);
+		MyOpenGLText (buf);
+	      }
+	  }
+
+
+
+	if (vispar.drawelementnumbers)
+	  {
+	    Array<int> v;
+	    for (int i = 1; i <= mesh->GetNE(); i++)
+	      {
+		// const ELEMENTTYPE & eltype = mesh->ElementType(i);
+		Array<int> pnums;
+
+		Point3d p;
+		const Element & el = mesh->VolumeElement (i);
+
+		if ( ! el.PNum(5)) //  eltype == TET )
+                  {
+
+		    pnums.SetSize(4);
+		    for( int j = 0; j < pnums.Size(); j++)
+		      pnums[j] = mesh->VolumeElement(i).PNum(j+1);
+
+
+		    const Point3d & p1 = mesh->Point(pnums[0]);
+		    const Point3d & p2 = mesh->Point(pnums[1]);
+		    const Point3d & p3 = mesh->Point(pnums[2]);
+		    const Point3d & p4 = mesh->Point(pnums[3]);
+		    p = Center (p1, p2, p3, p4);
+                  }
+		else if ( ! el.PNum(6)) // eltype == PYRAMID
+                  {
+		    pnums.SetSize(5);
+		    for( int j = 0; j < pnums.Size(); j++)
+		      pnums[j] = mesh->VolumeElement(i).PNum(j+1);
+
+
+		    const Point3d & p1 = mesh->Point(pnums[0]);
+		    const Point3d & p2 = mesh->Point(pnums[1]);
+		    const Point3d & p3 = mesh->Point(pnums[2]);
+		    const Point3d & p4 = mesh->Point(pnums[3]);
+		    const Point3d & p5 = mesh->Point(pnums[4]);
+
+		    p.X()  = 0.3 * p5.X() + 0.7 * Center ( Center(p1, p3) , Center(p2, p4) ) . X();
+		    p.Y()  = 0.3 * p5.Y() + 0.7 * Center ( Center(p1, p3) , Center(p2, p4) ) . Y();
+		    p.Z()  = 0.3 * p5.Z() + 0.7 * Center ( Center(p1, p3) , Center(p2, p4) ) . Z();
+
+                  }
+		else if ( ! el.PNum(7) ) // eltype == PRISM
+                  {
+		    pnums.SetSize(6);
+		    for( int j = 0; j < pnums.Size(); j++)
+		      pnums[j] = mesh->VolumeElement(i).PNum(j+1);
+
+		    const Point3d & p1 = mesh->Point(pnums[0]);
+		    const Point3d & p2 = mesh->Point(pnums[1]);
+		    const Point3d & p3 = mesh->Point(pnums[2]);
+		    const Point3d & p11 = mesh->Point(pnums[3]);
+		    const Point3d & p12 = mesh->Point(pnums[4]);
+		    const Point3d & p13 = mesh->Point(pnums[5]);
+		    p = Center (  Center (p1, p2, p3) , Center(p11, p12, p13) )  ;
+
+                  }
+		else if (! el.PNum(9) ) // eltype == HEX
+                  {
+		    pnums.SetSize(8);
+		    for( int j = 0; j < pnums.Size(); j++)
+		      pnums[j] = mesh->VolumeElement(i).PNum(j+1);
+
+		    const Point3d & p1 = mesh->Point(pnums[0]);
+		    const Point3d & p2 = mesh->Point(pnums[1]);
+		    const Point3d & p3 = mesh->Point(pnums[2]);
+		    const Point3d & p4 = mesh->Point(pnums[3]);
+		    const Point3d & p5 = mesh->Point(pnums[4]);
+		    const Point3d & p6 = mesh->Point(pnums[5]);
+		    const Point3d & p7 = mesh->Point(pnums[6]);
+		    const Point3d & p8 = mesh->Point(pnums[7]);
+
+		    p = Center ( Center ( Center(p1, p3), Center(p2, p4) ) , Center( Center(p5, p7) , Center(p6, p8 ) ) );
+                  }
+
+		glRasterPos3d (p.X(), p.Y(), p.Z());
+		sprintf (buf, "%d", i);
+		// glCallLists (strlen (buf), GL_UNSIGNED_BYTE, buf);
+		MyOpenGLText (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 (int 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 (int 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 (int 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 (int i = 1; i <= mesh->GetNE(); i++)
+	  {
+            Element el = mesh->VolumeElement (i);
+            int hascp = 0;
+            for (int j = 1; j <= el.GetNP(); j++)
+	      if (el.PNum(j) == vispar.centerpoint)
+		hascp = 1;
+
+            if (hascp)
+	      {
+		(*testout) << "draw el " << i << " : ";
+		for (int 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 (int 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 (int 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 (int i = 1; i <= mesh->GetNSE(); i++)
+	  {
+            Element2d el = mesh->SurfaceElement(i);
+            if (!el.BadElement())
+	      continue;
+
+            int drawel = 1;
+            for (int 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 (int j = 0; j < 6; j++)
+		    {
+		      glVertex3dv ( mesh->Point (el.PNum(lines[j][0])) );
+		      glVertex3dv ( mesh->Point (el.PNum(lines[j][0])) );
+		    }
+		  glEnd();
+		  break;
+		}
+
+	      case QUAD6:
+		{
+                  int lines[6][2] = {
+		    { 1, 5 }, { 2, 5 },
+		    { 3, 6 }, { 4, 6 },
+		    { 1, 4 }, { 2, 3 } };
+
+		  glBegin (GL_LINES);
+
+		  for (int 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++)
+
+	if (& mesh -> GetIdentifications() )
+	  {
+            INDEX_2_HASHTABLE<int> & idpts =
+	      mesh->GetIdentifications().GetIdentifiedPoints();
+            if (&idpts)
+	      {
+		for (int i = 1; i <= idpts.GetNBags(); i++)
+                  for (int 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 ();
+      }
+
+    if (lock)
+      {
+	lock -> UnLock();
+	delete lock;
+	lock = NULL;
+      }
+
+    vstimestamp = meshtimestamp;
+  }
+
+
+
+
+  void VisualSceneMesh :: BuildFilledList (bool names)
+  {
+    static int timer = NgProfiler::CreateTimer ("Mesh::BuildFilledList");
+    NgProfiler::RegionTimer reg (timer);
+
+#ifdef PARALLELGL
+    if (id == 0 && ntasks > 1)
+      {
+	InitParallelGL();
+	par_filledlists.SetSize (ntasks);
+
+	MyMPI_SendCmd ("redraw");
+	MyMPI_SendCmd ("filledlist");
+	for ( int dest = 1; dest < ntasks; dest++ )
+	  MyMPI_Recv (par_filledlists[dest], dest, MPI_TAG_VIS);
+
+	if (filledlist)
+	  glDeleteLists (filledlist, 1);
+
+	filledlist = glGenLists (1);
+	glNewList (filledlist, GL_COMPILE);
+
+	for ( int dest = 1; dest < ntasks; dest++ )
+	  glCallList (par_filledlists[dest]);
+
+	glEndList();
+
+	filledtimestamp = NextTimeStamp();
+	return;
+      }
+
+#endif
+
+
+    if (!lock)
+      {
+	lock = new NgLock (mesh->Mutex());
+	lock -> Lock();
+      }
+
+    filledtimestamp = NextTimeStamp();
+
+    if (filledlist)
+      glDeleteLists (filledlist, 1);
+
+    filledlist = glGenLists (1);
+    glNewList (filledlist, GL_COMPILE);
+
+      
+#ifdef STLGEOM
+    STLGeometry * stlgeometry = dynamic_cast<STLGeometry*> (ng_geometry);
+    bool checkvicinity = (stlgeometry != NULL) && stldoctor.showvicinity;
+#endif
+    glEnable (GL_NORMALIZE);
+
+    glLineWidth (1.0f);
+
+    Vector locms;
+
+    if (vispar.colormeshsize)
+      {
+	glEnable (GL_COLOR_MATERIAL);
+	glShadeModel (GL_SMOOTH);
+	locms.SetSize (mesh->GetNP());
+	maxh = -1;
+	minh = 1e99;
+	for (int i = 1; i <= locms.Size(); i++)
+	  {
+            Point3d p = mesh->Point(i);
+            locms(i-1) = mesh->GetH (p);
+            if (locms(i-1) > maxh) maxh = locms(i-1);
+            if (locms(i-1) < minh) minh = locms(i-1);
+	  }
+	if (!locms.Size())
+	  { 
+            minh = 1; 
+            maxh = 10; 
+	  }
+      }
+    else
+      glDisable (GL_COLOR_MATERIAL);
+
+
+    GLfloat matcol[] = { 0, 1, 0, 1 };
+    GLfloat matcolsel[] = { 1, 0, 0, 1 };
+
+    GLint rendermode;
+    glGetIntegerv (GL_RENDER_MODE, &rendermode);
+
+    CurvedElements & curv = mesh->GetCurvedElements();
+
+    int hoplotn = 1 << vispar.subdivisions;
+    
+    Array<SurfaceElementIndex> seia;
+
+
+    for (int faceindex = 1; faceindex <= mesh->GetNFD(); faceindex++)
+      {
+	mesh->GetSurfaceElementsOfFace (faceindex, seia);
+
+	// Philippose - 06/07/2009
+	// Modified the colour system to integrate the face colours into 
+	// the mesh data structure, rather than limit it to the OCC geometry 
+	// structure... allows other geometry types to use face colours too
+
+	matcol[0] = mesh->GetFaceDescriptor(faceindex).SurfColour().X();
+	matcol[1] = mesh->GetFaceDescriptor(faceindex).SurfColour().Y();
+	matcol[2] = mesh->GetFaceDescriptor(faceindex).SurfColour().Z();
+	matcol[3] = 1.0;
+
+	if (faceindex == selface)
+	  glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, matcolsel);
+	else
+	  glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, matcol);
+	
+
+
+	for (int hi = 0; hi < seia.Size(); hi++)
+	  {
+	    SurfaceElementIndex sei = seia[hi];
+            const Element2d & el = (*mesh)[sei];
+
+            bool drawel = (!el.IsDeleted() & el.IsVisible());
+
+#ifdef STLGEOM
+            if (checkvicinity)
+	      for (int j = 0; j < el.GetNP(); j++)
+		if (!stlgeometry->Vicinity(el.GeomInfoPi(j+1).trignum))
+		  drawel = 0;
+#endif
+
+            if (!drawel)
+	      continue;
+	    
+	    if (names)
+	      glLoadName (sei+1);
+
+            switch (el.GetType())
+	      {
+	      case TRIG:
+		{
+                  if (curv.IsHighOrder()) //  && curv.IsSurfaceElementCurved(sei))
+		    {
+		      if (hoplotn > 128) hoplotn = 128;
+		      Point<3> xa[129];
+		      Vec<3> na[129];
+
+		      for (int i = 0; i < hoplotn; i++)
+			{
+			  glBegin (GL_TRIANGLE_STRIP);
+
+			  for (int j = 0; j <= hoplotn-i; j++)
+			    for (int k = 0; k < 2; k++)
+			      {
+				if (j == hoplotn-i && k == 1) continue;
+
+				if (i > 0 && k == 0)
+				  {
+				    glNormal3dv (na[j]);
+				    glVertex3dv (xa[j]);
+				    continue;
+				  }
+
+				Point<2> xref (double(j) / hoplotn, double(i+k) / hoplotn);
+				Point<3> xglob;
+				Mat<3,2> dxdxi;
+				Vec<3> dx, dy, n;
+
+				curv.CalcSurfaceTransformation (xref, sei, xglob, dxdxi);
+				for (int i = 0; i < 3; i++)
+				  {
+				    dx(i) = dxdxi(i,0);
+				    dy(i) = dxdxi(i,1);
+				  }
+				n = Cross (dx, dy);
+				glNormal3dv (n);
+				glVertex3dv (xglob);
+
+				if (k == 1)
+				  {
+				    na[j] = n;
+				    xa[j] = xglob;
+				  }
+			      }
+			  glEnd();
+			}
+		    }
+                  else // not high order
+		    {
+		      glBegin (GL_TRIANGLES);
+		      
+		      const Point<3> & lp0 = (*mesh) [el[0]];
+		      const Point<3> & lp1 = (*mesh) [el[1]];
+		      const Point<3> & lp2 = (*mesh) [el[2]];
+
+		      Vec<3> n = Cross (lp1-lp0, lp2-lp0).Normalize();
+		      glNormal3dv (n);
+
+		      for (int j = 0; j < 3; j++)
+			{
+			  if (vispar.colormeshsize)
+			    SetOpenGlColor  (locms(el[0]-1), minh, maxh, 0);
+			  glVertex3dv ( (*mesh)[el[j]] );
+			}
+		      
+		      glEnd();
+		    }
+		  
+                  break;
+		}
+	      case QUAD:
+		{
+                  if (curv.IsHighOrder()) //  && curv.IsSurfaceElementCurved(sei))
+		    {
+		      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 Point<3> & lp1 = mesh->Point (el.PNum(1));
+		      const Point<3> & lp2 = mesh->Point (el.PNum(2));
+		      const Point<3> & lp3 = mesh->Point (el.PNum(4));
+		      const Point<3> & lp4 = mesh->Point (el.PNum(3));
+
+		      Vec<3> n = Cross (lp2-lp1,  Center (lp3, lp4)-lp1);
+		      n.Normalize();
+		      glNormal3dv (n);
+
+		      glVertex3dv (lp1);
+		      glVertex3dv (lp2);
+		      glVertex3dv (lp4);
+		      glVertex3dv (lp3);
+
+		      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 (int j = 0; j < 4; j++)
+		    {
+		      const Point<3> & lp1 = mesh->Point (el.PNum(trigs[j][0]));
+		      const Point<3> & lp2 = mesh->Point (el.PNum(trigs[j][1]));
+		      const Point<3> & lp3 = mesh->Point (el.PNum(trigs[j][2]));
+		      // Vec3d n = Cross (Vec3d (lp1, lp2), Vec3d (lp1, lp3));
+		      Vec<3> n = Cross (lp2-lp1, lp3-lp1);
+		      glNormal3dv (n);
+
+		      glVertex3dv (lp1);
+		      glVertex3dv (lp2);
+		      glVertex3dv (lp3);
+		    }
+		  glEnd();
+		  break;
+		}
+
+	      case QUAD6:
+		{
+                  glBegin (GL_QUADS);
+                  static int quads[2][4] = {
+		    { 1, 5, 6, 4 },
+		    { 5, 2, 3, 6 } };
+
+		  for (int 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;
+		}
+
+	      case QUAD8:
+		{
+                  glBegin (GL_TRIANGLES);
+                  static int boundary[] =
+		    { 1, 5, 2, 8, 3, 6, 4, 7, 1 };
+
+                  Point3d c(0,0,0);
+                  for (int j = 0; j < 4; j++)
+		    {
+		      const Point3d & hp = mesh->Point (el[j]);
+		      c.X() -= 0.25 * hp.X();
+		      c.Y() -= 0.25 * hp.Y();
+		      c.Z() -= 0.25 * hp.Z();
+		    }
+                  for (int j = 4; j < 8; j++)
+		    {
+		      const Point3d & hp = mesh->Point (el[j]);
+		      c.X() += 0.5 * hp.X();
+		      c.Y() += 0.5 * hp.Y();
+		      c.Z() += 0.5 * hp.Z();
+		    }
+
+                  for (int j = 0; j < 8; j++)
+		    {
+		      Point3d lp1 = mesh->Point (el.PNum(boundary[j]));
+		      Point3d lp2 = mesh->Point (el.PNum(boundary[j+1]));
+
+		      Vec3d n = Cross (Vec3d (c, lp1), Vec3d (c, lp2));
+		      n /= (n.Length() + 1e-12);
+		      glNormal3dv (&n.X());
+		      glVertex3dv (&lp1.X());
+		      glVertex3dv (&lp2.X());
+		      glVertex3dv (&c.X());
+		    }
+                  glEnd();
+                  break;
+		}
+
+
+	      default:
+		PrintSysError ("Cannot draw (2) surface element of type ",
+			       int(el.GetType()));
+	      }
+	    
+
+	    
+	  }
+      }
+    
+
+    glLoadName (0);
+    glEndList ();
+
+
+#ifdef PARALLELGL
+    glFinish();
+    if (id > 0)
+      MyMPI_Send (filledlist, 0, MPI_TAG_VIS);
+#endif
+  }
+
+
+  void VisualSceneMesh :: BuildLineList()
+  {
+    static int timer = NgProfiler::CreateTimer ("Mesh::BuildLineList");
+    NgProfiler::RegionTimer reg (timer);
+
+#ifdef PARALLELGL
+
+    if (id == 0 && ntasks > 1)
+      {
+	InitParallelGL();
+
+	par_linelists.SetSize (ntasks);
+
+	MyMPI_SendCmd ("redraw");
+	MyMPI_SendCmd ("linelist");
+
+	for ( int dest = 1; dest < ntasks; dest++ )
+	  MyMPI_Recv (par_linelists[dest], dest, MPI_TAG_VIS);
+
+	if (linelist)
+	  glDeleteLists (linelist, 1);
+
+	linelist = glGenLists (1);
+	glNewList (linelist, GL_COMPILE);
+
+	for ( int dest = 1; dest < ntasks; dest++ )
+	  glCallList (par_linelists[dest]);
+
+	glEndList();
+
+
+	linetimestamp = NextTimeStamp();
+	return;
+      }
+
+#endif
+
+    if (!lock)
+      {
+	lock = new NgLock (mesh->Mutex());
+	lock -> Lock();
+      }
+
+    linetimestamp = NextTimeStamp();
+
+#ifdef STLGEOM
+    STLGeometry * stlgeometry = dynamic_cast<STLGeometry*> (ng_geometry);
+    bool checkvicinity = (stlgeometry != NULL) && stldoctor.showvicinity;
+#endif
+
+    if (linelist)
+      glDeleteLists (linelist, 1);
+
+    linelist = glGenLists (1);
+    glNewList (linelist, GL_COMPILE);
+
+    // cout << "linelist = " << linelist << endl;
+
+    glLineWidth (1.0f);
+
+
+    int hoplotn = 1 << vispar.subdivisions;
+
+    // PrintMessage (3, "nse = ", mesh->GetNSE());
+    for (SurfaceElementIndex sei = 0; sei < mesh->GetNSE(); sei++)
+      {
+	const Element2d & el = (*mesh)[sei];
+
+	bool drawel = (!el.IsDeleted() & el.IsVisible());
+
+#ifdef STLGEOM
+	if (checkvicinity)
+	  for (int j = 0; j < el.GetNP(); j++)
+	    if (!stlgeometry->Vicinity(el.GeomInfoPi(j+1).trignum))
+	      drawel = 0;
+#endif
+
+	if (!drawel)
+	  continue;
+
+	switch (el.GetType())
+	  {
+	  case TRIG:
+            {
+	      CurvedElements & curv = mesh->GetCurvedElements();
+	      if (curv.IsHighOrder()) //  && curv.IsSurfaceElementCurved(sei))
+		{
+                  Point<3> xg;
+                  glBegin (GL_LINE_LOOP);
+                  for (int i = 0; i < hoplotn; i++)
+		    {
+		      Point<2> xr (double(i) / hoplotn, 0);
+		      curv.CalcSurfaceTransformation (xr, sei, xg);
+		      glVertex3dv (xg);
+		    }
+                  for (int i = 0; i < hoplotn; i++)
+		    {
+		      Point<2> xr (double(hoplotn-i) / hoplotn, double(i)/hoplotn);
+		      curv.CalcSurfaceTransformation (xr, sei, xg);
+		      glVertex3dv (xg);
+		    }
+                  for (int i = 0; i < hoplotn; i++)
+		    {
+		      Point<2> xr (0, double(hoplotn-i) / hoplotn);
+		      curv.CalcSurfaceTransformation (xr, sei, xg);
+		      glVertex3dv (xg);
+		    }
+
+                  glEnd();
+		}
+	      else
+		{
+                  glBegin (GL_TRIANGLES);
+
+		  for (int j = 0; j < 3; j++)
+		    glVertex3dv ( (*mesh) [el[j]] );
+		  /*
+                  const Point<3> & lp0 = (*mesh) [el[0]];
+                  const Point<3> & lp1 = (*mesh) [el[1]];
+                  const Point<3> & lp2 = (*mesh) [el[2]];
+
+                  glVertex3dv (lp0);
+                  glVertex3dv (lp1);
+                  glVertex3dv (lp2);
+		  */
+                  glEnd();
+		}
+
+	      break;
+
+            }
+
+	  case QUAD:
+            {
+	      CurvedElements & curv = mesh->GetCurvedElements();
+	      if (curv.IsHighOrder()) //  && curv.IsSurfaceElementCurved(sei))
+		{
+                  Point<2> xr;
+                  Point<3> xg;
+
+                  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;
+			    }
+
+			  curv.CalcSurfaceTransformation (xr, sei, xg);
+			  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)));
+		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 (int 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 (int 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 QUAD8:
+            {
+	      int lines[8][2] = {
+		{ 1, 5 }, { 2, 5 }, { 3, 6 }, { 4, 6 },
+		{ 1, 7 }, { 4, 7 }, { 2, 8 }, { 3, 8 }
+	      };
+
+	      glBegin (GL_LINES);
+
+	      for (int j = 0; j < 8; 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 ();
+
+
+#ifdef PARALLELGL
+    glFinish();
+    if (id > 0)
+      MyMPI_Send (linelist, 0, MPI_TAG_VIS);
+#endif
+  }
+
+
+
+  void VisualSceneMesh :: BuildEdgeList()
+  {
+    if (!lock)
+      {
+	lock = new NgLock (mesh->Mutex());
+	lock -> Lock();
+      }
+
+    if (edgetimestamp > mesh->GetTimeStamp () && vispar.shrink == 1)
+      return;
+
+    edgetimestamp = NextTimeStamp();
+
+    if (edgelist)
+      glDeleteLists (edgelist, 1);
+
+    edgelist = glGenLists (1);
+    glNewList (edgelist, GL_COMPILE);
+
+
+    GLfloat matcoledge[] = { 0, 0, 1, 1 };
+    GLfloat matcolsingedge[] = { 1, 0, 1, 1 };
+
+    glEnable (GL_POLYGON_OFFSET_LINE);
+    glPolygonOffset (1, -1);
+
+    glEnable (GL_COLOR_MATERIAL);
+    glDisable (GL_LIGHTING);
+
+    for (int i = 1; i <= mesh->GetNSeg(); i++)
+      {
+	const Segment & seg = mesh->LineSegment(i);
+	const Point3d & p1 = (*mesh)[seg[0]];
+	const Point3d & p2 = (*mesh)[seg[1]];
+
+	if (seg.singedge_left || seg.singedge_right)
+	  glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE,
+			matcolsingedge);
+	else
+	  glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE,
+			matcoledge);
+
+	if (seg.singedge_left || seg.singedge_right)
+	  glColor3fv (matcolsingedge);
+	else
+	  glColor3fv (matcoledge);
+
+	if (seg.edgenr == seledge)
+	  glLineWidth(5);
+	else
+	  glLineWidth(2);
+
+	if (mesh->GetCurvedElements().IsHighOrder())
+	  {
+            int hoplotn = 1 << vispar.subdivisions;
+            // mesh->GetCurvedElements().GetNVisualSubsecs();
+
+            Point<3> x;
+            glBegin (GL_LINE_STRIP);
+
+            for (int j = 0; j <= hoplotn; j++)
+	      {
+		mesh->GetCurvedElements().CalcSegmentTransformation ((double) j/hoplotn, i-1, x);
+		glVertex3d (x(0), x(1), x(2));
+		/*
+		  cout << "x = " << x(0) << ", " << x(1) << ", " << x(2)
+		  << ", norm = 1+" << sqrt(x(0)*x(0)+x(1)*x(1))-1
+		  << ", phi = " << atan2(x(1), x(0))/M_PI << endl;
+		*/
+	      }
+
+            glEnd();
+
+	  }
+	else
+	  {
+            glBegin (GL_LINES);
+            Point<3> hp1 = p1;
+            Point<3> hp2 = p2;
+            Point<3> c = Center(p1, p2);
+            if (vispar.shrink < 1)
+	      {
+		hp1 = c + vispar.shrink * (hp1 - c);
+		hp2 = c + vispar.shrink * (hp2 - c);
+	      }
+            glVertex3dv (hp1);
+            glVertex3dv (hp2); // p2.X(), p2.Y(), p2.Z());
+            glEnd();
+	  }
+      }
+
+    glLineWidth (2);
+    glDisable (GL_POLYGON_OFFSET_LINE);
+
+    glDisable (GL_COLOR_MATERIAL);
+    glEnable (GL_LIGHTING);
+
+    glEndList();
+  }
+
+
+
+
+  void VisualSceneMesh :: BuildPointNumberList()
+  {
+    ;
+  }
+
+
+
+  // Bernstein Pol B_{n,i}(x) = n! / i! / (n-i)! (1-x)^{n-i} x^i
+  static inline double Bernstein (int n, int i, double x)
+  {
+    double val = 1;
+    for (int j = 1; j <= i; j++)
+      val *= x;
+    for (int j = 1; j <= n-i; j++)
+      val *= (1-x) * (j+i) / j;
+    return val;
+  }
+
+  void ToBernstein (int order, Point<3> * pts, int stride)
+  {
+    static DenseMatrix mat, inv;
+    static Vector vec1, vec2;
+
+    if (mat.Height () != order+1)
+      {
+	mat.SetSize (order+1);
+	inv.SetSize (order+1);
+	vec1.SetSize (order+1);
+	vec2.SetSize (order+1);
+	for (int i = 0; i <= order; i++)
+	  {
+            double x = double(i) / order;
+            for (int j = 0; j <= order; j++)
+	      mat(i,j) = Bernstein (order, j, x);
+	  }
+
+	CalcInverse (mat, inv);
+      }
+
+    for (int i = 0; i < 3; i++)
+      {
+	for (int j = 0; j <= order; j++)
+	  vec1(j) = pts[j*stride](i);
+
+	inv.Mult (vec1, vec2);
+
+	for (int j = 0; j <= order; j++)
+	  pts[j*stride](i) = vec2(j);
+      }
+  }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+  void VisualSceneMesh :: BuildTetList()
+  {
+
+    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);
+
+
+    Vector locms;
+
+    // Philippose - 16/02/2010
+    // Add Mesh size based coloring of 
+    // meshes also for the volume elements
+    if (vispar.colormeshsize)
+      {
+	glEnable (GL_COLOR_MATERIAL);
+	locms.SetSize (mesh->GetNP());
+	maxh = -1;
+	minh = 1e99;
+	for (int i = 1; i <= locms.Size(); i++)
+	  {
+            Point3d p = mesh->Point(i);
+            locms(i-1) = mesh->GetH (p);
+            if (locms(i-1) > maxh) maxh = locms(i-1);
+            if (locms(i-1) < minh) minh = locms(i-1);
+	  }
+	if (!locms.Size())
+	  { 
+            minh = 1; 
+            maxh = 10; 
+	  }
+      }
+    else
+      glDisable (GL_COLOR_MATERIAL);
+
+
+
+    Array<Element2d> faces;
+
+    BitArray shownode(mesh->GetNP());
+    if (vispar.clipenable)
+      {
+	shownode.Clear();
+	for (int i = 1; i <= shownode.Size(); i++)
+	  {
+            Point<3> p = mesh->Point(i);
+
+            double val =
+	      p[0] * clipplane[0] +
+	      p[1] * clipplane[1] +
+	      p[2] * 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 }
+	/*
+	{ 1.0f, 1.0f, 0.0f, 0.3f },
+	{ 1.0f, 0.0f, 0.0f, 0.3f },
+	{ 0.0f, 1.0f, 0.0f, 0.3f },
+	{ 0.0f, 0.0f, 1.0f, 0.3f }
+	*/
+      };
+
+    static float tetcols_ghost[4][4];
+
+    for (int j = 0; j < 4; j++)
+      {
+	for (int i = 0; i < 3; i++)
+	  tetcols_ghost[j][i] = tetcols[j][i];
+	tetcols_ghost[j][3] = 0.3; 
+      }
+
+
+    CurvedElements & curv = mesh->GetCurvedElements();
+
+
+    if (!curv.IsHighOrder())
+      glShadeModel (GL_FLAT);
+    else
+      glShadeModel (GL_SMOOTH);
+
+    int hoplotn = max (2, 1 << vispar.subdivisions);
+
+
+
+    for (ElementIndex ei = 0; ei < mesh->GetNE(); ei++)
+      {
+	if (vispar.drawtetsdomain > 0)
+	  {
+	    int tetid = vispar.drawmetispartition ? 
+	      (*mesh)[ei].GetPartition() : (*mesh)[ei].GetIndex();
+	    
+	    if (vispar.drawtetsdomain != tetid) continue;
+	  }
+
+	const Element & el = (*mesh)[ei];
+
+	if ((el.GetType() == TET || el.GetType() == TET10) && !el.IsDeleted())
+	  {
+
+            bool drawtet = 1;
+            for (int j = 0; j < 4; j++)
+	      if (!shownode.Test(el[j]))
+		drawtet = 0;
+            if (!drawtet) continue;
+
+            int ind = el.GetIndex() % 4;
+
+            if (vispar.drawmetispartition && el.GetPartition()!=-1)
+	      ind = el.GetPartition() % 4;
+
+            if ( el.IsGhost() )
+	      glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, tetcols_ghost[ind]);
+            else
+	      glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, tetcols[ind]);
+
+
+            if (curv.IsHighOrder()) //  && curv.IsElementCurved(ei))
+	      {
+		const ELEMENT_FACE * faces = MeshTopology :: GetFaces1 (TET);
+		const Point3d * vertices = MeshTopology :: GetVertices (TET);
+
+		/*
+		  Point<3> grid[11][11];
+		  Point<3> fpts[3];
+		  int order = vispar.subdivisions+1;
+
+		  for (int trig = 0; trig < 4; trig++)
+		  {
+		  for (int j = 0; j < 3; j++)
+		  fpts[j] = vertices[faces[trig][j]-1];
+
+		  static Point<3> c(0.25, 0.25, 0.25);
+		  if (vispar.shrink < 1)
+		  for (int j = 0; j < 3; j++)
+		  fpts[j] += (1-vispar.shrink) * (c-fpts[j]);
+
+		  for (int ix = 0; ix <= order; ix++)
+		  for (int iy = 0; iy <= order; iy++)
+		  {
+		  double lami[3] =
+		  { (1-double(ix)/order) * (1-double(iy)/order),
+		  (  double(ix)/order) * (1-double(iy)/order),
+		  double(iy)/order };
+
+		  Point<3> xl;
+		  for (int l = 0; l < 3; l++)
+		  xl(l) = lami[0] * fpts[0](l) + lami[1] * fpts[1](l) +
+		  lami[2] * fpts[2](l);
+
+		  curv.CalcElementTransformation (xl, i-1, grid[ix][iy]);
+		  }
+
+		  for (int j = 0; j <= order; j++)
+		  ToBernstein (order, &grid[j][0], &grid[0][1]-&grid[0][0]);
+		  for (int j = 0; j <= order; j++)
+		  ToBernstein (order, &grid[0][j], &grid[1][0]-&grid[0][0]);
+
+		  glMap2d(GL_MAP2_VERTEX_3,
+		  0.0, 1.0, &grid[0][1](0)-&grid[0][0](0), order+1,
+		  0.0, 1.0, &grid[1][0](0)-&grid[0][0](0), order+1,
+		  &grid[0][0](0));
+		  glEnable(GL_MAP2_VERTEX_3);
+		  glEnable(GL_AUTO_NORMAL);
+
+		  glMapGrid2f(8, 0.0, 0.999, 8, 0.0, 1.0);
+		  glEvalMesh2(GL_FILL, 0, 8, 0, 8);
+
+		  glDisable (GL_AUTO_NORMAL);
+		  glDisable (GL_MAP2_VERTEX_3);
+		  }
+		*/
+
+
+
+		int order = curv.GetOrder();
+
+		Array<Point<3> > ploc ( (order+1)*(order+1) );
+		Array<Point<3> > pglob ( (order+1)*(order+1) );
+		Point<3> fpts[3];
+
+		for (int trig = 0; trig < 4; trig++)
+		  {
+		    for (int j = 0; j < 3; j++)
+		      fpts[j] = vertices[faces[trig][j]-1];
+
+		    static Point<3> c(0.25, 0.25, 0.25);
+		    if (vispar.shrink < 1)
+		      for (int j = 0; j < 3; j++)
+                        fpts[j] += (1-vispar.shrink) * (c-fpts[j]);
+
+		    for (int ix = 0, ii = 0; ix <= order; ix++)
+		      for (int iy = 0; iy <= order; iy++, ii++)
+			{
+			  double lami[3] =
+			    { (1-double(ix)/order) * (1-double(iy)/order),
+			      (  double(ix)/order) * (1-double(iy)/order),
+			      double(iy)/order };
+
+			  Point<3> xl;
+			  for (int l = 0; l < 3; l++)
+			    xl(l) = lami[0] * fpts[0](l) + lami[1] * fpts[1](l) +
+			      lami[2] * fpts[2](l);
+
+			  ploc[ii] = xl;
+			}
+
+		    curv.CalcMultiPointElementTransformation (&ploc, ei, &pglob, 0);
+
+		    Point<3> grid[11][11];
+		    for (int ix = 0, ii = 0; ix <= order; ix++)
+		      for (int iy = 0; iy <= order; iy++, ii++)
+			grid[ix][iy] = pglob[ii];
+
+		    for (int j = 0; j <= order; j++)
+		      ToBernstein (order, &grid[j][0], &grid[0][1]-&grid[0][0]);
+		    for (int j = 0; j <= order; j++)
+		      ToBernstein (order, &grid[0][j], &grid[1][0]-&grid[0][0]);
+
+		    glMap2d(GL_MAP2_VERTEX_3,
+			    0.0, 1.0, &grid[0][1](0)-&grid[0][0](0), order+1,
+			    0.0, 1.0, &grid[1][0](0)-&grid[0][0](0), order+1,
+			    &grid[0][0](0));
+		    glEnable(GL_MAP2_VERTEX_3);
+		    glEnable(GL_AUTO_NORMAL);
+
+		    glMapGrid2f(hoplotn, 0.0, 0.9999f, hoplotn, 0.0, 1.0);
+		    glEvalMesh2(GL_FILL, 0, hoplotn, 0, hoplotn);
+
+		    glDisable (GL_AUTO_NORMAL);
+		    glDisable (GL_MAP2_VERTEX_3);
+		  }
+	      }
+
+            else // Not High Order
+
+	      {
+		Point<3> pts[4];
+		for (int j = 0; j < 4; j++)
+                  pts[j] = (*mesh)[el[j]];
+
+		if (vispar.shrink < 1)
+		  {
+		    Point<3> c = Center (pts[0], pts[1], pts[2], pts[3]);
+		    for (int j = 0; j < 4; j++)
+		      pts[j] = c + vispar.shrink * (pts[j]-c);
+		  }
+
+
+		Vec<3> n;
+
+		glBegin (GL_TRIANGLE_STRIP);
+
+		// Philippose - 16/02/2010
+		// Add Mesh size based coloring of 
+		// meshes also for the volume elements
+		if(vispar.colormeshsize)
+		  {
+		    n = Cross (pts[1]-pts[0], pts[2]-pts[0]);
+		    glNormal3dv (n);
+
+		    SetOpenGlColor (locms(el[0]-1), minh, maxh, 0);
+		    glVertex3dv (pts[0]);
+
+		    SetOpenGlColor (locms(el[1]-1), minh, maxh, 0);
+		    glVertex3dv (pts[1]);
+
+		    SetOpenGlColor (locms(el[2]-1), minh, maxh, 0);
+		    glVertex3dv (pts[2]);
+
+		    n = Cross (pts[3]-pts[1], pts[2]-pts[1]);
+		    glNormal3dv (n);
+
+		    SetOpenGlColor (locms(el[3]-1), minh, maxh, 0);
+		    glVertex3dv (pts[3]);
+
+		    n = Cross (pts[3]-pts[2], pts[0]-pts[2]);
+		    glNormal3dv (n);
+
+		    SetOpenGlColor (locms(el[0]-1), minh, maxh, 0);
+		    glVertex3dv (pts[0]);
+
+		    n = Cross (pts[1]-pts[3], pts[0]-pts[3]);
+		    glNormal3dv (n);
+
+		    SetOpenGlColor (locms(el[1]-1), minh, maxh, 0);
+		    glVertex3dv (pts[1]);
+		  }
+		else // Do not color mesh based on mesh size
+		  {
+		    glNormal3dv (Cross (pts[1]-pts[0], pts[2]-pts[0]));
+
+		    glVertex3dv (pts[0]);
+		    glVertex3dv (pts[1]);
+		    glVertex3dv (pts[2]);
+
+		    glNormal3dv (Cross (pts[3]-pts[1], pts[2]-pts[1]));
+		    glVertex3dv (pts[3]);
+
+		    glNormal3dv (Cross (pts[3]-pts[2], pts[0]-pts[2]));
+		    glVertex3dv (pts[0]);
+
+		    glNormal3dv (Cross (pts[1]-pts[3], pts[0]-pts[3]));
+		    glVertex3dv (pts[1]);
+		  }
+
+		glEnd();
+	      }
+	  }
+      }
+
+    glEndList ();
+  }
+
+
+
+
+  void VisualSceneMesh :: BuildPrismList()
+  {
+    if (prismtimestamp > mesh->GetTimeStamp () &&
+	prismtimestamp > vispar.clipplanetimestamp )
+      return;
+
+    if (!lock)
+      {
+	lock = new NgLock (mesh->Mutex());
+	lock -> Lock();
+      }
+
+    prismtimestamp = NextTimeStamp();
+
+
+
+    if (prismlist)
+      glDeleteLists (prismlist, 1);
+
+    prismlist = glGenLists (1);
+    glNewList (prismlist, GL_COMPILE);
+
+    static float prismcol[] = { 0.0f, 1.0f, 1.0f, 1.0f };
+    glLineWidth (1.0f);
+
+    Array<Element2d> faces;
+
+
+    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, prismcol);
+
+    for (ElementIndex ei = 0; ei < mesh->GetNE(); ei++)
+      {
+	const Element & el = (*mesh)[ei];
+	if (el.GetType() == PRISM && !el.IsDeleted())
+	  {
+            int j;
+            int i = ei + 1;
+
+            CurvedElements & curv = mesh->GetCurvedElements();
+            if (curv.IsHighOrder()) //  && curv.IsElementCurved(ei))
+	      {
+		const ELEMENT_FACE * faces = MeshTopology :: GetFaces1 (PRISM);
+		const Point3d * vertices = MeshTopology :: GetVertices (PRISM);
+
+		Point<3> grid[11][11];
+		Point<3> fpts[4];
+		int order = vispar.subdivisions+1;
+
+		for (int trig = 0; trig < 2; trig++)
+		  {
+		    for (int j = 0; j < 3; j++)
+		      fpts[j] = vertices[faces[trig][j]-1];
+
+		    static Point<3> c(1.0/3.0, 1.0/3.0, 0.5);
+		    if (vispar.shrink < 1)
+		      for (int j = 0; j < 3; j++)
+                        fpts[j] += (1-vispar.shrink) * (c-fpts[j]);
+
+		    for (int ix = 0; ix <= order; ix++)
+		      for (int iy = 0; iy <= order; iy++)
+			{
+			  double lami[3] =
+			    { (1-double(ix)/order) * (1-double(iy)/order),
+			      (  double(ix)/order) * (1-double(iy)/order),
+			      double(iy)/order };
+
+			  Point<3> xl;
+			  for (int l = 0; l < 3; l++)
+			    xl(l) = lami[0] * fpts[0](l) + lami[1] * fpts[1](l) +
+			      lami[2] * fpts[2](l);
+
+			  curv.CalcElementTransformation (xl, i-1, grid[ix][iy]);
+			}
+
+		    for (int j = 0; j <= order; j++)
+		      ToBernstein (order, &grid[j][0], &grid[0][1]-&grid[0][0]);
+		    for (int j = 0; j <= order; j++)
+		      ToBernstein (order, &grid[0][j], &grid[1][0]-&grid[0][0]);
+
+		    glMap2d(GL_MAP2_VERTEX_3,
+			    0.0, 1.0, &grid[0][1](0)-&grid[0][0](0), order+1,
+			    0.0, 1.0, &grid[1][0](0)-&grid[0][0](0), order+1,
+			    &grid[0][0](0));
+		    glEnable(GL_MAP2_VERTEX_3);
+		    glEnable(GL_AUTO_NORMAL);
+
+		    glMapGrid2f(8, 0.0, 0.999f, 8, 0.0, 1.0);
+		    glEvalMesh2(GL_FILL, 0, 8, 0, 8);
+
+		    glDisable (GL_AUTO_NORMAL);
+		    glDisable (GL_MAP2_VERTEX_3);
+		  }
+
+		for (int quad = 2; quad < 5; quad++)
+		  {
+		    for (int j = 0; j < 4; j++)
+		      fpts[j] = vertices[faces[quad][j]-1];
+
+		    static Point<3> c(1.0/3.0, 1.0/3.0, 0.5);
+		    if (vispar.shrink < 1)
+		      for (int j = 0; j < 4; j++)
+                        fpts[j] += (1-vispar.shrink) * (c-fpts[j]);
+
+		    for (int ix = 0; ix <= order; ix++)
+		      for (int iy = 0; iy <= order; iy++)
+			{
+			  double lami[4] =
+			    { (1-double(ix)/order) * (1-double(iy)/order),
+			      (  double(ix)/order) * (1-double(iy)/order),
+			      (  double(ix)/order) * (  double(iy)/order),
+			      (1-double(ix)/order) * (  double(iy)/order) };
+
+			  Point<3> xl;
+			  for (int l = 0; l < 3; l++)
+			    xl(l) =
+			      lami[0] * fpts[0](l) + lami[1] * fpts[1](l) +
+			      lami[2] * fpts[2](l) + lami[3] * fpts[3](l);
+
+			  curv.CalcElementTransformation (xl, ei, grid[ix][iy]);
+			}
+
+		    for (int j = 0; j <= order; j++)
+		      ToBernstein (order, &grid[j][0], &grid[0][1]-&grid[0][0]);
+		    for (int j = 0; j <= order; j++)
+		      ToBernstein (order, &grid[0][j], &grid[1][0]-&grid[0][0]);
+
+		    glMap2d(GL_MAP2_VERTEX_3,
+			    0.0, 1.0, &grid[0][1](0)-&grid[0][0](0), order+1,
+			    0.0, 1.0, &grid[1][0](0)-&grid[0][0](0), order+1,
+			    &grid[0][0](0));
+		    glEnable(GL_MAP2_VERTEX_3);
+		    glEnable(GL_AUTO_NORMAL);
+
+		    glMapGrid2f(8, 0.0, 1.0, 8, 0.0, 1.0);
+		    glEvalMesh2(GL_FILL, 0, 8, 0, 8);
+
+		    glDisable (GL_AUTO_NORMAL);
+		    glDisable (GL_MAP2_VERTEX_3);
+		  }
+
+
+
+
+
+		/*
+		  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;
+		      }
+		  }
+
+		el.GetSurfaceTriangles (faces);
+		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()
+  {
+    if (hextimestamp > mesh->GetTimeStamp () &&
+	hextimestamp > vispar.clipplanetimestamp )
+      return;
+
+    if (!lock)
+      {
+	lock = new NgLock (mesh->Mutex());
+	lock -> Lock();
+      }
+
+    hextimestamp = NextTimeStamp();
+
+    if (hexlist) glDeleteLists (hexlist, 1);
+
+    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;
+    // int hoplotn = 1 << vispar.subdivisions;
+
+    for (ElementIndex ei = 0; ei < mesh->GetNE(); ei++)
+      {
+	const Element & el = (*mesh)[ei];
+	if (el.GetType() == HEX && !el.IsDeleted())
+	  {
+            CurvedElements & curv = mesh->GetCurvedElements();
+            if (curv.IsHighOrder()) //  && curv.IsElementCurved(ei))
+	      {
+		/* // classical
+		   glBegin (GL_QUADS);
+
+		   const ELEMENT_FACE * faces = MeshTopology :: GetFaces (HEX);
+		   const Point3d * vertices = MeshTopology :: GetVertices (HEX);
+
+		   Point<3> grid[33][33];
+		   Vec<3> gridn[33][33];
+		   Point<3> fpts[4];
+		   for (int quad = 0; quad<6; quad++)
+		   {
+		   for (int j = 0; j < 4; j++)
+		   fpts[j] = vertices[faces[quad][j]-1];
+
+		   static Point<3> c(0.5, 0.5, 0.5);
+		   if (vispar.shrink < 1)
+		   for (int j = 0; j < 4; j++)
+		   fpts[j] += (1-vispar.shrink) * (c-fpts[j]);
+
+		   Vec<3> taux = fpts[1]-fpts[0];
+		   Vec<3> tauy = fpts[3]-fpts[0];
+
+		   for (int ix = 0; ix <= hoplotn; ix++)
+		   for (int iy = 0; iy <= hoplotn; iy++)
+		   {
+		   Point<3> xl;
+		   Mat<3,3> dxdxi;
+		   double lami[4] =
+		   { (1-double(ix)/hoplotn) * (1-double(iy)/hoplotn),
+		   (  double(ix)/hoplotn) * (1-double(iy)/hoplotn),
+		   (  double(ix)/hoplotn) * (  double(iy)/hoplotn),
+		   (1-double(ix)/hoplotn) * (  double(iy)/hoplotn) };
+		   for (int l = 0; l < 3; l++)
+		   xl(l) = lami[0] * fpts[0](l) + lami[1] * fpts[1](l) +
+		   lami[2] * fpts[2](l) + lami[3] * fpts[3](l);
+
+		   curv.CalcElementTransformation (xl, ei, grid[ix][iy], dxdxi);
+
+		   Vec<3> gtaux = dxdxi * taux;
+		   Vec<3> gtauy = dxdxi * tauy;
+		   gridn[ix][iy] = Cross (gtauy, gtaux).Normalize();
+		   }
+
+		   for (int ix = 0; ix < hoplotn; ix++)
+		   for (int iy = 0; iy < hoplotn; iy++)
+		   {
+		   glNormal3dv (gridn[ix][iy]);
+		   glVertex3dv (grid[ix][iy]);
+
+		   glNormal3dv (gridn[ix+1][iy]);
+		   glVertex3dv (grid[ix+1][iy]);
+
+		   glNormal3dv (gridn[ix+1][iy+1]);
+		   glVertex3dv (grid[ix+1][iy+1]);
+
+		   glNormal3dv (gridn[ix][iy+1]);
+		   glVertex3dv (grid[ix][iy+1]);
+		   }
+		   }
+
+		   glEnd ();
+		*/
+
+		const ELEMENT_FACE * faces = MeshTopology :: GetFaces1 (HEX);
+		const Point3d * vertices = MeshTopology :: GetVertices (HEX);
+
+		Point<3> grid[11][11];
+		Point<3> fpts[4];
+		int order = vispar.subdivisions+1;
+
+		for (int quad = 0; quad<6; quad++)
+		  {
+		    for (int j = 0; j < 4; j++)
+		      fpts[j] = vertices[faces[quad][j]-1];
+
+		    static Point<3> c(0.5, 0.5, 0.5);
+		    if (vispar.shrink < 1)
+		      for (int j = 0; j < 4; j++)
+                        fpts[j] += (1-vispar.shrink) * (c-fpts[j]);
+
+		    for (int ix = 0; ix <= order; ix++)
+		      for (int iy = 0; iy <= order; iy++)
+			{
+			  double lami[4] =
+			    { (1-double(ix)/order) * (1-double(iy)/order),
+			      (  double(ix)/order) * (1-double(iy)/order),
+			      (  double(ix)/order) * (  double(iy)/order),
+			      (1-double(ix)/order) * (  double(iy)/order) };
+
+			  Point<3> xl;
+			  for (int l = 0; l < 3; l++)
+			    xl(l) = lami[0] * fpts[0](l) + lami[1] * fpts[1](l) +
+			      lami[2] * fpts[2](l) + lami[3] * fpts[3](l);
+
+			  curv.CalcElementTransformation (xl, ei, grid[ix][iy]);
+			}
+
+		    for (int j = 0; j <= order; j++)
+		      ToBernstein (order, &grid[j][0], &grid[0][1]-&grid[0][0]);
+		    for (int j = 0; j <= order; j++)
+		      ToBernstein (order, &grid[0][j], &grid[1][0]-&grid[0][0]);
+
+		    glMap2d(GL_MAP2_VERTEX_3,
+			    0.0, 1.0, &grid[0][1](0)-&grid[0][0](0), order+1,
+			    0.0, 1.0, &grid[1][0](0)-&grid[0][0](0), order+1,
+			    &grid[0][0](0));
+		    glEnable(GL_MAP2_VERTEX_3);
+		    glEnable(GL_AUTO_NORMAL);
+
+		    glMapGrid2f(8, 0.0, 1.0, 8, 0.0, 1.0);
+		    glEvalMesh2(GL_FILL, 0, 8, 0, 8);
+
+		    glDisable (GL_AUTO_NORMAL);
+		    glDisable (GL_MAP2_VERTEX_3);
+		  }
+	      }
+            else
+	      {
+		Point3d c(0,0,0);
+		if (vispar.shrink < 1)
+		  {
+		    for (int 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);
+
+		el.GetSurfaceTriangles (faces);
+		for (int j = 1; j <= faces.Size(); j++)
+		  {
+		    Element2d & face = faces.Elem(j);
+		    Point<3> lp1 = mesh->Point (el.PNum(face.PNum(1)));
+		    Point<3> lp2 = mesh->Point (el.PNum(face.PNum(2)));
+		    Point<3> lp3 = mesh->Point (el.PNum(face.PNum(3)));
+		    Vec<3> n = Cross (lp3-lp1, lp2-lp1);
+		    n.Normalize();
+		    glNormal3dv (n);
+
+		    if (vispar.shrink < 1)
+		      {
+			lp1 = c + vispar.shrink * (lp1 - c);
+			lp2 = c + vispar.shrink * (lp2 - c);
+			lp3 = c + vispar.shrink * (lp3 - c);
+		      }
+
+		    glVertex3dv (lp1);
+		    glVertex3dv (lp2);
+		    glVertex3dv (lp3);
+		  }
+
+		glEnd();
+	      }
+	  }
+      }
+    glEndList ();
+  }
+
+
+
+
+
+
+
+
+
+  void VisualSceneMesh :: BuildPyramidList()
+  {
+    if (pyramidtimestamp > mesh->GetTimeStamp () &&
+	pyramidtimestamp > vispar.clipplanetimestamp )
+      return;
+
+    if (!lock)
+      {
+	lock = new NgLock (mesh->Mutex());
+	lock -> Lock();
+      }
+
+    pyramidtimestamp = NextTimeStamp();
+
+
+    if (pyramidlist)
+      glDeleteLists (pyramidlist, 1);
+
+
+    pyramidlist = glGenLists (1);
+    glNewList (pyramidlist, GL_COMPILE);
+
+    static float pyramidcol[] = { 1.0f, 0.0f, 1.0f, 1.0f };
+    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, pyramidcol);
+
+    glLineWidth (1.0f);
+    Array<Element2d> faces;
+
+    for (ElementIndex ei = 0; ei < mesh->GetNE(); ei++)
+      {
+	const Element & el = (*mesh)[ei];
+	if (el.GetType() == PYRAMID && !el.IsDeleted())
+	  {
+            int i = ei + 1;
+
+            CurvedElements & curv = mesh->GetCurvedElements();
+            if (curv.IsHighOrder()) //  && curv.IsElementCurved(ei))
+	      {
+
+		const ELEMENT_FACE * faces = MeshTopology :: GetFaces1 (PYRAMID);
+		const Point3d * vertices = MeshTopology :: GetVertices (PYRAMID);
+
+		Point<3> grid[11][11];
+		Point<3> fpts[4];
+		int order = vispar.subdivisions+1;
+
+		for (int trig = 0; trig < 4; trig++)
+		  {
+		    for (int j = 0; j < 3; j++)
+		      fpts[j] = vertices[faces[trig][j]-1];
+
+		    static Point<3> c(0.375, 0.375, 0.25);
+		    if (vispar.shrink < 1)
+		      for (int j = 0; j < 3; j++)
+                        fpts[j] += (1-vispar.shrink) * (c-fpts[j]);
+
+		    for (int ix = 0; ix <= order; ix++)
+		      for (int iy = 0; iy <= order; iy++)
+			{
+			  double lami[3] =
+			    { (1-double(ix)/order) * (1-double(iy)/order),
+			      (  double(ix)/order) * (1-double(iy)/order),
+			      double(iy)/order };
+
+			  Point<3> xl;
+			  for (int l = 0; l < 3; l++)
+			    xl(l) = lami[0] * fpts[0](l) + lami[1] * fpts[1](l) +
+			      lami[2] * fpts[2](l);
+
+			  curv.CalcElementTransformation (xl, i-1, grid[ix][iy]);
+			}
+
+		    for (int j = 0; j <= order; j++)
+		      ToBernstein (order, &grid[j][0], &grid[0][1]-&grid[0][0]);
+		    for (int j = 0; j <= order; j++)
+		      ToBernstein (order, &grid[0][j], &grid[1][0]-&grid[0][0]);
+
+		    glMap2d(GL_MAP2_VERTEX_3,
+			    0.0, 1.0, &grid[0][1](0)-&grid[0][0](0), order+1,
+			    0.0, 1.0, &grid[1][0](0)-&grid[0][0](0), order+1,
+			    &grid[0][0](0));
+		    glEnable(GL_MAP2_VERTEX_3);
+		    glEnable(GL_AUTO_NORMAL);
+
+		    glMapGrid2f(8, 0.0, 0.999f, 8, 0.0, 1.0);
+		    glEvalMesh2(GL_FILL, 0, 8, 0, 8);
+
+		    glDisable (GL_AUTO_NORMAL);
+		    glDisable (GL_MAP2_VERTEX_3);
+		  }
+
+		for (int quad = 4; quad < 5; quad++)
+		  {
+		    for (int j = 0; j < 4; j++)
+		      fpts[j] = vertices[faces[quad][j]-1];
+
+		    static Point<3> c(0.375, 0.375, 0.25);
+		    if (vispar.shrink < 1)
+		      for (int j = 0; j < 4; j++)
+                        fpts[j] += (1-vispar.shrink) * (c-fpts[j]);
+
+		    for (int ix = 0; ix <= order; ix++)
+		      for (int iy = 0; iy <= order; iy++)
+			{
+			  double lami[4] =
+			    { (1-double(ix)/order) * (1-double(iy)/order),
+			      (  double(ix)/order) * (1-double(iy)/order),
+			      (  double(ix)/order) * (  double(iy)/order),
+			      (1-double(ix)/order) * (  double(iy)/order) };
+
+			  Point<3> xl;
+			  for (int l = 0; l < 3; l++)
+			    xl(l) =
+			      lami[0] * fpts[0](l) + lami[1] * fpts[1](l) +
+			      lami[2] * fpts[2](l) + lami[3] * fpts[3](l);
+
+			  curv.CalcElementTransformation (xl, ei, grid[ix][iy]);
+			}
+
+		    for (int j = 0; j <= order; j++)
+		      ToBernstein (order, &grid[j][0], &grid[0][1]-&grid[0][0]);
+		    for (int j = 0; j <= order; j++)
+		      ToBernstein (order, &grid[0][j], &grid[1][0]-&grid[0][0]);
+
+		    glMap2d(GL_MAP2_VERTEX_3,
+			    0.0, 1.0, &grid[0][1](0)-&grid[0][0](0), order+1,
+			    0.0, 1.0, &grid[1][0](0)-&grid[0][0](0), order+1,
+			    &grid[0][0](0));
+		    glEnable(GL_MAP2_VERTEX_3);
+		    glEnable(GL_AUTO_NORMAL);
+
+		    glMapGrid2f(8, 0.0, 1.0, 8, 0.0, 1.0);
+		    glEvalMesh2(GL_FILL, 0, 8, 0, 8);
+
+		    glDisable (GL_AUTO_NORMAL);
+		    glDisable (GL_MAP2_VERTEX_3);
+		  }
+
+
+
+
+
+
+		/*
+		  int hoplotn = 1 << vispar.subdivisions;
+
+		  const ELEMENT_FACE * faces = MeshTopology :: GetFaces (PYRAMID);
+		  const Point3d * vertices = MeshTopology :: GetVertices (PYRAMID);
+
+		  Point<3> grid[33][33];
+		  Vec<3> gridn[33][33];
+
+
+		  glBegin (GL_TRIANGLES);
+
+		  for (int trig = 0; trig < 4; trig++)
+		  {
+		  Point<3> p0 = vertices[faces[trig][0]-1];
+		  Point<3> p1 = vertices[faces[trig][1]-1];
+		  Point<3> p2 = vertices[faces[trig][2]-1];
+
+		  if (vispar.shrink < 1)
+		  {
+		  static Point<3> c(0.375, 0.375, 0.25);
+		  p0 = c + vispar.shrink * (p0 - c);
+		  p1 = c + vispar.shrink * (p1 - c);
+		  p2 = c + vispar.shrink * (p2 - c);
+		  }
+
+
+		  Vec<3> taux = p0-p2;
+		  Vec<3> tauy = p1-p2;
+		  Vec<3> gtaux, gtauy;
+
+		  Point<3> xl;
+		  Mat<3,3> dxdxi;
+
+		  for (int ix = 0; ix <= hoplotn; ix++)
+		  for (int iy = 0; iy <= hoplotn-ix; iy++)
+		  {
+		  for (int l = 0; l < 3; l++)
+		  xl(l) =
+		  (1-double(ix+iy)/hoplotn) * p2(l) +
+		  (double(ix)/hoplotn) * p0(l) +
+		  (double(iy)/hoplotn) * p1(l);
+
+		  curv.CalcElementTransformation (xl, i-1, grid[ix][iy], dxdxi);
+
+		  gtaux = dxdxi * taux;
+		  gtauy = dxdxi * tauy;
+		  gridn[ix][iy] = Cross (gtauy, gtaux).Normalize();
+		  }
+
+		  for (int ix = 0; ix < hoplotn; ix++)
+		  for (int iy = 0; iy < hoplotn-ix; iy++)
+		  {
+		  glNormal3dv (gridn[ix][iy]);
+		  glVertex3dv (grid[ix][iy]);
+
+		  glNormal3dv (gridn[ix+1][iy]);
+		  glVertex3dv (grid[ix+1][iy]);
+
+		  glNormal3dv (gridn[ix][iy+1]);
+		  glVertex3dv (grid[ix][iy+1]);
+
+		  if (iy < hoplotn-ix-1)
+		  {
+		  glNormal3dv (gridn[ix][iy+1]);
+		  glVertex3dv (grid[ix][iy+1]);
+
+		  glNormal3dv (gridn[ix+1][iy]);
+		  glVertex3dv (grid[ix+1][iy]);
+
+		  glNormal3dv (gridn[ix+1][iy+1]);
+		  glVertex3dv (grid[ix+1][iy+1]);
+		  }
+		  }
+		  }
+
+		  glEnd ();
+
+
+
+
+		  glBegin (GL_QUADS);
+
+		  for (int quad = 4; quad < 5; quad++)
+		  {
+		  Point<3> p0 = vertices[faces[quad][0]-1];
+		  Point<3> p1 = vertices[faces[quad][1]-1];
+		  Point<3> p2 = vertices[faces[quad][2]-1];
+		  Point<3> p3 = vertices[faces[quad][3]-1];
+
+		  if (vispar.shrink < 1)
+		  {
+		  static Point<3> c(0.375, 0.375, 0.25);
+		  p0 = c + vispar.shrink * (p0 - c);
+		  p1 = c + vispar.shrink * (p1 - c);
+		  p2 = c + vispar.shrink * (p2 - c);
+		  p3 = c + vispar.shrink * (p3 - c);
+		  }
+
+		  Vec<3> taux = p1-p0;
+		  Vec<3> tauy = p3-p0;
+		  Vec<3> gtaux, gtauy;
+
+		  Point<3> xl, xg;
+		  Mat<3,3> dxdxi;
+
+		  for (int ix = 0; ix <= hoplotn; ix++)
+		  for (int iy = 0; iy <= hoplotn; iy++)
+		  {
+		  Point<3> xl;
+		  for (int l = 0; l < 3; l++)
+		  xl(l) =
+		  (1-double(ix)/hoplotn)*(1-double(iy)/hoplotn) * p0(l) +
+		  (  double(ix)/hoplotn)*(1-double(iy)/hoplotn) * p1(l) +
+		  (  double(ix)/hoplotn)*(  double(iy)/hoplotn) * p2(l) +
+		  (1-double(ix)/hoplotn)*(  double(iy)/hoplotn) * p3(l);
+
+		  curv.CalcElementTransformation (xl, i-1, grid[ix][iy], dxdxi);
+
+		  gtaux = dxdxi * taux;
+		  gtauy = dxdxi * tauy;
+		  gridn[ix][iy] = Cross (gtauy, gtaux).Normalize();
+		  }
+
+		  for (int ix = 0; ix < hoplotn; ix++)
+		  for (int iy = 0; iy < hoplotn; iy++)
+		  {
+		  glNormal3dv (gridn[ix][iy]);
+		  glVertex3dv (grid[ix][iy]);
+
+		  glNormal3dv (gridn[ix+1][iy]);
+		  glVertex3dv (grid[ix+1][iy]);
+
+		  glNormal3dv (gridn[ix+1][iy+1]);
+		  glVertex3dv (grid[ix+1][iy+1]);
+
+		  glNormal3dv (gridn[ix][iy+1]);
+		  glVertex3dv (grid[ix][iy+1]);
+		  }
+		  }
+
+		  glEnd ();
+		*/
+
+
+	      }
+            else
+	      {
+
+
+
+		Point3d c(0,0,0);
+		if (vispar.shrink < 1)
+		  {
+		    for (int 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);
+
+		if (el.PNum(1))
+		  {
+		    glBegin (GL_TRIANGLES);
+
+		    for (int 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)
+  {
+    BuildFilledList (true);
+
+    MouseDblClickSelect(px,py,clipplane,backcolor,transformationmat,center,rad,
+			filledlist,selelement,selface,seledge,selpoint,selpoint2,locpi);
+
+
+    selecttimestamp = NextTimeStamp();
+
+    if(lock)
+      {
+	lock->UnLock();
+	delete lock;
+	lock = NULL;
+      }
+
+    /*
+      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];
+
+      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[0] == selpoint && seg[1] == selpoint2 ||
+      seg[1] == selpoint && seg[0] == selpoint2)
+      {
+      seledge = seg.edgenr;
+      cout << "seledge = " << seledge << endl;
+      }
+      }
+
+      }
+      else
+      {
+      selface = -1;
+      selelement = -1;
+      selpoint = -1;
+      selpoint2 = -1;
+      }
+
+      glDisable(GL_CLIP_PLANE0);
+
+      selecttimestamp = NextTimeStamp();
+    */
+
+  }
+
+
+
+
+
+  void MouseDblClickSelect (const int px, const int py,
+			    const GLdouble * clipplane, const GLdouble backcolor,
+			    const float * transformationmat,
+			    const Point3d & center,
+			    const double rad,
+			    const int displaylist,
+			    int & selelement, int & selface, int & seledge, int & selpoint,
+			    int & selpoint2, int & locpi)
+  {
+    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 (displaylist);
+
+    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[0] == selpoint && seg[1] == selpoint2) ||
+		 (seg[1] == selpoint && seg[0] == selpoint2) )
+	      {
+		seledge = seg.edgenr;
+		cout << "seledge = " << seledge << endl;
+	      }
+	  }
+
+      }
+    else
+      {
+	selface = -1;
+	selelement = -1;
+	selpoint = -1;
+	selpoint2 = -1;
+      }
+
+    glDisable(GL_CLIP_PLANE0);
+
+
+
+#ifdef PARALLELGL
+    vsmesh.Broadcast ();
+#endif
+  }
+
+
+  void VisualSceneMesh :: SetSelectedFace (int asf)
+  {
+    selface = asf;
+    selecttimestamp = NextTimeStamp();
+  }
+
+
+
+
+}
+
+
diff --git a/contrib/Netgen/libsrc/visualization/vsocc.cpp b/contrib/Netgen/libsrc/visualization/vsocc.cpp
new file mode 100644
index 0000000000..c16984ccc7
--- /dev/null
+++ b/contrib/Netgen/libsrc/visualization/vsocc.cpp
@@ -0,0 +1,762 @@
+#ifndef NOTCL
+
+#ifdef OCCGEOMETRY
+
+#include <mystdlib.h>
+#include <myadt.hpp>
+#include <meshing.hpp>
+
+#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 "Poly_Polygon3D.hxx"
+#include "Poly_PolygonOnTriangulation.hxx"
+
+#include <visual.hpp>
+
+namespace netgen
+{
+   extern OCCGeometry * occgeometry;
+
+   /* *********************** Draw OCC Geometry **************** */
+
+   VisualSceneOCCGeometry :: VisualSceneOCCGeometry ()
+   : VisualScene()
+   {
+      trilists.SetSize(0);
+      linelists.SetSize(1);
+
+   }
+
+   VisualSceneOCCGeometry :: ~VisualSceneOCCGeometry ()
+   {
+      ;
+   }
+
+   void VisualSceneOCCGeometry :: DrawScene ()
+   {
+      if ( occgeometry->changed )
+      {
+         BuildScene();
+         occgeometry -> changed = 0;
+      }
+
+      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);
+      
+      //  glEnable (GL_LIGHTING);
+
+      double shine = vispar.shininess;
+      // double transp = vispar.transp;
+
+      glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, shine);
+      glLogicOp (GL_COPY);
+
+      glEnable (GL_NORMALIZE);
+
+      float mat_col[] = {  0.2f, 0.2f, 0.8f, 1.0f};
+      glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_col);
+
+      glPolygonOffset (1, 1);
+      glEnable (GL_POLYGON_OFFSET_FILL);
+
+      // Philippose - 30/01/2009
+      // Added clipping planes to Geometry view
+      SetClippingPlane();
+
+      GLfloat matcoledge[] = {  0, 0, 1, 1};
+      GLfloat matcolhiedge[] = {  1, 0, 0, 1};
+
+      glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, matcoledge);
+      glLineWidth (1.0f);
+
+      if (vispar.occshowedges) glCallList (linelists.Get(1));
+      if (vispar.occshowsurfaces) glCallList (trilists.Get(1));
+
+      glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, matcolhiedge);
+      glLineWidth (5.0f);
+
+      if (vispar.occshowedges) glCallList (linelists.Get(2));
+
+      for (int i = 1; i <= occgeometry->vmap.Extent(); i++)
+      if (occgeometry->vvispar[i-1].IsHighlighted())
+      {
+         glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, matcolhiedge);
+         glLineWidth (5.0f);
+
+         glBegin (GL_LINES);
+
+         gp_Pnt p = BRep_Tool::Pnt(TopoDS::Vertex(occgeometry->vmap(i)));
+         double d = rad/100;
+         glVertex3f (p.X()-d, p.Y(), p.Z());
+         glVertex3f (p.X()+d, p.Y(), p.Z());
+         glVertex3f (p.X(), p.Y()-d, p.Z());
+         glVertex3f (p.X(), p.Y()+d, p.Z());
+         glVertex3f (p.X(), p.Y(), p.Z()-d);
+         glVertex3f (p.X(), p.Y(), p.Z()+d);
+         glEnd();
+      }
+
+      glDisable (GL_POLYGON_OFFSET_FILL);
+
+      glPopMatrix();
+      //  DrawCoordinateCross ();
+      //  DrawNetgenLogo ();
+      glFinish();
+
+      glDisable (GL_POLYGON_OFFSET_FILL);
+   }
+
+   /*
+    void VisualSceneOCCGeometry :: BuildScene (int zoomall)
+    {
+    int i = 0, j, k;
+
+    TopExp_Explorer ex, ex_edge;
+
+    if (vispar.occvisproblemfaces || (occgeometry -> changed != 2))
+    {
+    Box<3> bb = occgeometry -> GetBoundingBox();
+
+    center = bb.Center();
+    rad = bb.Diam() / 2;
+
+
+
+    if (vispar.occvisproblemfaces)
+    {
+    for (i = 1; i <= occgeometry->fmap.Extent(); i++)
+    if (occgeometry->facemeshstatus[i-1] == -1)
+    {
+    GProp_GProps system;
+    BRepGProp::LinearProperties(occgeometry->fmap(i), system);
+    gp_Pnt pnt = system.CentreOfMass();
+    center = Point<3> (pnt.X(), pnt.Y(), pnt.Z());
+    cout << "Setting center to mid of face " << i << " = " << center << endl;
+    }
+    }
+
+
+    CalcTransformationMatrices();
+    }
+
+
+    for (i = 1; i <= linelists.Size(); i++)
+    glDeleteLists (linelists.Elem(i), 1);
+    linelists.SetSize(0);
+
+    linelists.Append (glGenLists (1));
+    glNewList (linelists.Last(), GL_COMPILE);
+
+    i = 0;
+    for (ex_edge.Init(occgeometry -> shape, TopAbs_EDGE);
+    ex_edge.More(); ex_edge.Next())
+    {
+    if (BRep_Tool::Degenerated(TopoDS::Edge(ex_edge.Current()))) continue;
+    i++;
+
+
+    TopoDS_Edge edge = TopoDS::Edge(ex_edge.Current());
+
+    Handle(Poly_PolygonOnTriangulation) aEdgePoly;
+    Handle(Poly_Triangulation) T;
+    TopLoc_Location aEdgeLoc;
+    BRep_Tool::PolygonOnTriangulation(edge, aEdgePoly, T, aEdgeLoc);
+
+    if(aEdgePoly.IsNull())
+    {
+    cout << "cannot visualize edge " << i << endl;
+    continue;
+    }
+
+    glBegin (GL_LINE_STRIP);
+
+    int nbnodes = aEdgePoly -> NbNodes();
+    for (j = 1; j <= nbnodes; j++)
+    {
+    gp_Pnt p = (T -> Nodes())(aEdgePoly->Nodes()(j)).Transformed(aEdgeLoc);
+    glVertex3f (p.X(), p.Y(), p.Z());
+    }
+
+    glEnd ();
+
+
+    }
+
+    glEndList ();
+
+    for (i = 1; i <= trilists.Size(); i++)
+    glDeleteLists (trilists.Elem(i), 1);
+    trilists.SetSize(0);
+
+
+    trilists.Append (glGenLists (1));
+    glNewList (trilists.Last(), GL_COMPILE);
+
+    i = 0;
+
+    TopExp_Explorer exp0, exp1, exp2, exp3;
+    int shapenr = 0;
+    for (exp0.Init(occgeometry -> shape, TopAbs_SOLID); exp0.More(); exp0.Next())
+    {
+    shapenr++;
+
+    if (vispar.occshowvolumenr != 0 &&
+    vispar.occshowvolumenr != shapenr) continue;
+
+    float mat_col[4];
+    mat_col[3] = 1;
+    switch (shapenr)
+    {
+    case 1:
+    mat_col[0] = 0.2;
+    mat_col[1] = 0.2;
+    mat_col[2] = 0.8;
+    break;
+    case 2:
+    mat_col[0] = 0.8;
+    mat_col[1] = 0.2;
+    mat_col[2] = 0.8;
+    break;
+    case 3:
+    mat_col[0] = 0.2;
+    mat_col[1] = 0.8;
+    mat_col[2] = 0.8;
+    break;
+    case 4:
+    mat_col[0] = 0.8;
+    mat_col[1] = 0.2;
+    mat_col[2] = 0.2;
+    break;
+    case 5:
+    mat_col[0] = 0.8;
+    mat_col[1] = 0.8;
+    mat_col[2] = 0.8;
+    break;
+    case 6:
+    mat_col[0] = 0.6;
+    mat_col[1] = 0.6;
+    mat_col[2] = 0.6;
+    break;
+    case 7:
+    mat_col[0] = 0.2;
+    mat_col[1] = 0.8;
+    mat_col[2] = 0.2;
+    break;
+    case 8:
+    mat_col[0] = 0.8;
+    mat_col[1] = 0.8;
+    mat_col[2] = 0.2;
+    break;
+    default:
+    //	  mat_col[0] = 1-(1.0/double(shapenr));
+    //	  mat_col[1] = 0.5;
+    mat_col[0] = 0.5+double((shapenr*shapenr*shapenr*shapenr) % 10)/20.0;
+    mat_col[1] = 0.5+double(int(shapenr*shapenr*shapenr*shapenr*sin(double(shapenr))) % 10)/20.0;
+    mat_col[2] = 0.5+double((shapenr*shapenr*shapenr) % 10)/20.0;
+    }
+
+    glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_col);
+
+    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()));
+
+    i = occgeometry->fmap.FindIndex(face);
+
+    TopLoc_Location loc;
+    Handle(Geom_Surface) surf = BRep_Tool::Surface (face);
+    BRepAdaptor_Surface sf(face, Standard_False);
+    BRepLProp_SLProps prop(sf, 1, 1e-5);
+    Handle(Poly_Triangulation) triangulation = BRep_Tool::Triangulation (face, loc);
+
+    if (triangulation.IsNull())
+    {
+    cout << "cannot visualize face " << i << endl;
+    continue;
+    }
+
+    if (vispar.occvisproblemfaces)
+    {
+    switch (occgeometry->facemeshstatus[i-1])
+    {
+    case 0:
+    mat_col[0] = 0.2;
+    mat_col[1] = 0.2;
+    mat_col[2] = 0.8;
+    break;
+    case 1:
+    mat_col[0] = 0.2;
+    mat_col[1] = 0.8;
+    mat_col[2] = 0.2;
+    break;
+    case -1:
+    mat_col[0] = 0.8;
+    mat_col[1] = 0.2;
+    mat_col[2] = 0.2;
+    break;
+    }
+    glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_col);
+
+    }
+    glBegin (GL_TRIANGLES);
+
+    int ntriangles = triangulation -> NbTriangles();
+    for (j = 1; j <= ntriangles; j++)
+    {
+    Poly_Triangle triangle = (triangulation -> Triangles())(j);
+    for (k = 1; k <= 3; k++)
+    {
+    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);
+
+    if (face.Orientation() == TopAbs_REVERSED) n *= -1;
+    glNormal3f (n.X(), n.Y(), n.Z());
+    glVertex3f (pnt.X(), pnt.Y(), pnt.Z());
+    }
+    }
+    glEnd ();
+
+    }
+    }
+
+
+    glEndList ();
+
+    }
+    */
+
+   void VisualSceneOCCGeometry :: BuildScene (int zoomall)
+   {
+     if (occgeometry -> changed == OCCGEOMETRYVISUALIZATIONFULLCHANGE)
+       {
+         occgeometry -> BuildVisualizationMesh (vispar.occdeflection);
+
+         center = occgeometry -> Center();
+         rad = occgeometry -> GetBoundingBox().Diam() / 2;
+
+         if (vispar.occzoomtohighlightedentity)
+         {
+            bool hilite = false;
+            bool hiliteonepoint = false;
+            Bnd_Box bb;
+
+            for (int i = 1; i <= occgeometry->fmap.Extent(); i++)
+            if (occgeometry->fvispar[i-1].IsHighlighted())
+            {
+               hilite = true;
+               BRepBndLib::Add (occgeometry->fmap(i), bb);
+            }
+
+            for (int i = 1; i <= occgeometry->emap.Extent(); i++)
+            if (occgeometry->evispar[i-1].IsHighlighted())
+            {
+               hilite = true;
+               BRepBndLib::Add (occgeometry->emap(i), bb);
+            }
+
+            for (int i = 1; i <= occgeometry->vmap.Extent(); i++)
+            if (occgeometry->vvispar[i-1].IsHighlighted())
+            {
+               hiliteonepoint = true;
+               BRepBndLib::Add (occgeometry->vmap(i), bb);
+            }
+
+            if (hilite || hiliteonepoint)
+            {
+               double x1,y1,z1,x2,y2,z2;
+               bb.Get (x1,y1,z1,x2,y2,z2);
+               Point<3> p1 = Point<3> (x1,y1,z1);
+               Point<3> p2 = Point<3> (x2,y2,z2);
+               Box<3> boundingbox(p1,p2);
+
+               center = boundingbox.Center();
+               if (hiliteonepoint)
+               rad = occgeometry -> GetBoundingBox().Diam() / 100;
+               else
+               rad = boundingbox.Diam() / 2;
+            }
+         }
+
+         CalcTransformationMatrices();
+      }
+
+      // Clear lists
+
+      for (int i = 1; i <= linelists.Size(); i++)
+      glDeleteLists (linelists.Elem(i), 1);
+      linelists.SetSize(0);
+
+      for (int i = 1; i <= trilists.Size(); i++)
+      glDeleteLists (trilists.Elem(i), 1);
+      trilists.SetSize(0);
+
+      // Total wireframe
+
+      linelists.Append (glGenLists (1));
+      glNewList (linelists.Last(), GL_COMPILE);
+
+      for (int i = 1; i <= occgeometry->emap.Extent(); i++)
+      {
+         TopoDS_Edge edge = TopoDS::Edge(occgeometry->emap(i));
+         if (BRep_Tool::Degenerated(edge)) continue;
+         if (occgeometry->evispar[i-1].IsHighlighted()) continue;
+
+         Handle(Poly_PolygonOnTriangulation) aEdgePoly;
+         Handle(Poly_Triangulation) T;
+         TopLoc_Location aEdgeLoc;
+         BRep_Tool::PolygonOnTriangulation(edge, aEdgePoly, T, aEdgeLoc);
+
+         if(aEdgePoly.IsNull())
+         {
+            (*testout) << "visualizing edge " << occgeometry->emap.FindIndex (edge)
+            << " without using the occ visualization triangulation" << endl;
+
+            double s0, s1;
+            Handle(Geom_Curve) c = BRep_Tool::Curve(edge, s0, s1);
+
+            glBegin (GL_LINE_STRIP);
+            for (int i = 0; i<=50; i++)
+            {
+               gp_Pnt p = c->Value (s0 + i*(s1-s0)/50.0);
+               glVertex3f (p.X(),p.Y(),p.Z());
+            }
+            glEnd ();
+
+            continue;
+         }
+
+         int nbnodes = aEdgePoly -> NbNodes();
+         glBegin (GL_LINE_STRIP);
+         for (int j = 1; j <= nbnodes; j++)
+         {
+            gp_Pnt p = (T -> Nodes())(aEdgePoly->Nodes()(j)).Transformed(aEdgeLoc);
+            glVertex3f (p.X(), p.Y(), p.Z());
+         }
+         glEnd ();
+      }
+
+      glEndList ();
+
+      // Highlighted edge list
+
+      linelists.Append (glGenLists (1));
+      glNewList (linelists.Last(), GL_COMPILE);
+
+      for (int i = 1; i <= occgeometry->emap.Extent(); i++)
+      if (occgeometry->evispar[i-1].IsHighlighted())
+      {
+         TopoDS_Edge edge = TopoDS::Edge(occgeometry->emap(i));
+         if (BRep_Tool::Degenerated(edge)) continue;
+
+         Handle(Poly_PolygonOnTriangulation) aEdgePoly;
+         Handle(Poly_Triangulation) T;
+         TopLoc_Location aEdgeLoc;
+         BRep_Tool::PolygonOnTriangulation(edge, aEdgePoly, T, aEdgeLoc);
+
+         if(aEdgePoly.IsNull())
+         {
+            (*testout) << "visualizing edge " << occgeometry->emap.FindIndex (edge)
+            << " without using the occ visualization triangulation" << endl;
+
+            double s0, s1;
+            Handle(Geom_Curve) c = BRep_Tool::Curve(edge, s0, s1);
+
+            glBegin (GL_LINE_STRIP);
+            for (int i = 0; i<=50; i++)
+            {
+               gp_Pnt p = c->Value (s0 + i*(s1-s0)/50.0);
+               glVertex3f (p.X(),p.Y(),p.Z());
+            }
+            glEnd ();
+
+            continue;
+         }
+
+         int nbnodes = aEdgePoly -> NbNodes();
+         glBegin (GL_LINE_STRIP);
+         for (int j = 1; j <= nbnodes; j++)
+         {
+            gp_Pnt p = (T -> Nodes())(aEdgePoly->Nodes()(j)).Transformed(aEdgeLoc);
+            glVertex3f (p.X(), p.Y(), p.Z());
+         }
+         glEnd ();
+      }
+
+      glEndList ();
+
+      // display faces
+
+      trilists.Append (glGenLists (1));
+      glNewList (trilists.Last(), GL_COMPILE);
+
+      for (int i = 1; i <= occgeometry->fmap.Extent(); i++)
+      {
+         if (!occgeometry->fvispar[i-1].IsVisible()) continue;
+
+         glLoadName (i);
+         float mat_col[4];
+         mat_col[3] = 1;
+
+         TopoDS_Face face = TopoDS::Face(occgeometry->fmap(i));
+
+         if (!occgeometry->fvispar[i-1].IsHighlighted())
+         {
+            // Philippose - 30/01/2009
+            // OpenCascade XDE Support
+            Quantity_Color face_colour;
+            // Philippose - 23/02/2009
+            // Check to see if colours have been extracted first!!
+            // Forum bug-fox (Jean-Yves - 23/02/2009)
+            if(!(occgeometry->face_colours.IsNull())
+               && (occgeometry->face_colours->GetColor(face,XCAFDoc_ColorSurf,face_colour)))
+            {
+               mat_col[0] = face_colour.Red();
+               mat_col[1] = face_colour.Green();
+               mat_col[2] = face_colour.Blue();
+            }
+            else
+            {
+               mat_col[0] = 0.0;
+               mat_col[1] = 1.0;
+               mat_col[2] = 0.0;
+            }
+         }
+         else
+         {
+            mat_col[0] = 0.8;
+            mat_col[1] = 0.2;
+            mat_col[2] = 0.2;
+         }
+
+         glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_col);
+
+         TopLoc_Location loc;
+         Handle(Geom_Surface) surf = BRep_Tool::Surface (face);
+         BRepAdaptor_Surface sf(face, Standard_False);
+         BRepLProp_SLProps prop(sf, 1, 1e-5);
+         Handle(Poly_Triangulation) triangulation = BRep_Tool::Triangulation (face, loc);
+
+         if (triangulation.IsNull())
+         {
+            cout << "cannot visualize face " << i << endl;
+            occgeometry->fvispar[i-1].SetNotDrawable();
+            continue;
+         }
+
+         gp_Pnt2d uv;
+         gp_Pnt pnt;
+         gp_Vec n;
+
+         glBegin (GL_TRIANGLES);
+
+         int ntriangles = triangulation -> NbTriangles();
+         for (int j = 1; j <= ntriangles; j++)
+         {
+            Poly_Triangle triangle = (triangulation -> Triangles())(j);
+            gp_Pnt p[3];
+            for (int k = 1; k <= 3; k++)
+            p[k-1] = (triangulation -> Nodes())(triangle(k)).Transformed(loc);
+
+            for (int k = 1; k <= 3; k++)
+            {
+               uv = (triangulation -> UVNodes())(triangle(k));
+               prop.SetParameters (uv.X(), uv.Y());
+
+               //	      surf->D0 (uv.X(), uv.Y(), pnt);
+
+               if (prop.IsNormalDefined())
+               n = prop.Normal();
+               else
+               {
+                  (*testout) << "Visualization of face " << i
+                  << ": Normal vector not defined" << endl;
+                  //		  n = gp_Vec (0,0,0);
+                  gp_Vec a(p[0],p[1]);
+                  gp_Vec b(p[0],p[2]);
+                  n = b^a;
+               }
+
+               if (face.Orientation() == TopAbs_REVERSED) n *= -1;
+               glNormal3f (n.X(), n.Y(), n.Z());
+               glVertex3f (p[k-1].X(), p[k-1].Y(), p[k-1].Z());
+            }
+         }
+         glEnd ();
+
+      }
+      glEndList ();
+
+   }
+
+   void SelectFaceInOCCDialogTree (int facenr);
+
+   void VisualSceneOCCGeometry :: MouseDblClick (int px, int py)
+   {
+      int 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);
+
+      glDisable(GL_CLIP_PLANE0);
+
+      // Philippose - 30/01/2009
+      // Enable clipping planes for Selection mode in OCC Geometry
+      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 ();
+      }
+
+      glCallList (trilists.Get(1));
+
+      glDisable (GL_POLYGON_OFFSET_FILL);
+
+      glPopName();
+
+      glMatrixMode (GL_PROJECTION);
+      glPopMatrix();
+
+      glMatrixMode (GL_MODELVIEW);
+      glPopMatrix();
+
+      glFlush();
+
+      hits = glRenderMode (GL_RENDER);
+
+      int minname = 0;
+      GLuint mindepth = 0;
+
+      // find clippingplane
+      GLuint clipdepth = 0; // GLuint(-1);
+
+      for (int i = 0; i < hits; i++)
+      {
+         int curname = selbuf[4*i+3];
+         if (!curname) clipdepth = selbuf[4*i+1];
+      }
+
+      for (int i = 0; i < hits; i++)
+      {
+         int curname = selbuf[4*i+3];
+         GLuint curdepth = selbuf[4*i+1];
+         if (curname && (curdepth> clipdepth) &&
+               (curdepth < mindepth || !minname))
+         {
+            mindepth = curdepth;
+            minname = curname;
+         }
+      }
+
+      occgeometry->LowLightAll();
+
+      if (minname)
+      {
+         occgeometry->fvispar[minname-1].Highlight();
+
+         if (vispar.occzoomtohighlightedentity)
+         occgeometry->changed = OCCGEOMETRYVISUALIZATIONFULLCHANGE;
+         else
+         occgeometry->changed = OCCGEOMETRYVISUALIZATIONHALFCHANGE;
+         cout << "Selected face: " << minname << endl;
+      }
+      else
+      {
+         occgeometry->changed = OCCGEOMETRYVISUALIZATIONHALFCHANGE;
+      }
+
+      glDisable(GL_CLIP_PLANE0);
+
+      SelectFaceInOCCDialogTree (minname);
+
+      // Philippose - 30/01/2009
+      // Set the currently selected face in the array
+      // for local face mesh size definition
+      occgeometry->SetSelectedFace(minname);
+
+      //  selecttimestamp = NextTimeStamp();
+   }
+
+}
+
+#endif
+
+#endif // NOTCL
diff --git a/contrib/Netgen/libsrc/visualization/vssolution.cpp b/contrib/Netgen/libsrc/visualization/vssolution.cpp
new file mode 100644
index 0000000000..8ea46ddf0a
--- /dev/null
+++ b/contrib/Netgen/libsrc/visualization/vssolution.cpp
@@ -0,0 +1,4537 @@
+#ifndef NOTCL
+#include <mystdlib.h>
+#include "incvis.hpp"
+
+
+#include <myadt.hpp>
+#include <meshing.hpp>
+#include <csg.hpp>
+#include <stlgeom.hpp>
+
+// #include <parallel.hpp>
+#include <visual.hpp>
+
+
+namespace netgen
+{
+  extern AutoPtr<Mesh> mesh;
+  extern VisualSceneMesh vsmesh;
+
+
+  VisualSceneSolution :: SolData :: SolData ()
+    : name (0), data (0), solclass(0)
+  { ; }
+
+  VisualSceneSolution :: SolData :: ~SolData ()
+  {
+    delete [] name;
+    delete data;
+    delete solclass;
+  }
+
+  
+  VisualSceneSolution :: VisualSceneSolution ()
+    : VisualScene()
+  {
+    surfellist = 0;
+    linelist = 0;
+    clipplanelist_scal = 0;
+    clipplanelist_vec = 0;
+    isolinelist = 0;
+    clipplane_isolinelist = 0;
+    surface_vector_list = 0;
+    isosurface_list = 0;
+
+    fieldlineslist = 0;
+    pointcurvelist = 0;
+
+    num_fieldlineslists = 0;
+
+
+    surfeltimestamp = GetTimeStamp();
+    surfellinetimestamp = GetTimeStamp();
+    clipplanetimestamp = GetTimeStamp();
+    solutiontimestamp = GetTimeStamp();
+    fieldlinestimestamp = GetTimeStamp();
+    pointcurve_timestamp = GetTimeStamp();
+    surface_vector_timestamp = GetTimeStamp();
+    isosurface_timestamp = GetTimeStamp();
+    timetimestamp = GetTimeStamp();
+    AddVisualizationScene ("solution", &vssolution);
+  }
+  
+  VisualSceneSolution :: ~VisualSceneSolution ()
+  {
+    ClearSolutionData();
+  }
+
+  void VisualSceneSolution :: AddSolutionData (SolData * sd)
+  {
+    NgLock meshlock1 (mesh->MajorMutex(), 1);
+
+    int funcnr = -1;
+    for (int i = 0; i < soldata.Size(); i++)
+      {
+        if (strcmp (soldata[i]->name, sd->name) == 0)
+          {
+            delete soldata[i];
+            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;
+            }
+          default:
+            nsd->size = 0;
+          }
+        solutiontimestamp = NextTimeStamp();
+      }
+  }
+
+  
+  void VisualSceneSolution :: ClearSolutionData ()
+  {
+    for (int i = 0; i < soldata.Size(); i++)
+      delete soldata[i];
+    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);
+
+
+    if (strcmp (&filename[strlen(filename)-3], "sol") == 0)
+      {
+        ofstream ost(filename);
+        for (int 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;
+              default:
+                cerr << "save solution data, case not handeld" << endl;
+              }
+      
+            ost << endl;
+            for (int j = 0; j < sol.size; j++)
+              {
+                for (int k = 0; k < sol.components; k++)
+                  ost << sol.data[j*sol.dist+k] << " ";
+                ost << "\n";
+              }
+          }
+      }
+
+
+    if (strcmp (&filename[strlen(filename)-3], "vtk") == 0)
+      {
+        string surf_fn = filename;
+        surf_fn.erase (strlen(filename)-4);
+        surf_fn += "_surf.vtk";
+
+        cout << "surface mesh = " << surf_fn << endl;
+        
+        ofstream surf_ost(surf_fn.c_str());
+
+        surf_ost << "# vtk DataFile Version 1.0\n"
+		 << "NGSolve surface mesh\n"
+		 << "ASCII\n"
+		 << "DATASET UNSTRUCTURED_GRID\n\n";
+
+        surf_ost << "POINTS " << mesh->GetNP() << " float\n";
+        for (PointIndex pi = PointIndex::BASE; pi < mesh->GetNP()+PointIndex::BASE; pi++)
+          {
+            const MeshPoint & mp = (*mesh)[pi];
+            surf_ost << mp(0) << " " << mp(1) << " " << mp(2) << "\n";
+          }
+
+        int cntverts = 0;
+        for (SurfaceElementIndex sei = 0; sei < mesh->GetNSE(); sei++)
+          cntverts += 1 + (*mesh)[sei].GetNP();
+
+        surf_ost << "\nCELLS " << mesh->GetNSE() << " " << cntverts << "\n";
+        for (SurfaceElementIndex sei = 0; sei < mesh->GetNSE(); sei++)
+          {
+            const Element2d & el = (*mesh)[sei];
+            surf_ost << el.GetNP();
+            for (int j = 0; j < el.GetNP(); j++)
+              surf_ost << " " << el[j] - PointIndex::BASE;
+            surf_ost << "\n";
+          }
+        surf_ost << "\nCELL_TYPES " << mesh->GetNSE() << "\n";
+        for (SurfaceElementIndex sei = 0; sei < mesh->GetNSE(); sei++)
+          {
+            const Element2d & el = (*mesh)[sei];
+            switch (el.GetType())
+              {
+              case QUAD: surf_ost << 9; break;
+              case TRIG: surf_ost << 5; break;
+              default:
+                cerr << "not implemented 2378" << endl;
+              }
+            surf_ost << "\n";
+          }
+
+
+       
+        ofstream ost(filename);
+
+        ost << "# vtk DataFile Version 1.0\n"
+            << "NGSolve solution\n"
+            << "ASCII\n"
+            << "DATASET UNSTRUCTURED_GRID\n\n";
+
+        ost << "POINTS " << mesh->GetNP() << " float\n";
+        for (PointIndex pi = PointIndex::BASE; pi < mesh->GetNP()+PointIndex::BASE; pi++)
+          {
+            const MeshPoint & mp = (*mesh)[pi];
+            ost << mp(0) << " " << mp(1) << " " << mp(2) << "\n";
+          }
+
+        cntverts = 0;
+        for (ElementIndex ei = 0; ei < mesh->GetNE(); ei++)
+          cntverts += 1 + (*mesh)[ei].GetNP();
+
+        ost << "\nCELLS " << mesh->GetNE() << " " << cntverts << "\n";
+        for (ElementIndex ei = 0; ei < mesh->GetNE(); ei++)
+          {
+            const Element & el = (*mesh)[ei];
+            ost << el.GetNP();
+            for (int j = 0; j < el.GetNP(); j++)
+              ost << " " << el[j] - PointIndex::BASE;
+            ost << "\n";
+          }
+        ost << "\nCELL_TYPES " << mesh->GetNE() << "\n";
+        for (ElementIndex ei = 0; ei < mesh->GetNE(); ei++)
+          {
+            const Element & el = (*mesh)[ei];
+            switch (el.GetType())
+              {
+              case TET: ost << 10; break;
+              default:
+                cerr << "not implemented 67324" << endl;
+              }
+            ost << "\n";
+          }
+
+
+        ost << "CELL_DATA " << mesh->GetNE() << "\n";
+        for (int i = 0; i < soldata.Size(); i++)
+          {
+            ost << "VECTORS bfield float\n";
+            SolutionData & sol = *(soldata[i] -> solclass);
+            double values[3];
+
+            for (int elnr = 0; elnr < mesh->GetNE(); elnr++)
+              {
+                sol.GetValue (elnr, 0.25, 0.25, 0.25, values);
+                ost << values[0] << " "  << values[1] << " "  << values[2] << "\n";
+              }
+          }
+
+        /*
+	  ost << "POINT_DATA " << mesh->GetNP() << "\n";
+	  for (int i = 0; i < soldata.Size(); i++)
+          {
+	  ost << "VECTORS bfield float\n";
+	  SolutionData & sol = *(soldata[i] -> solclass);
+            
+	  for (PointIndex pi = PointIndex::BASE; 
+	  pi < mesh->GetNP()+PointIndex::BASE; pi++)
+	  {
+	  double values[3], sumvalues[3] = { 0, 0, 0 };
+
+	  FlatArray<int> els = mesh->GetTopology().GetVertexElements(pi);
+
+	  for (int j = 0; j < els.Size(); j++)
+	  {
+	  sol.GetValue (els[j]-1, 0.25, 0.25, 0.25, values);
+	  for (int k = 0; k < 3; k++)
+	  sumvalues[k] += values[k];
+	  }
+	  for (int k = 0; k < 3; k++)
+	  sumvalues[k] /= els.Size();
+                
+	  ost << sumvalues[0] << " "  << sumvalues[1] << " "  << sumvalues[2] << "\n";
+	  }
+          }
+        */
+      } 
+    
+  }
+  
+
+
+
+  void VisualSceneSolution :: DrawScene ()
+  {
+    if (!mesh) 
+      {
+        VisualScene::DrawScene();      
+        return;
+      }
+
+    // static NgLock mem_lock(mem_mutex);
+    // mem_lock.Lock();
+
+    NgLock meshlock1 (mesh->MajorMutex(), true);
+    NgLock meshlock (mesh->Mutex(), true);
+
+    BuildScene();
+
+    CreateTexture (numtexturecols, lineartexture, GL_MODULATE);
+
+    glClearColor(backcolor, backcolor, backcolor, 1);
+    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)
+      {
+        SetTextureMode (usetexture);
+
+        glMatrixMode (GL_TEXTURE);
+        glLoadIdentity();
+        
+        if (usetexture == 1)
+          {
+            double hmax = maxval;
+            double hmin = minval;
+            if (invcolor) Swap (hmax, hmin);
+
+            if (fabs (hmax - hmin) > 1e-30) 
+              glScaled (1.0 / (hmin - hmax), 0, 0);
+            else
+              glScaled (1e30, 0, 0);
+            
+            glTranslatef (-hmax, 0, 0);
+          }
+        else
+          {
+            glTranslatef (0.5, 0, 0);
+            glRotatef(360 * vssolution.time, 0, 0, -1);
+            if (fabs (maxval) > 1e-10)
+              glScalef(0.5/maxval, 0.5/maxval, 0.5/maxval);
+            else
+              glScalef (1e10, 1e10, 1e10);
+          }
+        glMatrixMode (GL_MODELVIEW);
+      }
+
+    if (vispar.drawfilledtrigs || vispar.drawtetsdomain > 0 || vispar.drawdomainsurf > 0)
+      {
+        SetClippingPlane ();
+        
+        glCallList (surfellist);
+        glCallList (surface_vector_list);
+      
+        glDisable(GL_CLIP_PLANE0);
+      }
+
+    if (showclipsolution)
+      {
+	if (clipsolution == 1)
+	  glCallList (clipplanelist_scal);
+	if (clipsolution == 2)
+	  glCallList (clipplanelist_vec);
+      }
+
+
+    if (draw_fieldlines)
+      {
+	SetClippingPlane();
+        if (num_fieldlineslists <= 1)
+          glCallList (fieldlineslist);
+        else
+          {  // animated
+            int start = int (time / 10 * num_fieldlineslists);
+            for (int ln = 0; ln < 10; ln++)
+              {
+                int nr = fieldlineslist + (start + ln) % num_fieldlineslists;
+                glCallList (nr);
+              }
+          }
+        glDisable(GL_CLIP_PLANE0);
+      }
+
+    if(drawpointcurves)
+      {
+	glCallList(pointcurvelist);
+      }
+
+
+    glMatrixMode (GL_TEXTURE);
+    glLoadIdentity();
+    glMatrixMode (GL_MODELVIEW);
+
+    glDisable (GL_TEXTURE_1D);
+    glDisable (GL_TEXTURE_2D);
+
+    glDisable (GL_POLYGON_OFFSET_FILL);
+    glDisable (GL_COLOR_MATERIAL);
+
+    if (draw_isosurface)
+      glCallList (isosurface_list);
+    
+    
+    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 ();
+        glCallList (linelist);
+        glDisable(GL_CLIP_PLANE0);
+      }
+
+    if (numisolines)
+      {
+        SetClippingPlane ();
+        glCallList (isolinelist);
+
+        glDisable(GL_CLIP_PLANE0);
+        glCallList (clipplane_isolinelist);
+      }
+
+    glPopMatrix();
+    
+    glDisable(GL_CLIP_PLANE0);
+    DrawColorBar (minval, maxval, logscale, lineartexture);
+    
+    if (vispar.drawcoordinatecross)
+      DrawCoordinateCross ();
+    DrawNetgenLogo ();
+    
+    glFinish();  
+
+    
+    // delete lock;
+    // mem_lock.UnLock();
+  }
+  
+
+
+  void VisualSceneSolution :: 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];
+          }
+      }
+  }
+
+
+  void VisualSceneSolution :: 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)
+  {
+    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);
+    
+    
+    SolData * sol = NULL;
+    SolData * vsol = NULL;
+  
+    if (scalfunction != -1) 
+      sol = soldata[scalfunction];
+    if (vecfunction != -1)
+      vsol = soldata[vecfunction];
+
+    if (mesh->GetTimeStamp () > solutiontimestamp)
+      {
+        sol = NULL;
+        vsol = NULL;
+      }
+ 
+
+    if (sol && sol->solclass) sol->solclass->SetMultiDimComponent (multidimcomponent);
+    if (vsol && vsol->solclass) vsol->solclass->SetMultiDimComponent (multidimcomponent);
+
+    if (!autoscale || (!sol && !vsol) )
+      {
+        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;
+              }
+          }
+      
+        DrawSurfaceElements();
+      
+        surfeltimestamp = max2 (solutiontimestamp, mesh->GetTimeStamp());
+      }
+
+    if (mesh->GetTimeStamp() > surfellinetimestamp ||
+        subdivision_timestamp > surfellinetimestamp ||
+        (deform && solutiontimestamp > surfellinetimestamp) || 
+        zoomall)
+      {
+        if (linelist)
+          glDeleteLists (linelist, 1);
+      
+        linelist = glGenLists (1);
+        glNewList (linelist, GL_COMPILE);
+      
+        DrawSurfaceElementLines();
+
+        glEndList ();
+      
+        surfellinetimestamp = max2 (solutiontimestamp, mesh->GetTimeStamp());
+      }
+
+  
+
+    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 == 2)      
+          {
+            // lock->UnLock();
+            NgLock mlock (mesh->Mutex(), 0);
+            mlock.UnLock(); 
+            mesh->BuildElementSearchTree();
+            mlock.Lock();
+
+            // lock->Lock();
+          }
+
+      
+        if (vispar.clipenable && clipsolution == 1 && sol)
+	  DrawClipPlaneTrigs (); 
+
+        if (clipplanelist_vec)
+          glDeleteLists (clipplanelist_vec, 1);
+      
+        clipplanelist_vec = glGenLists (1);
+        glNewList (clipplanelist_vec, GL_COMPILE);
+
+        if (vispar.clipenable && clipsolution == 2 && vsol)
+          {
+            SetTextureMode (usetexture);
+
+            if (autoscale)
+              GetMinMax (vecfunction, 0, minval, maxval);
+
+            Array<ClipPlanePoint> cpp;
+            GetClippingPlaneGrid (cpp);
+
+            for (int i = 0; i < cpp.Size(); i++)
+              {
+                const ClipPlanePoint & p = cpp[i];
+                double values[6];
+                Vec3d v;
+
+                bool drawelem = 
+                  GetValues (vsol, p.elnr, p.lami(0), p.lami(1), p.lami(2), values);
+                RealVec3d (values, v, vsol->iscomplex, imag_part);
+
+                double val = v.Length();
+
+                if (drawelem && val > 1e-10 * maxval)
+                  {
+                    v *= (rad / val / gridsize * 0.5);
+                  
+                    SetOpenGlColor  (val);
+                    DrawCone (p.p, p.p+v, rad / gridsize * 0.2);
+                  }
+              }
+          }
+
+        glEndList ();
+      }
+
+
+    if (mesh->GetTimeStamp() > isosurface_timestamp ||
+        solutiontimestamp > isosurface_timestamp ||
+        zoomall)
+      {
+        if (isosurface_list)
+          glDeleteLists (isosurface_list, 1);
+      
+        isosurface_list = glGenLists (1);
+        glNewList (isosurface_list, GL_COMPILE);
+
+        glEnable (GL_NORMALIZE);
+        DrawIsoSurface(sol, vsol, scalcomp);
+
+        glEndList ();
+
+        isosurface_timestamp = 
+          max2 (mesh->GetTimeStamp(), solutiontimestamp);
+      }
+
+    if(mesh->GetTimeStamp() > pointcurve_timestamp ||
+       solutiontimestamp > pointcurve_timestamp)
+      {
+	if(pointcurvelist)
+	  glDeleteLists(pointcurvelist,1);
+	
+		
+	if(mesh->GetNumPointCurves() > 0)
+	  {
+	    pointcurvelist = glGenLists(1);
+	    glNewList(pointcurvelist,GL_COMPILE);
+	    //glColor3f (1.0f, 0.f, 0.f);
+	    
+	    for(int i=0; i<mesh->GetNumPointCurves(); i++)
+	      {
+		Box3d box;
+		box.SetPoint(mesh->GetPointCurvePoint(i,0));
+		for(int j=1; j<mesh->GetNumPointsOfPointCurve(i); j++)
+		  box.AddPoint(mesh->GetPointCurvePoint(i,j));
+		double diam = box.CalcDiam();
+			     
+		double thick = min2(0.1*diam, 0.001*rad);
+
+		double red,green,blue;
+		mesh->GetPointCurveColor(i,red,green,blue);
+		glColor3f (red, green, blue);
+		for(int j=0; j<mesh->GetNumPointsOfPointCurve(i)-1; j++)
+		  {
+		    DrawCylinder(mesh->GetPointCurvePoint(i,j),
+				 mesh->GetPointCurvePoint(i,j+1),
+				 thick);
+		  }
+	      }
+	    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];
+      
+        int nse = mesh->GetNSE();
+
+        CurvedElements & curv = mesh->GetCurvedElements();
+
+        if (sol)
+          {
+            glBegin (GL_LINES);
+          
+            for (SurfaceElementIndex sei = 0; sei < nse; sei++)
+              {
+                const Element2d & el = (*mesh)[sei];
+
+#ifdef PARALLEL
+		// parallel visualization --> dont draw ghost elements
+		if ( el . IsGhost() ) continue;
+#endif
+                bool curved = curv.IsHighOrder(); //  && curv.IsSurfaceElementCurved(sei);
+              
+                if (el.GetType() == TRIG || el.GetType() == TRIG6)
+                  {
+                    Point<3> lp1, lp2, lp3;
+                    if (!curved)
+                      {
+                        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;
+                        
+                          // TODO: consider return value (bool: draw/don't draw element)
+                          GetSurfValue (sol, sei, x, y, scalcomp, values[ii]);
+                          Point<2> xref(x,y);
+                        
+                          if (curved)
+                            mesh->GetCurvedElements().
+                              CalcSurfaceTransformation (xref, sei, points[ii]);
+                          else
+                            points[ii] = lp3 + x * (lp1-lp3) + y * (lp2-lp3);
+                        
+                          if (deform)
+                            {
+                              points[ii] += GetSurfDeformation (sei, x, y);
+                            }
+                          ii++;
+                        }
+                  
+                    ii = 0;
+                    for (iy = 0; iy < n; iy++, ii++)
+                      for (ix = 0; ix < n-iy; ix++, ii++)
+                        {
+                          int index[] = { ii, ii+1, ii+n-iy+1,
+                                          ii+1, ii+n-iy+2, ii+n-iy+1 };
+                        
+                          DrawIsoLines (points[index[0]], points[index[1]], points[index[2]],
+                                        values[index[0]], values[index[1]], values[index[2]]);
+
+                          if (ix < n-iy-1) 
+                            DrawIsoLines (points[index[3]], points[index[4]], points[index[5]],
+                                          values[index[3]], values[index[4]], values[index[5]]);
+                        }    
+                  }
+              
+              
+                if (el.GetType() == QUAD || el.GetType() == QUAD6 || el.GetType() == QUAD8 )
+                  {
+                    Point<3> lpi[4];
+                    Vec<3> vx, vy, vtwist, def;
+                    if (!curved)
+                      {
+                        for (int j = 0; j < 4; j++)
+                          GetPointDeformation (el[j]-1, lpi[j]);
+                        vx = lpi[1]-lpi[0];
+                        vy = lpi[3]-lpi[0];
+                        vtwist = (lpi[0]-lpi[1]) + (lpi[2]-lpi[3]);
+                      }
+
+                    int n = 1 << subdivisions;
+                    int ix, iy, ii = 0;
+                    for (iy = 0; iy <= n; iy++)
+                      for (ix = 0; ix <= n; ix++, ii++)
+                        {
+                          double x = double(ix) / n;
+                          double y = double(iy) / n;
+                        
+                          // TODO: consider return value (bool: draw/don't draw element)
+                          GetSurfValue (sol, sei, x, y, scalcomp, values[ii]);
+                          Point<2> xref(x,y);
+                        
+                          if (curved)
+                            mesh->GetCurvedElements().
+                              CalcSurfaceTransformation (xref, sei, points[ii]);
+                          else
+                            points[ii] = lpi[0] + x * vx + y * vy + x*y * vtwist;
+                        
+                          if (deform)
+                            points[ii] += GetSurfDeformation (sei, x, y);
+                        }
+                  
+                    ii = 0;
+                    for (iy = 0; iy < n; iy++, ii++)
+                      for (ix = 0; ix < n; ix++, ii++)
+                        {
+                          DrawIsoLines (points[ii], points[ii+1], points[ii+n+1],
+                                        values[ii], values[ii+1], values[ii+n+1]);
+                          DrawIsoLines (points[ii+1], points[ii+n+2], points[ii+n+1],
+                                        values[ii+1], values[ii+n+2], values[ii+n+1]);
+                        }       
+                  }
+              }
+            glEnd();
+          }
+        glEndList ();
+
+        if (clipplane_isolinelist) glDeleteLists (clipplane_isolinelist, 1);
+            
+        if (vispar.clipenable && clipsolution == 1 && sol)
+          {
+            clipplane_isolinelist = glGenLists (1);
+            glNewList (clipplane_isolinelist, GL_COMPILE);
+
+            Array<ClipPlaneTrig> cpt;
+            Array<ClipPlanePoint> pts;
+            GetClippingPlaneTrigs (cpt, pts);  
+            bool drawelem;
+          
+            glNormal3d (-clipplane[0], -clipplane[1], -clipplane[2]);
+          
+            if (numisolines)
+              for (int i = 0; i < cpt.Size(); i++)
+                {
+                  const ClipPlaneTrig & trig = cpt[i];
+                  double vali[3];
+                  for (int j = 0; j < 3; j++)
+                    {
+                      Point<3> lami = pts[trig.points[j].pnr].lami;
+                      drawelem = GetValue (sol, trig.elnr, lami(0), lami(1), lami(2),
+                                           scalcomp, vali[j]);
+                    }
+                  if ( drawelem )
+                    DrawIsoLines (pts[trig.points[0].pnr].p,
+                                  pts[trig.points[1].pnr].p,
+                                  pts[trig.points[2].pnr].p,
+                                  // trig.points[1].p,
+                                  // trig.points[2].p,
+                                  vali[0], vali[1], vali[2]);
+                }
+            glEndList ();
+          }
+        glEnd();
+      }
+  
+    clipplanetimestamp = max2 (vispar.clipplanetimestamp, solutiontimestamp);
+  }
+  
+
+
+  void  VisualSceneSolution :: DrawSurfaceElements ()
+  {
+    static int timer = NgProfiler::CreateTimer ("Solution::DrawSurfaceElements");
+    NgProfiler::RegionTimer reg (timer);
+  
+    
+#ifdef PARALLELGL
+
+    if (id == 0 && ntasks > 1)
+      {
+	InitParallelGL();
+
+	par_surfellists.SetSize (ntasks);
+
+	MyMPI_SendCmd ("redraw");
+	MyMPI_SendCmd ("solsurfellist");
+
+	for ( int dest = 1; dest < ntasks; dest++ )
+	  MyMPI_Recv (par_surfellists[dest], dest, MPI_TAG_VIS);
+
+	if (surfellist)
+	  glDeleteLists (surfellist, 1);
+
+	surfellist = glGenLists (1);
+	glNewList (surfellist, GL_COMPILE);
+	
+	for ( int dest = 1; dest < ntasks; dest++ )
+	  glCallList (par_surfellists[dest]);
+	
+	glEndList();
+	return;
+      }
+#endif
+
+
+
+    if (surfellist)
+      glDeleteLists (surfellist, 1);
+    
+    surfellist = glGenLists (1);
+    glNewList (surfellist, GL_COMPILE);
+
+    
+    const SolData * sol = NULL;
+    
+    if (scalfunction != -1)
+      sol = soldata[scalfunction];
+    
+    if (mesh->GetTimeStamp () > solutiontimestamp)
+      sol = NULL;
+
+    if (sol && sol->solclass) sol->solclass->SetMultiDimComponent (multidimcomponent);
+
+
+
+    glLineWidth (1.0f);
+
+    GLfloat col_grey[] = { 0.6f, 0.6f, 0.6f };
+    glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col_grey);
+        
+
+    int nse = mesh->GetNSE();
+
+    SetTextureMode (usetexture);
+
+    CurvedElements & curv = mesh->GetCurvedElements();
+
+    int n = 1 << subdivisions;
+    int npt = sqr(n+1);
+
+    Array<Point<2> > pref (npt);
+    Array<Point<3> > points (npt);
+    Array<Mat<3,2> > dxdxis (npt);
+    Array<Vec<3> > nvs(npt);
+    Array<double> values(npt);
+
+    Array<double> mvalues(npt);
+    if (sol && sol->draw_surface) mvalues.SetSize (npt * sol->components);
+
+    Array<complex<double> > valuesc(npt);
+
+    for (SurfaceElementIndex sei = 0; sei < nse; sei++)
+      {
+        const Element2d & el = (*mesh)[sei];
+
+	if ( el . IsGhost() ) continue;
+
+        if (vispar.drawdomainsurf > 0)
+          {
+            if (mesh->GetDimension() == 3)
+              {
+                if (vispar.drawdomainsurf != mesh->GetFaceDescriptor(el.GetIndex()).DomainIn() &&
+                    vispar.drawdomainsurf != mesh->GetFaceDescriptor(el.GetIndex()).DomainOut())
+                  continue;
+              }
+            else
+              {
+                if (el.GetIndex() != vispar.drawdomainsurf) continue;
+              }
+          }
+
+
+
+        if ( el.GetType() == QUAD || el.GetType() == QUAD6 )
+          {
+            bool curved = curv.IsSurfaceElementCurved (sei);
+
+
+            for (int iy = 0, ii = 0; iy <= n; iy++)
+              for (int ix = 0; ix <= n; ix++, ii++)
+                pref[ii] = Point<2> (double(ix)/n, double(iy)/n);
+
+            int npt = (n+1)*(n+1);
+            if (curved)
+              for (int ii = 0; ii < npt; ii++)
+                {
+                  Point<2> xref = pref[ii];
+                  Mat<3,2> dxdxi;
+                  
+                  mesh->GetCurvedElements().
+                    CalcSurfaceTransformation (xref, sei, points[ii], dxdxi);
+                  nvs[ii] = Cross (dxdxi.Col(0), dxdxi.Col(1));
+                  nvs[ii].Normalize();
+                }
+            else
+              {
+		Point<3> lpi[4];
+		Vec<3> vx, vy, vtwist;
+		
+		for (int k = 0; k < 4; k++)
+		  GetPointDeformation (el[k]-1, lpi[k]);
+		
+		vx = lpi[1]-lpi[0];
+		vy = lpi[3]-lpi[0];
+		vtwist = (lpi[0]-lpi[1]) + (lpi[2]-lpi[3]);
+
+                for (int ii = 0; ii < npt; ii++)
+                  {
+                    double x = pref[ii](0);
+                    double y = pref[ii](1);
+                    points[ii] = lpi[0] + x * vx + y * vy + x*y * vtwist;
+                  }
+
+                Vec<3> nv = Cross (vx, vy);
+                nv.Normalize();
+                for (int ii = 0; ii < npt; ii++)
+                  nvs[ii] = nv;
+              }
+
+
+            bool drawelem = false;
+            if (sol && sol->draw_surface) 
+              {
+                if (usetexture == 2)
+                  for (int ii = 0; ii < npt; ii++)
+                    drawelem = GetSurfValueComplex (sol, sei, pref[ii](0), pref[ii](1), scalcomp, valuesc[ii]);
+                else
+                  for (int ii = 0; ii < npt; ii++)
+                    drawelem = GetSurfValue (sol, sei, pref[ii](0), pref[ii](1), scalcomp, values[ii]);
+              }
+            
+            if (deform)
+              for (int ii = 0; ii < npt; ii++)
+                points[ii] += GetSurfDeformation (sei, pref[ii](0), pref[ii](1));
+
+
+            int save_usetexture = usetexture;
+            if (!drawelem)
+              {
+                usetexture = 0;
+                SetTextureMode (0);
+              }
+
+            int ii = 0;
+
+            glBegin (GL_QUADS);
+
+            for (int iy = 0; iy < n; iy++, ii++)
+              for (int ix = 0; ix < n; ix++, ii++)
+                {
+                  int index[] = { ii, ii+1, ii+n+2, ii+n+1 };
+                  
+                  for (int j = 0; j < 4; j++)
+                    {
+                      if (drawelem)
+                        {
+                          if (usetexture != 2)
+                            SetOpenGlColor  (values[index[j]]);
+                          else
+                            glTexCoord2f ( valuesc[index[j]].real(),
+                                           valuesc[index[j]].imag() );
+                        }
+                      else
+                        glColor3fv (col_grey);
+                      
+                      glNormal3dv (nvs[index[j]]);
+                      glVertex3dv (points[index[j]]);
+                    }
+                }
+            glEnd();
+
+            if (!drawelem && (usetexture != save_usetexture))
+              {
+                usetexture = save_usetexture;
+                SetTextureMode (usetexture);
+              }
+
+          }
+      }
+
+    n = 1 << subdivisions;
+    double invn = 1.0 / n;
+    npt = (n+1)*(n+2)/2;
+
+    for(SurfaceElementIndex sei = 0; sei < nse; sei++)
+      {
+        const Element2d & el = (*mesh)[sei];
+
+	if ( el . IsGhost() ) continue;
+
+        if(vispar.drawdomainsurf > 0)
+	  {
+	    if (mesh->GetDimension() == 3)
+	      {
+		if (vispar.drawdomainsurf != mesh->GetFaceDescriptor(el.GetIndex()).DomainIn() &&
+		    vispar.drawdomainsurf != mesh->GetFaceDescriptor(el.GetIndex()).DomainOut())
+		  continue;
+	      }
+	    else
+	      {
+		if (el.GetIndex() != vispar.drawdomainsurf)
+		  continue;
+	      }
+	  }
+        
+        if ( el.GetType() == TRIG || el.GetType() == TRIG6 )
+          {
+	    bool curved = curv.IsSurfaceElementCurved(sei);
+
+            for (int iy = 0, ii = 0; iy <= n; iy++)
+              for (int ix = 0; ix <= n-iy; ix++, ii++)
+                pref[ii] = Point<2> (ix*invn, iy*invn);
+
+            if (curved)
+              {
+                mesh->GetCurvedElements().
+                  CalcMultiPointSurfaceTransformation (&pref, sei, &points, &dxdxis);
+
+                for (int ii = 0; ii < npt; ii++)
+                  nvs[ii] = Cross (dxdxis[ii].Col(0), dxdxis[ii].Col(1)).Normalize();
+              }
+            else
+              {
+		Point<3> p1 = mesh->Point (el[0]);
+		Point<3> p2 = mesh->Point (el[1]);
+		Point<3> p3 = mesh->Point (el[2]);
+
+                Vec<3> vx = p1-p3;
+                Vec<3> vy = p2-p3;
+                for (int ii = 0; ii < npt; ii++)
+                  {
+                    points[ii] = p3 + pref[ii](0) * vx + pref[ii](1) * vy;
+                    for (int j = 0; j < 3; j++)
+                      {
+                        dxdxis[ii](j,0) = vx(j);
+                        dxdxis[ii](j,1) = vy(j);
+                      }
+                  }
+
+                Vec<3> nv = Cross (vx, vy).Normalize();
+                for (int ii = 0; ii < npt; ii++)
+                  nvs[ii] = nv;
+              }
+
+            bool drawelem = false;
+            if (sol && sol->draw_surface) 
+              {
+		drawelem = GetMultiSurfValues (sol, sei, npt, 
+					       &pref[0](0), &pref[1](0)-&pref[0](0),
+					       &points[0](0), &points[1](0)-&points[0](0),
+					       &dxdxis[0](0), &dxdxis[1](0)-&dxdxis[0](0),
+					       &mvalues[0], sol->components);
+                if (usetexture == 2)
+		  for (int ii = 0; ii < npt; ii++)
+		    valuesc[ii] = ExtractValueComplex(sol, scalcomp, &mvalues[ii*sol->components]);
+                else
+		  for (int ii = 0; ii < npt; ii++)
+		    values[ii] = ExtractValue(sol, scalcomp, &mvalues[ii*sol->components]);
+              }
+            
+            if (deform)
+              for (int ii = 0; ii < npt; ii++)
+                points[ii] += GetSurfDeformation (sei, pref[ii](0), pref[ii](1));
+
+            int save_usetexture = usetexture;
+            if (!drawelem)
+              {
+                usetexture = 0;
+                SetTextureMode (usetexture);
+              }
+            
+            for (int iy = 0, ii = 0; iy < n; iy++)
+              {
+                glBegin (GL_TRIANGLE_STRIP);
+                for (int ix = 0; ix <= n-iy; ix++, ii++)
+                  for (int k = 0; k < 2; k++)
+                    {
+                      if (ix+iy+k > n) continue;
+                      int hi = (k == 0) ? ii : ii+n-iy+1;
+                      
+                      if (drawelem)
+                        {
+                          if (usetexture != 2)
+                            SetOpenGlColor (values[hi]); 
+                          else
+                            glTexCoord2f ( valuesc[hi].real(), valuesc[hi].imag() );
+                        }
+                      else
+                        glColor3fv (col_grey);
+                      
+                      glNormal3dv (nvs[hi]);
+                      glVertex3dv (points[hi]);
+                    }
+                glEnd();
+              }
+            if (!drawelem && (usetexture != save_usetexture))
+              {
+                usetexture = save_usetexture;
+                SetTextureMode (usetexture);
+              }
+	  }
+      }
+    glEndList ();
+
+
+#ifdef PARALLELGL
+    glFinish();
+    if (id > 0)
+      MyMPI_Send (surfellist, 0, MPI_TAG_VIS);
+#endif
+  }
+
+
+  void  VisualSceneSolution :: DrawSurfaceElementLines ()
+  {
+    glLineWidth (1.0f);
+    // glNormal3d (1, 0, 0);
+
+    int nse = mesh->GetNSE();
+
+    CurvedElements & curv = mesh->GetCurvedElements();
+
+    int n = 1 << subdivisions;
+    ArrayMem<Point<2>, 65> ptsloc(n+1);
+    ArrayMem<Point<3>, 65> ptsglob(n+1);
+
+    double trigpts[3][2] = { { 0, 0 }, { 1, 0 }, { 0, 1} };
+    double trigvecs[3][2] = { { 1, 0 }, { -1,1 }, { 0, -1} };
+
+    double quadpts[4][2] = { { 0, 0 }, { 1, 0 }, { 1, 1 }, { 0, 1} };
+    double quadvecs[4][2] = { { 1, 0 }, { 0, 1 }, { -1, 0}, { 0, -1} };
+
+    for (SurfaceElementIndex sei = 0; sei < nse; sei++)
+      {
+        Element2d & el = (*mesh)[sei];
+
+	if ( el . IsGhost() ) continue;
+
+        // bool curved = curv.IsSurfaceElementCurved (sei);
+
+        int nv = (el.GetType() == TRIG || el.GetType() == TRIG6) ? 3 : 4;
+        /*
+        Point<3> p1, p2, p3, p4;
+        if (!curved)
+	{
+            p1 = (*mesh)[el[0]];
+            p2 = (*mesh)[el[1]];
+            p3 = (*mesh)[el[2]];
+            if (nv == 4) p4 = (*mesh)[el[3]];
+          }
+	*/
+
+        for (int k = 0; k < nv; k++)
+          {
+            Point<2> p0;
+            Vec<2> vtau;
+            if (nv == 3)
+	      {
+		p0 = Point<2>(trigpts[k][0], trigpts[k][1]);
+		vtau = Vec<2>(trigvecs[k][0], trigvecs[k][1]);
+	      }
+            else
+	      {
+		p0 = Point<2>(quadpts[k][0], quadpts[k][1]);
+		vtau = Vec<2>(quadvecs[k][0], quadvecs[k][1]);
+	      }
+
+            glBegin (GL_LINE_STRIP);
+
+            // if (curved)
+              {
+                for (int ix = 0; ix <= n; ix++)
+                  ptsloc[ix] = p0 + (double(ix) / n) * vtau;
+                    
+                curv.CalcMultiPointSurfaceTransformation (&ptsloc, sei, &ptsglob, 0);
+
+                for (int ix = 0; ix <= n; ix++)
+                  {
+                    if (deform)
+                      ptsglob[ix] += GetSurfDeformation (sei, ptsloc[ix](0), ptsloc[ix](1));
+                    glVertex3dv (ptsglob[ix]);
+                  }
+              }
+	      /*
+            else
+              {
+                for (int ix = 0; ix <= n; ix++)
+                  {
+                    Point<2> p = p0 + (double(ix) / n) * vtau;
+
+                    Point<3> pnt;
+
+                    if (nv == 3)
+                      pnt = p3 + p(0) * (p1-p3) + p(1) * (p2-p3);
+                    else
+                      pnt = p1 + p(0) * (p2-p1) + p(1) * (p4-p1) + p(0)*p(1) * ( (p1-p2)+(p3-p4) );
+                
+                    if (deform)
+                      pnt += GetSurfDeformation (sei, p(0), p(1) );
+                    
+                    glVertex3dv (pnt);
+                  }
+              }
+	      */
+            glEnd ();
+          }
+      }
+  }
+
+
+
+
+
+
+
+
+
+  void VisualSceneSolution :: DrawIsoSurface(const SolData * sol, 
+                                             const SolData * vsol,
+                                             int comp)
+  {
+    if (!draw_isosurface) return;
+    if (!sol) return;
+
+   
+    SetTextureMode (0);
+    glColor3d (1.0, 0, 0);
+    glEnable (GL_COLOR_MATERIAL);
+
+
+    glBegin (GL_TRIANGLES);
+
+    int ne = mesh->GetNE();
+
+    const int edgei[6][2] =
+      { { 0, 1 }, { 0, 2 }, { 0, 3 },
+        { 1, 2 }, { 1, 3 }, { 2, 3 } };
+    
+    double edgelam[6];
+    Point<3> edgep[6];
+    Vec<3> normp[6];
+    double nodevali[4];
+    
+    int cntce;
+    int cpe1 = 0, cpe2 = 0, cpe3 = 0;
+    
+    int n = 1 << subdivisions;
+    int n3 = (n+1)*(n+1)*(n+1);
+    
+    Array<Point<3> > grid(n3);
+    Array<Point<3> > locgrid(n3);
+    Array<Mat<3,3> > trans(n3);
+    Array<double> val(n3);
+    Array<Vec<3> > grads(n3);
+    Array<int> compress(n3);
+    
+    MatrixFixWidth<3> pointmat(8);
+    grads = Vec<3> (0.0);
+
+    for (ElementIndex ei = 0; ei < ne; ei++)
+      {
+        // if(vispar.clipdomain > 0 && vispar.clipdomain != (*mesh)[ei].GetIndex()) continue;
+        // if(vispar.donotclipdomain > 0 && vispar.donotclipdomain == (*mesh)[ei].GetIndex()) continue;
+
+	if ( (*mesh)[ei] . IsGhost() ) continue;
+
+        ELEMENT_TYPE type = (*mesh)[ei].GetType();
+        if (type == HEX || type == PRISM || type == TET || type == PYRAMID)
+          {
+            const Element & el = (*mesh)[ei];
+            
+            int ii = 0;
+            int cnt_valid = 0;
+            
+            for (int ix = 0; ix <= n; ix++)
+              for (int iy = 0; iy <= n; iy++)
+                for (int iz = 0; iz <= n; iz++, ii++)
+                  {
+                    Point<3> ploc;
+                    compress[ii] = ii;
+                    
+                    switch (type)
+                      {
+                      case PRISM:
+                        if (ix+iy <= n)
+                          {
+                            ploc = Point<3> (double(ix) / n, double(iy) / n, double(iz) / n);
+                            compress[ii] = cnt_valid;
+                            cnt_valid++;
+                          }
+                        else
+                          compress[ii] = -1;
+                        break;
+                      case TET:
+                        if (ix+iy+iz <= n)
+                          {
+                            ploc = Point<3> (double(ix) / n, double(iy) / n, double(iz) / n);
+                            compress[ii] = cnt_valid;
+                            cnt_valid++;
+                          }
+                        else
+                          compress[ii] = -1;
+                        break;
+                      case HEX:
+                        ploc = Point<3> (double(ix) / n, double(iy) / n, double(iz) / n);
+                        break;
+                      case PYRAMID:
+                        ploc = Point<3> (double(ix) / n * (1-double(iz)/n),
+                                         double(iy) / n * (1-double(iz)/n),
+                                         double(iz)/n);
+                        break;
+                      default:
+                        cerr << "case not implementd 878234" << endl;
+                        ploc = 0.0;
+                      }
+                    if (compress[ii] != -1)
+                      locgrid[compress[ii]] = ploc;
+                  }
+            
+            if (type != TET && type != PRISM) cnt_valid = n3;
+            
+            
+            if (mesh->GetCurvedElements().IsHighOrder() || 1)
+              {
+                mesh->GetCurvedElements().
+                  CalcMultiPointElementTransformation (&locgrid, ei, &grid, &trans);
+              }
+            else
+              {
+                Vector shape(el.GetNP());
+                for (int k = 0; k < el.GetNP(); k++)
+                  for (int j = 0; j < 3; j++)
+                    pointmat(k,j) = (*mesh)[el[k]](j);
+                
+                for (int i = 0; i < cnt_valid; i++)
+                  {
+                    el.GetShapeNew (locgrid[i], shape);
+                    Point<3> pglob;
+                    for (int j = 0; j < 3; j++)
+                      {
+                        pglob(j) = 0;
+                        for (int k = 0; k < el.GetNP(); k++)
+                          pglob(j) += shape(k) * pointmat(k,j);
+                      }
+                    grid[i] = pglob;
+                  }
+              }
+
+            bool has_pos = 0, has_neg = 0;
+                
+            for (int i = 0; i < cnt_valid; i++)
+              {
+                GetValue (sol, ei, &locgrid[i](0), &grid[i](0), &trans[i](0), comp, val[i]);
+        
+                val[i] -= minval;
+
+                if (vsol)
+                  GetValues (vsol, ei, &locgrid[i](0), &grid[i](0), &trans[i](0), &grads[i](0));
+                grads[i] *= -1;
+
+
+                if (val[i] > 0)
+                  has_pos = 1;
+                else
+                  has_neg = 1;
+              }
+
+            if (!has_pos || !has_neg) continue;
+            
+            for (int ix = 0; ix < n; ix++)
+              for (int iy = 0; iy < n; iy++)
+                for (int iz = 0; iz < n; iz++)
+                  {
+                    int base = iz + (n+1)*iy + (n+1)*(n+1)*ix;
+                    int pi[8] = 
+                      { base, base+(n+1)*(n+1), base+(n+1)*(n+1)+(n+1), base+(n+1),
+                        base+1, base+(n+1)*(n+1)+1, base+(n+1)*(n+1)+(n+1)+1, base+(n+1)+1 };
+                    
+                    for (int j = 0; j < 8; j++)
+                      pi[j] = compress[pi[j]];
+                    
+                    int tets[6][4] = 
+                      { { 1, 2, 4, 5 },
+                        { 4, 5, 2, 8 },
+                        { 2, 8, 5, 6 },
+                        { 2, 3, 4, 8 },
+                        { 2, 3, 8, 6 },
+                        { 3, 8, 6, 7 } };
+                    
+                    for (int ii = 0; ii < 6; ii++)
+                      {
+                        int teti[4];
+                        for (int k = 0; k < 4; k++)
+                          teti[k] = pi[tets[ii][k]-1];
+                        
+                        bool is_valid = 1;
+                        for (int j = 0; j < 4; j++)
+                          if (teti[j] == -1) is_valid = 0;
+                        
+                        if (!is_valid) continue;
+                        
+                        for (int j = 0; j < 4; j++)
+                          nodevali[j] = val[teti[j]];
+                        
+                        cntce = 0;
+                        for (int j = 0; j < 6; j++)
+                          {
+                            int lpi1 = edgei[j][0];
+                            int lpi2 = edgei[j][1];
+                            if ( (nodevali[lpi1] > 0) !=
+                                 (nodevali[lpi2] > 0) )
+                              {
+                                Point<3> p1 = grid[teti[lpi1]];
+                                Point<3> p2 = grid[teti[lpi2]];
+
+                                edgelam[j] = nodevali[lpi2] / (nodevali[lpi2] - nodevali[lpi1]);
+                                edgep[j] = grid[teti[lpi1]] + (1-edgelam[j]) * (grid[teti[lpi2]]-grid[teti[lpi1]]);
+                                normp[j] = grads[teti[lpi1]] + (1-edgelam[j]) * (grads[teti[lpi2]]-grads[teti[lpi1]]);
+                                
+                                cntce++;
+                                cpe3 = cpe2;
+                                cpe2 = cpe1;
+                                cpe1 = j;
+                                if (cntce >= 3)
+                                  {
+                                    if (!vsol)
+                                      {
+                                        Point<3> points[3];
+                                        
+                                        points[0] = edgep[cpe1];
+                                        points[1] = edgep[cpe2];
+                                        points[2] = edgep[cpe3];
+
+                                        Vec<3> normal = Cross (points[2]-points[0], points[1]-points[0]);
+                                        if ( ( (normal * (p2-p1)) > 0 ) == ( nodevali[lpi1] < 0) )
+                                          normal *= -1;
+                                        glNormal3dv (normal);
+
+                                        glVertex3dv (points[0]);
+                                        glVertex3dv (points[1]);
+                                        glVertex3dv (points[2]);
+                                      }
+                                    else
+                                      {
+                                        glNormal3dv (normp[cpe1]);
+                                        glVertex3dv (edgep[cpe1]);
+                                        glNormal3dv (normp[cpe2]);
+                                        glVertex3dv (edgep[cpe2]);
+                                        glNormal3dv (normp[cpe3]);
+                                        glVertex3dv (edgep[cpe3]);
+                                      }
+                                  }
+                              }
+                          }
+                      }
+                  }
+          }
+      }
+    glEnd();
+  }
+    
+
+
+
+
+
+
+
+  void  VisualSceneSolution :: DrawTrigSurfaceVectors(const Array< Point<3> > & lp, 
+                                                      const Point<3> & pmin, const Point<3> & pmax,
+                                                      const int sei, const SolData * vsol)
+  {
+    int dir,dir1,dir2;
+    double s,t;
+
+    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;
+
+    Point<2> p2d[3];
+
+    int k;
+
+    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;
+          
+    //    cout << "drawsurfacevectors. xoffset = " << xoffset << ", yoffset = ";
+    //    cout << yoffset << endl;
+    
+    for (s = xoffset/gridsize; s <= 1+xoffset/gridsize; s += 1.0 / gridsize)
+      if (s >= minx2d && s <= maxx2d)
+        for (t = yoffset/gridsize; t <= 1+yoffset/gridsize; 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];
+                  bool drawelem = 
+                    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)
+                    if ( (!vsol->iscomplex && vsol->components != 3) ||
+                         (vsol->iscomplex && vsol->components != 6) )
+                      v(2) = 0;
+                  
+                  double val = v.Length();
+
+                  SetOpenGlColor  (val); // (val, minval, maxval, logscale);  // change JS
+
+                  if (val > 1e-10 * maxval)
+                    v *= (rad / val / gridsize * 0.5);
+                  else 
+                    drawelem = 0;
+
+                  if ( drawelem ) 
+                    DrawCone (cp, cp+4*v, 0.8*rad / gridsize);
+                }
+            }
+    
+  }
+
+
+
+  void  VisualSceneSolution :: DrawSurfaceVectors ()
+  {
+    SurfaceElementIndex sei;
+
+    const SolData * vsol = NULL;
+    // bool drawelem;
+
+    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);
+
+
+    // glColor3d (1.0, 1.0, 1.0);
+    // glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
+
+    if (vsol->draw_surface && showsurfacesolution)
+      {
+        int nse = mesh->GetNSE();
+        for (sei = 0; sei < nse; sei++)
+          {
+            const Element2d & el = (*mesh)[sei];
+          
+	    if ( el . IsGhost() ) continue;
+
+            if (el.GetType() == TRIG || el.GetType() == TRIG6)
+              {
+          
+                Array< Point<3> > lp(3);
+
+                lp[0] = mesh->Point(el[2]);
+                lp[1] = mesh->Point(el[0]);
+                lp[2] = mesh->Point(el[1]);
+
+                DrawTrigSurfaceVectors(lp,pmin,pmax,sei,vsol);
+                
+                /*
+                  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;
+          
+                  //      cout << "drawsurfacevectors. xoffset = " << xoffset << ", yoffset = ";
+                  //      cout << yoffset << endl;
+          
+                  for (s = xoffset/gridsize; s <= 1+xoffset/gridsize; s += 1.0 / gridsize)
+                  if (s >= minx2d && s <= maxx2d)
+                  for (t = yoffset/gridsize; t <= 1+yoffset/gridsize; 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];
+                  drawelem = 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)
+                  if ( (!vsol->iscomplex && vsol->components != 3) ||
+                  (vsol->iscomplex && vsol->components != 6) )
+                  v(2) = 0;
+                        
+                  double val = v.Length();
+                  SetOpenGlColor  (val, minval, maxval, logscale);
+
+                  if (val > 1e-10 * maxval)
+                  v *= (rad / val / gridsize * 0.5);
+                  else drawelem = 0;
+                  // "drawelem": added 07.04.2004 (FB)
+                  if ( drawelem ) DrawCone (cp, cp+4*v, 0.8*rad / gridsize);
+
+
+                  }
+                  }
+                */
+              }
+            else if (el.GetType() == QUAD)
+              {
+                /*
+		  Array < Point<3> > lp(3);
+
+		  lp[0] = mesh->Point(el[0]);
+		  lp[1] = mesh->Point(el[1]);
+		  lp[2] = mesh->Point(el[2]);
+
+		  DrawTrigSurfaceVectors(lp,pmin,pmax,sei,vsol);
+
+		  lp[0] = mesh->Point(el[0]);
+		  lp[1] = mesh->Point(el[2]);
+		  lp[2] = mesh->Point(el[3]);
+
+		  DrawTrigSurfaceVectors(lp,pmin,pmax,sei,vsol);
+                */
+                
+                Point<3> lp[4];
+                Point<2> p2d[4];
+                
+                for (int k = 0; k < 4; k++)
+                  lp[k] = mesh->Point (el[k]);
+                
+                
+                Vec<3> n = Cross (lp[1]-lp[0], lp[2]-lp[0]);
+                Vec<3> na (fabs (n(0)), fabs(n(1)), fabs(n(2)));
+                int dir, dir1, dir2;
+                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 (int k = 0; k < 4; 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 (int k = 1; k < 4; 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));
+                  }
+                
+                for (double s = xoffset/gridsize; s <= 1+xoffset/gridsize; s += 1.0 / gridsize)
+                  if (s >= minx2d && s <= maxx2d)
+                    for (double t = yoffset/gridsize; t <= 1+yoffset/gridsize; t += 1.0 / gridsize)
+                      if (t >= miny2d && t <= maxy2d)
+                        {
+                          double lami[3];
+                          Point3d p3d(2*rad*s+pmin(0), 2*rad*t+pmin(1),0);
+                          
+                          if (mesh->PointContainedIn2DElement (p3d, lami, sei+1))
+                            {
+                              Point<3> cp = p3d;
+                              double lam1 = lami[0];
+                              double lam2 = lami[1];
+                              
+                              //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];
+                              bool drawelem = GetSurfValues (vsol, sei, lam1, lam2, values);
+                              (*testout) << "sei " << sei << " lam1 " << lam1 << " lam2 " << lam2 << " drawelem " << drawelem << endl;
+                              
+                              if (!vsol->iscomplex)
+                                for (int k = 0; k < 3; k++)
+                                  v(k) = values[k];
+                              else
+                                {
+                                  if (!imag_part)
+                                    for (int k = 0; k < 3; k++)
+                                      v(k) = values[2*k];
+                                  else
+                                    for (int k = 0; k < 3; k++)
+                                      v(k) = values[2*k+1];
+                                }
+                              
+                              if (mesh->GetDimension() == 2)
+                                if ( (!vsol->iscomplex && vsol->components != 3) ||
+                                     (vsol->iscomplex && vsol->components != 6) )
+                                  v(2) = 0;
+                              
+                              double val = v.Length();
+                              SetOpenGlColor  (val); // , minval, maxval, logscale); july 09
+                              
+                              (*testout) << "v " << v << endl;
+                              
+                              if (val > 1e-10 * maxval)
+                                v *= (rad / val / gridsize * 0.5);
+                              
+                              (*testout) << "v " << v << endl;
+                              
+                              if ( drawelem )
+                                {
+                                  DrawCone (cp, cp+4*v, 0.8*rad / gridsize);
+                                  (*testout) << "cp " << cp << " rad " << rad << " gridsize " << gridsize << endl;
+                                }
+                              
+                            }
+                        }
+              }
+          }
+      }
+  }
+  
+  
+  
+  
+  void VisualSceneSolution :: 
+  DrawIsoLines (const Point<3> & p1, 
+                const Point<3> & p2, 
+                const Point<3> & p3,
+                double val1, double val2, double val3)
+  {
+    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 Point<3> & hp1, 
+                 const Point<3> & hp2, 
+                 const Point<3> & hp3,
+                 const Point<3> & hp4,
+                 double val1, double val2, double val3, double val4)
+  {
+    int n = numisolines;
+    Point<3> p1, p2, p3, p4;
+    if (val1 < val2)
+      {
+        p1 = hp1; p2 = hp2;
+      }
+    else
+      {
+        p1 = hp2; p2 = hp1;
+        swap (val1, val2);
+      }
+
+    if (val3 < val4)
+      {
+        p3 = hp3; p4 = hp4;
+      }
+    else
+      {
+        p3 = hp4; p4 = hp3;
+        swap (val3, val4);
+      }
+
+    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; 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)
+          {
+            Point<3> lp1 = p1 + lam1 * (p2-p1);
+            Point<3> lp2 = p3 + lam2 * (p4-p3);
+            glVertex3dv (lp1 );
+            glVertex3dv (lp2 );
+            // glVertex3dv (lp2 );  // better ?
+            // glVertex3dv (lp1 );  
+          }
+      }
+  }
+
+
+
+  void VisualSceneSolution :: 
+  GetMinMax (int funcnr, int comp, double & minv, double & maxv) const
+  {
+#ifdef PARALLEL
+    if (id == 0)
+      {
+	MyMPI_SendCmd ("redraw");
+	MyMPI_SendCmd ("getminmax");
+      }
+    MyMPI_Bcast (funcnr);
+    MyMPI_Bcast (comp);
+#endif
+
+    const SolData * sol;
+    double val;
+    bool considerElem;
+
+    bool hasit = false;
+    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++)
+              {
+                considerElem = GetValue (sol, i, 0.333, 0.333, 0.333, comp, val);
+                if (considerElem)
+                  {
+                    if (val > maxv || !hasit)
+                      maxv = val;
+                    if (val < minv || !hasit)
+                      minv = val;
+                    hasit = true;
+                  }
+              }
+          }
+        if (sol->draw_surface)
+          {
+            int nse = mesh->GetNSE();
+            for (int i = 0; i < nse; i++)
+              {
+                ELEMENT_TYPE type = mesh->SurfaceElement(i+1).GetType();
+                if (type == QUAD)
+                  considerElem = GetSurfValue (sol, i, 0.5, 0.5, comp, val);
+                else
+                  considerElem = GetSurfValue (sol, i, 0.3333333, 0.3333333, comp, val);
+                if (considerElem)
+                  {
+                    if (val > maxv || !hasit)
+                      maxv = val;
+                    if (val < minv || !hasit)
+                      minv = val;
+                    hasit = true;
+                  }
+              }
+          }
+      }
+    if (minv == maxv) maxv = minv+1e-6;
+
+#ifdef PARALLEL
+    if ((ntasks > 1) && (id == 0))
+      {
+	minv = 1e99;
+	maxv = -1e99;
+      }
+    double hmin, hmax;
+    MPI_Reduce (&minv, &hmin, 1, MPI_DOUBLE, MPI_MIN, 0, MPI_COMM_WORLD);
+    MPI_Reduce (&maxv, &hmax, 1, MPI_DOUBLE, MPI_MAX, 0, MPI_COMM_WORLD);
+    minv = hmin;
+    maxv = hmax;
+#endif
+  }
+
+
+
+
+
+  bool VisualSceneSolution :: 
+  GetValues (const SolData * data, ElementIndex elnr, 
+             double lam1, double lam2, double lam3,
+             double * values) const
+  {
+    bool ok = false;
+    switch (data->soltype)
+      {
+      case SOL_VIRTUALFUNCTION:
+        {
+          ok = data->solclass->GetValue (elnr, lam1, lam2, lam3, values);
+          break;
+        }
+      default:
+        {
+          for (int i = 0; i < data->components; i++)
+            ok = GetValue (data, elnr, lam1, lam2, lam3, i+1, values[i]);
+        }
+      }
+    return ok;
+  }
+
+  bool VisualSceneSolution :: 
+  GetValues (const SolData * data, ElementIndex elnr, 
+             const double xref[], const double x[], const double dxdxref[], 
+             double * values) const
+  {
+    bool ok = false;
+    switch (data->soltype)
+      {
+      case SOL_VIRTUALFUNCTION:
+        {
+          ok = data->solclass->GetValue (elnr, xref, x, dxdxref, values);
+          break;
+        }
+      default:
+        {
+          for (int i = 0; i < data->components; i++)
+            ok = GetValue (data, elnr, xref[0], xref[1], xref[2], i+1, values[i]);
+        }
+      }
+    return ok;
+  }
+
+
+  bool VisualSceneSolution :: 
+  GetValue (const SolData * data, ElementIndex elnr, 
+            const double xref[], const double x[], const double dxdxref[], 
+            int comp, double & val) const
+  {
+
+    double lam1 = xref[0];
+    double lam2 = xref[1];
+    double lam3 = xref[2];
+        
+    val = 0;
+    bool ok = 0;
+
+
+    if (comp == 0)
+      {
+        ArrayMem<double,20> values(data->components);
+        ok = GetValues (data, elnr, xref, x, dxdxref, &values[0]);
+
+	val = ExtractValue (data, 0, &values[0]);
+	return ok;
+      }
+
+
+    switch (data->soltype)
+      {
+      case SOL_VIRTUALFUNCTION:
+        {
+          double values[20];
+          ok = data->solclass->GetValue (elnr, xref, x, dxdxref, values);
+
+          val = values[comp-1];
+          return ok;
+        }
+      case SOL_NODAL:
+        {
+          const Element & el = (*mesh)[elnr];
+
+          double lami[8] = { 0.0 };
+          int np = 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;
+              }     
+            default:
+              cerr << "case not implementd 23523" << endl;
+            }
+
+          for (int i = 0; i < np; i++)
+            val += lami[i] * data->data[(el[i]-1) * data->dist + comp-1];
+
+          return 1;
+        }
+
+      case SOL_ELEMENT:
+        {
+          val = data->data[elnr * data->dist + comp-1];
+          return 1;
+        }
+
+      case SOL_SURFACE_ELEMENT:
+        return 0;
+
+      case SOL_NONCONTINUOUS:
+        {
+          const Element & el = (*mesh)[elnr];
+
+          double lami[8] = { 0.0 };
+          int np = 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 (int i = 0; i < np; i++)
+            val += lami[i] * data->data[(base+i) * data->dist + comp-1];
+
+          return 1;
+        }
+
+      case SOL_MARKED_ELEMENTS:
+        {
+          val = (*mesh)[elnr].TestRefinementFlag();
+          return 1;
+        }
+      
+      case SOL_ELEMENT_ORDER:
+        {
+          val = (*mesh)[elnr].GetOrder();
+          return 1;
+        }
+
+      default:
+        cerr << "case not handled 7234" << endl;
+      }
+    return 0;
+  }
+
+
+
+  bool VisualSceneSolution :: 
+  GetValue (const SolData * data, ElementIndex elnr, 
+            double lam1, double lam2, double lam3,
+            int comp, double & val) const
+  {
+
+    val = 0;
+    bool ok = 0;
+
+    if (comp == 0)
+      {
+        ArrayMem<double,20> values(data->components);
+        ok = GetValues (data, elnr, lam1, lam2, lam3, &values[0]);
+	val = ExtractValue (data, 0, &values[0]);
+	return ok;
+      }
+
+
+    switch (data->soltype)
+      {
+      case SOL_VIRTUALFUNCTION:
+        {
+          double values[20];
+          ok = data->solclass->GetValue (elnr, lam1, lam2, lam3, values);
+
+          val = values[comp-1];
+          return ok;
+        }
+      case SOL_NODAL:
+        {
+          const Element & el = (*mesh)[elnr];
+
+          double lami[8] = { 0.0 };
+          int np = 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;
+              }     
+            default:
+              cerr << "case not implemented 234324" << endl;
+            }
+
+          for (int i = 0; i < np; i++)
+            val += lami[i] * data->data[(el[i]-1) * data->dist + comp-1];
+
+          return 1;
+        }
+
+      case SOL_ELEMENT:
+        {
+          val = data->data[elnr * data->dist + comp-1];
+          return 1;
+        }
+
+      case SOL_SURFACE_ELEMENT:
+        return 0;
+
+      case SOL_NONCONTINUOUS:
+        {
+          const Element & el = (*mesh)[elnr];
+
+          double lami[8] = { 0.0 };
+          int np = 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 (int i = 0; i < np; i++)
+            val += lami[i] * data->data[(base+i) * data->dist + comp-1];
+
+          return 1;
+        }
+
+      case SOL_MARKED_ELEMENTS:
+        {
+          val = (*mesh)[elnr].TestRefinementFlag();
+          return 1;
+        }
+      
+      case SOL_ELEMENT_ORDER:
+        {
+          val = (*mesh)[elnr].GetOrder();
+          return 1;
+        }
+      default:
+        cerr << "case not implemented 234234" << endl;
+      }
+    return 0;
+  }
+
+
+
+
+
+
+
+  bool VisualSceneSolution :: 
+  GetValueComplex (const SolData * data, ElementIndex elnr, 
+                   double lam1, double lam2, double lam3,
+                   int comp, complex<double> & val) const
+  {
+    val = 0.0;
+    bool ok = 0;
+
+           
+    switch (data->soltype)
+      {
+      case SOL_VIRTUALFUNCTION:
+        {
+          double values[20];
+          ok = data->solclass->GetValue (elnr, lam1, lam2, lam3, values);
+          val = complex<double> (values[comp-1], values[comp]);
+          return ok;
+        }
+      default:
+        cerr << "case not handled 234234" << endl;
+      } 
+    return 0;
+  }
+  
+
+  bool VisualSceneSolution :: 
+  GetMultiValues (const SolData * data, ElementIndex elnr, int npt,
+		  const double * xref, int sxref,
+		  const double * x, int sx,
+		  const double * dxdxref, int sdxdxref,
+		  double * val, int sval) const
+  {
+    bool drawelem = false;
+    if (data->soltype == SOL_VIRTUALFUNCTION)
+      drawelem = data->solclass->GetMultiValue(elnr, npt, xref, sxref, x, sx, dxdxref, sdxdxref, val, sval);
+    else
+      for (int i = 0; i < npt; i++)
+        drawelem = GetValues (data, elnr, xref+i*sxref, x+i*sx, dxdxref+i*sdxdxref, val+i*sval);
+    return drawelem;
+  }
+
+
+
+
+
+
+  bool VisualSceneSolution :: 
+  GetSurfValues (const SolData * data, SurfaceElementIndex selnr, 
+                 double lam1, double lam2, 
+                 double * values) const
+  {
+    bool ok = false;
+    switch (data->soltype)
+      {
+      case SOL_VIRTUALFUNCTION:
+        {
+          ok = data->solclass->GetSurfValue (selnr, lam1, lam2, values);
+          // ok = 1;
+          // values[0] = 1.0;
+          break;
+        }
+      default:
+        {
+          for (int i = 0; i < data->components; i++)
+            ok = GetSurfValue (data, selnr, lam1, lam2, i+1, values[i]);
+        }
+      }
+    return ok;
+  }
+
+
+  bool VisualSceneSolution :: 
+  GetSurfValues (const SolData * data, SurfaceElementIndex selnr, 
+                 const double xref[], const double x[], const double dxdxref[], 
+                 double * values) const
+  {
+    bool ok = false;
+    switch (data->soltype)
+      {
+      case SOL_VIRTUALFUNCTION:
+        {
+          ok = data->solclass->GetSurfValue (selnr, xref, x, dxdxref, values);
+          break;
+        }
+      default:
+        {
+          for (int i = 0; i < data->components; i++)
+            ok = GetSurfValue (data, selnr, xref[0], xref[1], i+1, values[i]);
+        }
+      }
+    return ok;
+  }
+
+  bool VisualSceneSolution :: 
+  GetMultiSurfValues (const SolData * data, SurfaceElementIndex elnr, int npt,
+                      const double * xref, int sxref,
+                      const double * x, int sx,
+                      const double * dxdxref, int sdxdxref,
+                      double * val, int sval) const
+  {
+    bool drawelem = false;
+    if (data->soltype == SOL_VIRTUALFUNCTION)
+      drawelem = data->solclass->GetMultiSurfValue(elnr, npt, xref, sxref, x, sx, dxdxref, sdxdxref, val, sval);
+    else
+      for (int i = 0; i < npt; i++)
+        drawelem = GetSurfValues (data, elnr, xref+i*sxref, x+i*sx, dxdxref+i*sdxdxref, val+i*sval);
+    return drawelem;
+  }
+  
+  double VisualSceneSolution ::  ExtractValue (const SolData * data, int comp, double * values) const
+  {
+    double val = 0;
+    if (comp == 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 = 0;
+              switch (data->components)
+                {
+                case 1: d = 1; break;
+                case 3: d = 2; break;
+                case 6: d = 3; break;
+                }
+              for (int ci = 0; ci < d; ci++)
+                val += sqr (values[ci]);
+              for (int ci = d; ci < data->components; ci++)
+                val += 2*sqr (values[ci]);
+              val = sqrt (val);
+              break;
+            }
+
+          case FUNC_MISES:
+            {
+              int d = 0;
+              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 = 0;
+              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;
+      }
+
+    return values[comp-1];
+  }
+
+  complex<double> VisualSceneSolution ::  ExtractValueComplex (const SolData * data, int comp, double * values) const
+  {
+    if (!data->iscomplex)
+      return values[comp-1];
+    else
+      return complex<double> (values[comp-1], values[comp]);
+  }
+
+
+
+
+  bool VisualSceneSolution :: 
+  GetSurfValueComplex (const SolData * data, SurfaceElementIndex selnr, 
+                       double lam1, double lam2, 
+                       int comp, complex<double> & val) const
+  {
+    switch (data->soltype)
+      {
+      case SOL_VIRTUALFUNCTION:
+        {
+          ArrayMem<double,20> values(data->components);
+          bool ok;
+          
+          ok = data->solclass->GetSurfValue (selnr, lam1, lam2, &values[0]);
+          
+          if (ok)
+            {
+              if (!data->iscomplex)
+                val = values[comp-1];
+              else
+                val = complex<double> (values[comp-1], values[comp]);
+            }
+          
+          return ok;
+        }
+      default:
+        cerr << "case not implementd 6565" << endl;
+      }
+    return 0;
+  }
+  
+  bool VisualSceneSolution :: 
+  GetSurfValue (const SolData * data, SurfaceElementIndex selnr, 
+                double lam1, double lam2, 
+                int comp, double & val) const
+  {
+    bool ok;
+    if (comp == 0)
+      {
+        val = 0;
+        ArrayMem<double,20> values(data->components);
+        ok = GetSurfValues (data, selnr, lam1, lam2, &values[0]);
+	val = ExtractValue (data, 0, &values[0]);
+	return ok;
+      }
+
+
+    switch (data->soltype)
+      {
+      case SOL_VIRTUALFUNCTION:
+        {
+  
+          ArrayMem<double,20> values(data->components);
+          bool ok;
+
+          ok = data->solclass->GetSurfValue (selnr, lam1, lam2, &values[0]);
+
+          if (ok)
+            {
+              if (!data->iscomplex)
+                val =  values[comp-1];
+              else
+                {
+                  // cout << "time = " << time << ", cos = " << cos(time) << endl;
+     
+                  // old version: val = values[comp-1]*cos(3*time) + values[comp]*sin(3*time);
+                  // SZ: Sept 06 
+                  if(comp%2==0) 
+                    val =  values[comp-1]*cos(3*time) - values[comp-2]*sin(3*time);
+                  else
+                    val = values[comp-1]*cos(3*time) + values[comp]*sin(3*time);
+         
+         
+         
+                }
+            }
+
+          return ok;
+        }
+
+
+      case SOL_NODAL:
+        {
+          const Element2d & el = (*mesh)[selnr];
+
+          double lami[8];
+          int np, i;
+          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 1;
+        }
+
+      case SOL_ELEMENT:
+        {
+          int el1, el2;
+          mesh->GetTopology().GetSurface2VolumeElement (selnr+1, el1, el2);
+          el1--;
+
+          val = data->data[el1 * data->dist+comp-1];
+          return 1;
+        }
+
+      case SOL_NONCONTINUOUS:
+        {
+          val = 0;
+          // ?????
+          return 0;
+        }
+
+      case SOL_SURFACE_ELEMENT:
+        {
+          val = data->data[selnr * data->dist + comp-1];
+          return 1;
+        }
+
+      case SOL_SURFACE_NONCONTINUOUS:
+        {
+          const Element2d & el = (*mesh)[selnr];
+
+          double lami[8];
+          int np = 0;
+          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;
+                    }
+                  default:
+                    cerr << "case not implementd 2342" << endl;
+                  }
+                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;
+                    }
+                  default:
+                    cerr << "case not implemented 8712" << endl;
+                  }
+                break;
+              }
+            }
+        
+          int base;
+          if (order == 1)
+            base = 4 * selnr;
+          else 
+            base = 9 * selnr;
+
+          for (int i = 0; i < np; i++)
+            val += lami[i] * data->data[(base+i) * data->dist + comp-1];
+
+          return 1;
+        }
+
+      case SOL_MARKED_ELEMENTS:
+        {
+          val = (*mesh)[selnr].TestRefinementFlag();
+          return 1;
+        }
+      
+      case SOL_ELEMENT_ORDER:
+        {       
+          val = (*mesh)[selnr].GetOrder();
+          return 1;
+        }
+
+      }
+    return 0;
+  }
+
+
+
+
+
+
+
+
+
+
+
+
+  bool VisualSceneSolution :: 
+  GetSurfValue (const SolData * data, SurfaceElementIndex selnr,
+                const double xref[], const double x[], const double dxdxref[], 
+                int comp, double & val) const
+  {
+    double lam1 = xref[0], lam2 = xref[1];
+
+    bool ok;
+    if (comp == 0)
+      {
+        val = 0;
+        ArrayMem<double,20> values(data->components);
+        ok = GetSurfValues (data, selnr, xref, x, dxdxref, &values[0]);
+	val = ExtractValue (data, 0, &values[0]);
+	return ok;
+      }
+
+
+    switch (data->soltype)
+      {
+      case SOL_VIRTUALFUNCTION:
+        {
+          ArrayMem<double,20> values(data->components);
+          bool ok;
+
+          // ok = data->solclass->GetSurfValue (selnr, lam1, lam2, &values[0]);
+          // cout << "data->solclass = " << flush << data->solclass << endl;
+          ok = data->solclass->GetSurfValue (selnr, xref, x, dxdxref, &values[0]);
+          // ok = 1;
+          // values[0] = 1.0;
+
+          if (ok)
+            {
+              if (!data->iscomplex)
+                val =  values[comp-1];
+              else
+                {
+                  // cout << "time = " << time << ", cos = " << cos(time) << endl;
+     
+                  // old version: val = values[comp-1]*cos(3*time) + values[comp]*sin(3*time);
+                  // SZ: Sept 06 
+                  if(comp%2==0) 
+                    val =  values[comp-1]*cos(3*time) - values[comp-2]*sin(3*time);
+                  else
+                    val = values[comp-1]*cos(3*time) + values[comp]*sin(3*time);
+                  
+                }
+            }
+
+          return ok;
+        }
+
+
+      case SOL_NODAL:
+        {
+          const Element2d & el = (*mesh)[selnr];
+
+          double lami[8];
+          int np, i;
+          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 1;
+        }
+
+      case SOL_ELEMENT:
+        {
+          int el1, el2;
+          mesh->GetTopology().GetSurface2VolumeElement (selnr+1, el1, el2);
+          el1--;
+
+          val = data->data[el1 * data->dist+comp-1];
+          return 1;
+        }
+
+      case SOL_NONCONTINUOUS:
+        {
+          val = 0;
+          // ?????
+          return 0;
+        }
+
+      case SOL_SURFACE_ELEMENT:
+        {
+          val = data->data[selnr * data->dist + comp-1];
+          return 1;
+        }
+
+      case SOL_SURFACE_NONCONTINUOUS:
+        {
+          const Element2d & el = (*mesh)[selnr];
+
+          double lami[8] = { 0.0 };
+          int np = 0;
+          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;
+                    }
+                  default:
+                    cerr << "case not impl 234234" << endl;
+                  }
+                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;
+                    }
+                  default:
+                    cerr << "case not implented 3234" << endl;
+                  }
+                break;
+              }
+            }
+        
+          int base;
+          if (order == 1)
+            base = 4 * selnr;
+          else 
+            base = 9 * selnr;
+
+          for (int i = 0; i < np; i++)
+            val += lami[i] * data->data[(base+i) * data->dist + comp-1];
+
+          return 1;
+        }
+
+      case SOL_MARKED_ELEMENTS:
+        {
+          val = (*mesh)[selnr].TestRefinementFlag();
+          return 1;
+        }
+      
+      case SOL_ELEMENT_ORDER:
+        {       
+          val = (*mesh)[selnr].GetOrder();
+          return 1;
+        }
+
+      }
+    return 0;
+  }
+
+
+
+
+
+
+
+
+
+  Vec<3> VisualSceneSolution :: 
+  GetDeformation (ElementIndex elnr, const Point<3> & p) const
+  {
+    Vec<3> def;
+    if (deform && vecfunction != -1)
+      {
+        GetValues (soldata[vecfunction], elnr, p(0), p(1), p(2), &def(0));
+        def *= scaledeform;
+
+        if (soldata[vecfunction]->components == 2) def(2) = 0;
+      }
+    else
+      def = 0;
+    return def;
+  }
+
+
+  Vec<3> VisualSceneSolution :: 
+  GetSurfDeformation (SurfaceElementIndex elnr, double lam1, double lam2) const
+  {
+    Vec<3> def;
+    if (deform && vecfunction != -1)
+      {
+        GetSurfValues (soldata[vecfunction], elnr, lam1, lam2,  &def(0));
+        def *= scaledeform;
+
+        if (soldata[vecfunction]->components == 2) def(2) = 0;
+      }
+    else if (deform && scalfunction != -1 && mesh->GetDimension()==2)
+      { // he: allow for 3d plots of 2d surfaces: usage: turn deformation on
+        def = 0;
+        GetSurfValue (soldata[scalfunction], elnr, lam1, lam2, scalcomp, def(2));
+        def *= scaledeform;
+      }
+    else
+      def = 0;
+    return def;
+  }
+
+  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,
+                                                     Array<ClipPlanePoint> & pts)
+  {
+    static int timer1 = NgProfiler::CreateTimer ("ClipPlaneTrigs1");
+    static int timer2 = NgProfiler::CreateTimer ("ClipPlaneTrigs2");
+    static int timer3 = NgProfiler::CreateTimer ("ClipPlaneTrigs3");
+    static int timer4 = NgProfiler::CreateTimer ("ClipPlaneTrigs4");
+
+
+    NgProfiler::RegionTimer reg1 (timer1);
+
+    int ne = mesh->GetNE();
+
+    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<Point<3> > pointsloc;
+
+    int n = 1 << subdivisions;
+    int n3 = (n+1)*(n+1)*(n+1);
+
+    Array<Point<3> > grid(n3);
+    Array<Point<3> > locgrid(n3);
+    Array<Mat<3,3> > trans(n3);
+    Array<double> val(n3);
+    Array<int> compress(n3);
+
+
+    for (ElementIndex ei = 0; ei < ne; ei++)
+      {
+        int first_point_of_element = pts.Size();
+
+#ifdef PARALLEL
+	// parallel visualization --> dont draw ghost elements
+	if ( (*mesh)[ei] . IsGhost() ) continue;
+#endif
+
+	locgrid.SetSize(n3);
+        if(vispar.clipdomain > 0 && vispar.clipdomain != (*mesh)[ei].GetIndex()) continue;
+        if(vispar.donotclipdomain > 0 && vispar.donotclipdomain == (*mesh)[ei].GetIndex()) continue;
+
+        ELEMENT_TYPE type = (*mesh)[ei].GetType();
+        if (type == HEX || type == PRISM || type == TET || type == TET10 || type == PYRAMID)
+          {
+            const Element & el = (*mesh)[ei];
+
+            int ii = 0;
+            int cnt_valid = 0;
+
+            NgProfiler::StartTimer (timer2);
+
+
+            if (type == TET || type == TET10)
+              {
+                for (int ix = 0; ix <= n; ix++)
+                  for (int iy = 0; iy <= n; iy++)
+                    for (int iz = 0; iz <= n; iz++, ii++)
+                      {
+                        if (ix+iy+iz <= n)
+                          {
+                            compress[ii] = cnt_valid;
+                            locgrid[cnt_valid] = 
+                              Point<3> (double(ix) / n, double(iy) / n, double(iz) / n);
+                            cnt_valid++;
+                          }
+                        else
+                          compress[ii] = -1;
+                      }
+              }
+            
+            else
+              
+              for (int ix = 0; ix <= n; ix++)
+                for (int iy = 0; iy <= n; iy++)
+                  for (int iz = 0; iz <= n; iz++, ii++)
+                    {
+                      Point<3> ploc;
+                      compress[ii] = ii;
+                      
+                      switch (type)
+                        {
+                        case PRISM:
+                          if (ix+iy <= n)
+                            {
+                              ploc = Point<3> (double(ix) / n, double(iy) / n, double(iz) / n);
+                              compress[ii] = cnt_valid;
+                              cnt_valid++;
+                            }
+                          else
+                            compress[ii] = -1;
+                          break;
+                        case HEX:
+                          ploc = Point<3> (double(ix) / n, double(iy) / n, double(iz) / n);
+                          break;
+                        case PYRAMID:
+                          ploc = Point<3> (double(ix) / n * (1-double(iz)/n),
+                                           double(iy) / n * (1-double(iz)/n),
+                                           double(iz)/n);
+                          if (iz == n) ploc = Point<3> (0,0,1-1e-8);
+                          break;
+                        default:
+                          cerr << "clip plane trigs not implemented" << endl;
+                          ploc = Point<3> (0,0,0);
+                        }
+                      if (compress[ii] != -1)
+                        locgrid[compress[ii]] = ploc;
+                    }
+
+            if (type != TET && type != TET10 && type != PRISM) cnt_valid = n3;
+
+	    locgrid.SetSize(cnt_valid);
+
+            NgProfiler::StopTimer (timer2);
+            NgProfiler::RegionTimer reg4(timer4);
+
+            if (mesh->GetCurvedElements().IsHighOrder())
+              {
+                mesh->GetCurvedElements().
+                  CalcMultiPointElementTransformation (&locgrid, ei, &grid, 0);
+              }
+            else
+              {
+                Vector shape(el.GetNP());
+                MatrixFixWidth<3> pointmat(el.GetNP());
+
+                for (int k = 0; k < el.GetNP(); k++)
+                  for (int j = 0; j < 3; j++)
+                    pointmat(k,j) = (*mesh)[el[k]](j);
+                
+                for (int i = 0; i < cnt_valid; i++)
+                  {
+                    el.GetShapeNew (locgrid[i], shape);
+                    Point<3> pglob;
+                    for (int j = 0; j < 3; j++)
+                      {
+                        pglob(j) = 0;
+                        for (int k = 0; k < el.GetNP(); k++)
+                          pglob(j) += shape(k) * pointmat(k,j);
+                      }
+                    grid[i] = pglob;
+                  }
+              }
+
+            NgProfiler::RegionTimer reg3(timer3);
+
+            bool has_pos = 0, has_neg = 0;
+                
+            for (int i = 0; i < cnt_valid; i++)
+              {
+                val[i] = 
+                  grid[i](0) * clipplane[0] + 
+                  grid[i](1) * clipplane[1] + 
+                  grid[i](2) * clipplane[2] + 
+                  clipplane[3];
+                    
+                if (val[i] > 0)
+                  has_pos = 1;
+                else
+                  has_neg = 1;
+              }
+                
+            if (!has_pos || !has_neg) continue;
+                
+
+            for (int ix = 0; ix < n; ix++)
+              for (int iy = 0; iy < n; iy++)
+                for (int iz = 0; iz < n; iz++)
+                  {
+                    int base = iz + (n+1)*iy + (n+1)*(n+1)*ix;
+                    int pi[8] = 
+                      { base, base+(n+1)*(n+1), base+(n+1)*(n+1)+(n+1), base+(n+1),
+                        base+1, base+(n+1)*(n+1)+1, base+(n+1)*(n+1)+(n+1)+1, base+(n+1)+1 };
+
+                    for (int j = 0; j < 8; j++)
+                      pi[j] = compress[pi[j]];
+
+                    const int tets[6][4] = 
+                      { { 1, 2, 4, 5 },
+                        { 4, 5, 2, 8 },
+                        { 2, 8, 5, 6 },
+                        { 2, 3, 4, 8 },
+                        { 2, 3, 8, 6 },
+                        { 3, 8, 6, 7 } };
+
+                    for (int ii = 0; ii < 6; ii++)
+                      {
+                        int teti[4];
+                        for (int k = 0; k < 4; k++)
+                          teti[k] = pi[tets[ii][k]-1];
+
+                        bool is_valid = 1;
+                        for (int j = 0; j < 4; j++)
+                          if (teti[j] == -1) is_valid = 0;
+                        if (!is_valid) continue;
+
+                        for (int j = 0; j < 4; j++)
+                          nodevali[j] = val[teti[j]];
+          
+                        cntce = 0;
+                        for (int 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 = grid[teti[lpi1]];
+                                Point<3> p2 = grid[teti[lpi2]];
+                  
+                                edgep[j] = p1 + (1-edgelam[j]) * (p2-p1);
+                  
+                                cntce++;
+                                cpe3 = cpe2;
+                                cpe2 = cpe1;
+                                cpe1 = j;
+                                if (cntce >= 3)
+                                  {
+                                    ClipPlaneTrig cpt;
+                                    cpt.elnr = ei;
+                                  
+                                    for (int 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 = locgrid[teti[pi1]];
+                                        Point<3> p2 = locgrid[teti[pi2]];
+
+                                        // cpt.points[k].lami = p2 + edgelam[ednr] * (p1-p2);
+
+                                        ClipPlanePoint cppt;
+                                        cppt.elnr = ei;
+                                        cppt.p = edgep[ednr];
+                                        cppt.lami =  p2 + edgelam[ednr] * (p1-p2);
+
+                                        int pnr = -1;
+
+                                        for (int l = first_point_of_element; l < pts.Size(); l++)
+                                          if (fabs (cppt.lami(0)-pts[l].lami(0)) < 1e-8 &&
+                                              fabs (cppt.lami(1)-pts[l].lami(1)) < 1e-8 &&
+                                              fabs (cppt.lami(2)-pts[l].lami(2)) < 1e-8)
+                                            {
+                                              pnr = l;
+                                              break;
+                                            }
+
+                                        if (pnr == -1)
+                                          pnr = pts.Append (cppt)-1;
+
+                                        cpt.points[k].pnr = pnr;
+                                        cpt.points[k].locpnr = pnr-first_point_of_element;
+                                      }
+                                  
+                                    trigs.Append (cpt);
+                                  }
+                              }
+                          }
+                      }
+                  }
+          }
+
+        else
+          {  // other elements not supported (JS, June 2007)
+            return;
+          }
+      
+      }
+  }
+
+  void VisualSceneSolution :: GetClippingPlaneGrid (Array<ClipPlanePoint> & pts)
+  {
+    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();
+    n.Normalize();
+    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);
+
+    for (xi1 = xi1mid-rad+xoffset/gridsize; xi1 <= xi1mid+rad+xoffset/gridsize; xi1 += rad / gridsize)
+      for (xi2 = xi2mid-rad+yoffset/gridsize; xi2 <= xi2mid+rad+yoffset/gridsize; xi2 += rad / gridsize)
+        {
+          Point3d hp = p + xi1 * t1 + xi2 * t2;
+        
+          int cindex(-1);
+          bool allowindex(true);
+          if(vispar.clipdomain > 0)
+            {
+              cindex = vispar.clipdomain;
+            }
+          else if(vispar.donotclipdomain > 0)
+            {
+              allowindex = false;
+              cindex = vispar.donotclipdomain;
+            }
+
+          double lami[3];
+          int elnr = mesh->GetElementOfPoint (hp, lami,0,cindex,allowindex)-1;
+
+          if (elnr != -1)
+            {
+              ClipPlanePoint cpp;
+              cpp.p = hp;
+              cpp.elnr = elnr;
+              cpp.lami(0) = lami[0];
+              cpp.lami(1) = lami[1];
+              cpp.lami(2) = lami[2];
+              pts.Append (cpp);
+            }
+        }
+  };
+
+
+
+
+  void VisualSceneSolution :: DrawClipPlaneTrigs () 
+  {
+#ifdef PARALLELGL
+
+    if (id == 0 && ntasks > 1)
+      {
+	InitParallelGL();
+
+	Array<int> parlists (ntasks);
+
+	MyMPI_SendCmd ("redraw");
+	MyMPI_SendCmd ("clipplanetrigs");
+
+	for ( int dest = 1; dest < ntasks; dest++ )
+	  MyMPI_Recv (parlists[dest], dest, MPI_TAG_VIS);
+
+	if (clipplanelist_scal)
+	  glDeleteLists (clipplanelist_scal, 1);
+
+	clipplanelist_scal = glGenLists (1);
+	glNewList (clipplanelist_scal, GL_COMPILE);
+	
+	for ( int dest = 1; dest < ntasks; dest++ )
+	  glCallList (parlists[dest]);
+	
+	glEndList();
+	return;
+      }
+#endif
+
+
+
+
+
+    if (clipplanelist_scal)
+      glDeleteLists (clipplanelist_scal, 1);
+    
+    clipplanelist_scal = glGenLists (1);
+    glNewList (clipplanelist_scal, GL_COMPILE);
+
+
+    Array<ClipPlaneTrig> trigs;
+    Array<ClipPlanePoint> points;
+    GetClippingPlaneTrigs (trigs, points);
+	    
+    glNormal3d (-clipplane[0], -clipplane[1], -clipplane[2]);
+    glColor3d (1.0, 1.0, 1.0);
+    
+    SetTextureMode (usetexture);
+
+    SolData * sol = NULL;
+
+    if (scalfunction != -1) 
+      sol = soldata[scalfunction];
+
+
+
+    glBegin (GL_TRIANGLES);
+
+    int maxlpnr = 0;
+    for (int i = 0; i < trigs.Size(); i++)
+      for (int j = 0; j < 3; j++)
+        maxlpnr = max2 (maxlpnr, trigs[i].points[j].locpnr);
+
+    Array<double> vals(maxlpnr+1);
+    Array<complex<double> > valsc(maxlpnr+1);
+    Array<int> elnrs(maxlpnr+1);
+    Array<bool> trigok(maxlpnr+1);
+    Array<Point<3> > locpoints(maxlpnr+1);
+    Array<Point<3> > globpoints(maxlpnr+1);
+    Array<Mat<3> > jacobi(maxlpnr+1);
+    Array<double> mvalues( (maxlpnr+1) * sol->components);
+    trigok = false;
+    elnrs = -1;
+
+    Point<3> p[3];
+    // double val[3];
+    complex<double> valc[3];
+    int lastelnr = -1;
+    int nlp = -1;
+
+    for (int i = 0; i < trigs.Size(); i++)
+      {
+	bool ok = true;
+        const ClipPlaneTrig & trig = trigs[i];
+	if (trig.elnr != lastelnr)
+	  {
+	    lastelnr = trig.elnr;
+	    nlp = -1;
+
+	    for (int ii = i; ii < trigs.Size(); ii++)
+	      {
+		if (trigs[ii].elnr != trig.elnr) break;
+		for (int j = 0; j < 3; j++)
+		  nlp = max (nlp, trigs[ii].points[j].locpnr);
+	      }
+	    nlp++;
+	    locpoints.SetSize (nlp);
+
+	    for (int ii = i; ii < trigs.Size(); ii++)
+	      {
+		if (trigs[ii].elnr != trig.elnr) break;
+		for (int j = 0; j < 3; j++)
+		  locpoints[trigs[ii].points[j].locpnr] = points[trigs[ii].points[j].pnr].lami;
+	      }
+
+	    mesh->GetCurvedElements().
+	      CalcMultiPointElementTransformation (&locpoints, trig.elnr, 
+						   &globpoints, &jacobi);
+
+	    bool
+	      drawelem = GetMultiValues (sol, trig.elnr, nlp, 
+					 &locpoints[0](0), &locpoints[1](0)-&locpoints[0](0),
+					 &globpoints[0](0), &globpoints[1](0)-&globpoints[0](0),
+					 &jacobi[0](0), &jacobi[1](0)-&jacobi[0](0),
+					 &mvalues[0], sol->components);
+	    
+	    // cout << "have multivalues, comps = " << sol->components << endl;
+
+	    if (!drawelem) ok = false;
+	    if (usetexture != 2 || !sol->iscomplex)
+	      for (int ii = 0; ii < nlp; ii++)
+		vals[ii] = ExtractValue(sol, scalcomp, &mvalues[ii*sol->components]);
+	    else
+	      for (int ii = 0; ii < nlp; ii++)
+		valsc[ii] = complex<double> (mvalues[ii*sol->components],
+					     mvalues[ii*sol->components+1]);
+	  }
+	
+	if(ok)
+	  for(int j=0; j<3; j++)
+	    {
+	      if (usetexture != 2 || !sol->iscomplex)
+		SetOpenGlColor (vals[trig.points[j].locpnr]);
+	      else
+		glTexCoord2f ( valsc[trig.points[j].locpnr].real(), 
+			       valsc[trig.points[j].locpnr].imag() );
+
+	      p[j] = points[trig.points[j].pnr].p;
+
+	      if (deform)
+		{
+		  Point<3> ploc = points[trig.points[j].pnr].lami;
+		  p[j] += GetDeformation (trig.elnr, ploc);
+		}
+
+	      glVertex3dv (p[j]);
+	    }
+
+      }
+    glEnd();
+
+    glEndList ();
+
+
+#ifdef PARALLELGL
+    glFinish();
+    if (id > 0)
+      MyMPI_Send (clipplanelist_scal, 0, MPI_TAG_VIS);
+#endif
+  }
+
+
+
+
+
+
+
+
+
+
+  void VisualSceneSolution ::
+  SetOpenGlColor(double val)
+  {
+    if (usetexture == 1 && !logscale)
+      {
+        glTexCoord1f ( val );
+        return;
+      }
+
+    double valmin = minval;
+    double valmax = maxval;
+
+    double value;
+
+    if (!logscale)
+      value = (val - valmin) / (valmax - valmin);
+    else
+      {
+        if (valmax <= 0) valmax = 1;
+        if (valmin <= 0) valmin = 1e-4 * valmax;
+        value = (log(fabs(val)) - log(valmin)) / (log(valmax) - log(valmin));
+      }
+
+    if (!invcolor)
+      value = 1 - value;
+
+
+    if (value > 1) value = 1;
+    if (value < 0) value = 0;
+
+    value *= 4;
+
+    static 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];
+    for (int j = 0; j < 3; j++)
+      col[j] = (1-r) * colp[i][j] + r * colp[i+1][j];
+  
+    glColor3dv (col);
+  }
+
+
+
+  void VisualSceneSolution ::
+  SetTextureMode (int texturemode) const
+  {
+    switch (texturemode)
+      {
+      case 0:
+        glDisable (GL_TEXTURE_1D);
+        glDisable (GL_TEXTURE_2D);
+        break;
+      case 1:
+        glEnable (GL_TEXTURE_1D);
+        glDisable (GL_TEXTURE_2D);
+        glColor3d (1.0, 1.0, 1.0);   
+        break;
+      case 2:
+        glDisable (GL_TEXTURE_1D);
+        glEnable (GL_TEXTURE_2D);
+        glColor3d (1.0, 1.0, 1.0);   
+        break;
+      }
+  }
+
+
+
+
+  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);
+    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);
+    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)
+  {
+    vsmesh.SetClippingPlane();
+    // vsmesh.BuildFilledList();
+    vsmesh.MouseDblClick(px,py);
+  }
+
+
+
+#ifdef PARALLELGL
+
+  void VisualSceneSolution :: Broadcast ()
+  {
+    MPI_Datatype type;
+    int blocklen[] = 
+      { 
+	1, 1, 1, 1,
+	1, 1, 1, 1, 
+	1, 1, 1, 1, 
+	1, 4, 1
+      };
+    MPI_Aint displ[] = { (char*)&usetexture - (char*)this,
+			 (char*)&clipsolution - (char*)this,
+			 (char*)&scalfunction - (char*)this,
+			 (char*)&scalcomp - (char*)this,
+
+			 (char*)&vecfunction - (char*)this,
+			 (char*)&gridsize - (char*)this,
+			 (char*)&autoscale - (char*)this,
+			 (char*)&logscale - (char*)this,
+
+			 (char*)&minval - (char*)this,
+			 (char*)&maxval - (char*)this,
+			 (char*)&numisolines - (char*)this,
+			 (char*)&subdivisions - (char*)this,
+
+			 (char*)&evalfunc - (char*)this,
+			 (char*)&clipplane[0] - (char*)this,
+			 (char*)&multidimcomponent - (char*)this 
+    };
+
+
+    MPI_Datatype types[] = { 
+      MPI_INT, MPI_INT, MPI_INT, MPI_INT,
+      MPI_INT, MPI_INT, MPI_INT, MPI_INT,
+      MPI_DOUBLE, MPI_DOUBLE, MPI_INT, MPI_INT,
+      MPI_INT, MPI_DOUBLE, MPI_INT
+    };
+
+    MPI_Type_create_struct (15, blocklen, displ, types, &type);
+    MPI_Type_commit ( &type );
+
+    MPI_Bcast (this, 1, type, 0, MPI_COMM_WORLD);
+    MPI_Type_free (&type);
+
+    /*
+    MyMPI_Bcast (usetexture);
+    MyMPI_Bcast (clipsolution);
+    MyMPI_Bcast (scalfunction);
+    MyMPI_Bcast (scalcomp);
+    MyMPI_Bcast (vecfunction);
+    MyMPI_Bcast (gridsize);
+
+    MyMPI_Bcast (autoscale);
+    MyMPI_Bcast (logscale);
+    MyMPI_Bcast (minval);
+    MyMPI_Bcast (maxval);
+    MyMPI_Bcast (numisolines);
+    MyMPI_Bcast (subdivisions);
+
+    MyMPI_Bcast (clipplane[0]);
+    MyMPI_Bcast (clipplane[1]);
+    MyMPI_Bcast (clipplane[2]);
+    MyMPI_Bcast (clipplane[3]);
+    */
+  }
+  
+#endif
+
+
+  int Ng_Vis_Set (ClientData clientData,
+                  Tcl_Interp * interp,
+                  int argc, tcl_const char *argv[])
+
+  {
+    if (argc >= 2)
+      {
+        if (strcmp (argv[1], "parameters") == 0)
+          {
+            vssolution.imag_part = 
+              atoi (Tcl_GetVar (interp, "::visoptions.imaginary", TCL_GLOBAL_ONLY));      
+            vssolution.usetexture = 
+              atoi (Tcl_GetVar (interp, "::visoptions.usetexture", TCL_GLOBAL_ONLY));
+            if (atoi (Tcl_GetVar (interp, "::visoptions.redrawperiodic", TCL_GLOBAL_ONLY)))
+              vssolution.usetexture = 2;
+                
+            vssolution.invcolor = 
+              atoi (Tcl_GetVar (interp, "::visoptions.invcolor", TCL_GLOBAL_ONLY));       
+
+            vssolution.clipsolution = 0;
+
+            if (strcmp (Tcl_GetVar (interp, "::visoptions.clipsolution", TCL_GLOBAL_ONLY), 
+                        "scal") == 0)
+              vssolution.clipsolution = 1;
+            if (strcmp (Tcl_GetVar (interp, "::visoptions.clipsolution", TCL_GLOBAL_ONLY), 
+                        "vec") == 0)
+              vssolution.clipsolution = 2;
+            
+            tcl_const char * scalname =  
+              Tcl_GetVar (interp, "::visoptions.scalfunction", TCL_GLOBAL_ONLY);
+            tcl_const char * vecname = 
+              Tcl_GetVar (interp, "::visoptions.vecfunction", TCL_GLOBAL_ONLY);
+            tcl_const char * fieldlines_vecname = 
+              Tcl_GetVar (interp, "::visoptions.fieldlinesvecfunction", TCL_GLOBAL_ONLY);
+                
+          
+            vssolution.scalfunction = -1;
+            vssolution.vecfunction = -1;
+            vssolution.fieldlines_vecfunction = -1;
+
+            int pointpos; // SZ 
+            const char * pch = strchr(scalname,'.');
+            pointpos = int(pch-scalname+1);
+
+            for (int i = 0; i < vssolution.soldata.Size(); i++)
+              {
+                if ( (strlen (vssolution.soldata[i]->name) == pointpos-1) &&
+                     (strncmp (vssolution.soldata[i]->name, scalname, pointpos-1) == 0) )
+                  {
+                    vssolution.scalfunction = i;
+                    vssolution.scalcomp = atoi (scalname + pointpos);
+		    if ( vssolution.scalcomp > vssolution.soldata[i]->components )
+                      vssolution.scalcomp = 1;
+		    char newscalname[100];
+		    for ( int ii = 0; ii < pointpos; ii++ )
+		      newscalname[ii] = scalname[ii];
+		    newscalname[pointpos] = '.';
+		    sprintf (newscalname+pointpos, "%i", vssolution.scalcomp);
+
+                    if (strcmp (scalname, newscalname) != 0)
+                      Tcl_SetVar ( interp, "::visoptions.scalfunction", newscalname, TCL_GLOBAL_ONLY );
+		    scalname = Tcl_GetVar (interp, "::visoptions.scalfunction", TCL_GLOBAL_ONLY);
+                  }
+                if (strcmp (vssolution.soldata[i]->name, vecname) == 0)
+                  {
+                    vssolution.vecfunction = i;
+                    //cout  << "set vecfunction to " << i << endl;
+                  }
+                if (strcmp (vssolution.soldata[i]->name, fieldlines_vecname) == 0)
+                  {
+                    vssolution.fieldlines_vecfunction = i;
+                    //cout  << "set fieldlines-vecfunction to " << i << endl;
+                  }
+              }
+
+            if(vssolution.fieldlines_vecfunction != -1 &&
+               vssolution.vecfunction == -1)
+              {
+                //cout << "WARNING: Setting vector function in Visualization toolbox to value from Fieldlines toolbox!" << endl;
+                vssolution.vecfunction = vssolution.fieldlines_vecfunction;
+              }
+               
+	    // reset visoptions.scalfunction and visoptions.vecfunction if not avialable 
+	    if ( vssolution.scalfunction == -1 && strcmp (scalname, "none") != 0)
+              Tcl_SetVar ( interp, "::visoptions.scalfunction", "none", TCL_GLOBAL_ONLY );
+	    if ( vssolution.vecfunction == -1  && strcmp (vecname, "none") != 0)
+              Tcl_SetVar ( interp, "::visoptions.vecfunction", "none", TCL_GLOBAL_ONLY );
+
+            tcl_const char * evalname = 
+              Tcl_GetVar (interp, "::visoptions.evaluate", TCL_GLOBAL_ONLY);
+          
+            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", TCL_GLOBAL_ONLY));
+
+            vssolution.xoffset = 
+              atof (Tcl_GetVar (interp, "::visoptions.xoffset", TCL_GLOBAL_ONLY));
+
+            //    cout << "x-offset:" << vssolution.xoffset << endl;
+
+            vssolution.yoffset = 
+              atof (Tcl_GetVar (interp, "::visoptions.yoffset", TCL_GLOBAL_ONLY));
+
+            vssolution.autoscale = 
+              atoi (Tcl_GetVar (interp, "::visoptions.autoscale", TCL_GLOBAL_ONLY));
+
+
+            /*
+              vssolution.linear_colors = 
+              atoi (Tcl_GetVar (interp, "::visoptions.lineartexture", TCL_GLOBAL_ONLY));
+            */
+            vssolution.logscale = 
+              atoi (Tcl_GetVar (interp, "::visoptions.logscale", TCL_GLOBAL_ONLY));
+
+            vssolution.mminval = 
+              atof (Tcl_GetVar (interp, "::visoptions.mminval", TCL_GLOBAL_ONLY));
+            vssolution.mmaxval = 
+              atof (Tcl_GetVar (interp, "::visoptions.mmaxval", TCL_GLOBAL_ONLY));
+
+            vssolution.showclipsolution = 
+              atoi (Tcl_GetVar (interp, "::visoptions.showclipsolution", TCL_GLOBAL_ONLY));
+            vssolution.showsurfacesolution = 
+              atoi (Tcl_GetVar (interp, "::visoptions.showsurfacesolution", TCL_GLOBAL_ONLY));
+            vssolution.lineartexture = 
+              atoi (Tcl_GetVar (interp, "::visoptions.lineartexture", TCL_GLOBAL_ONLY));
+            vssolution.numtexturecols = 
+              atoi (Tcl_GetVar (interp, "::visoptions.numtexturecols", TCL_GLOBAL_ONLY));
+
+            vssolution.multidimcomponent = 
+              atoi (Tcl_GetVar (interp, "::visoptions.multidimcomponent", TCL_GLOBAL_ONLY));
+
+	    vssolution.drawpointcurves = 
+	      atoi (Tcl_GetVar (interp, "::visoptions.drawpointcurves", TCL_GLOBAL_ONLY));	      
+
+            vssolution.draw_fieldlines = 
+	      atoi (Tcl_GetVar (interp, "::visoptions.drawfieldlines", TCL_GLOBAL_ONLY));
+            vssolution.num_fieldlines = 
+              atoi (Tcl_GetVar (interp, "::visoptions.numfieldlines", TCL_GLOBAL_ONLY));
+            vssolution.fieldlines_randomstart =
+              atoi (Tcl_GetVar (interp, "::visoptions.fieldlinesrandomstart", TCL_GLOBAL_ONLY));
+
+            vssolution.fieldlines_reltolerance =
+              atof (Tcl_GetVar (interp, "::visoptions.fieldlinestolerance", TCL_GLOBAL_ONLY));
+
+            if (strcmp (Tcl_GetVar (interp, "::visoptions.fieldlinesrktype", TCL_GLOBAL_ONLY), 
+                        "euler") == 0)
+              vssolution.fieldlines_rktype = 0;
+            else if (strcmp (Tcl_GetVar (interp, "::visoptions.fieldlinesrktype", TCL_GLOBAL_ONLY), 
+                             "eulercauchy") == 0)
+              vssolution.fieldlines_rktype = 1;
+            else if (strcmp (Tcl_GetVar (interp, "::visoptions.fieldlinesrktype", TCL_GLOBAL_ONLY), 
+                             "simpson") == 0)
+              vssolution.fieldlines_rktype = 2;
+            else if (strcmp (Tcl_GetVar (interp, "::visoptions.fieldlinesrktype", TCL_GLOBAL_ONLY), 
+                             "crungekutta") == 0)
+              vssolution.fieldlines_rktype = 3;
+
+
+            vssolution.fieldlines_rellength =
+              atof (Tcl_GetVar (interp, "::visoptions.fieldlineslength", TCL_GLOBAL_ONLY));
+
+            vssolution.fieldlines_maxpoints = 
+              atoi (Tcl_GetVar (interp, "::visoptions.fieldlinesmaxpoints", TCL_GLOBAL_ONLY));
+
+            vssolution.fieldlines_relthickness =
+              atof (Tcl_GetVar (interp, "::visoptions.fieldlinesthickness", TCL_GLOBAL_ONLY));
+
+
+            vssolution.fieldlines_fixedphase = 
+              (atoi (Tcl_GetVar (interp, "::visoptions.fieldlinesonlyonephase", TCL_GLOBAL_ONLY)) != 0);
+
+            if(vssolution.fieldlines_fixedphase)
+              vssolution.fieldlines_phase =
+                atof (Tcl_GetVar (interp, "::visoptions.fieldlinesphase", TCL_GLOBAL_ONLY));
+
+
+            if (strcmp (Tcl_GetVar (interp, "::visoptions.fieldlinesstartarea", TCL_GLOBAL_ONLY), 
+                        "box") == 0)
+              vssolution.fieldlines_startarea  = 0;
+            else if (strcmp (Tcl_GetVar (interp, "::visoptions.fieldlinesstartarea", TCL_GLOBAL_ONLY), 
+                             "file") == 0)
+              vssolution.fieldlines_startarea  = 1;
+            else if (strcmp (Tcl_GetVar (interp, "::visoptions.fieldlinesstartarea", TCL_GLOBAL_ONLY), 
+                             "face") == 0)
+              vssolution.fieldlines_startarea  = 2;
+
+                
+            if (vssolution.fieldlines_startarea == 0)
+              {
+                vssolution.fieldlines_startarea_parameter.SetSize(6);
+                vssolution.fieldlines_startarea_parameter[0] = atof (Tcl_GetVar (interp, "::visoptions.fieldlinesstartareap1x", TCL_GLOBAL_ONLY));
+                vssolution.fieldlines_startarea_parameter[1] = atof (Tcl_GetVar (interp, "::visoptions.fieldlinesstartareap1y", TCL_GLOBAL_ONLY));
+                vssolution.fieldlines_startarea_parameter[2] = atof (Tcl_GetVar (interp, "::visoptions.fieldlinesstartareap1z", TCL_GLOBAL_ONLY));
+                vssolution.fieldlines_startarea_parameter[3] = atof (Tcl_GetVar (interp, "::visoptions.fieldlinesstartareap2x", TCL_GLOBAL_ONLY));
+                vssolution.fieldlines_startarea_parameter[4] = atof (Tcl_GetVar (interp, "::visoptions.fieldlinesstartareap2y", TCL_GLOBAL_ONLY));
+                vssolution.fieldlines_startarea_parameter[5] = atof (Tcl_GetVar (interp, "::visoptions.fieldlinesstartareap2z", TCL_GLOBAL_ONLY));
+              }
+            else if (vssolution.fieldlines_startarea == 1)
+              {
+                vssolution.fieldlines_filename = Tcl_GetVar (interp, "::visoptions.fieldlinesfilename", TCL_GLOBAL_ONLY);
+              }
+            else if (vssolution.fieldlines_startarea == 2)
+              {
+                vssolution.fieldlines_startface = atoi (Tcl_GetVar (interp, "::visoptions.fieldlinesstartface", TCL_GLOBAL_ONLY));
+              }
+
+          
+            vssolution.deform =
+              atoi (Tcl_GetVar (interp, "::visoptions.deformation", TCL_GLOBAL_ONLY));
+            vssolution.scaledeform =
+              atof (Tcl_GetVar (interp, "::visoptions.scaledeform1", TCL_GLOBAL_ONLY)) *
+              atof (Tcl_GetVar (interp, "::visoptions.scaledeform2", TCL_GLOBAL_ONLY));
+
+
+            if (atoi (Tcl_GetVar (interp, "::visoptions.isolines", TCL_GLOBAL_ONLY)))
+              vssolution.numisolines = atoi (Tcl_GetVar (interp, "::visoptions.numiso", TCL_GLOBAL_ONLY));
+            else
+              vssolution.numisolines = 0;
+            vssolution.draw_isosurface = 
+              atoi (Tcl_GetVar (interp, "::visoptions.isosurf", TCL_GLOBAL_ONLY));
+
+            vssolution.SetSubdivision(atoi (Tcl_GetVar (interp, "::visoptions.subdivisions", TCL_GLOBAL_ONLY)));
+
+            vssolution.UpdateSolutionTimeStamp();
+          }
+      
+        if (strcmp (argv[1], "parametersrange") == 0)
+          {
+            vssolution.invcolor = 
+              atoi (Tcl_GetVar (interp, "::visoptions.invcolor", TCL_GLOBAL_ONLY));       
+            vssolution.mminval = 
+              atof (Tcl_GetVar (interp, "::visoptions.mminval", TCL_GLOBAL_ONLY));
+            vssolution.mmaxval = 
+              atof (Tcl_GetVar (interp, "::visoptions.mmaxval", TCL_GLOBAL_ONLY));
+            vssolution.lineartexture = 
+              atoi (Tcl_GetVar (interp, "::visoptions.lineartexture", TCL_GLOBAL_ONLY));
+            vssolution.numtexturecols = 
+              atoi (Tcl_GetVar (interp, "::visoptions.numtexturecols", TCL_GLOBAL_ONLY));
+
+            if (vssolution.usetexture == 0 || vssolution.logscale)
+              vssolution.UpdateSolutionTimeStamp();
+          }
+
+
+        if (argc >= 3 && strcmp (argv[1], "time") == 0)
+          {
+            vssolution.time = double (atoi (argv[2])) / 1000;
+         
+            vssolution.timetimestamp = NextTimeStamp();
+            cout << "\rtime = " << vssolution.time << "    " << flush;
+          }
+
+      }
+
+    
+    vsmesh.SetClippingPlane ();  // for computing parameters
+    vssolution.SetClippingPlane ();  // for computing parameters
+    glDisable(GL_CLIP_PLANE0);
+
+#ifdef PARALLELGL
+    vsmesh.Broadcast ();
+#endif    
+
+
+    return TCL_OK;
+  }
+
+  int Ng_Vis_Field (ClientData clientData,
+                    Tcl_Interp * interp,
+                    int argc, tcl_const char *argv[])
+  {
+    int i;
+    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;
+  }
+}
+
+#endif // NOTCL
diff --git a/contrib/Netgen/libsrc/visualization/vssolution.hpp b/contrib/Netgen/libsrc/visualization/vssolution.hpp
new file mode 100644
index 0000000000..9bf1b78de4
--- /dev/null
+++ b/contrib/Netgen/libsrc/visualization/vssolution.hpp
@@ -0,0 +1,430 @@
+#ifndef FILE_VSSOLUTION
+#define FILE_VSSOLUTION
+
+
+
+#ifndef SMALLLIB
+#ifndef NOTCL
+
+extern 
+void ImportSolution (const char * filename);
+
+extern int Ng_Vis_Set (ClientData clientData,
+		       Tcl_Interp * interp,
+		       int argc, tcl_const char *argv[]);
+#endif
+#endif
+
+class FieldLineCalc;
+
+class VisualSceneSolution : public VisualScene
+{
+  friend class FieldLineCalc;
+  
+  class ClipPlaneTrig
+  {
+  public:
+    struct ps 
+    {
+      int pnr, locpnr;
+    };
+    ps points[3];
+    ElementIndex elnr;
+  };
+
+  class ClipPlanePoint
+  {
+  public:
+    ElementIndex elnr;
+    Point<3> lami;
+    Point<3> p;
+  };
+
+
+  int surfellist;
+  int linelist;
+  int clipplanelist_scal;
+  int clipplanelist_vec;
+  int isolinelist;
+  int clipplane_isolinelist;
+  int surface_vector_list;
+  // int cone_list;
+  int isosurface_list;
+
+  int pointcurvelist;
+
+  bool draw_fieldlines;
+  bool drawpointcurves;
+  bool draw_isosurface;
+  int num_fieldlines;
+  bool fieldlines_randomstart;
+  int fieldlineslist;
+  int num_fieldlineslists;
+  int fieldlines_startarea;
+  Array<double> fieldlines_startarea_parameter;
+  int fieldlines_startface;
+  string fieldlines_filename;
+  double fieldlines_reltolerance;
+  int fieldlines_rktype;
+  double fieldlines_rellength;
+  double fieldlines_relthickness;
+  int fieldlines_vecfunction;
+  bool fieldlines_fixedphase;
+  float fieldlines_phase;
+  int fieldlines_maxpoints;
+
+
+  int surfeltimestamp, clipplanetimestamp, solutiontimestamp;
+  int surfellinetimestamp;
+  int fieldlinestimestamp, surface_vector_timestamp;
+  int pointcurve_timestamp;
+  int isosurface_timestamp;
+  int subdivision_timestamp;
+  int timetimestamp;
+  double minval, maxval;
+
+  NgLock *lock;
+
+
+#ifdef PARALLELGL
+  Array<int> par_linelists;
+  Array<int> par_surfellists;
+#endif
+
+
+public:
+
+  enum EvalFunc { 
+    FUNC_ABS = 1, 
+    FUNC_ABS_TENSOR = 2,
+    FUNC_MISES = 3, 
+    FUNC_MAIN = 4
+  };
+  int 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:
+    SolData ();
+    ~SolData ();
+    
+    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;    // 0..no, 1..1D texture (standard), 2..2D-texture (complex)
+  int clipsolution;  // 0..no, 1..scal, 2..vec
+  int scalfunction, scalcomp, vecfunction;
+  int gridsize;
+  double xoffset, yoffset;
+
+  int autoscale, logscale;
+  double mminval, mmaxval;
+  int numisolines;
+  int subdivisions;
+
+  bool showclipsolution;
+  bool showsurfacesolution;
+  bool lineartexture;
+  int numtexturecols;
+
+  int multidimcomponent;
+
+  // bool fieldlineplot;
+  double time;
+
+  int deform;
+  double scaledeform;
+  bool imag_part;
+
+private:
+  void BuildFieldLinesFromFile(Array<Point3d> & startpoints);
+  void BuildFieldLinesFromFace(Array<Point3d> & startpoints);
+  void BuildFieldLinesFromBox(Array<Point3d> & startpoints);
+  void BuildFieldLinesFromLine(Array<Point3d> & startpoints);
+
+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);
+
+
+  static void RealVec3d (const double * values, Vec3d & v, 
+			 bool iscomplex, bool imag);
+  static void RealVec3d (const double * values, Vec3d & v, 
+			 bool iscomplex, double phaser, double phasei);
+
+
+  void SetSubdivision (int sd)
+  {
+    subdivisions = sd;
+    subdivision_timestamp = solutiontimestamp = NextTimeStamp();
+  }
+
+  void GetMinMax (int funcnr, int comp, double & minv, double & maxv) const;
+
+private:
+  void GetClippingPlaneTrigs (Array<ClipPlaneTrig> & trigs, Array<ClipPlanePoint> & pts);
+  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, 
+  bool GetValue (const SolData * data, ElementIndex elnr, 
+		   double lam1, double lam2, double lam3,
+		   int comp, double & val) const;
+
+  bool GetValue (const SolData * data, ElementIndex elnr,
+		 const double xref[], const double x[], const double dxdxref[], 
+		 int comp, double & val) const;
+
+  bool GetValueComplex (const SolData * data, ElementIndex elnr, 
+			double lam1, double lam2, double lam3,
+			int comp, complex<double> & val) const;
+
+  bool GetValues (const SolData * data, ElementIndex elnr, 
+		  double lam1, double lam2, double lam3,
+		  double * values) const;
+
+  bool GetValues (const SolData * data, ElementIndex elnr, 
+		  const double xref[], const double x[], const double dxdxref[], 
+		  double * values) const;
+
+  bool GetMultiValues (const SolData * data, ElementIndex elnr, int npt,
+		       const double * xref, int sxref,
+		       const double * x, int sx,
+		       const double * dxdxref, int sdxdxref,
+		       double * val, int sval) const;
+
+
+  bool GetSurfValue (const SolData * data, SurfaceElementIndex elnr,
+		     double lam1, double lam2, 
+		     int comp, double & val) const;
+
+  bool GetSurfValue (const SolData * data, SurfaceElementIndex elnr,
+		     const double xref[], const double x[], const double dxdxref[], 
+		     int comp, double & val) const;
+
+  
+  bool GetSurfValueComplex (const SolData * data, SurfaceElementIndex elnr,
+			    double lam1, double lam2, 
+			    int comp, complex<double> & val) const;
+
+  bool GetSurfValues (const SolData * data, SurfaceElementIndex elnr,
+		      double lam1, double lam2, 
+		      double * values) const;
+
+  bool GetSurfValues (const SolData * data, SurfaceElementIndex elnr,
+		      const double xref[], const double x[], const double dxdxref[], 
+		      double * values) const;
+
+  bool GetMultiSurfValues (const SolData * data, SurfaceElementIndex elnr, int npt,
+                           const double * xref, int sxref,
+                           const double * x, int sx,
+                           const double * dxdxref, int sdxdxref,
+                           double * val, int sval) const;
+  
+  double ExtractValue (const SolData * data, int comp, double * values) const;
+  complex<double> ExtractValueComplex (const SolData * data, int comp, double * values) const;
+
+
+  Vec<3> GetDeformation (ElementIndex elnr, const Point<3> & p) const;
+  Vec<3> GetSurfDeformation (SurfaceElementIndex selnr, double lam1, double lam2) const;
+
+  void GetPointDeformation (int pnum, Point<3> & p, SurfaceElementIndex elnr = -1) const;
+
+public:
+  /// draw elements (build lists)
+  void DrawSurfaceElements ();
+  void DrawSurfaceElementLines ();
+  void DrawSurfaceVectors ();
+  void DrawTrigSurfaceVectors(const Array< Point<3> > & lp, const Point<3> & pmin, const Point<3> & pmax,
+			      const int sei, const SolData * vsol);
+  void DrawIsoSurface(const SolData * sol, const SolData * grad, int comp);
+  
+  void DrawIsoLines (const Point<3> & p1, 
+		     const Point<3> & p2, 
+		     const Point<3> & p3,
+		     double val1, double val2, double val3);
+
+  // draw isolines between lines (p1,p2) and (p3,p4)
+  void DrawIsoLines2 (const Point<3> & p1, 
+		      const Point<3> & p2, 
+		      const Point<3> & p3,
+		      const Point<3> & p4,
+		      double val1, double val2, double val3, double val4);
+
+
+  void DrawClipPlaneTrigs (); // const SolData * sol, int comp);
+		  
+  void SetOpenGlColor(double val);
+
+  // 0 .. non, 1 .. scalar, 2 .. complex
+  void SetTextureMode (int texturemode) const;
+
+#ifndef SMALLLIB  
+#ifndef NOTCL
+
+  friend int Ng_Vis_Set (ClientData clientData,
+			 Tcl_Interp * interp,
+			 int argc, tcl_const char *argv[]);
+
+#endif
+#endif
+
+
+#ifdef PARALLELGL
+  void Broadcast ();
+#endif
+
+
+};
+
+
+
+
+class RKStepper
+{
+private:
+  Array<double> c,b;
+  TABLE<double> *a;
+  int steps;
+  int order;
+  
+  double tolerance;
+  
+  Array<Vec3d> K;
+  
+  int stepcount;
+  
+  double h;
+  double startt;
+  double startt_bak;
+  Point3d startval;
+  Point3d startval_bak;
+  
+  bool adaptive;
+  int adrun;
+  Point3d valh;
+  
+  int notrestarted;
+
+public:
+  
+  ~RKStepper();
+    
+  RKStepper(int type = 0);
+
+  void SetTolerance(const double tol){tolerance = tol;}
+        
+  void StartNextValCalc(const Point3d & astartval, const double astartt, const double ah, const bool aadaptive = false);
+
+  bool GetNextData(Point3d & val, double & t, double & ah);
+
+  bool FeedNextF(const Vec3d & f);
+};
+
+
+
+
+
+class FieldLineCalc
+{
+private:
+  const Mesh & mesh;
+  
+  VisualSceneSolution & vss;
+  
+  const VisualSceneSolution::SolData * vsol;
+
+  RKStepper stepper;
+
+  double maxlength;
+
+  int maxpoints;
+  
+  int direction;
+  
+  Point3d pmin, pmax;
+  double rad;
+  double phaser, phasei;
+  
+  double critical_value;
+
+  bool randomized;
+
+  double thickness;
+
+public:
+  FieldLineCalc(const Mesh & amesh, VisualSceneSolution & avss, const VisualSceneSolution::SolData * solution, 
+		const double rel_length, const int amaxpoints = -1, 
+		const double rel_thickness = -1, const double rel_tolerance = -1, const int rk_type = 0, const int adirection = 0);
+
+  void SetPhase(const double real, const double imag) { phaser = real; phasei = imag; }
+  
+  void SetCriticalValue(const double val) { critical_value = val; }
+
+  void Randomized(void) { randomized = true; }
+  void NotRandomized(void) { randomized = false; }
+
+  void Calc(const Point3d & startpoint, Array<Point3d> & points, Array<double> & vals, Array<bool> & drawelems, Array<int> & dirstart);
+  
+  void GenerateFieldLines(Array<Point3d> & potential_startpoints, const int numlines, const int gllist,
+			  const double minval, const double maxval, const int logscale, double phaser, double phasei);
+};
+
+
+
+
+extern VisualSceneSolution vssolution;
+
+
+
+
+#endif
+
-- 
GitLab