Repository: NGSolve/netgen Branch: master Commit: d61126401248 Files: 690 Total size: 10.1 MB Directory structure: gitextract_bskl7z7q/ ├── .clang-format ├── .gitignore ├── .gitlab-ci.yml ├── .gitmodules ├── AUTHORS ├── CMakeLists.txt ├── CONTRIBUTING.md ├── ChangeLog ├── INSTALL ├── LICENSE ├── NEWS ├── README.md ├── TODO ├── cmake/ │ ├── NetgenConfig.cmake.in │ ├── SuperBuild.cmake │ ├── check_submodules.cmake │ ├── cmake_modules/ │ │ ├── FindFFMPEG.cmake │ │ └── FindMETIS.cmake │ ├── cmake_uninstall.cmake.in │ ├── external_projects/ │ │ ├── catch.cmake │ │ ├── cgns.cmake │ │ ├── metis.cmake │ │ ├── spdlog.cmake │ │ ├── tcltk.cmake │ │ └── zlib.cmake │ ├── generate_version_file.cmake │ ├── mic.cmake │ └── netgen_fixup.cmake ├── depcomp ├── doc/ │ ├── CMakeLists.txt │ ├── element_types.tex │ └── ng4.tex ├── external_dependencies/ │ └── .gitignore ├── libsrc/ │ ├── CMakeLists.txt │ ├── core/ │ │ ├── .clang-tidy │ │ ├── CMakeLists.txt │ │ ├── _get_glibcxx_use_cxx11_abi.cpp │ │ ├── _get_gxx_abi.cpp │ │ ├── archive.cpp │ │ ├── archive.hpp │ │ ├── array.hpp │ │ ├── autodiff.hpp │ │ ├── autodiffdiff.hpp │ │ ├── bitarray.cpp │ │ ├── bitarray.hpp │ │ ├── concurrentqueue.h │ │ ├── exception.cpp │ │ ├── exception.hpp │ │ ├── flags.cpp │ │ ├── flags.hpp │ │ ├── generate_mpi_sources.py │ │ ├── hashtable.hpp │ │ ├── localheap.cpp │ │ ├── localheap.hpp │ │ ├── logging.cpp │ │ ├── logging.hpp │ │ ├── memtracer.hpp │ │ ├── mpi4py_pycapi.h │ │ ├── mpi_wrapper.hpp │ │ ├── ng_mpi.cpp │ │ ├── ng_mpi.hpp │ │ ├── ng_mpi_generated_declarations.hpp │ │ ├── ng_mpi_generated_dummy_init.hpp │ │ ├── ng_mpi_generated_init.hpp │ │ ├── ng_mpi_native.hpp │ │ ├── ng_mpi_wrapper.cpp │ │ ├── ngcore.hpp │ │ ├── ngcore_api.hpp │ │ ├── ngstream.hpp │ │ ├── paje_trace.cpp │ │ ├── paje_trace.hpp │ │ ├── profiler.cpp │ │ ├── profiler.hpp │ │ ├── python_ngcore.cpp │ │ ├── python_ngcore.hpp │ │ ├── python_ngcore_export.cpp │ │ ├── ranges.hpp │ │ ├── register_archive.hpp │ │ ├── signal.hpp │ │ ├── simd.hpp │ │ ├── simd_arm64.hpp │ │ ├── simd_avx.hpp │ │ ├── simd_avx512.hpp │ │ ├── simd_generic.hpp │ │ ├── simd_math.hpp │ │ ├── simd_sse.hpp │ │ ├── statushandler.cpp │ │ ├── statushandler.hpp │ │ ├── symboltable.hpp │ │ ├── table.cpp │ │ ├── table.hpp │ │ ├── taskmanager.cpp │ │ ├── taskmanager.hpp │ │ ├── type_traits.hpp │ │ ├── utils.cpp │ │ ├── utils.hpp │ │ ├── version.cpp │ │ ├── version.hpp │ │ └── xbool.hpp │ ├── csg/ │ │ ├── CMakeLists.txt │ │ ├── algprim.cpp │ │ ├── algprim.hpp │ │ ├── brick.cpp │ │ ├── brick.hpp │ │ ├── bspline2d.cpp │ │ ├── csg.hpp │ │ ├── csgeom.cpp │ │ ├── csgeom.hpp │ │ ├── csgparser.cpp │ │ ├── csgparser.hpp │ │ ├── csgpkg.cpp │ │ ├── curve2d.cpp │ │ ├── curve2d.hpp │ │ ├── edgeflw.cpp │ │ ├── edgeflw.hpp │ │ ├── explicitcurve2d.cpp │ │ ├── explicitcurve2d.hpp │ │ ├── extrusion.cpp │ │ ├── extrusion.hpp │ │ ├── gencyl.cpp │ │ ├── gencyl.hpp │ │ ├── genmesh.cpp │ │ ├── geoml.hpp │ │ ├── identify.cpp │ │ ├── identify.hpp │ │ ├── manifold.cpp │ │ ├── manifold.hpp │ │ ├── meshsurf.cpp │ │ ├── meshsurf.hpp │ │ ├── polyhedra.cpp │ │ ├── polyhedra.hpp │ │ ├── python_csg.cpp │ │ ├── revolution.cpp │ │ ├── revolution.hpp │ │ ├── singularref.cpp │ │ ├── singularref.hpp │ │ ├── solid.cpp │ │ ├── solid.hpp │ │ ├── specpoin.cpp │ │ ├── specpoin.hpp │ │ ├── spline3d.cpp │ │ ├── spline3d.hpp │ │ ├── splinesurface.cpp │ │ ├── splinesurface.hpp │ │ ├── surface.cpp │ │ ├── surface.hpp │ │ ├── triapprox.cpp │ │ ├── triapprox.hpp │ │ ├── vscsg.cpp │ │ ├── vscsg.hpp │ │ └── zrefine.cpp │ ├── general/ │ │ ├── CMakeLists.txt │ │ ├── autodiff.hpp │ │ ├── autoptr.hpp │ │ ├── dynamicmem.cpp │ │ ├── dynamicmem.hpp │ │ ├── gzstream.cpp │ │ ├── gzstream.h │ │ ├── hashtabl.cpp │ │ ├── hashtabl.hpp │ │ ├── myadt.hpp │ │ ├── mystring.cpp │ │ ├── mystring.hpp │ │ ├── netgenout.hpp │ │ ├── ngarray.hpp │ │ ├── ngbitarray.cpp │ │ ├── ngbitarray.hpp │ │ ├── ngpython.hpp │ │ ├── optmem.cpp │ │ ├── optmem.hpp │ │ ├── parthreads.cpp │ │ ├── parthreads.hpp │ │ ├── seti.cpp │ │ ├── seti.hpp │ │ ├── sort.cpp │ │ ├── sort.hpp │ │ ├── spbita2d.cpp │ │ ├── spbita2d.hpp │ │ ├── stack.hpp │ │ ├── table.cpp │ │ ├── table.hpp │ │ └── template.hpp │ ├── geom2d/ │ │ ├── CMakeLists.txt │ │ ├── csg2d.cpp │ │ ├── csg2d.hpp │ │ ├── genmesh2d.cpp │ │ ├── geom2dpkg.cpp │ │ ├── geometry2d.cpp │ │ ├── geometry2d.hpp │ │ ├── python_geom2d.cpp │ │ ├── spline2d.hpp │ │ ├── vsgeom2d.cpp │ │ └── vsgeom2d.hpp │ ├── gprim/ │ │ ├── CMakeLists.txt │ │ ├── adtree.cpp │ │ ├── adtree.hpp │ │ ├── geom2d.cpp │ │ ├── geom2d.hpp │ │ ├── geom3d.cpp │ │ ├── geom3d.hpp │ │ ├── geomfuncs.cpp │ │ ├── geomfuncs.hpp │ │ ├── geomobjects.hpp │ │ ├── geomops.hpp │ │ ├── geomtest3d.cpp │ │ ├── geomtest3d.hpp │ │ ├── gprim.hpp │ │ ├── spline.cpp │ │ ├── spline.hpp │ │ ├── splinegeometry.cpp │ │ ├── splinegeometry.hpp │ │ ├── transform3d.cpp │ │ └── transform3d.hpp │ ├── include/ │ │ ├── CMakeLists.txt │ │ ├── acisgeom.hpp │ │ ├── csg.hpp │ │ ├── geometry2d.hpp │ │ ├── gprim.hpp │ │ ├── incopengl.hpp │ │ ├── inctcl.hpp │ │ ├── incvis.hpp │ │ ├── linalg.hpp │ │ ├── meshing.hpp │ │ ├── myadt.hpp │ │ ├── mydefs.hpp │ │ ├── mystdlib.h │ │ ├── nginterface.h │ │ ├── nginterface_v2.hpp │ │ ├── nginterface_v2_impl.hpp │ │ ├── ngsimd.hpp │ │ ├── occgeom.hpp │ │ ├── opti.hpp │ │ ├── parallel.hpp │ │ ├── stlgeom.hpp │ │ └── visual.hpp │ ├── interface/ │ │ ├── CMakeLists.txt │ │ ├── nginterface.cpp │ │ ├── nginterface_v2.cpp │ │ ├── read_fnf_mesh.cpp │ │ ├── readtetmesh.cpp │ │ ├── readuser.cpp │ │ ├── rw_cgns.cpp │ │ ├── rw_medit.cpp │ │ ├── rw_medit.hpp │ │ ├── writeOpenFOAM15x.cpp │ │ ├── writeabaqus.cpp │ │ ├── writediffpack.cpp │ │ ├── writedolfin.cpp │ │ ├── writeelmer.cpp │ │ ├── writefeap.cpp │ │ ├── writefluent.cpp │ │ ├── writegmsh.cpp │ │ ├── writegmsh2.cpp │ │ ├── writejcm.cpp │ │ ├── writepermas.cpp │ │ ├── writetecplot.cpp │ │ ├── writetet.cpp │ │ ├── writetochnog.cpp │ │ ├── writeuser.cpp │ │ ├── writeuser.hpp │ │ └── wuchemnitz.cpp │ ├── linalg/ │ │ ├── CMakeLists.txt │ │ ├── bfgs.cpp │ │ ├── densemat.cpp │ │ ├── densemat.hpp │ │ ├── linalg.hpp │ │ ├── linopt.cpp │ │ ├── linsearch.cpp │ │ ├── opti.hpp │ │ ├── polynomial.cpp │ │ ├── polynomial.hpp │ │ └── vector.hpp │ ├── meshing/ │ │ ├── CMakeLists.txt │ │ ├── adfront2.cpp │ │ ├── adfront2.hpp │ │ ├── adfront3.cpp │ │ ├── adfront3.hpp │ │ ├── basegeom.cpp │ │ ├── basegeom.hpp │ │ ├── bcfunctions.cpp │ │ ├── bcfunctions.hpp │ │ ├── bisect.cpp │ │ ├── bisect.hpp │ │ ├── boundarylayer.cpp │ │ ├── boundarylayer.hpp │ │ ├── boundarylayer2d.cpp │ │ ├── boundarylayer_interpolate.cpp │ │ ├── boundarylayer_limiter.hpp │ │ ├── classifyhpel.hpp │ │ ├── clusters.cpp │ │ ├── clusters.hpp │ │ ├── curvedelems.cpp │ │ ├── curvedelems.hpp │ │ ├── debugging.cpp │ │ ├── debugging.hpp │ │ ├── delaunay.cpp │ │ ├── delaunay2d.cpp │ │ ├── delaunay2d.hpp │ │ ├── fieldlines.cpp │ │ ├── fieldlines.hpp │ │ ├── findip.hpp │ │ ├── findip2.hpp │ │ ├── geomsearch.cpp │ │ ├── geomsearch.hpp │ │ ├── global.cpp │ │ ├── global.hpp │ │ ├── hpref_hex.hpp │ │ ├── hpref_prism.hpp │ │ ├── hpref_pyramid.hpp │ │ ├── hpref_quad.hpp │ │ ├── hpref_segm.hpp │ │ ├── hpref_tet.hpp │ │ ├── hpref_trig.hpp │ │ ├── hprefinement.cpp │ │ ├── hprefinement.hpp │ │ ├── improve2.cpp │ │ ├── improve2.hpp │ │ ├── improve2gen.cpp │ │ ├── improve3.cpp │ │ ├── improve3.hpp │ │ ├── localh.cpp │ │ ├── localh.hpp │ │ ├── meshclass.cpp │ │ ├── meshclass.hpp │ │ ├── meshfunc.cpp │ │ ├── meshfunc.hpp │ │ ├── meshfunc2d.cpp │ │ ├── meshing.hpp │ │ ├── meshing2.cpp │ │ ├── meshing2.hpp │ │ ├── meshing3.cpp │ │ ├── meshing3.hpp │ │ ├── meshtool.cpp │ │ ├── meshtool.hpp │ │ ├── meshtype.cpp │ │ ├── meshtype.hpp │ │ ├── msghandler.cpp │ │ ├── msghandler.hpp │ │ ├── netrule2.cpp │ │ ├── netrule3.cpp │ │ ├── parallelmesh.cpp │ │ ├── paralleltop.cpp │ │ ├── paralleltop.hpp │ │ ├── parser2.cpp │ │ ├── parser3.cpp │ │ ├── python_mesh.cpp │ │ ├── python_mesh.hpp │ │ ├── refine.cpp │ │ ├── ruler2.cpp │ │ ├── ruler2.hpp │ │ ├── ruler3.cpp │ │ ├── ruler3.hpp │ │ ├── secondorder.cpp │ │ ├── smoothing2.5.cpp │ │ ├── smoothing2.cpp │ │ ├── smoothing3.cpp │ │ ├── soldata.hpp │ │ ├── specials.cpp │ │ ├── specials.hpp │ │ ├── surfacegeom.cpp │ │ ├── surfacegeom.hpp │ │ ├── topology.cpp │ │ ├── topology.hpp │ │ ├── validate.cpp │ │ ├── validate.hpp │ │ ├── visual_interface.cpp │ │ └── visual_interface.hpp │ ├── occ/ │ │ ├── CMakeLists.txt │ │ ├── Partition_Inter2d.cxx │ │ ├── Partition_Inter2d.hxx │ │ ├── Partition_Inter2d.ixx │ │ ├── Partition_Inter2d.jxx │ │ ├── Partition_Inter3d.cxx │ │ ├── Partition_Inter3d.hxx │ │ ├── Partition_Inter3d.ixx │ │ ├── Partition_Inter3d.jxx │ │ ├── Partition_Loop.cxx │ │ ├── Partition_Loop.hxx │ │ ├── Partition_Loop.ixx │ │ ├── Partition_Loop.jxx │ │ ├── Partition_Loop2d.cxx │ │ ├── Partition_Loop2d.hxx │ │ ├── Partition_Loop2d.ixx │ │ ├── Partition_Loop2d.jxx │ │ ├── Partition_Loop3d.cxx │ │ ├── Partition_Loop3d.hxx │ │ ├── Partition_Loop3d.ixx │ │ ├── Partition_Loop3d.jxx │ │ ├── Partition_Spliter.cxx │ │ ├── Partition_Spliter.hxx │ │ ├── Partition_Spliter.ixx │ │ ├── Partition_Spliter.jxx │ │ ├── cross_section.cpp │ │ ├── occ_edge.cpp │ │ ├── occ_edge.hpp │ │ ├── occ_face.cpp │ │ ├── occ_face.hpp │ │ ├── occ_solid.hpp │ │ ├── occ_utils.cpp │ │ ├── occ_utils.hpp │ │ ├── occ_vertex.cpp │ │ ├── occ_vertex.hpp │ │ ├── occconstruction.cpp │ │ ├── occgenmesh.cpp │ │ ├── occgeom.cpp │ │ ├── occgeom.hpp │ │ ├── occmeshsurf.cpp │ │ ├── occmeshsurf.hpp │ │ ├── occpkg.cpp │ │ ├── python_occ.cpp │ │ ├── python_occ_basic.cpp │ │ ├── python_occ_shapes.cpp │ │ ├── utilities.h │ │ ├── vsocc.cpp │ │ └── vsocc.hpp │ ├── stlgeom/ │ │ ├── CMakeLists.txt │ │ ├── meshstlsurface.cpp │ │ ├── meshstlsurface.hpp │ │ ├── python_stl.cpp │ │ ├── stlgeom.cpp │ │ ├── stlgeom.hpp │ │ ├── stlgeomchart.cpp │ │ ├── stlgeommesh.cpp │ │ ├── stlline.cpp │ │ ├── stlline.hpp │ │ ├── stlpkg.cpp │ │ ├── stltool.cpp │ │ ├── stltool.hpp │ │ ├── stltopology.cpp │ │ ├── stltopology.hpp │ │ ├── vsstl.cpp │ │ └── vsstl.hpp │ └── visualization/ │ ├── CMakeLists.txt │ ├── importsolution.cpp │ ├── meshdoc.cpp │ ├── meshdoc.hpp │ ├── mvdraw.cpp │ ├── mvdraw.hpp │ ├── vispar.hpp │ ├── visual.hpp │ ├── visual_api.hpp │ ├── visualpkg.cpp │ ├── vsfieldlines.cpp │ ├── vsmesh.cpp │ ├── vssolution.cpp │ └── vssolution.hpp ├── mkinstalldirs ├── netgen.icns ├── ng/ │ ├── CMakeLists.txt │ ├── Togl2.1/ │ │ ├── CMakeLists.txt │ │ ├── LICENSE │ │ ├── Makefile.in │ │ ├── README.stubs │ │ ├── Togl.py │ │ ├── Xmu/ │ │ │ ├── CmapAlloc.c │ │ │ ├── CrCmap.c │ │ │ ├── DelCmap.c │ │ │ ├── LookupCmap.c │ │ │ ├── README.togl │ │ │ ├── StdCmap.c │ │ │ └── StdCmap.h │ │ ├── aclocal.m4 │ │ ├── ben.rgb │ │ ├── configure │ │ ├── configure.in │ │ ├── doc/ │ │ │ ├── README.txt │ │ │ ├── capi.html │ │ │ ├── download.html │ │ │ ├── faq.html │ │ │ ├── header.js │ │ │ ├── index.html │ │ │ ├── stereo.html │ │ │ ├── tclapi.html │ │ │ ├── upgrading.html │ │ │ └── using.html │ │ ├── double.c │ │ ├── double.tcl │ │ ├── gears.c │ │ ├── gears.tcl │ │ ├── gl/ │ │ │ ├── glext.h │ │ │ ├── glxext.h │ │ │ └── wglext.h │ │ ├── image.c │ │ ├── image.h │ │ ├── index.c │ │ ├── index.tcl │ │ ├── multisample.tcl │ │ ├── overlay.c │ │ ├── overlay.tcl │ │ ├── pbuffer.c │ │ ├── pbuffer.tcl │ │ ├── pkgIndex.tcl.in │ │ ├── stereo.c │ │ ├── stereo.tcl │ │ ├── tclconfig/ │ │ │ ├── install-sh │ │ │ └── tcl.m4 │ │ ├── texture.c │ │ ├── texture.tcl │ │ ├── togl.c │ │ ├── togl.decls │ │ ├── togl.h │ │ ├── toglAGL.c │ │ ├── toglDecls.h │ │ ├── toglFont.c │ │ ├── toglGLX.c │ │ ├── toglNSOpenGL.c │ │ ├── toglProcAddr.c │ │ ├── toglStubInit.c │ │ ├── toglStubLib.c │ │ ├── toglWGL.c │ │ ├── togl_ws.h.in │ │ ├── toglpy.h │ │ └── tree2.rgba │ ├── acisgeom.tcl │ ├── csgeom.tcl │ ├── demoview.cpp │ ├── demoview.hpp │ ├── dialog.tcl │ ├── drawing.tcl │ ├── drawing_togl17.tcl │ ├── encoding.hpp │ ├── fonts.hpp │ ├── gui.cpp │ ├── menustat.tcl │ ├── netgen.ocf │ ├── netgenpy.cpp │ ├── ng.tcl │ ├── ng_acis.hpp │ ├── ngappinit.cpp │ ├── ngguipy.cpp │ ├── nghelp.tcl │ ├── ngicon.tcl │ ├── ngpkg.cpp │ ├── ngshell.tcl │ ├── ngtcl.cpp │ ├── ngtesting.tcl │ ├── ngvisual.tcl │ ├── occgeom.tcl │ ├── onetcl.cpp │ ├── onetcl.py │ ├── parallelfunc.cpp │ ├── parallelfunc.hpp │ ├── parameters.tcl │ ├── sockets.tcl │ ├── stlgeom.tcl │ └── variables.tcl ├── nglib/ │ ├── CMakeLists.txt │ ├── cube.surf │ ├── hinge.stl │ ├── netgen.py │ ├── ng_occ.cpp │ ├── ng_stl.cpp │ ├── ng_vol.cpp │ ├── nglib.cpp │ ├── nglib.h │ ├── nglib_occ.cpp │ ├── nglib_occ.h │ └── parallelfunc.cpp ├── py_tutorials/ │ ├── CMakeLists.txt │ ├── csg2d.py │ ├── csg_first_example.py │ ├── cube.geo │ ├── exportNeutral.py │ ├── merge.py │ ├── mesh.py │ ├── opengl.py │ ├── opengl_thread.py │ ├── opengl_window.py │ ├── python_geometry.py │ └── shaft.geo ├── python/ │ ├── .gitignore │ ├── CMakeLists.txt │ ├── NgOCC.py │ ├── __init__.py │ ├── __main__.py │ ├── config/ │ │ ├── __init__.py │ │ ├── __main__.py │ │ └── config_template.py │ ├── csg.py │ ├── gengeom.py │ ├── gengeom_curve.py │ ├── geom2d.py │ ├── gui.py │ ├── init_geom2d.py │ ├── meshing.py │ ├── occ.py │ ├── pyngcore/ │ │ └── __init__.py │ ├── read_gmsh.py │ ├── read_meshio.py │ ├── stl.py │ ├── version_template.py │ └── webgui.py ├── rules/ │ ├── CMakeLists.txt │ ├── hexrules.rls │ ├── makerlsfile.cpp │ ├── prismrules2.rls │ ├── prisms.rls │ ├── pyramidrules.rls │ ├── pyramidrules2.rls │ ├── quadrules.rls │ ├── tetrules.rls │ └── triarules.rls ├── setup.py ├── tests/ │ ├── CMakeLists.txt │ ├── build_debug.sh │ ├── build_guidelines.sh │ ├── build_mpi.sh │ ├── build_ngsolve.sh │ ├── build_nospdlog.sh │ ├── build_pip.ps1 │ ├── build_pip.sh │ ├── build_pip_mac.sh │ ├── catch/ │ │ ├── CMakeLists.txt │ │ ├── archive.cpp │ │ ├── array.cpp │ │ ├── main.cpp │ │ ├── ranges.cpp │ │ ├── symboltable.cpp │ │ ├── utils.cpp │ │ └── version.cpp │ ├── dockerfile │ ├── dockerfile_mpi │ ├── pytest/ │ │ ├── CMakeLists.txt │ │ ├── compare_results.py │ │ ├── conftest.py │ │ ├── geofiles/ │ │ │ └── plane.stl │ │ ├── meshes.py │ │ ├── test_array.py │ │ ├── test_bitarray.py │ │ ├── test_boundarylayer.py │ │ ├── test_csg.py │ │ ├── test_csg2d.py │ │ ├── test_geom2d.py │ │ ├── test_meshclass.py │ │ ├── test_mpi4py.py │ │ ├── test_nonnative_master │ │ ├── test_occ.py │ │ ├── test_occ_identifications.py │ │ ├── test_pickling.py │ │ ├── test_savemesh.py │ │ ├── test_splinegeo_tensordomainmeshing.py │ │ └── test_tutorials.py │ └── utils.py ├── tutorials/ │ ├── CMakeLists.txt │ ├── boundarycondition.geo │ ├── boxcyl.geo │ ├── circle_on_cube.geo │ ├── cone.geo │ ├── cube.geo │ ├── cubeandring.geo │ ├── cubeandspheres.geo │ ├── cubemcyl.geo │ ├── cubemsphere.geo │ ├── cylinder.geo │ ├── cylsphere.geo │ ├── ellipsoid.geo │ ├── ellipticcone.geo │ ├── ellipticcyl.geo │ ├── extrusion.geo │ ├── fichera.geo │ ├── frame.step │ ├── hinge.stl │ ├── lense.in2d │ ├── lshape3d.geo │ ├── manyholes.geo │ ├── manyholes2.geo │ ├── matrix.geo │ ├── ortho.geo │ ├── part1.stl │ ├── period.geo │ ├── revolution.geo │ ├── screw.step │ ├── sculpture.geo │ ├── shaft.geo │ ├── shell.geo │ ├── sphere.geo │ ├── sphereincube.geo │ ├── square.in2d │ ├── squarecircle.in2d │ ├── squarehole.in2d │ ├── test.dem │ ├── torus.geo │ ├── trafo.geo │ ├── twobricks.geo │ ├── twocubes.geo │ └── twocyl.geo └── windows/ ├── .gitignore ├── CMakeLists.txt ├── netgen.rc.template └── resource.h ================================================ FILE CONTENTS ================================================ ================================================ FILE: .clang-format ================================================ Language: Cpp BasedOnStyle: LLVM AlignAfterOpenBracket: Align AlignConsecutiveAssignments: false AlignConsecutiveDeclarations: false AlignEscapedNewlines: Left AlignOperands: true AlignTrailingComments: true AllowAllParametersOfDeclarationOnNextLine: false AllowShortBlocksOnASingleLine: false AllowShortCaseLabelsOnASingleLine: true AllowShortFunctionsOnASingleLine: InlineOnly AllowShortIfStatementsOnASingleLine: false AllowShortLoopsOnASingleLine: false AlwaysBreakAfterDefinitionReturnType: None AlwaysBreakTemplateDeclarations: Yes BinPackArguments: false BinPackParameters: false BreakBeforeBinaryOperators: NonAssignment BreakBeforeBraces: Custom BraceWrapping: AfterClass: true AfterControlStatement: true AfterEnum: true AfterFunction: true AfterNamespace: true AfterStruct: true AfterUnion: true BeforeCatch: true BeforeElse: true IndentBraces: true BreakBeforeTernaryOperators: true BreakConstructorInitializersBeforeComma: false BreakInheritanceList: AfterColon ColumnLimit: 0 ConstructorInitializerAllOnOneLineOrOnePerLine: true ConstructorInitializerIndentWidth: 2 ContinuationIndentWidth: 2 Cpp11BracedListStyle: true EmptyLineBeforeAccessModifier: Never IndentCaseLabels: false IndentPPDirectives: None IndentWidth: 2 KeepEmptyLinesAtTheStartOfBlocks: false MaxEmptyLinesToKeep: 1 NamespaceIndentation: None PointerAlignment: Left ReflowComments: true SortIncludes: false SpaceAfterCStyleCast: false SpaceAfterLogicalNot: false SpaceBeforeParens: Custom SpaceBeforeParensOptions: AfterControlStatements: true AfterFunctionDefinitionName: true AfterFunctionDeclarationName: true SpacesInAngles: false SpacesInContainerLiterals: false SpacesInCStyleCastParentheses: false SpacesInSquareBrackets: false Standard: Latest TabWidth: 2 UseTab: Never ================================================ FILE: .gitignore ================================================ *.whl dist build *.vol.gz *.vol *.ini __pycache__ *.json *.zip .cache *.patch ================================================ FILE: .gitlab-ci.yml ================================================ stages: - build - test - test_ngsolve - deploy - cleanup push_github: stage: build tags: - linux - docker - bash script: - git remote add github git@github.com:NGSolve/netgen.git || true - git remote update - git checkout --track origin/master - git pull origin master - git push github master --tags only: - master ############################################ # Windows ############################################ .template_windows: &win tags: - windows - pip before_script: - | $ErrorActionPreference = "Stop" # Import MSVC environment from vcvars64.bat into the current PowerShell process $vcvars = '"C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat"' cmd /c "$vcvars && set" | ForEach-Object { if ($_ -match '^(.*?)=(.*)$') { [System.Environment]::SetEnvironmentVariable($matches[1], $matches[2]) Set-Item -Path "env:$($matches[1])" -Value $matches[2] -ErrorAction SilentlyContinue } } $env:CI_DIR = "C:\ci\$env:CI_PIPELINE_ID" $env:CCACHE_BASEDIR = $env:CI_DIR $env:NETGEN_BUILD_DIR = Join-Path $env:CI_DIR "build" $env:INSTALL_DIR = Join-Path $env:CI_DIR "install" $env:SRC_DIR = Join-Path $env:CI_DIR "src" $env:NETGENDIR = Join-Path $env:INSTALL_DIR "bin" $env:PYTHONPATH = Join-Path $env:INSTALL_DIR "lib\site-packages" Write-Output $env:PATH $env:PATH = @( (Join-Path $env:INSTALL_DIR "bin") "C:\python314" "C:\python314\bin" "C:\python314\Scripts" "C:\tools" $env:PATH ) -join ";" Write-Output $env:PATH $env:CCACHE_HARDLINK = "1" $env:CCACHE_NOHASHDIR = "1" & "C:\tools\ccache.exe" -s & "C:\tools\ccache.exe" -M "20G" python.exe --version cmake --version build_win: <<: *win stage: build script: - | New-Item -ItemType Directory -Force -Path $env:SRC_DIR | Out-Null Get-ChildItem -Force | Copy-Item -Destination $env:SRC_DIR -Recurse -Force python.exe -m pip install -U netgen-occt netgen-occt-devel ninja cmake Set-Location $env:SRC_DIR git submodule update --init --recursive if (Test-Path $env:NETGEN_BUILD_DIR) { Remove-Item $env:NETGEN_BUILD_DIR -Recurse -Force } New-Item -ItemType Directory -Force -Path $env:NETGEN_BUILD_DIR | Out-Null Set-Location $env:NETGEN_BUILD_DIR cmake $env:SRC_DIR ` -G Ninja ` -DCMAKE_PREFIX=C:/python314 ` -DPython3_ROOT_DIR=C:/python314 ` -DCMAKE_INSTALL_PREFIX="$($env:INSTALL_DIR)" ` -DCHECK_RANGE=ON ` -DUSE_CGNS=OFF ` -DUSE_OCC=ON ` -DUSE_CCACHE=ON ` -DENABLE_UNIT_TESTS=OFF ` -DCMAKE_BUILD_TYPE=Release cmake --build . --target install --config Release test_win: <<: *win stage: test script: - | pip install pytest-check Set-Location (Join-Path $env:NETGEN_BUILD_DIR "netgen") ctest -C Release -V --output-on-failure Set-Location .. needs: ["build_win"] generate_results: <<: *win stage: test script: - | pip install pytest-check Set-Location "tests\pytest" python test_tutorials.py "new_results.json" needs: ["build_win"] when: manual artifacts: paths: - tests/pytest/new_results.json when: always expire_in: 1 week cleanup_win: <<: *win stage: cleanup script: - | Set-Location $env:CI_PROJECT_DIR if (Test-Path $env:CI_DIR) { Remove-Item $env:CI_DIR -Recurse -Force } when: always allow_failure: true needs: ["test_win"] ############################################ # Ubuntu/Linux ############################################ .template_ubuntu: &ubuntu tags: - linux - bash before_script: - pwd - ls - docker info - export PYTHONPATH=/opt/netgen/`python3 -c "import os.path, sysconfig;print(os.path.relpath(sysconfig.get_path('platlib'), sysconfig.get_path('data')))"` variables: UBUNTU_VERSION: "22.04" build_ubuntu_debug: <<: *ubuntu stage: build script: - docker build -t netgen_${CI_PIPELINE_ID}:${UBUNTU_VERSION} -f tests/dockerfile . - rm -f netgen_${CI_PIPELINE_ID}_$UBUNTU_VERSION.id - >- docker run --cidfile netgen_${CI_PIPELINE_ID}_${UBUNTU_VERSION}.id -e CCACHE_DIR=/ccache -e PYTHONPATH=$PYTHONPATH -v /mnt/ccache:/ccache netgen_${CI_PIPELINE_ID}:${UBUNTU_VERSION} bash /root/src/netgen/tests/build_debug.sh - docker commit `cat netgen_${CI_PIPELINE_ID}_${UBUNTU_VERSION}.id` netgen_${CI_PIPELINE_ID}_installed:${UBUNTU_VERSION} - rm netgen_${CI_PIPELINE_ID}_${UBUNTU_VERSION}.id build_ubuntu_mpi: <<: *ubuntu stage: build script: - docker build -t netgen_mpi_${CI_PIPELINE_ID}:${UBUNTU_VERSION} -f tests/dockerfile_mpi . - rm -f netgen_mpi_${CI_PIPELINE_ID}_$UBUNTU_VERSION.id_mpi - >- docker run>- --cidfile netgen_mpi_${CI_PIPELINE_ID}_${UBUNTU_VERSION}.id>- -e CCACHE_DIR=/ccache -e PYTHONPATH=$PYTHONPATH -e RUN_SLOW_TESTS=${RUN_SLOW_TESTS} -v /mnt/ccache:/ccache netgen_mpi_${CI_PIPELINE_ID}:${UBUNTU_VERSION} bash /root/src/netgen/tests/build_mpi.sh - docker commit `cat netgen_mpi_${CI_PIPELINE_ID}_${UBUNTU_VERSION}.id` netgen_mpi_${CI_PIPELINE_ID}_installed:${UBUNTU_VERSION} - rm netgen_mpi_${CI_PIPELINE_ID}_${UBUNTU_VERSION}.id test_ubuntu_debug: <<: *ubuntu stage: test script: - >- docker run -e PYTHONPATH=$PYTHONPATH netgen_${CI_PIPELINE_ID}_installed:${UBUNTU_VERSION} bash -c 'cd /root/build/netgen && make test_netgen ARGS="-V --output-on-failure"' needs: ["build_ubuntu_debug"] test_ubuntu_mpi: <<: *ubuntu stage: test script: - >- docker run -e RUN_SLOW_TESTS=${RUN_SLOW_TESTS} -e PYTHONPATH=$PYTHONPATH netgen_mpi_${CI_PIPELINE_ID}_installed:${UBUNTU_VERSION} bash -c 'cd /root/build/netgen && make test_netgen ARGS="-V --output-on-failure"' needs: ["build_ubuntu_mpi"] test_build_ngsolve: <<: *ubuntu allow_failure: true stage: test_ngsolve script: - >- docker run -e NETGENDIR=/opt/netgen/bin -e PYTHONPATH=$PYTHONPATH -e MKLROOT=/opt/intel/mkl -v /opt/intel:/opt/intel -e CCACHE_DIR=/ccache -v /mnt/ccache:/ccache netgen_${CI_PIPELINE_ID}_installed:${UBUNTU_VERSION} bash -c 'cd /root/src/netgen/tests/ && ./build_ngsolve.sh' cleanup_ubuntu: stage: cleanup tags: - linux - bash script: # remove intermediate and old docker images and containers - docker rm -f `docker ps --no-trunc -aq` - docker images --no-trunc -aqf "dangling=true" | xargs docker rmi -f || true - docker rmi -f netgen_${CI_PIPELINE_ID}:${UBUNTU_VERSION} || true - docker rmi -f netgen_${CI_PIPELINE_ID}_installed:${UBUNTU_VERSION} || true - docker rmi -f netgen_mpi_${CI_PIPELINE_ID}:${UBUNTU_VERSION} || true - docker rmi -f netgen_mpi_${CI_PIPELINE_ID}_installed:${UBUNTU_VERSION} || true when: always allow_failure: true ############################################ # MacOSX ############################################ .template_mac: &mac tags: - macosx - m1 before_script: - export PATH=/Library/Frameworks/Python.framework/Versions/3.14/bin:$PATH - export ROOT_DIR=/tmp/$CI_PIPELINE_ID - export SRC_DIR=$ROOT_DIR/src - export BUILD_DIR=$ROOT_DIR/build - export CMAKE_INSTALL_PREFIX=/tmp/$CI_PIPELINE_ID/install/Netgen.app - export PYTHONPATH=$CMAKE_INSTALL_PREFIX/Contents/Resources/`python3 -c "import os.path, sysconfig;print(os.path.relpath(sysconfig.get_path('platlib'), sysconfig.get_path('data')))"`:. - export PATH=$CMAKE_INSTALL_PREFIX/Contents/MacOS:$PATH build_mac: <<: *mac stage: build script: - python3 -m pip install -U netgen-occt netgen-occt-devel cmake pytest-check - git submodule update --init --recursive - rm -rf $BUILD_DIR - mkdir -p $BUILD_DIR - rm -rf $SRC_DIR - mkdir -p $SRC_DIR - cp -a . $SRC_DIR/ - cd $BUILD_DIR - >- cmake $SRC_DIR -DCMAKE_INSTALL_PREFIX=$CMAKE_INSTALL_PREFIX -DCMAKE_BUILD_TYPE=Release -DCHECK_RANGE=ON -DUSE_NATIVE_ARCH=ON -DUSE_CCACHE=ON -DENABLE_UNIT_TESTS=ON -DCMAKE_OSX_DEPLOYMENT_TARGET=10.15 -DCMAKE_OSX_SYSROOT=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk -DUSE_CGNS=OFF -DPython3_ROOT_DIR=/Library/Frameworks/Python.framework/Versions/3.14 -DUSE_OCC=ON - make -j5 install test_mac: <<: *mac stage: test script: - cd $BUILD_DIR/netgen - ctest . -V --output-on-failure needs: ["build_mac"] cleanup_mac: <<: *mac stage: cleanup script: - rm -rf $ROOT_DIR when: always allow_failure: true needs: ["test_mac"] pip_linux: image: quay.io/pypa/manylinux_2_28_x86_64 stage: build tags: - pip - linux - docker script: - ./tests/build_pip.sh when: manual pip_windows: stage: build tags: - pip - windows script: - .\tests\build_pip.ps1 C:\Python314 - .\tests\build_pip.ps1 C:\Python313 - .\tests\build_pip.ps1 C:\Python312 - .\tests\build_pip.ps1 C:\Python311 - .\tests\build_pip.ps1 C:\Python310 when: manual pip_macos: stage: build tags: - pip - macosx - m1 script: - ./tests/build_pip_mac.sh 3.14 - ./tests/build_pip_mac.sh 3.13 - ./tests/build_pip_mac.sh 3.12 - ./tests/build_pip_mac.sh 3.11 - ./tests/build_pip_mac.sh 3.10 when: manual ================================================ FILE: .gitmodules ================================================ [submodule "external_dependencies/pybind11"] path = external_dependencies/pybind11 url = https://github.com/ngsolve/pybind11.git ================================================ FILE: AUTHORS ================================================ Joachim Schoeberl ================================================ FILE: CMakeLists.txt ================================================ if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING INTERNAL) endif(NOT CMAKE_BUILD_TYPE) set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreadedDLL") cmake_minimum_required(VERSION 3.16) cmake_policy(VERSION 3.16) if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.24.0") cmake_policy(SET CMP0135 NEW) endif() include (CMakeDependentOption) option( USE_NATIVE_ARCH "build for native cpu architecture" ON) option( USE_GUI "build with GUI" ON ) option( USE_PYTHON "build with python interface" ON ) cmake_dependent_option( PREFER_SYSTEM_PYBIND11 "Use system wide PyBind11" OFF "USE_PYTHON" OFF) option( USE_MPI "enable mpi parallelization" OFF ) option( USE_MPI_WRAPPER "enable mpi wrapper (run-time dispatch of MPI library calls)" OFF ) option( USE_OCC "build with OpenCascade geometry kernel interface" ON) option( USE_STLGEOM "build with STL geometry support" ON) option( USE_CSG "build with CSG kernel" ON) option( USE_INTERFACE "build nginterface" ON) option( USE_GEOM2D "build 2d geometry kernels" ON) option( USE_JPEG "enable snapshots using library libjpeg" OFF ) option( USE_MPEG "enable video recording with FFmpeg, uses libavcodec" OFF ) option( USE_CGNS "enable CGNS file read/write support" OFF ) option( USE_NUMA "compile with NUMA-aware code") option( INTEL_MIC "cross compile for intel xeon phi") option( INSTALL_PROFILES "install environment variable settings to /etc/profile.d" OFF ) option( USE_CCACHE "use ccache") option( USE_INTERNAL_TCL "Compile tcl files into the code and don't install them" ON) option( ENABLE_UNIT_TESTS "Enable Catch unit tests") option( ENABLE_CPP_CORE_GUIDELINES_CHECK "Enable cpp core guideline checks on ngcore" OFF) option( DEBUG_LOG "Enable more debug output (may increase computation time) - only works with USE_SPDLOG=ON" OFF) option( CHECK_RANGE "Check array range access, automatically enabled if built in debug mode" OFF) option( BUILD_STUB_FILES "Build stub files for better autocompletion" ON) option( BUILD_FOR_CONDA "Link python libraries only to executables" OFF) option( USE_SUPERBUILD "build dependencies automatically" ON) option( TRACE_MEMORY "Enable memory tracing" OFF) set(NG_COMPILE_FLAGS "" CACHE STRING "Additional compile flags") set(NGLIB_LIBRARY_TYPE SHARED CACHE STRING "nglib library type") set(NGCORE_LIBRARY_TYPE SHARED CACHE STRING "ngcore library type") set(NGGUI_LIBRARY_TYPE SHARED CACHE STRING "nggui library type") set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}" "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake_modules") if(APPLE) set(INSTALL_DIR_DEFAULT /Applications/Netgen.app) else(APPLE) if(WIN32) set(INSTALL_DIR_DEFAULT "C:/netgen") else(WIN32) set(INSTALL_DIR_DEFAULT /opt/netgen) endif(WIN32) endif(APPLE) if(INSTALL_DIR) message(WARNING "INSTALL_DIR is deprecated, use CMAKE_INSTALL_PREFIX instead") set(INSTALL_DIR_DEFAULT ${INSTALL_DIR}) endif(INSTALL_DIR) if(UNIX AND USE_SUPERBUILD) message("Checking for write permissions in install directory...") execute_process(COMMAND mkdir -p ${CMAKE_INSTALL_PREFIX}) execute_process(COMMAND test -w ${CMAKE_INSTALL_PREFIX} RESULT_VARIABLE res) if(res) message(WARNING "No write access at install directory, please set correct permissions") endif() endif(UNIX AND USE_SUPERBUILD) if (USE_SUPERBUILD) project (SUPERBUILD) else() project(Netgen) endif() if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) set(CMAKE_INSTALL_PREFIX "${INSTALL_DIR_DEFAULT}" CACHE PATH "Install directory" FORCE) endif() set(NG_INSTALL_SUFFIX netgen CACHE STRING "Suffix appended to install directories (project name)") if(USE_PYTHON) if(${CMAKE_VERSION} VERSION_GREATER_EQUAL 3.18) find_package(Python3 REQUIRED COMPONENTS Development.Module) if(NOT EMSCRIPTEN) find_package(Python3 COMPONENTS Interpreter Development.Embed) endif() else() find_package(Python3 REQUIRED COMPONENTS Interpreter Development) endif() if(NOT CMAKE_CROSSCOMPILING) find_package(Python3 REQUIRED COMPONENTS Interpreter) execute_process(COMMAND ${Python3_EXECUTABLE} -c "import os.path, sysconfig;print(os.path.relpath(sysconfig.get_path('platlib'), sysconfig.get_path('data')))" OUTPUT_VARIABLE PYTHON_PACKAGES_INSTALL_DIR OUTPUT_STRIP_TRAILING_WHITESPACE) file(TO_CMAKE_PATH ${PYTHON_PACKAGES_INSTALL_DIR} PYTHON_PACKAGES_INSTALL_DIR) endif(NOT CMAKE_CROSSCOMPILING) endif(USE_PYTHON) if(APPLE AND NOT EMSCRIPTEN) set(NG_INSTALL_DIR_BIN_DEFAULT Contents/MacOS) set(NG_INSTALL_DIR_LIB_DEFAULT Contents/MacOS) set(NG_INSTALL_DIR_CMAKE_DEFAULT Contents/Resources/CMake) set(NG_INSTALL_DIR_PYTHON_DEFAULT Contents/Resources/${PYTHON_PACKAGES_INSTALL_DIR}) set(NG_INSTALL_DIR_RES_DEFAULT Contents/Resources/share) set(NG_INSTALL_DIR_INCLUDE_DEFAULT Contents/Resources/include) set(NG_RPATH_TOKEN "@loader_path") else(APPLE AND NOT EMSCRIPTEN) set(NG_INSTALL_DIR_BIN_DEFAULT bin) set(NG_INSTALL_DIR_LIB_DEFAULT lib) if(WIN32) set(NG_INSTALL_DIR_CMAKE_DEFAULT cmake) else(WIN32) set(NG_INSTALL_DIR_CMAKE_DEFAULT lib/cmake/${NG_INSTALL_SUFFIX}) endif(WIN32) set(NG_INSTALL_DIR_PYTHON_DEFAULT ${PYTHON_PACKAGES_INSTALL_DIR}) set(NG_INSTALL_DIR_RES_DEFAULT share) set(NG_INSTALL_DIR_INCLUDE_DEFAULT include) set(NG_RPATH_TOKEN "\$ORIGIN") endif(APPLE AND NOT EMSCRIPTEN) set(NG_INSTALL_DIR_PYTHON ${NG_INSTALL_DIR_PYTHON_DEFAULT} CACHE STRING "Install directory for Python files") set(NG_INSTALL_DIR_BIN ${NG_INSTALL_DIR_BIN_DEFAULT} CACHE STRING "Install directory for executables") set(NG_INSTALL_DIR_LIB ${NG_INSTALL_DIR_LIB_DEFAULT} CACHE STRING "Install directory for libraries") set(NG_INSTALL_DIR_INCLUDE ${NG_INSTALL_DIR_INCLUDE_DEFAULT} CACHE STRING "Install directory for header files") set(NG_INSTALL_DIR_CMAKE ${NG_INSTALL_DIR_CMAKE_DEFAULT} CACHE STRING "Install directory for CMake files") set(NG_INSTALL_DIR_RES ${NG_INSTALL_DIR_RES_DEFAULT} CACHE STRING "Install directory for resources") get_filename_component(NETGEN_CMAKE_DIR_ABSOLUTE ${NG_INSTALL_DIR_CMAKE} ABSOLUTE BASE_DIR ${CMAKE_INSTALL_PREFIX}) get_filename_component(NETGEN_BINARY_DIR_ABSOLUTE ${NG_INSTALL_DIR_BIN} ABSOLUTE BASE_DIR ${CMAKE_INSTALL_PREFIX}) get_filename_component(NETGEN_LIBRARY_DIR_ABSOLUTE ${NG_INSTALL_DIR_LIB} ABSOLUTE BASE_DIR ${CMAKE_INSTALL_PREFIX}) get_filename_component(NETGEN_INCLUDE_DIR_ABSOLUTE ${NG_INSTALL_DIR_INCLUDE} ABSOLUTE BASE_DIR ${CMAKE_INSTALL_PREFIX}) get_filename_component(NETGEN_RESOURCE_DIR_ABSOLUTE ${NG_INSTALL_DIR_RES} ABSOLUTE BASE_DIR ${CMAKE_INSTALL_PREFIX}) file(RELATIVE_PATH NETGEN_DIR ${NETGEN_CMAKE_DIR_ABSOLUTE} ${CMAKE_INSTALL_PREFIX}) file(RELATIVE_PATH NETGEN_BINARY_DIR ${NETGEN_CMAKE_DIR_ABSOLUTE} ${NETGEN_BINARY_DIR_ABSOLUTE}) file(RELATIVE_PATH NETGEN_LIBRARY_DIR ${NETGEN_CMAKE_DIR_ABSOLUTE} ${NETGEN_LIBRARY_DIR_ABSOLUTE}) file(RELATIVE_PATH NETGEN_INCLUDE_DIR ${NETGEN_CMAKE_DIR_ABSOLUTE} ${NETGEN_INCLUDE_DIR_ABSOLUTE}) file(RELATIVE_PATH NETGEN_RESOURCE_DIR ${NETGEN_CMAKE_DIR_ABSOLUTE} ${NETGEN_RESOURCE_DIR_ABSOLUTE}) file(RELATIVE_PATH NETGEN_RPATH ${NETGEN_BINARY_DIR_ABSOLUTE} ${NETGEN_LIBRARY_DIR_ABSOLUTE}) if (USE_SUPERBUILD) # execute the superbuild (this script will be invoked again without the # USE_SUPERBUILD option this time) include (cmake/SuperBuild.cmake) return() # stop processing this file further endif() set(CMAKE_EXPORT_COMPILE_COMMANDS ON) include (${CMAKE_CURRENT_LIST_DIR}/cmake/generate_version_file.cmake) set(CPACK_PACKAGE_VERSION "${NETGEN_VERSION}") ####################################################################### if(USE_CCACHE) find_program(CCACHE_FOUND NAMES ccache ccache.bat) if(CCACHE_FOUND) set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ${CCACHE_FOUND}) message(STATUS "Using ccache ${CCACHE_FOUND}") endif(CCACHE_FOUND) endif(USE_CCACHE) ####################################################################### if(INTEL_MIC) set(MKL_ARCH "mic") include(cmake/mic.cmake) else(INTEL_MIC) set(MKL_ARCH "intel64") endif(INTEL_MIC) ####################################################################### # Append install paths of software in non-standard paths (e.g. openmpi, metis, intel mkl, ...) # cmake -DUSE_MPI=ON -DCMAKE_PREFIX_PATH="/opt/openmpi165;/opt/metis51" ../ set(ADDITIONAL_PATHS "" CACHE PATH "List of paths to additional libraries in non-standard locations, separated by ';'") if (ADDITIONAL_PATHS) set(CMAKE_PREFIX_PATH ${ADDITIONAL_PATHS}) endif (ADDITIONAL_PATHS) ####################################################################### # build options include_directories ("${PROJECT_SOURCE_DIR}/include") include_directories ("${PROJECT_SOURCE_DIR}/libsrc") include_directories ("${PROJECT_SOURCE_DIR}/libsrc/include") include_directories ("${PROJECT_BINARY_DIR}") set(CMAKE_INCLUDE_CURRENT_DIR ON) if(USE_PYTHON) get_filename_component(NETGEN_PYTHON_DIR_ABSOLUTE ${NG_INSTALL_DIR_PYTHON} ABSOLUTE BASE_DIR ${CMAKE_INSTALL_PREFIX}) file(RELATIVE_PATH NETGEN_PYTHON_DIR ${NETGEN_CMAKE_DIR_ABSOLUTE} ${NETGEN_PYTHON_DIR_ABSOLUTE}) file(RELATIVE_PATH NETGEN_PYTHON_RPATH_BIN ${NETGEN_PYTHON_DIR_ABSOLUTE} ${NETGEN_BINARY_DIR_ABSOLUTE}) file(RELATIVE_PATH NETGEN_PYTHON_RPATH ${NETGEN_PYTHON_DIR_ABSOLUTE} ${NETGEN_LIBRARY_DIR_ABSOLUTE}) if(WIN32) set(NETGEN_PYTHON_RPATH ${NETGEN_PYTHON_RPATH_BIN}) endif(WIN32) endif(USE_PYTHON) set(NG_INSTALL_DIR EXPORT netgen-targets RUNTIME DESTINATION ${NG_INSTALL_DIR_BIN} COMPONENT netgen LIBRARY DESTINATION ${NG_INSTALL_DIR_LIB} COMPONENT netgen_devel ARCHIVE DESTINATION ${NG_INSTALL_DIR_LIB} COMPONENT netgen_devel) install(EXPORT netgen-targets DESTINATION ${NG_INSTALL_DIR_CMAKE} COMPONENT netgen_devel) set(CMAKE_MACOSX_RPATH TRUE) set(CMAKE_INSTALL_RPATH "${NG_RPATH_TOKEN};${NG_RPATH_TOKEN}/${NETGEN_RPATH}") if(BUILD_FOR_CONDA) file(RELATIVE_PATH py_rpath "/bin" "/${NG_INSTALL_DIR_LIB}") set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_RPATH};${py_rpath}") endif(BUILD_FOR_CONDA) include (CheckIncludeFiles) check_include_files (dlfcn.h HAVE_DLFCN_H) if(HAVE_DLFCN_H) add_definitions(-DHAVE_DLFCN_H) endif() include_directories(BEFORE ${CMAKE_CURRENT_BINARY_DIR}) ####################################################################### # platform specific definitions and flags macro(get_WIN32_WINNT version) if (WIN32 AND CMAKE_SYSTEM_VERSION) if("${CMAKE_SYSTEM_VERSION}" MATCHES "^([0-9]+)\\.([0-9]+)") math(EXPR ver "${CMAKE_MATCH_1}*100 + ${CMAKE_MATCH_2}") endif() set(${version} "0x${ver}") endif() endmacro() macro(get_dll_from_lib dll_path lib_path) get_filename_component(parent_lib_path ${lib} DIRECTORY) get_filename_component(lib_name ${lib} name) endmacro() set(CMAKE_CXX_VISIBILITY_PRESET hidden) set(CMAKE_CXX_STANDARD 17) if(WIN32) set(CMAKE_MFC_FLAG 0) endif(WIN32) if(APPLE) set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -undefined dynamic_lookup") endif(APPLE) ####################################################################### add_library(nglib ${NGLIB_LIBRARY_TYPE}) if(USE_GUI) add_library(nggui ${NGGUI_LIBRARY_TYPE}) if(WIN32) set_target_properties( nggui PROPERTIES OUTPUT_NAME "libnggui") endif(WIN32) endif(USE_GUI) ####################################################################### if(NOT ZLIB_INCLUDE_DIRS) find_package(ZLIB REQUIRED) endif(NOT ZLIB_INCLUDE_DIRS) target_include_directories(nglib PRIVATE ${ZLIB_INCLUDE_DIRS}) if(USE_GUI) target_include_directories(nggui PRIVATE ${ZLIB_INCLUDE_DIRS}) endif(USE_GUI) ####################################################################### if(WIN32) add_library(netgen_gui INTERFACE IMPORTED) else() add_library(netgen_gui INTERFACE) endif() if (USE_GUI) find_package(TCL 8.5 REQUIRED) find_package(TclStub 8.5 REQUIRED) find_package(Threads REQUIRED) if(APPLE) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -framework AppKit") target_link_libraries(netgen_gui INTERFACE "-framework AppKit") else(APPLE) find_package(X11 REQUIRED) target_link_libraries( netgen_gui INTERFACE ${X11_Xmu_LIB} ${X11_X11_LIB}) endif(APPLE) find_package(OpenGL REQUIRED) target_compile_definitions(netgen_gui INTERFACE -DTCL -DOPENGL -DUSE_TOGL_2 -DUSE_TCL_STUBS -DUSE_TK_STUBS) target_include_directories(netgen_gui INTERFACE ${TCL_INCLUDE_PATH} ${TK_INCLUDE_PATH}) target_link_libraries(netgen_gui INTERFACE ${TCL_STUB_LIBRARY} ${TK_STUB_LIBRARY}) if(NOT EXISTS ${TK_INCLUDE_PATH}/tkWin.h AND EXISTS ${TK_INCLUDE_PATH}/../win/tkWin.h) target_include_directories(netgen_gui INTERFACE ${TK_INCLUDE_PATH}/../win) endif() if(NOT EXISTS ${TK_INCLUDE_PATH}/x11/Xlib.h AND EXISTS ${TK_INCLUDE_PATH}/../xlib/X11/Xlib.h) target_include_directories(netgen_gui INTERFACE ${TK_INCLUDE_PATH}/../xlib) endif() target_link_libraries(nggui PUBLIC nglib togl PRIVATE "$" ) if(WIN32) target_compile_definitions(netgen_gui INTERFACE -DTOGL_WGL) endif() if(APPLE) target_compile_definitions(netgen_gui INTERFACE -DTOGL_NSOPENGL) endif() if(UNIX AND NOT APPLE) target_compile_definitions(netgen_gui INTERFACE -DTOGL_X11) endif() endif (USE_GUI) ####################################################################### if(WIN32) add_library(netgen_python INTERFACE IMPORTED) else() add_library(netgen_python INTERFACE) endif() if (USE_PYTHON) if (PREFER_SYSTEM_PYBIND11) set(NG_INSTALL_PYBIND OFF) find_package(pybind11 CONFIG REQUIRED) else() add_subdirectory(external_dependencies/pybind11) endif() target_compile_definitions(netgen_python INTERFACE NG_PYTHON NETGEN_PYTHON) target_include_directories(netgen_python INTERFACE ${pybind11_INCLUDE_DIR} ${Python3_INCLUDE_DIRS}) target_include_directories(nglib PRIVATE ${pybind11_INCLUDE_DIR} ${Python3_INCLUDE_DIRS}) if(Python3_LIBRARIES AND (WIN32 OR NOT BUILD_FOR_CONDA)) target_link_libraries(netgen_python INTERFACE ${Python3_LIBRARIES}) endif() if(NG_INSTALL_PYBIND) install(DIRECTORY ${pybind11_INCLUDE_DIR}/pybind11 DESTINATION ${NG_INSTALL_DIR_INCLUDE} COMPONENT netgen_devel) install(FILES ${pybind11_INCLUDE_DIR}/../LICENSE DESTINATION ${NG_INSTALL_DIR_INCLUDE}/pybind11 COMPONENT netgen_devel) endif(NG_INSTALL_PYBIND) endif (USE_PYTHON) ####################################################################### add_library(netgen_metis INTERFACE) if (USE_MPI) set(MPI_DETERMINE_LIBRARY_VERSION TRUE) find_package(MPI) find_package(METIS REQUIRED) target_include_directories(netgen_metis INTERFACE ${METIS_INCLUDE_DIR}) target_link_libraries(netgen_metis INTERFACE ${METIS_LIBRARY} ) target_compile_definitions(netgen_metis INTERFACE METIS ) endif (USE_MPI) ####################################################################### add_library(occ_libs INTERFACE IMPORTED) if (USE_OCC) find_package(OpenCascade NAMES OpenCASCADE opencascade REQUIRED CMAKE_FIND_ROOT_PATH_BOTH) add_definitions(-DOCCGEOMETRY) set(OCC_LIBRARIES TKBO TKBRep TKBool TKCAF TKCDF TKFillet TKG2d TKG3d TKGeomAlgo TKGeomBase TKHLR TKLCAF TKMath TKMesh TKOffset TKPrim TKService TKShHealing TKTopAlgo TKV3d TKVCAF TKXCAF TKXSBase TKernel ) if(${OpenCASCADE_MAJOR_VERSION}.${OpenCASCADE_MINOR_VERSION} VERSION_GREATER_EQUAL 7.8) list(APPEND OCC_LIBRARIES TKDEIGES TKDESTEP TKDESTL) else() list(APPEND OCC_LIBRARIES TKIGES TKSTEP TKSTL TKXDEIGES TKXDESTEP TKSTEP209 TKSTEPAttr TKSTEPBase ) endif() if(UNIX AND NOT APPLE) list(PREPEND OCC_LIBRARIES -Wl,--start-group) list(APPEND OCC_LIBRARIES -Wl,--end-group) endif() target_link_libraries(occ_libs INTERFACE ${OCC_LIBRARIES}) get_target_property(occ_include_dir TKernel INTERFACE_INCLUDE_DIRECTORIES) if(NOT occ_include_dir) set(occ_include_dir ${OpenCASCADE_INCLUDE_DIR}) endif() target_include_directories(occ_libs INTERFACE ${occ_include_dir}) message(STATUS "OpenCasCade include dirs: ${occ_include_dir}") if(NOT OpenCASCADE_BUILD_SHARED_LIBS) if(OpenCASCADE_WITH_FREETYPE) find_library( FREETYPE NAMES freetype HINTS ${OpenCASCADE_LIBRARY_DIR}) list(APPEND OCC_LIBRARIES ${FREETYPE}) target_link_libraries(occ_libs INTERFACE ${FREETYPE}) if(UNIX AND NOT APPLE) find_package(Fontconfig REQUIRED) target_link_libraries(occ_libs INTERFACE ${Fontconfig_LIBRARIES}) endif() endif(OpenCASCADE_WITH_FREETYPE) set(THREADS_PREFER_PTHREAD_FLAG ON) find_package(Threads REQUIRED) target_link_libraries(occ_libs INTERFACE Threads::Threads) endif() if(WIN32 AND USE_GUI) target_link_libraries(nggui PRIVATE Ws2_32.lib) endif(WIN32 AND USE_GUI) if(USE_GUI) target_link_libraries(nggui PRIVATE occ_libs) endif(USE_GUI) endif (USE_OCC) ####################################################################### if (USE_JPEG) find_package(JPEG REQUIRED) add_definitions(-DJPEGLIB) include_directories(${JPEG_INCLUDE_DIR}) endif (USE_JPEG) ####################################################################### if (USE_MPEG) find_package(FFMPEG REQUIRED) add_definitions(-DFFMPEG -D__STDC_CONSTANT_MACROS) include_directories(${FFMPEG_INCLUDE_DIR}) endif (USE_MPEG) ####################################################################### add_custom_target(ng_generate_version_file ${CMAKE_COMMAND} -DBDIR=${CMAKE_CURRENT_BINARY_DIR} -P ${CMAKE_CURRENT_LIST_DIR}/cmake/generate_version_file.cmake ) ####################################################################### if(INSTALL_PROFILES) file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/netgen.sh "#!/bin/sh\n") file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/netgen.sh "export PATH=${CMAKE_INSTALL_PREFIX}/bin:$PATH\n") file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/netgen.sh "export NETGENDIR=${CMAKE_INSTALL_PREFIX}/bin\n") file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/netgen.sh "export PYTHONPATH=${CMAKE_INSTALL_PREFIX}/${PYTHON_PACKAGES_INSTALL_DIR}:.\n") file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/netgen.sh "export LD_LIBRARY_PATH=${CMAKE_INSTALL_PREFIX}/lib:.\n") install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/netgen.sh DESTINATION /etc/profile.d COMPONENT netgen) string(ASCII 27 Esc) file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/postinst "#!/bin/sh\n") file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/postinst "echo \"${Esc}[0;31mPlease log out and in again or do 'source /etc/profile.d/netgen.sh' to load the correct environment variables!${Esc}[m\"") set( CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${CMAKE_CURRENT_BINARY_DIR}/postinst") endif(INSTALL_PROFILES) ####################################################################### file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/fixup.cmake "\ include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/netgen_fixup.cmake) set(APP ${CMAKE_INSTALL_PREFIX}) message(\${APP}) set(BU_CHMOD_BUNDLE_ITEMS ON) file(GLOB libs ${CMAKE_INSTALL_PREFIX}/${NG_INSTALL_DIR_LIB}/*.dylib ${CMAKE_INSTALL_PREFIX}/${NG_INSTALL_DIR_LIB}/*.so) message(\"\${libs}\") netgen_fixup_bundle( \${APP}/Contents/MacOS/netgen \"\${libs}\" ${CMAKE_INSTALL_PREFIX}/${NG_INSTALL_DIR_LIB} ) execute_process(COMMAND ln -s /Applications ${CMAKE_INSTALL_PREFIX}/../Applications) set (bundle_filename \$ENV{NETGEN_BUNDLE_NAME}) if(NOT bundle_filename) set(bundle_filename netgen) endif(NOT bundle_filename) execute_process(COMMAND hdiutil create -volname Netgen -srcfolder ${CMAKE_INSTALL_PREFIX} -ov -format UDZO \${bundle_filename}-${PACKAGE_VERSION}.dmg) ") add_custom_target(bundle COMMAND ${CMAKE_COMMAND} "-P" "${CMAKE_CURRENT_BINARY_DIR}/fixup.cmake") ####################################################################### # CTest enable_testing() include(CTest) if(ENABLE_UNIT_TESTS) include(${CMAKE_CURRENT_LIST_DIR}/cmake/external_projects/catch.cmake) endif(ENABLE_UNIT_TESTS) ####################################################################### if(USE_SPDLOG) include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/external_projects/spdlog.cmake) include_directories(${SPDLOG_INCLUDE_DIR}) endif(USE_SPDLOG) if(ENABLE_CPP_CORE_GUIDELINES_CHECK) find_program( CLANG_TIDY_EXE NAMES "clang-tidy" DOC "Path to clang-tidy executable" ) if(NOT CLANG_TIDY_EXE) message(WARNING "clang-tidy not found.") else() message(STATUS "clang-tidy found: ${CLANG_TIDY_EXE}") set(DO_CLANG_TIDY "${CLANG_TIDY_EXE}" "-header-filter=libsrc/core/") endif() endif(ENABLE_CPP_CORE_GUIDELINES_CHECK) add_library(netgen_cgns INTERFACE) if(USE_CGNS) find_library( CGNS_LIBRARY NAMES cgns cgnsdll ) find_path( CGNS_INCLUDE_DIR cgnslib.h ) target_compile_definitions(netgen_cgns INTERFACE NG_CGNS) target_include_directories(netgen_cgns INTERFACE ${CGNS_INCLUDE_DIR}) target_link_libraries(netgen_cgns INTERFACE ${CGNS_LIBRARY}) if(NOT WIN32 AND NOT APPLE) # hdf5 is statically linked into cgns in Windows amd MacOS binaries find_library(HDF5_LIBRARY NAMES hdf5 hdf5_serial) target_link_libraries(netgen_cgns INTERFACE ${HDF5_LIBRARY}) endif(NOT WIN32 AND NOT APPLE) endif(USE_CGNS) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/netgen_version.hpp ${CMAKE_CURRENT_BINARY_DIR}/netgen_config.hpp DESTINATION ${NG_INSTALL_DIR_INCLUDE}/include COMPONENT netgen_devel) # include instead of add_subdirectory to recognize the generated source files properly include(rules/CMakeLists.txt) add_subdirectory(windows) add_subdirectory(libsrc) add_subdirectory(ng) add_subdirectory(tutorials) add_subdirectory(py_tutorials) add_subdirectory(doc) add_subdirectory(nglib) add_subdirectory(tests) ####################################################################### if(USE_NATIVE_ARCH) if(WIN32) include(CheckCXXSourceRuns) check_cxx_source_runs(" #include int main() { __m256d a{1.,2.,3.,4.}; __m256d b{2.,0.,3.,5.}; __m256d c = _mm256_mul_pd(a,b); return 0; } " NG_HAVE_AVX) check_cxx_source_runs(" #include int main() { __m256i a{1,2,3,4}; __m256i b{2,0,3,5}; __m256i c = _mm256_cmpgt_epi64 (a,b); return 0; } " NG_HAVE_AVX2) check_cxx_source_runs(" #include int main() { __m512d a{1.,2.,3.,4.}; __m512d b{5.,6.,7.,8.}; __m512d c = _mm512_mul_pd(a,b); return 0; } " NG_HAVE_AVX512) if(NG_HAVE_AVX512) target_compile_options(ngcore PUBLIC "/arch:AVX512") message(STATUS "Build for AVX512 CPU") elseif(NG_HAVE_AVX2) target_compile_options(ngcore PUBLIC "/arch:AVX2") message(STATUS "Build for AVX2 CPU") elseif(NG_HAVE_AVX) target_compile_options(ngcore PUBLIC "/arch:AVX") message(STATUS "Build for AVX CPU") else() message(STATUS "Build for generic CPU") endif() elseif(APPLE AND CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") # no flag necessary/available on Apple M1 else() target_compile_options(ngcore PUBLIC "-march=native") endif(WIN32) if(APPLE) # work-around for bug in Xcode 11.3: https://forums.developer.apple.com/thread/121887 target_compile_options(ngcore PUBLIC "-fno-stack-check") endif(APPLE) endif(USE_NATIVE_ARCH) if (USE_PYTHON) add_subdirectory(python) endif (USE_PYTHON) ####################################################################### # Debian packager if(UNIX) set(CPACK_SOURCE_GENERATOR "TGZ") set(CPACK_SOURCE_IGNORE_FILES "/cmake/;/build/;/.gz/;~$;${CPACK_SOURCE_IGNORE_FILES}") set(CPACK_PACKAGE_VERSION ${PACKAGE_VERSION} ) set(CPACK_PACKAGE_NAME netgen) set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "automatic 3d tetrahedral mesh generator") set(CPACK_PACKAGE_DESCRIPTION "NETGEN is an automatic 3d tetrahedral mesh generator. It accepts input from constructive solid geometry (CSG) or boundary representation (BRep) from STL file format. The connection to a geometry kernel allows the handling of IGES and STEP files. NETGEN contains modules for mesh optimization and hierarchical mesh refinement. Netgen is open source based on the LGPL license. It is available for Unix/Linux and Windows.") set(CPACK_PACKAGING_INSTALL_PREFIX "/opt/netgen") execute_process(COMMAND grep CODENAME /etc/lsb-release OUTPUT_VARIABLE temp OUTPUT_STRIP_TRAILING_WHITESPACE) execute_process(COMMAND dpkg --print-architecture OUTPUT_VARIABLE CPACK_DEBIAN_PACKAGE_ARCHITECTURE OUTPUT_STRIP_TRAILING_WHITESPACE) if(temp) set(CPACK_GENERATOR "DEB") string(SUBSTRING ${temp} 17 -1 UBUNTU_VERSION) message("ubuntu version: ${UBUNTU_VERSION}") set(CPACK_DEBIAN_PACKAGE_DEPENDS "python3, libtk8.5, libtcl8.5, tix, libxmu6") execute_process(COMMAND dpkg --print-architecture OUTPUT_VARIABLE CPACK_DEBIAN_PACKAGE_ARCHITECTURE OUTPUT_STRIP_TRAILING_WHITESPACE) set(CPACK_DEBIAN_PACKAGE_MAINTAINER "Matthias Hochsteger ") if(USE_MPI) set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS}, libmetis5, openmpi-bin") set(CPACK_PACKAGE_NAME "${CPACK_PACKAGE_NAME}_mpi") endif(USE_MPI) if(USE_OCC) set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS}, liboce-ocaf-dev") endif(USE_OCC) set(CPACK_DEBIAN_PACKAGE_SECTION Science) set(CPACK_DEBIAN_PACKAGE_NAME ${CPACK_PACKAGE_NAME}) set(CPACK_PACKAGE_FILE_NAME "netgen-${PACKAGE_VERSION}_${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}") endif(temp) endif(UNIX) if(USE_PYTHON AND NOT SKBUILD) # install egg file to let python/pip know that Netgen ist installed file( WRITE "netgen_mesher-py3.egg-info" "Metadata-Version: 2.1 Name: netgen-mesher Version: ${NETGEN_VERSION_MAJOR}.${NETGEN_VERSION_MINOR}.${NETGEN_VERSION_PATCH}.post${NETGEN_VERSION_TWEAK} ") install(FILES netgen_mesher-py3.egg-info DESTINATION ${NG_INSTALL_DIR_PYTHON} COMPONENT netgen) endif() if(APPLE AND NOT SKBUILD) # create some auxiliary files set(mac_startup ${CMAKE_CURRENT_BINARY_DIR}/startup.sh) file(WRITE ${mac_startup} "\ #!/bin/sh Netgen_BUNDLE=\"`echo \"$0\" | sed -e 's/\\/Contents\\/MacOS\\/startup.sh//'`\" Netgen_MACOS=\"$Netgen_BUNDLE/Contents/MacOS\" export NETGENDIR=$Netgen_MACOS export DYLD_LIBRARY_PATH=$Netgen_MACOS:$DYLD_LIBRARY_PATH # export TIX_LIBRARY=$Netgen_MACOS/library # export TCLLIBPATH=$Netgen_MACOS:$TCLLIBPATH export PYTHONPATH=$Netgen_BUNDLE/Contents/Resources/${PYTHON_PACKAGES_INSTALL_DIR}:$PYTHONPATH cd $Netgen_MACOS $Netgen_MACOS/netgen ") install(PROGRAMS ${mac_startup} DESTINATION ${NG_INSTALL_DIR_BIN}) set(mac_ngsuite ${CMAKE_CURRENT_BINARY_DIR}/ngsuite.sh) file(WRITE ${mac_ngsuite} "\ #!/bin/sh Netgen_BUNDLE=\"`echo \"$0\" | sed -e 's/\\/Contents\\/MacOS\\/Netgen1//'`\" Netgen_MACOS=\"$Netgen_BUNDLE/Contents/MacOS\" open -a /Applications/Utilities/Terminal.app $Netgen_MACOS/startup.sh || open -a /System/Applications/Utilities/Terminal.app $Netgen_MACOS/startup.sh ") install(PROGRAMS ${mac_ngsuite} DESTINATION ${NG_INSTALL_DIR_BIN} RENAME Netgen1) set(mac_plist ${CMAKE_CURRENT_BINARY_DIR}/Info.plist) file(WRITE ${mac_plist} " CFBundleDevelopmentRegion English CFBundleExecutable Netgen1 CFBundleIconFile Netgen.icns NSHighResolutionCapable True ") install(FILES ${mac_plist} DESTINATION ${NG_INSTALL_DIR_BIN}/../) install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/netgen.icns DESTINATION ${NG_INSTALL_DIR_RES}/../ RENAME Netgen.icns) endif(APPLE AND NOT SKBUILD) if(NOT APPLE) include(CPack) endif() ####################################################################### # uninstall target configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY) add_custom_target(uninstall COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake) ####################################################################### # Generate package config file set(NETGEN_MSVC_RUNTIME_LIBRARY ${CMAKE_MSVC_RUNTIME_LIBRARY}) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/NetgenConfig.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/NetgenConfig.cmake @ONLY ESCAPE_QUOTES) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/NetgenConfig.cmake DESTINATION ${NG_INSTALL_DIR_CMAKE} COMPONENT netgen_devel) ####################################################################### # Configure message # TODO: other message in case of failure string(TOUPPER "CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE}" name) set(flags "${${name}} ${CMAKE_CXX_FLAGS}") message(" ------------------------------------------------------------------------ ${PROJECT_NAME} ${PACKAGE_VERSION}: Automatic configuration OK. Build type: ${CMAKE_BUILD_TYPE} Flags: ${flags} Enabled functionality: OCC: ............... ${USE_OCC} JPEGlib: ........... ${USE_JPEG} FFMPEG: ............ ${USE_MPEG} GUI: ............... ${USE_GUI} MPI: ............... ${USE_MPI} PYTHON: ............ ${USE_PYTHON} Building: ") if(WIN32) message(" Open ${CMAKE_BINARY_DIR}/Netgen.sln and build solution to compile ${PROJECT_NAME}. Build \"INSTALL\" to install ${PROJECT_NAME}. ") else(WIN32) message(" Type 'make' to compile ${PROJECT_NAME}. Type 'make install' to install ${PROJECT_NAME}. ") endif(WIN32) message(" Install directory: ${CMAKE_INSTALL_PREFIX} Please set the following environment variables: NETGENDIR=${CMAKE_INSTALL_PREFIX}/bin") if(USE_PYTHON) message(" PYTHONPATH=.:${CMAKE_INSTALL_PREFIX}/${PYTHON_PACKAGES_INSTALL_DIR}") endif(USE_PYTHON) message(" ------------------------------------------------------------------------ ") if (ADDITIONAL_PATHS) message(WARNING "The use of ADDITIONAL_PATHS is deprecated, use CMAKE_PREFIX_PATH instead") endif (ADDITIONAL_PATHS) ================================================ FILE: CONTRIBUTING.md ================================================ # How to Contribute ## Reporting issues If you have a problem using Netgen/NGSolve consider asking a question in our [forum](https://ngsolve.org/forum). If you found a bug create an issue in the [Github Issue Tracker](https://github.com/NGSolve/netgen/issues). Please be as specific as possible, issues with a reproducible minimal failing example will get more attention than unspecific one liners :) ## Contributing patches We love and want to encourage community engagement and will review and accept patches and contributions to this project. There are just a few steps to follow: On your first contribution, to clear any legal questions, we ask you to sign our [Contributor License Agreement](CLA.pdf). Generally you have to sign this only once for Netgen or NGSolve. Please send the signed agreement to . Place a pull request on GitHub. From there we will pull it into our internal testing environment and, if approved, merge it into the main codebase. If you have any questions feel free to ask on the [forum](https://ngsolve.org/forum). ================================================ FILE: ChangeLog ================================================ ================================================ FILE: INSTALL ================================================ Basic Installation ================== These are generic installation instructions. The `configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses those values to create a `Makefile' in each directory of the package. It may also create one or more `.h' files containing system-dependent definitions. Finally, it creates a shell script `config.status' that you can run in the future to recreate the current configuration, a file `config.cache' that saves the results of its tests to speed up reconfiguring, and a file `config.log' containing compiler output (useful mainly for debugging `configure'). If you need to do unusual things to compile the package, please try to figure out how `configure' could check whether to do them, and mail diffs or instructions to the address given in the `README' so they can be considered for the next release. If at some point `config.cache' contains results you don't want to keep, you may remove or edit it. The file `configure.in' is used to create `configure' by a program called `autoconf'. You only need `configure.in' if you want to change it or regenerate `configure' using a newer version of `autoconf'. The simplest way to compile this package is: 1. `cd' to the directory containing the package's source code and type `./configure' to configure the package for your system. If you're using `csh' on an old version of System V, you might need to type `sh ./configure' instead to prevent `csh' from trying to execute `configure' itself. Running `configure' takes a while. While running, it prints some messages telling which features it is checking for. 2. Type `make' to compile the package. 3. Type `make install' to install the programs and any data files and documentation. 4. You can remove the program binaries and object files from the source code directory by typing `make clean'. Compilers and Options ===================== Some systems require unusual options for compilation or linking that the `configure' script does not know about. You can give `configure' initial values for variables by setting them in the environment. Using a Bourne-compatible shell, you can do that on the command line like this: CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure Or on systems that have the `env' program, you can do it like this: env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure Compiling For Multiple Architectures ==================================== You can compile the package for more than one kind of computer at the same time, by placing the object files for each architecture in their own directory. To do this, you must use a version of `make' that supports the `VPATH' variable, such as GNU `make'. `cd' to the directory where you want the object files and executables to go and run the `configure' script. `configure' automatically checks for the source code in the directory that `configure' is in and in `..'. If you have to use a `make' that does not supports the `VPATH' variable, you have to compile the package for one architecture at a time in the source code directory. After you have installed the package for one architecture, use `make distclean' before reconfiguring for another architecture. Installation Names ================== By default, `make install' will install the package's files in `/usr/local/bin', `/usr/local/man', etc. You can specify an installation prefix other than `/usr/local' by giving `configure' the option `--prefix=PATH'. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you give `configure' the option `--exec-prefix=PATH', the package will use PATH as the prefix for installing programs and libraries. Documentation and other data files will still use the regular prefix. If the package supports it, you can cause programs to be installed with an extra prefix or suffix on their names by giving `configure' the option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. Optional Features ================= Some packages pay attention to `--enable-FEATURE' options to `configure', where FEATURE indicates an optional part of the package. They may also pay attention to `--with-PACKAGE' options, where PACKAGE is something like `gnu-as' or `x' (for the X Window System). The `README' should mention any `--enable-' and `--with-' options that the package recognizes. For packages that use the X Window System, `configure' can usually find the X include and library files automatically, but if it doesn't, you can use the `configure' options `--x-includes=DIR' and `--x-libraries=DIR' to specify their locations. Specifying the System Type ========================== There may be some features `configure' can not figure out automatically, but needs to determine by the type of host the package will run on. Usually `configure' can figure that out, but if it prints a message saying it can not guess the host type, give it the `--host=TYPE' option. TYPE can either be a short name for the system type, such as `sun4', or a canonical name with three fields: CPU-COMPANY-SYSTEM See the file `config.sub' for the possible values of each field. If `config.sub' isn't included in this package, then this package doesn't need to know the host type. If you are building compiler tools for cross-compiling, you can also use the `--target=TYPE' option to select the type of system they will produce code for and the `--build=TYPE' option to select the type of system on which you are compiling the package. Sharing Defaults ================ If you want to set default values for `configure' scripts to share, you can create a site shell script called `config.site' that gives default values for variables like `CC', `cache_file', and `prefix'. `configure' looks for `PREFIX/share/config.site' if it exists, then `PREFIX/etc/config.site' if it exists. Or, you can set the `CONFIG_SITE' environment variable to the location of the site script. A warning: not all `configure' scripts look for a site script. Operation Controls ================== `configure' recognizes the following options to control how it operates. `--cache-file=FILE' Use and save the results of the tests in FILE instead of `./config.cache'. Set FILE to `/dev/null' to disable caching, for debugging `configure'. `--help' Print a summary of the options to `configure', and exit. `--quiet' `--silent' `-q' Do not print messages saying which checks are being made. `--srcdir=DIR' Look for the package's source code in directory DIR. Usually `configure' can determine that directory automatically. `--version' Print the version of Autoconf used to generate the `configure' script, and exit. `configure' also accepts some other, not widely useful, options. ================================================ FILE: LICENSE ================================================ GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! ================================================ FILE: NEWS ================================================ ================================================ FILE: README.md ================================================ Netgen mesh generator NETGEN is an automatic 3d tetrahedral mesh generator. It accepts input from constructive solid geometry (CSG) or boundary representation (BRep) from STL file format. The connection to a geometry kernel allows the handling of IGES and STEP files. NETGEN contains modules for mesh optimization and hierarchical mesh refinement. Netgen 6.x supports scripting via a Python interface. Netgen is open source based on the LGPL license. It is available for Unix/Linux, Windows, and OSX. Find the Open Source Community on https://ngsolve.org Support & Services: https://cerbsim.com ================================================ FILE: TODO ================================================ ================================================ FILE: cmake/NetgenConfig.cmake.in ================================================ set(CMAKE_MSVC_RUNTIME_LIBRARY "@CMAKE_MSVC_RUNTIME_LIBRARY@") set(NETGEN_VERSION "@NETGEN_VERSION@") set(NETGEN_VERSION_MAJOR "@NETGEN_VERSION_MAJOR@") set(NETGEN_VERSION_MINOR "@NETGEN_VERSION_MINOR@") set(NETGEN_VERSION_PATCH "@NETGEN_VERSION_PATCH@") set(NETGEN_VERSION_TWEAK "@NETGEN_VERSION_TWEAK@") get_filename_component(NETGEN_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) get_filename_component(NETGEN_DIR "${NETGEN_CMAKE_DIR}/@NETGEN_DIR@" ABSOLUTE) set(NETGEN_COMPILE_DEFINITIONS "@NETGEN_COMPILE_DEFINITIONS@") get_filename_component(NETGEN_INCLUDE_DIR "${NETGEN_CMAKE_DIR}/@NETGEN_INCLUDE_DIR@" ABSOLUTE) get_filename_component(NETGEN_BINARY_DIR "${NETGEN_CMAKE_DIR}/@NETGEN_BINARY_DIR@" ABSOLUTE) get_filename_component(NETGEN_LIBRARY_DIR "${NETGEN_CMAKE_DIR}/@NETGEN_LIBRARY_DIR@" ABSOLUTE) get_filename_component(NETGEN_PYTHON_DIR "${NETGEN_CMAKE_DIR}/@NETGEN_PYTHON_DIR@" ABSOLUTE) get_filename_component(NETGEN_RESOURCE_DIR "${NETGEN_CMAKE_DIR}/@NETGEN_RESOURCE_DIR@" ABSOLUTE) set(NETGEN_SOURCE_DIR "@PROJECT_SOURCE_DIR@") set(NETGEN_BUILD_FOR_CONDA "@BUILD_FOR_CONDA@") set(NETGEN_CHECK_RANGE "@CHECK_RANGE@") set(NETGEN_INCLUDE_DIRS "${NETGEN_INCLUDE_DIR}/include;${NETGEN_INCLUDE_DIR}") set(NETGEN_CMAKE_THREAD_LIBS_INIT "@CMAKE_THREAD_LIBS_INIT@") set(NETGEN_FFMPEG_LIBRARIES "@FFMPEG_LIBRARIES@") set(NETGEN_JPEG_INCLUDE_DIR "@JPEG_INCLUDE_DIR@") set(NETGEN_JPEG_LIBRARIES "@JPEG_LIBRARIES@") set(NETGEN_LIBTOGL "@LIBTOGL@") set(NETGEN_METIS_INCLUDE_DIR "@METIS_INCLUDE_DIR@") set(NETGEN_METIS_LIBRARY "@METIS_LIBRARY@") set(NETGEN_MKL_LIBRARIES "@MKL_LIBRARIES@") set(NETGEN_MPI_CXX_INCLUDE_PATH "@MPI_CXX_INCLUDE_PATH@") set(NETGEN_MPI_CXX_LIBRARIES "@MPI_CXX_LIBRARIES@") set(NETGEN_NUMA_LIBRARY "@NUMA_LIBRARY@") set(NETGEN_OCC_DIR "@OpenCasCade_DIR@") set(NETGEN_OCC_INCLUDE_DIR "@OpenCASCADE_INCLUDE_DIR@") set(NETGEN_OCC_LIBRARIES_BIN "@OpenCASCADE_BINARY_DIR@") set(NETGEN_OCC_LIBRARIES "@OCC_LIBRARIES@") set(NETGEN_OCC_LIBRARY_DIR "@OpenCASCADE_LIBRARY_DIR@") set(NETGEN_OPENGL_LIBRARIES "@OPENGL_LIBRARIES@") set(NETGEN_PYTHON_EXECUTABLE "@Python3_EXECUTABLE@") set(NETGEN_PYTHON_INCLUDE_DIRS "@Python3_INCLUDE_DIRS@") set(NETGEN_PYTHON_LIBRARIES "@Python3_LIBRARIES@") set(NETGEN_TCL_INCLUDE_PATH "@TCL_INCLUDE_PATH@") set(NETGEN_TCL_LIBRARY "@TCL_STUB_LIBRARY@") set(NETGEN_TK_DND_LIBRARY "@TK_DND_LIBRARY@") set(NETGEN_TK_INCLUDE_PATH "@TK_INCLUDE_PATH@") set(NETGEN_TK_LIBRARY "@TK_STUB_LIBRARY@") set(NETGEN_X11_X11_LIB "@X11_X11_LIB@") set(NETGEN_X11_Xmu_LIB "@X11_Xmu_LIB@") set(NETGEN_ZLIB_INCLUDE_DIRS "@ZLIB_INCLUDE_DIRS@") set(NETGEN_ZLIB_LIBRARIES "@ZLIB_LIBRARIES@") set(NETGEN_USE_GUI @USE_GUI@) set(NETGEN_USE_PYTHON @USE_PYTHON@) set(NETGEN_USE_MPI @USE_MPI@) set(NETGEN_USE_OCC @USE_OCC@) set(NETGEN_USE_JPEG @USE_JPEG@) set(NETGEN_USE_MPEG @USE_MPEG@) set(NETGEN_USE_CGNS @USE_CGNS@) set(NETGEN_INTEL_MIC @INTEL_MIC@) set(NETGEN_INSTALL_PROFILES @INSTALL_PROFILES@) set(NETGEN_USE_CCACHE @USE_CCACHE@) set(NETGEN_USE_NATIVE_ARCH @USE_NATIVE_ARCH@) set(NETGEN_USE_NUMA @USE_NUMA@) set(NETGEN_PYTHON_RPATH "@NETGEN_PYTHON_RPATH@") set(NETGEN_RPATH_TOKEN "@NG_RPATH_TOKEN@") set(NETGEN_INSTALL_DIR_PYTHON @NG_INSTALL_DIR_PYTHON@) set(NETGEN_INSTALL_DIR_BIN @NG_INSTALL_DIR_BIN@) set(NETGEN_INSTALL_DIR_LIB @NG_INSTALL_DIR_LIB@) set(NETGEN_INSTALL_DIR_INCLUDE @NG_INSTALL_DIR_INCLUDE@) set(NETGEN_INSTALL_DIR_CMAKE @NG_INSTALL_DIR_CMAKE@) set(NETGEN_INSTALL_DIR_RES @NG_INSTALL_DIR_RES@) if (NETGEN_USE_PYTHON) # Make sure we are finding the same Python version Netgen was built with set(Python3_FIND_VERSION_MAJOR @Python3_VERSION_MAJOR@) set(Python3_FIND_VERSION_MINOR @Python3_VERSION_MINOR@) endif() include(${CMAKE_CURRENT_LIST_DIR}/netgen-targets.cmake) message(STATUS "Found Netgen: ${CMAKE_CURRENT_LIST_DIR}") ================================================ FILE: cmake/SuperBuild.cmake ================================================ include (ExternalProject) option( BUILD_ZLIB "Build and link static version of zlib (useful for pip binaries)" OFF ) option( BUILD_OCC "Build and link static version of occ (useful for pip binaries)" OFF ) set_property (DIRECTORY PROPERTY EP_PREFIX dependencies) set (NETGEN_DEPENDENCIES) set (LAPACK_DEPENDENCIES) set (NETGEN_CMAKE_ARGS "" CACHE INTERNAL "") set (SUBPROJECT_CMAKE_ARGS "" CACHE INTERNAL "") set (SUBPROJECT_ARGS LIST_SEPARATOR | PREFIX ${CMAKE_CURRENT_BINARY_DIR}/dependencies ) if (EMSCRIPTEN) set (SUBPROJECT_ARGS ${SUBPROJECT_ARGS} CMAKE_COMMAND emcmake ${CMAKE_COMMAND}) endif() # only show output on failure in ci-builds if(DEFINED ENV{CI}) set (SUBPROJECT_ARGS ${SUBPROJECT_ARGS} LOG_DOWNLOAD ON LOG_BUILD ON LOG_INSTALL ON LOG_CONFIGURE ON ) if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.14.0") set (SUBPROJECT_ARGS ${SUBPROJECT_ARGS} LOG_OUTPUT_ON_FAILURE ON LOG_MERGED_STDOUTERR ON ) endif() endif() set (NETGEN_CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} ) macro(set_vars VAR_OUT) foreach(varname ${ARGN}) if(NOT "${${varname}}" STREQUAL "") string(REPLACE ";" "|" varvalue "${${varname}}" ) set(${VAR_OUT} "${${VAR_OUT}};-D${varname}=${varvalue}" CACHE INTERNAL "") endif() endforeach() endmacro() ####################################################################### set_vars(SUBPROJECT_CMAKE_ARGS CMAKE_OSX_DEPLOYMENT_TARGET) set_vars(SUBPROJECT_CMAKE_ARGS CMAKE_OSX_SYSROOT) set_vars(SUBPROJECT_CMAKE_ARGS CMAKE_C_COMPILER) set_vars(SUBPROJECT_CMAKE_ARGS CMAKE_CXX_COMPILER) set_vars(SUBPROJECT_CMAKE_ARGS CMAKE_BUILD_TYPE) set(SUBPROJECT_CMAKE_ARGS "${SUBPROJECT_CMAKE_ARGS};-DCMAKE_POSITION_INDEPENDENT_CODE=ON;-DCMAKE_POLICY_VERSION_MINIMUM=3.5" CACHE INTERNAL "") if(USE_CCACHE) find_program(CCACHE_FOUND NAMES ccache ccache.bat) if(CCACHE_FOUND) set(SUBPROJECT_CMAKE_ARGS "${SUBPROJECT_CMAKE_ARGS};-DCMAKE_CXX_COMPILER_LAUNCHER=${CCACHE_FOUND}" CACHE INTERNAL "") endif() endif() ####################################################################### set (DEPS_DOWNLOAD_URL "https://github.com/NGSolve/ngsolve_dependencies/releases/download/v1.0.0" CACHE STRING INTERNAL) set (OCC_DOWNLOAD_URL_WIN "${DEPS_DOWNLOAD_URL}/occ75_win64.zip" CACHE STRING INTERNAL) set (TCLTK_DOWNLOAD_URL_WIN "${DEPS_DOWNLOAD_URL}/tcltk_win64.zip" CACHE STRING INTERNAL) set (ZLIB_DOWNLOAD_URL_WIN "${DEPS_DOWNLOAD_URL}/zlib_win64.zip" CACHE STRING INTERNAL) set (CGNS_DOWNLOAD_URL_WIN "${DEPS_DOWNLOAD_URL}/cgns_win64.zip" CACHE STRING INTERNAL) set (CGNS_DOWNLOAD_URL_MAC "${DEPS_DOWNLOAD_URL}/cgns_mac.zip" CACHE STRING INTERNAL) if(UNIX) message("Checking for write permissions in install directory...") execute_process(COMMAND mkdir -p ${CMAKE_INSTALL_PREFIX}) execute_process(COMMAND test -w ${CMAKE_INSTALL_PREFIX} RESULT_VARIABLE res) if(res) message(WARNING "No write access at install directory, please set correct permissions") endif() endif(UNIX) if(USE_OCC) if(BUILD_OCC) set(OCC_DIR ${CMAKE_CURRENT_BINARY_DIR}/dependencies/occ) ExternalProject_Add(project_occ # URL https://github.com/Open-Cascade-SAS/OCCT/archive/refs/tags/V7_6_3.zip # URL_MD5 2426e373903faabbd4f96a01a934b66d # URL https://github.com/Open-Cascade-SAS/OCCT/archive/refs/tags/V7_7_2.zip # URL_MD5 533eb4f18af0f77ae321b158caeaee79 URL https://github.com/Open-Cascade-SAS/OCCT/archive/refs/tags/V7_8_1.zip URL_MD5 bf62952a03696dab9e4272aa8efacb1a DOWNLOAD_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external_dependencies ${SUBPROJECT_ARGS} CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${OCC_DIR} -DCMAKE_PREFIX_PATH=${OCC_DIR} -DBUILD_LIBRARY_TYPE:STRING=Static -DBUILD_MODULE_FoundationClasses:BOOL=ON -DBUILD_MODULE_ModelingData:BOOL=ON -DBUILD_MODULE_ModelingAlgorithms:BOOL=ON -DBUILD_MODULE_DataExchange:BOOL=ON -DBUILD_MODULE_Visualization:BOOL=OFF -DBUILD_MODULE_ApplicationFramework:BOOL=OFF -DBUILD_MODULE_Draw:BOOL=OFF -DBUILD_MODULE_DETools:BOOL=OFF -DUSE_FREETYPE:BOOL=OFF -DUSE_OPENGL:BOOL=OFF -DUSE_XLIB:BOOL=OFF -DBUILD_DOC_Overview:BOOL=OFF ${SUBPROJECT_CMAKE_ARGS} UPDATE_COMMAND "" ) list(APPEND NETGEN_DEPENDENCIES project_occ) set(OpenCascade_ROOT ${OCC_DIR}) else(BUILD_OCC) find_package(OpenCascade NAMES OpenCasCade OpenCASCADE opencascade) if(NOT OpenCascade_FOUND) message(FATAL_ERROR "Opencascade not found, either\n\ - install pip packages netgen-occt-devel netgen-occt\n\ - set OpenCascade_DIR to a directory containting opencascadeConfig.cmake\n\ - build OpenCascade automatically by passing -DBUILD_OCC=ON\n\ - disable OpenCascade by passing -DUSE_OCC=OFF\n\ ") endif() endif(BUILD_OCC) endif(USE_OCC) if(BUILD_ZLIB) set(ZLIB_ROOT ${CMAKE_CURRENT_BINARY_DIR}/dependencies/zlib) ExternalProject_Add(project_zlib ${SUBPROJECT_ARGS} URL https://github.com/madler/zlib/archive/refs/tags/v1.2.11.zip URL_MD5 9d6a627693163bbbf3f26403a3a0b0b1 DOWNLOAD_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external_dependencies CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${ZLIB_ROOT} ${SUBPROJECT_CMAKE_ARGS} UPDATE_COMMAND "" # Disable update BUILD_IN_SOURCE 1 ) list(APPEND NETGEN_DEPENDENCIES project_zlib) if(WIN32) # force linking the static library set(ZLIB_INCLUDE_DIRS ${ZLIB_ROOT}/include) set(ZLIB_LIBRARIES ${ZLIB_ROOT}/lib/zlibstatic.lib) set(ZLIB_LIBRARY_RELEASE ${ZLIB_ROOT}/lib/zlibstatic.lib) else(WIN32) set(ZLIB_INCLUDE_DIRS ${ZLIB_ROOT}/include) set(ZLIB_LIBRARIES ${ZLIB_ROOT}/lib/libz.a) set(ZLIB_LIBRARY_RELEASE ${ZLIB_ROOT}/lib/libz.a) endif(WIN32) else() include(cmake/external_projects/zlib.cmake) endif() ####################################################################### if (USE_PYTHON) find_path(PYBIND_INCLUDE_DIR pybind11/pybind11.h PATHS ${CMAKE_CURRENT_SOURCE_DIR}/external_dependencies/pybind11/include NO_DEFAULT_PATH) set(NG_INSTALL_PYBIND ON) if( NOT PYBIND_INCLUDE_DIR ) # if the pybind submodule is missing, try to initialize and update all submodules execute_process(COMMAND git submodule update --init --recursive WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) find_path(PYBIND_INCLUDE_DIR pybind11/pybind11.h PATHS ${CMAKE_CURRENT_SOURCE_DIR}/external_dependencies/pybind11/include NO_DEFAULT_PATH) endif( NOT PYBIND_INCLUDE_DIR ) if( PYBIND_INCLUDE_DIR ) message("-- Found Pybind11: ${PYBIND_INCLUDE_DIR}") else( PYBIND_INCLUDE_DIR ) message(FATAL_ERROR "Could NOT find pybind11!") endif( PYBIND_INCLUDE_DIR ) if(${CMAKE_VERSION} VERSION_GREATER_EQUAL 3.18) find_package(Python3 COMPONENTS Interpreter Development.Module) if(NOT EMSCRIPTEN) find_package(Python3 COMPONENTS Interpreter Development.Embed) endif() else() find_package(Python3 REQUIRED COMPONENTS Interpreter Development) endif() set_vars(NETGEN_CMAKE_ARGS Python3_INCLUDE_DIRS Python3_LIBRARIES Python3_EXECUTABLE Python3_VERSION PYBIND_INCLUDE_DIR NG_INSTALL_PYBIND ) endif (USE_PYTHON) ####################################################################### if(USE_GUI) include(cmake/external_projects/tcltk.cmake) endif(USE_GUI) if(USE_CGNS) include(cmake/external_projects/cgns.cmake) endif(USE_CGNS) ####################################################################### if(USE_MPI) if (METIS_DIR) message(STATUS "Using external METIS at: ${METIS_DIR}") else (METIS_DIR) message(STATUS "Looking for system METIS") find_package(METIS QUIET) if(NOT METIS_FOUND) message(WARNING "Could not find METIS, it will be built from source (this might conflict with NGSolve MUMPS)!") include(cmake/external_projects/metis.cmake) endif(NOT METIS_FOUND) endif(METIS_DIR) endif(USE_MPI) ####################################################################### # propagate cmake variables to Netgen subproject set_vars( NETGEN_CMAKE_ARGS CMAKE_MODULE_LINKER_FLAGS CMAKE_MODULE_LINKER_FLAGS_RELEASE CMAKE_SHARED_LINKER_FLAGS CMAKE_SHARED_LINKER_FLAGS_RELEASE CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_RELEASE CMAKE_STRIP USE_GUI USE_PYTHON USE_MPI USE_MPI_WRAPPER USE_VT USE_VTUNE USE_NUMA USE_CCACHE USE_NATIVE_ARCH USE_OCC USE_MPEG USE_JPEG USE_CGNS USE_INTERNAL_TCL INSTALL_PROFILES INTEL_MIC CMAKE_INSTALL_PREFIX ENABLE_UNIT_TESTS ENABLE_CPP_CORE_GUIDELINES_CHECK USE_SPDLOG DEBUG_LOG CHECK_RANGE TRACE_MEMORY BUILD_STUB_FILES BUILD_FOR_CONDA NG_COMPILE_FLAGS OpenCascade_ROOT ZLIB_INCLUDE_DIRS ZLIB_LIBRARIES ZLIB_LIBRARY_RELEASE ZLIB_ROOT NGLIB_LIBRARY_TYPE NGCORE_LIBRARY_TYPE NGGUI_LIBRARY_TYPE NG_INSTALL_DIR_PYTHON NG_INSTALL_DIR_BIN NG_INSTALL_DIR_LIB NG_INSTALL_DIR_INCLUDE NG_INSTALL_DIR_CMAKE NG_INSTALL_DIR_RES NG_INSTALL_SUFFIX ) # propagate all variables set on the command line using cmake -DFOO=BAR # to Netgen subproject get_cmake_property(CACHE_VARS CACHE_VARIABLES) foreach(CACHE_VAR ${CACHE_VARS}) get_property(CACHE_VAR_HELPSTRING CACHE ${CACHE_VAR} PROPERTY HELPSTRING) if(CACHE_VAR_HELPSTRING STREQUAL "No help, variable specified on the command line." AND NOT CACHE_VAR STREQUAL "CMAKE_OSX_ARCHITECTURES") get_property(CACHE_VAR_TYPE CACHE ${CACHE_VAR} PROPERTY TYPE) string(REPLACE ";" "|" varvalue "${${CACHE_VAR}}" ) set(NETGEN_CMAKE_ARGS ${NETGEN_CMAKE_ARGS};-D${CACHE_VAR}:${CACHE_VAR_TYPE}=${varvalue} CACHE INTERNAL "") endif() endforeach() if(${CMAKE_GENERATOR} STREQUAL "Unix Makefiles") set(NETGEN_BUILD_COMMAND $(MAKE) --silent ) else() set(NETGEN_BUILD_COMMAND ${CMAKE_COMMAND} --build ${CMAKE_CURRENT_BINARY_DIR}/netgen --config ${CMAKE_BUILD_TYPE}) endif() string(REPLACE ";" "|" NETGEN_CMAKE_PREFIX_PATH_ALT_SEP "${NETGEN_CMAKE_PREFIX_PATH}") ExternalProject_Add (netgen ${SUBPROJECT_ARGS} DEPENDS ${NETGEN_DEPENDENCIES} SOURCE_DIR ${PROJECT_SOURCE_DIR} CMAKE_ARGS -DUSE_SUPERBUILD=OFF ${NETGEN_CMAKE_ARGS} ${SUBPROJECT_CMAKE_ARGS} -DCMAKE_PREFIX_PATH=${NETGEN_CMAKE_PREFIX_PATH_ALT_SEP} INSTALL_COMMAND "" BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/netgen BUILD_COMMAND ${NETGEN_BUILD_COMMAND} STEP_TARGETS build ) # Check if the git submodules (i.e. pybind11) are up to date # in case, something is wrong, emit a warning but continue ExternalProject_Add_Step(netgen check_submodules COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/check_submodules.cmake DEPENDERS install # Steps on which this step depends ) # Due to 'ALWAYS 1', this step is always run which also forces a build of # the Netgen subproject ExternalProject_Add_Step(netgen check_submodules1 COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/check_submodules.cmake DEPENDEES configure # Steps on which this step depends DEPENDERS build # Steps that depend on this step ALWAYS 1 # No stamp file, step always runs ) install(CODE "execute_process(COMMAND \"${CMAKE_COMMAND}\" --build . --target install --config ${CMAKE_BUILD_TYPE} WORKING_DIRECTORY \"${CMAKE_CURRENT_BINARY_DIR}/netgen\")") add_custom_target(test_netgen ${CMAKE_COMMAND} --build ${CMAKE_CURRENT_BINARY_DIR}/netgen --target test --config ${CMAKE_BUILD_TYPE} ) ================================================ FILE: cmake/check_submodules.cmake ================================================ execute_process(COMMAND git submodule status --recursive WORKING_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/../" OUTPUT_VARIABLE git_status_output) string(REPLACE "\n" ";" git_status_output "${git_status_output}") foreach( a ${git_status_output}) if(NOT ${a} MATCHES " [a-f,0-9]* external_dependencies[.]*") message(WARNING "***************************************************************** WARNING: The git submodules are out of sync! Please run git submodule update --init --recursive in your source directory *****************************************************************") endif() endforeach() ================================================ FILE: cmake/cmake_modules/FindFFMPEG.cmake ================================================ # - Try to find ffmpeg libraries (libavcodec, libavformat, libavutil and swscale) # Once done this will define # # FFMPEG_FOUND - system has ffmpeg or libav # FFMPEG_INCLUDE_DIR - the ffmpeg include directory # FFMPEG_LIBRARIES - Link these to use ffmpeg # FFMPEG_LIBAVCODEC # FFMPEG_LIBAVFORMAT # FFMPEG_LIBAVUTIL # FFMPEG_SWSCALE # # Copyright (c) 2008 Andreas Schneider # Modified for other libraries by Lasse Kärkkäinen # Modified for Hedgewars by Stepik777 # Modified for Netgen by Christoph Lehrenfeld (2015) (current version) # # Redistribution and use is allowed according to the terms of the New # BSD license. # if (FFMPEG_LIBRARIES AND FFMPEG_INCLUDE_DIR) # in cache already set(FFMPEG_FOUND TRUE) else (FFMPEG_LIBRARIES AND FFMPEG_INCLUDE_DIR) # use pkg-config to get the directories and then use these values # in the FIND_PATH() and FIND_LIBRARY() calls find_package(PkgConfig) if (PKG_CONFIG_FOUND) pkg_check_modules(_FFMPEG_AVCODEC libavcodec) pkg_check_modules(_FFMPEG_AVFORMAT libavformat) pkg_check_modules(_FFMPEG_AVUTIL libavutil) pkg_check_modules(SWSCALE libswscale) endif (PKG_CONFIG_FOUND) find_path(FFMPEG_AVCODEC_INCLUDE_DIR NAMES libavcodec/avcodec.h PATHS ${_FFMPEG_AVCODEC_INCLUDE_DIRS} /usr/include /usr/local/include /opt/local/include /sw/include PATH_SUFFIXES ffmpeg libav ) find_library(FFMPEG_LIBAVCODEC NAMES avcodec PATHS ${_FFMPEG_AVCODEC_LIBRARY_DIRS} /usr/lib /usr/local/lib /opt/local/lib /sw/lib ) find_library(FFMPEG_LIBAVFORMAT NAMES avformat PATHS ${_FFMPEG_AVFORMAT_LIBRARY_DIRS} /usr/lib /usr/local/lib /opt/local/lib /sw/lib ) find_library(FFMPEG_LIBAVUTIL NAMES avutil PATHS ${_FFMPEG_AVUTIL_LIBRARY_DIRS} /usr/lib /usr/local/lib /opt/local/lib /sw/lib ) find_library(FFMPEG_SWSCALE NAMES swscale PATHS ${SWSCALE_LIBRARY_DIRS} /usr/lib /usr/local/lib /opt/local/lib /sw/lib ) if (FFMPEG_LIBAVCODEC AND FFMPEG_LIBAVFORMAT) set(FFMPEG_FOUND TRUE) endif() if (FFMPEG_FOUND) set(FFMPEG_INCLUDE_DIR ${FFMPEG_AVCODEC_INCLUDE_DIR}) set(FFMPEG_LIBRARIES ${FFMPEG_LIBAVCODEC} ${FFMPEG_LIBAVFORMAT} ${FFMPEG_LIBAVUTIL} ${FFMPEG_SWSCALE} ) endif (FFMPEG_FOUND) if (FFMPEG_FOUND) if (NOT FFMPEG_FIND_QUIETLY) message(STATUS "Found FFMPEG or Libav: ${FFMPEG_LIBRARIES}, ${FFMPEG_INCLUDE_DIR}") endif (NOT FFMPEG_FIND_QUIETLY) else (FFMPEG_FOUND) if (FFMPEG_FIND_REQUIRED) message(FATAL_ERROR "Could not find libavcodec or libavformat or libavutil") endif (FFMPEG_FIND_REQUIRED) endif (FFMPEG_FOUND) endif (FFMPEG_LIBRARIES AND FFMPEG_INCLUDE_DIR) ================================================ FILE: cmake/cmake_modules/FindMETIS.cmake ================================================ # -*- mode: cmake -*- # # METIS Find Module for MSTK # Shamelessly stolen from Amanzi open source code https://software.lanl.gov/ascem/trac # # Usage: # Control the search through METIS_DIR or setting environment variable # METIS_ROOT to the METIS installation prefix. # # This module does not search default paths! # # Following variables are set: # METIS_FOUND (BOOL) Flag indicating if METIS was found # METIS_INCLUDE_DIR (PATH) Path to the METIS include file # METIS_INCLUDE_DIRS (LIST) List of all required include files # METIS_LIBRARY_DIR (PATH) Path to the METIS library # METIS_LIBRARY (FILE) METIS library # METIS_LIBRARIES (LIST) List of all required METIS libraries # # ############################################################################# # Standard CMake modules see CMAKE_ROOT/Modules include(FindPackageHandleStandardArgs) # Amanzi CMake functions see /tools/cmake for source # include(PrintVariable) if ( METIS_LIBRARIES AND METIS_INCLUDE_DIRS ) # Do nothing. Variables are set. No need to search again else(METIS_LIBRARIES AND METIS_INCLUDE_DIRS) # Cache variables if(METIS_DIR) set(METIS_DIR "${METIS_DIR}" CACHE PATH "Path to search for METIS include and library files") endif() if(METIS_INCLUDE_DIR) set(METIS_INCLUDE_DIR "${METIS_INCLUDE_DIR}" CACHE PATH "Path to search for METIS include files") endif() if(METIS_LIBRARY_DIR) set(METIS_LIBRARY_DIR "${METIS_LIBRARY_DIR}" CACHE PATH "Path to search for METIS library files") endif() # Search for include files # Search order preference: # (1) METIS_INCLUDE_DIR - check existence of path AND if the include files exist # (2) METIS_DIR/ # (3) Default CMake paths See cmake --html-help=out.html file for more information. # set(metis_inc_names "metis.h") if (METIS_INCLUDE_DIR) if (EXISTS "${METIS_INCLUDE_DIR}") find_path(metis_test_include_path NAMES ${metis_inc_names} HINTS ${METIS_INCLUDE_DIR} NO_DEFAULT_PATH) set(METIS_INCLUDE_DIR "${metis_test_include_path}") endif() else() # Metis sometimes puts the include files in a subdir called Lib set(metis_inc_suffixes "include" "Lib") if(METIS_DIR) if (EXISTS "${METIS_DIR}" ) find_path(METIS_INCLUDE_DIR NAMES ${metis_inc_names} HINTS ${METIS_DIR} PATH_SUFFIXES ${metis_inc_suffixes} NO_DEFAULT_PATH) endif() else() find_path(METIS_INCLUDE_DIR NAMES ${metis_inc_names} PATH_SUFFIXES ${metis_inc_suffixes}) endif() endif() # Search for libraries # Search order preference: # (1) METIS_LIBRARY_DIR - check existence of path AND if the library file exists # (2) METIS_DIR/ # (3) Default CMake paths See cmake --html-help=out.html file for more information. # set(metis_lib_names "metis5" "metis") if (METIS_LIBRARY_DIR) if (EXISTS "${METIS_LIBRARY_DIR}") find_library(METIS_LIBRARY NAMES ${metis_lib_names} HINTS ${METIS_LIBRARY_DIR} NO_DEFAULT_PATH) endif() else() list(APPEND metis_lib_suffixes "lib" "Lib") if(METIS_DIR) if (EXISTS "${METIS_DIR}" ) find_library(METIS_LIBRARY NAMES ${metis_lib_names} HINTS ${METIS_DIR} PATH_SUFFIXES ${metis_lib_suffixes} NO_DEFAULT_PATH) endif() else() find_library(METIS_LIBRARY NAMES ${metis_lib_names} PATH_SUFFIXES ${metis_lib_suffixes}) endif() endif() # Define prerequisite packages set(METIS_INCLUDE_DIRS ${METIS_INCLUDE_DIR}) set(METIS_LIBRARIES ${METIS_LIBRARY}) endif(METIS_LIBRARIES AND METIS_INCLUDE_DIRS ) # Send useful message if everything is found find_package_handle_standard_args(METIS DEFAULT_MSG METIS_LIBRARIES METIS_INCLUDE_DIRS) # find_package_handle_standard_args should set METIS_FOUND but it does not! if ( METIS_LIBRARIES AND METIS_INCLUDE_DIRS) set(METIS_FOUND TRUE) else() set(METIS_FOUND FALSE) endif() # Define the version mark_as_advanced( METIS_INCLUDE_DIR METIS_INCLUDE_DIRS METIS_LIBRARY METIS_LIBRARIES METIS_LIBRARY_DIR ) ================================================ FILE: cmake/cmake_uninstall.cmake.in ================================================ if(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") message(FATAL_ERROR "Cannot find install manifest: @CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") endif(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) string(REGEX REPLACE "\n" ";" files "${files}") foreach(file ${files}) message(STATUS "Uninstalling $ENV{DESTDIR}${file}") if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") exec_program( "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" OUTPUT_VARIABLE rm_out RETURN_VALUE rm_retval ) if(NOT "${rm_retval}" STREQUAL 0) message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}") endif(NOT "${rm_retval}" STREQUAL 0) else(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") message(STATUS "File $ENV{DESTDIR}${file} does not exist.") endif(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") endforeach(file) ================================================ FILE: cmake/external_projects/catch.cmake ================================================ include (ExternalProject) find_program(GIT_EXECUTABLE git) ExternalProject_Add( project_catch PREFIX ${CMAKE_BINARY_DIR}/catch GIT_REPOSITORY https://github.com/catchorg/Catch2.git GIT_TAG v2.13.7 TIMEOUT 10 UPDATE_COMMAND "" # ${GIT_EXECUTABLE} pull CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND "" LOG_DOWNLOAD ON ) # Expose required variable (CATCH_INCLUDE_DIR) to parent scope ExternalProject_Get_Property(project_catch source_dir) set(CATCH_INCLUDE_DIR ${source_dir}/single_include CACHE INTERNAL "Path to include folder for Catch") ================================================ FILE: cmake/external_projects/cgns.cmake ================================================ if(WIN32) ExternalProject_Add(project_win_cgns URL ${CGNS_DOWNLOAD_URL_WIN} UPDATE_COMMAND "" # Disable update BUILD_IN_SOURCE 1 CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND ${CMAKE_COMMAND} -E copy_directory . ${CMAKE_INSTALL_PREFIX} LOG_DOWNLOAD 1 ) list(APPEND NETGEN_DEPENDENCIES project_win_cgns) endif(WIN32) if(APPLE) ExternalProject_Add(project_mac_cgns URL ${CGNS_DOWNLOAD_URL_MAC} UPDATE_COMMAND "" # Disable update BUILD_IN_SOURCE 1 CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND ${CMAKE_COMMAND} -E copy_directory . ${CMAKE_INSTALL_PREFIX} LOG_DOWNLOAD 1 ) list(APPEND NETGEN_DEPENDENCIES project_mac_cgns) list(APPEND NETGEN_CMAKE_ARGS "-DCGNS_INCLUDE_DIR=${CMAKE_INSTALL_PREFIX}/Contents/Resources/include") list(APPEND NETGEN_CMAKE_ARGS "-DCGNS_LIBRARY=${CMAKE_INSTALL_PREFIX}/Contents/MacOS/libcgns.dylib") endif(APPLE) ================================================ FILE: cmake/external_projects/metis.cmake ================================================ set(METIS_SRC_DIR ${CMAKE_CURRENT_BINARY_DIR}/dependencies/src/project_metis) set(METIS_DIR ${CMAKE_CURRENT_BINARY_DIR}/dependencies/metis) ExternalProject_Add(project_metis PREFIX ${CMAKE_CURRENT_BINARY_DIR}/dependencies URL https://bitbucket.org/petsc/pkg-metis/get/v5.1.0-p12.tar.gz URL_MD5 6cd66f75f88dfa2cf043de011f85d8bc DOWNLOAD_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external_dependencies CMAKE_ARGS -DCMAKE_POLICY_VERSION_MINIMUM=3.5 -DGKLIB_PATH=${METIS_SRC_DIR}/GKlib -DCMAKE_INSTALL_PREFIX=${METIS_DIR} -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} UPDATE_COMMAND "" # Disable update BUILD_IN_SOURCE 1 ) set_vars( NETGEN_CMAKE_ARGS METIS_DIR ) list(APPEND NETGEN_DEPENDENCIES project_metis) ================================================ FILE: cmake/external_projects/spdlog.cmake ================================================ include(ExternalProject) find_program(GIT_EXECUTABLE git) ExternalProject_Add( project_spdlog PREFIX ${CMAKE_BINARY_DIR}/spdlog GIT_REPOSITORY https://github.com/gabime/spdlog.git GIT_TAG v1.2.1 TIMEOUT 01 UPDATE_COMMAND "" CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND "" LOG_DOWNLOAD ON ) ExternalProject_Get_Property(project_spdlog source_dir) set(SPDLOG_INCLUDE_DIR ${source_dir}/include) ================================================ FILE: cmake/external_projects/tcltk.cmake ================================================ if(UNIX AND NOT APPLE) set (LINUX TRUE) endif() if(LINUX) find_package(TclStub 8.5 REQUIRED) else(LINUX) if(SKBUILD) # we are building a pip package - download the tcl/tk sources matching the tkinter version (for private headers not shipped with python) execute_process(COMMAND ${Python3_EXECUTABLE} -c "import tkinter;print(tkinter.Tcl().eval('info patchlevel').replace('.','-'))" OUTPUT_VARIABLE PYTHON_TCL_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE) set(TCL_DIR ${CMAKE_CURRENT_BINARY_DIR}/dependencies/src/project_tcl) set(TK_DIR ${CMAKE_CURRENT_BINARY_DIR}/dependencies/src/project_tk) ExternalProject_Add(project_tcl URL "https://github.com/tcltk/tcl/archive/refs/tags/core-${PYTHON_TCL_VERSION}.zip" UPDATE_COMMAND "" CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND "" ${SUBPROJECT_ARGS} DOWNLOAD_DIR download_tcl ) ExternalProject_Add(project_tk URL "https://github.com/tcltk/tk/archive/refs/tags/core-${PYTHON_TCL_VERSION}.zip" UPDATE_COMMAND "" CONFIGURE_COMMAND "" INSTALL_COMMAND "" BUILD_COMMAND ${CMAKE_COMMAND} -E copy_directory macosx generic ${SUBPROJECT_ARGS} DOWNLOAD_DIR download_tk BUILD_IN_SOURCE 1 ) set(TCL_INCLUDE_PATH ${TCL_DIR}/generic) set(TK_INCLUDE_PATH ${TK_DIR}/generic) list(APPEND NETGEN_DEPENDENCIES project_tcl project_tk) if(APPLE OR WIN32) execute_process(COMMAND ${Python3_EXECUTABLE} -c "import sys; print(sys.prefix)" OUTPUT_VARIABLE PYTHON_PREFIX OUTPUT_STRIP_TRAILING_WHITESPACE) file(TO_CMAKE_PATH ${PYTHON_PREFIX} PYTHON_PREFIX) set(tcl_find_args REQUIRED NO_DEFAULT_PATH NO_PACKAGE_ROOT_PATH NO_CMAKE_PATH NO_CMAKE_ENVIRONMENT_PATH NO_SYSTEM_ENVIRONMENT_PATH NO_CMAKE_SYSTEM_PATH NO_CMAKE_FIND_ROOT_PATH HINTS ${PYTHON_PREFIX}/lib ${PYTHON_PREFIX}/tcl ${PYTHON_PREFIX}/Frameworks ${PYTHON_PREFIX}/Frameworks/Tcl.framework ${PYTHON_PREFIX}/Frameworks/Tk.framework ) find_library(TCL_STUB_LIBRARY NAMES tclstub85 tclstub8.5 tclstub86 tclstub8.6 ${tcl_find_args}) find_library(TK_STUB_LIBRARY NAMES tkstub85 tkstub8.5 tkstub86 tkstub8.6 ${tcl_find_args}) find_library(TCL_LIBRARY NAMES tcl85 tcl8.5 tcl86 tcl8.6 tcl86t Tcl ${tcl_find_args}) find_library(TK_LIBRARY NAMES tk85 tk8.5 tk86 tk8.6 tk86t Tk ${tcl_find_args}) else() # use system tcl/tk on linux find_package(TclStub REQUIRED) endif() else(SKBUILD) if(APPLE) set(tcl_prefix ${CMAKE_INSTALL_PREFIX}) # URL "http://sourceforge.net/projects/tcl/files/Tcl/8.6.9/tcl8.6.9-src.tar.gz" # URL_MD5 aa0a121d95a0e7b73a036f26028538d4 ExternalProject_Add(project_tcl URL "https://github.com/NGSolve/tcl/archive/7769161.zip" URL_MD5 1131f188dd26944df557913c475d43b4 DOWNLOAD_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external_dependencies UPDATE_COMMAND "" CONFIGURE_COMMAND ../project_tcl/macosx/configure --enable-threads --enable-framework --prefix=${tcl_prefix} --libdir=${tcl_prefix}/Contents/Frameworks --bindir=${tcl_prefix}/Contents/Frameworks/Tcl.framework/bin BUILD_COMMAND make -j4 binaries libraries INSTALL_COMMAND make install-binaries install-headers install-libraries install-private-headers ${SUBPROJECT_ARGS} ) # URL "http://sourceforge.net/projects/tcl/files/Tcl/8.6.9/tk8.6.9.1-src.tar.gz" # URL_MD5 9efe3976468352dc894dae0c4e785a8e ExternalProject_Add(project_tk DEPENDS project_tcl URL "https://github.com/NGSolve/tk/archive/e7c2bc7.zip" URL_MD5 94044140d4826069c22f1c60cedb6e59 DOWNLOAD_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external_dependencies UPDATE_COMMAND "" CONFIGURE_COMMAND ../project_tk/macosx/configure --enable-aqua=yes --enable-threads --enable-framework --prefix=${tcl_prefix} --libdir=${tcl_prefix}/Contents/Frameworks --bindir=${tcl_prefix}/Contents/Frameworks/Tcl.framework/bin --with-tcl=${tcl_prefix}/Contents/Frameworks/Tcl.framework BUILD_COMMAND make -j4 binaries libraries INSTALL_COMMAND make install-binaries install-headers install-libraries install-private-headers ${SUBPROJECT_ARGS} ) ExternalProject_Add(project_tkdnd URL "https://src.fedoraproject.org/repo/pkgs/tkdnd/tkdnd2.8-src.tar.gz/a6d47a996ea957416469b12965d4db91/tkdnd2.8-src.tar.gz" URL_MD5 a6d47a996ea957416469b12965d4db91 DEPENDS project_tcl project_tk DOWNLOAD_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external_dependencies PATCH_COMMAND patch < ${CMAKE_CURRENT_LIST_DIR}/tkdnd_macosx.patch UPDATE_COMMAND "" # Disable update BUILD_IN_SOURCE 1 CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}/Contents/MacOS -DTCL_INCLUDE_PATH=${CMAKE_INSTALL_PREFIX}/Contents/Frameworks/Tcl.framework/Headers -DTK_INCLUDE_PATH=${CMAKE_INSTALL_PREFIX}/Contents/Frameworks/Tk.framework/Headers -DCMAKE_POLICY_VERSION_MINIMUM=3.5 ${SUBPROJECT_ARGS} ) list(APPEND NETGEN_DEPENDENCIES project_tcl project_tk project_tkdnd) list(APPEND CMAKE_PREFIX_PATH ${CMAKE_INSTALL_PREFIX}/Contents/Frameworks) set(TCL_INCLUDE_PATH ${CMAKE_INSTALL_PREFIX}/Contents/Frameworks/Tcl.framework/Headers) set(TCL_LIBRARY ${CMAKE_INSTALL_PREFIX}/Contents/Frameworks/Tcl.framework) set(TK_LIBRARY ${CMAKE_INSTALL_PREFIX}/Contents/Frameworks/Tk.framework) set(TK_INCLUDE_PATH ${CMAKE_INSTALL_PREFIX}/Contents/Frameworks/Tk.framework/Headers) set(TCL_STUB_LIBRARY ${CMAKE_INSTALL_PREFIX}/Contents/Frameworks/Tcl.framework/libtclstub8.6.a) set(TK_STUB_LIBRARY ${CMAKE_INSTALL_PREFIX}/Contents/Frameworks/Tk.framework/libtkstub8.6.a) # # use system tcl/tk # if((${PYTHON_VERSION_STRING} VERSION_EQUAL "3.7") OR (${PYTHON_VERSION_STRING} VERSION_GREATER "3.7")) # # fetch tcl/tk sources to match the one used in Python 3.7 # ExternalProject_Add(project_tcl # URL "https://prdownloads.sourceforge.net/tcl/tcl8.6.8-src.tar.gz" # URL_MD5 81656d3367af032e0ae6157eff134f89 # DOWNLOAD_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external_dependencies # UPDATE_COMMAND "" # Disable update # CONFIGURE_COMMAND "" # BUILD_COMMAND "" # INSTALL_COMMAND "" # ) # ExternalProject_Add(project_tk # URL "https://prdownloads.sourceforge.net/tcl/tk8.6.8-src.tar.gz" # URL_MD5 5e0faecba458ee1386078fb228d008ba # DOWNLOAD_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external_dependencies # UPDATE_COMMAND "" # Disable update # CONFIGURE_COMMAND "" # BUILD_COMMAND "" # INSTALL_COMMAND "" # ) # # get_filename_component(PYTHON_LIB_DIR ${PYTHON_LIBRARY} DIRECTORY) # find_library(TCL_LIBRARY libtcl8.6.dylib PATHS ${PYTHON_LIB_DIR} NO_DEFAULT_PATH) # find_library(TK_LIBRARY libtk8.6.dylib PATHS ${PYTHON_LIB_DIR} NO_DEFAULT_PATH) # # set(TCL_DIR ${CMAKE_CURRENT_BINARY_DIR}/dependencies/src/project_tcl) # set(TK_DIR ${CMAKE_CURRENT_BINARY_DIR}/dependencies/src/project_tk) # set(TCL_INCLUDE_PATH "${TCL_DIR}/generic;${TCL_DIR}/macosx") # set(TK_INCLUDE_PATH "${TK_DIR}/generic;${TK_DIR}/macosx;${TK_DIR}/xlib") # string(REPLACE ";" "$" TCL_INC "${TCL_INCLUDE_PATH}") # string(REPLACE ";" "$" TK_INC "${TK_INCLUDE_PATH}") # # ExternalProject_Add(project_tkdnd # URL "http://sourceforge.net/projects/tkdnd/files/TkDND/TkDND%202.8/tkdnd2.8-src.tar.gz" # URL_MD5 a6d47a996ea957416469b12965d4db91 # DEPENDS project_tcl project_tk # DOWNLOAD_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external_dependencies # PATCH_COMMAND patch < ${CMAKE_CURRENT_LIST_DIR}/tkdnd_macosx.patch # UPDATE_COMMAND "" # Disable update # BUILD_IN_SOURCE 1 # CMAKE_ARGS # -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}/Contents/MacOS # -DTCL_INCLUDE_PATH=${TCL_INC} # -DTK_INCLUDE_PATH=${TK_INC} # -DTK_LIBRARY=${TK_LIBRARY} # -DTCL_LIBRARY=${TCL_LIBRARY} # LOG_DOWNLOAD 1 # LOG_CONFIGURE 1 # LOG_BUILD 1 # LOG_INSTALL 1 # ) # # list(APPEND NETGEN_DEPENDENCIES project_tkdnd) # else() # find_package(TCL 8.5 REQUIRED) # endif() elseif(WIN32) ExternalProject_Add(project_win_tcltk URL ${TCLTK_DOWNLOAD_URL_WIN} UPDATE_COMMAND "" # Disable update BUILD_IN_SOURCE 1 CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND ${CMAKE_COMMAND} -E copy_directory lib ${CMAKE_INSTALL_PREFIX}/${NG_INSTALL_DIR_LIB} COMMAND ${CMAKE_COMMAND} -E copy_directory bin ${CMAKE_INSTALL_PREFIX}/${NG_INSTALL_DIR_BIN} COMMAND ${CMAKE_COMMAND} -E copy_directory include ${CMAKE_INSTALL_PREFIX}/${NG_INSTALL_DIR_INCLUDE} ${SUBPROJECT_ARGS} ) set (TK_INCLUDE_PATH ${CMAKE_INSTALL_PREFIX}/include) set (TCL_INCLUDE_PATH ${CMAKE_INSTALL_PREFIX}/include) set (TCL_LIBRARY ${CMAKE_INSTALL_PREFIX}/lib/tcl86t.lib) set (TK_LIBRARY ${CMAKE_INSTALL_PREFIX}/lib/tk86t.lib) set (TCL_STUB_LIBRARY ${CMAKE_INSTALL_PREFIX}/lib/tclstub86.lib) set (TK_STUB_LIBRARY ${CMAKE_INSTALL_PREFIX}/lib/tkstub86.lib) list(APPEND NETGEN_DEPENDENCIES project_win_tcltk) else(WIN32) find_package(TCL 8.5 REQUIRED) # ExternalProject_Add(project_tkdnd # GIT_REPOSITORY https://github.com/petasis/tkdnd.git # GIT_TAG d7cfd96087b248255da5349086ef70cc4bbfb619 # PREFIX ${CMAKE_CURRENT_BINARY_DIR}/tkdnd # CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}/lib # UPDATE_COMMAND "" # LOG_DOWNLOAD 1 # LOG_BUILD 1 # LOG_INSTALL 1 # ) # list(APPEND NETGEN_DEPENDENCIES project_tkdnd) endif(APPLE) endif(SKBUILD) endif(LINUX) # Propagate settings to Netgen subproject set_vars(NETGEN_CMAKE_ARGS TCL_INCLUDE_PATH TCL_STUB_LIBRARY TCL_LIBRARY TK_STUB_LIBRARY TK_LIBRARY TK_INCLUDE_PATH TCL_TCLSH TK_WISH) ================================================ FILE: cmake/external_projects/zlib.cmake ================================================ if(WIN32) ExternalProject_Add(project_win_zlib URL ${ZLIB_DOWNLOAD_URL_WIN} UPDATE_COMMAND "" # Disable update BUILD_IN_SOURCE 1 CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND ${CMAKE_COMMAND} -E copy_directory lib ${CMAKE_INSTALL_PREFIX}/${NG_INSTALL_DIR_LIB} COMMAND ${CMAKE_COMMAND} -E copy_directory bin ${CMAKE_INSTALL_PREFIX}/${NG_INSTALL_DIR_BIN} COMMAND ${CMAKE_COMMAND} -E copy_directory include ${CMAKE_INSTALL_PREFIX}/${NG_INSTALL_DIR_INCLUDE} LOG_DOWNLOAD 1 ) list(APPEND NETGEN_DEPENDENCIES project_win_zlib) endif(WIN32) ================================================ FILE: cmake/generate_version_file.cmake ================================================ if(NOT BDIR) set(BDIR ${CMAKE_CURRENT_BINARY_DIR}) endif() if(NETGEN_VERSION_GIT) set(git_version_string ${NETGEN_VERSION_GIT}) else() find_package(Git REQUIRED) execute_process(COMMAND git describe --tags --match "v[0-9]*" --long --dirty WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} OUTPUT_VARIABLE git_version_string RESULT_VARIABLE status ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE ) endif() if(status AND NOT status EQUAL 0) if(EXISTS ${CMAKE_CURRENT_LIST_DIR}/../version.txt) # for source package files (generated for ubuntu builds on launchpad) read the version from version.txt if(EXISTS ${CMAKE_CURRENT_LIST_DIR}/../version.txt) file(READ ${CMAKE_CURRENT_LIST_DIR}/../version.txt git_version_string ) else() get_filename_component(git_version_string ${CMAKE_CURRENT_LIST_DIR}/.. NAME) string(REGEX REPLACE "^netgen(.*)" "\\1" git_version_string "${git_version_string}") endif() else() MESSAGE(WARNING "Could not determine git-version from source code - assuming 6.2.0-0") set(git_version_string "v6.2.0-0") endif() endif() string(STRIP ${git_version_string} git_version_string) string(REGEX REPLACE "^v([0-9]+)\\..*" "\\1" NETGEN_VERSION_MAJOR "${git_version_string}") string(REGEX REPLACE "^v[0-9]+\\.([0-9]+).*" "\\1" NETGEN_VERSION_MINOR "${git_version_string}") string(REGEX REPLACE "^v[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" NETGEN_VERSION_PATCH "${git_version_string}") string(REGEX REPLACE "^v[0-9]+\\.[0-9]+\\.[0-9]+\\-([0-9]+).*" "\\1" NETGEN_VERSION_TWEAK "${git_version_string}") string(REGEX REPLACE "^v[0-9]+\\.[0-9]+\\.[0-9]+\\-[0-9]+\\-([0-9a-z]+).*" "\\1" NETGEN_VERSION_HASH "${git_version_string}") set(NETGEN_VERSION_SHORT ${NETGEN_VERSION_MAJOR}.${NETGEN_VERSION_MINOR}.${NETGEN_VERSION_PATCH}) set(NETGEN_VERSION_LONG ${NETGEN_VERSION_SHORT}-${NETGEN_VERSION_TWEAK}-${NETGEN_VERSION_HASH}) if(NETGEN_VERSION_TWEAK) # no release version - nightly build set(NETGEN_VERSION ${NETGEN_VERSION_LONG}) else() # TWEAK is 0 -> current version has a tag assigned set(NETGEN_VERSION ${NETGEN_VERSION_SHORT}) endif() set(NETGEN_VERSION_LONG ${NETGEN_VERSION_SHORT}-${NETGEN_VERSION_TWEAK}-${NETGEN_VERSION_HASH}) if(NOT NETGEN_VERSION_GIT) set(NETGEN_VERSION_GIT ${NETGEN_VERSION_LONG}) endif() if(NOT NETGEN_VERSION_PYTHON) set(NETGEN_VERSION_PYTHON ${NETGEN_VERSION_TWEAK}) endif() set(version_file ${BDIR}/netgen_version.hpp) set(new_version_file_string "\ #ifndef NETGEN_VERSION_HPP_INCLUDED #define NETGEN_VERSION_HPP_INCLUDED #define NETGEN_VERSION \"${NETGEN_VERSION}\" #define NETGEN_VERSION_MAJOR ${NETGEN_VERSION_MAJOR} #define NETGEN_VERSION_MINOR ${NETGEN_VERSION_MINOR} #define NETGEN_VERSION_PATCH ${NETGEN_VERSION_PATCH} #define NETGEN_VERSION_TWEAK ${NETGEN_VERSION_TWEAK} #define NETGEN_VERSION_HASH \"${NETGEN_VERSION_HASH}\" #endif // NETGEN_VERSION_HPP_INCLUDED ") if(EXISTS ${version_file}) file(READ ${version_file} old_version_file_string ) if(${old_version_file_string} STREQUAL ${new_version_file_string}) else() file(WRITE ${BDIR}/netgen_version.hpp ${new_version_file_string}) endif() else() file(WRITE ${BDIR}/netgen_version.hpp ${new_version_file_string}) endif() file(GENERATE OUTPUT netgen_config.hpp CONTENT "\ #ifndef NETGEN_CONFIG_HPP_INCLUDED___ #define NETGEN_CONFIG_HPP_INCLUDED___ #define NETGEN_USE_NATIVE_ARCH $ #define NETGEN_USE_GUI $ #define NETGEN_USE_PYTHON $ #define NETGEN_USE_MPI $ #define NETGEN_USE_MPI4PY $ #define NETGEN_USE_OCC $ #define NETGEN_USE_JPEG $ #define NETGEN_USE_MPEG $ #define NETGEN_USE_CGNS $ #define NETGEN_USE_NUMA $ #define NETGEN_INTEL_MIC $ #define NETGEN_INSTALL_PROFILES $ #define NETGEN_USE_CCACHE $ #define NETGEN_USE_INTERNAL_TCL $ #define NETGEN_ENABLE_UNIT_TESTS $ #define NETGEN_ENABLE_CPP_CORE_GUIDELINES_CHECK $ #define NETGEN_USE_SPDLOG $ #define NETGEN_DEBUG_LOG $ #define NETGEN_USE_CHECK_RANGE $ #define NETGEN_BUILD_STUB_FILES $ #define NETGEN_BUILD_FOR_CONDA $ #define NETGEN_SHARED_LIBRARY_SUFFIX \"${CMAKE_SHARED_LIBRARY_SUFFIX}\" #endif // NETGEN_CONFIG_HPP_INCLUDED___ ") ================================================ FILE: cmake/mic.cmake ================================================ set(CMAKE_SYSTEM_NAME Linux) set(CMAKE_SYSTEM_PROCESSOR k1om) set(CMAKE_SYSTEM_VERSION 1) # specify the cross compiler set(CMAKE_C_COMPILER icc) set(CMAKE_CXX_COMPILER icpc) set(MPI_C_COMPILER mpiicc) set(_CMAKE_TOOLCHAIN_PREFIX x86_64-k1om-linux-) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mmic") set(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} -limf -lsvml -lirng -lintlc") # where is the target environment set(CMAKE_FIND_ROOT_PATH /usr/linux-k1om-4.7) ================================================ FILE: cmake/netgen_fixup.cmake ================================================ include(BundleUtilities) function(netgen_fixup_bundle app libs dirs) message(STATUS "fixup_bundle") message(STATUS " app='${app}'") message(STATUS " libs='${libs}'") message(STATUS " dirs='${dirs}'") get_bundle_and_executable("${app}" bundle executable valid) if(valid) get_filename_component(exepath "${executable}" PATH) message(STATUS "fixup_bundle: preparing...") get_bundle_keys("${app}" "${libs}" "${dirs}" keys) message(STATUS "fixup_bundle: copying...") list(LENGTH keys n) math(EXPR n ${n}*2) set(i 0) foreach(key ${keys}) math(EXPR i ${i}+1) if(${${key}_COPYFLAG}) set(item "${${key}_ITEM}") if(item MATCHES "[^/]+\\.framework/") copy_resolved_framework_into_bundle("${${key}_RESOLVED_ITEM}" "${${key}_RESOLVED_EMBEDDED_ITEM}") else() copy_resolved_item_into_bundle("${${key}_RESOLVED_ITEM}" "${${key}_RESOLVED_EMBEDDED_ITEM}") endif() endif() endforeach() message(STATUS "fixup_bundle: fixing...") foreach(key ${keys}) math(EXPR i ${i}+1) message(STATUS "${i}/${n}: fixing up '${${key}_RESOLVED_EMBEDDED_ITEM}'") fixup_bundle_item("${${key}_RESOLVED_EMBEDDED_ITEM}" "${exepath}" "${dirs}") endforeach() message(STATUS "fixup_bundle: cleaning up...") clear_bundle_keys(keys) else() message(SEND_ERROR "error: fixup_bundle: not a valid bundle") endif() message(STATUS "fixup_bundle: done") endfunction() ================================================ FILE: depcomp ================================================ #! /bin/sh # depcomp - compile a program generating dependencies as side-effects # Copyright 1999, 2000 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA # 02111-1307, USA. # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Alexandre Oliva . if test -z "$depmode" || test -z "$source" || test -z "$object"; then echo "depcomp: Variables source, object and depmode must be set" 1>&2 exit 1 fi # `libtool' can also be set to `yes' or `no'. depfile=${depfile-`echo "$object" | sed 's,\([^/]*\)$,.deps/\1,;s/\.\([^.]*\)$/.P\1/'`} tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} rm -f "$tmpdepfile" # Some modes work just like other modes, but use different flags. We # parameterize here, but still list the modes in the big case below, # to make depend.m4 easier to write. Note that we *cannot* use a case # here, because this file can only contain one case statement. if test "$depmode" = hp; then # HP compiler uses -M and no extra arg. gccflag=-M depmode=gcc fi if test "$depmode" = dashXmstdout; then # This is just like dashmstdout with a different argument. dashmflag=-xM depmode=dashmstdout fi case "$depmode" in gcc3) ## gcc 3 implements dependency tracking that does exactly what ## we want. Yay! Note: for some reason libtool 1.4 doesn't like ## it if -MD -MP comes after the -MF stuff. Hmm. "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi mv "$tmpdepfile" "$depfile" ;; gcc) ## There are various ways to get dependency output from gcc. Here's ## why we pick this rather obscure method: ## - Don't want to use -MD because we'd like the dependencies to end ## up in a subdir. Having to rename by hand is ugly. ## (We might end up doing this anyway to support other compilers.) ## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like ## -MM, not -M (despite what the docs say). ## - Using -M directly means running the compiler twice (even worse ## than renaming). if test -z "$gccflag"; then gccflag=-MD, fi "$@" -Wp,"$gccflag$tmpdepfile" stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz ## The second -e expression handles DOS-style file names with drive letters. sed -e 's/^[^:]*: / /' \ -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" ## This next piece of magic avoids the `deleted header file' problem. ## The problem is that when a header file which appears in a .P file ## is deleted, the dependency causes make to die (because there is ## typically no way to rebuild the header). We avoid this by adding ## dummy dependencies for each header file. Too bad gcc doesn't do ## this for us directly. tr ' ' ' ' < "$tmpdepfile" | ## Some versions of gcc put a space before the `:'. On the theory ## that the space means something, we add a space to the output as ## well. ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; sgi) if test "$libtool" = yes; then "$@" "-Wp,-MDupdate,$tmpdepfile" else "$@" -MDupdate "$tmpdepfile" fi stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files echo "$object : \\" > "$depfile" # Clip off the initial element (the dependent). Don't try to be # clever and replace this with sed code, as IRIX sed won't handle # lines with more than a fixed number of characters (4096 in # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; # the IRIX cc adds comments like `#:fec' to the end of the # dependency line. tr ' ' ' ' < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \ tr ' ' ' ' >> $depfile echo >> $depfile # The second pass generates a dummy entry for each header file. tr ' ' ' ' < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ >> $depfile else # The sourcefile does not contain any dependencies, so just # store a dummy comment line, to avoid errors with the Makefile # "include basename.Plo" scheme. echo "#dummy" > "$depfile" fi rm -f "$tmpdepfile" ;; aix) # The C for AIX Compiler uses -M and outputs the dependencies # in a .u file. This file always lives in the current directory. # Also, the AIX compiler puts `$object:' at the start of each line; # $object doesn't have directory information. stripped=`echo "$object" | sed -e 's,^.*/,,' -e 's/\(.*\)\..*$/\1/'` tmpdepfile="$stripped.u" outname="$stripped.o" if test "$libtool" = yes; then "$@" -Wc,-M else "$@" -M fi stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi if test -f "$tmpdepfile"; then # Each line is of the form `foo.o: dependent.h'. # Do two passes, one to just change these to # `$object: dependent.h' and one to simply `dependent.h:'. sed -e "s,^$outname:,$object :," < "$tmpdepfile" > "$depfile" sed -e "s,^$outname: \(.*\)$,\1:," < "$tmpdepfile" >> "$depfile" else # The sourcefile does not contain any dependencies, so just # store a dummy comment line, to avoid errors with the Makefile # "include basename.Plo" scheme. echo "#dummy" > "$depfile" fi rm -f "$tmpdepfile" ;; icc) # Must come before tru64. # Intel's C compiler understands `-MD -MF file'. However # icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c # will fill foo.d with something like # foo.o: sub/foo.c # foo.o: sub/foo.h # which is wrong. We want: # sub/foo.o: sub/foo.c # sub/foo.o: sub/foo.h # sub/foo.c: # sub/foo.h: "$@" -MD -MF "$tmpdepfile" stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each line is of the form `foo.o: dependent.h'. # Do two passes, one to just change these to # `$object: dependent.h' and one to simply `dependent.h:'. sed -e "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" sed -e "s,^[^:]*: \(.*\)$,\1:," < "$tmpdepfile" >> "$depfile" rm -f "$tmpdepfile" ;; tru64) # The Tru64 AIX compiler uses -MD to generate dependencies as a side # effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'. # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put # dependencies in `foo.d' instead, so we check for that too. # Subdirectories are respected. tmpdepfile1="$object.d" tmpdepfile2=`echo "$object" | sed -e 's/.o$/.d/'` if test "$libtool" = yes; then "$@" -Wc,-MD else "$@" -MD fi stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile1" "$tmpdepfile2" exit $stat fi if test -f "$tmpdepfile1"; then tmpdepfile="$tmpdepfile1" else tmpdepfile="$tmpdepfile2" fi if test -f "$tmpdepfile"; then sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" # That's a space and a tab in the []. sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" else echo "#dummy" > "$depfile" fi rm -f "$tmpdepfile" ;; #nosideeffect) # This comment above is used by automake to tell side-effect # dependency tracking mechanisms from slower ones. dashmstdout) # Important note: in order to support this mode, a compiler *must* # always write the proprocessed file to stdout, regardless of -o, # because we must use -o when running libtool. test -z "$dashmflag" && dashmflag=-M ( IFS=" " case " $* " in *" --mode=compile "*) # this is libtool, let us make it quiet for arg do # cycle over the arguments case "$arg" in "--mode=compile") # insert --quiet before "--mode=compile" set fnord "$@" --quiet shift # fnord ;; esac set fnord "$@" "$arg" shift # fnord shift # "$arg" done ;; esac "$@" $dashmflag | sed 's:^[^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile" ) & proc=$! "$@" stat=$? wait "$proc" if test "$stat" != 0; then exit $stat; fi rm -f "$depfile" cat < "$tmpdepfile" > "$depfile" tr ' ' ' ' < "$tmpdepfile" | \ ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; dashXmstdout) # This case only exists to satisfy depend.m4. It is never actually # run, as this mode is specially recognized in the preamble. exit 1 ;; makedepend) # X makedepend ( shift cleared=no for arg in "$@"; do case $cleared in no) set ""; shift cleared=yes esac case "$arg" in -D*|-I*) set fnord "$@" "$arg"; shift;; -*) ;; *) set fnord "$@" "$arg"; shift;; esac done obj_suffix="`echo $object | sed 's/^.*\././'`" touch "$tmpdepfile" ${MAKEDEPEND-makedepend} 2>/dev/null -o"$obj_suffix" -f"$tmpdepfile" "$@" ) & proc=$! "$@" stat=$? wait "$proc" if test "$stat" != 0; then exit $stat; fi rm -f "$depfile" cat < "$tmpdepfile" > "$depfile" tail +3 "$tmpdepfile" | tr ' ' ' ' | \ ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" "$tmpdepfile".bak ;; cpp) # Important note: in order to support this mode, a compiler *must* # always write the proprocessed file to stdout, regardless of -o, # because we must use -o when running libtool. ( IFS=" " case " $* " in *" --mode=compile "*) for arg do # cycle over the arguments case $arg in "--mode=compile") # insert --quiet before "--mode=compile" set fnord "$@" --quiet shift # fnord ;; esac set fnord "$@" "$arg" shift # fnord shift # "$arg" done ;; esac "$@" -E | sed -n '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' | sed '$ s: \\$::' > "$tmpdepfile" ) & proc=$! "$@" stat=$? wait "$proc" if test "$stat" != 0; then exit $stat; fi rm -f "$depfile" echo "$object : \\" > "$depfile" cat < "$tmpdepfile" >> "$depfile" sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; msvisualcpp) # Important note: in order to support this mode, a compiler *must* # always write the proprocessed file to stdout, regardless of -o, # because we must use -o when running libtool. ( IFS=" " case " $* " in *" --mode=compile "*) for arg do # cycle over the arguments case $arg in "--mode=compile") # insert --quiet before "--mode=compile" set fnord "$@" --quiet shift # fnord ;; esac set fnord "$@" "$arg" shift # fnord shift # "$arg" done ;; esac "$@" -E | sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::echo "`cygpath -u \\"\1\\"`":p' | sort | uniq > "$tmpdepfile" ) & proc=$! "$@" stat=$? wait "$proc" if test "$stat" != 0; then exit $stat; fi rm -f "$depfile" echo "$object : \\" > "$depfile" . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile" echo " " >> "$depfile" . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::\1\::p' >> "$depfile" rm -f "$tmpdepfile" ;; none) exec "$@" ;; *) echo "Unknown depmode $depmode" 1>&2 exit 1 ;; esac exit 0 ================================================ FILE: doc/CMakeLists.txt ================================================ INSTALL(FILES ng4.pdf DESTINATION ${NG_INSTALL_DIR_RES}/${NG_INSTALL_SUFFIX}/doc COMPONENT netgen_doc) ================================================ FILE: doc/element_types.tex ================================================ \documentclass[convert=pdf2svg]{standalone} % \documentclass{article} \usepackage[T1]{fontenc} \usepackage{lmodern} \renewcommand{\familydefault}{\sfdefault} \usepackage{tikz} \usepackage{tikz-3dplot} \usetikzlibrary{external} \tikzset{external/force remake} \tikzset{external/disable dependency files} \tikzset{external/aux in dpth={false}} % uncomment this to generate a figure for each cell type (and change documentclass to article) % \tikzexternalize \tikzstyle{vertex} = [circle,draw=black,fill=black,scale = 0.5] \tdplotsetmaincoords{70}{110} % cnode(tag,x,y,z,label,label_pos) \def\cnode(#1,#2,#3,#4,#5,#6){ \node (#1) at (#2,#3,#4) [vertex,label=#6:$\mathsf{#5}$] {}; } \pagestyle{empty} \begin{document} \begin{tabular}{cc} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% SEGMENT & SEGMENT3 \\ \tikzsetnextfilename{line} \begin{tikzpicture}[scale = 2] \cnode(n0,0,0,0,1,below right); \cnode(n1,2,0,0,2,below right); \draw (n0) -- (n1); \end{tikzpicture} & \tikzsetnextfilename{line3} \begin{tikzpicture}[scale = 2] \cnode(n0,0,0,0,1,below right); \cnode(n1,2,0,0,2,below right); \cnode(n2,1,0,0,3,below right); \draw (n0) -- (n2) -- (n1); \end{tikzpicture} \\[1 em] %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% TRIG & TRIG6 \\ \tikzsetnextfilename{triangle} \begin{tikzpicture}[scale = 2] \cnode(n0,0,0,0,1,below right); \cnode(n1,2,0,0,2,below right); \cnode(n2,0,2,0,3,right); \draw (n0) -- (n1) -- (n2) -- (n0); \end{tikzpicture} & \tikzsetnextfilename{triangle6} \begin{tikzpicture}[scale = 2] \cnode(n0,0,0,0,1,below right); \cnode(n1,2,0,0,2,below right); \cnode(n2,0,2,0,3,right); \cnode(n3,1,0,0,6,below right); \cnode(n4,1,1,0,4,right); \cnode(n5,0,1,0,5,below right); \draw (n0) -- (n3) -- (n1) -- (n4) -- (n2) -- (n5) -- (n0); \end{tikzpicture} \\[1 em] %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% QUAD & QUAD8 \\ \tikzsetnextfilename{quad} \begin{tikzpicture}[scale = 2] \cnode(n0,0,0,0,1,below right); \cnode(n1,2,0,0,2,below right); \cnode(n2,2,2,0,3,below right); \cnode(n3,0,2,0,4,below right); \draw (n0) -- (n1) -- (n2) -- (n3) -- (n0); \end{tikzpicture} & \tikzsetnextfilename{quad8} \begin{tikzpicture}[scale = 2] \cnode(n0,0,0,0,1,below right); \cnode(n1,2,0,0,2,below right); \cnode(n2,2,2,0,3,below right); \cnode(n3,0,2,0,4,below right); \cnode(n4,1,0,0,5,below right); \cnode(n5,2,1,0,8,below right); \cnode(n6,1,2,0,6,below right); \cnode(n7,0,1,0,7,below right); \draw (n0) -- (n4) -- (n1) -- (n5) -- (n2) -- (n6) -- (n3) -- (n7) -- (n0); \end{tikzpicture} \\[1 em] %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% TET & TET10 \\ \tikzsetnextfilename{tetra} \begin{tikzpicture}[scale = 2, tdplot_main_coords] \cnode(n0,0,0,0,1,below right); \cnode(n1,2,0,0,3,below right); \cnode(n2,0,2,0,2,below right); \cnode(n3,0,0,2,4,right); \draw (n0) -- (n1) -- (n2) -- (n0); \draw (n0) -- (n3); \draw (n1) -- (n3); \draw (n2) -- (n3); \end{tikzpicture} & \tikzsetnextfilename{tetra10} % VTK \begin{tikzpicture}[scale = 2, tdplot_main_coords] \cnode(n0,0,0,0,1,below right); \cnode(n1,2,0,0,3,below right); \cnode(n2,0,2,0,2,below right); \cnode(n3,0,0,2,4,right); \cnode(n4,1,0,0,6,below right); \cnode(n5,1,1,0,8,below right); \cnode(n6,0,1,0,5,below right); \cnode(n7,0,0,1,7,below right); \cnode(n8,1,0,1,10,below right); \cnode(n9,0,1,1,9,right); \draw (n0) -- (n4) -- (n1) -- (n5) -- (n2) -- (n6) -- (n0); \draw (n0) -- (n7) -- (n3); \draw (n1) -- (n8) -- (n3); \draw (n2) -- (n9) -- (n3); \end{tikzpicture} \\[1 em] %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% PYRAMID & PYRAMID13 \\ \tikzsetnextfilename{pyramid} \begin{tikzpicture}[scale = 2, tdplot_main_coords] \cnode(n0,0,0,0,1,below right); \cnode(n1,2,0,0,4,below right); \cnode(n2,2,2,0,3,below right); \cnode(n3,0,2,0,2,below right); \cnode(n4,1,1,2,5,right); \draw (n0) -- (n1) -- (n2) -- (n3) -- (n0); \draw (n0) -- (n4); \draw (n1) -- (n4); \draw (n2) -- (n4); \draw (n3) -- (n4); \end{tikzpicture} & \tikzsetnextfilename{pyramid13} % VTK != gmsh \begin{tikzpicture}[scale = 2, tdplot_main_coords] \cnode(n0,0,0,0,1,below right); \cnode(n1,2,0,0,4,below right); \cnode(n2,2,2,0,3,below right); \cnode(n3,0,2,0,2,below right); \cnode(n4,1,1,2,5,right); \cnode(n5,1,0,0,8,below right); \cnode(n6,2,1,0,7,below right); \cnode(n7,1,2,0,9,below right); \cnode(n8,0,1,0,6,below right); \cnode(n9,0.5,0.5,1,10,below right); \cnode(n10,1.5,0.5,1,13,below right); \cnode(n11,1.5,1.5,1,12,below right); \cnode(n12,0.5,1.5,1,11,right); \draw (n0) -- (n5) -- (n1) -- (n6) -- (n2) -- (n7) -- (n3) -- (n8) -- (n0); \draw (n0) -- (n9) -- (n4); \draw (n1) -- (n10) -- (n4); \draw (n2) -- (n11) -- (n4); \draw (n3) -- (n12) -- (n4); \end{tikzpicture} \\[1 em] %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% PRISM & PRISM15 \\ \tikzsetnextfilename{wedge} % gmsh != VTK \begin{tikzpicture}[scale = 2, tdplot_main_coords] \cnode(n0,0,0,0,1,below right); \cnode(n1,2,0,0,3,below right); \cnode(n2,0,2,0,2,below right); \cnode(n3,0,0,2,4,below right); \cnode(n4,2,0,2,6,below right); \cnode(n5,0,2,2,5,below right); \draw (n0) -- (n1) -- (n2) -- (n0); \draw (n3) -- (n4) -- (n5) -- (n3); \draw (n0) -- (n3); \draw (n1) -- (n4); \draw (n2) -- (n5); \end{tikzpicture} & \tikzsetnextfilename{wedge15} % VTK != gmsh \begin{tikzpicture}[scale = 2, tdplot_main_coords] \cnode(n0,0,0,0,1,below right); \cnode(n1,2,0,0,3,below right); \cnode(n2,0,2,0,2,below right); \cnode(n3,0,0,2,4,below right); \cnode(n4,2,0,2,6,below right); \cnode(n5,0,2,2,5,below right); \cnode(n6,1,0,0,8,below right); \cnode(n7,1,1,0,9,below right); \cnode(n8,0,1,0,7,below right); \cnode(n9,1,0,2,14,below right); \cnode(n10,1,1,2,15,below right); \cnode(n11,0,1,2,13,below right); \cnode(n12,0,0,1,10,below right); \cnode(n13,2,0,1,12,below right); \cnode(n14,0,2,1,11,below right); \draw (n0) -- (n6) -- (n1) -- (n7) -- (n2) -- (n8) -- (n0); \draw (n3) -- (n9) -- (n4) -- (n10) -- (n5) -- (n11) -- (n3); \draw (n0) -- (n12) -- (n3); \draw (n1) -- (n13) -- (n4); \draw (n2) -- (n14) -- (n5); \end{tikzpicture} \\[1 em] %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% HEX & HEX20 \\ \tikzsetnextfilename{hexahedron} \begin{tikzpicture}[scale = 2, tdplot_main_coords] \cnode(n0,0,0,0,1,below right); \cnode(n1,2,0,0,4,below right); \cnode(n2,2,2,0,3,below right); \cnode(n3,0,2,0,2,below right); \cnode(n4,0,0,2,5,below right); \cnode(n5,2,0,2,8,below right); \cnode(n6,2,2,2,7,below right); \cnode(n7,0,2,2,6,below right); \draw (n0) -- (n1) -- (n2) -- (n3) -- (n0); \draw (n4) -- (n5) -- (n6) -- (n7) -- (n4); \draw (n0) -- (n4); \draw (n1) -- (n5); \draw (n2) -- (n6); \draw (n3) -- (n7); \end{tikzpicture} & \tikzsetnextfilename{hexahedron20} % VTK != gmsh \begin{tikzpicture}[scale = 2, tdplot_main_coords] \cnode(n0,0,0,0,1,below right); \cnode(n1,2,0,0,4,below right); \cnode(n2,2,2,0,3,below right); \cnode(n3,0,2,0,2,below right); \cnode(n4,0,0,2,5,below right); \cnode(n5,2,0,2,8,below right); \cnode(n6,2,2,2,7,below right); \cnode(n7,0,2,2,6,below right); \cnode(n8,1,0,0,11,below right); \cnode(n9,2,1,0,10,below right); \cnode(n10,1,2,0,12,below right); \cnode(n11,0,1,0,9,below right); \cnode(n12,1,0,2,15,below right); \cnode(n13,2,1,2,14,below right); \cnode(n14,1,2,2,16,below right); \cnode(n15,0,1,2,13,below right); \cnode(n16,0,0,1,17,below right); \cnode(n17,2,0,1,20,below right); \cnode(n18,2,2,1,19,below right); \cnode(n19,0,2,1,18,below right); \draw (n0) -- (n8) -- (n1) -- (n9) -- (n2) -- (n10) -- (n3) -- (n11) -- (n0); \draw (n4) -- (n12) -- (n5) -- (n13) -- (n6) -- (n14) -- (n7) -- (n15) -- (n4); \draw (n0) -- (n16) -- (n4); \draw (n1) -- (n17) -- (n5); \draw (n2) -- (n18) -- (n6); \draw (n3) -- (n19) -- (n7); \end{tikzpicture} \end{tabular} \end{document} ================================================ FILE: doc/ng4.tex ================================================ % % Requires latex and latex2html packages % % Generate pdf-file with % pdflatex ng4.tex % % Generate html docu with % latex2html ng4.tex % \documentclass[12pt]{book} \usepackage{a4, epsf, graphicx} \usepackage{html} \title{NETGEN - 4.X} \author{Joachim Sch\"oberl} \unitlength=1cm \begin{document} \maketitle \tableofcontents \chapter{Getting Started} WARNING: DOCUMENTATION IS NOT UP TO DATE \section{What is NETGEN} NETGEN is an automatic mesh generation tool for two and three dimensions. Netgen is open source under the conditions of the LGPL. It comes as stand alone programme with graphical user interface, or as C++ library to be linked into an other application. Netgen is available for Unix/Linux and Windows 98/NT. Netgen generates triangular or quadrilateral meshes in 2D, and tetrahedral meshes in 3D. The input for 2D is described by spline curves, and the input for 3D problems is either defined by constructive solid geometries (CSG), see Chapter \ref{chap_csg}, or by the standard STL file format. NETGEN contains modules for mesh optimization and hierarchical mesh refinement. Curved elements are supported of arbitrary order. \section{The history of NETGEN} % The NETGEN project was started 1994 in the master's programme of Joachim Sch\"oberl, under supervision of Prof. Ulrich Langer, at the Department of Computational Mathematics and Optimization, University Linz, Austria. Its further development was supported by the Austrian science Fund ``Fonds zur F\"orderung der wissenschaftlichen Forschung'' (http://www.fwf.ac.at) under projects P 10643-TEC and SFB 1306. Starting from 2002, the development continued within the Start project ``hp-FEM'' (http://www.hpfem.jku.at) granted by the FWF. In 2006, the Netgen development moved together with J.~Sch\"oberl to RWTH Aachen University, Germany (http://www.mathcces.rwth-aachen.de/netgen). \section{How to receive NETGEN} % The latest NETGEN source code release is available from sourceforge \begin{center} http://sourceforge.net/projects/netgen-mesher \end{center} There are file releases, as well as a public SVN repository containing the latest sources. The latest NETGEN Windows executable is available from \begin{center} http://www.mathcces.rwth-aachen.de/netgen \end{center} \section{Installing NETGEN} THIS SECTION NEEDS UPDATE INFORMATION AVAILABLE AT http://netgen-mesher.wiki.sourceforge.net/ \subsection{Installing NETGEN for Unix/Linux} To install NETGEN on Unix/Linux you will download the source code and compile it yourself. You need the following libraries: \begin{itemize} \item The 3D visualization library {\bf OpenGL}. It comes with most systems with hardware graphics. The free software version mesagl is available from \htmladdnormallink{http://www.mesa3d.org}{http://www.mesa3d.org/}. \item The graphical toolkit {\bf TclTk} developed by John Ousterhout (available from \htmladdnormallink{http://www.scriptics.com/}{http://www.scriptics.com/}) and its extension {\bf Tix} available from \htmladdnormallink{http://www.sourceforge.com}{http://www.sourceforge.com/}) by Iam Lan. Netgen has been tested with version TclTk 8.0 - TclTk 8.4 and Tix 4.6. - Tix 8.2 \end{itemize} You can also download these packages from the Netgen site. To install NETGEN please move into the directory ng4. You set the Unix-variable MACHINE according to your machine/operating system, e.g. \begin{quote} \tt setenv MACHINE LINUX \end{quote} % (in bash shell you type {\tt export MACHINE=LINUX}). The Makefile includes the makefile-include \begin{quote} \tt libsrc/makefile.mach.\$(MACHINE) %$ \end{quote} Please create/modify the according file, (e.g. copy makefile.mach.LINUX to makefile.mach.SUN). Then you enter {\bf \tt make} to build the executable. \medskip To make NETGEN globally available you just copy the binary ``ng'' to the global bin - directory. In difference to earlier versions, it needs no additional files. \subsection{Installing NETGEN for Windows} NETGEN is available now for Windows in binary form. You download the zip - archive {\tt ng4win.zip}. After unpacking it with winzip, you can start the executable ``ng4.exe''. \subsection{Adding IGES/STEP file support via OpenCascade} \label{subsec_occ} NETGEN is capable of importing IGES and STEP geometry files. If you want to use this functionality you have the add the OpenCascade library to your NETGEN distribution. OpenCascade is an open source 3D solid modeller library by OpenCASCADE S.A. You can obtain it from \htmladdnormallink{http://www.opencascade.org}{http://www.opencascade.org/} (Linux and Windows). To compile NETGEN with OpenCascade for Windows just choose the project settings ``Release (OCC)'' and adjust the proper search paths. For Linux adjust the directory search paths OCC\_DIR, OCCINC\_DIR and OCCLIB\_DIR in the Makefile and in libsrc/makefile.inc. Then add -DOCCGEOMETRY to the CPLUSPLUSFLAGS2 in libsrc/makefile.mach.\$(MACHINE). If you use OpenCascade version 5.2 also add -DOCC52 and -DHAVE\_IOSTREAM to the CPLUSPLUSFLAGS2. \subsection{Testing Netgen} Please start Netgen by entering ``ng'' or clicking the ``ng.exe'' icon. A white window with menu items should appear. Please load a geometry file by selecting "File {\tt ->} Load Geometry", choose e.g. tutorials/cube.geo. Then press the button "Generate Mesh". By keeping pressed the left, middle or right button of your mouse you can rotate, move or zoom the object. With ``File {\tt->} Export Mesh'' you can save the mesh file. \chapter{Constructive Solid Geometry (CSG)} \label{chap_csg} % The CSG input format is a useful geometry format for small and medium size geometries. One defines the geometry by writing an ASCII file in a text editor. The geometry is defined by the Eulerian operations (union, intersection and complement) from primitives. A complete list of available primitives is given in Section~\ref{sec_primitives}. The following input describes a cube: \begin{quote} \begin{verbatim} # A cube algebraic3d solid cube = orthobrick (0, 0, 0; 1, 1, 1); tlo cube; \end{verbatim} \end{quote} Lines starting with $\#$ are comment lines. Every CSG file must contain the keyword {\tt algebraic3d} before any non-comment line. The keyword {\tt solid} defines a named solid, here the solid {\it cube} is defined. A solid is defined by the Eulerian operations applied to primitives. Here, the solid is just the primitive defined by {\tt orthobrick}. This is a brick parallel to the axis, specified by the minimal $x$, $y$, and $z$ coordinates, and the maximal $x$, $y$, and $z$ coordinates. The present definition gives the cube $[0,1]^3$. Finally, the definition {\tt tlo cube} declares the solid {\it cube} as a top-level-object, what is necessary for meshing. Please start netgen with the geometry file above by entering \begin{quote} ng cube.geo \end{quote} Instead, you can also load the geometry from the file menu. You will see a blue cube, which you can rotate by keeping the left mouse button pressed. Pressing the big {\bf generate mesh} button will result in a (very coarse) mesh of that cube. Instead of using the primitive {\tt orthobrick}, one can also specify a cube by intersecting six halfspaces (called planes). Each primitive {\tt plane} is given by an arbitrary point in the plane, and a outward vector, not necessarily a unit vector. The six halfspaces are intersected by the keyword {\tt and}. The following input gives an equivalent result: \begin{quote} \begin{verbatim} # A cube algebraic3d solid cube = plane (0, 0, 0; 0, 0, -1) and plane (0, 0, 0; 0, -1, 0) and plane (0, 0, 0; -1, 0, 0) and plane (1, 1, 1; 0, 0, 1) and plane (1, 1, 1; 0, 1, 0) and plane (1, 1, 1; 1, 0, 0); tlo cube; \end{verbatim} \end{quote} To drill a hole though the cube, we will intersect the cube and the complement of a cylinder. A cylinder is defined by two points on the central axis, and the radius. Please note, a cylinder is understood as an infinitely long cylinder (although the visualization may suggest a finite cylinder): \begin{quote} \begin{verbatim} # cube with hole algebraic3d solid cubehole = orthobrick (0, 0, 0; 1, 1, 1) and not cylinder (0.5, 0.5, 0; 0.5, 0.5, 1; 0.1); tlo cubehole; \end{verbatim} \end{quote} Like {\tt and} denotes the intersection, {\tt or} denotes the union: \begin{quote} \begin{verbatim} solid cubeball = orthobrick (0, 0, 0; 1, 1, 1) or sphere (0, 0, 0; 0.5) -maxh=0.2; \end{verbatim} \end{quote} The flag {\tt -maxh=0.2} assigns the maximal mesh size of $0.2$ to the solid. The current version, NG4.1, uses the mesh size assigned to the main solid of the top-level-object for the domain. Future version will contain more possibilities to define mesh-sizes for parts of a domain. It is possible to define geometries with several sub-domains, simply by declaring several tlos: \begin{quote} \begin{verbatim} algebraic3d solid cube = orthobrick (0, 0, 0; 1, 1, 1); solid cyl = cylinder (0.5, 0.5, 0; 0.5, 0.5, 1; 0.1); solid dom1 = cube and not cyl; solid dom2 = cube and cyl; tlo dom1 -col=[0,0,1] -transparent; tlo dom2 -col=[1,0,0]; \end{verbatim} \end{quote} This example show also solid trees involving previously defined named solids. Top-level-objects can be assigned a color specified by the amount of red, green and blue (RGB) values. The flag {\tt -transparent} makes the solid appear transparent. It is possible to specify boundary condition numbers for individual surfaces of a solid. The flag {\tt -bc} assigns the bc to all surfaces of that solid-tree. If several flags are given the one closest to the leaves of the tree dominates. The following file defines a cube, with $bc=1$ at the bottom, $bc=2$ at the top, and $bc=3$ for all other surfaces: \begin{quote} \begin{verbatim} algebraic3d solid bottom = plane (0, 0, 0; 0, 0, -1) -bc=1; solid top = plane (1, 1, 1; 0, 0, 1) -bc=2; solid cube = bottm and top and plane (0, 0, 0; 0, -1, 0) and plane (0, 0, 0; -1, 0, 0) and plane (1, 1, 1; 0, 1, 0) and plane (1, 1, 1; 1, 0, 0) -bc=3; tlo cube; \end{verbatim} \end{quote} \section{Curves} For the construction of some of the primitives in the following section it is necessary to define 2D or 3D curves, which are given in terms of straight lines and of quadratic rational spline patches. A line is given by the two endpoints, a spline patch by three d'Boor points. The patch is an elliptic arc from point 1 to point 3, such that the lines 1--2 and 2--3 are tangents. A 2D curve is defined as \begin{quote} \samepage \tt \begin{tabbing} aaa\=aaa\=aaa\=aaa\=aaa\=aaa\= \kill curve2d $name$ = ($np$;\\ \>\> $x_1$, $y_1$;\\ \>\> \ldots\\ \>\> $x_{np}$, $y_{np}$;\\ \>\> $ns$;\\ \>\> [ 2 | 3 ], $p_{1,1}$, $p_{1,2}$ [, $p_{1,3}$];\\ \>\> \ldots\\ \>\> [ 2 | 3 ], $p_{ns,1}$, $p_{ns,2}$ [, $p_{ns,3}$]); \end{tabbing} \end{quote} The number of points is given by $np$, the number of segments by $ns$. Each point is given by its coordinates, each segment by the number of points (2 for line segments, 3 for spline patches) and the pointnumbers. The 3D curves are given analogously by \begin{quote} \samepage \tt \begin{tabbing} aaa\=aaa\=aaa\=aaa\=aaa\=aaa\= \kill curve3d $name$ = ($np$;\\ \>\> $x_1$, $y_1$, $z_1$;\\ \>\> \ldots\\ \>\> $x_{np}$, $y_{np}$, $z_{np}$;\\ \>\> $ns$;\\ \>\> [ 2 | 3 ], $p_{1,1}$, $p_{1,2}$ [, $p_{1,3}$];\\ \>\> \ldots\\ \>\> [ 2 | 3 ], $p_{ns,1}$, $p_{ns,2}$ [, $p_{ns,3}$]); \end{tabbing} \end{quote} \section{Available Primitives} \label{sec_primitives} Netgen %4.1 supports the following primitives: \begin{enumerate} \item A halfspace, i.e., a plane and everything on one side of it, given by an arbitrary point~$p = (p_x, p_y, p_z)$ in the plane and an outside normal vector~$n = (n_x, n_y, n_z)$, not necessarily a unit vector: \begin{quote} \tt plane ( $p_x$, $p_y$, $p_z$ ; $n_x$, $n_y$, $n_z$ ) \end{quote} \item A cylinder of infinite length, given by two points~$a=(a_x, a_y,a_z)$ and $b=(b_x, b_y, b_z)$ on the central axis and the radius $r$: \begin{quote} \tt cylinder ( $a_x$, $a_y$, $a_z$ ; $b_x$, $b_y$, $b_z$ ; $r$ ) \end{quote} \item A sphere, given by the center~ $c=(c_x,c_y,c_z)$ and the radius~$r$: \begin{quote} \tt sphere ( $c_x$, $c_y$, $c_z$ ; $r$ ) \end{quote} \item An elliptic cylinder, given by the point $c=(c_x, c_y, c_z)$ on the main axis, and the vectors $v$ and $w$ of the long and short axis of the ellipse, respectively: \begin{quote} \tt ellipticcylinder ($c_x$, $c_y$, $c_z$ ; $v_x$, $v_y$, $v_z$ ; $w_x$, $w_y$, $w_z$) \end{quote} \item An ellipsoid, given by the center $c=(c_x, c_y, c_z)$, and the vectors $u$, $v$ and $w$ of the main axis of the ellipsoid: \begin{quote} \tt ellipsoid ($c_x$, $c_y$, $c_z$ ; $u_x$, $u_y$, $u_z$; $v_x$, $v_y$, $v_z$ ; $w_x$, $w_y$, $w_z$) \end{quote} \item A cone is given by two points on the central axis and the two corresponding radii. It is not possible to mesh the top of the cone yet, it must be cut off. \begin{quote} \tt cone ( $a_x$, $a_y$, $a_z$ ; $r_a$; $b_x$, $b_y$, $b_z$ ; $r_b$ ) \end{quote} \item A orthobrick is a brick parallel to the coordinate axis. It is specified by two opposite corner points $a = (a_x, a_y, a_z)$ and $b = (b_x, b_y, b_z)$: \begin{quote} \tt orthobrick ( $a_x$, $a_y$, $a_z$ ; $b_x$, $b_y$, $b_z$ ) \end{quote} \item A polyhedron is defined by a set of triangles forming a closed polyhedron. First, a set of points is defined, then the triangles are given by point indices. The triangles must be oriented counter-clockwise when looking onto the object. The following polyhedron describes a tetrahedron: \begin{quote} \begin{verbatim} algebraic3d solid poly = polyhedron (0,0,0; 1,0,0; 0,1,0; 0,0,1 ;; 1,3,2 ; 1,4,3; 1,2,4 ; 2,3,4 ); tlo poly; \end{verbatim} \end{quote} \item A body of extrusion is defined by its profile (which has to be a closed, \textit{clockwise} oriented 2D curve), by a path (a 3D curve) and a vector $d$. It is constructed as follows. Take a point $p$ on the path and denote the (unit-) tangent of the path in this point by $t$. If we cut the body by the plane given by $p$ and $t$ as normal vector, the cut is the profile. The profile is oriented by the (local) y-direction $\bar{y} := d - (d \cdot t) t$ and the (local) x-direction $\bar{x} := t \times \bar{y}$. The syntax is: \begin{quote} \tt extrusion ( ; ; $d_x$, $d_y$, $d_z$ ) \end{quote} The following points have to be noticed: \begin{itemize} \item If the path is not closed, then also the body is NOT closed. In this case e.g.\ planes or orthobricks have to be used to construct a closed body. \item The path has to be smooth, i.e.\ the tangents at the end- resp.\ startpoint of two consecutive spline or line patches have to have the same directions. \end{itemize} \item A body of revolution is given by two points, defining the axis of revolution, and the 2D curve which is rotated: \begin{quote} \tt revolution ( $p_{1,x}$, $p_{1,y}$, $p_{1,z}$; $p_{2,x}$, $p_{2,y}$, $p_{2,z}$; ) \end{quote} The first point defines the origin of the local 2D coordinate system of the curve. It is assumed, that the curve lies above the (local) x-axis, and that it is described \textit{clockwise}. If the curve is not closed, then the start point and the end point have to lie on the x-axis, and the tangents at those points have to be orthogonal to the x-axis. \end{enumerate} \section{Surface Identification} In Netgen it is possible to construct prismatic meshes between two surfaces, where these surfaces have to be specified explicitly in the .geo file with the command \begin{quote} \tt identify closesurfaces ; \end{quote} (this feature originally was intended for close surface, which is the reason for the command name). \paragraph{Optional parameters:} (selection) \begin{itemize} \item \texttt{-tlo=}\\ the prisms are only constructed between two faces of a tlo. \item \texttt{-direction=[,,]}\\ This parameter has to be used if \textbf{skew prisms} should be built. In this case netgen ``needs help'' by the user, it needs to know the direction of identification. \textit{Example:} We start with a cylinder with the axis given by the points $(-1,0,4)$ and $(4,10,1)$. This cylinder is cut by the planes \texttt{p1} and \texttt{p2} (which are not necessarily normal to the axis and not necessarily parallel) and we want to build prisms between these planes. Then the command would, e.g., look like \begin{quote} \tt identify closesurfaces p1 p2 -direction=[5,10,-3] \end{quote} \end{itemize} \section{Known problems and work-arounds} \subsection{Interfaces} A airdomain with two connected interior parts may be described by \begin{quote} \begin{verbatim} algebraic3d solid cube = orthobrick (0, 0, 0; 1, 1, 1); solid part1 = orthobrick (0.2, 0.2, 0.2; 0.5, 0.8, 0.8); solid part2 = orthobrick (0.5, 0.2, 0.2; 0.8, 0.8, 0.8); solid air = cube and not part1 and not part2; tlo air; tlo part1; tlo part2; \end{verbatim} \end{quote} The problem is, that a domain is an open domain. Thus, the domain {\it air} is not only the outer part, but also the interface between {\it part1} and {\it part2}. The result is unspecified. To fix this problem, one can define the {\it air}-domain by cutting out one big brick: \begin{quote} \begin{verbatim} solid air = cube and not othrobrick (0.2, 0.2, 0.2; 0.8, 0.8, 0.8); \end{verbatim} \end{quote} \subsection{Degenerated edges} Degenerated edges are found sometimes, but some still cause troubles. A sphere on top of a cylinder my be described by: \begin{quote} \begin{verbatim} solid cyl = cylinder (0, 0, 0; 1, 0, 0; 0.5) and plane (0, 0, 0; -1, 0, 0) and plane (1, 0, 0; 1, 0, 0); solid main = cyl or sphere (1, 0, 0; 0.5); tlo main; \end{verbatim} \end{quote} The edge is a degenerated one. A work-around is to split the domain (artificially) into two non-degenerated parts: \begin{quote} \begin{verbatim} solid cyl = cylinder (0, 0, 0; 1, 0, 0; 0.5) and plane (0, 0, 0; -1, 0, 0) and plane (1, 0, 0; 1, 0, 0); solid hemisphere = sphere (1, 0, 0; 0.5) and not plane (1, 0, 0; -1, 0, 0); tlo cyl; tlo hemisphere; \end{verbatim} \end{quote} \chapter{Other Geometry Formats} \section{Using IGES/STEP Geometries} % IGES and STEP are standard exchange formats for CAD files. Contrary to the STL format, IGES and STEP deliver an exact representation of the geometry and do not approximate it. In order to use IGES/STEP geometries you have to install NETGEN with the OpenCascade Geometry Kernel as described in \ref{subsec_occ}. Most solid modellers can export IGES or STEP files. However, often these files are not as exact as a mesher needs them to be. So is meshing fails, try repairing the model via {\bf IGES/STEP Topology Explorer/Doctor}. \section{Using STL Geometries} % STL is a standardized file format to describe (approximate) geometies by triangulated surfaces. It is useful to describe complicated parts which are modeled with some CAD programmes. Also, some users have written their own (C) programmes to define STL geometries, where was not so easy to use the CSG format. The syntax of STL files is as follows \begin{quote} (not available yet. please figure out the syntax from the examples) \end{quote} We found that many STL geometries have some difficulties. Some of them can be corrected (removed) by the {\bf STL - Doctor}. Please see the corresponding manual pages (not available yet). \section{2D Spline Geometry} % The extension for 2D spline geometry is ``.in2d''. The boundary is given in terms of straight lines and of quadratic rational spline patches. A line is given by the two endpoints, a spline patch by 3 d'Boor points. The patch is an elliptic arc from point 1 to point 3, such that the lines 1-2 and 2-3 are tangents. It is possible to use different subdomains with this format. This file format also supports a priori mesh grading. To the spline point i one adds a local refinement factor {\tt rp}$_i$ . Close to this point the mesh-size $h(x)$ is {\tt h}$_{Glob}$ / {\tt rp}$_i$ . The global parameter {\tt grading} describes how fast the mesh-size decreases. The gradient of the local mesh-size function $h(x)$ is bounded by $| \nabla_x h(x)| \leq \mbox{grading}^{-1}$ Also a refinement by a factor {\tt rs}$_i$ > 1 along the whole segment i is possible. The file looks like: % \begin{quote} \samepage \tt splinecurves2d \\ grading \\ np \\ x$_1$ y$_1$ rp$_1$ \\ ... \\ x$_{np}$ y$_{np}$ rp$_{np}$ \\ ns \\ dil$_1$ dir$_1$ [ 2 | 3 ] pi$_{1,1}$ pi$_{1,2}$ [ pi$_{1,3}$ ] rs$_1$ \\ ... \\ dil$_{nl}$ dir$_{nl}$ [ 2 | 3 ] pi$_{nl,1}$ pi$_{nl,2}$ [ pi$_{nl,3}$ ] rs$_{nl}$ \\ \end{quote} % {\tt np} is the number of points, {\tt ns} the number of spline segments. Every segment starts with the domain numbers at the left and at the right sides of the segment. Domain number 0 is reserved for the exterior. Then the number of points and two or three point indices follow. Finally, the refinement factor along the line follows. \chapter{Mesh and Solution Formats} You can export meshes to a couple of file formats. Some are self-defined, some other are standard formats. The self-defined are the following: \section{Mesh Size File} By means of a mesh size file you can provide a local mesh size density. The file extension must be {\it .msz}. If you want to use the mesh size file, you specify it in the ``Meshing Options'', dialog box, page ``Mesh Size''. The syntay is: \begin{verbatim} np x1 y1 z1 h1 x2 y2 z2 h2 .... xnp ynp znp hnp nl xs1 ys1 zs1 xe1 ye1 ze1 h1 xs2 ys2 zs2 xe2 ye2 ze2 h2 .... xsnl ysnl zsnl xenl yenl zenl hnl \end{verbatim} You specify {\tt np} points, given by the $(x_i,y_i,z_i)$-coordinates, where the mesh size will be reduced at least to $h_i$. You specify also {\tt nl} line-segments by the start-point and end-point coordinates. The mesh-size along the whole line will be reduced to the given $h_i$. \section{Neutral Format} The neutral volume mesh format contains the following sections: \begin{enumerate} \item nodes \\ After the number of nodes there follows a list of $x$, $y$, and $z$-coordinates of the mesh-nodes. \item volume elements \\ After the number of volume elements there follows the list of tetrahedra. Each element is specified by the sub-domain number, and 4 node indices. The node indices start with 1. \item surface elements \\ After the number of surface elements there follows the list of triangles. Each element is specified by the boundary condition number, and 3 node indices. The node indices start with 1. \end{enumerate} \section{Fepp Format 2D} The Fepp 2D format contains the following sections: \begin{enumerate} \item boundary segments \\ After the number of boundary segments there follows a list of segments. Each segment is specified by the spline - patch number, and the two node indices. Counting starts with 1 \item domain elements \\ After the number of domain elements there follows the list of elements. Each element is specified by the sub-domain number, the number of nodes (3 or 4) and the node indices. Counting starts with 1 \item nodes \\ After the number of nodes there follows a list of $x$ and $y$ -coordinates of the mesh-nodes. \item geometric information \\ After the number of spline patches there follows a list of spline specifications. Each spline patch is given by the 6 coefficients of the describing quadratic polynomial equation $$ c_1 x^2 + c_2 y^2 + c_3 xy + c_4 x + c_5 y + c_6 = 0 $$ \end{enumerate} \section{Surface triangulaton file} One can export to and import from a surface mesh file. It´s structure is as follows: \begin{enumerate} \item {\tt surfacemesh} \\ starts with that keyword \item number of points \\ point coordinates $(x,y,z)$. \item number of surface triangles, \\ surface triangles oriented counter-clock wise when looking at the object, index starts from 1. \end{enumerate} \section{Solution File Format} The Netgen software includes also a simple visualizer for finite element gridfunctions. It supports scalar fields (e.g. temperature), and vector valued fields (flow velocities, mechanical deformations). The solution field is imported by the menu item File $->$ Import Solution. It is important to load the corresponding mesh in advance. The format of the solution file is as follows. It consists of an arbitrary number of blocks of this structure: \begin{enumerate} \item {\tt solution} {\it function-name} flags {\tt solution} is the keyword, {\it function-name} is a string to refer to that functions. The supported flags are \begin{enumerate} \item -size=s \\ number of entries (default: number of mesh-points) \item -components=c \\ number of components (default: 1). Mechanical deformations have 3 components. \item -type=[nodal,element,surfaceelement] \\ the grid-funciton has nodal values, or one value per volume element, or one value per surface element (default: nodal) \end{enumerate} \item block of $size \times components$ values \end{enumerate} Please try out to import the solution file 'tutorials/cube.sol' fitting to the mesh 'tutorials/cube.vol'. \chapter{Netgen operations} You can use netgen in interactive mode using its menus, or, you can run netgen in batch-mode using command line arguments. \section{Command line arguments} Command line arguments are specified as {\it -flag=value}. \begin{itemize} \item -help \newline Prints the available command line arguments \item -geofile=filename \newline Specifies geometry file. Is equivalent to {\it filename}, i.e., you can scip {\it -geofile=}. \item -meshfile=filename \newline Mesh file will be stored in file {\it filename}. \item -batchmode \newline Exit after mesh generation. Otherwise, the GUI will be started \item -V \newline Verbose mode. Prints some additional information \item -verycoarse, -coarse, -moderate, -fine, -veryfine \newline Mesh size control \end{itemize} \chapter{Using the Graphical User Interface} The Netgen main window looks like: \begin{center} \includegraphics[width=12cm]{pictures/screenshot} \end{center} It consists of the menuline and the button line at the top, the status line at the bottom, and the large drawing window. The menu items will be explained in \ref{sec_menuitems}. The button line provides shot-cuts for common opteration: \begin{itemize} \item Quit \newline Terminate Netgen \item Generate mesh \newline Perform mesh generation \item Stop Meshing \newline Stop mesh generation \item Geometry/Edges/Mesh/Solution \newline Switch between operation modes of visualization. \item Zoom all \newline Zooms such that the whole visualization scene fits into the window. \item Center \newline Center rotation and scaling at marked point, available only in mesh - visuailzation mode. \item Rotate/Move/Zoom Left mouse drag rotates/moves/zooms object. \end{itemize} The status line shows information, namely \begin{itemize} \item Points \newline Number of points in the mesh \item Elements \newline Number of volume elements (3D) in the mesh \item Surf Elements \newline Number of surface elements (3D) or inner elements (2d) in the mesh. \item Mem \newline Used memory in the large memory arena \item Meshing Job, percentage Douriing mesh generation, the current job as well as the progress is displayed on the right side of the statu line. \end{itemize} The drawing window displays the geometry or the mesh. The view can be changed with the mouse: \begin{itemize} \item drag with left button pressed rotates the object, \item drag with middle button pressed moves the object, \item drag with right button pressed zooms the object. \end{itemize} The view can also be changed with the keyboard: \begin{itemize} \item cursor keys rotate the object \item shift + cursor keys move the object \item control + cursor keys zoom the object \end{itemize} When in Mesh - visualization scene, double clicking on triangles mark the surface. The point cursor is set. \section{The Netgen menu items} \label{sec_menuitems} \subsection{The menu item {\em File}} \includegraphics[height=7.8cm]{pictures/menufile} \subsection{The menu item {\em Geometry}} \includegraphics[height=2.7cm]{pictures/menugeometry} \subsection{The menu item {\em Mesh}} \includegraphics[height=9.8cm]{pictures/menumesh} \subsection{The menu item {\em View}} \includegraphics[height=6.0cm]{pictures/menuview} \subsection{The menu item {\em Refinement}} \includegraphics[width=3.2cm]{pictures/menurefinement} \section{Meshing Options} \includegraphics[width=10cm]{pictures/meshingoptions_1} \includegraphics[width=10cm]{pictures/meshingoptions_2} \includegraphics[width=10cm]{pictures/meshingoptions_3} \includegraphics[width=10cm]{pictures/meshingoptions_4} \includegraphics[width=10cm]{pictures/meshingoptions_5} \includegraphics[width=10cm]{pictures/meshingoptions_6} \section{Visualization Options} % \chapter{The Algorithms of Netgen} % % Netgen follows a top down strategy. It starts from computing the % corner points (CSG only). Then, the edges are defined and meshed into % segments (CSG and STL). Next, the faces are meshed by an advancing front % surface mesh generator. After meshing, the faces meshes are optimized. % Finally, the individual sub-domains are filled with tets. Therefore, % a fast Delaunay algorithm generates most of the elements (about 98 percent). % But often it fails for mesh the whole domain, then the slower back-tracking % rule-base algorithm takes over. Finally, the volume is optimized by the % usual node - movement, element swapping and splitting algorithms. \chapter{Programming Interfaces} % \section{The nginterface} By means of the nginterface one's own simulation code can be included into the netgen environment. This is particular useful for FEM (FVM,BEM) code developers, since they may profit from the netgen preprocessing and postprocessing possibilities. Please download the example Netgen-add-on module {\it demoapp} and follow the instructions therein \section{The nglib} \subsection{Introduction} The NETGEN mesh generation library {\it nglib} is available in C++ source code and can be compiled for Unix/Linux as well as Win95/98/NT and linked to one library file. The interface to the application programme is by the C language header file {\it nglib.h}. The functionality of nglib is volume mesh generation by a domain given by a surface triangulation, and surface mesh generation from a domain described by an STL file (standard file format for geometries defined by triangle approximation). It can do mesh optimization as well as mesh refinement. It can generate 4 node tetrahedra and 10 node tetrahedrons (with quadratic shape functions). The local mesh size can be defined automatically by geometric features and/or by user specification. \subsection{The Header File} The interface file contains the following type definitions and function calls. All Netgen types and functions start with {\tt Ng}. Types and functions have capital initial letters, constants are in capital letters. \subsection{Types and Constants} \begin{verbatim} /// Data type for NETGEN mesh typedef void * Ng_Mesh; /// Data type for NETGEN STL geomty typedef void * Ng_STL_Geometry; // max number of nodes per element #define NG_VOLUME_ELEMENT_MAXPOINTS 10 // implemented element types: enum Ng_Volume_Element_Type { NG_TET = 1, NG_PYRAMID = 2, NG_PRISM = 3, NG_TET10 = 4 }; // max number of nodes per surface element #define NG_SURFACE_ELEMENT_MAXPOINTS 6 // implemented element types: enum Ng_Surface_Element_Type { NG_TRIG = 1, NG_QUAD = 2, NG_TRIG6 = 3 }; struct Ng_Meshing_Parameters { double maxh; double fineness; // 0 .. coarse, 1 .. fine int secondorder; }; enum Ng_Result { NG_OK = 0, NG_SURFACE_INPUT_ERROR = 1, NG_VOLUME_FAILURE = 2, NG_STL_INPUT_ERROR = 3, NG_SURFACE_FAILURE = 4 }; \end{verbatim} {\tt Ng\_Mesh} is a data type representing a Netgen mesh. {\tt Ng\_STL\_Geometry} represents an STL geometry. One can operate on these data structures by the functions defined below. Netgen can (now and/or in future) work with various element types defined by generic constants. Several parameters can be specified in the {\tt Ng\_Meshing\_Parameters} structure for volume and/or surface mesh generation. The result of Netgen functions is of type {\tt Ng\_Result}. \subsection{Initialization} Please call these functions before using netgen functions and after using netgen functions, respectively: \begin{verbatim} // initialize, deconstruct Netgen library: void Ng_Init (); void Ng_Exit (); \end{verbatim} \subsection{Mesh access} Netgen meshes can be processed by the means of the following functions. A mesh contains nodes, surface elements and volume elements. Counting starts from 1. \begin{verbatim} // Generates new mesh structure Ng_Mesh * Ng_NewMesh (); void Ng_DeleteMesh (Ng_Mesh * mesh); // feeds points, surface elements and volume elements to the mesh void Ng_AddPoint (Ng_Mesh * mesh, double * x); void Ng_AddSurfaceElement (Ng_Mesh * mesh, Ng_Surface_Element_Type et, int * pi); void Ng_AddVolumeElement (Ng_Mesh * mesh, Ng_Volume_Element_Type et, int * pi); // ask for number of points, surface and volume elements int Ng_GetNP (Ng_Mesh * mesh); int Ng_GetNSE (Ng_Mesh * mesh); int Ng_GetNE (Ng_Mesh * mesh); // return point coordinates void Ng_GetPoint (Ng_Mesh * mesh, int num, double * x); // return surface and volume element in pi Ng_Surface_Element_Type Ng_GetSurfaceElement (Ng_Mesh * mesh, int num, int * pi); Ng_Volume_Element_Type Ng_GetVolumeElement (Ng_Mesh * mesh, int num, int * pi); \end{verbatim} \subsubsection{Mesh Generation} The user can specify the mesh size function by the global parameter maximal mesh size, and can additionally restrict the mesh size in points or cubes. The function {\tt Ng\_GenerateVolumeMesh} generates the volume mesh starting from the surface. \begin{verbatim} // Defines MeshSize Functions void Ng_RestrictMeshSizeGlobal (Ng_Mesh * mesh, double h); void Ng_RestrictMeshSizePoint (Ng_Mesh * mesh, double * p, double h); void Ng_RestrictMeshSizeBox (Ng_Mesh * mesh, double * pmin, double * pmax, double h); // generates volume mesh from surface mesh Ng_Result Ng_GenerateVolumeMesh (Ng_Mesh * mesh, Ng_Meshing_Parameters * mp); \end{verbatim} \subsection{STL Geometry} A STL geometry can be read from a STL file (ASCII or binary), or can be assembled by providing triangle by triangle. Either, the user can specify the edges of the geometry, or netgen can define edges by {\tt Ng\_STL\_MakeEdges} by using an angle criterium. \begin{verbatim} // loads geometry from STL file Ng_STL_Geometry * Ng_STL_LoadGeometry (char * filename, int binary = 0); // generate new STL Geometry Ng_STL_Geometry * Ng_STL_NewGeometry (); // fills STL Geometry // positive orientation // normal vector may be null-pointer void Ng_STL_AddTriangle (Ng_STL_Geometry * geom, double * p1, double * p2, double * p3, double * nv); // add (optional) edges: void Ng_STL_AddEdge (Ng_STL_Geometry * geom, double * p1, double * p2); // after adding triangles (and edges) initialize Ng_Result Ng_STL_InitSTLGeometry (Ng_STL_Geometry * geom); // automatically generates edges: void Ng_STL_MakeEdges (Ng_STL_Geometry * geom); // generates mesh, empty mesh be already created. Ng_Result Ng_STL_GenerateSurfaceMesh (Ng_STL_Geometry * geom, Ng_Mesh * mesh, Ng_Meshing_Parameters * mp); \end{verbatim} \subsection{Programming Example} The File {\it ngcore.cc}, see Appendix A, is a simple application using the netgen volume mesh generator. First, the surface mesh is read from a file containing point coordinates and surface triangles (see e.g. file {\it cube.surf}). The volume mesh generate is called, and the volume mesh is written to the standard output, see file {\it cube.vol}. \end{document} ================================================ FILE: external_dependencies/.gitignore ================================================ *.tar.gz ================================================ FILE: libsrc/CMakeLists.txt ================================================ add_subdirectory(core) add_subdirectory(general) add_subdirectory(gprim) add_subdirectory(linalg) add_subdirectory(include) add_subdirectory(meshing) if(USE_OCC) add_subdirectory(occ) endif(USE_OCC) if(USE_STLGEOM) add_subdirectory(stlgeom) endif(USE_STLGEOM) if(USE_GUI) add_subdirectory(visualization) endif(USE_GUI) if(USE_INTERFACE) add_subdirectory(interface) endif(USE_INTERFACE) if(USE_CSG) add_subdirectory(csg) endif(USE_CSG) if(USE_GEOM2D) add_subdirectory(geom2d) endif(USE_GEOM2D) ================================================ FILE: libsrc/core/.clang-tidy ================================================ Checks: '*,-cppcoreguidelines-avoid-non-const-global-variables,-llvmlibc-restrict-system-libc-headers,-clang-analyzer-alpha.*,-*braces-around-statements,-fuchsia-*,-google-runtime-references,-readability-implicit-bool-conversion,-google-explicit-constructor,-hicpp-explicit-conversions,-google-runtime-int,-llvm-header-guard,-modernize-pass-by-value,-cppcoreguidelines-non-private-member-variables-in-classes,-misc-non-private-member-variables-in-classes,-readability-magic-numbers,-cppcoreguidelines-avoid-magic-numbers' CheckOptions: - key: cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor value: 1 - key: cppcoreguidelines-macro-usage.AllowedRegexp value: NGCORE_*|NETGEN_*|NG_EXCEPTION* WarningsAsErrors: '*' ================================================ FILE: libsrc/core/CMakeLists.txt ================================================ add_library(ngcore ${NGCORE_LIBRARY_TYPE} archive.cpp bitarray.cpp exception.cpp localheap.cpp logging.cpp flags.cpp paje_trace.cpp profiler.cpp table.cpp taskmanager.cpp utils.cpp version.cpp ng_mpi_wrapper.cpp statushandler.cpp ) string(REPLACE "|" ";" ng_compile_flags_replace_sep "${NG_COMPILE_FLAGS}") target_compile_options(ngcore PUBLIC ${ng_compile_flags_replace_sep}) if(EMSCRIPTEN) set(PYTHON_MODULE_EXTENSION ".so") target_link_options(ngcore PUBLIC -sALLOW_MEMORY_GROWTH -sENVIRONMENT=web -sWASM_BIGINT -fwasm-exceptions) target_compile_options(ngcore PUBLIC -fwasm-exceptions) endif() if (CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND USE_PYTHON) # Python packages on Linux are compiled with the old ABI, # make sure that the same ABI is used in plugins aswell try_run( ret_val can_compile ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/_get_glibcxx_use_cxx11_abi.cpp RUN_OUTPUT_VARIABLE use_glibcxx_cxx11_abi ) target_compile_definitions(ngcore PUBLIC -D_GLIBCXX_USE_CXX11_ABI=${use_glibcxx_cxx11_abi}) try_run( ret_val can_compile ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/_get_gxx_abi.cpp RUN_OUTPUT_VARIABLE default_cxx_abi_version ) if(${can_compile} AND (${ret_val} EQUAL 0)) # Different python modules using pybind11 need to use the same C++ ABI version # for compatibility set(cxx_abi_version 17) message(STATUS "GNU C++ ABI version: ${cxx_abi_version}") target_compile_options(ngcore PUBLIC "-fabi-version=${cxx_abi_version}") endif() endif() if(USE_PYTHON) target_sources(ngcore PRIVATE python_ngcore.cpp) target_compile_definitions(ngcore PUBLIC NETGEN_PYTHON NG_PYTHON PYBIND11_SIMPLE_GIL_MANAGEMENT) endif(USE_PYTHON) if(WIN32) target_compile_options(ngcore PUBLIC /bigobj $) get_WIN32_WINNT(ver) target_compile_definitions(ngcore PUBLIC _WIN32_WINNT=${ver} WNT WNT_WINDOW NOMINMAX MSVC_EXPRESS _CRT_SECURE_NO_WARNINGS HAVE_STRUCT_TIMESPEC WIN32) target_link_options(ngcore PUBLIC /ignore:4273 /ignore:4217 /ignore:4049) else(WIN32) target_link_libraries(ngcore PUBLIC dl) endif(WIN32) target_compile_definitions(ngcore PRIVATE NGCORE_EXPORTS) target_include_directories(ngcore INTERFACE $ $) if(CHECK_RANGE) target_compile_definitions(ngcore PUBLIC NETGEN_ENABLE_CHECK_RANGE) endif(CHECK_RANGE) if(CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "DEBUG") target_compile_definitions(ngcore PUBLIC _DEBUG NETGEN_ENABLE_CHECK_RANGE) endif(CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "DEBUG") if(TRACE_MEMORY) target_compile_definitions(ngcore PUBLIC NETGEN_TRACE_MEMORY) endif(TRACE_MEMORY) if(USE_NUMA) find_library(NUMA_LIBRARY libnuma.so) target_compile_definitions(ngcore PUBLIC USE_NUMA) target_link_libraries(ngcore PRIVATE ${NUMA_LIBRARY}) endif(USE_NUMA) install(TARGETS ngcore DESTINATION ${NG_INSTALL_DIR} COMPONENT netgen) target_link_libraries(ngcore PRIVATE "$" ${CMAKE_THREAD_LIBS_INIT}) install(FILES ngcore.hpp archive.hpp type_traits.hpp version.hpp ngcore_api.hpp logging.hpp memtracer.hpp exception.hpp symboltable.hpp paje_trace.hpp utils.hpp profiler.hpp mpi_wrapper.hpp array.hpp taskmanager.hpp concurrentqueue.h localheap.hpp python_ngcore.hpp flags.hpp xbool.hpp signal.hpp bitarray.hpp table.hpp hashtable.hpp ranges.hpp ngstream.hpp simd.hpp simd_avx.hpp simd_avx512.hpp simd_generic.hpp simd_math.hpp simd_sse.hpp simd_arm64.hpp register_archive.hpp autodiff.hpp autodiffdiff.hpp ng_mpi.hpp ng_mpi_generated_declarations.hpp mpi4py_pycapi.h ng_mpi_native.hpp statushandler.hpp DESTINATION ${NG_INSTALL_DIR_INCLUDE}/core COMPONENT netgen_devel) if(ENABLE_CPP_CORE_GUIDELINES_CHECK) set_target_properties(ngcore PROPERTIES CXX_CLANG_TIDY "${DO_CLANG_TIDY}") endif(ENABLE_CPP_CORE_GUIDELINES_CHECK) add_dependencies(ngcore ng_generate_version_file) if(USE_PYTHON) pybind11_add_module(pyngcore MODULE python_ngcore_export.cpp) target_link_libraries(pyngcore PUBLIC ngcore PRIVATE "$") set_target_properties(pyngcore PROPERTIES INSTALL_RPATH "${NG_RPATH_TOKEN}/../${NETGEN_PYTHON_RPATH}") if(EMSCRIPTEN) target_link_options(pyngcore PUBLIC -sALLOW_MEMORY_GROWTH -sENVIRONMENT=web -sWASM_BIGINT -fwasm-exceptions) endif(EMSCRIPTEN) install(TARGETS pyngcore DESTINATION ${NG_INSTALL_DIR_PYTHON}/pyngcore COMPONENT netgen) endif(USE_PYTHON) function (build_mpi_variant) set(target ng_${ARGV0}) set(include_dir ${ARGV1}) message("1Building MPI variant: ${ARGV0} ${ARGV1}") add_library(${target} SHARED ng_mpi.cpp) target_link_libraries(${target} PUBLIC ngcore PRIVATE "$") target_compile_definitions(${target} PUBLIC PARALLEL NG_MPI_WRAPPER) target_include_directories(${target} PRIVATE ${include_dir}) set_target_properties(${target} PROPERTIES PREFIX "") install(TARGETS ${target} RUNTIME DESTINATION ${NG_INSTALL_DIR_BIN} LIBRARY DESTINATION ${NG_INSTALL_DIR_LIB} COMPONENT netgen) endfunction() if(USE_MPI) target_compile_definitions(ngcore PUBLIC PARALLEL) message(STATUS "Found MPI version\n${MPI_C_LIBRARY_VERSION_STRING}") if(USE_MPI_WRAPPER) target_compile_definitions(ngcore PUBLIC NG_MPI_WRAPPER) if(MPI_C_LIBRARY_VERSION_STRING MATCHES "Microsoft MPI.*") set(MICROSOFT_MPI_INCLUDE_DIR ${MPI_C_HEADER_DIR}) set(MICROSOFT_MPI_LIBRARY ${MPI_msmpi_LIBRARY}) endif() if(MPI_C_LIBRARY_VERSION_STRING MATCHES "Open MPI.*") set(OPENMPI_INCLUDE_DIR ${MPI_C_INCLUDE_PATH}) endif() if(MPI_C_LIBRARY_VERSION_STRING MATCHES "MPICH.*") set(MPICH_INCLUDE_DIR ${MPI_C_INCLUDE_PATH}) endif() if(MPI_C_LIBRARY_VERSION_STRING MATCHES "Intel.*") set(INTEL_MPI_INCLUDE_DIR ${MPI_C_INCLUDE_PATH}) endif() if(OPENMPI_INCLUDE_DIR) build_mpi_variant(openmpi ${OPENMPI_INCLUDE_DIR}) endif() if(MPICH_INCLUDE_DIR) build_mpi_variant(mpich ${MPICH_INCLUDE_DIR}) endif() if(INTEL_MPI_INCLUDE_DIR) build_mpi_variant(intel_mpi ${INTEL_MPI_INCLUDE_DIR}) if(WIN32) target_link_libraries(ng_intel_mpi PUBLIC ${INTEL_MPI_LIBRARY}) endif() endif() if(MICROSOFT_MPI_INCLUDE_DIR) build_mpi_variant(microsoft_mpi ${MICROSOFT_MPI_INCLUDE_DIR}) target_link_libraries(ng_microsoft_mpi PUBLIC ${MICROSOFT_MPI_LIBRARY}) endif() else() target_link_libraries(ngcore PUBLIC ${MPI_C_LIBRARIES}) target_include_directories(ngcore PUBLIC ${MPI_C_INCLUDE_PATH}) endif(USE_MPI_WRAPPER) endif(USE_MPI) ================================================ FILE: libsrc/core/_get_glibcxx_use_cxx11_abi.cpp ================================================ #include int main() { #ifdef _GLIBCXX_USE_CXX11_ABI if(_GLIBCXX_USE_CXX11_ABI) std::cout << 1; else std::cout << 0; #else // _GLIBCXX_USE_CXX11_ABI std::cout << 0; #endif // _GLIBCXX_USE_CXX11_ABI return 0; } ================================================ FILE: libsrc/core/_get_gxx_abi.cpp ================================================ #include int main() { if (__GXX_ABI_VERSION >= 2000 || __GXX_ABI_VERSION < 1000) return 1; std::cout << (__GXX_ABI_VERSION % 100); return 0; } ================================================ FILE: libsrc/core/archive.cpp ================================================ #include "archive.hpp" #include "register_archive.hpp" #include "version.hpp" #ifndef WIN32 #include #endif namespace ngcore { std::map & GetTypeRegister() { static std::map type_register; return type_register; } const detail::ClassArchiveInfo& Archive :: GetArchiveRegister(const std::string& classname) { // if(type_register == nullptr) type_register = // std::make_unique>(); return GetTypeRegister()[classname]; } void Archive :: SetArchiveRegister(const std::string& classname, const detail::ClassArchiveInfo& info) { // if(type_register == nullptr) type_register = // std::make_unique>(); GetTypeRegister()[classname] = info; } bool Archive :: IsRegistered(const std::string& classname) { // if(type_register == nullptr) type_register = // std::make_unique>(); return GetTypeRegister().count(classname) != 0; } #ifdef NETGEN_PYTHON pybind11::object CastAnyToPy(const std::any& a) { auto info = Archive::GetArchiveRegister(Demangle(a.type().name())); return info.anyToPyCaster(a); } std::any CastPyToAny(pybind11::object& obj) { auto name = Demangle(pybind11::detail::get_type_info((PyTypeObject*) pybind11::type::of(obj).ptr())->cpptype->name()); auto info = Archive::GetArchiveRegister(name); if(!info.pyToAnyCaster) throw Exception("Need to register class " + name + " for Archive using std::any"); return info.pyToAnyCaster(obj); } #endif // NETGEN_PYTHON } // namespace ngcore ================================================ FILE: libsrc/core/archive.hpp ================================================ #ifndef NETGEN_CORE_ARCHIVE_HPP #define NETGEN_CORE_ARCHIVE_HPP #include #include #include // for array #include // for complex #include // for size_t, strlen #include // for path #include // for ifstream, ofstream #include // for function #include // for map #include // for shared_ptr #include // for optional #include // for string #include // for declval, enable_if_t, false_type, is_co... #include // for std::byte #include // for set #include // for type_info #include // for move, swap, pair #include // for vector #include "exception.hpp" // for UnreachableCodeException, Exception #include "ngcore_api.hpp" // for NGCORE_API #include "type_traits.hpp" // for all_of_tmpl #include "utils.hpp" // for Demangle, unlikely #include "version.hpp" // for VersionInfo #ifdef NETGEN_PYTHON namespace pybind11 { class object; } #endif // NETGEN_PYTHON namespace ngcore { template struct Shallow { T val; Shallow() = default; Shallow(T aval) : val(aval) { ; } operator T&() { return val; } }; // Helper to detect shared_from_this template class has_shared_from_this2 { private: // typedef T* T_ptr; template static std::true_type test(decltype(((C*)nullptr)->shared_from_this())); template static std::false_type test(...); public: // If the test returns true_type, then T has shared_from_this static constexpr bool value = decltype(test(0))::value; }; template class has_shallow_archive : public std::false_type {}; template class has_shallow_archive> : public std::is_same {}; #ifdef NETGEN_PYTHON NGCORE_API pybind11::object CastAnyToPy(const std::any& a); NGCORE_API std::any CastPyToAny(pybind11::object& h); #endif // NETGEN_PYTHON class NGCORE_API Archive; namespace detail { template T* construct_from_tuple(Tuple&& tuple, std::index_sequence ) { // return new T{std::get(std::forward(tuple))...}; return new T{std::get(std::move(tuple))...}; } template T* construct_from_tuple(Tuple&& tuple) { return construct_from_tuple(std::forward(tuple), std::make_index_sequence>::value>{} ); } // create new pointer of type T if it is default constructible, else throw template T* constructIfPossible(std::tuple args) { if constexpr(std::is_constructible_v) return construct_from_tuple(args); throw Exception(std::string(Demangle(typeid(T).name())) + " is not constructible!"); } template T *constructIfPossible() { if constexpr(std::is_constructible_v) return new T(); throw Exception(std::string(Demangle(typeid(T).name())) + " is not default constructible!"); } //Type trait to check if a class implements a 'void DoArchive(Archive&)' function template struct has_DoArchive { private: template static constexpr auto check(T2*) -> typename std::is_same().DoArchive(std::declval())),void>::type; template static constexpr std::false_type check(...); using type = decltype(check(nullptr)); // NOLINT public: NGCORE_API static constexpr bool value = type::value; }; // Check if class is archivable template struct is_Archivable_struct { private: template static constexpr auto check(T2*) -> typename std::is_same() & std::declval()),Archive&>::type; template static constexpr std::false_type check(...); using type = decltype(check(nullptr)); // NOLINT public: NGCORE_API static constexpr bool value = type::value; }; template struct has_GetCArgs { template static std::true_type check( decltype( sizeof(&C::GetCArgs )) ) { return std::true_type(); } template static std::false_type check(...) { return std::false_type(); } typedef decltype( check(sizeof(char)) ) type; static constexpr type value = type(); }; template constexpr bool has_GetCArgs_v = has_GetCArgs::value; template>::type* = nullptr> std::tuple<> GetCArgs(T&val) { return {}; } template>::type* = nullptr> auto GetCArgs(T&val) { return val.GetCArgs(); } template using TCargs = decltype(GetCArgs(*static_cast(nullptr))); struct ClassArchiveInfo { // create new object of this type and return a void* pointer that is points to the location // of the (base)class given by type_info // std::function creator; void* (*creator)(const std::type_info&, Archive&); // This caster takes a void* pointer to the type stored in this info and casts it to a // void* pointer pointing to the (base)class type_info // std::function upcaster; void* (*upcaster) (const std::type_info&, void*); // This caster takes a void* pointer to the (base)class type_info and returns void* pointing // to the type stored in this info // std::function downcaster; void* (*downcaster)(const std::type_info&, void*); // Archive constructor arguments // std::function cargs_archiver; void (*cargs_archiver)(Archive&, void*); #ifdef NETGEN_PYTHON // std::function anyToPyCaster; pybind11::object (*anyToPyCaster)(const std::any&); std::any (*pyToAnyCaster)(pybind11::object&); #endif // NETGEN_PYTHON }; } // namespace detail template constexpr bool is_archivable = detail::is_Archivable_struct::value; template constexpr size_t TotSize () { if constexpr (sizeof...(Trest) == 0) return sizeof(T); else return sizeof(T) + TotSize (); } // Base Archive class class NGCORE_API Archive { const bool is_output; // how many different shared_ptr/pointer have been (un)archived int shared_ptr_count{0}, ptr_count{0}; // maps for archived shared pointers and pointers std::map shared_ptr2nr{}, ptr2nr{}; // vectors for storing the unarchived (shared) pointers std::vector> nr2shared_ptr{}; std::vector nr2ptr{}; protected: bool shallow_to_python = false; std::map version_map = GetLibraryVersions(); public: template static constexpr bool is_archivable = detail::is_Archivable_struct::value; Archive() = delete; Archive(const Archive&) = delete; Archive(Archive&&) = delete; Archive (bool ais_output) : is_output(ais_output) { ; } virtual ~Archive() { ; } // If the object is pickled, all shallow archived objects will be pickled as a list, // instead of written as a binary archive. This allows pickle to serialize every object only // once and put them together correctly afterwards. Therefore all objects that may live in // Python should be archived using this Shallow function. If Shallow is called from C++ code // it archives the object normally. #ifdef NETGEN_PYTHON template Archive& Shallow(T& val); // implemented in register_archive.hpp #ifndef __CUDACC__ Archive& Shallow(std::any& val); // implemented in python_ngcore.cpp #endif // __CUDACC__ #else // NETGEN_PYTHON template Archive& Shallow(T& val) { static_assert(detail::is_any_pointer, "ShallowArchive must be given pointer type!"); *this & val; return *this; } #endif // NETGEN_PYTHON #ifdef NETGEN_PYTHON virtual void ShallowOutPython(const pybind11::object& /*unused*/) { throw UnreachableCodeException{}; } virtual void ShallowInPython(pybind11::object &) { throw UnreachableCodeException{}; } #endif // NETGEN_PYTHON Archive& operator=(const Archive&) = delete; Archive& operator=(Archive&&) = delete; bool Output () const { return is_output; } bool Input () const { return !is_output; } const VersionInfo& GetVersion(const std::string& library) { return version_map[library]; } // only used for PyArchive virtual void NeedsVersion(const std::string& /*unused*/, const std::string& /*unused*/) {} // Pure virtual functions that have to be implemented by In-/OutArchive virtual Archive & operator & (std::byte & d) = 0; virtual Archive & operator & (float & d) = 0; virtual Archive & operator & (double & d) = 0; virtual Archive & operator & (int & i) = 0; virtual Archive & operator & (long & i) = 0; virtual Archive & operator & (size_t & i) = 0; virtual Archive & operator & (short & i) = 0; virtual Archive & operator & (unsigned char & i) = 0; virtual Archive & operator & (bool & b) = 0; virtual Archive & operator & (std::string & str) = 0; virtual Archive & operator & (char *& str) = 0; #ifdef NETGEN_PYTHON Archive & operator &(std::any& a) { Shallow(a); return *this; } #endif Archive & operator & (VersionInfo & version) { if(Output()) (*this) << version.to_string(); else { std::string s; (*this) & s; version = VersionInfo(s); } return *this; } // Archive std classes ================================================ template Archive& operator & (std::complex& c) { if(Output()) (*this) << c.real() << c.imag(); else { T tmp; (*this) & tmp; c.real(tmp); (*this) & tmp; c.imag(tmp); } return (*this); } template Archive& operator & (std::vector& v) { size_t size; if(Output()) size = v.size(); (*this) & size; if(Input()) v.resize(size); Do(&v[0], size); return (*this); } // archive implementation for enums template auto operator & (T& val) -> std::enable_if_t::value, Archive&> { int enumval; if(Output()) enumval = int(val); *this & enumval; if(Input()) val = T(enumval); return *this; } // vector has special implementation (like a bitarray) therefore // it needs a special overload (this could probably be more efficient, but we // don't use it that often anyway) Archive& operator& (std::vector& v) { size_t size; if(Output()) size = v.size(); (*this) & size; if(Input()) { v.resize(size); bool b; for(size_t i=0; i Archive& operator& (std::map& map) { if(Output()) { (*this) << size_t(map.size()); for(auto& pair : map) (*this) << pair.first << pair.second; } else { size_t size = 0; (*this) & size; T1 key; T2 val; for(size_t i = 0; i < size; i++) { T1 key; T2 val; (*this) & key & val; map[key] = val; } } return (*this); } template Archive& operator& (std::optional& opt) { bool has_value = opt.has_value(); (*this) & has_value; if(has_value) { if(Output()) (*this) << *opt; else { T value; (*this) & value; opt = value; } } return (*this); } template Archive& operator&(std::set &s) { auto size = s.size(); (*this) & size; if(Output()) for(const auto & val : s) (*this) << val; else { for(size_t i=0; i>> Archive & Do (T * data, size_t n) { for (size_t j = 0; j < n; j++) { (*this) & data[j]; }; return *this; }; // NOLINT virtual Archive & Do (std::byte * d, size_t n) { for (size_t j = 0; j < n; j++) { (*this) & d[j]; }; return *this; }; // NOLINT virtual Archive & Do (double * d, size_t n) { for (size_t j = 0; j < n; j++) { (*this) & d[j]; }; return *this; }; // NOLINT virtual Archive & Do (int * i, size_t n) { for (size_t j = 0; j < n; j++) { (*this) & i[j]; }; return *this; }; // NOLINT virtual Archive & Do (long * i, size_t n) { for (size_t j = 0; j < n; j++) { (*this) & i[j]; }; return *this; }; // NOLINT virtual Archive & Do (size_t * i, size_t n) { for (size_t j = 0; j < n; j++) { (*this) & i[j]; }; return *this; }; // NOLINT virtual Archive & Do (short * i, size_t n) { for (size_t j = 0; j < n; j++) { (*this) & i[j]; }; return *this; }; // NOLINT virtual Archive & Do (unsigned char * i, size_t n) { for (size_t j = 0; j < n; j++) { (*this) & i[j]; }; return *this; }; // NOLINT virtual Archive & Do (bool * b, size_t n) { for (size_t j = 0; j < n; j++) { (*this) & b[j]; }; return *this; }; // NOLINT // Archive a class implementing a (void DoArchive(Archive&)) method ======= template::value>> Archive& operator & (T& val) { val.DoArchive(*this); return *this; } // pack elements to binary template Archive & DoPacked (Types & ... args) { if (true) // (isbinary) { constexpr size_t totsize = TotSize(); // (args...); std::byte mem[totsize]; if (is_output) { CopyToBin (&mem[0], args...); Do(&mem[0], totsize); } else { Do(&mem[0], totsize); CopyFromBin (&mem[0], args...); } } // else // cout << "DoPacked of non-binary called --> individual pickling" << endl; return *this; } template constexpr void CopyToBin (std::byte * ptr, T & first, Trest & ...rest) const { memcpy (ptr, &first, sizeof(first)); CopyToBin(ptr+sizeof(first), rest...); } constexpr void CopyToBin (std::byte * ptr) const { } template constexpr void CopyFromBin (std::byte * ptr, T & first, Trest & ...rest) const { memcpy (&first, ptr, sizeof(first)); CopyFromBin(ptr+sizeof(first), rest...); } constexpr void CopyFromBin (std::byte * ptr) const { } template Archive& operator & (ngcore::Shallow& shallow) { if(shallow_to_python) Shallow(shallow.val); return *this; } // Archive shared_ptrs ================================================= template Archive& operator & (std::shared_ptr& ptr) { if constexpr(has_shallow_archive::value) if (shallow_to_python) { Shallow (ptr); return *this; } if(Output()) { // save -2 for nullptr if(!ptr) return (*this) << -2; void* reg_ptr = ptr.get(); bool neededDowncast = false; // Downcasting is only possible for our registered classes if(typeid(T) != typeid(*ptr)) { if(!IsRegistered(Demangle(typeid(*ptr).name()))) throw Exception(std::string("Archive error: Polymorphic type ") + Demangle(typeid(*ptr).name()) + " not registered for archive"); reg_ptr = GetArchiveRegister(Demangle(typeid(*ptr).name())).downcaster(typeid(T), ptr.get()); // if there was a true downcast we have to store more information if(reg_ptr != static_cast(ptr.get())) neededDowncast = true; } auto pos = shared_ptr2nr.find(reg_ptr); // if not found store -1 and the pointer if(pos == shared_ptr2nr.end()) { auto p = ptr.get(); (*this) << -1; (*this) & neededDowncast & p; // if we did downcast we store the true type as well if(neededDowncast) (*this) << Demangle(typeid(*ptr).name()); shared_ptr2nr[reg_ptr] = shared_ptr_count++; return *this; } // if found store the position and if it has to be downcasted and how (*this) << pos->second << neededDowncast; if(neededDowncast) (*this) << Demangle(typeid(*ptr).name()); } else // Input { int nr; (*this) & nr; // -2 restores a nullptr if(nr == -2) { ptr = nullptr; return *this; } // -1 restores a new shared ptr by restoring the inner pointer and creating a shared_ptr to it if (nr == -1) { T* p = nullptr; bool neededDowncast; (*this) & neededDowncast & p; ptr = std::shared_ptr(p); // if we did downcast we need to store a shared_ptr to the true object if(neededDowncast) { std::string name; (*this) & name; auto info = GetArchiveRegister(name); // for this we use an aliasing constructor to create a shared pointer sharing lifetime // with our shared ptr, but pointing to the true object nr2shared_ptr.push_back(std::shared_ptr(std::static_pointer_cast(ptr), info.downcaster(typeid(T), ptr.get()))); } else nr2shared_ptr.push_back(ptr); } else { auto other = nr2shared_ptr[nr]; bool neededDowncast; (*this) & neededDowncast; if(neededDowncast) { // if there was a downcast we can expect the class to be registered (since archiving // wouldn't have worked else) std::string name; (*this) & name; auto info = GetArchiveRegister(name); // same trick as above, create a shared ptr sharing lifetime with // the shared_ptr in the register, but pointing to our object ptr = std::static_pointer_cast(std::shared_ptr(other, info.upcaster(typeid(T), other.get()))); } else { ptr = std::static_pointer_cast(other); } } } return *this; } // Archive pointers ======================================================= template Archive & operator& (T *& p) { if (Output()) { // if the pointer is null store -2 if (!p) return (*this) << -2; auto reg_ptr = static_cast(p); if(typeid(T) != typeid(*p)) { if(!IsRegistered(Demangle(typeid(*p).name()))) throw Exception(std::string("Archive error: Polymorphic type ") + Demangle(typeid(*p).name()) + " not registered for archive"); reg_ptr = GetArchiveRegister(Demangle(typeid(*p).name())).downcaster(typeid(T), static_cast(p)); } auto pos = ptr2nr.find(reg_ptr); // if the pointer is not found in the map create a new entry if (pos == ptr2nr.end()) { ptr2nr[reg_ptr] = ptr_count++; if(typeid(*p) == typeid(T)) if (std::is_constructible::value) return (*this) << -1 & (*p); else { if (IsRegistered(Demangle(typeid(*p).name()))) { (*this) << -3 << Demangle(typeid(*p).name()); GetArchiveRegister(Demangle(typeid(*p).name())). cargs_archiver(*this, p); return (*this) & (*p); } else throw Exception(std::string("Archive error: Class ") + Demangle(typeid(*p).name()) + " does not provide a default constructor!"); } else { // if a pointer to a base class is archived, the class hierarchy must be registered // to avoid compile time issues we allow this behaviour only for "our" classes that // implement a void DoArchive(Archive&) member function // To recreate the object we need to store the true type of it if(!IsRegistered(Demangle(typeid(*p).name()))) throw Exception(std::string("Archive error: Polymorphic type ") + Demangle(typeid(*p).name()) + " not registered for archive"); (*this) << -3 << Demangle(typeid(*p).name()); GetArchiveRegister(Demangle(typeid(*p).name())). cargs_archiver(*this, p); return (*this) & (*p); } } else { (*this) & pos->second; bool downcasted = !(reg_ptr == static_cast(p) ); // store if the class has been downcasted and the name (*this) << downcasted << Demangle(typeid(*p).name()); } } else { int nr; (*this) & nr; if (nr == -2) // restore a nullptr p = nullptr; else if (nr == -1) // create a new pointer of standard type (no virtual or multiple inheritance,...) { p = detail::constructIfPossible(); nr2ptr.push_back(p); (*this) & *p; } else if(nr == -3) // restore one of our registered classes that can have multiple inheritance,... { // As stated above, we want this special behaviour only for our classes that implement DoArchive std::string name; (*this) & name; auto info = GetArchiveRegister(name); // the creator creates a new object of type name, and returns a void* pointing // to T (which may have an offset) p = static_cast(info.creator(typeid(T), *this)); // we store the downcasted pointer (to be able to find it again from // another class in a multiple inheritance tree) nr2ptr.push_back(info.downcaster(typeid(T),p)); (*this) & *p; } else { bool downcasted; std::string name; (*this) & downcasted & name; if(downcasted) { // if the class has been downcasted we can assume it is in the register auto info = GetArchiveRegister(name); p = static_cast(info.upcaster(typeid(T), nr2ptr[nr])); } else p = static_cast(nr2ptr[nr]); } } return *this; } Archive& operator&(std::tuple<>&) { return *this; } template Archive& operator&(std::tuple &t) { // call operator& for each element of the tuple std::apply([this](auto&... arg) { std::make_tuple(((*this) & arg).IsParallel()...);}, t); return *this; } // const ptr template Archive& operator &(const T*& t) { return (*this) & const_cast(t); // NOLINT } // Write a read only variable template Archive & operator << (const T & t) { T ht(t); (*this) & ht; return *this; } virtual void FlushBuffer() {} bool parallel = false; bool IsParallel() const { return parallel; } void SetParallel (bool _parallel) { parallel = _parallel; } private: template friend class RegisterClassForArchive; #ifdef NETGEN_PYTHON friend pybind11::object CastAnyToPy(const std::any&); friend std::any CastPyToAny(pybind11::object&); #endif // NETGEN_PYTHON // Returns ClassArchiveInfo of Demangled typeid static const detail::ClassArchiveInfo& GetArchiveRegister(const std::string& classname); // Set ClassArchiveInfo for Demangled typeid, this is done by creating an instance of // RegisterClassForArchive static void SetArchiveRegister(const std::string& classname, const detail::ClassArchiveInfo& info); static bool IsRegistered(const std::string& classname); // Helper class for up-/downcasting template struct Caster{}; template struct Caster> { static void* tryUpcast (const std::type_info& /*unused*/, T* /*unused*/) { throw Exception("Upcast not successful, some classes are not registered properly for archiving!"); } static void* tryDowncast (const std::type_info& /*unused*/, void* /*unused*/) { throw Exception("Downcast not successful, some classes are not registered properly for archiving!"); } }; template struct Caster { static void* tryUpcast(const std::type_info& ti, T* p) { try { return GetArchiveRegister(Demangle(typeid(B1).name())) .upcaster(ti, static_cast(dynamic_cast(p))); } catch (const Exception &) { throw Exception("Upcast not successful, some classes are not " "registered properly for archiving!"); } } static void* tryDowncast(const std::type_info& ti, void* p) { if(typeid(B1) == ti) return dynamic_cast(static_cast(p)); try { return dynamic_cast(static_cast(GetArchiveRegister(Demangle(typeid(B1).name())). downcaster(ti, p))); } catch (const Exception &) { throw Exception("Downcast not successful, some classes are not " "registered properly for archiving!"); } } }; template struct Caster> { static void* tryUpcast(const std::type_info& ti, T* p) { try { return GetArchiveRegister(Demangle(typeid(B1).name())). upcaster(ti, static_cast(dynamic_cast(p))); } catch(const Exception&) { return Caster>::tryUpcast(ti, p); } } static void* tryDowncast(const std::type_info& ti, void* p) { if(typeid(B1) == ti) return dynamic_cast(static_cast(p)); try { return dynamic_cast(static_cast(GetArchiveRegister(Demangle(typeid(B1).name())). downcaster(ti, p))); } catch(const Exception&) { return Caster>::tryDowncast(ti, p); } } }; }; // BinaryOutArchive ====================================================================== class NGCORE_API BinaryOutArchive : public Archive { static constexpr size_t BUFFERSIZE = 1024; std::array buffer{}; size_t ptr = 0; protected: std::shared_ptr stream; public: BinaryOutArchive() = delete; BinaryOutArchive(const BinaryOutArchive&) = delete; BinaryOutArchive(BinaryOutArchive&&) = delete; BinaryOutArchive(std::shared_ptr&& astream) : Archive(true), stream(std::move(astream)) { } BinaryOutArchive(const std::filesystem::path& filename) : BinaryOutArchive(std::make_shared(filename)) {} ~BinaryOutArchive () override { FlushBuffer(); } BinaryOutArchive& operator=(const BinaryOutArchive&) = delete; BinaryOutArchive& operator=(BinaryOutArchive&&) = delete; using Archive::operator&; Archive & operator & (std::byte & d) override { return Write(d); } Archive & operator & (float & f) override { return Write(f); } Archive & operator & (double & d) override { return Write(d); } Archive & operator & (int & i) override { return Write(i); } Archive & operator & (short & i) override { return Write(i); } Archive & operator & (long & i) override { // for platform independence if constexpr (sizeof(long) == 8) return Write(i); else return Write(static_cast(i)); } Archive & operator & (size_t & i) override { // for platform independence if constexpr (sizeof(size_t) == 8) return Write(i); else return Write(static_cast(i)); } Archive & operator & (unsigned char & i) override { return Write(i); } Archive & operator & (bool & b) override { return Write(b); } Archive & operator & (std::string & str) override { int len = str.length(); (*this) & len; FlushBuffer(); if(len) stream->write (&str[0], len); return *this; } Archive & operator & (char *& str) override { long len = str ? static_cast(strlen (str)) : -1; (*this) & len; FlushBuffer(); if(len > 0) stream->write (&str[0], len); // NOLINT return *this; } void FlushBuffer() override { if (ptr > 0) { stream->write(&buffer[0], ptr); ptr = 0; } } Archive & Do (std::byte * d, size_t n) override { FlushBuffer(); stream->write(reinterpret_cast(d), n*sizeof(std::byte)); return *this; } private: template Archive & Write (T x) { static_assert(sizeof(T) < BUFFERSIZE, "Cannot write large types with this function!"); if (unlikely(ptr > BUFFERSIZE-sizeof(T))) { stream->write(&buffer[0], ptr); ptr = 0; } memcpy(&buffer[ptr], &x, sizeof(T)); ptr += sizeof(T); return *this; } }; // BinaryInArchive ====================================================================== class NGCORE_API BinaryInArchive : public Archive { protected: std::shared_ptr stream; public: BinaryInArchive (std::shared_ptr&& astream) : Archive(false), stream(std::move(astream)) { } BinaryInArchive (const std::filesystem::path& filename) : BinaryInArchive(std::make_shared(filename)) { ; } using Archive::operator&; Archive & operator & (std::byte & d) override { Read(d); return *this; } Archive & operator & (float & f) override { Read(f); return *this; } Archive & operator & (double & d) override { Read(d); return *this; } Archive & operator & (int & i) override { Read(i); return *this; } Archive & operator & (short & i) override { Read(i); return *this; } Archive & operator & (long & i) override { // for platform independence if constexpr (sizeof(long) == 8) Read(i); else { int64_t tmp = 0; Read(tmp); i = tmp; } return *this; } Archive & operator & (size_t & i) override { // for platform independence if constexpr (sizeof(long) == 8) Read(i); else { uint64_t tmp = 0; Read(tmp); i = tmp; } return *this; } Archive & operator & (unsigned char & i) override { Read(i); return *this; } Archive & operator & (bool & b) override { Read(b); return *this; } Archive & operator & (std::string & str) override { int len; (*this) & len; str.resize(len); if(len) stream->read(&str[0], len); // NOLINT return *this; } Archive & operator & (char *& str) override { long len; (*this) & len; if(len == -1) str = nullptr; else { str = new char[len+1]; // NOLINT stream->read(&str[0], len); // NOLINT str[len] = '\0'; // NOLINT } return *this; } Archive & Do (std::byte * d, size_t n) override { stream->read(reinterpret_cast(d), n*sizeof(std::byte)); return *this; } // NOLINT Archive & Do (double * d, size_t n) override { stream->read(reinterpret_cast(d), n*sizeof(double)); return *this; } // NOLINT Archive & Do (int * i, size_t n) override { stream->read(reinterpret_cast(i), n*sizeof(int)); return *this; } // NOLINT Archive & Do (size_t * i, size_t n) override { // for platform independence if constexpr (sizeof(long) == 8) stream->read(reinterpret_cast(i), n*sizeof(size_t)); // NOLINT else for(size_t j = 0; j < n; j++) (*this) & i[j]; return *this; } private: template inline void Read(T& val) { stream->read(reinterpret_cast(&val), sizeof(T)); } // NOLINT }; // TextOutArchive ====================================================================== class NGCORE_API TextOutArchive : public Archive { protected: std::shared_ptr stream; public: TextOutArchive (std::shared_ptr&& astream) : Archive(true), stream(std::move(astream)) { } TextOutArchive (const std::filesystem::path& filename) : TextOutArchive(std::make_shared(filename)) { } using Archive::operator&; Archive & operator & (std::byte & d) override { *stream << int(d) << ' '; return *this; } Archive & operator & (float & f) override { *stream << f << '\n'; return *this; } Archive & operator & (double & d) override { *stream << d << '\n'; return *this; } Archive & operator & (int & i) override { *stream << i << '\n'; return *this; } Archive & operator & (short & i) override { *stream << i << '\n'; return *this; } Archive & operator & (long & i) override { *stream << i << '\n'; return *this; } Archive & operator & (size_t & i) override { *stream << i << '\n'; return *this; } Archive & operator & (unsigned char & i) override { *stream << int(i) << '\n'; return *this; } Archive & operator & (bool & b) override { *stream << (b ? 't' : 'f') << '\n'; return *this; } Archive & operator & (std::string & str) override { int len = str.length(); *stream << len << '\n'; if(len) { stream->write(&str[0], len); // NOLINT *stream << '\n'; } return *this; } Archive & operator & (char *& str) override { long len = str ? static_cast(strlen (str)) : -1; *this & len; if(len > 0) { stream->write (&str[0], len); // NOLINT *stream << '\n'; } return *this; } }; // TextInArchive ====================================================================== class NGCORE_API TextInArchive : public Archive { protected: std::shared_ptr stream; public: TextInArchive (std::shared_ptr&& astream) : Archive(false), stream(std::move(astream)) { } TextInArchive (const std::filesystem::path& filename) : TextInArchive(std::make_shared(filename)) {} using Archive::operator&; Archive & operator & (std::byte & d) override { int tmp; *stream >> tmp; d = std::byte(tmp); return *this; } Archive & operator & (float & f) override { *stream >> f; return *this; } Archive & operator & (double & d) override { *stream >> d; return *this; } Archive & operator & (int & i) override { *stream >> i; return *this; } Archive & operator & (short & i) override { *stream >> i; return *this; } Archive & operator & (long & i) override { *stream >> i; return *this; } Archive & operator & (size_t & i) override { *stream >> i; return *this; } Archive & operator & (unsigned char & i) override { int _i; *stream >> _i; i = _i; return *this; } Archive & operator & (bool & b) override { char c; *stream >> c; b = (c=='t'); return *this; } Archive & operator & (std::string & str) override { // Ignore \r (carriage return) characters when reading strings // this is necessary for instance when a file was written on Windows and is read on Unix int len; *stream >> len; char ch; stream->get(ch); // read newline character if(ch == '\r') // windows line endings -> read \n as well stream->get(ch); str.resize(len); if(len) stream->get(&str[0], len+1, '\0'); // remove all \r characters from the string, check if size changed // if so, read the remaining characters str.erase(std::remove(str.begin(), str.end(), '\r'), str.cend()); size_t chars_to_read = len-str.size(); while (chars_to_read>0) { auto old_size = str.size(); str.resize(len); stream->get(&str[old_size], chars_to_read+1, '\0'); str.erase(std::remove(str.begin()+old_size, str.end(), '\r'), str.cend()); chars_to_read = len - str.size(); } return *this; } Archive & operator & (char *& str) override { long len; (*this) & len; char ch; if(len == -1) { str = nullptr; return (*this); } str = new char[len+1]; // NOLINT if(len) { stream->get(ch); // \n if(ch == '\r') // windows line endings, read \n as well stream->get(ch); stream->get(&str[0], len+1, '\0'); // NOLINT } str[len] = '\0'; // NOLINT return *this; } }; // HashArchive ================================================================= // This class enables to easily create hashes for archivable objects by xoring // threw its data class NGCORE_API HashArchive : public Archive { size_t hash_value = 0; char* h; int offset = 0; public: HashArchive() : Archive(true) { h = (char*)&hash_value; } using Archive::operator&; Archive & operator & (std::byte & d) override { return ApplyHash(d); } Archive & operator & (float & f) override { return ApplyHash(f); } Archive & operator & (double & d) override { return ApplyHash(d); } Archive & operator & (int & i) override { return ApplyHash(i); } Archive & operator & (short & i) override { return ApplyHash(i); } Archive & operator & (long & i) override { return ApplyHash(i); } Archive & operator & (size_t & i) override { return ApplyHash(i); } Archive & operator & (unsigned char & i) override { return ApplyHash(i); } Archive & operator & (bool & b) override { return ApplyHash(b); } Archive & operator & (std::string & str) override { for(auto c : str) ApplyHash(c); return *this; } Archive & operator & (char *& str) override { char* s = str; while(*s != '\0') ApplyHash(*(s++)); return *this; } // HashArchive can be used in const context template Archive & operator& (const T& val) const { return (*this) & const_cast(val); } size_t GetHash() const { return hash_value; } private: template Archive& ApplyHash(T val) { size_t n = sizeof(T); char* pval = (char*)&val; for(size_t i = 0; i < n; i++) { h[offset++] ^= pval[i]; offset %= 8; } return *this; } }; NGCORE_API std::map & GetTypeRegister(); } // namespace ngcore #endif // NETGEN_CORE_ARCHIVE_HPP ================================================ FILE: libsrc/core/array.hpp ================================================ #ifndef NETGEN_CORE_ARRAY_HPP #define NETGEN_CORE_ARRAY_HPP /**************************************************************************/ /* File: array.hpp */ /* Author: Joachim Schoeberl */ /* Date: 01. Jun. 95 */ /**************************************************************************/ #include #include #include #include "exception.hpp" #include "logging.hpp" // for logger #include "ngcore_api.hpp" // for NGCORE_API #include "type_traits.hpp" // for all_of_tmpl #include "localheap.hpp" #include "memtracer.hpp" #include "utils.hpp" namespace ngcore { using std::ostream; template class Tuple { public: int Size() const { return 0; } }; template class Tuple : Tuple { typedef Tuple BASE; HEAD head; public: Tuple () { ; } Tuple (HEAD h, TAIL ... t) : Tuple (t...), head(h) { ; } HEAD Head() const { return head; } Tuple Tail() const { return *this; } int Size() const { return BASE::Size()+1; } }; template ostream & operator<< (ostream & ost, Tuple /* tup */) { return ost; } template ostream & operator<< (ostream & ost, Tuple tup) { ost << tup.Head() << ", " << tup.Tail(); return ost; } template Tuple MakeTuple (ARGS ... args) { return Tuple (args...); } template class AOWrapperIterator { const AO & ao; size_t ind; public: NETGEN_INLINE AOWrapperIterator (const AO & aao, size_t ai) : ao(aao), ind(ai) { ; } NETGEN_INLINE AOWrapperIterator operator++ (int) { return AOWrapperIterator(ao, ind++); } NETGEN_INLINE AOWrapperIterator& operator++ () { ++ind; return *this; } NETGEN_INLINE auto operator*() const -> decltype(ao[ind]) { return ao[ind]; } NETGEN_INLINE auto operator*() -> decltype(ao[ind]) { return ao[ind]; } NETGEN_INLINE bool operator != (AOWrapperIterator d2) { return ind != d2.ind; } NETGEN_INLINE bool operator == (AOWrapperIterator d2) { return ind == d2.ind; } }; /* Some class which can be treated as array */ template // , typename TA = T> class BaseArrayObject { public: NETGEN_INLINE BaseArrayObject() { ; } NETGEN_INLINE const T & Spec() const { return static_cast (*this); } NETGEN_INLINE size_t Size() const { return Spec().Size(); } template NETGEN_INLINE bool Contains(const T2 & el) const { for (size_t i = 0; i < Size(); i++) if (Spec()[i] == el) return true; return false; } static constexpr size_t ILLEGAL_POSITION = size_t(-1); template NETGEN_INLINE size_t Pos(const T2 & el) const { for (size_t i = 0; i < Size(); i++) if (Spec()[i] == el) return i; return ILLEGAL_POSITION; } template NETGEN_INLINE size_t PosSure(const T2 & el) const { for (size_t i = 0; ; i++) if (Spec()[i] == el) return i; } // NETGEN_INLINE auto & operator[] (size_t i) { return Spec()[i]; } NETGEN_INLINE auto operator[] (size_t i) const { return Spec()[i]; } // NETGEN_INLINE auto begin() const { return Spec().begin(); } // NETGEN_INLINE auto end() const { return Spec().end(); } NETGEN_INLINE auto begin () const { return AOWrapperIterator (*this, 0); } NETGEN_INLINE auto end () const { return AOWrapperIterator (*this, Size()); } }; template class AOWrapper : public BaseArrayObject> { T ar; public: NETGEN_INLINE AOWrapper (T aar) : ar(aar) { ; } NETGEN_INLINE operator T () const { return ar; } NETGEN_INLINE size_t Size() const { return ar.Size(); } NETGEN_INLINE auto operator[] (size_t i) { return ar[i]; } NETGEN_INLINE auto operator[] (size_t i) const { return ar[i]; } NETGEN_INLINE AOWrapperIterator begin () const { return AOWrapperIterator (*this, 0); } NETGEN_INLINE AOWrapperIterator end () const { return AOWrapperIterator (*this, Size()); } }; template NETGEN_INLINE AOWrapper ArrayObject (const T & ar) { return AOWrapper (ar); } template NETGEN_INLINE AOWrapper ArrayObject (T && ar) { return AOWrapper (ar); } template auto ArrayObject (size_t s, FUNC f) { class Dummy { size_t s; FUNC f; public: Dummy (size_t _s, FUNC _f) : s(_s), f(_f) { ; } size_t Size() const { return s; } auto operator[] (size_t i) const { return f(i); } }; return ArrayObject(Dummy(s,f)); } template auto Substitute (const BaseArrayObject & ao, FUNC f) { return ArrayObject(ao.Size(), [&ao,f] (size_t i) { return f(ao[i]); }); } /** nothing more but a new type for a C array. return value for Addr - operator of array */ template class CArray { protected: /// the data T * data; public: /// initialize array NETGEN_INLINE CArray () { data = 0; } /// provide size and memory NETGEN_INLINE CArray (T * adata) : data(adata) { ; } /// Access array NETGEN_INLINE T & operator[] (size_t i) const { return data[i]; } NETGEN_INLINE operator T* () const { return data; } }; template constexpr T IndexBASE () { return T(0); } template constexpr T IndexBASE (T ind) { return IndexBASE(); } class IndexFromEnd { ptrdiff_t i; public: constexpr IndexFromEnd (ptrdiff_t ai) : i(ai) { } IndexFromEnd operator+ (ptrdiff_t inc) const { return i+inc; } IndexFromEnd operator- (ptrdiff_t dec) const { return i-dec; } // operator ptrdiff_t () const { return i; } ptrdiff_t Value() const { return i; } }; constexpr IndexFromEnd END(0); template class FlatArray; template class ArrayIterator { FlatArray ar; IndexType ind; public: NETGEN_INLINE ArrayIterator (FlatArray aar, IndexType ai) : ar(aar), ind(ai) { ; } NETGEN_INLINE ArrayIterator operator++ (int) { return ArrayIterator(ar, ind++); } NETGEN_INLINE ArrayIterator operator++ () { return ArrayIterator(ar, ++ind); } // NETGEN_INLINE const TELEM & operator*() const { return ar[ind]; } // NETGEN_INLINE TELEM & operator*() { return ar[ind]; } NETGEN_INLINE auto operator*() const -> decltype(ar[ind]) { return ar[ind]; } NETGEN_INLINE auto operator*() -> decltype(ar[ind]) { return ar[ind]; } NETGEN_INLINE bool operator != (ArrayIterator d2) { return ind != d2.ind; } NETGEN_INLINE bool operator == (ArrayIterator d2) { return ind == d2.ind; } }; template class ArrayRangeIterator { TSIZE ind; public: NETGEN_INLINE ArrayRangeIterator (TSIZE ai) : ind(ai) { ; } NETGEN_INLINE ArrayRangeIterator operator++ (int) { return ind++; } NETGEN_INLINE ArrayRangeIterator operator++ () { return ++ind; } NETGEN_INLINE TSIZE operator*() const { return ind; } NETGEN_INLINE TSIZE Index() { return ind; } NETGEN_INLINE operator TSIZE () const { return ind; } NETGEN_INLINE bool operator != (ArrayRangeIterator d2) { return ind != d2.ind; } NETGEN_INLINE bool operator == (ArrayRangeIterator d2) { return ind == d2.ind; } }; /// a range of integers template class T_Range : public BaseArrayObject > { T first, next; public: NETGEN_INLINE T_Range () { ; } // NETGEN_INLINE T_Range (T n) : first(0), next(n) {;} NETGEN_INLINE explicit T_Range (size_t n) : first(IndexBASE()), next(IndexBASE()+n) {;} NETGEN_INLINE T_Range (T f, T n) : first(f), next(n) {;} template NETGEN_INLINE T_Range(T_Range r2) : first(r2.First()), next(r2.Next()) { ; } NETGEN_INLINE T First() const { return first; } NETGEN_INLINE T Next() const { return next; } NETGEN_INLINE T & First() { return first; } NETGEN_INLINE T & Next() { return next; } NETGEN_INLINE auto Size() const { return next-first; } NETGEN_INLINE T operator[] (size_t i) const { return first+i; } NETGEN_INLINE bool Contains (T i) const { return ((i >= first) && (i < next)); } NETGEN_INLINE T_Range Modify(int inc_beg, int inc_end) const { return T_Range(first+inc_beg, next+inc_end); } NETGEN_INLINE ArrayRangeIterator begin() const { return first; } NETGEN_INLINE ArrayRangeIterator end() const { return next; } NETGEN_INLINE T_Range Split (size_t nr, int tot) const { auto diff = next-first; return T_Range (first + nr * diff / tot, first + (nr+1) * diff / tot); } // NETGEN_INLINE operator IntRange () const { return IntRange(first,next); } }; using IntRange = T_Range; template NETGEN_INLINE T_Range Range (T a, T b) { return T_Range(a,b); } template NETGEN_INLINE auto Range (const T& ao) -> typename std::enable_if, decltype(std::declval().Range())>::type { return ao.Range(); } template NETGEN_INLINE auto Range (FlatArray fa) { return fa.Range(); } template NETGEN_INLINE T_Range Range_impl (T n, std::true_type) { return T_Range (0, n); } template NETGEN_INLINE auto Range_impl (const TA & ao, std::false_type) -> T_Range> { return T_Range> (IndexBASE>(), IndexBASE>() + index_type(ao.Size())); } /* Range(obj) will create a range in using the following steps: * if obj is an integral type it will create T_Range(0, obj) * if obj has a function Range() it will return obj.Range() * if obj has a typedef index_type it will return T_Range(IndexBASE(), IndexBASE() + index_type(obj.Size())) * else it will return T_Range (0, obj.Size()) */ template NETGEN_INLINE auto Range(const T & x) -> typename std::enable_if || !has_range, decltype(Range_impl(x, std::is_integral()))>::type { return Range_impl(x, std::is_integral()); } NETGEN_INLINE IntRange operator+ (const IntRange & range, int shift) { return IntRange (range.First()+shift, range.Next()+shift); } NETGEN_INLINE IntRange operator+ (int shift, const IntRange & range) { return IntRange (range.First()+shift, range.Next()+shift); } NETGEN_INLINE IntRange operator* (int scale, const IntRange & range) { return IntRange (scale*range.First(), scale*range.Next()); } NETGEN_INLINE IntRange operator* (const IntRange & range, int scale) { return IntRange (scale*range.First(), scale*range.Next()); } template inline ostream & operator<< (ostream & s, T_Range ir) { s << "[" << ir.First() << "," << ir.Next() << ")"; return s; } template ostream & operator<< (ostream & ost, Tuple tup) { ost << tup.Head() << ", " << tup.Tail(); return ost; } template inline ostream & operator<< (ostream & ost, const BaseArrayObject & array) { for (auto i : Range(array.Size())) ost << i << ":" << array[i] << std::endl; return ost; } template class IndirectArray : public BaseArrayObject > { FlatArray ba; const INDEX_ARRAY & ia; public: NETGEN_INLINE IndirectArray (FlatArray aba, const INDEX_ARRAY & aia) : ba(aba), ia(aia) { ; } NETGEN_INLINE size_t Size() const { return ia.Size(); } NETGEN_INLINE T & operator[] (size_t i) const { return ba[ia[i]]; } // NETGEN_INLINE T & operator[] (size_t i) { return ba[ia[i]]; } NETGEN_INLINE IndirectArray operator= (const T & val) { for (auto i : Range(Size())) (*this)[i] = val; return IndirectArray (ba, ia); } template NETGEN_INLINE IndirectArray operator= (const BaseArrayObject & a2) { for (auto i : Range(Size())) (*this)[i] = a2[i]; return IndirectArray (ba, ia); } NETGEN_INLINE AOWrapperIterator begin() const { return { *this, 0 }; } NETGEN_INLINE AOWrapperIterator end() const { return { *this, Size() }; } }; /** 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 NETGEN_CHECK_RANGE */ template class FlatArray : public BaseArrayObject > { protected: static constexpr IndexType BASE = IndexBASE(); /// the size size_t size = 0; /// the data T * __restrict data = nullptr; public: typedef T value_type; typedef IndexType index_type; using BaseArrayObject::ILLEGAL_POSITION; /// initialize array FlatArray () = default; // { ; } // size = 0; data = 0; } /// copy constructor allows size-type conversion FlatArray (const FlatArray & a2) = default; // : size(a2.Size()), data(a2.data) { ; } /// provide size and memory NETGEN_INLINE FlatArray (size_t asize, T * adata) : size(asize), data(adata) { ; } /// memory from local heap NETGEN_INLINE FlatArray(size_t asize, Allocator & lh) : size(asize), data(new (lh) T[asize]) { ; } NETGEN_INLINE FlatArray(size_t asize, LocalHeap & lh) : size(asize), data (lh.Alloc (asize)) { ; } template NETGEN_INLINE FlatArray(std::array & a) : size(N), data(&a[0]) { } /// the size NETGEN_INLINE size_t Size() const { return size; } /// the data NETGEN_INLINE T* Data() const { return data; } /// Fill array with value val NETGEN_INLINE const FlatArray & operator= (const T & val) const { size_t hsize = size; T * hdata = data; for (size_t i = 0; i < hsize; i++) hdata[i] = val; return *this; } /// copies array NETGEN_INLINE const FlatArray & operator= (const FlatArray & a2) const { size_t hsize = size; T * hdata = data; for (size_t i = 0; i < hsize; i++) hdata[i] = a2.data[i]; return *this; } template NETGEN_INLINE const FlatArray & operator= (const BaseArrayObject & a2) const { size_t hsize = size; T * hdata = data; auto p2 = a2.begin(); for (size_t i = 0; i < hsize; i++, p2++) hdata[i] = *p2; return *this; } template ::value>> NETGEN_INLINE const FlatArray & operator= (const T2 & func) const { for (size_t i = 0; i < size; i++) data[i] = func(i+BASE); return *this; } // template // const FlatArray operator= (ParallelValue val); // template // const FlatArray operator= (ParallelFunction val); /// copies pointers NETGEN_INLINE const FlatArray & Assign (const FlatArray & a2) { size = a2.size; data = a2.data; return *this; } /// assigns memory from local heap NETGEN_INLINE const FlatArray & Assign (size_t asize, LocalHeap & lh) { size = asize; data = lh.Alloc (asize); return *this; } /// Access array. range check by macro NETGEN_CHECK_RANGE NETGEN_INLINE T & operator[] (IndexType i) const { NETGEN_CHECK_RANGE(i,BASE,size+BASE); return data[i-BASE]; } NETGEN_INLINE T_Range Range () const { return T_Range (BASE, size+BASE); } NETGEN_INLINE const CArray Addr (size_t pos) const { return CArray (data+pos-BASE); } // const CArray operator+ (int pos) // { return CArray (data+pos); } NETGEN_INLINE T * operator+ (size_t pos) const { return data+pos; } /// access first element. check by macro NETGEN_CHECK_RANGE T & First () const { NETGEN_CHECK_RANGE(0,0,size); return data[0]; } /// access last element. check by macro NETGEN_CHECK_RANGE T & Last () const { NETGEN_CHECK_RANGE(size-1,0,size); return data[size-1]; } /// takes sub-array starting from position pos NETGEN_INLINE const FlatArray Part (size_t pos) { return FlatArray (size-pos, data+pos); } /// takes subsize elements starting from position pos NETGEN_INLINE const FlatArray Part (size_t pos, size_t subsize) { return FlatArray (subsize, data+pos); } /// takes range starting from position start of end-start elements NETGEN_INLINE FlatArray Range (size_t start, size_t end) const { return FlatArray (end-start, data+start); } /// takes range starting from position start of end-start elements NETGEN_INLINE FlatArray Range (size_t start, IndexFromEnd indend) const { return this->Range(start, size_t(Size()+indend.Value())); } /// takes range starting from position start of end-start elements NETGEN_INLINE FlatArray Range (T_Range range) const { return FlatArray (range.Size(), data+range.First()); } /// takes range starting from position start of end-start elements NETGEN_INLINE const FlatArray operator[] (T_Range range) const { return FlatArray (range.Size(), data+range.First()); } template auto operator[] (const BaseArrayObject & ind_array) const { return IndirectArray > (*this, ind_array); } /// first position of element elem, returns -1 if element not contained in array NETGEN_INLINE size_t Pos(const T & el) const { for (size_t i = 0; i < Size(); i++) if (data[i] == el) return i; return ILLEGAL_POSITION; } /// does the array contain element elem ? NETGEN_INLINE bool Contains(const T & elem) const { return Pos(elem) != ILLEGAL_POSITION; } //auto begin() const { return ArrayIterator (*this, BASE); } // auto end() const { return ArrayIterator (*this, size+BASE); } NETGEN_INLINE auto begin() const { return data; } NETGEN_INLINE auto end() const { return data+Size(); } }; template FlatArray View (FlatArray fa) { return fa; } template auto Max (FlatArray array, typename std::remove_const::type max = std::numeric_limits::min()) -> T { for (auto & v : array) if (v > max) max = v; return max; } template auto Min (FlatArray array, typename std::remove_const::type min = std::numeric_limits::max()) -> T { for (auto & v : array) if (v < min) min = v; return min; } /// print array template inline ostream & operator<< (ostream & s, const FlatArray & a) { for (auto i : a.Range()) s << i << ": " << a[i] << "\n"; return s; } /// have arrays the same contents ? template inline bool operator== (const FlatArray & a1, const FlatArray & a2) { if (a1.Size () != a2.Size()) return 0; for (size_t i = 0; i < a1.Size(); i++) if (a1[i] != a2[i]) return false; return true; } template inline bool operator!= (const FlatArray & a1, const FlatArray & a2) { return !(a1==a2); } /** Dynamic array container. Array 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 Array : public FlatArray { protected: /// physical size of array size_t allocsize; /// that's the data we have to delete, nullptr for not owning the memory T * mem_to_delete; MemoryTracer mt; using FlatArray::size; using FlatArray::data; using FlatArray::BASE; public: using index_type = typename FlatArray::index_type; /// Generate array of logical and physical size asize NETGEN_INLINE explicit Array() : FlatArray (0, nullptr) { allocsize = 0; mem_to_delete = nullptr; } NETGEN_INLINE explicit Array(size_t asize) : FlatArray (asize, new T[asize]) { allocsize = asize; mem_to_delete = data; mt.Alloc(sizeof(T)*asize); } /// Generate array in user data NETGEN_INLINE Array(size_t asize, T* adata, bool ownMemory = false) : FlatArray (asize, adata) { allocsize = asize; if(ownMemory) { mem_to_delete = adata; mt.Alloc(sizeof(T)*asize); } else mem_to_delete = nullptr; } /// Generate array in user data template NETGEN_INLINE Array(size_t asize, ALLOCATOR & lh) : FlatArray (asize, lh) { allocsize = asize; mem_to_delete = nullptr; } NETGEN_INLINE Array (Array && a2) { mt = std::move(a2.mt); size = a2.size; data = a2.data; allocsize = a2.allocsize; mem_to_delete = a2.mem_to_delete; a2.size = 0; a2.allocsize = 0; a2.data = nullptr; a2.mem_to_delete = nullptr; } /// array copy NETGEN_INLINE explicit Array (const Array & a2) : FlatArray (a2.Size(), a2.Size() ? new T[a2.Size()] : nullptr) { if constexpr (std::is_copy_assignable::value) { allocsize = size; mem_to_delete = data; mt.Alloc(sizeof(T)*size); for (size_t i = 0; i < size; i++) data[i] = a2.data[i]; } // #ifdef __cpp_exceptions #ifndef __CUDA_ARCH__ else throw Exception(std::string("cannot copy-construct Array of type ") + typeid(T).name()); #endif } template explicit Array (const BaseArrayObject & a2) : FlatArray (a2.Size(), a2.Size() ? new T[a2.Size()] : nullptr) { allocsize = size; mem_to_delete = data; mt.Alloc(sizeof(T)*size); /* for (size_t i = 0; i < size; i++) data[i] = a2[i]; */ auto p2 = a2.begin(); for (size_t i = 0; i < size; i++, p2++) data[i] = *p2; } Array (std::initializer_list list) : FlatArray (list.size(), list.size() ? new T[list.size()] : NULL) { allocsize = size; mem_to_delete = data; mt.Alloc(sizeof(T)*size); size_t cnt = 0; for (auto val : list) data[cnt++] = val; } /// array merge-copy explicit Array (const Array & a2, const Array & a3) : FlatArray (a2.Size()+a3.Size(), a2.Size()+a3.Size() ? new T[a2.Size()+a3.Size()] : 0) { allocsize = size; mem_to_delete = data; mt.Alloc(sizeof(T)*size); for(size_t i = 0; i < a2.Size(); i++) data[i] = a2[i]; for (size_t i = a2.Size(), j=0; i < size; i++,j++) data[i] = a3[j]; } /// if responsible, deletes memory NETGEN_INLINE ~Array() { if(mem_to_delete) mt.Free(sizeof(T)*allocsize); delete [] mem_to_delete; } // Only provide this function if T is archivable template auto DoArchive(ARCHIVE& archive) -> typename std::enable_if_t, void> { if(archive.Output()) archive << size; else { size_t s; archive & s; SetSize(s); } archive.Do(data, size); } /// we tell the compiler that there is no need for deleting the array .. NETGEN_INLINE void NothingToDelete () { mem_to_delete = nullptr; // this memory is not managed by the Array anymore, so set the memory usage to 0 mt.Free(sizeof(T)*allocsize); } /// Change logical size. If necessary, do reallocation. Keeps contents. NETGEN_INLINE void SetSize(size_t nsize) { if (nsize > allocsize) ReSize (nsize); size = nsize; } /// NETGEN_INLINE void SetSize0() { size = 0; } /// Change physical size. Keeps logical size. Keeps contents. NETGEN_INLINE void SetAllocSize (size_t nallocsize) { if (nallocsize > allocsize) ReSize (nallocsize); } /// Change physical size. Keeps logical size. Keeps contents. NETGEN_INLINE size_t AllocSize () const { return allocsize; } /// assigns memory from local heap NETGEN_INLINE const Array & Assign (size_t asize, LocalHeap & lh) { if(mem_to_delete) mt.Free(sizeof(T)*allocsize); delete [] mem_to_delete; size = allocsize = asize; data = lh.Alloc (asize); mem_to_delete = nullptr; return *this; } /// Add element at end of array. reallocation if necessary. /// Returns index of new element. NETGEN_INLINE index_type Append (const T & el) { if (size == allocsize) ReSize (size+1); data[size] = el; return BASE + size++; } /// Add element at end of array. reallocation not necessary. /// Returns index of new element. NETGEN_INLINE index_type AppendHaveMem (const T & el) { NETGEN_CHECK_RANGE(size, 0, allocsize); data[size] = el; return BASE + size++; } /// Add element at end of array. reallocation if necessary. /// Returns index of new element. NETGEN_INLINE index_type Append (T && el) { if (size == allocsize) ReSize (size+1); data[size] = std::move(el); return BASE + size++; } // Add elements of initializer list to end of array. Reallocation if necessary. NETGEN_INLINE void Append(std::initializer_list lst) { if(allocsize < size + lst.size()) ReSize(size+lst.size()); for(auto val : lst) data[size++] = val; } /// Add element at end of array. reallocation if necessary. NETGEN_INLINE void Insert (size_t pos, const T & el) { if (size == allocsize) ReSize (size+1); for (size_t i = size; i > pos; i--) data[i] = data[i-1]; data[pos] = el; size++; } NETGEN_INLINE Array & operator += (const T & el) { Append (el); return *this; } /// Append array at end of array. reallocation if necessary. NETGEN_INLINE void Append (FlatArray source) { if(size + source.Size() >= allocsize) ReSize (size + source.Size() + 1); for(size_t i = size, j=0; jsize; j++) this->data[j] = this->data[j+1]; this->size--; } template NETGEN_INLINE void RemoveElementIf (FUNC func) { ptrdiff_t move_forward = 0; for (size_t j = 0; j < this->size; j++) { if (func(this->data[j])) move_forward++; else { if (move_forward > 0) this->data[j-move_forward] = this->data[j]; } } this->size -= move_forward; } /// Delete last element. NETGEN_INLINE void DeleteLast () { NETGEN_CHECK_RANGE(size-1,0,size); size--; } /// Deallocate memory NETGEN_INLINE void DeleteAll () { if(mem_to_delete) mt.Free(sizeof(T)*allocsize); delete [] mem_to_delete; mem_to_delete = NULL; data = 0; size = allocsize = 0; } /// Fill array with val NETGEN_INLINE Array & operator= (const T & val) { FlatArray::operator= (val); return *this; } /// array copy NETGEN_INLINE Array & operator= (const Array & a2) { if constexpr (std::is_copy_assignable::value) { SetSize0 (); SetSize (a2.Size()); for (size_t i = 0; i < size; i++) data[i] = a2.data[i]; return *this; } #ifndef __CUDA_ARCH__ else throw Exception(std::string("cannot copy Array of type ") + typeid(T).name()); #endif } /// steal array NETGEN_INLINE Array & operator= (Array && a2) { mt = std::move(a2.mt); ngcore::Swap (size, a2.size); ngcore::Swap (data, a2.data); ngcore::Swap (allocsize, a2.allocsize); ngcore::Swap (mem_to_delete, a2.mem_to_delete); return *this; } /// array copy NETGEN_INLINE Array & operator= (const FlatArray & a2) { SetSize (a2.Size()); for (size_t i = 0; i < size; i++) data[i] = a2[i]; return *this; } /* /// fill array with first, first+1, ... Array & operator= (const IntRange & range) { SetSize (range.Size()); for (int i = 0; i < size; i++) (*this)[i] = range.First()+i; return *this; } */ template Array & operator= (const BaseArrayObject & a2) { size_t newsize = a2.Spec().Size(); SetSize0 (); SetSize (newsize); // for (size_t i = 0; i < newsize; i++) // (*this)[i] = a2.Spec()[i]; size_t i = 0; for (auto val : a2.Spec()) (*this)[i++] = val; return *this; } template Array & operator= (Tuple tup) { SetSize (ArraySize (tup)); StoreToArray (*this, tup); return *this; } Array & operator= (std::initializer_list list) { *this = Array (list); return *this; } // template // Array & operator= (ParallelValue val) // { // FlatArray::operator= (val); // return *this; // } // template // Array & operator= (ParallelFunction val) // { // FlatArray::operator= (val); // return *this; // } NETGEN_INLINE void Swap (Array & b) { mt = std::move(b.mt); ngcore::Swap (size, b.size); ngcore::Swap (data, b.data); ngcore::Swap (allocsize, b.allocsize); ngcore::Swap (mem_to_delete, b.mem_to_delete); } NETGEN_INLINE void StartMemoryTracing () const { if(mem_to_delete) mt.Alloc(sizeof(T) * allocsize); } const MemoryTracer& GetMemoryTracer() const { return mt; } private: /// resize array, at least to size minsize. copy contents NETGEN_INLINE void ReSize (size_t minsize); }; /// resize array, at least to size minsize. copy contents template NETGEN_INLINE void Array :: ReSize (size_t minsize) { size_t nsize = 2 * allocsize; if (nsize < minsize) nsize = minsize; T * hdata = data; data = new T[nsize]; mt.Alloc(sizeof(T) * nsize); if (hdata) { size_t mins = (nsize < size) ? nsize : size; #if defined(__GNUG__) && __GNUC__ < 5 && !defined(__clang__) for (size_t i = 0; i < mins; i++) data[i] = std::move(hdata[i]); #else if (std::is_trivially_copyable::value) memcpy ((void*)data, hdata, sizeof(T)*mins); else for (size_t i = 0; i < mins; i++) data[i] = std::move(hdata[i]); #endif if(mem_to_delete) mt.Free(sizeof(T) * allocsize); delete [] mem_to_delete; } mem_to_delete = data; allocsize = nsize; } //extern template class Array; /** Array with static and dynamic memory management. Declares a static array which size is given by the template parameter. If the dynamic size fits into the static size, use static memory, otherwise perform dynamic allocation */ template class ArrayMem : public Array { T mem[S]; using Array::size; using Array::allocsize; using Array::data; using Array::mem_to_delete; using Array::mt; // using Array::ownmem; public: /// Generate array of logical and physical size asize explicit ArrayMem(size_t asize = 0) : Array (S, mem) { size = asize; if (asize > S) { data = new T[asize]; allocsize = size; mem_to_delete = data; mt.Alloc(sizeof(T)*asize); } } /// copies from Array a2 explicit ArrayMem(const Array & a2) : Array (S, (T*)mem) { Array::operator= (a2); } /// copies from ArrayMem a2 explicit ArrayMem(const ArrayMem & a2) : Array (S, (T*)mem) { Array::operator= (a2); } ArrayMem(ArrayMem && a2) : Array (a2.Size(), (T*)mem) { mt = std::move(a2.mt); if (a2.mem_to_delete) { mem_to_delete = a2.mem_to_delete; data = a2.data; allocsize = a2.allocsize; a2.mem_to_delete = nullptr; a2.data = nullptr; a2.size = 0; } else { allocsize = S; for (auto i : ngcore::Range(size)) mem[i] = a2.mem[i]; } } ArrayMem (std::initializer_list list) : ArrayMem (list.size()) { size_t cnt = 0; for (auto val : list) data[cnt++] = val; } template ArrayMem (const BaseArrayObject & a2) : ArrayMem (a2.Size()) { for (size_t i : ngcore::Range(size)) data[i] = a2[i]; } ArrayMem & operator= (const T & val) { FlatArray::operator= (val); return *this; } ArrayMem & operator= (ArrayMem && a2) { mt = std::move(a2.mt); ngcore::Swap (mem_to_delete, a2.mem_to_delete); ngcore::Swap (allocsize, a2.allocsize); ngcore::Swap (size, a2.size); if (mem_to_delete==nullptr) { for (auto i : ngcore::Range(size)) mem[i] = std::move(a2.mem[i]); data = mem; } else ngcore::Swap (data, a2.data); return *this; } /// array copy ArrayMem & operator= (const FlatArray & a2) { this->SetSize (a2.Size()); for (size_t i = 0; i < size; i++) (*this)[i] = a2[i]; return *this; } template ArrayMem & operator= (const BaseArrayObject & a2) { this->SetSize (a2.Spec().Size()); size_t i = 0; for (auto val : a2.Spec()) (*this)[i++] = val; return *this; } }; template size_t ArraySize (Tuple /* tup */) { return 0;} template size_t ArraySize (Tuple tup) { return 1+ArraySize(tup.Tail()); } template size_t ArraySize (Tuple tup) { return tup.Head().Size()+ArraySize(tup.Tail()); } template void StoreToArray (FlatArray /* a */, Tuple /* tup */) { ; } template void StoreToArray (FlatArray a, Tuple tup) { a[0] = tup.Head(); StoreToArray (a.Range(1, a.Size()), tup.Tail()); } template void StoreToArray (FlatArray a, Tuple tup) { IntRange r = tup.Head(); a.Range(0,r.Size()) = r; StoreToArray (a.Range(r.Size(), a.Size()), tup.Tail()); } /* template template NETGEN_INLINE Array & Array :: operator= (Tuple tup) { SetSize (ArraySize (tup)); StoreToArray (*this, tup); } */ /* /// append integers to array inline Array & operator+= (Array & array, const IntRange & range) { int oldsize = array.Size(); int s = range.Next() - range.First(); array.SetSize (oldsize+s); for (int i = 0; i < s; i++) array[oldsize+i] = range.First()+i; return array; } */ /* template inline Array & operator+= (Array & array, const BaseArrayObject & a2) { size_t oldsize = array.Size(); size_t s = a2.Spec().Size(); array.SetSize (oldsize+s); for (size_t i = 0; i < s; i++) array[oldsize+i] = a2.Spec()[i]; return array; } */ template inline Array & operator+= (Array & array, const BaseArrayObject & a2) { auto oldsize = array.Size(); auto s = a2.Spec().Size(); array.SetSize (oldsize+s); for (auto val : a2.Spec()) array[oldsize++] = val; return array; } template inline Array operator+= (Array && array, const BaseArrayObject & a2) { array += a2; return std::move(array); } /// bubble sort array template inline void BubbleSort (FlatArray data) { T hv; for (size_t i = 0; i < data.Size(); i++) for (size_t j = i+1; j < data.Size(); j++) if (data[i] > data[j]) { hv = data[i]; data[i] = data[j]; data[j] = hv; } } /// bubble sort array template inline void BubbleSort (FlatArray data, FlatArray index) { for (size_t i = 0; i < data.Size(); i++) for (size_t 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 = index[i]; index[i] = index[j]; index[j] = hvs; } } template void QuickSort (FlatArray data, TLESS less) { constexpr size_t INSERTION_SORT_THRESHOLD = 16; if (data.Size() <= INSERTION_SORT_THRESHOLD) { // insertion sort for (ptrdiff_t k = 1; k < data.Size(); ++k) { auto newval = data[k]; ptrdiff_t l = k; for ( ; l > 0 && less(newval, data[l-1]); --l) data[l] = data[l-1]; data[l] = newval; } return; } // if (data.Size() <= 1) return; ptrdiff_t i = 0; ptrdiff_t j = data.Size()-1; T midval = data[ (i+j)/2 ]; do { while (less (data[i], midval)) i++; while (less (midval, data[j])) j--; if (i <= j) { Swap (data[i], data[j]); i++; j--; } } while (i <= j); QuickSort (data.Range (0, j+1), less); QuickSort (data.Range (i, data.Size()), less); } template NETGEN_INLINE bool DefaultLess (const T & a, const T & b) { return a < b; } template class DefaultLessCl { public: bool operator() (const T & a, const T & b) const { return a < b; } }; template NETGEN_INLINE void QuickSort (FlatArray data) { QuickSort (data, DefaultLessCl()); } template void QuickSortI (FlatArray data, FlatArray index, TLESS less) { if (index.Size() <= 1) return; ptrdiff_t i = 0; ptrdiff_t j = index.Size()-1; int midval = index[ (i+j)/2 ]; do { while (less (data[index[i]],data[midval]) ) i++; while (less (data[midval], data[index[j]])) j--; if (i <= j) { Swap (index[i], index[j]); i++; j--; } } while (i <= j); QuickSortI (data, index.Range (0, j+1), less); QuickSortI (data, index.Range (i, index.Size()), less); } template NETGEN_INLINE void QuickSortI (FlatArray data, FlatArray index) { QuickSortI (data, index, DefaultLessCl()); } template NETGEN_INLINE T xxxRemoveRef (const T & x) { return x; } template class SumArray : public BaseArrayObject> { const TA1 & a1; const TA2 & a2; public: SumArray (const TA1 & aa1, const TA2 & aa2) : a1(aa1), a2(aa2) { ; } size_t Size() const { return a1.Size()+a2.Size(); } auto operator[] (size_t i) const -> decltype (xxxRemoveRef (a1[0])) { return (i < a1.Size()) ? a1[i] : a2[i-a1.Size()]; } }; template SumArray operator+ (const BaseArrayObject & a1, const BaseArrayObject & a2) { return SumArray (a1.Spec(), a2.Spec()); } struct HTAHelp { }; // head-tail array template class HTArray { HTArray tail; T head; public: constexpr HTArray () = default; constexpr HTArray (const HTArray &) = default; template constexpr HTArray (const HTArray & a2) : tail(a2.Tail()), head(a2.Head()) { ; } constexpr HTArray (T v) : tail(v), head(v) { } // all the same template = true> constexpr HTArray (const T &v, T2... rest) : tail{HTAHelp(), v,rest...}, head(std::get(std::tuple(rest...))) { } template constexpr HTArray (HTAHelp h, const T &v, T2... rest) : tail{h, v,rest...}, head(std::get(std::tuple(rest...))) { } HTArray & operator= (const HTArray &) = default; T * Ptr () { return tail.Ptr(); } T & operator[] (size_t i) { return Ptr()[i]; } const T * Ptr () const { return tail.Ptr(); } const T & operator[] (size_t i) const { return Ptr()[i]; } template T & Elem() { return (NR==S-1) ? head : tail.template Elem(); } auto Tail() const { return tail; } auto Head() const { return head; } }; template class HTArray<1,T> { T head; public: constexpr HTArray () = default; constexpr HTArray (const HTArray &) = default; template constexpr HTArray (const HTArray<1,T2> & a2) : head(a2.Head()) { ; } constexpr HTArray (T v) : head(v) { } // all the same template constexpr HTArray (HTAHelp h, const T &v, T2... rest) : head(v) { } HTArray & operator= (const HTArray &) = default; T * Ptr () { return &head; } T & operator[] (size_t i) { return Ptr()[i]; } const T * Ptr () const { return &head; } const T & operator[] (size_t i) const { return Ptr()[i]; } template T & Elem() { // assert(NR==0, "HTArray index error"); return head; } auto Head() const { return head; } }; template class HTArray<0,T> { // T head; // dummy variable public: HTArray () = default; HTArray (const HTArray &) = default; template HTArray (const HTArray<0,T2> & a2) { ; } constexpr HTArray (T v) { } // all the same HTArray & operator= (const HTArray &) = default; /* T * Ptr () { return &head; } T & operator[] (size_t i) { return Ptr()[i]; } const T * Ptr () const { return &head; } const T & operator[] (size_t i) const { return Ptr()[i]; } template T & Elem() { // assert(false, "HTArray index error"); return head; } */ // T * Ptr () { return (T*)(void*)&head; } T * Ptr () { return (T*)(void*)this; } T & operator[] (size_t i) { return Ptr()[i]; } // const T * Ptr () const { return (const T*)(const void*)&head; } const T * Ptr () const { return (const T*)(const void*)this; } const T & operator[] (size_t i) const { return Ptr()[i]; } template T & Elem() { throw Exception("illegal HTArray<0>::Elem<0>"); } }; template const T * operator+ (const HTArray & ar, size_t i) { return ar.Ptr()+i; } template T * operator+ (HTArray & ar, size_t i) { return ar.Ptr()+i; } template class IteratorPair { TIA a; TIB b; public: IteratorPair (TIA _a, TIB _b) : a(_a), b(_b) { ; } IteratorPair & operator++() { ++a; ++b; return *this; } bool operator!= (const IteratorPair & it2) { return a != it2.a; } auto operator*() { // return pair(*a,*b); return std::pair (*a, *b); // keep reference } }; template class Zip { const TA & a; const TB & b; public: Zip(const TA & _a, const TB & _b) : a(_a), b(_b) { ; } auto begin() const { return IteratorPair(a.begin(), b.begin()); } auto end() const { return IteratorPair(a.end(), b.end()); } }; template inline size_t size (const BaseArrayObject & ao) { return ao.Size(); } template class Enumerate { IntRange r; const TA & a; public: Enumerate(const TA & _a) : r(size(_a)), a(_a) { ; } auto begin() const { return IteratorPair(r.begin(), a.begin()); } auto end() const { return IteratorPair(r.end(), a.end()); } }; } #endif // NETGEN_CORE_ARRAY_HPP ================================================ FILE: libsrc/core/autodiff.hpp ================================================ #ifndef FILE_AUTODIFF #define FILE_AUTODIFF /**************************************************************************/ /* File: autodiff.hpp */ /* Author: Joachim Schoeberl */ /* Date: 24. Oct. 02 */ /**************************************************************************/ namespace ngcore { // Automatic differentiation datatype template class AutoDiffRec; /** Datatype for automatic differentiation. Contains function value and D derivatives. Algebraic operations are overloaded by using product-rule etc. etc. **/ template class AutoDiffVec { SCAL val; SCAL dval[D?D:1]; public: typedef AutoDiffVec TELEM; typedef SCAL TSCAL; /// elements are undefined // NETGEN_INLINE AutoDiffVec () throw() { }; AutoDiffVec() = default; // { val = 0; for (int i = 0; i < D; i++) dval[i] = 0; } // ! /// copy constructor AutoDiffVec (const AutoDiffVec & ad2) = default; /* NETGEN_INLINE AutoDiffVec (const AutoDiffVec & ad2) throw() { val = ad2.val; for (int i = 0; i < D; i++) dval[i] = ad2.dval[i]; } */ /// initial object with constant value NETGEN_INLINE AutoDiffVec (SCAL aval) throw() { val = aval; for (int i = 0; i < D; i++) dval[i] = 0; } /// init object with (val, e_diffindex) NETGEN_INLINE AutoDiffVec (SCAL aval, int diffindex) throw() { val = aval; for (int i = 0; i < D; i++) dval[i] = 0; dval[diffindex] = 1; } NETGEN_INLINE AutoDiffVec (SCAL aval, const SCAL * grad) { val = aval; LoadGradient (grad); } /// assign constant value NETGEN_INLINE AutoDiffVec & operator= (SCAL aval) throw() { val = aval; for (int i = 0; i < D; i++) dval[i] = 0; return *this; } AutoDiffVec & operator= (const AutoDiffVec & ad2) = default; /// returns value NETGEN_INLINE SCAL Value() const throw() { return val; } /// returns partial derivative NETGEN_INLINE SCAL DValue (int i) const throw() { return dval[i]; } /// NETGEN_INLINE void StoreGradient (SCAL * p) const { for (int i = 0; i < D; i++) p[i] = dval[i]; } NETGEN_INLINE void LoadGradient (const SCAL * p) { for (int i = 0; i < D; i++) dval[i] = p[i]; } /// access value NETGEN_INLINE SCAL & Value() throw() { return val; } /// accesses partial derivative NETGEN_INLINE SCAL & DValue (int i) throw() { return dval[i]; } }; //@{ AutoDiffVec helper functions. /// prints AutoDiffVec template inline ostream & operator<< (ostream & ost, const AutoDiffVec & x) { ost << x.Value() << ", D = "; for (int i = 0; i < D; i++) ost << x.DValue(i) << " "; return ost; } /// AutoDiffVec plus AutoDiffVec template NETGEN_INLINE AutoDiffVec operator+ (const AutoDiffVec & x, const AutoDiffVec & y) throw() { AutoDiffVec res; res.Value () = x.Value()+y.Value(); // AutoDiffVec res(x.Value()+y.Value()); for (int i = 0; i < D; i++) res.DValue(i) = x.DValue(i) + y.DValue(i); return res; } /// AutoDiffVec minus AutoDiffVec template NETGEN_INLINE AutoDiffVec operator- (const AutoDiffVec & x, const AutoDiffVec & y) throw() { AutoDiffVec res; res.Value() = x.Value()-y.Value(); // AutoDiffVec 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 AutoDiffVec template::value, int>::type = 0> NETGEN_INLINE AutoDiffVec operator+ (SCAL2 x, const AutoDiffVec & y) throw() { AutoDiffVec res; res.Value() = x+y.Value(); for (int i = 0; i < D; i++) res.DValue(i) = y.DValue(i); return res; } /// AutoDiffVec plus double template::value, int>::type = 0> NETGEN_INLINE AutoDiffVec operator+ (const AutoDiffVec & y, SCAL2 x) throw() { AutoDiffVec res; res.Value() = x+y.Value(); for (int i = 0; i < D; i++) res.DValue(i) = y.DValue(i); return res; } /// minus AutoDiffVec template NETGEN_INLINE AutoDiffVec operator- (const AutoDiffVec & x) throw() { AutoDiffVec res; res.Value() = -x.Value(); for (int i = 0; i < D; i++) res.DValue(i) = -x.DValue(i); return res; } /// AutoDiffVec minus double template::value, int>::type = 0> NETGEN_INLINE AutoDiffVec operator- (const AutoDiffVec & x, SCAL2 y) throw() { AutoDiffVec res; res.Value() = x.Value()-y; for (int i = 0; i < D; i++) res.DValue(i) = x.DValue(i); return res; } /// template::value, int>::type = 0> NETGEN_INLINE AutoDiffVec operator- (SCAL2 x, const AutoDiffVec & y) throw() { AutoDiffVec res; res.Value() = x-y.Value(); for (int i = 0; i < D; i++) res.DValue(i) = -y.DValue(i); return res; } /// double times AutoDiffVec template::value, int>::type = 0> NETGEN_INLINE AutoDiffVec operator* (SCAL2 x, const AutoDiffVec & y) throw() { AutoDiffVec res; res.Value() = x*y.Value(); for (int i = 0; i < D; i++) res.DValue(i) = x*y.DValue(i); return res; } /// AutoDiffVec times double template::value, int>::type = 0> NETGEN_INLINE AutoDiffVec operator* (const AutoDiffVec & y, SCAL2 x) throw() { AutoDiffVec res; res.Value() = x*y.Value(); for (int i = 0; i < D; i++) res.DValue(i) = x*y.DValue(i); return res; } /// AutoDiffVec times AutoDiffVec template NETGEN_INLINE AutoDiffVec operator* (const AutoDiffVec & x, const AutoDiffVec & y) throw() { AutoDiffVec 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; } /// AutoDiffVec times AutoDiffVec template NETGEN_INLINE AutoDiffVec sqr (const AutoDiffVec & x) throw() { AutoDiffVec 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 AutoDiffVec template NETGEN_INLINE AutoDiffVec Inv (const AutoDiffVec & x) { AutoDiffVec res(1.0 / x.Value()); for (int i = 0; i < D; i++) res.DValue(i) = -x.DValue(i) / (x.Value() * x.Value()); return res; } /// AutoDiffVec div AutoDiffVec template NETGEN_INLINE AutoDiffVec operator/ (const AutoDiffVec & x, const AutoDiffVec & y) { return x * Inv (y); } /// AutoDiffVec div double template::value, int>::type = 0> NETGEN_INLINE AutoDiffVec operator/ (const AutoDiffVec & x, SCAL2 y) { return (1.0/y) * x; } /// double div AutoDiffVec template::value, int>::type = 0> NETGEN_INLINE AutoDiffVec operator/ (SCAL2 x, const AutoDiffVec & y) { return x * Inv(y); } template NETGEN_INLINE AutoDiffVec & operator+= (AutoDiffVec & x, SCAL2 y) throw() { x.Value() += y; return x; } /// template NETGEN_INLINE AutoDiffVec & operator+= (AutoDiffVec & x, AutoDiffVec y) { x.Value() += y.Value(); for (int i = 0; i < D; i++) x.DValue(i) += y.DValue(i); return x; } /// template NETGEN_INLINE AutoDiffVec & operator-= (AutoDiffVec & x, AutoDiffVec y) { x.Value() -= y.Value(); for (int i = 0; i < D; i++) x.DValue(i) -= y.DValue(i); return x; } template NETGEN_INLINE AutoDiffVec & operator-= (AutoDiffVec & x, SCAL2 y) { x.Value() -= y; return x; } /// template NETGEN_INLINE AutoDiffVec & operator*= (AutoDiffVec & x, AutoDiffVec y) { for (int i = 0; i < D; i++) x.DValue(i) = x.DValue(i)*y.Value() + x.Value() * y.DValue(i); x.Value() *= y.Value(); return x; } /// template NETGEN_INLINE AutoDiffVec & operator*= (AutoDiffVec & x, SCAL2 y) { x.Value() *= y; for (int i = 0; i < D; i++) x.DValue(i) *= y; return x; } /// template NETGEN_INLINE AutoDiffVec & operator/= (AutoDiffVec & x, SCAL y) { SCAL iy = 1.0 / y; x.Value() *= iy; for (int i = 0; i < D; i++) x.DValue(i) *= iy; return x; } /// template NETGEN_INLINE bool operator== (AutoDiffVec x, SCAL val2) { return x.Value() == val2; } /// template NETGEN_INLINE bool operator!= (AutoDiffVec x, SCAL val2) throw() { return x.Value() != val2; } /// template NETGEN_INLINE bool operator< (AutoDiffVec x, SCAL val2) throw() { return x.Value() < val2; } /// template NETGEN_INLINE bool operator> (AutoDiffVec x, SCAL val2) throw() { return x.Value() > val2; } template NETGEN_INLINE AutoDiffVec fabs (const AutoDiffVec & x) { double abs = fabs (x.Value()); AutoDiffVec res( abs ); if (abs != 0.0) for (int i = 0; i < D; i++) res.DValue(i) = x.Value()*x.DValue(i) / abs; else for (int i = 0; i < D; i++) res.DValue(i) = 0.0; return res; } using std::sqrt; template NETGEN_INLINE AutoDiffVec sqrt (const AutoDiffVec & x) { AutoDiffVec res; res.Value() = sqrt(x.Value()); for (int j = 0; j < D; j++) res.DValue(j) = 0.5 / res.Value() * x.DValue(j); return res; } using std::log; template AutoDiffVec log (AutoDiffVec x) { AutoDiffVec res; res.Value() = log(x.Value()); for (int k = 0; k < D; k++) res.DValue(k) = x.DValue(k) / x.Value(); return res; } using std::exp; template NETGEN_INLINE AutoDiffVec exp (AutoDiffVec x) { AutoDiffVec res; res.Value() = exp(x.Value()); for (int k = 0; k < D; k++) res.DValue(k) = x.DValue(k) * res.Value(); return res; } using std::pow; template NETGEN_INLINE AutoDiffVec pow (AutoDiffVec x, AutoDiffVec y ) { return exp(log(x)*y); } using std::sin; /* template NETGEN_INLINE AutoDiffVec sin (AutoDiffVec x) { AutoDiffVec res; res.Value() = sin(x.Value()); SCAL c = cos(x.Value()); for (int k = 0; k < D; k++) res.DValue(k) = x.DValue(k) * c; return res; } */ template NETGEN_INLINE AutoDiffVec sin (AutoDiffVec x) { return sin(AutoDiffRec(x)); } using std::cos; /* template NETGEN_INLINE AutoDiffVec cos (AutoDiffVec x) { AutoDiffVec res; res.Value() = cos(x.Value()); SCAL ms = -sin(x.Value()); for (int k = 0; k < D; k++) res.DValue(k) = x.DValue(k) * ms; return res; } */ template NETGEN_INLINE AutoDiffVec cos (AutoDiffVec x) { return cos(AutoDiffRec(x)); } using std::tan; template NETGEN_INLINE AutoDiffVec tan (AutoDiffVec x) { return sin(x) / cos(x); } using std::sinh; template NETGEN_INLINE AutoDiffVec sinh (AutoDiffVec x) { AutoDiffVec res; res.Value() = sinh(x.Value()); SCAL ch = cosh(x.Value()); for (int k = 0; k < D; k++) res.DValue(k) = x.DValue(k) * ch; return res; } using std::cosh; template NETGEN_INLINE AutoDiffVec cosh (AutoDiffVec x) { AutoDiffVec res; res.Value() = cosh(x.Value()); SCAL sh = sinh(x.Value()); for (int k = 0; k < D; k++) res.DValue(k) = x.DValue(k) * sh; return res; } using std::erf; template NETGEN_INLINE AutoDiffVec erf (AutoDiffVec x) { return erf(AutoDiffRec(x)); } using std::floor; template NETGEN_INLINE AutoDiffVec floor (const AutoDiffVec & x) { AutoDiffVec res; res.Value() = floor(x.Value()); for (int j = 0; j < D; j++) res.DValue(j) = 0.0; return res; } using std::ceil; template NETGEN_INLINE AutoDiffVec ceil (const AutoDiffVec & x) { AutoDiffVec res; res.Value() = ceil(x.Value()); for (int j = 0; j < D; j++) res.DValue(j) = 0.0; return res; } using std::atan; /* template NETGEN_INLINE AutoDiffVec atan (AutoDiffVec x) { AutoDiffVec res; SCAL a = atan(x.Value()); res.Value() = a; for (int k = 0; k < D; k++) res.DValue(k) = x.DValue(k)/(1+x.Value()*x.Value()) ; return res; } */ template AutoDiffVec atan (AutoDiffVec x) { return atan (AutoDiffRec (x)); } using std::atan2; template NETGEN_INLINE AutoDiffVec atan2 (AutoDiffVec x, AutoDiffVec y) { AutoDiffVec res; SCAL a = atan2(x.Value(), y.Value()); res.Value() = a; for (int k = 0; k < D; k++) res.DValue(k) = (x.Value()*y.DValue(k)-y.Value()*x.DValue(k))/(y.Value()*y.Value()+x.Value()*x.Value()); return res; } using std::acos; template NETGEN_INLINE AutoDiffVec acos (AutoDiffVec x) { AutoDiffVec res; SCAL a = acos(x.Value()); res.Value() = a; SCAL da = -1 / sqrt(1-x.Value()*x.Value()); for (int k = 0; k < D; k++) res.DValue(k) = x.DValue(k)*da; return res; } using std::asin; template NETGEN_INLINE AutoDiffVec asin (AutoDiffVec x) { AutoDiffVec res; SCAL a = asin(x.Value()); res.Value() = a; SCAL da = 1 / sqrt(1-x.Value()*x.Value()); for (int k = 0; k < D; k++) res.DValue(k) = x.DValue(k)*da; return res; } template auto IfPos (AutoDiffVec a, TB b, TC c) // -> decltype(IfPos (a.Value(), b, c)) { return IfPos (a.Value(), b, c); } template NETGEN_INLINE AutoDiffVec IfPos (SCAL /* SIMD */ a, AutoDiffVec b, AutoDiffVec c) { AutoDiffVec res; res.Value() = IfPos (a, b.Value(), c.Value()); for (int j = 0; j < D; j++) res.DValue(j) = IfPos (a, b.DValue(j), c.DValue(j)); return res; } template NETGEN_INLINE AutoDiffVec IfPos (SCAL /* SIMD */ a, AutoDiffVec b, TC c) { return IfPos (a, b, AutoDiffVec (c)); } //@} template class AutoDiffRec { AutoDiffRec rec; SCAL last; public: AutoDiffRec () = default; AutoDiffRec (const AutoDiffRec &) = default; NETGEN_INLINE AutoDiffRec (AutoDiffRec _rec, SCAL _last) : rec(_rec), last(_last) { ; } AutoDiffRec & operator= (const AutoDiffRec &) = default; NETGEN_INLINE AutoDiffRec (SCAL aval) : rec(aval), last(0.0) { ; } NETGEN_INLINE AutoDiffRec (SCAL aval, int diffindex) : rec(aval, diffindex), last((diffindex==D-1) ? 1.0 : 0.0) { ; } NETGEN_INLINE AutoDiffRec (SCAL aval, const SCAL * grad) : rec(aval, grad), last(grad[D-1]) { } NETGEN_INLINE AutoDiffRec (const AutoDiffVec & ad) { Value() = ad.Value(); for (int i = 0; i < D; i++) DValue(i) = ad.DValue(i); } NETGEN_INLINE AutoDiffRec & operator= (SCAL aval) { rec = aval; last = 0.0; return *this; } NETGEN_INLINE SCAL Value() const { return rec.Value(); } NETGEN_INLINE SCAL DValue(int i) const { return (i == D-1) ? last : rec.DValue(i); } NETGEN_INLINE SCAL & Value() { return rec.Value(); } NETGEN_INLINE SCAL & DValue(int i) { return (i == D-1) ? last : rec.DValue(i); } NETGEN_INLINE auto Rec() const { return rec; } NETGEN_INLINE auto Last() const { return last; } NETGEN_INLINE auto & Rec() { return rec; } NETGEN_INLINE auto & Last() { return last; } NETGEN_INLINE operator AutoDiffVec () const { AutoDiffVec res(Value()); for (int i = 0; i < D; i++) res.DValue(i) = DValue(i); return res; } }; template ostream & operator<< (ostream & ost, AutoDiffRec ad) { return ost << AutoDiffVec (ad); } template class AutoDiffRec<0,SCAL> { SCAL val; public: AutoDiffRec () = default; AutoDiffRec (const AutoDiffRec &) = default; NETGEN_INLINE AutoDiffRec (SCAL _val) : val(_val) { ; } NETGEN_INLINE AutoDiffRec (SCAL _val, SCAL /* _dummylast */) : val(_val) { ; } NETGEN_INLINE AutoDiffRec (SCAL aval, const SCAL * /* grad */) : val(aval) { } AutoDiffRec & operator= (const AutoDiffRec &) = default; NETGEN_INLINE AutoDiffRec & operator= (SCAL aval) { val = aval; return *this; } NETGEN_INLINE SCAL Value() const { return val; } NETGEN_INLINE SCAL DValue(int /* i */) const { return SCAL(0); } NETGEN_INLINE SCAL & Value() { return val; } // SCAL & DValue(int i) { return val; } NETGEN_INLINE auto Rec() const { return val; } NETGEN_INLINE auto Last() const { return SCAL(0); } NETGEN_INLINE auto & Rec() { return val; } NETGEN_INLINE auto & Last() { return val; } NETGEN_INLINE operator AutoDiffVec<0,SCAL> () const { return AutoDiffVec<0,SCAL>(); } }; template class AutoDiffRec<1,SCAL> { SCAL val; SCAL last; public: AutoDiffRec () = default; AutoDiffRec (const AutoDiffRec &) = default; NETGEN_INLINE AutoDiffRec (SCAL _val) : val(_val), last(0.0) { ; } NETGEN_INLINE AutoDiffRec (SCAL _val, SCAL _last) : val(_val), last(_last) { ; } NETGEN_INLINE AutoDiffRec (SCAL aval, int diffindex) : val(aval), last((diffindex==0) ? 1.0 : 0.0) { ; } NETGEN_INLINE AutoDiffRec (SCAL aval, const SCAL * grad) : val(aval), last(grad[0]) { } NETGEN_INLINE AutoDiffRec (const AutoDiffVec<1,SCAL> & ad) { Value() = ad.Value(); DValue(0) = ad.DValue(0); } AutoDiffRec & operator= (const AutoDiffRec &) = default; NETGEN_INLINE AutoDiffRec & operator= (SCAL aval) { val = aval; last = 0.0; return *this; } NETGEN_INLINE SCAL Value() const { return val; } NETGEN_INLINE SCAL DValue(int /* i */) const { return last; } NETGEN_INLINE SCAL & Value() { return val; } NETGEN_INLINE SCAL & DValue(int /* i */) { return last; } NETGEN_INLINE auto Rec() const { return val; } NETGEN_INLINE auto Last() const { return last; } NETGEN_INLINE auto & Rec() { return val; } NETGEN_INLINE auto & Last() { return last; } NETGEN_INLINE operator AutoDiffVec<1,SCAL> () const { AutoDiffVec<1,SCAL> res(Value()); res.DValue(0) = DValue(0); return res; } }; template ::value, int>::type = 0> NETGEN_INLINE AutoDiffRec operator+ (SCAL2 a, AutoDiffRec b) { return AutoDiffRec (a+b.Rec(), b.Last()); } template ::value, int>::type = 0> NETGEN_INLINE AutoDiffRec operator+ (AutoDiffRec a, SCAL2 b) { return AutoDiffRec (a.Rec()+b, a.Last()); } template NETGEN_INLINE AutoDiffRec operator+ (AutoDiffRec a, AutoDiffRec b) { return AutoDiffRec (a.Rec()+b.Rec(), a.Last()+b.Last()); } template ::value, int>::type = 0> NETGEN_INLINE AutoDiffRec operator- (SCAL2 b, AutoDiffRec a) { return AutoDiffRec (b-a.Rec(), -a.Last()); } template ::value, int>::type = 0> NETGEN_INLINE AutoDiffRec operator- (AutoDiffRec a, SCAL2 b) { return AutoDiffRec (a.Rec()-b, a.Last()); } template NETGEN_INLINE AutoDiffRec operator- (AutoDiffRec a, AutoDiffRec b) { return AutoDiffRec (a.Rec()-b.Rec(), a.Last()-b.Last()); } /// minus AutoDiff template NETGEN_INLINE AutoDiffRec operator- (AutoDiffRec a) { return AutoDiffRec (-a.Rec(), -a.Last()); } template NETGEN_INLINE AutoDiffRec operator* (AutoDiffRec a, AutoDiffRec b) { return AutoDiffRec (a.Rec()*b.Rec(), a.Value()*b.Last()+b.Value()*a.Last()); } template ::value, int>::type = 0> NETGEN_INLINE AutoDiffRec operator* (AutoDiffRec b, SCAL1 a) { return AutoDiffRec (a*b.Rec(), a*b.Last()); } template ::value, int>::type = 0> NETGEN_INLINE AutoDiffRec operator* (SCAL1 a, AutoDiffRec b) { return AutoDiffRec (a*b.Rec(), a*b.Last()); } template NETGEN_INLINE AutoDiffRec & operator+= (AutoDiffRec & a, AutoDiffRec b) { a.Rec() += b.Rec(); a.Last() += b.Last(); return a; } template NETGEN_INLINE AutoDiffRec & operator-= (AutoDiffRec & a, double b) { a.Rec() -= b; return a; } template NETGEN_INLINE AutoDiffRec & operator-= (AutoDiffRec & a, AutoDiffRec b) { a.Rec() -= b.Rec(); a.Last() -= b.Last(); return a; } template NETGEN_INLINE AutoDiffRec & operator*= (AutoDiffRec & a, AutoDiffRec b) { a = a*b; return a; } template NETGEN_INLINE AutoDiffRec & operator*= (AutoDiffRec & b, SCAL2 a) { b.Rec() *= a; b.Last() *= a; return b; } /// Inverse of AutoDiffRec template auto Inv1 (SCAL x) { return 1.0/x; } template NETGEN_INLINE AutoDiffRec Inv1 (AutoDiffRec x) { return AutoDiffRec (Inv1(x.Rec()), (-sqr(1.0/x.Value())) * x.Last()); } /// AutoDiffRec div AutoDiffRec template NETGEN_INLINE AutoDiffRec operator/ (const AutoDiffRec & x, const AutoDiffRec & y) { return x * Inv1 (y); } /// AutoDiffVec div double template::value, int>::type = 0> NETGEN_INLINE AutoDiffRec operator/ (const AutoDiffRec & x, SCAL2 y) { return (1.0/y) * x; } /// double div AutoDiffVec template::value, int>::type = 0> NETGEN_INLINE AutoDiffRec operator/ (SCAL2 x, const AutoDiffRec & y) { return x * Inv1(y); } /// template NETGEN_INLINE bool operator== (AutoDiffRec x, SCAL val2) { return x.Value() == val2; } /// template NETGEN_INLINE bool operator!= (AutoDiffRec x, SCAL val2) throw() { return x.Value() != val2; } /// template NETGEN_INLINE bool operator< (AutoDiffRec x, SCAL val2) throw() { return x.Value() < val2; } /// template NETGEN_INLINE bool operator> (AutoDiffRec x, SCAL val2) throw() { return x.Value() > val2; } using std::fabs; template NETGEN_INLINE AutoDiffRec fabs (const AutoDiffRec & x) { auto sign = IfPos(x.Value(), SCAL(1.0), IfPos(-x.Value(), SCAL(-1.0), SCAL(0.0))); return AutoDiffRec (fabs(x.Rec()), sign*x.Last()); // return fabs (AutoDiffVec(x)); /* double abs = fabs (x.Value()); AutoDiffVec res( abs ); if (abs != 0.0) for (int i = 0; i < D; i++) res.DValue(i) = x.Value()*x.DValue(i) / abs; else for (int i = 0; i < D; i++) res.DValue(i) = 0.0; return res; */ } template NETGEN_INLINE auto sqrt (const AutoDiffRec & x) { return AutoDiffRec (sqrt(x.Rec()), (0.5/sqrt(x.Value()))*x.Last()); } template auto log (AutoDiffRec x) { return AutoDiffRec (log(x.Rec()), (1.0/x.Value())*x.Last()); } template auto exp (AutoDiffRec x) { return AutoDiffRec (exp(x.Rec()), exp(x.Value())*x.Last()); } template NETGEN_INLINE AutoDiffRec pow (AutoDiffRec x, AutoDiffRec y ) { return exp(log(x)*y); } template auto sin (AutoDiffRec x) { return AutoDiffRec (sin(x.Rec()), cos(x.Value())*x.Last()); } template auto cos (AutoDiffRec x) { return AutoDiffRec (cos(x.Rec()), -sin(x.Value())*x.Last()); } template auto tan (AutoDiffRec x) { return sin(x) / cos(x); } template auto sinh (AutoDiffRec x) { return AutoDiffRec (sinh(x.Rec()), cosh(x.Value())*x.Last()); } template auto cosh (AutoDiffRec x) { return AutoDiffRec (cosh(x.Rec()), sinh(x.Value())*x.Last()); } template auto asinh (AutoDiffRec x) { return AutoDiffRec (asinh(x.Rec()), 1/sqrt(sqr(x.Value()+1))*x.Last()); } template auto acosh (AutoDiffRec x) { return AutoDiffRec (acosh(x.Rec()), 1/sqrt(sqr(x.Value()-1))*x.Last()); } template auto erf (AutoDiffRec x) { return AutoDiffRec (erf(x.Rec()), 2. / sqrt(M_PI) * exp(- x.Value() * x.Value())*x.Last()); } template auto floor (AutoDiffRec x) { return AutoDiffRec (floor(x.Rec()), 0.0); } template auto ceil (AutoDiffRec x) { return AutoDiffRec (ceil(x.Rec()), 0.0); } template auto atan (AutoDiffRec x) { return AutoDiffRec (atan(x.Rec()), (1./(1.+x.Value()*x.Value()))*x.Last()); } template auto atan2 (AutoDiffRec x, AutoDiffRec y) { return AutoDiffRec (atan2(x.Rec(), y.Rec()), (1./(x.Value()*x.Value()+y.Value()*y.Value()))*(x.Value()*y.Last()-y.Value()*x.Last())); } template auto acos (AutoDiffRec x) { return AutoDiffRec (acos(x.Rec()), (-1./sqrt(1.-x.Value()*x.Value()))*x.Last()); } template auto asin (AutoDiffRec x) { return AutoDiffRec (asin(x.Rec()), (1./sqrt(1.-x.Value()*x.Value()))*x.Last()); } template auto IfPos (AutoDiffRec a, TB b, TC c) // -> decltype(IfPos (a.Value(), b, c)) { return IfPos (a.Value(), b, c); } template NETGEN_INLINE AutoDiffRec IfPos (SCAL /* SIMD */ a, AutoDiffRec b, AutoDiffRec c) { /* AutoDiffRec res; res.Value() = IfPos (a, b.Value(), c.Value()); for (int j = 0; j < D; j++) res.DValue(j) = IfPos (a, b.DValue(j), c.DValue(j)); return res; */ return AutoDiffRec (IfPos(a, b.Rec(), c.Rec()), IfPos(a, b.Last(), c.Last())); } template NETGEN_INLINE AutoDiffRec IfPos (SCAL /* SIMD */ a, AutoDiffRec b, TC c) { return IfPos (a, b, AutoDiffRec (c)); } template using AutoDiff = AutoDiffRec; } namespace ngbla { template struct is_scalar_type; template struct is_scalar_type> { static constexpr bool value = true; }; // not meaningful for AutoDiff, since this is // not (complex) differentiable anyway template inline auto L2Norm2 (const ngcore::AutoDiff & x) { return x*x; } template inline auto L2Norm (const ngcore::AutoDiff & x) throw() { return IfPos(x.Value(), x, -x); } template NETGEN_INLINE auto Conj (const ngcore::AutoDiff & a) { ngcore::AutoDiff b; b.Value() = conj(a.Value()); for(int i=0;i class AutoDiffDiff { SCAL val; SCAL dval[D?D:1]; SCAL ddval[D?D*D:1]; public: typedef AutoDiffDiff TELEM; /// elements are undefined AutoDiffDiff () throw() { ; } /// copy constructor AutoDiffDiff (const AutoDiffDiff & ad2) throw() { val = ad2.val; for (int i = 0; i < D; i++) dval[i] = ad2.dval[i]; for (int i = 0; i < D*D; i++) ddval[i] = ad2.ddval[i]; } /// initial object with constant value AutoDiffDiff (SCAL aval) throw() { val = aval; for (int i = 0; i < D; i++) dval[i] = 0; for (int i = 0; i < D*D; i++) ddval[i] = 0; } /// initial object with value and derivative AutoDiffDiff (const AutoDiff & ad2) throw() { val = ad2.Value(); for (int i = 0; i < D; i++) dval[i] = ad2.DValue(i); for (int i = 0; i < D*D; i++) ddval[i] = 0; } /// init object with (val, e_diffindex) AutoDiffDiff (SCAL aval, int diffindex) throw() { val = aval; for (int i = 0; i < D; i++) dval[i] = 0; for (int i = 0; i < D*D; i++) ddval[i] = 0; dval[diffindex] = 1; } NETGEN_INLINE AutoDiffDiff (SCAL aval, const SCAL * grad) { val = aval; LoadGradient (grad); for (int i = 0; i < D*D; i++) ddval[i] = 0; } NETGEN_INLINE AutoDiffDiff (SCAL aval, const SCAL * grad, const SCAL * hesse) { val = aval; LoadGradient (grad); LoadHessian (hesse); } /// assign constant value AutoDiffDiff & operator= (SCAL aval) throw() { val = aval; for (int i = 0; i < D; i++) dval[i] = 0; for (int i = 0; i < D*D; i++) ddval[i] = 0; return *this; } NETGEN_INLINE void StoreGradient (SCAL * p) const { for (int i = 0; i < D; i++) p[i] = dval[i]; } NETGEN_INLINE void LoadGradient (const SCAL * p) { for (int i = 0; i < D; i++) dval[i] = p[i]; } NETGEN_INLINE void StoreHessian (SCAL * p) const { for (int i = 0; i < D*D; i++) p[i] = ddval[i]; } NETGEN_INLINE void LoadHessian (const SCAL * p) { for (int i = 0; i < D*D; i++) ddval[i] = p[i]; } /// returns value SCAL Value() const throw() { return val; } /// returns partial derivative SCAL DValue (int i) const throw() { return dval[i]; } AutoDiff DValueAD (int i) const { AutoDiff r(dval[i]); for (int j = 0; j < D; j++) r.DValue(j) = ddval[i*D+j]; return r; } /// returns partial derivative SCAL DDValue (int i) const throw() { return ddval[i]; } /// returns partial derivative SCAL DDValue (int i, int j) const throw() { return ddval[i*D+j]; } /// access value SCAL & Value() throw() { return val; } /// accesses partial derivative SCAL & DValue (int i) throw() { return dval[i]; } /// accesses partial derivative SCAL & DDValue (int i) throw() { return ddval[i]; } /// accesses partial derivative SCAL & DDValue (int i, int j) throw() { return ddval[i*D+j]; } explicit operator AutoDiff () const { return AutoDiff (val, &dval[0]); } /// add autodiffdiff object AutoDiffDiff & operator+= (const AutoDiffDiff & y) throw() { val += y.val; for (int i = 0; i < D; i++) dval[i] += y.dval[i]; for (int i = 0; i < D*D; i++) ddval[i] += y.ddval[i]; return *this; } /// subtract autodiffdiff object AutoDiffDiff & operator-= (const AutoDiffDiff & y) throw() { val -= y.val; for (int i = 0; i < D; i++) dval[i] -= y.dval[i]; for (int i = 0; i < D*D; i++) ddval[i] -= y.ddval[i]; return *this; } /// multiply with autodiffdiff object AutoDiffDiff & operator*= (const AutoDiffDiff & y) throw() { for (int i = 0; i < D*D; i++) ddval[i] = val * y.ddval[i] + y.val * ddval[i]; for (int i = 0; i < D; i++) for (int j = 0; j < D; j++) ddval[i*D+j] += dval[i] * y.dval[j] + dval[j] * y.dval[i]; for (int i = 0; i < D; i++) { dval[i] *= y.val; dval[i] += val * y.dval[i]; } val *= y.val; return *this; } /// multiply with scalar AutoDiffDiff & operator*= (const SCAL & y) throw() { for ( int i = 0; i < D*D; i++ ) ddval[i] *= y; for (int i = 0; i < D; i++) dval[i] *= y; val *= y; return *this; } /// divide by scalar AutoDiffDiff & operator/= (const SCAL & y) throw() { SCAL iy = 1.0 / y; for ( int i = 0; i < D*D; i++ ) ddval[i] *= iy; for (int i = 0; i < D; i++) dval[i] *= iy; val *= iy; return *this; } /// same value bool operator== (SCAL val2) throw() { return val == val2; } /// different values bool operator!= (SCAL val2) throw() { return val != val2; } /// less bool operator< (SCAL val2) throw() { return val < val2; } /// greater bool operator> (SCAL val2) throw() { return val > val2; } }; //@{ AutoDiff helper functions. /// Prints AudoDiffDiff template inline ostream & operator<< (ostream & ost, const AutoDiffDiff & x) { ost << x.Value() << ", D = "; for (int i = 0; i < D; i++) ost << x.DValue(i) << " "; ost << ", DD = "; for (int i = 0; i < D*D; i++) ost << x.DDValue(i) << " "; return ost; } /// template inline AutoDiffDiff operator+ (const AutoDiffDiff & x, const AutoDiffDiff & y) throw() { AutoDiffDiff res; res.Value () = x.Value()+y.Value(); for (int i = 0; i < D; i++) res.DValue(i) = x.DValue(i) + y.DValue(i); for (int i = 0; i < D*D; i++) res.DDValue(i) = x.DDValue(i) + y.DDValue(i); return res; } /// template inline AutoDiffDiff operator- (const AutoDiffDiff & x, const AutoDiffDiff & y) throw() { AutoDiffDiff res; res.Value() = x.Value()-y.Value(); for (int i = 0; i < D; i++) res.DValue(i) = x.DValue(i) - y.DValue(i); for (int i = 0; i < D*D; i++) res.DDValue(i) = x.DDValue(i) - y.DDValue(i); return res; } /// template::value, int>::type = 0> inline AutoDiffDiff operator+ (SCAL2 x, const AutoDiffDiff & y) throw() { AutoDiffDiff res; res.Value() = x+y.Value(); for (int i = 0; i < D; i++) res.DValue(i) = y.DValue(i); for (int i = 0; i < D*D; i++) res.DDValue(i) = y.DDValue(i); return res; } /// template::value, int>::type = 0> inline AutoDiffDiff operator+ (const AutoDiffDiff & y, SCAL2 x) throw() { AutoDiffDiff res; res.Value() = x+y.Value(); for (int i = 0; i < D; i++) res.DValue(i) = y.DValue(i); for (int i = 0; i < D*D; i++) res.DDValue(i) = y.DDValue(i); return res; } /// template inline AutoDiffDiff operator- (const AutoDiffDiff & x) throw() { AutoDiffDiff res; res.Value() = -x.Value(); for (int i = 0; i < D; i++) res.DValue(i) = -x.DValue(i); for (int i = 0; i < D*D; i++) res.DDValue(i) = -x.DDValue(i); return res; } /// template::value, int>::type = 0> inline AutoDiffDiff operator- (const AutoDiffDiff & x, SCAL2 y) throw() { AutoDiffDiff res; res.Value() = x.Value()-y; for (int i = 0; i < D; i++) res.DValue(i) = x.DValue(i); for (int i = 0; i < D*D; i++) res.DDValue(i) = x.DDValue(i); return res; } /// template::value, int>::type = 0> inline AutoDiffDiff operator- (SCAL2 x, const AutoDiffDiff & y) throw() { AutoDiffDiff res; res.Value() = x-y.Value(); for (int i = 0; i < D; i++) res.DValue(i) = -y.DValue(i); for (int i = 0; i < D*D; i++) res.DDValue(i) = -y.DDValue(i); return res; } /// template::value, int>::type = 0> inline AutoDiffDiff operator* (SCAL2 x, const AutoDiffDiff & y) throw() { AutoDiffDiff res; res.Value() = x*y.Value(); for (int i = 0; i < D; i++) res.DValue(i) = x*y.DValue(i); for (int i = 0; i < D*D; i++) res.DDValue(i) = x*y.DDValue(i); return res; } /// template::value, int>::type = 0> inline AutoDiffDiff operator* (const AutoDiffDiff & y, SCAL2 x) throw() { AutoDiffDiff res; res.Value() = x*y.Value(); for (int i = 0; i < D; i++) res.DValue(i) = x*y.DValue(i); for (int i = 0; i < D*D; i++) res.DDValue(i) = x*y.DDValue(i); return res; } /// template inline AutoDiffDiff operator* (const AutoDiffDiff & x, const AutoDiffDiff & y) throw() { AutoDiffDiff 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); for (int i = 0; i < D; i++) for (int j = 0; j < D; j++) res.DDValue(i,j) = hx * y.DDValue(i,j) + hy * x.DDValue(i,j) + x.DValue(i) * y.DValue(j) + x.DValue(j) * y.DValue(i); return res; } template inline AutoDiffDiff Inv (const AutoDiffDiff & x) { AutoDiffDiff res(1.0 / x.Value()); for (int i = 0; i < D; i++) res.DValue(i) = -x.DValue(i) / (x.Value() * x.Value()); SCAL fac1 = 2/(x.Value()*x.Value()*x.Value()); SCAL fac2 = 1/sqr(x.Value()); for (int i = 0; i < D; i++) for (int j = 0; j < D; j++) res.DDValue(i,j) = fac1*x.DValue(i)*x.DValue(j) - fac2*x.DDValue(i,j); return res; } template inline AutoDiffDiff operator/ (const AutoDiffDiff & x, const AutoDiffDiff & y) { return x * Inv (y); } template::value, int>::type = 0> inline AutoDiffDiff operator/ (const AutoDiffDiff & x, SCAL2 y) { return (1/y) * x; } template::value, int>::type = 0> inline AutoDiffDiff operator/ (SCAL2 x, const AutoDiffDiff & y) { return x * Inv(y); } template inline AutoDiffDiff sqrt (const AutoDiffDiff & x) { AutoDiffDiff res; res.Value() = sqrt(x.Value()); for (int j = 0; j < D; j++) res.DValue(j) = IfZero(x.DValue(j),SCAL{0.},0.5 / res.Value() * x.DValue(j)); for (int i = 0; i < D; i++) for (int j = 0; j < D; j++) res.DDValue(i,j) = IfZero(x.DDValue(i,j)+x.DValue(i) * x.DValue(j),SCAL{0.},0.5/res.Value() * x.DDValue(i,j) - 0.25 / (x.Value()*res.Value()) * x.DValue(i) * x.DValue(j)); return res; } // df(u)/dx = exp(x) * du/dx // d^2 f(u) / dx^2 = exp(x) * (du/dx)^2 + exp(x) * d^2u /dx^2 template NETGEN_INLINE AutoDiffDiff exp (AutoDiffDiff x) { AutoDiffDiff res; res.Value() = exp(x.Value()); for (int k = 0; k < D; k++) res.DValue(k) = x.DValue(k) * res.Value(); for (int k = 0; k < D; k++) for (int l = 0; l < D; l++) res.DDValue(k,l) = (x.DValue(k) * x.DValue(l)+x.DDValue(k,l)) * res.Value(); return res; } using std::pow; template NETGEN_INLINE AutoDiffDiff pow (AutoDiffDiff x, AutoDiffDiff y ) { return exp(log(x)*y); } template NETGEN_INLINE AutoDiffDiff log (AutoDiffDiff x) { AutoDiffDiff res; res.Value() = log(x.Value()); SCAL xinv = 1.0/x.Value(); for (int k = 0; k < D; k++) res.DValue(k) = x.DValue(k) * xinv; for (int k = 0; k < D; k++) for (int l = 0; l < D; l++) res.DDValue(k,l) = -xinv*xinv*x.DValue(k) * x.DValue(l) + xinv * x.DDValue(k,l); return res; } template NETGEN_INLINE AutoDiffDiff sin (AutoDiffDiff x) { AutoDiffDiff res; SCAL s = sin(x.Value()); SCAL c = cos(x.Value()); res.Value() = s; for (int k = 0; k < D; k++) res.DValue(k) = x.DValue(k) * c; for (int k = 0; k < D; k++) for (int l = 0; l < D; l++) res.DDValue(k,l) = -s * x.DValue(k) * x.DValue(l) + c * x.DDValue(k,l); return res; } template NETGEN_INLINE AutoDiffDiff cos (AutoDiffDiff x) { AutoDiffDiff res; SCAL s = sin(x.Value()); SCAL c = cos(x.Value()); res.Value() = c; for (int k = 0; k < D; k++) res.DValue(k) = -s * x.DValue(k); for (int k = 0; k < D; k++) for (int l = 0; l < D; l++) res.DDValue(k,l) = -c * x.DValue(k) * x.DValue(l) - s * x.DDValue(k,l); return res; } template NETGEN_INLINE AutoDiffDiff tan (AutoDiffDiff x) { return sin(x) / cos(x); } template NETGEN_INLINE AutoDiffDiff atan (AutoDiffDiff x) { AutoDiffDiff res; SCAL a = atan(x.Value()); res.Value() = a; for (int k = 0; k < D; k++) res.DValue(k) = x.DValue(k)/(1+x.Value()*x.Value()) ; for (int k = 0; k < D; k++) for (int l = 0; l < D; l++) res.DDValue(k,l) = -2*x.Value()/((1+x.Value()*x.Value())*(1+x.Value()*x.Value())) * x.DValue(k) * x.DValue(l) + x.DDValue(k,l)/(1+x.Value()*x.Value()); return res; } template NETGEN_INLINE AutoDiffDiff atan2 (AutoDiffDiff x,AutoDiffDiff y) { AutoDiffDiff res; SCAL a = atan2(x.Value(), y.Value()); res.Value() = a; for (int k = 0; k < D; k++) res.DValue(k) = (x.Value()*y.DValue(k)-y.Value()*x.DValue(k))/(y.Value()*y.Value()+x.Value()*x.Value()); for (int k = 0; k < D; k++) for (int l = 0; l < D; l++) res.DDValue(k,l) = (x.DValue(k)*y.DValue(l)+x.Value()*y.DDValue(l,k) - y.DValue(k)*x.DValue(l) - y.Value()*x.DDValue(l,k))/(y.Value()*y.Value()+x.Value()*x.Value()) - 2 * (x.Value()*y.DValue(k)-y.Value()*x.DValue(k)) * (x.Value()*x.DValue(k) + y.Value()*y.DValue(k))/( (y.Value()*y.Value()+x.Value()*x.Value()) * (y.Value()*y.Value()+x.Value()*x.Value()) ); return res; } using std::acos; template NETGEN_INLINE AutoDiffDiff acos (AutoDiffDiff x) { AutoDiffDiff res; SCAL a = acos(x.Value()); res.Value() = a; auto omaa = 1-x.Value()*x.Value(); auto s = sqrt(omaa); SCAL da = -1 / s; SCAL dda = -x.Value() / (s*omaa); for (int k = 0; k < D; k++) res.DValue(k) = x.DValue(k)*da; for (int k = 0; k < D; k++) for (int l = 0; l < D; l++) res.DDValue(k,l) = dda * x.DValue(k) * x.DValue(l) + da * x.DDValue(k,l); return res; } using std::acos; template NETGEN_INLINE AutoDiffDiff asin (AutoDiffDiff x) { AutoDiffDiff res; SCAL a = asin(x.Value()); res.Value() = a; auto omaa = 1-x.Value()*x.Value(); auto s = sqrt(omaa); SCAL da = 1 / s; SCAL dda = x.Value() / (s*omaa); for (int k = 0; k < D; k++) res.DValue(k) = x.DValue(k)*da; for (int k = 0; k < D; k++) for (int l = 0; l < D; l++) res.DDValue(k,l) = dda * x.DValue(k) * x.DValue(l) + da * x.DDValue(k,l); return res; } template NETGEN_INLINE AutoDiffDiff sinh (AutoDiffDiff x) { AutoDiffDiff res; SCAL sh = sinh(x.Value()); SCAL ch = cosh(x.Value()); res.Value() = sh; for (int k = 0; k < D; k++) res.DValue(k) = x.DValue(k) * ch; for (int k = 0; k < D; k++) for (int l = 0; l < D; l++) res.DDValue(k,l) = sh * x.DValue(k) * x.DValue(l) + ch * x.DDValue(k,l); return res; } template NETGEN_INLINE AutoDiffDiff cosh (AutoDiffDiff x) { AutoDiffDiff res; SCAL sh = sinh(x.Value()); SCAL ch = cosh(x.Value()); res.Value() = ch; for (int k = 0; k < D; k++) res.DValue(k) = sh * x.DValue(k); for (int k = 0; k < D; k++) for (int l = 0; l < D; l++) res.DDValue(k,l) = ch * x.DValue(k) * x.DValue(l) + sh * x.DDValue(k,l); return res; } template NETGEN_INLINE AutoDiffDiff erf (AutoDiffDiff x) { AutoDiffDiff res; SCAL derf = 2. / sqrt(M_PI) * exp(- x.Value() * x.Value()); res.Value() = erf(x.Value()); for (int k = 0; k < D; k++) res.DValue(k) = - derf * x.DValue(k); for (int k = 0; k < D; k++) for (int l = 0; l < D; l++) res.DDValue(k,l) = derf * (x.DDValue(k, l) - 2 * x.Value() * x.DValue(k) * x.DValue(l)); return res; } using std::floor; template NETGEN_INLINE AutoDiffDiff floor (const AutoDiffDiff & x) { return floor(x.Value()); } using std::ceil; template NETGEN_INLINE AutoDiffDiff ceil (const AutoDiffDiff & x) { return ceil(x.Value()); } template auto IfPos (AutoDiffDiff a, TB b, TC c) -> decltype(IfPos (a.Value(), b, c)) { return IfPos (a.Value(), b, c); } template NETGEN_INLINE AutoDiffDiff IfPos (SCAL /* SIMD */ a, AutoDiffDiff b, AutoDiffDiff c) { AutoDiffDiff res; res.Value() = IfPos (a, b.Value(), c.Value()); for (int j = 0; j < D; j++) { res.DValue(j) = IfPos (a, b.DValue(j), c.DValue(j)); res.DDValue(j) = IfPos (a, b.DDValue(j), c.DDValue(j)); } return res; } template NETGEN_INLINE AutoDiffDiff IfPos (SCAL /* SIMD */ a, AutoDiffDiff b, TC c) { return IfPos (a, b, AutoDiffDiff (c)); } //@} } namespace ngbla { template struct is_scalar_type; template struct is_scalar_type> { static constexpr bool value = true; }; // not meaningful for AutoDiff, since this is // not (complex) differentiable anyway template inline auto L2Norm2 (const ngcore::AutoDiffDiff & x) { return x*x; } } #endif ================================================ FILE: libsrc/core/bitarray.cpp ================================================ /**************************************************************************/ /* File: bitarray.cpp */ /* Autho: Joachim Schoeberl */ /* Date: 01. Jun. 95 */ /**************************************************************************/ /* data type BitArray */ #include "bitarray.hpp" #include "archive.hpp" namespace ngcore { BitArray :: BitArray (size_t asize) { size = 0; data = NULL; SetSize (asize); } BitArray :: BitArray (size_t asize, LocalHeap & lh) { size = asize; data = new (lh) unsigned char [Addr (size)+1]; owns_data = false; } BitArray :: BitArray (const BitArray & ba2) { size = 0; data = NULL; (*this) = ba2; } void BitArray :: SetSize (size_t asize) { if (size == asize) return; if (owns_data) { delete [] data; mt.Free(GetMemoryUsage()); } size = asize; data = new unsigned char [Addr (size)+1]; owns_data = true; mt.Alloc(GetMemoryUsage()); } BitArray & BitArray :: Set () throw() { if (!size) return *this; for (size_t i = 0; i <= Addr (size); i++) data[i] = UCHAR_MAX; return *this; } BitArray & BitArray :: Clear () throw() { if (!size) return *this; for (size_t i = 0; i <= Addr (size); i++) data[i] = 0; return *this; } BitArray & BitArray :: Invert () { if (!size) return *this; for (size_t i = 0; i <= Addr (size); i++) data[i] ^= 255; return *this; } BitArray & BitArray :: And (const BitArray & ba2) { if (!size) return *this; for (size_t i = 0; i <= Addr (size); i++) data[i] &= ba2.data[i]; return *this; } BitArray & BitArray :: Or (const BitArray & ba2) { if (!size) return *this; for (size_t i = 0; i <= Addr (size); i++) data[i] |= ba2.data[i]; return *this; } bool BitArray :: operator==(const BitArray& other) const { if(size != other.Size()) return false; for(auto i : Range(size/CHAR_BIT)) if(data[i] != other.data[i]) return false; for(auto i : Range(size%CHAR_BIT)) if(Test(i + CHAR_BIT * (size/CHAR_BIT)) != other.Test(i + CHAR_BIT * (size/CHAR_BIT))) return false; return true; } BitArray & BitArray :: operator= (const BitArray & ba2) { SetSize (ba2.Size()); if (!size) return *this; for (size_t i = 0; i <= Addr (size); i++) data[i] = ba2.data[i]; return *this; } std::ostream & operator<<(std::ostream & s, const BitArray & ba) { size_t n = ba.Size(); for (size_t i = 0; i < n; i++) { if (i % 50 == 0) s << i << ": "; s << int(ba[i]); if (i % 50 == 49) s << "\n"; } s << std::flush; return s; } size_t BitArray :: NumSet () const { size_t cnt = 0; for (size_t i = 0; i < Size(); i++) if (Test(i)) cnt++; return cnt; } void BitArray :: DoArchive(Archive& archive) { if(archive.GetVersion("netgen") >= "v6.2.2007-62") { archive.NeedsVersion("netgen", "v6.2.2007-62"); auto size = Size(); archive & size; if(archive.Input()) SetSize(size); if(archive.GetVersion("netgen") < "v6.2.2009-20") archive.Do(data, size/CHAR_BIT+1); else { archive.NeedsVersion("netgen", "v6.2.2009-20"); archive.Do(data, size/CHAR_BIT); for(size_t i = 0; i < size%CHAR_BIT; i++) { size_t index = CHAR_BIT * (size/CHAR_BIT) + i; bool b = Test(index); archive & b; b ? SetBit(index) : Clear(index); } } } else { if (archive.Output()) { throw Exception("should not get here"); archive << Size(); for (size_t i = 0; i < Size(); i++) archive << (*this)[i]; } else { size_t size; archive & size; SetSize (size); Clear(); for (size_t i = 0; i < size; i++) { bool b; archive & b; if (b) SetBit(i); } } } } } // namespace ngcore ================================================ FILE: libsrc/core/bitarray.hpp ================================================ #ifndef NETGEN_CORE_BITARRAY #define NETGEN_CORE_BITARRAY /**************************************************************************/ /* File: bitarray.hpp */ /* Author: Joachim Schoeberl */ /* Date: 01. Jun. 95 */ /**************************************************************************/ #include #include #include #include "array.hpp" #include "localheap.hpp" #include "ngcore_api.hpp" #include "utils.hpp" namespace ngcore { /** A compressed array of bools. Provides bit-operations and whole array operations. */ class BitArray { protected: /// number of bits size_t size; /// the data unsigned char * data; /// bool owns_data = true; public: /// empty array BitArray () : size(0), data(nullptr) { ; } /// array of asize bits NGCORE_API BitArray (size_t asize); /// array of asize bits NGCORE_API BitArray (size_t asize, LocalHeap & lh); /// NGCORE_API BitArray (const BitArray & ba2); BitArray (BitArray && ba2) : size(ba2.size), data(ba2.data), owns_data(ba2.owns_data) { ba2.owns_data = false; ba2.data = nullptr; mt = std::move(ba2.mt); } template NETGEN_INLINE BitArray (std::initializer_list list) : BitArray (list.size()) { Clear(); int cnt = 0; for (auto i = list.begin(); i < list.end(); i++, cnt++) if (*i) SetBit(cnt); StartMemoryTracing(); } /// delete data ~BitArray () { if (owns_data) { delete [] data; mt.Free(GetMemoryUsage()); } } /// Set size, loose values NGCORE_API void SetSize (size_t asize); /// the size size_t Size () const { return size; } /// set all bits NGCORE_API BitArray & Set () throw(); /// clear all bits NGCORE_API BitArray & Clear () throw(); /// set bit i [[deprecated("Use either SetBit() or SetBitAtomic()")]] void Set (size_t i) { SetBitAtomic(i); } /// set bit i ( not thread safe ) void SetBit (size_t i) { NETGEN_CHECK_RANGE(i, 0, size); data[Addr(i)] |= Mask(i); } /// set bit i ( thread safe ) void SetBitAtomic (size_t i) { NETGEN_CHECK_RANGE(i, 0, size); unsigned char * p = data+Addr(i); unsigned char mask = Mask(i); AsAtomic(*p) |= mask; } /// clear bit i void Clear (size_t i) { NETGEN_CHECK_RANGE(i, 0, size); data[Addr(i)] &= ~Mask(i); } /// check bit i bool Test (size_t i) const { NETGEN_CHECK_RANGE(i, 0, size); return (data[Addr(i)] & Mask(i)) ? true : false; } /// set all bits to b BitArray & operator= (bool b) { if (b) Set(); else Clear(); return *this; } /// check bit i bool operator[] (size_t i) const { NETGEN_CHECK_RANGE(i, 0, size); return Test(i); } NGCORE_API bool operator==(const BitArray& other) const; /// invert all bits NGCORE_API BitArray & Invert (); /// logical AND with ba2 NGCORE_API BitArray & And (const BitArray & ba2); /// logical OR with ba2 NGCORE_API BitArray & Or (const BitArray & ba2); /// copy from ba2 NGCORE_API BitArray & operator= (const BitArray & ba2); NGCORE_API size_t NumSet () const; NGCORE_API void DoArchive(class Archive& archive); NGCORE_API auto * Data() const { return data; } size_t GetMemoryUsage() const { return owns_data ? (size+CHAR_BIT-1)/CHAR_BIT : 0; } const MemoryTracer& GetMemoryTracer() const { return mt; } void StartMemoryTracing() const { mt.Alloc(GetMemoryUsage()); } private: /// unsigned char Mask (size_t i) const { return char(1) << (i % CHAR_BIT); } /// size_t Addr (size_t i) const { return (i / CHAR_BIT); } MemoryTracer mt; }; inline BitArray & operator|= (BitArray & me, const BitArray & you) { me.Or(you); return me; } inline BitArray & operator&= (BitArray & me, const BitArray & you) { me.And(you); return me; } inline BitArray operator| (const BitArray & a, const BitArray & b) { BitArray res = a; res |= b; return res; } inline BitArray operator& (const BitArray & a, const BitArray & b) { BitArray res = a; res &= b; return res; } inline BitArray operator~ (const BitArray & a) { BitArray res = a; res.Invert(); return res; } NGCORE_API std::ostream & operator<<(std::ostream & s, const BitArray & ba); template class TBitArray : public BitArray { public: using BitArray::BitArray; void SetBit (IndexType i) { BitArray::SetBit(i-IndexBASE()); } void Clear () { BitArray::Clear(); } void Clear (IndexType i) { BitArray::Clear(i-IndexBASE()); } void SetBitAtomic (IndexType i) { BitArray::SetBitAtomic(i-IndexBASE()); } bool Test (IndexType i) const { return BitArray::Test(i-IndexBASE()); } bool operator[] (IndexType i) const { return Test(i); } T_Range Range() const { return { IndexBASE(), IndexBASE()+Size() }; } NGCORE_API TBitArray & Or (const TBitArray & ba2) { BitArray::Or(ba2); return *this; } }; } // namespace ngcore #endif // NETGEN_CORE_BITARRAY ================================================ FILE: libsrc/core/concurrentqueue.h ================================================ // Provides a C++11 implementation of a multi-producer, multi-consumer lock-free queue. // An overview, including benchmark results, is provided here: // http://moodycamel.com/blog/2014/a-fast-general-purpose-lock-free-queue-for-c++ // The full design is also described in excruciating detail at: // http://moodycamel.com/blog/2014/detailed-design-of-a-lock-free-queue // Boost Software License - Version 1.0 - August 17th, 2003 // // Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following: // // The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE #pragma once #if defined(__GNUC__) // Disable -Wconversion warnings (spuriously triggered when Traits::size_t and // Traits::index_t are set to < 32 bits, causing integer promotion, causing warnings // upon assigning any computed values) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wconversion" #ifdef MCDBGQ_USE_RELACY #pragma GCC diagnostic ignored "-Wint-to-pointer-cast" #endif #endif #if defined(__APPLE__) #include "TargetConditionals.h" #endif #ifdef MCDBGQ_USE_RELACY #include "relacy/relacy_std.hpp" #include "relacy_shims.h" // We only use malloc/free anyway, and the delete macro messes up `= delete` method declarations. // We'll override the default trait malloc ourselves without a macro. #undef new #undef delete #undef malloc #undef free #else #include // Requires C++11. Sorry VS2010. #include #endif #include // for max_align_t #include #include #include #include #include #include #include // for CHAR_BIT #include #include // partly for __WINPTHREADS_VERSION if on MinGW-w64 w/ POSIX threading // Platform-specific definitions of a numeric thread ID type and an invalid value namespace moodycamel { namespace details { template struct thread_id_converter { typedef thread_id_t thread_id_numeric_size_t; typedef thread_id_t thread_id_hash_t; static thread_id_hash_t prehash(thread_id_t const& x) { return x; } }; } } #if defined(MCDBGQ_USE_RELACY) namespace moodycamel { namespace details { typedef std::uint32_t thread_id_t; static const thread_id_t invalid_thread_id = 0xFFFFFFFFU; static const thread_id_t invalid_thread_id2 = 0xFFFFFFFEU; static inline thread_id_t thread_id() { return rl::thread_index(); } } } #elif defined(_WIN32) || defined(__WINDOWS__) || defined(__WIN32__) // No sense pulling in windows.h in a header, we'll manually declare the function // we use and rely on backwards-compatibility for this not to break extern "C" __declspec(dllimport) unsigned long __stdcall GetCurrentThreadId(void); namespace moodycamel { namespace details { static_assert(sizeof(unsigned long) == sizeof(std::uint32_t), "Expected size of unsigned long to be 32 bits on Windows"); typedef std::uint32_t thread_id_t; static const thread_id_t invalid_thread_id = 0; // See http://blogs.msdn.com/b/oldnewthing/archive/2004/02/23/78395.aspx static const thread_id_t invalid_thread_id2 = 0xFFFFFFFFU; // Not technically guaranteed to be invalid, but is never used in practice. Note that all Win32 thread IDs are presently multiples of 4. static inline thread_id_t thread_id() { return static_cast(::GetCurrentThreadId()); } } } #elif defined(__arm__) || defined(_M_ARM) || defined(__aarch64__) || (defined(__APPLE__) && TARGET_OS_IPHONE) namespace moodycamel { namespace details { static_assert(sizeof(std::thread::id) == 4 || sizeof(std::thread::id) == 8, "std::thread::id is expected to be either 4 or 8 bytes"); typedef std::thread::id thread_id_t; static const thread_id_t invalid_thread_id; // Default ctor creates invalid ID // Note we don't define a invalid_thread_id2 since std::thread::id doesn't have one; it's // only used if MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED is defined anyway, which it won't // be. static inline thread_id_t thread_id() { return std::this_thread::get_id(); } template struct thread_id_size { }; template<> struct thread_id_size<4> { typedef std::uint32_t numeric_t; }; template<> struct thread_id_size<8> { typedef std::uint64_t numeric_t; }; template<> struct thread_id_converter { typedef thread_id_size::numeric_t thread_id_numeric_size_t; #ifndef __APPLE__ typedef std::size_t thread_id_hash_t; #else typedef thread_id_numeric_size_t thread_id_hash_t; #endif static thread_id_hash_t prehash(thread_id_t const& x) { #ifndef __APPLE__ return std::hash()(x); #else return *reinterpret_cast(&x); #endif } }; } } #else // Use a nice trick from this answer: http://stackoverflow.com/a/8438730/21475 // In order to get a numeric thread ID in a platform-independent way, we use a thread-local // static variable's address as a thread identifier :-) #if defined(__GNUC__) || defined(__INTEL_COMPILER) #define MOODYCAMEL_THREADLOCAL __thread #elif defined(_MSC_VER) #define MOODYCAMEL_THREADLOCAL __declspec(thread) #else // Assume C++11 compliant compiler #define MOODYCAMEL_THREADLOCAL thread_local #endif namespace moodycamel { namespace details { typedef std::uintptr_t thread_id_t; static const thread_id_t invalid_thread_id = 0; // Address can't be nullptr static const thread_id_t invalid_thread_id2 = 1; // Member accesses off a null pointer are also generally invalid. Plus it's not aligned. static inline thread_id_t thread_id() { static MOODYCAMEL_THREADLOCAL int x; return reinterpret_cast(&x); } } } #endif // Exceptions #ifndef MOODYCAMEL_EXCEPTIONS_ENABLED #if (defined(_MSC_VER) && defined(_CPPUNWIND)) || (defined(__GNUC__) && defined(__EXCEPTIONS)) || (!defined(_MSC_VER) && !defined(__GNUC__)) #define MOODYCAMEL_EXCEPTIONS_ENABLED #endif #endif #ifdef MOODYCAMEL_EXCEPTIONS_ENABLED #define MOODYCAMEL_TRY try #define MOODYCAMEL_CATCH(...) catch(__VA_ARGS__) #define MOODYCAMEL_RETHROW throw #define MOODYCAMEL_THROW(expr) throw (expr) #else #define MOODYCAMEL_TRY if (true) #define MOODYCAMEL_CATCH(...) else if (false) #define MOODYCAMEL_RETHROW #define MOODYCAMEL_THROW(expr) #endif #ifndef MOODYCAMEL_NOEXCEPT #if !defined(MOODYCAMEL_EXCEPTIONS_ENABLED) #define MOODYCAMEL_NOEXCEPT #define MOODYCAMEL_NOEXCEPT_CTOR(type, valueType, expr) true #define MOODYCAMEL_NOEXCEPT_ASSIGN(type, valueType, expr) true #elif defined(_MSC_VER) && defined(_NOEXCEPT) && _MSC_VER < 1800 // VS2012's std::is_nothrow_[move_]constructible is broken and returns true when it shouldn't :-( // We have to assume *all* non-trivial constructors may throw on VS2012! #define MOODYCAMEL_NOEXCEPT _NOEXCEPT #define MOODYCAMEL_NOEXCEPT_CTOR(type, valueType, expr) (std::is_rvalue_reference::value && std::is_move_constructible::value ? std::is_trivially_move_constructible::value : std::is_trivially_copy_constructible::value) #define MOODYCAMEL_NOEXCEPT_ASSIGN(type, valueType, expr) ((std::is_rvalue_reference::value && std::is_move_assignable::value ? std::is_trivially_move_assignable::value || std::is_nothrow_move_assignable::value : std::is_trivially_copy_assignable::value || std::is_nothrow_copy_assignable::value) && MOODYCAMEL_NOEXCEPT_CTOR(type, valueType, expr)) #elif defined(_MSC_VER) && defined(_NOEXCEPT) && _MSC_VER < 1900 #define MOODYCAMEL_NOEXCEPT _NOEXCEPT #define MOODYCAMEL_NOEXCEPT_CTOR(type, valueType, expr) (std::is_rvalue_reference::value && std::is_move_constructible::value ? std::is_trivially_move_constructible::value || std::is_nothrow_move_constructible::value : std::is_trivially_copy_constructible::value || std::is_nothrow_copy_constructible::value) #define MOODYCAMEL_NOEXCEPT_ASSIGN(type, valueType, expr) ((std::is_rvalue_reference::value && std::is_move_assignable::value ? std::is_trivially_move_assignable::value || std::is_nothrow_move_assignable::value : std::is_trivially_copy_assignable::value || std::is_nothrow_copy_assignable::value) && MOODYCAMEL_NOEXCEPT_CTOR(type, valueType, expr)) #else #define MOODYCAMEL_NOEXCEPT noexcept #define MOODYCAMEL_NOEXCEPT_CTOR(type, valueType, expr) noexcept(expr) #define MOODYCAMEL_NOEXCEPT_ASSIGN(type, valueType, expr) noexcept(expr) #endif #endif #ifndef MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED #ifdef MCDBGQ_USE_RELACY #define MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED #else // VS2013 doesn't support `thread_local`, and MinGW-w64 w/ POSIX threading has a crippling bug: http://sourceforge.net/p/mingw-w64/bugs/445 // g++ <=4.7 doesn't support thread_local either. // Finally, iOS/ARM doesn't have support for it either, and g++/ARM allows it to compile but it's unconfirmed to actually work #if (!defined(_MSC_VER) || _MSC_VER >= 1900) && (!defined(__MINGW32__) && !defined(__MINGW64__) || !defined(__WINPTHREADS_VERSION)) && (!defined(__GNUC__) || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)) && (!defined(__APPLE__) || !TARGET_OS_IPHONE) && !defined(__arm__) && !defined(_M_ARM) && !defined(__aarch64__) // Assume `thread_local` is fully supported in all other C++11 compilers/platforms //#define MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED // always disabled for now since several users report having problems with it on #endif #endif #endif // VS2012 doesn't support deleted functions. // In this case, we declare the function normally but don't define it. A link error will be generated if the function is called. #ifndef MOODYCAMEL_DELETE_FUNCTION #if defined(_MSC_VER) && _MSC_VER < 1800 #define MOODYCAMEL_DELETE_FUNCTION #else #define MOODYCAMEL_DELETE_FUNCTION = delete #endif #endif // Compiler-specific likely/unlikely hints namespace moodycamel { namespace details { #if defined(__GNUC__) static inline bool (likely)(bool x) { return __builtin_expect((x), true); } static inline bool (unlikely)(bool x) { return __builtin_expect((x), false); } #else static inline bool (likely)(bool x) { return x; } static inline bool (unlikely)(bool x) { return x; } #endif } } #ifdef MOODYCAMEL_QUEUE_INTERNAL_DEBUG #include "internal/concurrentqueue_internal_debug.h" #endif namespace moodycamel { namespace details { template struct const_numeric_max { static_assert(std::is_integral::value, "const_numeric_max can only be used with integers"); static const T value = std::numeric_limits::is_signed ? (static_cast(1) << (sizeof(T) * CHAR_BIT - 1)) - static_cast(1) : static_cast(-1); }; #if defined(__GLIBCXX__) typedef ::max_align_t std_max_align_t; // libstdc++ forgot to add it to std:: for a while #else typedef std::max_align_t std_max_align_t; // Others (e.g. MSVC) insist it can *only* be accessed via std:: #endif // Some platforms have incorrectly set max_align_t to a type with <8 bytes alignment even while supporting // 8-byte aligned scalar values (*cough* 32-bit iOS). Work around this with our own union. See issue #64. typedef union { std_max_align_t x; long long y; void* z; } max_align_t; } // Default traits for the ConcurrentQueue. To change some of the // traits without re-implementing all of them, inherit from this // struct and shadow the declarations you wish to be different; // since the traits are used as a template type parameter, the // shadowed declarations will be used where defined, and the defaults // otherwise. struct ConcurrentQueueDefaultTraits { // General-purpose size type. std::size_t is strongly recommended. typedef std::size_t size_t; // The type used for the enqueue and dequeue indices. Must be at least as // large as size_t. Should be significantly larger than the number of elements // you expect to hold at once, especially if you have a high turnover rate; // for example, on 32-bit x86, if you expect to have over a hundred million // elements or pump several million elements through your queue in a very // short space of time, using a 32-bit type *may* trigger a race condition. // A 64-bit int type is recommended in that case, and in practice will // prevent a race condition no matter the usage of the queue. Note that // whether the queue is lock-free with a 64-int type depends on the whether // std::atomic is lock-free, which is platform-specific. typedef std::size_t index_t; // Internally, all elements are enqueued and dequeued from multi-element // blocks; this is the smallest controllable unit. If you expect few elements // but many producers, a smaller block size should be favoured. For few producers // and/or many elements, a larger block size is preferred. A sane default // is provided. Must be a power of 2. static const size_t BLOCK_SIZE = 32; // For explicit producers (i.e. when using a producer token), the block is // checked for being empty by iterating through a list of flags, one per element. // For large block sizes, this is too inefficient, and switching to an atomic // counter-based approach is faster. The switch is made for block sizes strictly // larger than this threshold. static const size_t EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD = 32; // How many full blocks can be expected for a single explicit producer? This should // reflect that number's maximum for optimal performance. Must be a power of 2. static const size_t EXPLICIT_INITIAL_INDEX_SIZE = 32; // How many full blocks can be expected for a single implicit producer? This should // reflect that number's maximum for optimal performance. Must be a power of 2. static const size_t IMPLICIT_INITIAL_INDEX_SIZE = 32; // The initial size of the hash table mapping thread IDs to implicit producers. // Note that the hash is resized every time it becomes half full. // Must be a power of two, and either 0 or at least 1. If 0, implicit production // (using the enqueue methods without an explicit producer token) is disabled. static const size_t INITIAL_IMPLICIT_PRODUCER_HASH_SIZE = 32; // Controls the number of items that an explicit consumer (i.e. one with a token) // must consume before it causes all consumers to rotate and move on to the next // internal queue. static const std::uint32_t EXPLICIT_CONSUMER_CONSUMPTION_QUOTA_BEFORE_ROTATE = 256; // The maximum number of elements (inclusive) that can be enqueued to a sub-queue. // Enqueue operations that would cause this limit to be surpassed will fail. Note // that this limit is enforced at the block level (for performance reasons), i.e. // it's rounded up to the nearest block size. static const size_t MAX_SUBQUEUE_SIZE = details::const_numeric_max::value; #ifndef MCDBGQ_USE_RELACY // Memory allocation can be customized if needed. // malloc should return nullptr on failure, and handle alignment like std::malloc. #if defined(malloc) || defined(free) // Gah, this is 2015, stop defining macros that break standard code already! // Work around malloc/free being special macros: static inline void* WORKAROUND_malloc(size_t size) { return malloc(size); } static inline void WORKAROUND_free(void* ptr) { return free(ptr); } static inline void* (malloc)(size_t size) { return WORKAROUND_malloc(size); } static inline void (free)(void* ptr) { return WORKAROUND_free(ptr); } #else static inline void* malloc(size_t size) { return std::malloc(size); } static inline void free(void* ptr) { return std::free(ptr); } #endif #else // Debug versions when running under the Relacy race detector (ignore // these in user code) static inline void* malloc(size_t size) { return rl::rl_malloc(size, $); } static inline void free(void* ptr) { return rl::rl_free(ptr, $); } #endif }; // When producing or consuming many elements, the most efficient way is to: // 1) Use one of the bulk-operation methods of the queue with a token // 2) Failing that, use the bulk-operation methods without a token // 3) Failing that, create a token and use that with the single-item methods // 4) Failing that, use the single-parameter methods of the queue // Having said that, don't create tokens willy-nilly -- ideally there should be // a maximum of one token per thread (of each kind). struct ProducerToken; struct ConsumerToken; template class ConcurrentQueue; template class BlockingConcurrentQueue; class ConcurrentQueueTests; namespace details { struct ConcurrentQueueProducerTypelessBase { ConcurrentQueueProducerTypelessBase* next; std::atomic inactive; ProducerToken* token; ConcurrentQueueProducerTypelessBase() : next(nullptr), inactive(false), token(nullptr) { } }; template struct _hash_32_or_64 { static inline std::uint32_t hash(std::uint32_t h) { // MurmurHash3 finalizer -- see https://code.google.com/p/smhasher/source/browse/trunk/MurmurHash3.cpp // Since the thread ID is already unique, all we really want to do is propagate that // uniqueness evenly across all the bits, so that we can use a subset of the bits while // reducing collisions significantly h ^= h >> 16; h *= 0x85ebca6b; h ^= h >> 13; h *= 0xc2b2ae35; return h ^ (h >> 16); } }; template<> struct _hash_32_or_64<1> { static inline std::uint64_t hash(std::uint64_t h) { h ^= h >> 33; h *= 0xff51afd7ed558ccd; h ^= h >> 33; h *= 0xc4ceb9fe1a85ec53; return h ^ (h >> 33); } }; template struct hash_32_or_64 : public _hash_32_or_64<(size > 4)> { }; static inline size_t hash_thread_id(thread_id_t id) { static_assert(sizeof(thread_id_t) <= 8, "Expected a platform where thread IDs are at most 64-bit values"); return static_cast(hash_32_or_64::thread_id_hash_t)>::hash( thread_id_converter::prehash(id))); } template static inline bool circular_less_than(T a, T b) { #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4554) #endif static_assert(std::is_integral::value && !std::numeric_limits::is_signed, "circular_less_than is intended to be used only with unsigned integer types"); return static_cast(a - b) > static_cast(static_cast(1) << static_cast(sizeof(T) * CHAR_BIT - 1)); #ifdef _MSC_VER #pragma warning(pop) #endif } template static inline char* align_for(char* ptr) { const std::size_t alignment = std::alignment_of::value; return ptr + (alignment - (reinterpret_cast(ptr) % alignment)) % alignment; } template static inline T ceil_to_pow_2(T x) { static_assert(std::is_integral::value && !std::numeric_limits::is_signed, "ceil_to_pow_2 is intended to be used only with unsigned integer types"); // Adapted from http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2 --x; x |= x >> 1; x |= x >> 2; x |= x >> 4; for (std::size_t i = 1; i < sizeof(T); i <<= 1) { x |= x >> (i << 3); } ++x; return x; } template static inline void swap_relaxed(std::atomic& left, std::atomic& right) { T temp = std::move(left.load(std::memory_order_relaxed)); left.store(std::move(right.load(std::memory_order_relaxed)), std::memory_order_relaxed); right.store(std::move(temp), std::memory_order_relaxed); } template static inline T const& nomove(T const& x) { return x; } template struct nomove_if { template static inline T const& eval(T const& x) { return x; } }; template<> struct nomove_if { template static inline auto eval(U&& x) -> decltype(std::forward(x)) { return std::forward(x); } }; template static inline auto deref_noexcept(It& it) MOODYCAMEL_NOEXCEPT -> decltype(*it) { return *it; } #if defined(__clang__) || !defined(__GNUC__) || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) template struct is_trivially_destructible : std::is_trivially_destructible { }; #else template struct is_trivially_destructible : std::has_trivial_destructor { }; #endif #ifdef MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED #ifdef MCDBGQ_USE_RELACY typedef RelacyThreadExitListener ThreadExitListener; typedef RelacyThreadExitNotifier ThreadExitNotifier; #else struct ThreadExitListener { typedef void (*callback_t)(void*); callback_t callback; void* userData; ThreadExitListener* next; // reserved for use by the ThreadExitNotifier }; class ThreadExitNotifier { public: static void subscribe(ThreadExitListener* listener) { auto& tlsInst = instance(); listener->next = tlsInst.tail; tlsInst.tail = listener; } static void unsubscribe(ThreadExitListener* listener) { auto& tlsInst = instance(); ThreadExitListener** prev = &tlsInst.tail; for (auto ptr = tlsInst.tail; ptr != nullptr; ptr = ptr->next) { if (ptr == listener) { *prev = ptr->next; break; } prev = &ptr->next; } } private: ThreadExitNotifier() : tail(nullptr) { } ThreadExitNotifier(ThreadExitNotifier const&) MOODYCAMEL_DELETE_FUNCTION; ThreadExitNotifier& operator=(ThreadExitNotifier const&) MOODYCAMEL_DELETE_FUNCTION; ~ThreadExitNotifier() { // This thread is about to exit, let everyone know! assert(this == &instance() && "If this assert fails, you likely have a buggy compiler! Change the preprocessor conditions such that MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED is no longer defined."); for (auto ptr = tail; ptr != nullptr; ptr = ptr->next) { ptr->callback(ptr->userData); } } // Thread-local static inline ThreadExitNotifier& instance() { static thread_local ThreadExitNotifier notifier; return notifier; } private: ThreadExitListener* tail; }; #endif #endif template struct static_is_lock_free_num { enum { value = 0 }; }; template<> struct static_is_lock_free_num { enum { value = ATOMIC_CHAR_LOCK_FREE }; }; template<> struct static_is_lock_free_num { enum { value = ATOMIC_SHORT_LOCK_FREE }; }; template<> struct static_is_lock_free_num { enum { value = ATOMIC_INT_LOCK_FREE }; }; template<> struct static_is_lock_free_num { enum { value = ATOMIC_LONG_LOCK_FREE }; }; template<> struct static_is_lock_free_num { enum { value = ATOMIC_LLONG_LOCK_FREE }; }; template struct static_is_lock_free : static_is_lock_free_num::type> { }; template<> struct static_is_lock_free { enum { value = ATOMIC_BOOL_LOCK_FREE }; }; template struct static_is_lock_free { enum { value = ATOMIC_POINTER_LOCK_FREE }; }; } struct ProducerToken { template explicit ProducerToken(ConcurrentQueue& queue); template explicit ProducerToken(BlockingConcurrentQueue& queue); ProducerToken(ProducerToken&& other) MOODYCAMEL_NOEXCEPT : producer(other.producer) { other.producer = nullptr; if (producer != nullptr) { producer->token = this; } } inline ProducerToken& operator=(ProducerToken&& other) MOODYCAMEL_NOEXCEPT { swap(other); return *this; } void swap(ProducerToken& other) MOODYCAMEL_NOEXCEPT { std::swap(producer, other.producer); if (producer != nullptr) { producer->token = this; } if (other.producer != nullptr) { other.producer->token = &other; } } // A token is always valid unless: // 1) Memory allocation failed during construction // 2) It was moved via the move constructor // (Note: assignment does a swap, leaving both potentially valid) // 3) The associated queue was destroyed // Note that if valid() returns true, that only indicates // that the token is valid for use with a specific queue, // but not which one; that's up to the user to track. inline bool valid() const { return producer != nullptr; } ~ProducerToken() { if (producer != nullptr) { producer->token = nullptr; producer->inactive.store(true, std::memory_order_release); } } // Disable copying and assignment ProducerToken(ProducerToken const&) MOODYCAMEL_DELETE_FUNCTION; ProducerToken& operator=(ProducerToken const&) MOODYCAMEL_DELETE_FUNCTION; private: template friend class ConcurrentQueue; friend class ConcurrentQueueTests; protected: details::ConcurrentQueueProducerTypelessBase* producer; }; struct ConsumerToken { template explicit ConsumerToken(ConcurrentQueue& q); template explicit ConsumerToken(BlockingConcurrentQueue& q); ConsumerToken(ConsumerToken&& other) MOODYCAMEL_NOEXCEPT : initialOffset(other.initialOffset), lastKnownGlobalOffset(other.lastKnownGlobalOffset), itemsConsumedFromCurrent(other.itemsConsumedFromCurrent), currentProducer(other.currentProducer), desiredProducer(other.desiredProducer) { } inline ConsumerToken& operator=(ConsumerToken&& other) MOODYCAMEL_NOEXCEPT { swap(other); return *this; } void swap(ConsumerToken& other) MOODYCAMEL_NOEXCEPT { std::swap(initialOffset, other.initialOffset); std::swap(lastKnownGlobalOffset, other.lastKnownGlobalOffset); std::swap(itemsConsumedFromCurrent, other.itemsConsumedFromCurrent); std::swap(currentProducer, other.currentProducer); std::swap(desiredProducer, other.desiredProducer); } // Disable copying and assignment ConsumerToken(ConsumerToken const&) MOODYCAMEL_DELETE_FUNCTION; ConsumerToken& operator=(ConsumerToken const&) MOODYCAMEL_DELETE_FUNCTION; private: template friend class ConcurrentQueue; friend class ConcurrentQueueTests; private: // but shared with ConcurrentQueue std::uint32_t initialOffset; std::uint32_t lastKnownGlobalOffset; std::uint32_t itemsConsumedFromCurrent; details::ConcurrentQueueProducerTypelessBase* currentProducer; details::ConcurrentQueueProducerTypelessBase* desiredProducer; }; // Need to forward-declare this swap because it's in a namespace. // See http://stackoverflow.com/questions/4492062/why-does-a-c-friend-class-need-a-forward-declaration-only-in-other-namespaces template inline void swap(typename ConcurrentQueue::ImplicitProducerKVP& a, typename ConcurrentQueue::ImplicitProducerKVP& b) MOODYCAMEL_NOEXCEPT; template class ConcurrentQueue { public: typedef ::moodycamel::ProducerToken producer_token_t; typedef ::moodycamel::ConsumerToken consumer_token_t; typedef typename Traits::index_t index_t; typedef typename Traits::size_t size_t; static const size_t BLOCK_SIZE = static_cast(Traits::BLOCK_SIZE); static const size_t EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD = static_cast(Traits::EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD); static const size_t EXPLICIT_INITIAL_INDEX_SIZE = static_cast(Traits::EXPLICIT_INITIAL_INDEX_SIZE); static const size_t IMPLICIT_INITIAL_INDEX_SIZE = static_cast(Traits::IMPLICIT_INITIAL_INDEX_SIZE); static const size_t INITIAL_IMPLICIT_PRODUCER_HASH_SIZE = static_cast(Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE); static const std::uint32_t EXPLICIT_CONSUMER_CONSUMPTION_QUOTA_BEFORE_ROTATE = static_cast(Traits::EXPLICIT_CONSUMER_CONSUMPTION_QUOTA_BEFORE_ROTATE); #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4307) // + integral constant overflow (that's what the ternary expression is for!) #pragma warning(disable: 4309) // static_cast: Truncation of constant value #endif static const size_t MAX_SUBQUEUE_SIZE = (details::const_numeric_max::value - static_cast(Traits::MAX_SUBQUEUE_SIZE) < BLOCK_SIZE) ? details::const_numeric_max::value : ((static_cast(Traits::MAX_SUBQUEUE_SIZE) + (BLOCK_SIZE - 1)) / BLOCK_SIZE * BLOCK_SIZE); #ifdef _MSC_VER #pragma warning(pop) #endif static_assert(!std::numeric_limits::is_signed && std::is_integral::value, "Traits::size_t must be an unsigned integral type"); static_assert(!std::numeric_limits::is_signed && std::is_integral::value, "Traits::index_t must be an unsigned integral type"); static_assert(sizeof(index_t) >= sizeof(size_t), "Traits::index_t must be at least as wide as Traits::size_t"); static_assert((BLOCK_SIZE > 1) && !(BLOCK_SIZE & (BLOCK_SIZE - 1)), "Traits::BLOCK_SIZE must be a power of 2 (and at least 2)"); static_assert((EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD > 1) && !(EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD & (EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD - 1)), "Traits::EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD must be a power of 2 (and greater than 1)"); static_assert((EXPLICIT_INITIAL_INDEX_SIZE > 1) && !(EXPLICIT_INITIAL_INDEX_SIZE & (EXPLICIT_INITIAL_INDEX_SIZE - 1)), "Traits::EXPLICIT_INITIAL_INDEX_SIZE must be a power of 2 (and greater than 1)"); static_assert((IMPLICIT_INITIAL_INDEX_SIZE > 1) && !(IMPLICIT_INITIAL_INDEX_SIZE & (IMPLICIT_INITIAL_INDEX_SIZE - 1)), "Traits::IMPLICIT_INITIAL_INDEX_SIZE must be a power of 2 (and greater than 1)"); static_assert((INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) || !(INITIAL_IMPLICIT_PRODUCER_HASH_SIZE & (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE - 1)), "Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE must be a power of 2"); static_assert(INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0 || INITIAL_IMPLICIT_PRODUCER_HASH_SIZE >= 1, "Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE must be at least 1 (or 0 to disable implicit enqueueing)"); public: // Creates a queue with at least `capacity` element slots; note that the // actual number of elements that can be inserted without additional memory // allocation depends on the number of producers and the block size (e.g. if // the block size is equal to `capacity`, only a single block will be allocated // up-front, which means only a single producer will be able to enqueue elements // without an extra allocation -- blocks aren't shared between producers). // This method is not thread safe -- it is up to the user to ensure that the // queue is fully constructed before it starts being used by other threads (this // includes making the memory effects of construction visible, possibly with a // memory barrier). explicit ConcurrentQueue(size_t capacity = 6 * BLOCK_SIZE) : producerListTail(nullptr), producerCount(0), initialBlockPoolIndex(0), nextExplicitConsumerId(0), globalExplicitConsumerOffset(0) { implicitProducerHashResizeInProgress.clear(std::memory_order_relaxed); populate_initial_implicit_producer_hash(); populate_initial_block_list(capacity / BLOCK_SIZE + ((capacity & (BLOCK_SIZE - 1)) == 0 ? 0 : 1)); #ifdef MOODYCAMEL_QUEUE_INTERNAL_DEBUG // Track all the producers using a fully-resolved typed list for // each kind; this makes it possible to debug them starting from // the root queue object (otherwise wacky casts are needed that // don't compile in the debugger's expression evaluator). explicitProducers.store(nullptr, std::memory_order_relaxed); implicitProducers.store(nullptr, std::memory_order_relaxed); #endif } // Computes the correct amount of pre-allocated blocks for you based // on the minimum number of elements you want available at any given // time, and the maximum concurrent number of each type of producer. ConcurrentQueue(size_t minCapacity, size_t maxExplicitProducers, size_t maxImplicitProducers) : producerListTail(nullptr), producerCount(0), initialBlockPoolIndex(0), nextExplicitConsumerId(0), globalExplicitConsumerOffset(0) { implicitProducerHashResizeInProgress.clear(std::memory_order_relaxed); populate_initial_implicit_producer_hash(); size_t blocks = (((minCapacity + BLOCK_SIZE - 1) / BLOCK_SIZE) - 1) * (maxExplicitProducers + 1) + 2 * (maxExplicitProducers + maxImplicitProducers); populate_initial_block_list(blocks); #ifdef MOODYCAMEL_QUEUE_INTERNAL_DEBUG explicitProducers.store(nullptr, std::memory_order_relaxed); implicitProducers.store(nullptr, std::memory_order_relaxed); #endif } // Note: The queue should not be accessed concurrently while it's // being deleted. It's up to the user to synchronize this. // This method is not thread safe. ~ConcurrentQueue() { // Destroy producers auto ptr = producerListTail.load(std::memory_order_relaxed); while (ptr != nullptr) { auto next = ptr->next_prod(); if (ptr->token != nullptr) { ptr->token->producer = nullptr; } destroy(ptr); ptr = next; } // Destroy implicit producer hash tables if (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE != 0) { auto hash = implicitProducerHash.load(std::memory_order_relaxed); while (hash != nullptr) { auto prev = hash->prev; if (prev != nullptr) { // The last hash is part of this object and was not allocated dynamically for (size_t i = 0; i != hash->capacity; ++i) { hash->entries[i].~ImplicitProducerKVP(); } hash->~ImplicitProducerHash(); (Traits::free)(hash); } hash = prev; } } // Destroy global free list auto block = freeList.head_unsafe(); while (block != nullptr) { auto next = block->freeListNext.load(std::memory_order_relaxed); if (block->dynamicallyAllocated) { destroy(block); } block = next; } // Destroy initial free list destroy_array(initialBlockPool, initialBlockPoolSize); } // Disable copying and copy assignment ConcurrentQueue(ConcurrentQueue const&) MOODYCAMEL_DELETE_FUNCTION; ConcurrentQueue& operator=(ConcurrentQueue const&) MOODYCAMEL_DELETE_FUNCTION; // Moving is supported, but note that it is *not* a thread-safe operation. // Nobody can use the queue while it's being moved, and the memory effects // of that move must be propagated to other threads before they can use it. // Note: When a queue is moved, its tokens are still valid but can only be // used with the destination queue (i.e. semantically they are moved along // with the queue itself). ConcurrentQueue(ConcurrentQueue&& other) MOODYCAMEL_NOEXCEPT : producerListTail(other.producerListTail.load(std::memory_order_relaxed)), producerCount(other.producerCount.load(std::memory_order_relaxed)), initialBlockPoolIndex(other.initialBlockPoolIndex.load(std::memory_order_relaxed)), initialBlockPool(other.initialBlockPool), initialBlockPoolSize(other.initialBlockPoolSize), freeList(std::move(other.freeList)), nextExplicitConsumerId(other.nextExplicitConsumerId.load(std::memory_order_relaxed)), globalExplicitConsumerOffset(other.globalExplicitConsumerOffset.load(std::memory_order_relaxed)) { // Move the other one into this, and leave the other one as an empty queue implicitProducerHashResizeInProgress.clear(std::memory_order_relaxed); populate_initial_implicit_producer_hash(); swap_implicit_producer_hashes(other); other.producerListTail.store(nullptr, std::memory_order_relaxed); other.producerCount.store(0, std::memory_order_relaxed); other.nextExplicitConsumerId.store(0, std::memory_order_relaxed); other.globalExplicitConsumerOffset.store(0, std::memory_order_relaxed); #ifdef MOODYCAMEL_QUEUE_INTERNAL_DEBUG explicitProducers.store(other.explicitProducers.load(std::memory_order_relaxed), std::memory_order_relaxed); other.explicitProducers.store(nullptr, std::memory_order_relaxed); implicitProducers.store(other.implicitProducers.load(std::memory_order_relaxed), std::memory_order_relaxed); other.implicitProducers.store(nullptr, std::memory_order_relaxed); #endif other.initialBlockPoolIndex.store(0, std::memory_order_relaxed); other.initialBlockPoolSize = 0; other.initialBlockPool = nullptr; reown_producers(); } inline ConcurrentQueue& operator=(ConcurrentQueue&& other) MOODYCAMEL_NOEXCEPT { return swap_internal(other); } // Swaps this queue's state with the other's. Not thread-safe. // Swapping two queues does not invalidate their tokens, however // the tokens that were created for one queue must be used with // only the swapped queue (i.e. the tokens are tied to the // queue's movable state, not the object itself). inline void swap(ConcurrentQueue& other) MOODYCAMEL_NOEXCEPT { swap_internal(other); } private: ConcurrentQueue& swap_internal(ConcurrentQueue& other) { if (this == &other) { return *this; } details::swap_relaxed(producerListTail, other.producerListTail); details::swap_relaxed(producerCount, other.producerCount); details::swap_relaxed(initialBlockPoolIndex, other.initialBlockPoolIndex); std::swap(initialBlockPool, other.initialBlockPool); std::swap(initialBlockPoolSize, other.initialBlockPoolSize); freeList.swap(other.freeList); details::swap_relaxed(nextExplicitConsumerId, other.nextExplicitConsumerId); details::swap_relaxed(globalExplicitConsumerOffset, other.globalExplicitConsumerOffset); swap_implicit_producer_hashes(other); reown_producers(); other.reown_producers(); #ifdef MOODYCAMEL_QUEUE_INTERNAL_DEBUG details::swap_relaxed(explicitProducers, other.explicitProducers); details::swap_relaxed(implicitProducers, other.implicitProducers); #endif return *this; } public: // Enqueues a single item (by copying it). // Allocates memory if required. Only fails if memory allocation fails (or implicit // production is disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE is 0, // or Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed). // Thread-safe. inline bool enqueue(T const& item) { if (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) return false; return inner_enqueue(item); } // Enqueues a single item (by moving it, if possible). // Allocates memory if required. Only fails if memory allocation fails (or implicit // production is disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE is 0, // or Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed). // Thread-safe. inline bool enqueue(T&& item) { if (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) return false; return inner_enqueue(std::move(item)); } // Enqueues a single item (by copying it) using an explicit producer token. // Allocates memory if required. Only fails if memory allocation fails (or // Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed). // Thread-safe. inline bool enqueue(producer_token_t const& token, T const& item) { return inner_enqueue(token, item); } // Enqueues a single item (by moving it, if possible) using an explicit producer token. // Allocates memory if required. Only fails if memory allocation fails (or // Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed). // Thread-safe. inline bool enqueue(producer_token_t const& token, T&& item) { return inner_enqueue(token, std::move(item)); } // Enqueues several items. // Allocates memory if required. Only fails if memory allocation fails (or // implicit production is disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE // is 0, or Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed). // Note: Use std::make_move_iterator if the elements should be moved instead of copied. // Thread-safe. template bool enqueue_bulk(It itemFirst, size_t count) { if (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) return false; return inner_enqueue_bulk(itemFirst, count); } // Enqueues several items using an explicit producer token. // Allocates memory if required. Only fails if memory allocation fails // (or Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed). // Note: Use std::make_move_iterator if the elements should be moved // instead of copied. // Thread-safe. template bool enqueue_bulk(producer_token_t const& token, It itemFirst, size_t count) { return inner_enqueue_bulk(token, itemFirst, count); } // Enqueues a single item (by copying it). // Does not allocate memory. Fails if not enough room to enqueue (or implicit // production is disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE // is 0). // Thread-safe. inline bool try_enqueue(T const& item) { if (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) return false; return inner_enqueue(item); } // Enqueues a single item (by moving it, if possible). // Does not allocate memory (except for one-time implicit producer). // Fails if not enough room to enqueue (or implicit production is // disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE is 0). // Thread-safe. inline bool try_enqueue(T&& item) { if (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) return false; return inner_enqueue(std::move(item)); } // Enqueues a single item (by copying it) using an explicit producer token. // Does not allocate memory. Fails if not enough room to enqueue. // Thread-safe. inline bool try_enqueue(producer_token_t const& token, T const& item) { return inner_enqueue(token, item); } // Enqueues a single item (by moving it, if possible) using an explicit producer token. // Does not allocate memory. Fails if not enough room to enqueue. // Thread-safe. inline bool try_enqueue(producer_token_t const& token, T&& item) { return inner_enqueue(token, std::move(item)); } // Enqueues several items. // Does not allocate memory (except for one-time implicit producer). // Fails if not enough room to enqueue (or implicit production is // disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE is 0). // Note: Use std::make_move_iterator if the elements should be moved // instead of copied. // Thread-safe. template bool try_enqueue_bulk(It itemFirst, size_t count) { if (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) return false; return inner_enqueue_bulk(itemFirst, count); } // Enqueues several items using an explicit producer token. // Does not allocate memory. Fails if not enough room to enqueue. // Note: Use std::make_move_iterator if the elements should be moved // instead of copied. // Thread-safe. template bool try_enqueue_bulk(producer_token_t const& token, It itemFirst, size_t count) { return inner_enqueue_bulk(token, itemFirst, count); } // Attempts to dequeue from the queue. // Returns false if all producer streams appeared empty at the time they // were checked (so, the queue is likely but not guaranteed to be empty). // Never allocates. Thread-safe. template bool try_dequeue(U& item) { // Instead of simply trying each producer in turn (which could cause needless contention on the first // producer), we score them heuristically. size_t nonEmptyCount = 0; ProducerBase* best = nullptr; size_t bestSize = 0; for (auto ptr = producerListTail.load(std::memory_order_acquire); nonEmptyCount < 3 && ptr != nullptr; ptr = ptr->next_prod()) { auto size = ptr->size_approx(); if (size > 0) { if (size > bestSize) { bestSize = size; best = ptr; } ++nonEmptyCount; } } // If there was at least one non-empty queue but it appears empty at the time // we try to dequeue from it, we need to make sure every queue's been tried if (nonEmptyCount > 0) { if ((details::likely)(best->dequeue(item))) { return true; } for (auto ptr = producerListTail.load(std::memory_order_acquire); ptr != nullptr; ptr = ptr->next_prod()) { if (ptr != best && ptr->dequeue(item)) { return true; } } } return false; } // Attempts to dequeue from the queue. // Returns false if all producer streams appeared empty at the time they // were checked (so, the queue is likely but not guaranteed to be empty). // This differs from the try_dequeue(item) method in that this one does // not attempt to reduce contention by interleaving the order that producer // streams are dequeued from. So, using this method can reduce overall throughput // under contention, but will give more predictable results in single-threaded // consumer scenarios. This is mostly only useful for internal unit tests. // Never allocates. Thread-safe. template bool try_dequeue_non_interleaved(U& item) { for (auto ptr = producerListTail.load(std::memory_order_acquire); ptr != nullptr; ptr = ptr->next_prod()) { if (ptr->dequeue(item)) { return true; } } return false; } // Attempts to dequeue from the queue using an explicit consumer token. // Returns false if all producer streams appeared empty at the time they // were checked (so, the queue is likely but not guaranteed to be empty). // Never allocates. Thread-safe. template bool try_dequeue(consumer_token_t& token, U& item) { // The idea is roughly as follows: // Every 256 items from one producer, make everyone rotate (increase the global offset) -> this means the highest efficiency consumer dictates the rotation speed of everyone else, more or less // If you see that the global offset has changed, you must reset your consumption counter and move to your designated place // If there's no items where you're supposed to be, keep moving until you find a producer with some items // If the global offset has not changed but you've run out of items to consume, move over from your current position until you find an producer with something in it if (token.desiredProducer == nullptr || token.lastKnownGlobalOffset != globalExplicitConsumerOffset.load(std::memory_order_relaxed)) { if (!update_current_producer_after_rotation(token)) { return false; } } // If there was at least one non-empty queue but it appears empty at the time // we try to dequeue from it, we need to make sure every queue's been tried if (static_cast(token.currentProducer)->dequeue(item)) { if (++token.itemsConsumedFromCurrent == EXPLICIT_CONSUMER_CONSUMPTION_QUOTA_BEFORE_ROTATE) { globalExplicitConsumerOffset.fetch_add(1, std::memory_order_relaxed); } return true; } auto tail = producerListTail.load(std::memory_order_acquire); auto ptr = static_cast(token.currentProducer)->next_prod(); if (ptr == nullptr) { ptr = tail; } while (ptr != static_cast(token.currentProducer)) { if (ptr->dequeue(item)) { token.currentProducer = ptr; token.itemsConsumedFromCurrent = 1; return true; } ptr = ptr->next_prod(); if (ptr == nullptr) { ptr = tail; } } return false; } // Attempts to dequeue several elements from the queue. // Returns the number of items actually dequeued. // Returns 0 if all producer streams appeared empty at the time they // were checked (so, the queue is likely but not guaranteed to be empty). // Never allocates. Thread-safe. template size_t try_dequeue_bulk(It itemFirst, size_t max) { size_t count = 0; for (auto ptr = producerListTail.load(std::memory_order_acquire); ptr != nullptr; ptr = ptr->next_prod()) { count += ptr->dequeue_bulk(itemFirst, max - count); if (count == max) { break; } } return count; } // Attempts to dequeue several elements from the queue using an explicit consumer token. // Returns the number of items actually dequeued. // Returns 0 if all producer streams appeared empty at the time they // were checked (so, the queue is likely but not guaranteed to be empty). // Never allocates. Thread-safe. template size_t try_dequeue_bulk(consumer_token_t& token, It itemFirst, size_t max) { if (token.desiredProducer == nullptr || token.lastKnownGlobalOffset != globalExplicitConsumerOffset.load(std::memory_order_relaxed)) { if (!update_current_producer_after_rotation(token)) { return 0; } } size_t count = static_cast(token.currentProducer)->dequeue_bulk(itemFirst, max); if (count == max) { if ((token.itemsConsumedFromCurrent += static_cast(max)) >= EXPLICIT_CONSUMER_CONSUMPTION_QUOTA_BEFORE_ROTATE) { globalExplicitConsumerOffset.fetch_add(1, std::memory_order_relaxed); } return max; } token.itemsConsumedFromCurrent += static_cast(count); max -= count; auto tail = producerListTail.load(std::memory_order_acquire); auto ptr = static_cast(token.currentProducer)->next_prod(); if (ptr == nullptr) { ptr = tail; } while (ptr != static_cast(token.currentProducer)) { auto dequeued = ptr->dequeue_bulk(itemFirst, max); count += dequeued; if (dequeued != 0) { token.currentProducer = ptr; token.itemsConsumedFromCurrent = static_cast(dequeued); } if (dequeued == max) { break; } max -= dequeued; ptr = ptr->next_prod(); if (ptr == nullptr) { ptr = tail; } } return count; } // Attempts to dequeue from a specific producer's inner queue. // If you happen to know which producer you want to dequeue from, this // is significantly faster than using the general-case try_dequeue methods. // Returns false if the producer's queue appeared empty at the time it // was checked (so, the queue is likely but not guaranteed to be empty). // Never allocates. Thread-safe. template inline bool try_dequeue_from_producer(producer_token_t const& producer, U& item) { return static_cast(producer.producer)->dequeue(item); } // Attempts to dequeue several elements from a specific producer's inner queue. // Returns the number of items actually dequeued. // If you happen to know which producer you want to dequeue from, this // is significantly faster than using the general-case try_dequeue methods. // Returns 0 if the producer's queue appeared empty at the time it // was checked (so, the queue is likely but not guaranteed to be empty). // Never allocates. Thread-safe. template inline size_t try_dequeue_bulk_from_producer(producer_token_t const& producer, It itemFirst, size_t max) { return static_cast(producer.producer)->dequeue_bulk(itemFirst, max); } // Returns an estimate of the total number of elements currently in the queue. This // estimate is only accurate if the queue has completely stabilized before it is called // (i.e. all enqueue and dequeue operations have completed and their memory effects are // visible on the calling thread, and no further operations start while this method is // being called). // Thread-safe. size_t size_approx() const { size_t size = 0; for (auto ptr = producerListTail.load(std::memory_order_acquire); ptr != nullptr; ptr = ptr->next_prod()) { size += ptr->size_approx(); } return size; } // Returns true if the underlying atomic variables used by // the queue are lock-free (they should be on most platforms). // Thread-safe. static bool is_lock_free() { return details::static_is_lock_free::value == 2 && details::static_is_lock_free::value == 2 && details::static_is_lock_free::value == 2 && details::static_is_lock_free::value == 2 && details::static_is_lock_free::value == 2 && details::static_is_lock_free::thread_id_numeric_size_t>::value == 2; } private: friend struct ProducerToken; friend struct ConsumerToken; struct ExplicitProducer; friend struct ExplicitProducer; struct ImplicitProducer; friend struct ImplicitProducer; friend class ConcurrentQueueTests; enum AllocationMode { CanAlloc, CannotAlloc }; /////////////////////////////// // Queue methods /////////////////////////////// template inline bool inner_enqueue(producer_token_t const& token, U&& element) { return static_cast(token.producer)->ConcurrentQueue::ExplicitProducer::template enqueue(std::forward(element)); } template inline bool inner_enqueue(U&& element) { auto producer = get_or_add_implicit_producer(); return producer == nullptr ? false : producer->ConcurrentQueue::ImplicitProducer::template enqueue(std::forward(element)); } template inline bool inner_enqueue_bulk(producer_token_t const& token, It itemFirst, size_t count) { return static_cast(token.producer)->ConcurrentQueue::ExplicitProducer::template enqueue_bulk(itemFirst, count); } template inline bool inner_enqueue_bulk(It itemFirst, size_t count) { auto producer = get_or_add_implicit_producer(); return producer == nullptr ? false : producer->ConcurrentQueue::ImplicitProducer::template enqueue_bulk(itemFirst, count); } inline bool update_current_producer_after_rotation(consumer_token_t& token) { // Ah, there's been a rotation, figure out where we should be! auto tail = producerListTail.load(std::memory_order_acquire); if (token.desiredProducer == nullptr && tail == nullptr) { return false; } auto prodCount = producerCount.load(std::memory_order_relaxed); auto globalOffset = globalExplicitConsumerOffset.load(std::memory_order_relaxed); if ((details::unlikely)(token.desiredProducer == nullptr)) { // Aha, first time we're dequeueing anything. // Figure out our local position // Note: offset is from start, not end, but we're traversing from end -- subtract from count first std::uint32_t offset = prodCount - 1 - (token.initialOffset % prodCount); token.desiredProducer = tail; for (std::uint32_t i = 0; i != offset; ++i) { token.desiredProducer = static_cast(token.desiredProducer)->next_prod(); if (token.desiredProducer == nullptr) { token.desiredProducer = tail; } } } std::uint32_t delta = globalOffset - token.lastKnownGlobalOffset; if (delta >= prodCount) { delta = delta % prodCount; } for (std::uint32_t i = 0; i != delta; ++i) { token.desiredProducer = static_cast(token.desiredProducer)->next_prod(); if (token.desiredProducer == nullptr) { token.desiredProducer = tail; } } token.lastKnownGlobalOffset = globalOffset; token.currentProducer = token.desiredProducer; token.itemsConsumedFromCurrent = 0; return true; } /////////////////////////// // Free list /////////////////////////// template struct FreeListNode { FreeListNode() : freeListRefs(0), freeListNext(nullptr) { } std::atomic freeListRefs; std::atomic freeListNext; }; // A simple CAS-based lock-free free list. Not the fastest thing in the world under heavy contention, but // simple and correct (assuming nodes are never freed until after the free list is destroyed), and fairly // speedy under low contention. template // N must inherit FreeListNode or have the same fields (and initialization of them) struct FreeList { FreeList() : freeListHead(nullptr) { } FreeList(FreeList&& other) : freeListHead(other.freeListHead.load(std::memory_order_relaxed)) { other.freeListHead.store(nullptr, std::memory_order_relaxed); } void swap(FreeList& other) { details::swap_relaxed(freeListHead, other.freeListHead); } FreeList(FreeList const&) MOODYCAMEL_DELETE_FUNCTION; FreeList& operator=(FreeList const&) MOODYCAMEL_DELETE_FUNCTION; inline void add(N* node) { #if MCDBGQ_NOLOCKFREE_FREELIST debug::DebugLock lock(mutex); #endif // We know that the should-be-on-freelist bit is 0 at this point, so it's safe to // set it using a fetch_add if (node->freeListRefs.fetch_add(SHOULD_BE_ON_FREELIST, std::memory_order_acq_rel) == 0) { // Oh look! We were the last ones referencing this node, and we know // we want to add it to the free list, so let's do it! add_knowing_refcount_is_zero(node); } } inline N* try_get() { #if MCDBGQ_NOLOCKFREE_FREELIST debug::DebugLock lock(mutex); #endif auto head = freeListHead.load(std::memory_order_acquire); while (head != nullptr) { auto prevHead = head; auto refs = head->freeListRefs.load(std::memory_order_relaxed); if ((refs & REFS_MASK) == 0 || !head->freeListRefs.compare_exchange_strong(refs, refs + 1, std::memory_order_acquire, std::memory_order_relaxed)) { head = freeListHead.load(std::memory_order_acquire); continue; } // Good, reference count has been incremented (it wasn't at zero), which means we can read the // next and not worry about it changing between now and the time we do the CAS auto next = head->freeListNext.load(std::memory_order_relaxed); if (freeListHead.compare_exchange_strong(head, next, std::memory_order_acquire, std::memory_order_relaxed)) { // Yay, got the node. This means it was on the list, which means shouldBeOnFreeList must be false no // matter the refcount (because nobody else knows it's been taken off yet, it can't have been put back on). assert((head->freeListRefs.load(std::memory_order_relaxed) & SHOULD_BE_ON_FREELIST) == 0); // Decrease refcount twice, once for our ref, and once for the list's ref head->freeListRefs.fetch_sub(2, std::memory_order_release); return head; } // OK, the head must have changed on us, but we still need to decrease the refcount we increased. // Note that we don't need to release any memory effects, but we do need to ensure that the reference // count decrement happens-after the CAS on the head. refs = prevHead->freeListRefs.fetch_sub(1, std::memory_order_acq_rel); if (refs == SHOULD_BE_ON_FREELIST + 1) { add_knowing_refcount_is_zero(prevHead); } } return nullptr; } // Useful for traversing the list when there's no contention (e.g. to destroy remaining nodes) N* head_unsafe() const { return freeListHead.load(std::memory_order_relaxed); } private: inline void add_knowing_refcount_is_zero(N* node) { // Since the refcount is zero, and nobody can increase it once it's zero (except us, and we run // only one copy of this method per node at a time, i.e. the single thread case), then we know // we can safely change the next pointer of the node; however, once the refcount is back above // zero, then other threads could increase it (happens under heavy contention, when the refcount // goes to zero in between a load and a refcount increment of a node in try_get, then back up to // something non-zero, then the refcount increment is done by the other thread) -- so, if the CAS // to add the node to the actual list fails, decrease the refcount and leave the add operation to // the next thread who puts the refcount back at zero (which could be us, hence the loop). auto head = freeListHead.load(std::memory_order_relaxed); while (true) { node->freeListNext.store(head, std::memory_order_relaxed); node->freeListRefs.store(1, std::memory_order_release); if (!freeListHead.compare_exchange_strong(head, node, std::memory_order_release, std::memory_order_relaxed)) { // Hmm, the add failed, but we can only try again when the refcount goes back to zero if (node->freeListRefs.fetch_add(SHOULD_BE_ON_FREELIST - 1, std::memory_order_release) == 1) { continue; } } return; } } private: // Implemented like a stack, but where node order doesn't matter (nodes are inserted out of order under contention) std::atomic freeListHead; static const std::uint32_t REFS_MASK = 0x7FFFFFFF; static const std::uint32_t SHOULD_BE_ON_FREELIST = 0x80000000; #if MCDBGQ_NOLOCKFREE_FREELIST debug::DebugMutex mutex; #endif }; /////////////////////////// // Block /////////////////////////// enum InnerQueueContext { implicit_context = 0, explicit_context = 1 }; struct Block { Block() : next(nullptr), elementsCompletelyDequeued(0), freeListRefs(0), freeListNext(nullptr), shouldBeOnFreeList(false), dynamicallyAllocated(true) { #if MCDBGQ_TRACKMEM owner = nullptr; #endif } template inline bool is_empty() const { if (context == explicit_context && BLOCK_SIZE <= EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD) { // Check flags for (size_t i = 0; i < BLOCK_SIZE; ++i) { if (!emptyFlags[i].load(std::memory_order_relaxed)) { return false; } } // Aha, empty; make sure we have all other memory effects that happened before the empty flags were set std::atomic_thread_fence(std::memory_order_acquire); return true; } else { // Check counter if (elementsCompletelyDequeued.load(std::memory_order_relaxed) == BLOCK_SIZE) { std::atomic_thread_fence(std::memory_order_acquire); return true; } assert(elementsCompletelyDequeued.load(std::memory_order_relaxed) <= BLOCK_SIZE); return false; } } // Returns true if the block is now empty (does not apply in explicit context) template inline bool set_empty(index_t i) { if (context == explicit_context && BLOCK_SIZE <= EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD) { // Set flag assert(!emptyFlags[BLOCK_SIZE - 1 - static_cast(i & static_cast(BLOCK_SIZE - 1))].load(std::memory_order_relaxed)); emptyFlags[BLOCK_SIZE - 1 - static_cast(i & static_cast(BLOCK_SIZE - 1))].store(true, std::memory_order_release); return false; } else { // Increment counter auto prevVal = elementsCompletelyDequeued.fetch_add(1, std::memory_order_release); assert(prevVal < BLOCK_SIZE); return prevVal == BLOCK_SIZE - 1; } } // Sets multiple contiguous item statuses to 'empty' (assumes no wrapping and count > 0). // Returns true if the block is now empty (does not apply in explicit context). template inline bool set_many_empty(index_t i, size_t count) { if (context == explicit_context && BLOCK_SIZE <= EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD) { // Set flags std::atomic_thread_fence(std::memory_order_release); i = BLOCK_SIZE - 1 - static_cast(i & static_cast(BLOCK_SIZE - 1)) - count + 1; for (size_t j = 0; j != count; ++j) { assert(!emptyFlags[i + j].load(std::memory_order_relaxed)); emptyFlags[i + j].store(true, std::memory_order_relaxed); } return false; } else { // Increment counter auto prevVal = elementsCompletelyDequeued.fetch_add(count, std::memory_order_release); assert(prevVal + count <= BLOCK_SIZE); return prevVal + count == BLOCK_SIZE; } } template inline void set_all_empty() { if (context == explicit_context && BLOCK_SIZE <= EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD) { // Set all flags for (size_t i = 0; i != BLOCK_SIZE; ++i) { emptyFlags[i].store(true, std::memory_order_relaxed); } } else { // Reset counter elementsCompletelyDequeued.store(BLOCK_SIZE, std::memory_order_relaxed); } } template inline void reset_empty() { if (context == explicit_context && BLOCK_SIZE <= EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD) { // Reset flags for (size_t i = 0; i != BLOCK_SIZE; ++i) { emptyFlags[i].store(false, std::memory_order_relaxed); } } else { // Reset counter elementsCompletelyDequeued.store(0, std::memory_order_relaxed); } } inline T* operator[](index_t idx) MOODYCAMEL_NOEXCEPT { return static_cast(static_cast(elements)) + static_cast(idx & static_cast(BLOCK_SIZE - 1)); } inline T const* operator[](index_t idx) const MOODYCAMEL_NOEXCEPT { return static_cast(static_cast(elements)) + static_cast(idx & static_cast(BLOCK_SIZE - 1)); } private: // IMPORTANT: This must be the first member in Block, so that if T depends on the alignment of // addresses returned by malloc, that alignment will be preserved. Apparently clang actually // generates code that uses this assumption for AVX instructions in some cases. Ideally, we // should also align Block to the alignment of T in case it's higher than malloc's 16-byte // alignment, but this is hard to do in a cross-platform way. Assert for this case: static_assert(std::alignment_of::value <= std::alignment_of::value, "The queue does not support super-aligned types at this time"); // Additionally, we need the alignment of Block itself to be a multiple of max_align_t since // otherwise the appropriate padding will not be added at the end of Block in order to make // arrays of Blocks all be properly aligned (not just the first one). We use a union to force // this. union { char elements[sizeof(T) * BLOCK_SIZE]; details::max_align_t dummy; }; public: Block* next; std::atomic elementsCompletelyDequeued; std::atomic emptyFlags[BLOCK_SIZE <= EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD ? BLOCK_SIZE : 1]; public: std::atomic freeListRefs; std::atomic freeListNext; std::atomic shouldBeOnFreeList; bool dynamicallyAllocated; // Perhaps a better name for this would be 'isNotPartOfInitialBlockPool' #if MCDBGQ_TRACKMEM void* owner; #endif }; static_assert(std::alignment_of::value >= std::alignment_of::value, "Internal error: Blocks must be at least as aligned as the type they are wrapping"); #if MCDBGQ_TRACKMEM public: struct MemStats; private: #endif /////////////////////////// // Producer base /////////////////////////// struct ProducerBase : public details::ConcurrentQueueProducerTypelessBase { ProducerBase(ConcurrentQueue* parent_, bool isExplicit_) : tailIndex(0), headIndex(0), dequeueOptimisticCount(0), dequeueOvercommit(0), tailBlock(nullptr), isExplicit(isExplicit_), parent(parent_) { } virtual ~ProducerBase() { }; template inline bool dequeue(U& element) { if (isExplicit) { return static_cast(this)->dequeue(element); } else { return static_cast(this)->dequeue(element); } } template inline size_t dequeue_bulk(It& itemFirst, size_t max) { if (isExplicit) { return static_cast(this)->dequeue_bulk(itemFirst, max); } else { return static_cast(this)->dequeue_bulk(itemFirst, max); } } inline ProducerBase* next_prod() const { return static_cast(next); } inline size_t size_approx() const { auto tail = tailIndex.load(std::memory_order_relaxed); auto head = headIndex.load(std::memory_order_relaxed); return details::circular_less_than(head, tail) ? static_cast(tail - head) : 0; } inline index_t getTail() const { return tailIndex.load(std::memory_order_relaxed); } protected: std::atomic tailIndex; // Where to enqueue to next std::atomic headIndex; // Where to dequeue from next std::atomic dequeueOptimisticCount; std::atomic dequeueOvercommit; Block* tailBlock; public: bool isExplicit; ConcurrentQueue* parent; protected: #if MCDBGQ_TRACKMEM friend struct MemStats; #endif }; /////////////////////////// // Explicit queue /////////////////////////// struct ExplicitProducer : public ProducerBase { explicit ExplicitProducer(ConcurrentQueue* parent) : ProducerBase(parent, true), blockIndex(nullptr), pr_blockIndexSlotsUsed(0), pr_blockIndexSize(EXPLICIT_INITIAL_INDEX_SIZE >> 1), pr_blockIndexFront(0), pr_blockIndexEntries(nullptr), pr_blockIndexRaw(nullptr) { size_t poolBasedIndexSize = details::ceil_to_pow_2(parent->initialBlockPoolSize) >> 1; if (poolBasedIndexSize > pr_blockIndexSize) { pr_blockIndexSize = poolBasedIndexSize; } new_block_index(0); // This creates an index with double the number of current entries, i.e. EXPLICIT_INITIAL_INDEX_SIZE } ~ExplicitProducer() { // Destruct any elements not yet dequeued. // Since we're in the destructor, we can assume all elements // are either completely dequeued or completely not (no halfways). if (this->tailBlock != nullptr) { // Note this means there must be a block index too // First find the block that's partially dequeued, if any Block* halfDequeuedBlock = nullptr; if ((this->headIndex.load(std::memory_order_relaxed) & static_cast(BLOCK_SIZE - 1)) != 0) { // The head's not on a block boundary, meaning a block somewhere is partially dequeued // (or the head block is the tail block and was fully dequeued, but the head/tail are still not on a boundary) size_t i = (pr_blockIndexFront - pr_blockIndexSlotsUsed) & (pr_blockIndexSize - 1); while (details::circular_less_than(pr_blockIndexEntries[i].base + BLOCK_SIZE, this->headIndex.load(std::memory_order_relaxed))) { i = (i + 1) & (pr_blockIndexSize - 1); } assert(details::circular_less_than(pr_blockIndexEntries[i].base, this->headIndex.load(std::memory_order_relaxed))); halfDequeuedBlock = pr_blockIndexEntries[i].block; } // Start at the head block (note the first line in the loop gives us the head from the tail on the first iteration) auto block = this->tailBlock; do { block = block->next; if (block->ConcurrentQueue::Block::template is_empty()) { continue; } size_t i = 0; // Offset into block if (block == halfDequeuedBlock) { i = static_cast(this->headIndex.load(std::memory_order_relaxed) & static_cast(BLOCK_SIZE - 1)); } // Walk through all the items in the block; if this is the tail block, we need to stop when we reach the tail index auto lastValidIndex = (this->tailIndex.load(std::memory_order_relaxed) & static_cast(BLOCK_SIZE - 1)) == 0 ? BLOCK_SIZE : static_cast(this->tailIndex.load(std::memory_order_relaxed) & static_cast(BLOCK_SIZE - 1)); while (i != BLOCK_SIZE && (block != this->tailBlock || i != lastValidIndex)) { (*block)[i++]->~T(); } } while (block != this->tailBlock); } // Destroy all blocks that we own if (this->tailBlock != nullptr) { auto block = this->tailBlock; do { auto nextBlock = block->next; if (block->dynamicallyAllocated) { destroy(block); } else { this->parent->add_block_to_free_list(block); } block = nextBlock; } while (block != this->tailBlock); } // Destroy the block indices auto header = static_cast(pr_blockIndexRaw); while (header != nullptr) { auto prev = static_cast(header->prev); header->~BlockIndexHeader(); (Traits::free)(header); header = prev; } } template inline bool enqueue(U&& element) { index_t currentTailIndex = this->tailIndex.load(std::memory_order_relaxed); index_t newTailIndex = 1 + currentTailIndex; if ((currentTailIndex & static_cast(BLOCK_SIZE - 1)) == 0) { // We reached the end of a block, start a new one auto startBlock = this->tailBlock; auto originalBlockIndexSlotsUsed = pr_blockIndexSlotsUsed; if (this->tailBlock != nullptr && this->tailBlock->next->ConcurrentQueue::Block::template is_empty()) { // We can re-use the block ahead of us, it's empty! this->tailBlock = this->tailBlock->next; this->tailBlock->ConcurrentQueue::Block::template reset_empty(); // We'll put the block on the block index (guaranteed to be room since we're conceptually removing the // last block from it first -- except instead of removing then adding, we can just overwrite). // Note that there must be a valid block index here, since even if allocation failed in the ctor, // it would have been re-attempted when adding the first block to the queue; since there is such // a block, a block index must have been successfully allocated. } else { // Whatever head value we see here is >= the last value we saw here (relatively), // and <= its current value. Since we have the most recent tail, the head must be // <= to it. auto head = this->headIndex.load(std::memory_order_relaxed); assert(!details::circular_less_than(currentTailIndex, head)); if (!details::circular_less_than(head, currentTailIndex + BLOCK_SIZE) || (MAX_SUBQUEUE_SIZE != details::const_numeric_max::value && (MAX_SUBQUEUE_SIZE == 0 || MAX_SUBQUEUE_SIZE - BLOCK_SIZE < currentTailIndex - head))) { // We can't enqueue in another block because there's not enough leeway -- the // tail could surpass the head by the time the block fills up! (Or we'll exceed // the size limit, if the second part of the condition was true.) return false; } // We're going to need a new block; check that the block index has room if (pr_blockIndexRaw == nullptr || pr_blockIndexSlotsUsed == pr_blockIndexSize) { // Hmm, the circular block index is already full -- we'll need // to allocate a new index. Note pr_blockIndexRaw can only be nullptr if // the initial allocation failed in the constructor. if (allocMode == CannotAlloc || !new_block_index(pr_blockIndexSlotsUsed)) { return false; } } // Insert a new block in the circular linked list auto newBlock = this->parent->ConcurrentQueue::template requisition_block(); if (newBlock == nullptr) { return false; } #if MCDBGQ_TRACKMEM newBlock->owner = this; #endif newBlock->ConcurrentQueue::Block::template reset_empty(); if (this->tailBlock == nullptr) { newBlock->next = newBlock; } else { newBlock->next = this->tailBlock->next; this->tailBlock->next = newBlock; } this->tailBlock = newBlock; ++pr_blockIndexSlotsUsed; } if (!MOODYCAMEL_NOEXCEPT_CTOR(T, U, new (nullptr) T(std::forward(element)))) { // The constructor may throw. We want the element not to appear in the queue in // that case (without corrupting the queue): MOODYCAMEL_TRY { new ((*this->tailBlock)[currentTailIndex]) T(std::forward(element)); } MOODYCAMEL_CATCH (...) { // Revert change to the current block, but leave the new block available // for next time pr_blockIndexSlotsUsed = originalBlockIndexSlotsUsed; this->tailBlock = startBlock == nullptr ? this->tailBlock : startBlock; MOODYCAMEL_RETHROW; } } else { (void)startBlock; (void)originalBlockIndexSlotsUsed; } // Add block to block index auto& entry = blockIndex.load(std::memory_order_relaxed)->entries[pr_blockIndexFront]; entry.base = currentTailIndex; entry.block = this->tailBlock; blockIndex.load(std::memory_order_relaxed)->front.store(pr_blockIndexFront, std::memory_order_release); pr_blockIndexFront = (pr_blockIndexFront + 1) & (pr_blockIndexSize - 1); if (!MOODYCAMEL_NOEXCEPT_CTOR(T, U, new (nullptr) T(std::forward(element)))) { this->tailIndex.store(newTailIndex, std::memory_order_release); return true; } } // Enqueue new ((*this->tailBlock)[currentTailIndex]) T(std::forward(element)); this->tailIndex.store(newTailIndex, std::memory_order_release); return true; } template bool dequeue(U& element) { auto tail = this->tailIndex.load(std::memory_order_relaxed); auto overcommit = this->dequeueOvercommit.load(std::memory_order_relaxed); if (details::circular_less_than(this->dequeueOptimisticCount.load(std::memory_order_relaxed) - overcommit, tail)) { // Might be something to dequeue, let's give it a try // Note that this if is purely for performance purposes in the common case when the queue is // empty and the values are eventually consistent -- we may enter here spuriously. // Note that whatever the values of overcommit and tail are, they are not going to change (unless we // change them) and must be the same value at this point (inside the if) as when the if condition was // evaluated. // We insert an acquire fence here to synchronize-with the release upon incrementing dequeueOvercommit below. // This ensures that whatever the value we got loaded into overcommit, the load of dequeueOptisticCount in // the fetch_add below will result in a value at least as recent as that (and therefore at least as large). // Note that I believe a compiler (signal) fence here would be sufficient due to the nature of fetch_add (all // read-modify-write operations are guaranteed to work on the latest value in the modification order), but // unfortunately that can't be shown to be correct using only the C++11 standard. // See http://stackoverflow.com/questions/18223161/what-are-the-c11-memory-ordering-guarantees-in-this-corner-case std::atomic_thread_fence(std::memory_order_acquire); // Increment optimistic counter, then check if it went over the boundary auto myDequeueCount = this->dequeueOptimisticCount.fetch_add(1, std::memory_order_relaxed); // Note that since dequeueOvercommit must be <= dequeueOptimisticCount (because dequeueOvercommit is only ever // incremented after dequeueOptimisticCount -- this is enforced in the `else` block below), and since we now // have a version of dequeueOptimisticCount that is at least as recent as overcommit (due to the release upon // incrementing dequeueOvercommit and the acquire above that synchronizes with it), overcommit <= myDequeueCount. // However, we can't assert this since both dequeueOptimisticCount and dequeueOvercommit may (independently) // overflow; in such a case, though, the logic still holds since the difference between the two is maintained. // Note that we reload tail here in case it changed; it will be the same value as before or greater, since // this load is sequenced after (happens after) the earlier load above. This is supported by read-read // coherency (as defined in the standard), explained here: http://en.cppreference.com/w/cpp/atomic/memory_order tail = this->tailIndex.load(std::memory_order_acquire); if ((details::likely)(details::circular_less_than(myDequeueCount - overcommit, tail))) { // Guaranteed to be at least one element to dequeue! // Get the index. Note that since there's guaranteed to be at least one element, this // will never exceed tail. We need to do an acquire-release fence here since it's possible // that whatever condition got us to this point was for an earlier enqueued element (that // we already see the memory effects for), but that by the time we increment somebody else // has incremented it, and we need to see the memory effects for *that* element, which is // in such a case is necessarily visible on the thread that incremented it in the first // place with the more current condition (they must have acquired a tail that is at least // as recent). auto index = this->headIndex.fetch_add(1, std::memory_order_acq_rel); // Determine which block the element is in auto localBlockIndex = blockIndex.load(std::memory_order_acquire); auto localBlockIndexHead = localBlockIndex->front.load(std::memory_order_acquire); // We need to be careful here about subtracting and dividing because of index wrap-around. // When an index wraps, we need to preserve the sign of the offset when dividing it by the // block size (in order to get a correct signed block count offset in all cases): auto headBase = localBlockIndex->entries[localBlockIndexHead].base; auto blockBaseIndex = index & ~static_cast(BLOCK_SIZE - 1); auto offset = static_cast(static_cast::type>(blockBaseIndex - headBase) / BLOCK_SIZE); auto block = localBlockIndex->entries[(localBlockIndexHead + offset) & (localBlockIndex->size - 1)].block; // Dequeue auto& el = *((*block)[index]); if (!MOODYCAMEL_NOEXCEPT_ASSIGN(T, T&&, element = std::move(el))) { // Make sure the element is still fully dequeued and destroyed even if the assignment // throws struct Guard { Block* block; index_t index; ~Guard() { (*block)[index]->~T(); block->ConcurrentQueue::Block::template set_empty(index); } } guard = { block, index }; element = std::move(el); } else { element = std::move(el); el.~T(); block->ConcurrentQueue::Block::template set_empty(index); } return true; } else { // Wasn't anything to dequeue after all; make the effective dequeue count eventually consistent this->dequeueOvercommit.fetch_add(1, std::memory_order_release); // Release so that the fetch_add on dequeueOptimisticCount is guaranteed to happen before this write } } return false; } template bool enqueue_bulk(It itemFirst, size_t count) { // First, we need to make sure we have enough room to enqueue all of the elements; // this means pre-allocating blocks and putting them in the block index (but only if // all the allocations succeeded). index_t startTailIndex = this->tailIndex.load(std::memory_order_relaxed); auto startBlock = this->tailBlock; auto originalBlockIndexFront = pr_blockIndexFront; auto originalBlockIndexSlotsUsed = pr_blockIndexSlotsUsed; Block* firstAllocatedBlock = nullptr; // Figure out how many blocks we'll need to allocate, and do so size_t blockBaseDiff = ((startTailIndex + count - 1) & ~static_cast(BLOCK_SIZE - 1)) - ((startTailIndex - 1) & ~static_cast(BLOCK_SIZE - 1)); index_t currentTailIndex = (startTailIndex - 1) & ~static_cast(BLOCK_SIZE - 1); if (blockBaseDiff > 0) { // Allocate as many blocks as possible from ahead while (blockBaseDiff > 0 && this->tailBlock != nullptr && this->tailBlock->next != firstAllocatedBlock && this->tailBlock->next->ConcurrentQueue::Block::template is_empty()) { blockBaseDiff -= static_cast(BLOCK_SIZE); currentTailIndex += static_cast(BLOCK_SIZE); this->tailBlock = this->tailBlock->next; firstAllocatedBlock = firstAllocatedBlock == nullptr ? this->tailBlock : firstAllocatedBlock; auto& entry = blockIndex.load(std::memory_order_relaxed)->entries[pr_blockIndexFront]; entry.base = currentTailIndex; entry.block = this->tailBlock; pr_blockIndexFront = (pr_blockIndexFront + 1) & (pr_blockIndexSize - 1); } // Now allocate as many blocks as necessary from the block pool while (blockBaseDiff > 0) { blockBaseDiff -= static_cast(BLOCK_SIZE); currentTailIndex += static_cast(BLOCK_SIZE); auto head = this->headIndex.load(std::memory_order_relaxed); assert(!details::circular_less_than(currentTailIndex, head)); bool full = !details::circular_less_than(head, currentTailIndex + BLOCK_SIZE) || (MAX_SUBQUEUE_SIZE != details::const_numeric_max::value && (MAX_SUBQUEUE_SIZE == 0 || MAX_SUBQUEUE_SIZE - BLOCK_SIZE < currentTailIndex - head)); if (pr_blockIndexRaw == nullptr || pr_blockIndexSlotsUsed == pr_blockIndexSize || full) { if (allocMode == CannotAlloc || full || !new_block_index(originalBlockIndexSlotsUsed)) { // Failed to allocate, undo changes (but keep injected blocks) pr_blockIndexFront = originalBlockIndexFront; pr_blockIndexSlotsUsed = originalBlockIndexSlotsUsed; this->tailBlock = startBlock == nullptr ? firstAllocatedBlock : startBlock; return false; } // pr_blockIndexFront is updated inside new_block_index, so we need to // update our fallback value too (since we keep the new index even if we // later fail) originalBlockIndexFront = originalBlockIndexSlotsUsed; } // Insert a new block in the circular linked list auto newBlock = this->parent->ConcurrentQueue::template requisition_block(); if (newBlock == nullptr) { pr_blockIndexFront = originalBlockIndexFront; pr_blockIndexSlotsUsed = originalBlockIndexSlotsUsed; this->tailBlock = startBlock == nullptr ? firstAllocatedBlock : startBlock; return false; } #if MCDBGQ_TRACKMEM newBlock->owner = this; #endif newBlock->ConcurrentQueue::Block::template set_all_empty(); if (this->tailBlock == nullptr) { newBlock->next = newBlock; } else { newBlock->next = this->tailBlock->next; this->tailBlock->next = newBlock; } this->tailBlock = newBlock; firstAllocatedBlock = firstAllocatedBlock == nullptr ? this->tailBlock : firstAllocatedBlock; ++pr_blockIndexSlotsUsed; auto& entry = blockIndex.load(std::memory_order_relaxed)->entries[pr_blockIndexFront]; entry.base = currentTailIndex; entry.block = this->tailBlock; pr_blockIndexFront = (pr_blockIndexFront + 1) & (pr_blockIndexSize - 1); } // Excellent, all allocations succeeded. Reset each block's emptiness before we fill them up, and // publish the new block index front auto block = firstAllocatedBlock; while (true) { block->ConcurrentQueue::Block::template reset_empty(); if (block == this->tailBlock) { break; } block = block->next; } if (MOODYCAMEL_NOEXCEPT_CTOR(T, decltype(*itemFirst), new (nullptr) T(details::deref_noexcept(itemFirst)))) { blockIndex.load(std::memory_order_relaxed)->front.store((pr_blockIndexFront - 1) & (pr_blockIndexSize - 1), std::memory_order_release); } } // Enqueue, one block at a time index_t newTailIndex = startTailIndex + static_cast(count); currentTailIndex = startTailIndex; auto endBlock = this->tailBlock; this->tailBlock = startBlock; assert((startTailIndex & static_cast(BLOCK_SIZE - 1)) != 0 || firstAllocatedBlock != nullptr || count == 0); if ((startTailIndex & static_cast(BLOCK_SIZE - 1)) == 0 && firstAllocatedBlock != nullptr) { this->tailBlock = firstAllocatedBlock; } while (true) { auto stopIndex = (currentTailIndex & ~static_cast(BLOCK_SIZE - 1)) + static_cast(BLOCK_SIZE); if (details::circular_less_than(newTailIndex, stopIndex)) { stopIndex = newTailIndex; } if (MOODYCAMEL_NOEXCEPT_CTOR(T, decltype(*itemFirst), new (nullptr) T(details::deref_noexcept(itemFirst)))) { while (currentTailIndex != stopIndex) { new ((*this->tailBlock)[currentTailIndex++]) T(*itemFirst++); } } else { MOODYCAMEL_TRY { while (currentTailIndex != stopIndex) { // Must use copy constructor even if move constructor is available // because we may have to revert if there's an exception. // Sorry about the horrible templated next line, but it was the only way // to disable moving *at compile time*, which is important because a type // may only define a (noexcept) move constructor, and so calls to the // cctor will not compile, even if they are in an if branch that will never // be executed new ((*this->tailBlock)[currentTailIndex]) T(details::nomove_if<(bool)!MOODYCAMEL_NOEXCEPT_CTOR(T, decltype(*itemFirst), new (nullptr) T(details::deref_noexcept(itemFirst)))>::eval(*itemFirst)); ++currentTailIndex; ++itemFirst; } } MOODYCAMEL_CATCH (...) { // Oh dear, an exception's been thrown -- destroy the elements that // were enqueued so far and revert the entire bulk operation (we'll keep // any allocated blocks in our linked list for later, though). auto constructedStopIndex = currentTailIndex; auto lastBlockEnqueued = this->tailBlock; pr_blockIndexFront = originalBlockIndexFront; pr_blockIndexSlotsUsed = originalBlockIndexSlotsUsed; this->tailBlock = startBlock == nullptr ? firstAllocatedBlock : startBlock; if (!details::is_trivially_destructible::value) { auto block = startBlock; if ((startTailIndex & static_cast(BLOCK_SIZE - 1)) == 0) { block = firstAllocatedBlock; } currentTailIndex = startTailIndex; while (true) { stopIndex = (currentTailIndex & ~static_cast(BLOCK_SIZE - 1)) + static_cast(BLOCK_SIZE); if (details::circular_less_than(constructedStopIndex, stopIndex)) { stopIndex = constructedStopIndex; } while (currentTailIndex != stopIndex) { (*block)[currentTailIndex++]->~T(); } if (block == lastBlockEnqueued) { break; } block = block->next; } } MOODYCAMEL_RETHROW; } } if (this->tailBlock == endBlock) { assert(currentTailIndex == newTailIndex); break; } this->tailBlock = this->tailBlock->next; } if (!MOODYCAMEL_NOEXCEPT_CTOR(T, decltype(*itemFirst), new (nullptr) T(details::deref_noexcept(itemFirst))) && firstAllocatedBlock != nullptr) { blockIndex.load(std::memory_order_relaxed)->front.store((pr_blockIndexFront - 1) & (pr_blockIndexSize - 1), std::memory_order_release); } this->tailIndex.store(newTailIndex, std::memory_order_release); return true; } template size_t dequeue_bulk(It& itemFirst, size_t max) { auto tail = this->tailIndex.load(std::memory_order_relaxed); auto overcommit = this->dequeueOvercommit.load(std::memory_order_relaxed); auto desiredCount = static_cast(tail - (this->dequeueOptimisticCount.load(std::memory_order_relaxed) - overcommit)); if (details::circular_less_than(0, desiredCount)) { desiredCount = desiredCount < max ? desiredCount : max; std::atomic_thread_fence(std::memory_order_acquire); auto myDequeueCount = this->dequeueOptimisticCount.fetch_add(desiredCount, std::memory_order_relaxed);; tail = this->tailIndex.load(std::memory_order_acquire); auto actualCount = static_cast(tail - (myDequeueCount - overcommit)); if (details::circular_less_than(0, actualCount)) { actualCount = desiredCount < actualCount ? desiredCount : actualCount; if (actualCount < desiredCount) { this->dequeueOvercommit.fetch_add(desiredCount - actualCount, std::memory_order_release); } // Get the first index. Note that since there's guaranteed to be at least actualCount elements, this // will never exceed tail. auto firstIndex = this->headIndex.fetch_add(actualCount, std::memory_order_acq_rel); // Determine which block the first element is in auto localBlockIndex = blockIndex.load(std::memory_order_acquire); auto localBlockIndexHead = localBlockIndex->front.load(std::memory_order_acquire); auto headBase = localBlockIndex->entries[localBlockIndexHead].base; auto firstBlockBaseIndex = firstIndex & ~static_cast(BLOCK_SIZE - 1); auto offset = static_cast(static_cast::type>(firstBlockBaseIndex - headBase) / BLOCK_SIZE); auto indexIndex = (localBlockIndexHead + offset) & (localBlockIndex->size - 1); // Iterate the blocks and dequeue auto index = firstIndex; do { auto firstIndexInBlock = index; auto endIndex = (index & ~static_cast(BLOCK_SIZE - 1)) + static_cast(BLOCK_SIZE); endIndex = details::circular_less_than(firstIndex + static_cast(actualCount), endIndex) ? firstIndex + static_cast(actualCount) : endIndex; auto block = localBlockIndex->entries[indexIndex].block; if (MOODYCAMEL_NOEXCEPT_ASSIGN(T, T&&, details::deref_noexcept(itemFirst) = std::move((*(*block)[index])))) { while (index != endIndex) { auto& el = *((*block)[index]); *itemFirst++ = std::move(el); el.~T(); ++index; } } else { MOODYCAMEL_TRY { while (index != endIndex) { auto& el = *((*block)[index]); *itemFirst = std::move(el); ++itemFirst; el.~T(); ++index; } } MOODYCAMEL_CATCH (...) { // It's too late to revert the dequeue, but we can make sure that all // the dequeued objects are properly destroyed and the block index // (and empty count) are properly updated before we propagate the exception do { block = localBlockIndex->entries[indexIndex].block; while (index != endIndex) { (*block)[index++]->~T(); } block->ConcurrentQueue::Block::template set_many_empty(firstIndexInBlock, static_cast(endIndex - firstIndexInBlock)); indexIndex = (indexIndex + 1) & (localBlockIndex->size - 1); firstIndexInBlock = index; endIndex = (index & ~static_cast(BLOCK_SIZE - 1)) + static_cast(BLOCK_SIZE); endIndex = details::circular_less_than(firstIndex + static_cast(actualCount), endIndex) ? firstIndex + static_cast(actualCount) : endIndex; } while (index != firstIndex + actualCount); MOODYCAMEL_RETHROW; } } block->ConcurrentQueue::Block::template set_many_empty(firstIndexInBlock, static_cast(endIndex - firstIndexInBlock)); indexIndex = (indexIndex + 1) & (localBlockIndex->size - 1); } while (index != firstIndex + actualCount); return actualCount; } else { // Wasn't anything to dequeue after all; make the effective dequeue count eventually consistent this->dequeueOvercommit.fetch_add(desiredCount, std::memory_order_release); } } return 0; } private: struct BlockIndexEntry { index_t base; Block* block; }; struct BlockIndexHeader { size_t size; std::atomic front; // Current slot (not next, like pr_blockIndexFront) BlockIndexEntry* entries; void* prev; }; bool new_block_index(size_t numberOfFilledSlotsToExpose) { auto prevBlockSizeMask = pr_blockIndexSize - 1; // Create the new block pr_blockIndexSize <<= 1; auto newRawPtr = static_cast((Traits::malloc)(sizeof(BlockIndexHeader) + std::alignment_of::value - 1 + sizeof(BlockIndexEntry) * pr_blockIndexSize)); if (newRawPtr == nullptr) { pr_blockIndexSize >>= 1; // Reset to allow graceful retry return false; } auto newBlockIndexEntries = reinterpret_cast(details::align_for(newRawPtr + sizeof(BlockIndexHeader))); // Copy in all the old indices, if any size_t j = 0; if (pr_blockIndexSlotsUsed != 0) { auto i = (pr_blockIndexFront - pr_blockIndexSlotsUsed) & prevBlockSizeMask; do { newBlockIndexEntries[j++] = pr_blockIndexEntries[i]; i = (i + 1) & prevBlockSizeMask; } while (i != pr_blockIndexFront); } // Update everything auto header = new (newRawPtr) BlockIndexHeader; header->size = pr_blockIndexSize; header->front.store(numberOfFilledSlotsToExpose - 1, std::memory_order_relaxed); header->entries = newBlockIndexEntries; header->prev = pr_blockIndexRaw; // we link the new block to the old one so we can free it later pr_blockIndexFront = j; pr_blockIndexEntries = newBlockIndexEntries; pr_blockIndexRaw = newRawPtr; blockIndex.store(header, std::memory_order_release); return true; } private: std::atomic blockIndex; // To be used by producer only -- consumer must use the ones in referenced by blockIndex size_t pr_blockIndexSlotsUsed; size_t pr_blockIndexSize; size_t pr_blockIndexFront; // Next slot (not current) BlockIndexEntry* pr_blockIndexEntries; void* pr_blockIndexRaw; #ifdef MOODYCAMEL_QUEUE_INTERNAL_DEBUG public: ExplicitProducer* nextExplicitProducer; private: #endif #if MCDBGQ_TRACKMEM friend struct MemStats; #endif }; ////////////////////////////////// // Implicit queue ////////////////////////////////// struct ImplicitProducer : public ProducerBase { ImplicitProducer(ConcurrentQueue* parent) : ProducerBase(parent, false), nextBlockIndexCapacity(IMPLICIT_INITIAL_INDEX_SIZE), blockIndex(nullptr) { new_block_index(); } ~ImplicitProducer() { // Note that since we're in the destructor we can assume that all enqueue/dequeue operations // completed already; this means that all undequeued elements are placed contiguously across // contiguous blocks, and that only the first and last remaining blocks can be only partially // empty (all other remaining blocks must be completely full). #ifdef MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED // Unregister ourselves for thread termination notification if (!this->inactive.load(std::memory_order_relaxed)) { details::ThreadExitNotifier::unsubscribe(&threadExitListener); } #endif // Destroy all remaining elements! auto tail = this->tailIndex.load(std::memory_order_relaxed); auto index = this->headIndex.load(std::memory_order_relaxed); Block* block = nullptr; assert(index == tail || details::circular_less_than(index, tail)); bool forceFreeLastBlock = index != tail; // If we enter the loop, then the last (tail) block will not be freed while (index != tail) { if ((index & static_cast(BLOCK_SIZE - 1)) == 0 || block == nullptr) { if (block != nullptr) { // Free the old block this->parent->add_block_to_free_list(block); } block = get_block_index_entry_for_index(index)->value.load(std::memory_order_relaxed); } ((*block)[index])->~T(); ++index; } // Even if the queue is empty, there's still one block that's not on the free list // (unless the head index reached the end of it, in which case the tail will be poised // to create a new block). if (this->tailBlock != nullptr && (forceFreeLastBlock || (tail & static_cast(BLOCK_SIZE - 1)) != 0)) { this->parent->add_block_to_free_list(this->tailBlock); } // Destroy block index auto localBlockIndex = blockIndex.load(std::memory_order_relaxed); if (localBlockIndex != nullptr) { for (size_t i = 0; i != localBlockIndex->capacity; ++i) { localBlockIndex->index[i]->~BlockIndexEntry(); } do { auto prev = localBlockIndex->prev; localBlockIndex->~BlockIndexHeader(); (Traits::free)(localBlockIndex); localBlockIndex = prev; } while (localBlockIndex != nullptr); } } template inline bool enqueue(U&& element) { index_t currentTailIndex = this->tailIndex.load(std::memory_order_relaxed); index_t newTailIndex = 1 + currentTailIndex; if ((currentTailIndex & static_cast(BLOCK_SIZE - 1)) == 0) { // We reached the end of a block, start a new one auto head = this->headIndex.load(std::memory_order_relaxed); assert(!details::circular_less_than(currentTailIndex, head)); if (!details::circular_less_than(head, currentTailIndex + BLOCK_SIZE) || (MAX_SUBQUEUE_SIZE != details::const_numeric_max::value && (MAX_SUBQUEUE_SIZE == 0 || MAX_SUBQUEUE_SIZE - BLOCK_SIZE < currentTailIndex - head))) { return false; } #if MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX debug::DebugLock lock(mutex); #endif // Find out where we'll be inserting this block in the block index BlockIndexEntry* idxEntry; if (!insert_block_index_entry(idxEntry, currentTailIndex)) { return false; } // Get ahold of a new block auto newBlock = this->parent->ConcurrentQueue::template requisition_block(); if (newBlock == nullptr) { rewind_block_index_tail(); idxEntry->value.store(nullptr, std::memory_order_relaxed); return false; } #if MCDBGQ_TRACKMEM newBlock->owner = this; #endif newBlock->ConcurrentQueue::Block::template reset_empty(); if (!MOODYCAMEL_NOEXCEPT_CTOR(T, U, new (nullptr) T(std::forward(element)))) { // May throw, try to insert now before we publish the fact that we have this new block MOODYCAMEL_TRY { new ((*newBlock)[currentTailIndex]) T(std::forward(element)); } MOODYCAMEL_CATCH (...) { rewind_block_index_tail(); idxEntry->value.store(nullptr, std::memory_order_relaxed); this->parent->add_block_to_free_list(newBlock); MOODYCAMEL_RETHROW; } } // Insert the new block into the index idxEntry->value.store(newBlock, std::memory_order_relaxed); this->tailBlock = newBlock; if (!MOODYCAMEL_NOEXCEPT_CTOR(T, U, new (nullptr) T(std::forward(element)))) { this->tailIndex.store(newTailIndex, std::memory_order_release); return true; } } // Enqueue new ((*this->tailBlock)[currentTailIndex]) T(std::forward(element)); this->tailIndex.store(newTailIndex, std::memory_order_release); return true; } template bool dequeue(U& element) { // See ExplicitProducer::dequeue for rationale and explanation index_t tail = this->tailIndex.load(std::memory_order_relaxed); index_t overcommit = this->dequeueOvercommit.load(std::memory_order_relaxed); if (details::circular_less_than(this->dequeueOptimisticCount.load(std::memory_order_relaxed) - overcommit, tail)) { std::atomic_thread_fence(std::memory_order_acquire); index_t myDequeueCount = this->dequeueOptimisticCount.fetch_add(1, std::memory_order_relaxed); tail = this->tailIndex.load(std::memory_order_acquire); if ((details::likely)(details::circular_less_than(myDequeueCount - overcommit, tail))) { index_t index = this->headIndex.fetch_add(1, std::memory_order_acq_rel); // Determine which block the element is in auto entry = get_block_index_entry_for_index(index); // Dequeue auto block = entry->value.load(std::memory_order_relaxed); auto& el = *((*block)[index]); if (!MOODYCAMEL_NOEXCEPT_ASSIGN(T, T&&, element = std::move(el))) { #if MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX // Note: Acquiring the mutex with every dequeue instead of only when a block // is released is very sub-optimal, but it is, after all, purely debug code. debug::DebugLock lock(producer->mutex); #endif struct Guard { Block* block; index_t index; BlockIndexEntry* entry; ConcurrentQueue* parent; ~Guard() { (*block)[index]->~T(); if (block->ConcurrentQueue::Block::template set_empty(index)) { entry->value.store(nullptr, std::memory_order_relaxed); parent->add_block_to_free_list(block); } } } guard = { block, index, entry, this->parent }; element = std::move(el); } else { element = std::move(el); el.~T(); if (block->ConcurrentQueue::Block::template set_empty(index)) { { #if MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX debug::DebugLock lock(mutex); #endif // Add the block back into the global free pool (and remove from block index) entry->value.store(nullptr, std::memory_order_relaxed); } this->parent->add_block_to_free_list(block); // releases the above store } } return true; } else { this->dequeueOvercommit.fetch_add(1, std::memory_order_release); } } return false; } template bool enqueue_bulk(It itemFirst, size_t count) { // First, we need to make sure we have enough room to enqueue all of the elements; // this means pre-allocating blocks and putting them in the block index (but only if // all the allocations succeeded). // Note that the tailBlock we start off with may not be owned by us any more; // this happens if it was filled up exactly to the top (setting tailIndex to // the first index of the next block which is not yet allocated), then dequeued // completely (putting it on the free list) before we enqueue again. index_t startTailIndex = this->tailIndex.load(std::memory_order_relaxed); auto startBlock = this->tailBlock; Block* firstAllocatedBlock = nullptr; auto endBlock = this->tailBlock; // Figure out how many blocks we'll need to allocate, and do so size_t blockBaseDiff = ((startTailIndex + count - 1) & ~static_cast(BLOCK_SIZE - 1)) - ((startTailIndex - 1) & ~static_cast(BLOCK_SIZE - 1)); index_t currentTailIndex = (startTailIndex - 1) & ~static_cast(BLOCK_SIZE - 1); if (blockBaseDiff > 0) { #if MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX debug::DebugLock lock(mutex); #endif do { blockBaseDiff -= static_cast(BLOCK_SIZE); currentTailIndex += static_cast(BLOCK_SIZE); // Find out where we'll be inserting this block in the block index BlockIndexEntry* idxEntry = nullptr; // initialization here unnecessary but compiler can't always tell Block* newBlock; bool indexInserted = false; auto head = this->headIndex.load(std::memory_order_relaxed); assert(!details::circular_less_than(currentTailIndex, head)); bool full = !details::circular_less_than(head, currentTailIndex + BLOCK_SIZE) || (MAX_SUBQUEUE_SIZE != details::const_numeric_max::value && (MAX_SUBQUEUE_SIZE == 0 || MAX_SUBQUEUE_SIZE - BLOCK_SIZE < currentTailIndex - head)); if (full || !(indexInserted = insert_block_index_entry(idxEntry, currentTailIndex)) || (newBlock = this->parent->ConcurrentQueue::template requisition_block()) == nullptr) { // Index allocation or block allocation failed; revert any other allocations // and index insertions done so far for this operation if (indexInserted) { rewind_block_index_tail(); idxEntry->value.store(nullptr, std::memory_order_relaxed); } currentTailIndex = (startTailIndex - 1) & ~static_cast(BLOCK_SIZE - 1); for (auto block = firstAllocatedBlock; block != nullptr; block = block->next) { currentTailIndex += static_cast(BLOCK_SIZE); idxEntry = get_block_index_entry_for_index(currentTailIndex); idxEntry->value.store(nullptr, std::memory_order_relaxed); rewind_block_index_tail(); } this->parent->add_blocks_to_free_list(firstAllocatedBlock); this->tailBlock = startBlock; return false; } #if MCDBGQ_TRACKMEM newBlock->owner = this; #endif newBlock->ConcurrentQueue::Block::template reset_empty(); newBlock->next = nullptr; // Insert the new block into the index idxEntry->value.store(newBlock, std::memory_order_relaxed); // Store the chain of blocks so that we can undo if later allocations fail, // and so that we can find the blocks when we do the actual enqueueing if ((startTailIndex & static_cast(BLOCK_SIZE - 1)) != 0 || firstAllocatedBlock != nullptr) { assert(this->tailBlock != nullptr); this->tailBlock->next = newBlock; } this->tailBlock = newBlock; endBlock = newBlock; firstAllocatedBlock = firstAllocatedBlock == nullptr ? newBlock : firstAllocatedBlock; } while (blockBaseDiff > 0); } // Enqueue, one block at a time index_t newTailIndex = startTailIndex + static_cast(count); currentTailIndex = startTailIndex; this->tailBlock = startBlock; assert((startTailIndex & static_cast(BLOCK_SIZE - 1)) != 0 || firstAllocatedBlock != nullptr || count == 0); if ((startTailIndex & static_cast(BLOCK_SIZE - 1)) == 0 && firstAllocatedBlock != nullptr) { this->tailBlock = firstAllocatedBlock; } while (true) { auto stopIndex = (currentTailIndex & ~static_cast(BLOCK_SIZE - 1)) + static_cast(BLOCK_SIZE); if (details::circular_less_than(newTailIndex, stopIndex)) { stopIndex = newTailIndex; } if (MOODYCAMEL_NOEXCEPT_CTOR(T, decltype(*itemFirst), new (nullptr) T(details::deref_noexcept(itemFirst)))) { while (currentTailIndex != stopIndex) { new ((*this->tailBlock)[currentTailIndex++]) T(*itemFirst++); } } else { MOODYCAMEL_TRY { while (currentTailIndex != stopIndex) { new ((*this->tailBlock)[currentTailIndex]) T(details::nomove_if<(bool)!MOODYCAMEL_NOEXCEPT_CTOR(T, decltype(*itemFirst), new (nullptr) T(details::deref_noexcept(itemFirst)))>::eval(*itemFirst)); ++currentTailIndex; ++itemFirst; } } MOODYCAMEL_CATCH (...) { auto constructedStopIndex = currentTailIndex; auto lastBlockEnqueued = this->tailBlock; if (!details::is_trivially_destructible::value) { auto block = startBlock; if ((startTailIndex & static_cast(BLOCK_SIZE - 1)) == 0) { block = firstAllocatedBlock; } currentTailIndex = startTailIndex; while (true) { stopIndex = (currentTailIndex & ~static_cast(BLOCK_SIZE - 1)) + static_cast(BLOCK_SIZE); if (details::circular_less_than(constructedStopIndex, stopIndex)) { stopIndex = constructedStopIndex; } while (currentTailIndex != stopIndex) { (*block)[currentTailIndex++]->~T(); } if (block == lastBlockEnqueued) { break; } block = block->next; } } currentTailIndex = (startTailIndex - 1) & ~static_cast(BLOCK_SIZE - 1); for (auto block = firstAllocatedBlock; block != nullptr; block = block->next) { currentTailIndex += static_cast(BLOCK_SIZE); auto idxEntry = get_block_index_entry_for_index(currentTailIndex); idxEntry->value.store(nullptr, std::memory_order_relaxed); rewind_block_index_tail(); } this->parent->add_blocks_to_free_list(firstAllocatedBlock); this->tailBlock = startBlock; MOODYCAMEL_RETHROW; } } if (this->tailBlock == endBlock) { assert(currentTailIndex == newTailIndex); break; } this->tailBlock = this->tailBlock->next; } this->tailIndex.store(newTailIndex, std::memory_order_release); return true; } template size_t dequeue_bulk(It& itemFirst, size_t max) { auto tail = this->tailIndex.load(std::memory_order_relaxed); auto overcommit = this->dequeueOvercommit.load(std::memory_order_relaxed); auto desiredCount = static_cast(tail - (this->dequeueOptimisticCount.load(std::memory_order_relaxed) - overcommit)); if (details::circular_less_than(0, desiredCount)) { desiredCount = desiredCount < max ? desiredCount : max; std::atomic_thread_fence(std::memory_order_acquire); auto myDequeueCount = this->dequeueOptimisticCount.fetch_add(desiredCount, std::memory_order_relaxed); tail = this->tailIndex.load(std::memory_order_acquire); auto actualCount = static_cast(tail - (myDequeueCount - overcommit)); if (details::circular_less_than(0, actualCount)) { actualCount = desiredCount < actualCount ? desiredCount : actualCount; if (actualCount < desiredCount) { this->dequeueOvercommit.fetch_add(desiredCount - actualCount, std::memory_order_release); } // Get the first index. Note that since there's guaranteed to be at least actualCount elements, this // will never exceed tail. auto firstIndex = this->headIndex.fetch_add(actualCount, std::memory_order_acq_rel); // Iterate the blocks and dequeue auto index = firstIndex; BlockIndexHeader* localBlockIndex; auto indexIndex = get_block_index_index_for_index(index, localBlockIndex); do { auto blockStartIndex = index; auto endIndex = (index & ~static_cast(BLOCK_SIZE - 1)) + static_cast(BLOCK_SIZE); endIndex = details::circular_less_than(firstIndex + static_cast(actualCount), endIndex) ? firstIndex + static_cast(actualCount) : endIndex; auto entry = localBlockIndex->index[indexIndex]; auto block = entry->value.load(std::memory_order_relaxed); if (MOODYCAMEL_NOEXCEPT_ASSIGN(T, T&&, details::deref_noexcept(itemFirst) = std::move((*(*block)[index])))) { while (index != endIndex) { auto& el = *((*block)[index]); *itemFirst++ = std::move(el); el.~T(); ++index; } } else { MOODYCAMEL_TRY { while (index != endIndex) { auto& el = *((*block)[index]); *itemFirst = std::move(el); ++itemFirst; el.~T(); ++index; } } MOODYCAMEL_CATCH (...) { do { entry = localBlockIndex->index[indexIndex]; block = entry->value.load(std::memory_order_relaxed); while (index != endIndex) { (*block)[index++]->~T(); } if (block->ConcurrentQueue::Block::template set_many_empty(blockStartIndex, static_cast(endIndex - blockStartIndex))) { #if MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX debug::DebugLock lock(mutex); #endif entry->value.store(nullptr, std::memory_order_relaxed); this->parent->add_block_to_free_list(block); } indexIndex = (indexIndex + 1) & (localBlockIndex->capacity - 1); blockStartIndex = index; endIndex = (index & ~static_cast(BLOCK_SIZE - 1)) + static_cast(BLOCK_SIZE); endIndex = details::circular_less_than(firstIndex + static_cast(actualCount), endIndex) ? firstIndex + static_cast(actualCount) : endIndex; } while (index != firstIndex + actualCount); MOODYCAMEL_RETHROW; } } if (block->ConcurrentQueue::Block::template set_many_empty(blockStartIndex, static_cast(endIndex - blockStartIndex))) { { #if MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX debug::DebugLock lock(mutex); #endif // Note that the set_many_empty above did a release, meaning that anybody who acquires the block // we're about to free can use it safely since our writes (and reads!) will have happened-before then. entry->value.store(nullptr, std::memory_order_relaxed); } this->parent->add_block_to_free_list(block); // releases the above store } indexIndex = (indexIndex + 1) & (localBlockIndex->capacity - 1); } while (index != firstIndex + actualCount); return actualCount; } else { this->dequeueOvercommit.fetch_add(desiredCount, std::memory_order_release); } } return 0; } private: // The block size must be > 1, so any number with the low bit set is an invalid block base index static const index_t INVALID_BLOCK_BASE = 1; struct BlockIndexEntry { std::atomic key; std::atomic value; }; struct BlockIndexHeader { size_t capacity; std::atomic tail; BlockIndexEntry* entries; BlockIndexEntry** index; BlockIndexHeader* prev; }; template inline bool insert_block_index_entry(BlockIndexEntry*& idxEntry, index_t blockStartIndex) { auto localBlockIndex = blockIndex.load(std::memory_order_relaxed); // We're the only writer thread, relaxed is OK if (localBlockIndex == nullptr) { return false; // this can happen if new_block_index failed in the constructor } auto newTail = (localBlockIndex->tail.load(std::memory_order_relaxed) + 1) & (localBlockIndex->capacity - 1); idxEntry = localBlockIndex->index[newTail]; if (idxEntry->key.load(std::memory_order_relaxed) == INVALID_BLOCK_BASE || idxEntry->value.load(std::memory_order_relaxed) == nullptr) { idxEntry->key.store(blockStartIndex, std::memory_order_relaxed); localBlockIndex->tail.store(newTail, std::memory_order_release); return true; } // No room in the old block index, try to allocate another one! if (allocMode == CannotAlloc || !new_block_index()) { return false; } localBlockIndex = blockIndex.load(std::memory_order_relaxed); newTail = (localBlockIndex->tail.load(std::memory_order_relaxed) + 1) & (localBlockIndex->capacity - 1); idxEntry = localBlockIndex->index[newTail]; assert(idxEntry->key.load(std::memory_order_relaxed) == INVALID_BLOCK_BASE); idxEntry->key.store(blockStartIndex, std::memory_order_relaxed); localBlockIndex->tail.store(newTail, std::memory_order_release); return true; } inline void rewind_block_index_tail() { auto localBlockIndex = blockIndex.load(std::memory_order_relaxed); localBlockIndex->tail.store((localBlockIndex->tail.load(std::memory_order_relaxed) - 1) & (localBlockIndex->capacity - 1), std::memory_order_relaxed); } inline BlockIndexEntry* get_block_index_entry_for_index(index_t index) const { BlockIndexHeader* localBlockIndex; auto idx = get_block_index_index_for_index(index, localBlockIndex); return localBlockIndex->index[idx]; } inline size_t get_block_index_index_for_index(index_t index, BlockIndexHeader*& localBlockIndex) const { #if MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX debug::DebugLock lock(mutex); #endif index &= ~static_cast(BLOCK_SIZE - 1); localBlockIndex = blockIndex.load(std::memory_order_acquire); auto tail = localBlockIndex->tail.load(std::memory_order_acquire); auto tailBase = localBlockIndex->index[tail]->key.load(std::memory_order_relaxed); assert(tailBase != INVALID_BLOCK_BASE); // Note: Must use division instead of shift because the index may wrap around, causing a negative // offset, whose negativity we want to preserve auto offset = static_cast(static_cast::type>(index - tailBase) / BLOCK_SIZE); size_t idx = (tail + offset) & (localBlockIndex->capacity - 1); assert(localBlockIndex->index[idx]->key.load(std::memory_order_relaxed) == index && localBlockIndex->index[idx]->value.load(std::memory_order_relaxed) != nullptr); return idx; } bool new_block_index() { auto prev = blockIndex.load(std::memory_order_relaxed); size_t prevCapacity = prev == nullptr ? 0 : prev->capacity; auto entryCount = prev == nullptr ? nextBlockIndexCapacity : prevCapacity; auto raw = static_cast((Traits::malloc)( sizeof(BlockIndexHeader) + std::alignment_of::value - 1 + sizeof(BlockIndexEntry) * entryCount + std::alignment_of::value - 1 + sizeof(BlockIndexEntry*) * nextBlockIndexCapacity)); if (raw == nullptr) { return false; } auto header = new (raw) BlockIndexHeader; auto entries = reinterpret_cast(details::align_for(raw + sizeof(BlockIndexHeader))); auto index = reinterpret_cast(details::align_for(reinterpret_cast(entries) + sizeof(BlockIndexEntry) * entryCount)); if (prev != nullptr) { auto prevTail = prev->tail.load(std::memory_order_relaxed); auto prevPos = prevTail; size_t i = 0; do { prevPos = (prevPos + 1) & (prev->capacity - 1); index[i++] = prev->index[prevPos]; } while (prevPos != prevTail); assert(i == prevCapacity); } for (size_t i = 0; i != entryCount; ++i) { new (entries + i) BlockIndexEntry; entries[i].key.store(INVALID_BLOCK_BASE, std::memory_order_relaxed); index[prevCapacity + i] = entries + i; } header->prev = prev; header->entries = entries; header->index = index; header->capacity = nextBlockIndexCapacity; header->tail.store((prevCapacity - 1) & (nextBlockIndexCapacity - 1), std::memory_order_relaxed); blockIndex.store(header, std::memory_order_release); nextBlockIndexCapacity <<= 1; return true; } private: size_t nextBlockIndexCapacity; std::atomic blockIndex; #ifdef MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED public: details::ThreadExitListener threadExitListener; private: #endif #ifdef MOODYCAMEL_QUEUE_INTERNAL_DEBUG public: ImplicitProducer* nextImplicitProducer; private: #endif #if MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX mutable debug::DebugMutex mutex; #endif #if MCDBGQ_TRACKMEM friend struct MemStats; #endif }; ////////////////////////////////// // Block pool manipulation ////////////////////////////////// void populate_initial_block_list(size_t blockCount) { initialBlockPoolSize = blockCount; if (initialBlockPoolSize == 0) { initialBlockPool = nullptr; return; } initialBlockPool = create_array(blockCount); if (initialBlockPool == nullptr) { initialBlockPoolSize = 0; } for (size_t i = 0; i < initialBlockPoolSize; ++i) { initialBlockPool[i].dynamicallyAllocated = false; } } inline Block* try_get_block_from_initial_pool() { if (initialBlockPoolIndex.load(std::memory_order_relaxed) >= initialBlockPoolSize) { return nullptr; } auto index = initialBlockPoolIndex.fetch_add(1, std::memory_order_relaxed); return index < initialBlockPoolSize ? (initialBlockPool + index) : nullptr; } inline void add_block_to_free_list(Block* block) { #if MCDBGQ_TRACKMEM block->owner = nullptr; #endif freeList.add(block); } inline void add_blocks_to_free_list(Block* block) { while (block != nullptr) { auto next = block->next; add_block_to_free_list(block); block = next; } } inline Block* try_get_block_from_free_list() { return freeList.try_get(); } // Gets a free block from one of the memory pools, or allocates a new one (if applicable) template Block* requisition_block() { auto block = try_get_block_from_initial_pool(); if (block != nullptr) { return block; } block = try_get_block_from_free_list(); if (block != nullptr) { return block; } if (canAlloc == CanAlloc) { return create(); } return nullptr; } #if MCDBGQ_TRACKMEM public: struct MemStats { size_t allocatedBlocks; size_t usedBlocks; size_t freeBlocks; size_t ownedBlocksExplicit; size_t ownedBlocksImplicit; size_t implicitProducers; size_t explicitProducers; size_t elementsEnqueued; size_t blockClassBytes; size_t queueClassBytes; size_t implicitBlockIndexBytes; size_t explicitBlockIndexBytes; friend class ConcurrentQueue; private: static MemStats getFor(ConcurrentQueue* q) { MemStats stats = { 0 }; stats.elementsEnqueued = q->size_approx(); auto block = q->freeList.head_unsafe(); while (block != nullptr) { ++stats.allocatedBlocks; ++stats.freeBlocks; block = block->freeListNext.load(std::memory_order_relaxed); } for (auto ptr = q->producerListTail.load(std::memory_order_acquire); ptr != nullptr; ptr = ptr->next_prod()) { bool implicit = dynamic_cast(ptr) != nullptr; stats.implicitProducers += implicit ? 1 : 0; stats.explicitProducers += implicit ? 0 : 1; if (implicit) { auto prod = static_cast(ptr); stats.queueClassBytes += sizeof(ImplicitProducer); auto head = prod->headIndex.load(std::memory_order_relaxed); auto tail = prod->tailIndex.load(std::memory_order_relaxed); auto hash = prod->blockIndex.load(std::memory_order_relaxed); if (hash != nullptr) { for (size_t i = 0; i != hash->capacity; ++i) { if (hash->index[i]->key.load(std::memory_order_relaxed) != ImplicitProducer::INVALID_BLOCK_BASE && hash->index[i]->value.load(std::memory_order_relaxed) != nullptr) { ++stats.allocatedBlocks; ++stats.ownedBlocksImplicit; } } stats.implicitBlockIndexBytes += hash->capacity * sizeof(typename ImplicitProducer::BlockIndexEntry); for (; hash != nullptr; hash = hash->prev) { stats.implicitBlockIndexBytes += sizeof(typename ImplicitProducer::BlockIndexHeader) + hash->capacity * sizeof(typename ImplicitProducer::BlockIndexEntry*); } } for (; details::circular_less_than(head, tail); head += BLOCK_SIZE) { //auto block = prod->get_block_index_entry_for_index(head); ++stats.usedBlocks; } } else { auto prod = static_cast(ptr); stats.queueClassBytes += sizeof(ExplicitProducer); auto tailBlock = prod->tailBlock; bool wasNonEmpty = false; if (tailBlock != nullptr) { auto block = tailBlock; do { ++stats.allocatedBlocks; if (!block->ConcurrentQueue::Block::template is_empty() || wasNonEmpty) { ++stats.usedBlocks; wasNonEmpty = wasNonEmpty || block != tailBlock; } ++stats.ownedBlocksExplicit; block = block->next; } while (block != tailBlock); } auto index = prod->blockIndex.load(std::memory_order_relaxed); while (index != nullptr) { stats.explicitBlockIndexBytes += sizeof(typename ExplicitProducer::BlockIndexHeader) + index->size * sizeof(typename ExplicitProducer::BlockIndexEntry); index = static_cast(index->prev); } } } auto freeOnInitialPool = q->initialBlockPoolIndex.load(std::memory_order_relaxed) >= q->initialBlockPoolSize ? 0 : q->initialBlockPoolSize - q->initialBlockPoolIndex.load(std::memory_order_relaxed); stats.allocatedBlocks += freeOnInitialPool; stats.freeBlocks += freeOnInitialPool; stats.blockClassBytes = sizeof(Block) * stats.allocatedBlocks; stats.queueClassBytes += sizeof(ConcurrentQueue); return stats; } }; // For debugging only. Not thread-safe. MemStats getMemStats() { return MemStats::getFor(this); } private: friend struct MemStats; #endif ////////////////////////////////// // Producer list manipulation ////////////////////////////////// ProducerBase* recycle_or_create_producer(bool isExplicit) { bool recycled; return recycle_or_create_producer(isExplicit, recycled); } ProducerBase* recycle_or_create_producer(bool isExplicit, bool& recycled) { #if MCDBGQ_NOLOCKFREE_IMPLICITPRODHASH debug::DebugLock lock(implicitProdMutex); #endif // Try to re-use one first for (auto ptr = producerListTail.load(std::memory_order_acquire); ptr != nullptr; ptr = ptr->next_prod()) { if (ptr->inactive.load(std::memory_order_relaxed) && ptr->isExplicit == isExplicit) { bool expected = true; if (ptr->inactive.compare_exchange_strong(expected, /* desired */ false, std::memory_order_acquire, std::memory_order_relaxed)) { // We caught one! It's been marked as activated, the caller can have it recycled = true; return ptr; } } } recycled = false; return add_producer(isExplicit ? static_cast(create(this)) : create(this)); } ProducerBase* add_producer(ProducerBase* producer) { // Handle failed memory allocation if (producer == nullptr) { return nullptr; } producerCount.fetch_add(1, std::memory_order_relaxed); // Add it to the lock-free list auto prevTail = producerListTail.load(std::memory_order_relaxed); do { producer->next = prevTail; } while (!producerListTail.compare_exchange_weak(prevTail, producer, std::memory_order_release, std::memory_order_relaxed)); #ifdef MOODYCAMEL_QUEUE_INTERNAL_DEBUG if (producer->isExplicit) { auto prevTailExplicit = explicitProducers.load(std::memory_order_relaxed); do { static_cast(producer)->nextExplicitProducer = prevTailExplicit; } while (!explicitProducers.compare_exchange_weak(prevTailExplicit, static_cast(producer), std::memory_order_release, std::memory_order_relaxed)); } else { auto prevTailImplicit = implicitProducers.load(std::memory_order_relaxed); do { static_cast(producer)->nextImplicitProducer = prevTailImplicit; } while (!implicitProducers.compare_exchange_weak(prevTailImplicit, static_cast(producer), std::memory_order_release, std::memory_order_relaxed)); } #endif return producer; } void reown_producers() { // After another instance is moved-into/swapped-with this one, all the // producers we stole still think their parents are the other queue. // So fix them up! for (auto ptr = producerListTail.load(std::memory_order_relaxed); ptr != nullptr; ptr = ptr->next_prod()) { ptr->parent = this; } } ////////////////////////////////// // Implicit producer hash ////////////////////////////////// struct ImplicitProducerKVP { std::atomic key; ImplicitProducer* value; // No need for atomicity since it's only read by the thread that sets it in the first place ImplicitProducerKVP() : value(nullptr) { } ImplicitProducerKVP(ImplicitProducerKVP&& other) MOODYCAMEL_NOEXCEPT { key.store(other.key.load(std::memory_order_relaxed), std::memory_order_relaxed); value = other.value; } inline ImplicitProducerKVP& operator=(ImplicitProducerKVP&& other) MOODYCAMEL_NOEXCEPT { swap(other); return *this; } inline void swap(ImplicitProducerKVP& other) MOODYCAMEL_NOEXCEPT { if (this != &other) { details::swap_relaxed(key, other.key); std::swap(value, other.value); } } }; template friend void moodycamel::swap(typename ConcurrentQueue::ImplicitProducerKVP&, typename ConcurrentQueue::ImplicitProducerKVP&) MOODYCAMEL_NOEXCEPT; struct ImplicitProducerHash { size_t capacity; ImplicitProducerKVP* entries; ImplicitProducerHash* prev; }; inline void populate_initial_implicit_producer_hash() { if (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) return; implicitProducerHashCount.store(0, std::memory_order_relaxed); auto hash = &initialImplicitProducerHash; hash->capacity = INITIAL_IMPLICIT_PRODUCER_HASH_SIZE; hash->entries = &initialImplicitProducerHashEntries[0]; for (size_t i = 0; i != INITIAL_IMPLICIT_PRODUCER_HASH_SIZE; ++i) { initialImplicitProducerHashEntries[i].key.store(details::invalid_thread_id, std::memory_order_relaxed); } hash->prev = nullptr; implicitProducerHash.store(hash, std::memory_order_relaxed); } void swap_implicit_producer_hashes(ConcurrentQueue& other) { if (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) return; // Swap (assumes our implicit producer hash is initialized) initialImplicitProducerHashEntries.swap(other.initialImplicitProducerHashEntries); initialImplicitProducerHash.entries = &initialImplicitProducerHashEntries[0]; other.initialImplicitProducerHash.entries = &other.initialImplicitProducerHashEntries[0]; details::swap_relaxed(implicitProducerHashCount, other.implicitProducerHashCount); details::swap_relaxed(implicitProducerHash, other.implicitProducerHash); if (implicitProducerHash.load(std::memory_order_relaxed) == &other.initialImplicitProducerHash) { implicitProducerHash.store(&initialImplicitProducerHash, std::memory_order_relaxed); } else { ImplicitProducerHash* hash; for (hash = implicitProducerHash.load(std::memory_order_relaxed); hash->prev != &other.initialImplicitProducerHash; hash = hash->prev) { continue; } hash->prev = &initialImplicitProducerHash; } if (other.implicitProducerHash.load(std::memory_order_relaxed) == &initialImplicitProducerHash) { other.implicitProducerHash.store(&other.initialImplicitProducerHash, std::memory_order_relaxed); } else { ImplicitProducerHash* hash; for (hash = other.implicitProducerHash.load(std::memory_order_relaxed); hash->prev != &initialImplicitProducerHash; hash = hash->prev) { continue; } hash->prev = &other.initialImplicitProducerHash; } } // Only fails (returns nullptr) if memory allocation fails ImplicitProducer* get_or_add_implicit_producer() { // Note that since the data is essentially thread-local (key is thread ID), // there's a reduced need for fences (memory ordering is already consistent // for any individual thread), except for the current table itself. // Start by looking for the thread ID in the current and all previous hash tables. // If it's not found, it must not be in there yet, since this same thread would // have added it previously to one of the tables that we traversed. // Code and algorithm adapted from http://preshing.com/20130605/the-worlds-simplest-lock-free-hash-table #if MCDBGQ_NOLOCKFREE_IMPLICITPRODHASH debug::DebugLock lock(implicitProdMutex); #endif auto id = details::thread_id(); auto hashedId = details::hash_thread_id(id); auto mainHash = implicitProducerHash.load(std::memory_order_acquire); for (auto hash = mainHash; hash != nullptr; hash = hash->prev) { // Look for the id in this hash auto index = hashedId; while (true) { // Not an infinite loop because at least one slot is free in the hash table index &= hash->capacity - 1; auto probedKey = hash->entries[index].key.load(std::memory_order_relaxed); if (probedKey == id) { // Found it! If we had to search several hashes deep, though, we should lazily add it // to the current main hash table to avoid the extended search next time. // Note there's guaranteed to be room in the current hash table since every subsequent // table implicitly reserves space for all previous tables (there's only one // implicitProducerHashCount). auto value = hash->entries[index].value; if (hash != mainHash) { index = hashedId; while (true) { index &= mainHash->capacity - 1; probedKey = mainHash->entries[index].key.load(std::memory_order_relaxed); auto empty = details::invalid_thread_id; #ifdef MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED auto reusable = details::invalid_thread_id2; if ((probedKey == empty && mainHash->entries[index].key.compare_exchange_strong(empty, id, std::memory_order_relaxed, std::memory_order_relaxed)) || (probedKey == reusable && mainHash->entries[index].key.compare_exchange_strong(reusable, id, std::memory_order_acquire, std::memory_order_acquire))) { #else if ((probedKey == empty && mainHash->entries[index].key.compare_exchange_strong(empty, id, std::memory_order_relaxed, std::memory_order_relaxed))) { #endif mainHash->entries[index].value = value; break; } ++index; } } return value; } if (probedKey == details::invalid_thread_id) { break; // Not in this hash table } ++index; } } // Insert! auto newCount = 1 + implicitProducerHashCount.fetch_add(1, std::memory_order_relaxed); while (true) { if (newCount >= (mainHash->capacity >> 1) && !implicitProducerHashResizeInProgress.test_and_set(std::memory_order_acquire)) { // We've acquired the resize lock, try to allocate a bigger hash table. // Note the acquire fence synchronizes with the release fence at the end of this block, and hence when // we reload implicitProducerHash it must be the most recent version (it only gets changed within this // locked block). mainHash = implicitProducerHash.load(std::memory_order_acquire); if (newCount >= (mainHash->capacity >> 1)) { auto newCapacity = mainHash->capacity << 1; while (newCount >= (newCapacity >> 1)) { newCapacity <<= 1; } auto raw = static_cast((Traits::malloc)(sizeof(ImplicitProducerHash) + std::alignment_of::value - 1 + sizeof(ImplicitProducerKVP) * newCapacity)); if (raw == nullptr) { // Allocation failed implicitProducerHashCount.fetch_sub(1, std::memory_order_relaxed); implicitProducerHashResizeInProgress.clear(std::memory_order_relaxed); return nullptr; } auto newHash = new (raw) ImplicitProducerHash; newHash->capacity = newCapacity; newHash->entries = reinterpret_cast(details::align_for(raw + sizeof(ImplicitProducerHash))); for (size_t i = 0; i != newCapacity; ++i) { new (newHash->entries + i) ImplicitProducerKVP; newHash->entries[i].key.store(details::invalid_thread_id, std::memory_order_relaxed); } newHash->prev = mainHash; implicitProducerHash.store(newHash, std::memory_order_release); implicitProducerHashResizeInProgress.clear(std::memory_order_release); mainHash = newHash; } else { implicitProducerHashResizeInProgress.clear(std::memory_order_release); } } // If it's < three-quarters full, add to the old one anyway so that we don't have to wait for the next table // to finish being allocated by another thread (and if we just finished allocating above, the condition will // always be true) if (newCount < (mainHash->capacity >> 1) + (mainHash->capacity >> 2)) { bool recycled; auto producer = static_cast(recycle_or_create_producer(false, recycled)); if (producer == nullptr) { implicitProducerHashCount.fetch_sub(1, std::memory_order_relaxed); return nullptr; } if (recycled) { implicitProducerHashCount.fetch_sub(1, std::memory_order_relaxed); } #ifdef MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED producer->threadExitListener.callback = &ConcurrentQueue::implicit_producer_thread_exited_callback; producer->threadExitListener.userData = producer; details::ThreadExitNotifier::subscribe(&producer->threadExitListener); #endif auto index = hashedId; while (true) { index &= mainHash->capacity - 1; auto probedKey = mainHash->entries[index].key.load(std::memory_order_relaxed); auto empty = details::invalid_thread_id; #ifdef MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED auto reusable = details::invalid_thread_id2; if ((probedKey == empty && mainHash->entries[index].key.compare_exchange_strong(empty, id, std::memory_order_relaxed, std::memory_order_relaxed)) || (probedKey == reusable && mainHash->entries[index].key.compare_exchange_strong(reusable, id, std::memory_order_acquire, std::memory_order_acquire))) { #else if ((probedKey == empty && mainHash->entries[index].key.compare_exchange_strong(empty, id, std::memory_order_relaxed, std::memory_order_relaxed))) { #endif mainHash->entries[index].value = producer; break; } ++index; } return producer; } // Hmm, the old hash is quite full and somebody else is busy allocating a new one. // We need to wait for the allocating thread to finish (if it succeeds, we add, if not, // we try to allocate ourselves). mainHash = implicitProducerHash.load(std::memory_order_acquire); } } #ifdef MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED void implicit_producer_thread_exited(ImplicitProducer* producer) { // Remove from thread exit listeners details::ThreadExitNotifier::unsubscribe(&producer->threadExitListener); // Remove from hash #if MCDBGQ_NOLOCKFREE_IMPLICITPRODHASH debug::DebugLock lock(implicitProdMutex); #endif auto hash = implicitProducerHash.load(std::memory_order_acquire); assert(hash != nullptr); // The thread exit listener is only registered if we were added to a hash in the first place auto id = details::thread_id(); auto hashedId = details::hash_thread_id(id); details::thread_id_t probedKey; // We need to traverse all the hashes just in case other threads aren't on the current one yet and are // trying to add an entry thinking there's a free slot (because they reused a producer) for (; hash != nullptr; hash = hash->prev) { auto index = hashedId; do { index &= hash->capacity - 1; probedKey = hash->entries[index].key.load(std::memory_order_relaxed); if (probedKey == id) { hash->entries[index].key.store(details::invalid_thread_id2, std::memory_order_release); break; } ++index; } while (probedKey != details::invalid_thread_id); // Can happen if the hash has changed but we weren't put back in it yet, or if we weren't added to this hash in the first place } // Mark the queue as being recyclable producer->inactive.store(true, std::memory_order_release); } static void implicit_producer_thread_exited_callback(void* userData) { auto producer = static_cast(userData); auto queue = producer->parent; queue->implicit_producer_thread_exited(producer); } #endif ////////////////////////////////// // Utility functions ////////////////////////////////// template static inline U* create_array(size_t count) { assert(count > 0); auto p = static_cast((Traits::malloc)(sizeof(U) * count)); if (p == nullptr) { return nullptr; } for (size_t i = 0; i != count; ++i) { new (p + i) U(); } return p; } template static inline void destroy_array(U* p, size_t count) { if (p != nullptr) { assert(count > 0); for (size_t i = count; i != 0; ) { (p + --i)->~U(); } (Traits::free)(p); } } template static inline U* create() { auto p = (Traits::malloc)(sizeof(U)); return p != nullptr ? new (p) U : nullptr; } template static inline U* create(A1&& a1) { auto p = (Traits::malloc)(sizeof(U)); return p != nullptr ? new (p) U(std::forward(a1)) : nullptr; } template static inline void destroy(U* p) { if (p != nullptr) { p->~U(); } (Traits::free)(p); } private: std::atomic producerListTail; std::atomic producerCount; std::atomic initialBlockPoolIndex; Block* initialBlockPool; size_t initialBlockPoolSize; #if !MCDBGQ_USEDEBUGFREELIST FreeList freeList; #else debug::DebugFreeList freeList; #endif std::atomic implicitProducerHash; std::atomic implicitProducerHashCount; // Number of slots logically used ImplicitProducerHash initialImplicitProducerHash; std::array initialImplicitProducerHashEntries; std::atomic_flag implicitProducerHashResizeInProgress; std::atomic nextExplicitConsumerId; std::atomic globalExplicitConsumerOffset; #if MCDBGQ_NOLOCKFREE_IMPLICITPRODHASH debug::DebugMutex implicitProdMutex; #endif #ifdef MOODYCAMEL_QUEUE_INTERNAL_DEBUG std::atomic explicitProducers; std::atomic implicitProducers; #endif }; template ProducerToken::ProducerToken(ConcurrentQueue& queue) : producer(queue.recycle_or_create_producer(true)) { if (producer != nullptr) { producer->token = this; } } template ProducerToken::ProducerToken(BlockingConcurrentQueue& queue) : producer(reinterpret_cast*>(&queue)->recycle_or_create_producer(true)) { if (producer != nullptr) { producer->token = this; } } template ConsumerToken::ConsumerToken(ConcurrentQueue& queue) : itemsConsumedFromCurrent(0), currentProducer(nullptr), desiredProducer(nullptr) { initialOffset = queue.nextExplicitConsumerId.fetch_add(1, std::memory_order_release); lastKnownGlobalOffset = -1; } template ConsumerToken::ConsumerToken(BlockingConcurrentQueue& queue) : itemsConsumedFromCurrent(0), currentProducer(nullptr), desiredProducer(nullptr) { initialOffset = reinterpret_cast*>(&queue)->nextExplicitConsumerId.fetch_add(1, std::memory_order_release); lastKnownGlobalOffset = -1; } template inline void swap(ConcurrentQueue& a, ConcurrentQueue& b) MOODYCAMEL_NOEXCEPT { a.swap(b); } inline void swap(ProducerToken& a, ProducerToken& b) MOODYCAMEL_NOEXCEPT { a.swap(b); } inline void swap(ConsumerToken& a, ConsumerToken& b) MOODYCAMEL_NOEXCEPT { a.swap(b); } template inline void swap(typename ConcurrentQueue::ImplicitProducerKVP& a, typename ConcurrentQueue::ImplicitProducerKVP& b) MOODYCAMEL_NOEXCEPT { a.swap(b); } } #if defined(__GNUC__) #pragma GCC diagnostic pop #endif ================================================ FILE: libsrc/core/exception.cpp ================================================ #include "exception.hpp" #include "utils.hpp" #ifdef EMSCRIPTEN #include #endif // EMSCRIPTEN // no backtrace on Emscripten // backtrace on Apple platforms with GNUC (does not define __GLIBC__) // backtrace on GNU/Linux with glibc // no backtrace with musl libc #if !defined(__EMSCRIPTEN__) && ( \ (defined(__APPLE__) && defined(__GNUC__)) || \ (defined(__GNUC__) && defined(__GLIBC__)) ) #define NG_HAVE_BACKTRACE #endif namespace ngcore { Exception :: Exception(const std::string& s) : m_what(s) { #ifdef EMSCRIPTEN std::cout << "THROW Exception " << s << std::endl; #endif } Exception :: Exception(const char* s) : m_what(s) { #ifdef EMSCRIPTEN std::cout << "THROW Exception " << s << std::endl; #endif } Exception :: Exception(std::string_view s1, std::string_view s2) : Exception(std::string(s1)+std::string(s2)) { } Exception :: Exception(std::string_view s1, std::string_view s2, std::string_view s3) : Exception(std::string(s1)+std::string(s2)+std::string(s3)) { } void Exception :: Throw (std::string_view s1) { throw Exception(std::string(s1)); } void Exception :: Throw (std::string_view s1, std::string_view s2) { throw Exception(std::string(s1)+std::string(s2)); } void Exception :: Throw (std::string_view s1, std::string_view s2, std::string_view s3) { throw Exception(std::string(s1)+std::string(s2)+std::string(s3)); } RangeException :: RangeException (// const std::string & where, const char * where, ptrdiff_t ind, ptrdiff_t imin, ptrdiff_t imax) : Exception("") { std::stringstream str; str << where << ": index " << ind << " out of range [" << imin << "," << imax << ")\n"; Append (str.str()); Append (GetBackTrace()); } void ThrowRangeException(const char * s, ptrdiff_t ind, ptrdiff_t imin, ptrdiff_t imax) { throw RangeException(s, ind, imin, imax); } void ThrowException(const std::string & s) { throw Exception (s); } void ThrowException(const char * s) { throw Exception (s); } void ThrowNotTheSameException(const char * s, ptrdiff_t a, ptrdiff_t b) { throw ngcore::Exception(std::string(s) + ", a="+ToString(a) + ", b="+ToString(b) + GetBackTrace()); } } // namespace ngcore // ********* STUFF FOR GETBACKTRACE *************************** #ifdef NG_HAVE_BACKTRACE #include #include #include #include #include #include #include #include #include #include #include #include namespace ngcore { namespace detail { static int exec(std::string cmd, std::string & out) { std::array buffer; FILE *pipe = popen(cmd.c_str(), "r"); if (!pipe) throw std::runtime_error("popen() failed!"); out = ""; while (fgets(buffer.data(), buffer.size(), pipe) != nullptr) out += buffer.data(); int error_code = pclose(pipe); return error_code; } #ifdef __APPLE__ // Split output line from backtrace_symbols to recover function name and offset // then use `nm` command line tool to get the address of the function // then use `add42line` command line tool to map function address + offset to line in source code static std::string TranslateBacktrace( std::string s, std::string libname ) { // example line // 1 libngcore.dylib 0x000000010ddb298c _ZL21ngcore_signal_handleri + 316 constexpr char reset_shell[] = "\033[0m"; constexpr char green[] = "\033[32m"; [[maybe_unused]] constexpr char yellow[] = "\033[33m"; std::istringstream in(s); std::string libname1, funcname, addr, plus_sign; size_t i,offset; in >> i >> libname1 >> addr >> funcname >> plus_sign >> std::hex >> offset; std::stringstream out; if(!funcname.empty() && !libname.empty()) { std::string nm_command = "nm " + libname + " | grep \"" + funcname + "$\" | cut -f 1 -d ' '"; std::string output; auto exit_code = exec(nm_command, output); auto fptr = std::strtoul(output.c_str(), 0, 16); if(fptr == 0) return out.str()+'\n'; std::stringstream offset_s; offset_s << "0x" << std::hex << fptr+offset - 5; std::string addr2line_command = std::string("atos -o ") + libname + " --fullPath " + offset_s.str(); exit_code = exec(addr2line_command, output); if(exit_code==0) out << " at " << green << output << reset_shell; else out << '\n'; } else out << s << '\n'; return out.str(); } #else // __APPLE__ // Split output line from backtrace_symbols to recover function name and offset // then use `nm` command line tool to get the address of the function // then use `addr2line` command line tool to map function address + offset to line in source code static std::string TranslateBacktrace( std::string s, std::string /*dummy*/ ) { // example line: // /home/mhochsteger/install/ngs_clang/bin/../lib/libngcore.so(_ZN6ngcore11TaskManager4LoopEi+0x1e0) [0x7f2991fe1030] constexpr char reset_shell[] = "\033[0m"; constexpr char green[] = "\033[32m"; constexpr char yellow[] = "\033[33m"; auto brace_open_pos = s.find('('); auto brace_close_pos = s.find(')', brace_open_pos); auto plus_pos = s.find('+', brace_open_pos); auto bracket_open_pos = s.find('['); auto bracket_close_pos = s.find(']'); auto libname = s.substr(0, brace_open_pos); auto funcname = s.substr(brace_open_pos+1, plus_pos - brace_open_pos - 1); auto offset = std::strtoul(s.substr(plus_pos+1, brace_close_pos - plus_pos - 1).c_str(), 0, 16); // auto position = std::strtoul(s.substr(bracket_open_pos+1, bracket_close_pos - bracket_open_pos - 1).c_str(), 0, 16); std::stringstream out; if(!funcname.empty()) { std::vector buffer(10240); int status; size_t size = buffer.size(); abi::__cxa_demangle(funcname.c_str(), &buffer[0], &size, &status); out << "in " << yellow << &buffer[0] << reset_shell << '\n'; std::string nm_command = "nm " + libname + " | grep " + funcname + " | cut -f 1 -d ' '"; std::string output; auto exit_code = exec(nm_command, output); auto fptr = std::strtoul(output.c_str(), 0, 16); std::stringstream offset_s; offset_s << "0x" << std::hex << fptr+offset - 5; std::string addr2line_command = std::string("addr2line -i -p -e ") + libname + " " + offset_s.str(); exit_code = exec(addr2line_command, output); if(exit_code==0) { std::stringstream soutput(output); std::string s; while(soutput) { if(getline(soutput, s)) out << "\t at " << green << s << reset_shell << '\n'; } } else out << '\n'; } else out << s << '\n'; return out.str(); } #endif // __APPLE__ } // namespace detail std::string GetBackTrace() { if(!getenv("NG_BACKTRACE")) return ""; std::cerr << "Collecting backtrace..." << std::endl; std::stringstream result; void *bt[100]; int bt_size; char **bt_syms; int i; bt_size = backtrace(bt, 100); bt_syms = backtrace_symbols(bt, bt_size); Dl_info info; for (i = 1; i < bt_size-1; i++) { dladdr(bt[i], &info); // size_t len = strlen(bt_syms[i]); result << '#'<< i << '\t' << detail::TranslateBacktrace( bt_syms[i], info.dli_fname ); } free(bt_syms); return result.str(); } } // namespace ngcore static void ngcore_signal_handler(int sig) { static bool first_call = true; if(!first_call) exit(1); // avoid endless recursions if signals are caused by this handler first_call = false; switch(sig) { case SIGABRT: std::cerr << "Caught SIGABRT: usually caused by abort() or assert()" << std::endl; break; case SIGILL: std::cerr << "Caught SIGILL: illegal instruction" << std::endl; break; case SIGSEGV: std::cerr << "Caught SIGSEGV: segmentation fault" << std::endl; break; } std::cerr << ngcore::GetBackTrace() << std::endl; exit(1); } // register signal handler when library is loaded static bool dummy = []() { if(getenv("NG_BACKTRACE")) { signal(SIGABRT, ngcore_signal_handler); signal(SIGILL, ngcore_signal_handler); signal(SIGSEGV, ngcore_signal_handler); } return true; }(); #else // NG_HAVE_BACKTRACE namespace ngcore { std::string GetBackTrace() { return std::string(); } } // namespace ngcore #endif // NG_HAVE_BACKTRACE ================================================ FILE: libsrc/core/exception.hpp ================================================ #ifndef NETGEN_CORE_EXCEPTION_HPP #define NETGEN_CORE_EXCEPTION_HPP #include #include // for stringstream #include // for exception #include // for string #include "ngcore_api.hpp" // for NGCORE_API #include "utils.hpp" // for ToString namespace ngcore { NGCORE_API std::string GetBackTrace(); // Exception for code that shouldn't be executed class NGCORE_API UnreachableCodeException : public std::exception { const char* what() const noexcept override { return "Shouldn't get here, something went wrong!"; } }; // Default exception class class NGCORE_API Exception : public std::exception { /// a verbal description of the exception std::string m_what; public: Exception() = default; Exception(const Exception&) = default; Exception(Exception&&) = default; Exception(const std::string& s); // : m_what(s) {} Exception(const char* s); // : m_what(s) {} Exception(std::string_view s1, std::string_view s2); Exception(std::string_view s1, std::string_view s2, std::string_view s3); ~Exception() override = default; [[noreturn]] static void Throw (std::string_view s1); [[noreturn]] static void Throw (std::string_view s1, std::string_view s2); [[noreturn]] static void Throw (std::string_view s1, std::string_view s2, std::string_view s3); Exception& operator =(const Exception&) = default; Exception& operator =(Exception&&) noexcept = default; /// append string to description Exception & Append (const std::string & s) { m_what += s; return *this; } /// append string to description Exception & Append (const char * s) { m_what += s; return *this; } /// verbal description of exception const std::string & What() const { return m_what; } /// implement virtual function of std::exception const char* what() const noexcept override { return m_what.c_str(); } }; [[noreturn]] NGCORE_API void ThrowException(const std::string & s); [[noreturn]] NGCORE_API void ThrowException(const char * s); // Out of Range exception class NGCORE_API RangeException : public Exception { public: /// where it occurs, index, minimal and maximal indices RangeException (// const std::string & where, const char * where, ptrdiff_t ind, ptrdiff_t imin, ptrdiff_t imax); /* : Exception("") { std::stringstream str; str << where << ": index " << ind << " out of range [" << imin << "," << imax << ")\n"; Append (str.str()); Append (GetBackTrace()); } */ template RangeException(const std::string& where, const T& value) { std::stringstream str; str << where << " called with wrong value " << value << "\n"; Append(str.str()); } }; [[noreturn]] NGCORE_API void ThrowRangeException(const char * s, ptrdiff_t ind, ptrdiff_t imin, ptrdiff_t imax); [[noreturn]] NGCORE_API void ThrowNotTheSameException(const char * s, ptrdiff_t a, ptrdiff_t b); // Exception used if no simd implementation is available to fall back to standard evaluation class NGCORE_API ExceptionNOSIMD : public Exception { public: using Exception::Exception; }; template struct IsSafe { constexpr operator bool() const { return false; } }; namespace detail { template inline static constexpr void CheckRange(const char * s, const T& n, Tmin first, Tmax next) { if constexpr (!IsSafe()) if (n=next) ThrowRangeException(s, ptrdiff_t(n), ptrdiff_t(first), ptrdiff_t(next)); } template inline static constexpr void CheckSame(const char * s, const Ta& a, const Tb& b) { if constexpr (!IsSafe() || !IsSafe()) if(a != b) { if constexpr(std::is_integral_v && std::is_same_v) ThrowNotTheSameException(s, long(a), long(b)); \ else throw Exception(std::string(s) + "\t: not the same, a="+ToString(a) + ", b="+ngcore::ToString(b) + GetBackTrace()); } } } // namespace detail } // namespace ngcore #define NETGEN_CORE_NGEXEPTION_STR_HELPER(x) #x #define NETGEN_CORE_NGEXEPTION_STR(x) NETGEN_CORE_NGEXEPTION_STR_HELPER(x) // Convenience macro to append file name and line of exception origin to the string #define NG_EXCEPTION(s) ngcore::Exception(__FILE__ ":" NETGEN_CORE_NGEXEPTION_STR(__LINE__) "\t"+std::string(s)) #if defined(NETGEN_ENABLE_CHECK_RANGE) && !defined(__CUDA_ARCH__) #define NETGEN_CHECK_RANGE(value, min, max_plus_one) ngcore::detail::CheckRange(__FILE__ ":" NETGEN_CORE_NGEXEPTION_STR(__LINE__) "\t", value, min, max_plus_one); #define NETGEN_CHECK_SAME(a,b) ngcore::detail::CheckSame(__FILE__ ":" NETGEN_CORE_NGEXEPTION_STR(__LINE__) "\t", a, b); #define NETGEN_NOEXCEPT #else // defined(NETGEN_ENABLE_CHECK_RANGE) && !defined(__CUDA_ARCH__) #define NETGEN_CHECK_RANGE(value, min, max) #define NETGEN_CHECK_SAME(a,b) // #define NETGEN_CHECK_SHAPE(a,b) #define NETGEN_NOEXCEPT noexcept #endif // defined(NETGEN_ENABLE_CHECK_RANGE) && !defined(__CUDA_ARCH__) #endif // NETGEN_CORE_EXCEPTION_HPP ================================================ FILE: libsrc/core/flags.cpp ================================================ /**************************************************************************/ /* File: flags.cpp */ /* Author: Joachim Schoeberl */ /* Date: 10. Oct. 96 */ /**************************************************************************/ #include "archive.hpp" #include "flags.hpp" #ifdef WIN32 #include #endif #include namespace ngcore { using std::string; using std::string_view; using std::endl; Flags :: Flags () { ; } Flags :: Flags (const Flags & flags) { string name; for (int i = 0; i < flags.GetNStringFlags(); i++) { string str = flags.GetStringFlag (i, name); SetFlag (name, str); } for (int i = 0; i < flags.GetNNumFlags(); i++) { double val = flags.GetNumFlag (i, name); SetFlag (name, val); } for (int i = 0; i < flags.GetNDefineFlags(); i++) { bool val = flags.GetDefineFlag (i, name); SetFlag (name, val); } for (int i = 0; i < flags.GetNNumListFlags(); i++) { auto numa = flags.GetNumListFlag (i, name); SetFlag (name, *numa); } for (int i = 0; i < flags.GetNStringListFlags(); i++) { auto stra = flags.GetStringListFlag (i, name); SetFlag (name, *stra); } for (int i = 0; i < flags.GetNFlagsFlags(); i++) { auto lflags = flags.GetFlagsFlag (i, name); SetFlag (name, lflags); } for(auto i : Range(flags.anyflags.Size())) { SetFlag(flags.anyflags.GetName(i), flags.anyflags[i]); } } Flags :: Flags (std::initializer_list list) { for (auto i = list.begin(); i < list.end(); i++) SetCommandLineFlag ((string("-")+*i).c_str()); } Flags :: Flags (string f1, string f2, string f3, string f4, string f5) { SetCommandLineFlag ((string("-")+f1).c_str()); if (f2.length()) SetCommandLineFlag ( (string("-")+f2).c_str() ); if (f3.length()) SetCommandLineFlag ( (string("-")+f3).c_str() ); if (f4.length()) SetCommandLineFlag ( (string("-")+f4).c_str() ); if (f5.length()) SetCommandLineFlag ( (string("-")+f5).c_str() ); } Flags :: ~Flags () { DeleteFlags (); } void Flags :: DeleteFlags () { strflags.DeleteAll(); numflags.DeleteAll(); defflags.DeleteAll(); strlistflags.DeleteAll(); numlistflags.DeleteAll(); } Flags Flags :: SetFlag (const char * name, bool b) && { this -> SetFlag (name, b); return std::move(*this); } Flags Flags :: SetFlag (const char * name, double val) && { this -> SetFlag (name, val); return std::move(*this); } Flags & Flags :: SetFlag (const char * name, const string & val) { strflags.Set (name, val); return *this; } Flags & Flags :: SetFlag (const char * name, double val) & { numflags.Set (name, val); return *this; } Flags & Flags :: SetFlag (const char * name, bool b) & { defflags.Set (name, b); return *this; } Flags & Flags :: SetFlag (const char * name, Flags & val) & { flaglistflags.Set (name, val); return *this; } Flags & Flags :: SetFlag (const string & name, const string & val) { // char * hval = new char[strlen (val) + 1]; // strcpy (hval, val); strflags.Set (name, val); return *this; } Flags & Flags :: SetFlag (const string & name, double val) { numflags.Set (name, val); return *this; } Flags & Flags :: SetFlag (const string & name, bool b) { defflags.Set (name, b); return *this; } Flags & Flags :: SetFlag (const string & name, Flags & val) { flaglistflags.Set (name, val); return *this; } Flags & Flags :: SetFlag (const string & name, const Array & val) { auto strarray = std::make_shared>(val); /* for (int i = 0; i < val.Size(); i++) { strarray->Append (new char[strlen(val[i])+1]); strcpy (strarray->Last(), val[i]); } */ strlistflags.Set (name, strarray); return *this; } Flags & Flags :: SetFlag (const string & name, const Array & val) { // Array * numarray = new Array(val); auto numarray = std::make_shared> (val); numlistflags.Set (name, numarray); return *this; } Flags & Flags :: SetFlag (const string & name, const std::any & val) { anyflags.Set(name, val); return *this; } string Flags :: GetStringFlag (const string & name, const char * def) const { if (strflags.Used (name)) return strflags[name]; else { if (!def) return string(""); return def; } } string Flags :: GetStringFlag (const string & name, string def) const { if (strflags.Used (name)) return strflags[name]; else return def; } double Flags :: GetNumFlag (string_view name, double def) const { if (numflags.Used (name)) return numflags[string(name)]; else return def; } const double * Flags :: GetNumFlagPtr (string_view name) const { if (numflags.Used (name)) return & ((SymbolTable&)numflags)[string(name)]; else return NULL; } double * Flags :: GetNumFlagPtr (const string & name) { if (numflags.Used (name)) return & ((SymbolTable&)numflags)[name]; else return NULL; } /* int Flags :: GetDefineFlag (const char * name) const { return defflags.Used (name); } */ bool Flags :: GetDefineFlag (string_view name) const throw() { if (!defflags.Used (string(name))) return false; return defflags[string(name)]; } xbool Flags :: GetDefineFlagX (string_view name) const throw() { if (!defflags.Used (string(name))) return maybe; return bool(defflags[string(name)]); } const Array & Flags :: GetStringListFlag (const string & name) const { if (strlistflags.Used (name)) return *strlistflags[name]; else { static Array hstra(0); return hstra; } } const Array & Flags ::GetNumListFlag (const string & name) const { if (numlistflags.Used (name)) return *numlistflags[name]; else { static Array hnuma(0); return hnuma; } } const Flags & Flags ::GetFlagsFlag (const string & name) const { if (flaglistflags.Used (name)) return flaglistflags[name]; else { static Flags empty; return empty; } } const std::any& Flags:: GetAnyFlag(const std::string& name) const { if(anyflags.Used(name)) return anyflags[name]; static std::any empty; return empty; } bool Flags :: StringFlagDefined (string_view name) const noexcept { return strflags.Used (name); } bool Flags :: NumFlagDefined (string_view name) const noexcept { return numflags.Used (name); } bool Flags :: FlagsFlagDefined (string_view name) const noexcept { return flaglistflags.Used (name); } bool Flags :: StringListFlagDefined (string_view name) const noexcept { return strlistflags.Used (name); } bool Flags :: NumListFlagDefined (string_view name) const noexcept { return numlistflags.Used (name); } bool Flags :: AnyFlagDefined (string_view name) const noexcept { return anyflags.Used(name); } void Flags :: SaveFlags (ostream & str) const { for (int i = 0; i < strflags.Size(); i++) str << strflags.GetName(i) << " = " << strflags[i] << endl; for (int i = 0; i < numflags.Size(); i++) str << numflags.GetName(i) << " = " << numflags[i] << endl; for (int i = 0; i < defflags.Size(); i++) str << defflags.GetName(i) << " = " << (defflags[i] ? "_TRUE" : "_FALSE") << endl; for (int i = 0; i < flaglistflags.Size(); i++) str << flaglistflags.GetName(i) << " =*" << flaglistflags[i] << endl; for (int i = 0; i < numlistflags.Size(); i++) { str << numlistflags.GetName(i) << " = ["; int j = 0; for (j = 0; j + 1 < numlistflags[i]->Size(); ++j) str << (*numlistflags[i])[j] << ", "; if (numlistflags[i]->Size()) str << (*numlistflags[i])[j]; str << "]" << endl; } } void Flags :: SaveFlags (const char * filename) const { std::ofstream outfile (filename); SaveFlags(outfile); } void Flags :: PrintFlags (ostream & ost) const { for (int i = 0; i < strflags.Size(); i++) ost << strflags.GetName(i) << " = " << strflags[i] << endl; for (int i = 0; i < numflags.Size(); i++) ost << numflags.GetName(i) << " = " << numflags[i] << endl; for (int i = 0; i < defflags.Size(); i++) ost << defflags.GetName(i) << endl; for (int i = 0; i < strlistflags.Size(); i++) ost << strlistflags.GetName(i) << " = " << *strlistflags[i] << endl; for (int i = 0; i < numlistflags.Size(); i++) ost << numlistflags.GetName(i) << " = " << *numlistflags[i] << endl; for (int i = 0; i < flaglistflags.Size(); i++) ost << flaglistflags.GetName(i) << " = " << flaglistflags[i] << endl; for (int i = 0; i < anyflags.Size(); i++) ost << anyflags.GetName(i) << " = " << "[any]" << endl; } void Flags :: LoadFlags (const char * filename, SymbolTable * sf) { std::ifstream str(filename); LoadFlags(str,sf); } void Flags :: LoadFlags (std::istream & istr, SymbolTable * sf ) { char str[100]; char ch; // double val; while (istr.good()) { string name; string content; string line; getline(istr, line); std::istringstream line_stream(line); getline(line_stream, name, '='); name.erase(std::remove(name.begin(), name.end(), ' '), name.end()); getline(line_stream, content); content.erase(std::remove(content.begin(), content.end(), ' '), content.end()); // if (name[0] == '/' && name[1] == '/') // { // ch = 0; // while (ch != '\n' && istr.good()) // { // ch = istr.get(); // } // continue; // } if (strlen(content.c_str())==0) { SetFlag (name); continue; } else { std::istringstream content_stream(content); content_stream >> ch; if (ch != '*') { if (ch == '[') { // content_stream.putback (ch); // content_stream >> ch; string inner_string; getline(content_stream, inner_string, ']'); std::istringstream inner_string_stream(inner_string); Array values; Array strings; string cur; while (getline(inner_string_stream, cur, ',')) { char* endptr; double vald = strtod (cur.c_str(), &endptr); if (endptr != cur.c_str() && strings.Size() == 0) values.Append(vald); else strings.Append(cur); } if (strings.Size() > 0) SetFlag(name, strings); else SetFlag(name, values); } else { if(content == "_TRUE" || content == "_FALSE") { SetFlag(name, (content =="_TRUE") ? true : false); continue; } char* endptr; double vald = strtod (content.c_str(), &endptr); if (endptr != content.c_str()) SetFlag (name, vald); else SetFlag (name, content); } } else { content_stream.clear(); content_stream >> str; if (sf) SetFlag (name, (*sf)[str]); else throw Exception (" no symboltable of flags "); } } } } void Flags :: DoArchive(Archive & archive) { archive & strflags & numflags & defflags & numlistflags & strlistflags & flaglistflags & anyflags; } void Flags :: Update(const Flags& other) { strflags.Update(other.strflags); numflags.Update(other.numflags); defflags.Update(other.defflags); numlistflags.Update(other.numlistflags); strlistflags.Update(other.strlistflags); flaglistflags.Update(other.flaglistflags); } void Flags :: SetCommandLineFlag (const char * st, SymbolTable * sf ) { //cout << "SetCommandLineFlag: flag = " << st << endl; std::istringstream inst( (char *)st); char name[100]; double val; if (st[0] != '-') { std::cerr << "flag must start with '-'" << endl; return; } // flag with double -- if (st[1] == '-') st++; const char * pos = strchr (st, '='); const char * posstar = strchr (st, '*'); const char * posbrack = 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; cout << "isfinite = " << std::isfinite (val) << endl; cout << "isinf = " << std::isinf (val) << endl; cout << "pos = " << pos << ", endpos = " << endptr << endl; */ if (endptr != pos && !std::isfinite (val)) endptr = const_cast(pos); /* #ifdef WIN32 if(endptr != pos && !_finite(val)) endptr = const_cast(pos); #else #ifdef MACOS if(endptr != pos && (__isnand(val) || __isinfd(val))) endptr = const_cast(pos); #else #ifdef SUN #else if(endptr != pos && (std::isnan(val) || std::isinf(val))) endptr = const_cast(pos); #endif #endif #endif */ //cout << "val = " << val << endl; if (!posbrack) { if (posstar) { pos++; if (sf) SetFlag (name, (*sf)[pos]); else throw Exception (" no symboltable of flags "); } else if (endptr == pos) { // string-flag //(cout) << "Add String Flag: " << name << " = " << pos << endl; SetFlag (name, pos); } else { // num-flag //(cout) << "Add Num Flag: " << name << " = " << val << endl; SetFlag (name, val); } } else { // list-flag char hc; double val; val = strtod (posbrack+1, &endptr); if (endptr != posbrack+1) { Array values; std::istringstream ist(posbrack); ist >> hc; // '[' ist >> val; while (ist.good()) { values.Append (val); ist >> hc; // ',' ist >> val; } SetFlag (name, values); } else { // to be cleaned up ... Array strs; posbrack++; char * hstr = new char[strlen(posbrack)+1]; strcpy (hstr, posbrack); char * chp = hstr; bool start = 1; while (*chp && *chp != ']') { if (start) strs.Append (chp); start = 0; if (*chp == ',') { *chp = 0; start = 1; } chp++; } *chp = 0; Array strings; for (int i = 0; i < strs.Size(); i++) strings.Append (string (strs[i])); SetFlag (name, strings); delete [] hstr; } } } } } // namespace ngcore ================================================ FILE: libsrc/core/flags.hpp ================================================ #ifndef NETGEN_CORE_FLAGS_HPP #define NETGEN_CORE_FLAGS_HPP /**************************************************************************/ /* File: flags.hpp */ /* Author: Joachim Schoeberl */ /* Date: 10. Oct. 96 */ /**************************************************************************/ #include #include #include #include #include "array.hpp" #include "symboltable.hpp" #include "xbool.hpp" namespace ngcore { /** A storage for command-line flags. The flag structure maintains string flags, numerical flags, define flags, string list flags, num list flags. */ class NGCORE_API Flags { /// string flags SymbolTable strflags; /// numerical flags SymbolTable numflags; /// define flags SymbolTable defflags; /// string list flags SymbolTable>> strlistflags; /// numerical list flags SymbolTable>> numlistflags; /// flags list flags SymbolTable flaglistflags; /// any object can be stored as a flag SymbolTable anyflags; public: /// no flags Flags (); /// copy flags Flags (const Flags & flags); /// steal flags Flags (Flags && flags) = default; /// Flags (std::initializer_list list); /// Flags (std::string f1, std::string f2 = "", std::string f3 = "", std::string f4 = "", std::string f5 = ""); /// delete mem ~Flags (); Flags & operator= (const Flags & f2) = default; Flags & operator= (Flags && f2) = default; void DoArchive(class Archive& ar); void Update(const Flags& other); /// Deletes all flags void DeleteFlags (); /// Sets string flag, overwrite if exists Flags & SetFlag (const char * name, const std::string & val); /// Sets string flag, overwrite if exists Flags & SetFlag (const char * name, const char * str) { return SetFlag (name, std::string(str)); } /// Sets numerical flag, overwrite if exists Flags & SetFlag (const char * name, double val) &; /// Sets numerical flag, overwrite if exists Flags & SetFlag (const char * name, int val) { return SetFlag (name, double(val)); } /// Sets boolean flag Flags & SetFlag (const char * name, bool b = true) &; /// Sets numerical flag, overwrite if exists Flags & SetFlag (const char * name, Flags & val) &; /// Sets string flag, overwrite if exists Flags & SetFlag (const std::string & name, const std::string & val); Flags & SetFlag (const std::string & name, const char * str) { return SetFlag (name, std::string(str)); } /// Sets numerical flag, overwrite if exists Flags & SetFlag (const std::string & name, double val); /// Sets numerical flag, overwrite if exists Flags & SetFlag (const std::string & name, int val) { return SetFlag (name, double(val)); } /// Sets boolean flag Flags & SetFlag (const std::string & name, bool b = true); /// Sets numerical flag, overwrite if exists Flags & SetFlag (const std::string & name, Flags & val); /// Sets string array flag Flags & SetFlag (const std::string & name, const Array & val); /// Sets double array flag Flags & SetFlag (const std::string & name, const Array & val); /// Sets any flag Flags & SetFlag(const std::string& name, const std::any& val); Flags SetFlag (const char * name, bool b = true) &&; Flags SetFlag (const char * name, double val) &&; /// Save flags to file void SaveFlags (const char * filename) const; void SaveFlags (ostream & str) const; /// write flags to stream void PrintFlags (ostream & ost) const; /// Load flags from file void LoadFlags (const char * filename, SymbolTable * sf = nullptr); void LoadFlags (std::istream & str, SymbolTable * sf = nullptr); /** Set command line flag. Flag must be in form: -name=hello -val=0.5 -defflag -names=[Joe,Jim] -values=[1,3,4] -solverflags=*abc */ void SetCommandLineFlag (const char * st, SymbolTable * sf = nullptr); /// Returns string flag, default value if not exists std::string GetStringFlag (const std::string & name, const char * def) const; /// Returns std::string flag, default value if not exists std::string GetStringFlag (const std::string & name, std::string def = "") const; /// Returns numerical flag, default value if not exists double GetNumFlag (std::string_view name, double def) const; /// Returns address of numerical flag, null if not exists const double * GetNumFlagPtr (std::string_view name) const; /// Returns address of numerical flag, null if not exists double * GetNumFlagPtr (const std::string & name); /// Returns boolean flag // int GetDefineFlag (const char * name) const; bool GetDefineFlag (std::string_view name) const noexcept; xbool GetDefineFlagX (std::string_view name) const noexcept; /// Returns string list flag, empty array if not exist const Array & GetStringListFlag (const std::string & name) const; /// Returns num list flag, empty array if not exist const Array & GetNumListFlag (const std::string & name) const; /// Returns flag list flag, empty flag if not exist const Flags & GetFlagsFlag (const std::string & name) const; const std::any& GetAnyFlag (const std::string& name) const; /// Test, if string flag is defined bool StringFlagDefined (std::string_view name) const noexcept; /// Test, if num flag is defined bool NumFlagDefined (std::string_view name) const noexcept; /// Test, if num flag is defined bool FlagsFlagDefined (std::string_view name) const noexcept; /// Test, if string list flag is defined bool StringListFlagDefined (std::string_view name) const noexcept; /// Test, if num list flag is defined bool NumListFlagDefined (std::string_view name) const noexcept; bool AnyFlagDefined (std::string_view name) const noexcept; /// number of string flags int GetNStringFlags () const { return strflags.Size(); } /// number of num flags int GetNNumFlags () const { return numflags.Size(); } /// number of num flags int GetNFlagsFlags () const { return flaglistflags.Size(); } /// number of define flags int GetNDefineFlags () const { return defflags.Size(); } /// number of string-list flags int GetNStringListFlags () const { return strlistflags.Size(); } /// number of num-list flags int GetNNumListFlags () const { return numlistflags.Size(); } int GetNAnyFlags() const { return anyflags.Size(); } /// const std::string & GetStringFlag (int i, std::string & name) const { name = strflags.GetName(i); return strflags[i]; } double GetNumFlag (int i, std::string & name) const { name = numflags.GetName(i); return numflags[i]; } bool GetDefineFlag (int i, std::string & name) const { name = defflags.GetName(i); return defflags[i]; } const std::shared_ptr> GetNumListFlag (int i, std::string & name) const { name = numlistflags.GetName(i).c_str(); return numlistflags[i]; } const std::shared_ptr> GetStringListFlag (int i, std::string & name) const { name = strlistflags.GetName(i); return strlistflags[i]; } const Flags & GetFlagsFlag (int i, std::string & name) const { name = flaglistflags.GetName(i); return flaglistflags[i]; } const std::any& GetAnyFlag(int i, std::string& name) const { name = anyflags.GetName(i); return anyflags[i]; } }; /// Print flags inline std::ostream & operator<< (std::ostream & s, const Flags & flags) { flags.PrintFlags (s); return s; } } // namespace ngcore #endif // NETGEN_CORE_FLAGS_HPP ================================================ FILE: libsrc/core/generate_mpi_sources.py ================================================ functions = [ ("double", "MPI_Wtime"), ("int", "MPI_Allgather", "void*", "int", "MPI_Datatype", "void*", "int", "MPI_Datatype", "MPI_Comm"), ("int", "MPI_Allreduce", "void*", "void*", "int", "MPI_Datatype", "MPI_Op", "MPI_Comm"), ("int", "MPI_Alltoall", "void*", "int", "MPI_Datatype", "void*", "int", "MPI_Datatype", "MPI_Comm"), ("int", "MPI_Barrier", "MPI_Comm"), ("int", "MPI_Bcast", "void*", "int", "MPI_Datatype", "int", "MPI_Comm"), ("int", "MPI_Ibcast", "void*", "int", "MPI_Datatype", "int", "MPI_Comm", "MPI_Request*"), ("int", "MPI_Comm_c2f", "MPI_Comm"), ("int", "MPI_Comm_create", "MPI_Comm", "MPI_Group", "MPI_Comm*"), ("int", "MPI_Comm_create_group", "MPI_Comm", "MPI_Group", "int", "MPI_Comm*"), ("int", "MPI_Comm_free", "MPI_Comm*"), ("int", "MPI_Comm_group", "MPI_Comm", "MPI_Group*"), ("int", "MPI_Comm_rank", "MPI_Comm", "int*"), ("int", "MPI_Comm_size", "MPI_Comm", "int*"), ("int", "MPI_Finalize"), ("int", "MPI_Gather", "void*", "int", "MPI_Datatype", "void*", "int", "MPI_Datatype", "int", "MPI_Comm"), ("int", "MPI_Gatherv", "void*", "int", "MPI_Datatype", "void*", "int*", "int*", "MPI_Datatype", "int", "MPI_Comm"), ("int", "MPI_Get_count", "MPI_Status*", "MPI_Datatype", "int*"), ("int", "MPI_Get_processor_name", "char*", "int*"), ("int", "MPI_Group_incl", "MPI_Group", "int", "int*", "MPI_Group*"), ("int", "MPI_Init", "int*", "char***"), ("int", "MPI_Init_thread", "int*", "char***", "int", "int*"), ("int", "MPI_Initialized", "int*"), ("int", "MPI_Iprobe", "int", "int", "MPI_Comm", "int*", "MPI_Status*"), ("int", "MPI_Irecv", "void*", "int", "MPI_Datatype", "int", "int", "MPI_Comm", "MPI_Request*"), ("int", "MPI_Isend", "void*", "int", "MPI_Datatype", "int", "int", "MPI_Comm", "MPI_Request*"), ("int", "MPI_Probe", "int", "int", "MPI_Comm", "MPI_Status*"), ("int", "MPI_Query_thread", "int*"), ("int", "MPI_Recv", "void*", "int", "MPI_Datatype", "int", "int", "MPI_Comm", "MPI_Status*"), ("int", "MPI_Recv_init", "void*", "int", "MPI_Datatype", "int", "int", "MPI_Comm", "MPI_Request*"), ("int", "MPI_Reduce", "void*", "void*", "int", "MPI_Datatype", "MPI_Op", "int", "MPI_Comm"), ("int", "MPI_Reduce_local", "void*", "void*", "int", "MPI_Datatype", "MPI_Op"), ("int", "MPI_Request_free", "MPI_Request*"), ("int", "MPI_Scatter", "void*", "int", "MPI_Datatype", "void*", "int", "MPI_Datatype", "int", "MPI_Comm"), ("int", "MPI_Send", "void*", "int", "MPI_Datatype", "int", "int", "MPI_Comm"), ("int", "MPI_Send_init", "void*", "int", "MPI_Datatype", "int", "int", "MPI_Comm", "MPI_Request*"), ("int", "MPI_Startall", "int", "MPI_Request*:0"), ("int", "MPI_Type_commit", "MPI_Datatype*"), ("int", "MPI_Type_contiguous", "int", "MPI_Datatype", "MPI_Datatype*"), ("int", "MPI_Type_create_resized", "MPI_Datatype", "MPI_Aint", "MPI_Aint", "MPI_Datatype*"), ("int", "MPI_Type_create_struct", "int", "int*:0", "MPI_Aint*:0", "MPI_Datatype*:0", "MPI_Datatype*"), ("int", "MPI_Type_free", "MPI_Datatype*"), ("int", "MPI_Type_get_extent", "MPI_Datatype", "MPI_Aint*", "MPI_Aint*"), ("int", "MPI_Type_indexed", "int", "int*:0", "int*:0", "MPI_Datatype", "MPI_Datatype*"), ("int", "MPI_Type_size", "MPI_Datatype", "int*"), ("int", "MPI_Wait", "MPI_Request*", "MPI_Status*"), ("int", "MPI_Waitall", "int", "MPI_Request*:0", "MPI_Status*"), ("int", "MPI_Waitany", "int", "MPI_Request*:0", "int*", "MPI_Status*"), ] constants = [ ("MPI_Comm", "MPI_COMM_NULL"), ("MPI_Comm", "MPI_COMM_WORLD"), ("MPI_Datatype", "MPI_CHAR"), ("MPI_Datatype", "MPI_CXX_DOUBLE_COMPLEX"), ("MPI_Datatype", "MPI_C_BOOL"), ("MPI_Datatype", "MPI_DATATYPE_NULL"), ("MPI_Datatype", "MPI_DOUBLE"), ("MPI_Datatype", "MPI_FLOAT"), ("MPI_Datatype", "MPI_INT"), ("MPI_Datatype", "MPI_SHORT"), ("MPI_Datatype", "MPI_UINT64_T"), ("MPI_Op", "MPI_LOR"), ("MPI_Op", "MPI_MAX"), ("MPI_Op", "MPI_MIN"), ("MPI_Op", "MPI_SUM"), ("MPI_Request", "MPI_REQUEST_NULL"), ("MPI_Status*", "MPI_STATUSES_IGNORE"), ("MPI_Status*", "MPI_STATUS_IGNORE"), ("int", "MPI_ANY_SOURCE"), ("int", "MPI_ANY_TAG"), ("int", "MPI_MAX_PROCESSOR_NAME"), ("int", "MPI_PROC_NULL"), ("int", "MPI_ROOT"), ("int", "MPI_SUBVERSION"), ("int", "MPI_THREAD_MULTIPLE"), ("int", "MPI_THREAD_SINGLE"), ("int", "MPI_VERSION"), ("void*", "MPI_IN_PLACE"), ] def get_args(f, counts=False): args = [] for arg in f[2:]: has_count = ':' in arg if has_count: s, count = arg.split(':') count = int(count) else: s = arg count = None if s.startswith("MPI_"): s = "NG_" + s if counts: args.append((s, count)) else: args.append(s) return args def generate_declarations(): code = "" nowrapper_code = "" for f in functions: ret = f[0] name = f[1] args = ", ".join(get_args(f)) code += f"NGCORE_API extern {ret} (*NG_{name})({args});\n" nowrapper_code += f"#define NG_{name} {name}\n" for typ, name in constants: if typ.startswith("MPI_"): typ = "NG_" + typ code += f"NGCORE_API extern {typ} NG_{name};\n" nowrapper_code += f"#define NG_{name} {name}\n" with open("ng_mpi_generated_declarations.hpp", "w") as f: f.write("#ifdef NG_MPI_WRAPPER\n") f.write(code) f.write("#else // NG_MPI_WRAPPER\n") f.write(nowrapper_code) f.write("#endif // NG_MPI_WRAPPER\n") def generate_dummy_init(): code = "" for f in functions: ret = f[0] name = f[1] args = ", ".join(get_args(f)) code += f"decltype(NG_{name}) NG_{name} = []({args})->{ret} {{ throw no_mpi(); }};\n" for typ, name in constants: if typ.startswith("MPI_"): typ = "NG_" + typ code += f"{typ} NG_{name} = 0;\n" with open("ng_mpi_generated_dummy_init.hpp", "w") as f: f.write(code) def generate_init(): code = "" for f in functions: ret = f[0] name = f[1] args = get_args(f, counts=True) in_args ='' call_args = '' for i in range(len(args)): arg, count = args[i] if i > 0: in_args += ', ' call_args += ', ' in_args += arg + f" arg{i}" if not arg.startswith("NG_"): # plain type (like int, int *, etc.), just pass the argument along call_args += f" arg{i}" elif count is None: # MPI type (by value or pointer), but just one object, no arrays call_args += f" ng2mpi(arg{i})" else: # arrays of MPI types, we need to copy them due to incompatible size call_args += f" ng2mpi(arg{i}, arg{count})" code += f"NG_{name} = []({in_args})->{ret} {{ return {name}({call_args}); }};\n" for _, name in constants: code += f"NG_{name} = mpi2ng({name});\n" with open("ng_mpi_generated_init.hpp", "w") as f: f.write(code) if __name__ == "__main__": generate_declarations() generate_dummy_init() generate_init() ================================================ FILE: libsrc/core/hashtable.hpp ================================================ #ifndef FILE_NGSTD_HASHTABLE #define FILE_NGSTD_HASHTABLE /**************************************************************************/ /* File: hashtable.hpp */ /* Author: Joachim Schoeberl */ /* Date: 01. Jun. 95 */ /**************************************************************************/ #include #include #include // #include "mpi_wrapper.hpp" #include "ngcore_api.hpp" #include "table.hpp" #include "utils.hpp" namespace ngcore { template class MakeTupleFromInt { public: template auto operator()(I & i) { return tuple_cat(MakeTupleFromInt ()(i), std::tie(i[K-1])); } }; template <> class MakeTupleFromInt<1> { public: template auto operator()(I & i) { return std::tie(i[0]); } }; // feature check macro for transition from INT to IVec #define NGCORE_HAS_IVEC /// N integers template class IVec { /// data // T i[(N>0)?N:1]; HTArray i; public: /// constexpr IVec () = default; constexpr NETGEN_INLINE IVec (const IVec & i1) : i(i1.i) { } constexpr NETGEN_INLINE IVec (T ai1) : i(ai1) { } template = true> constexpr IVec (const T &v, T2... rest) : i{v,rest...} { } /* /// init all NETGEN_INLINE IVec (T ai1) { for (int j = 0; j < N; j++) { i[j] = ai1; } } /// init i[0], i[1] constexpr NETGEN_INLINE IVec (T ai1, T ai2) : i{ai1, ai2} { ; } /// init i[0], i[1], i[2] constexpr NETGEN_INLINE IVec (T ai1, T ai2, T ai3) : i{ai1, ai2, ai3} { ; } /// init i[0], i[1], i[2] constexpr NETGEN_INLINE IVec (T ai1, T ai2, T ai3, T ai4) : i{ai1, ai2, ai3, ai4} { ; } /// init i[0], i[1], i[2] constexpr NETGEN_INLINE IVec (T ai1, T ai2, T ai3, T ai4, T ai5) : i{ai1, ai2, ai3, ai4, ai5} { ; } /// init i[0], i[1], i[2] NETGEN_INLINE IVec (T ai1, T ai2, T ai3, T ai4, T ai5, T ai6, T ai7, T ai8, T ai9) : i{ai1, ai2, ai3, ai4, ai5, ai6, ai7, ai8, ai9 } { ; } */ template void DoArchive(ARCHIVE& ar) { // ar.Do(i.begin(), N); ar.Do(i.Ptr(), N); } template NETGEN_INLINE IVec (const IVec & in2) { if (N2 <= N) { for (int j = 0; j < N2; j++) i[j] = in2[j]; for (int j = N2; j < N; j++) i[j] = 0; } else { for (int j = 0; j < N; j++) i[j] = in2[j]; } } template NETGEN_INLINE IVec (const BaseArrayObject & ao) { for (int j = 0; j < N; j++) i[j] = ao.Spec()[j]; } NETGEN_INLINE size_t Size() const { return N; } /// all ints equal ? NETGEN_INLINE bool operator== (const IVec & in2) const { for (int j = 0; j < N; j++) if (i[j] != in2.i[j]) return 0; return 1; } /// any ints unequal ? NETGEN_INLINE bool operator!= (const IVec & in2) const { for (int j = 0; j < N; j++) if (i[j] != in2.i[j]) return 1; return 0; } /// sort integers NETGEN_INLINE IVec & Sort () & { for (int k = 0; k < N; k++) for (int l = k+1; l < N; l++) if (i[k] > i[l]) Swap (i[k], i[l]); return *this; } NETGEN_INLINE IVec Sort () && { for (int k = 0; k < N; k++) for (int l = k+1; l < N; l++) if (i[k] > i[l]) Swap (i[k], i[l]); return *this; } /// access NETGEN_INLINE T & operator[] (int j) { return i[j]; } /// access NETGEN_INLINE constexpr const T & operator[] (int j) const { return i[j]; } template constexpr T get() const { return i[J]; } operator FlatArray () { return FlatArray (N, i.Ptr()); } NETGEN_INLINE IVec & operator= (T value) { for (int j = 0; j < N; j++) i[j] = value; return *this; } template NETGEN_INLINE IVec & operator= (IVec v2) { for (int j = 0; j < N; j++) i[j] = v2[j]; return *this; } template operator std::tuple () { return MakeTupleFromInt()(*this); } bool Contains (T val) { for (int j = 0; j < N; j++) if (i[j] == val) return true; return false; } }; /// sort 2 integers template <> NETGEN_INLINE IVec<2> & IVec<2>::Sort () & { if (i[0] > i[1]) Swap (i[0], i[1]); return *this; } template <> NETGEN_INLINE IVec<2> IVec<2>::Sort () && { if (i[0] > i[1]) Swap (i[0], i[1]); return *this; } /// sort 3 integers template <> NETGEN_INLINE IVec<3> IVec<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; } /// Print integers template inline ostream & operator<<(ostream & s, const IVec & i2) { for (int j = 0; j < N; j++) s << (int) i2[j] << " "; return s; } template auto begin(const IVec & ind) { return AOWrapperIterator> (ind, 0); } template auto end(const IVec & ind) { return AOWrapperIterator> (ind, N); } template NETGEN_INLINE size_t HashValue (const IVec & ind, size_t size) { IVec lind = ind; size_t sum = 0; for (int i = 0; i < N; i++) sum += lind[i]; return sum % size; } /// hash value of 1 int template NETGEN_INLINE size_t HashValue (const IVec<1,TI> & ind, size_t size) { return ind[0] % size; } /// hash value of 2 int template NETGEN_INLINE size_t HashValue (const IVec<2,TI> & ind, size_t size) { IVec<2,size_t> lind = ind; return (113*lind[0]+lind[1]) % size; } /// hash value of 3 int template NETGEN_INLINE size_t HashValue (const IVec<3,TI> & ind, size_t size) { IVec<3,size_t> lind = ind; return (113*lind[0]+59*lind[1]+lind[2]) % size; } NETGEN_INLINE size_t HashValue (size_t ind, size_t size) { return ind%size; } NETGEN_INLINE size_t HashValue (int ind, size_t size) { return size_t(ind)%size; } template NETGEN_INLINE constexpr size_t HashValue2 (const IVec & ind, size_t mask) { IVec lind = ind; size_t sum = 0; for (int i = 0; i < N; i++) sum += lind[i]; return sum & mask; } /// hash value of 1 int template NETGEN_INLINE constexpr size_t HashValue2 (const IVec<1,TI> & ind, size_t mask) { return ind[0] & mask; } /// hash value of 2 int template NETGEN_INLINE constexpr size_t HashValue2 (const IVec<2,TI> & ind, size_t mask) { IVec<2,size_t> lind = ind; return (113*lind[0]+lind[1]) & mask; } /// hash value of 3 int template NETGEN_INLINE constexpr size_t HashValue2 (const IVec<3,TI> & ind, size_t mask) { IVec<3,size_t> lind = ind; return (113*lind[0]+59*lind[1]+lind[2]) & mask; } NETGEN_INLINE constexpr size_t HashValue2 (size_t ind, size_t mask) { return ind & mask; } NETGEN_INLINE constexpr size_t HashValue2 (int ind, size_t mask) { return size_t(ind) & mask; } // using ngstd::max; template NETGEN_INLINE T Max (const IVec & i) { if (D == 0) return 0; T m = i[0]; for (int j = 1; j < D; j++) if (i[j] > m) m = i[j]; return m; } template NETGEN_INLINE T Min (const IVec & i) { if (D == 0) return 0; T m = i[0]; for (int j = 1; j < D; j++) if (i[j] < m) m = i[j]; return m; } template NETGEN_INLINE IVec Max (IVec i1, IVec i2) { IVec tmp; for (int i = 0; i < D; i++) tmp[i] = std::max(i1[i], i2[i]); return tmp; } template NETGEN_INLINE IVec operator+ (IVec i1, IVec i2) { IVec tmp; for (int i = 0; i < D; i++) tmp[i] = i1[i]+i2[i]; return tmp; } /** A hash-table. Generic identifiers are mapped to the generic type T. An open hashtable. The table is implemented by a DynamicTable. Identifiers must provide a HashValue method. */ template class HashTable { /* DynamicTable hash; DynamicTable cont; */ DynamicTable> table; public: /// Constructs a hashtable of size bags. NETGEN_INLINE HashTable (int size) // : hash(size), cont(size) : table(size) { ; } NETGEN_INLINE ~HashTable () { ; } /// Sets identifier ahash to value acont void Set (const T_HASH & ahash, const T & acont) { int bnr = HashValue (ahash, Size()); int pos = CheckPosition (bnr, ahash); if (pos != -1) // cont.Set (bnr, pos, acont); table[bnr][pos].second = acont; else { // hash.Add (bnr, ahash); // cont.Add (bnr, acont); table.Add (bnr, std::make_pair(ahash, acont)); } } /// get value of identifier ahash, exception if unused const T & Get (const T_HASH & ahash) const { int bnr = HashValue (ahash, Size()); int pos = Position (bnr, ahash); // return cont.Get (bnr, pos); return table.Get (bnr, pos).second; } /// get value of identifier ahash, exception if unused const T & Get (int bnr, int pos) const { // return cont.Get (bnr, pos); return table.Get (bnr, pos).second; } /// is identifier used ? bool Used (const T_HASH & ahash) const { // return (CheckPosition (HashValue (ahash, hash.Size()), ahash) != -1); return (CheckPosition (HashValue (ahash, table.Size()), ahash) != -1); } /// is identifier used ? bool Used (const T_HASH & ahash, int & bnr, int & pos) const { // bnr = HashValue (ahash, hash.Size()); bnr = HashValue (ahash, Size()); pos = CheckPosition (bnr, ahash); return (pos != -1); } /// number of hash entries size_t Size () const { // return hash.Size(); return table.Size(); } /// size of hash entry size_t EntrySize (int bnr) const { // return hash[bnr].Size(); return table[bnr].Size(); } /// get identifier and value of entry bnr, position colnr void GetData (int bnr, int colnr, T_HASH & ahash, T & acont) const { // ahash = hash[bnr][colnr]; // acont = cont[bnr][colnr]; ahash = table[bnr][colnr].first; acont = table[bnr][colnr].second; } /// set identifier and value of entry bnr, position colnr void SetData (int bnr, int colnr, const T_HASH & ahash, const T & acont) { // hash[bnr][colnr] = ahash; // cont[bnr][colnr] = acont; table[bnr][colnr] = std::make_pair(ahash, acont); } /// returns position of index. returns -1 on unused int CheckPosition (int bnr, const T_HASH & ind) const { /* for (int i = 0; i < hash[bnr].Size(); i++) if (hash[bnr][i] == ind) return i; */ for (int i = 0; i < table[bnr].Size(); i++) if (table[bnr][i].first == ind) return i; return -1; } /// returns position of index. exception on unused int Position (int bnr, const T_HASH & ind) const { for (int i = 0; i < table[bnr].Size(); i++) if (table[bnr][i].first == ind) return i; throw Exception ("Ask for unused hash-value"); } T & operator[] (T_HASH ahash) { int bnr, pos; if (Used (ahash, bnr, pos)) return table[bnr][pos].second; else { // hash.Add (bnr, ahash); // cont.Add (bnr, T(0)); table.Add (bnr, std::make_pair(ahash, T(0))); // return cont[bnr][cont[bnr].Size()-1]; return table[bnr][table[bnr].Size()-1].second; } } const T & operator[] (T_HASH ahash) const { return Get(ahash); } class Iterator { const HashTable & ht; int bnr; int pos; public: Iterator (const HashTable & aht, int abnr, int apos) : ht(aht), bnr(abnr), pos(apos) { ; } std::pair operator* () const { T_HASH hash; T data; ht.GetData (bnr, pos, hash, data); return std::pair (hash, data); } Iterator & operator++() { pos++; if (pos == ht.EntrySize(bnr)) { pos = 0; bnr++; for ( ; bnr < ht.Size(); bnr++) if (ht.EntrySize(bnr) != 0) break; } return *this; } bool operator!= (const Iterator & it2) { return bnr != it2.bnr || pos != it2.pos; } }; Iterator begin () const { int i = 0; for ( ; i < Size(); i++) if (EntrySize(i) != 0) break; return Iterator(*this, i,0); } Iterator end () const { return Iterator(*this, Size(),0); } }; inline size_t RoundUp2 (size_t i) { size_t res = 1; while (res < i) res *= 2; // hope it will never be too large return res; } template constexpr inline T InvalidHash() { return T(-1); } template struct CHT_trait { constexpr static inline T_HASH Invalid() { return InvalidHash(); } constexpr static inline size_t HashValue (const T_HASH & hash, size_t mask) { return HashValue2(hash, mask); } }; template struct CHT_trait> { constexpr static inline std::tuple Invalid() { return { CHT_trait::Invalid(), CHT_trait::Invalid() } ; } constexpr static inline size_t HashValue (const std::tuple & hash, size_t mask) { return (CHT_trait::HashValue(std::get<0>(hash), mask) + CHT_trait::HashValue(std::get<1>(hash),mask)) & mask; } }; /** A closed hash-table. All information is stored in one fixed array. The array should be allocated with the double size of the expected number of entries. */ template class ClosedHashTable { protected: /// size_t size; size_t mask; /// size_t used = 0; /// Array hash; /// Array cont; /// // T_HASH invalid = -1; // static constexpr T_HASH invalid = InvalidHash(); static constexpr T_HASH invalid = CHT_trait::Invalid(); public: /// ClosedHashTable (size_t asize = 128) : size(RoundUp2(asize)), hash(size), cont(size) { mask = size-1; // hash = T_HASH(invalid); // hash = InvalidHash(); hash = CHT_trait::Invalid(); } ClosedHashTable (ClosedHashTable && ht2) = default; /// allocate on local heap ClosedHashTable (size_t asize, LocalHeap & lh) : size(RoundUp2(asize)), mask(size-1), hash(size, lh), cont(size, lh) { // hash = T_HASH(invalid); hash = InvalidHash(); } ClosedHashTable & operator= (ClosedHashTable && ht2) = default; /// size_t Size() const { return size; } /// is position used bool UsedPos (size_t pos) const { return ! (hash[pos] == invalid); } /// number of used elements size_t UsedElements () const { return used; } size_t Position (const T_HASH ind) const { // size_t i = HashValue2(ind, mask); size_t i = CHT_trait::HashValue(ind, mask); while (true) { if (hash[i] == ind) return i; if (hash[i] == invalid) return size_t(-1); i = (i+1) & mask; } } void DoubleSize() { ClosedHashTable tmp(2*Size()); for (auto both : *this) tmp[both.first] = both.second; *this = std::move(tmp); } // returns true if new position is created bool PositionCreate (const T_HASH ind, size_t & apos) { if (UsedElements()*2 > Size()) DoubleSize(); // size_t i = HashValue2 (ind, mask); size_t i = CHT_trait::HashValue (ind, mask); while (true) { if (hash[i] == invalid) { hash[i] = ind; apos = i; used++; return true; } if (hash[i] == ind) { apos = i; return false; } i = (i+1) & mask; } } /// void Set (const T_HASH & ahash, const T & acont) { size_t pos; PositionCreate (ahash, pos); hash[pos] = ahash; cont[pos] = acont; } /// const T & Get (const T_HASH & ahash) const { size_t pos = Position (ahash); if (pos == size_t(-1)) throw Exception (std::string("illegal key: ") + ToString(ahash) ); return cont[pos]; } /// bool Used (const T_HASH & ahash) const { return (Position (ahash) != size_t(-1)); } inline std::optional GetIfUsed (const T_HASH & ahash) const { size_t pos = Position (ahash); if (pos != size_t(-1)) return cont[pos]; else return std::nullopt; } void SetData (size_t pos, const T_HASH & ahash, const T & acont) { hash[pos] = ahash; cont[pos] = acont; } void GetData (size_t pos, T_HASH & ahash, T & acont) const { ahash = hash[pos]; acont = cont[pos]; } void SetData (size_t pos, const T & acont) { cont[pos] = acont; } void GetData (size_t pos, T & acont) const { acont = cont[pos]; } T GetData (size_t pos) const { return cont[pos]; } std::pair GetBoth (size_t pos) const { return std::pair (hash[pos], cont[pos]); } const T & operator[] (T_HASH key) const { return Get(key); } T & operator[] (T_HASH key) { size_t pos; PositionCreate(key, pos); return cont[pos]; } void SetSize (size_t asize) { size = asize; hash.Alloc(size); cont.Alloc(size); // for (size_t i = 0; i < size; i++) // hash[i] = invalid; hash = T_HASH(invalid); } void Delete (T_HASH key) { size_t pos = Position(key); if (pos == size_t(-1)) return; hash[pos] = invalid; used--; while (1) { size_t nextpos = pos+1; if (nextpos == size) nextpos = 0; if (hash[nextpos] == invalid) break; auto key = hash[nextpos]; auto val = cont[nextpos]; hash[pos] = invalid; used--; Set (key, val); pos = nextpos; } } void DeleteData() { hash = T_HASH(invalid); used = 0; } template void DoArchive (ARCHIVE& ar) { ar & hash & cont; ar & size & mask & used; } struct EndIterator { }; class Iterator { const ClosedHashTable & tab; size_t nr; public: Iterator (const ClosedHashTable & _tab, size_t _nr) : tab(_tab), nr(_nr) { while (nr < tab.Size() && !tab.UsedPos(nr)) nr++; } Iterator & operator++() { nr++; while (nr < tab.Size() && !tab.UsedPos(nr)) nr++; return *this; } bool operator!= (EndIterator it2) { return nr != tab.Size(); } auto operator* () const { return tab.GetBoth(nr); } }; Iterator begin() const { return Iterator(*this, 0); } EndIterator end() const { return EndIterator(); } }; template ostream & operator<< (ostream & ost, const ClosedHashTable & tab) { /* for (size_t i = 0; i < tab.Size(); i++) if (tab.UsedPos(i)) { T_HASH key; T val; tab.GetData (i, key, val); ost << key << ": " << val << ", "; } */ for (auto [key,val] : tab) ost << key << ": " << val << ", "; return ost; } template NETGEN_INLINE size_t HashValue (const IVec<3,TI> ind) { IVec<3,size_t> lind = ind; return 113*lind[0]+59*lind[1]+lind[2]; } template NETGEN_INLINE size_t HashValue (const IVec<2,TI> ind) { IVec<2,size_t> lind = ind; return 113*lind[0]+lind[1]; } template NETGEN_INLINE size_t HashValue (const IVec<1,TI> ind) { return ind[0]; } template class ParallelHashTable { class ClosedHT { Array keys; Array values; size_t used; public: ClosedHT(size_t asize = 256) : keys(asize), values(asize), used(0) { keys = TKEY(-1); } size_t Size () const { return keys.Size(); } size_t Used () const { return used; } ClosedHT & operator= (ClosedHT&&) = default; void Resize() { ClosedHT tmp(keys.Size()*2); for (size_t i = 0; i < keys.Size(); i++) if (keys[i] != TKEY(-1)) { TKEY hkey = keys[i]; T hval = values[i]; size_t hhash = HashValue(hkey); size_t hhash2 = hhash / 256; tmp.DoSave(hkey, [hval] (T & v) { v = hval; }, hhash2); } (*this) = std::move(tmp); } template auto Do (TKEY key, TFUNC func, size_t hash) { if (used > keys.Size()/2) Resize(); return DoSave (key, func, hash); } template auto DoSave (TKEY key, TFUNC func, size_t hash) { size_t pos = hash & (keys.Size()-1); while (1) { if (keys[pos] == key) break; if (keys[pos] == TKEY(-1)) { keys[pos] = key; values[pos] = T(0); used++; break; } pos++; if (pos == keys.Size()) pos = 0; } return func(values[pos]); } T Get (TKEY key, size_t hash) { size_t pos = hash & (keys.Size()-1); while (1) { if (keys[pos] == key) return values[pos]; if (keys[pos] == TKEY(-1)) throw Exception ("ParallelHashTable::Get of unused key"); pos++; if (pos == keys.Size()) pos = 0; } } size_t GetCosts (TKEY key, size_t hash) { size_t pos = hash & (keys.Size()-1); size_t costs = 1; while (1) { if (keys[pos] == key) return costs; if (keys[pos] == TKEY(-1)) throw Exception ("ParallelHashTable::Get of unused key"); costs++; pos++; if (pos == keys.Size()) pos = 0; } } template void Iterate (TFUNC func) const { for (size_t i = 0; i < keys.Size(); i++) if (keys[i] != TKEY(-1)) func(keys[i], values[i]); } void Print (ostream & ost) const { for (size_t i = 0; i < keys.Size(); i++) if (keys[i] != TKEY(-1)) ost << keys[i] << ": " << values[i] << ", "; } }; Array hts; class alignas(64) MyMutex64 : public MyMutex { }; Array locks; public: ParallelHashTable() : hts(256), locks(256) { ; } size_t NumBuckets() const { return hts.Size(); } auto & Bucket(size_t nr) { return hts[nr]; } size_t BucketSize(size_t nr) const { return hts[nr].Size(); } size_t Used (size_t nr) const { return hts[nr].Used(); } size_t Used() const { size_t used = 0; for (auto & ht : hts) used += ht.Used(); return used; } template auto Do (TKEY key, TFUNC func) { size_t hash = HashValue(key); size_t hash1 = hash % 256; size_t hash2 = hash / 256; // locks[hash1].lock(); // hts[hash1].Do (key, func, hash2); // locks[hash1].unlock(); MyLock lock(locks[hash1]); return hts[hash1].Do (key, func, hash2); } T Get (TKEY key) { size_t hash = HashValue(key); size_t hash1 = hash % 256; size_t hash2 = hash / 256; return hts[hash1].Get (key, hash2); } auto GetCosts (TKEY key) { size_t hash = HashValue(key); size_t hash1 = hash % 256; size_t hash2 = hash / 256; return hts[hash1].GetCosts (key, hash2); } template void Iterate(TFUNC func) const { for (auto & bucket : hts) bucket.Iterate(func); } template void Iterate(size_t nr, TFUNC func) const { hts[nr].Iterate(func); } template void IterateParallel (FUNC func) { Array base(NumBuckets()); size_t sum = 0; for (size_t i = 0; i < NumBuckets(); i++) { base[i] = sum; sum += Used(i); } ParallelFor(NumBuckets(), [&] (size_t nr) { size_t cnt = base[nr]; Iterate(nr, [&cnt, func] (TKEY key, T val) { func(cnt, key, val); cnt++; }); }); } void Print (ostream & ost) const { for (size_t i : Range(hts)) if (hts[i].Used() > 0) { ost << i << ": "; hts[i].Print(ost); } } }; template inline ostream & operator<< (ostream & ost, const ParallelHashTable & ht) { ht.Print(ost); return ost; } template class CompressedTable { Table table; ClosedHashTable idmap; public: CompressedTable (Table && atable, ClosedHashTable && aidmap) : table(std::move(atable)), idmap(std::move(aidmap)) { } FlatArray operator[](IndexType id) const { if (auto nr = idmap.GetIfUsed(id)) return table[*nr]; else return { 0, nullptr }; } auto & GetTable() { return table; } }; template class CompressedTableCreator { protected: int mode; // 1 .. cnt, 2 .. cnt entries, 3 .. fill table size_t nd; // number of entries; ClosedHashTable idmap; Array cnt; Table table; public: CompressedTableCreator() { nd = 0; mode = 1; } CompressedTable MoveTable() { return { std::move(table), std::move(idmap) }; } bool Done () { return mode > 3; } void operator++(int) { SetMode (mode+1); } int GetMode () const { return mode; } void SetMode (int amode) { mode = amode; if (mode == 2) { cnt.SetSize(nd); cnt = 0; } if (mode == 3) { table = Table (cnt); cnt = 0; } } void Add (IndexType blocknr, const T & data) { switch (mode) { case 1: { if (!idmap.Used (blocknr)) idmap[blocknr] = nd++; break; } case 2: cnt[idmap.Get(blocknr)]++; break; case 3: size_t cblock = idmap.Get(blocknr); int ci = cnt[cblock]++; table[cblock][ci] = data; break; } } }; } // namespace ngcore /* #ifdef PARALLEL namespace ngcore { template class MPI_typetrait > { public: /// gets the MPI datatype static MPI_Datatype MPIType () { static MPI_Datatype MPI_T = 0; if (!MPI_T) { MPI_Type_contiguous ( S, MPI_typetrait::MPIType(), &MPI_T); MPI_Type_commit ( &MPI_T ); } return MPI_T; } }; } #endif */ namespace ngcore { template struct MPI_typetrait; template struct MPI_typetrait > { static auto MPIType () { return MPI_typetrait>::MPIType(); } }; } namespace std { // structured binding support template struct tuple_size> : std::integral_constant {}; template struct tuple_element> { using type = T; }; } #endif ================================================ FILE: libsrc/core/localheap.cpp ================================================ /**************************************************************************/ /* File: localheap.cpp */ /* Author: Joachim Schoeberl */ /* Date: 19. Apr. 2002 */ /**************************************************************************/ #include #include #include "localheap.hpp" #include "taskmanager.hpp" namespace ngcore { LocalHeap :: LocalHeap (size_t asize, const char * aname, bool mult_by_threads) { if (mult_by_threads) asize *= TaskManager::GetMaxThreads(); totsize = asize; try { data = new char[asize]; } catch (std::exception & e) { throw Exception (ToString ("Could not allocate localheap, heapsize = ") + ToString(asize)); } next = data + totsize; p = data; owner = true; name = aname; CleanUp(); // align pointer } LocalHeap LocalHeap :: Split() const { int pieces = TaskManager::GetNumThreads(); int i = TaskManager::GetThreadId(); size_t freemem = totsize - (p - data); size_t size_of_piece = freemem / pieces; return LocalHeap (p + i * size_of_piece, size_of_piece, name); } void LocalHeap :: ThrowException() // throw (LocalHeapOverflow) { /* cout << "allocated: " << (p-data) << endl; cout << "throw LocalHeapOverflow, totsize = "<< totsize << endl; cout << "heap name = " << name << endl; */ throw LocalHeapOverflow(totsize); } LocalHeapOverflow :: LocalHeapOverflow (size_t size) : Exception("Local Heap overflow\n") { std::stringstream str; str << "Current heapsize is " << size << '\n'; Append (str.str()); // Append ("please use 'define constant heapsize = xxx' with larger value\n"); } LocalHeapOverflow :: ~LocalHeapOverflow () { ; } } ================================================ FILE: libsrc/core/localheap.hpp ================================================ #ifndef NETGEN_CORE_LOCALHEAP_HPP #define NETGEN_CORE_LOCALHEAP_HPP /**************************************************************************/ /* File: localheap.hpp */ /* Author: Joachim Schoeberl */ /* Date: 19. Apr. 2000 */ /**************************************************************************/ #include #include "exception.hpp" #include "ngcore_api.hpp" #include "utils.hpp" namespace ngcore { class Allocator { public: virtual ~Allocator() {} virtual void * Alloc (size_t size) { return new char[size]; } virtual void Delete(void* p) { delete (char*) p; } virtual void ArrayDelete(void* p) { delete [] (char*) p; } }; static Allocator global_alloc; /** Exception on heap overflow. Thrown by allocation on LocalHeap. */ class NGCORE_API LocalHeapOverflow : public Exception { public: LocalHeapOverflow (size_t size); virtual ~LocalHeapOverflow (); }; /** Optimized memory handler. One block of data is organized as stack memory. One can allocate memory out of it. This increases the stack pointer. With \Ref{CleanUp}, the pointer is reset to the beginning or to a specific position. */ class LocalHeap : public Allocator { char * data; char * next; char * p; size_t totsize; public: bool owner; const char * name; #if defined(__MIC__) || defined (__AVX512F__) enum { ALIGN = 64 }; #else enum { ALIGN = 32 }; #endif public: /// Allocate one block of size asize. NGCORE_API LocalHeap (size_t asize, const char * aname = "noname", bool mult_by_threads = false); /// Use provided memory for the LocalHeap NETGEN_INLINE LocalHeap (char * adata, size_t asize, const char * aname = "noname") throw () { totsize = asize; data = adata; next = data + totsize; owner = 0; // p = data; name = aname; CleanUp(); } /* /// Use provided memory for the LocalHeap NETGEN_INLINE LocalHeap (const LocalHeap & lh2) : data(lh2.data), p(lh2.p), totsize(lh2.totsize), owner(false), name(lh2.name) { next = data + totsize; } */ NETGEN_INLINE LocalHeap (const LocalHeap & lh2) = delete; NETGEN_INLINE LocalHeap (LocalHeap && lh2) : data(lh2.data), p(lh2.p), totsize(lh2.totsize), owner(lh2.owner), name(lh2.name) { next = data + totsize; lh2.owner = false; } NETGEN_INLINE LocalHeap Borrow() { return LocalHeap (p, Available()); } NETGEN_INLINE LocalHeap & operator= (LocalHeap && lh2) { if (owner) delete [] data; data = lh2.data; p = lh2.p; totsize = lh2.totsize; owner = lh2.owner; name = lh2.name; next = data + totsize; lh2.owner = false; return *this; } NETGEN_INLINE LocalHeap () : data(nullptr), next(nullptr), p(nullptr), totsize(0), owner(false) { ; } /// free memory virtual ~LocalHeap () { if (owner) delete [] data; } /// delete all memory on local heap NETGEN_INLINE void CleanUp() throw () { p = data; // p += (16 - (long(p) & 15) ); p += (ALIGN - (size_t(p) & (ALIGN-1) ) ); } /// returns heap-pointer NETGEN_INLINE void * GetPointer () throw () { return p; } /// deletes memory back to heap-pointer NETGEN_INLINE void CleanUp (void * addr) throw () { p = (char*)addr; } /// allocates size bytes of memory from local heap void * Alloc (size_t size) final // throw (LocalHeapOverflow) { char * oldp = p; // 16 byte alignment size += (ALIGN - size % ALIGN); p += size; // if ( size_t(p - data) >= totsize ) #ifndef FULLSPEED if (likely(p >= next)) ThrowException(); #endif return oldp; } /// allocates size objects of type T on local heap template T * Alloc (size_t size) // throw (LocalHeapOverflow) { char * oldp = p; size *= sizeof (T); // 16 byte alignment size += (ALIGN - size % ALIGN); p += size; #ifndef FULLSPEED if (likely(p >= next)) ThrowException(); #endif return reinterpret_cast (oldp); } virtual void Delete(void* /* p */) {} virtual void ArrayDelete(void* /* p */) {} private: /// #ifndef __CUDA_ARCH__ [[noreturn]] NGCORE_API void ThrowException(); #else NETGEN_INLINE void ThrowException() { ; } #endif public: /// free memory (dummy function) NETGEN_INLINE void Free (void * /* data */) throw () { ; } /// available memory on LocalHeap NETGEN_INLINE size_t Available () const throw () { return (totsize - (p-data)); } /// Split free memory on heap into pieces for each thread NGCORE_API LocalHeap Split () const; /// Split free memory on heap into pieces NETGEN_INLINE LocalHeap Split (int partnr, int nparts) const { int pieces = nparts; int i = partnr; size_t freemem = totsize - (p - data); size_t size_of_piece = freemem / pieces; return LocalHeap (p + i * size_of_piece, size_of_piece, name); } NETGEN_INLINE void ClearValues () { for (size_t i = 0; i < totsize; i++) data[i] = 47; } NETGEN_INLINE size_t UsedSize () { for (size_t i = totsize-1; i != 0; i--) if (data[i] != 47) return i; return 0; } }; /** Optimized memory handler. Provides static memory for the local heap. The template argument specifies the size in number of chars. */ template class LocalHeapMem : public LocalHeap { char mem[S]; public: NETGEN_INLINE LocalHeapMem (const char * aname) throw () : LocalHeap (mem, S, aname) { ; } }; /** A reset for the heap-pointer of a LocalHeap.. The constructor stores the heap-pointer, the constructor at the end of the regions resets the heap-pointer. */ class HeapReset { LocalHeap & lh; void * pointer; public: /// NETGEN_INLINE HeapReset (LocalHeap & alh) : lh(alh), pointer (alh.GetPointer()) { ; } /// NETGEN_INLINE ~HeapReset () { lh.CleanUp (pointer); } }; } NETGEN_INLINE void * operator new (size_t size, ngcore::Allocator & alloc) { return alloc.Alloc(size); } NETGEN_INLINE void * operator new [] (size_t size, ngcore::Allocator & alloc) { return alloc.Alloc(size); } NETGEN_INLINE void operator delete (void * p, ngcore::Allocator & lh) { lh.Delete(p); } NETGEN_INLINE void operator delete [] (void * p, ngcore::Allocator & lh) { lh.ArrayDelete(p); } #endif // NETGEN_CORE_LOCALHEAP_HPP ================================================ FILE: libsrc/core/logging.cpp ================================================ #include "logging.hpp" #include namespace ngcore { std::ostream* testout = new std::ostream(nullptr); // NOLINT level::level_enum Logger::global_level = level::warn; void Logger::log(level::level_enum level, std::string && s) { if(level>=global_level) std::clog << s << '\n'; } } //namespace ngcore namespace spdlog { class logger { public: logger() = default; }; } // namespace spdlog namespace ngcore { // Dummy functions if no spdlog is available std::shared_ptr GetLogger(const std::string& /*unused*/) { return std::make_shared(std::make_shared()); } void SetLoggingLevel(level::level_enum level, const std::string& /*unused*/) { Logger::SetGlobalLoggingLevel(level); } void AddFileSink(const std::string& /*unused*/, level::level_enum /*unused*/, const std::string& /*unused*/) {} void AddConsoleSink(level::level_enum /*unused*/, const std::string& /*unused*/) {} void ClearLoggingSinks(const std::string& /*unused*/) {} void FlushOnLoggingLevel(level::level_enum /*unused*/, const std::string& /*unused*/) {} } //namespace ngcore ================================================ FILE: libsrc/core/logging.hpp ================================================ #ifndef NETGEN_CORE_LOGGING_HPP #define NETGEN_CORE_LOGGING_HPP #include #include #include #include #include "exception.hpp" #include "ngcore_api.hpp" #include "utils.hpp" #ifndef NETGEN_DEBUG_LOG #define NETGEN_DEBUG_LOG(logger, ...) #endif // NETGEN_DEBUG_LOG namespace spdlog { class logger; } // namespace spdlog namespace ngcore { NGCORE_API extern std::ostream* testout; // NOLINT namespace level { enum level_enum { trace = 0, debug = 1, info = 2, warn = 3, err = 4, critical = 5, off = 6 }; } // namespace level class Logger { static NGCORE_API level::level_enum global_level; public: static auto SetGlobalLoggingLevel( level::level_enum level ) { auto oldval = global_level; global_level = level; return oldval; } std::shared_ptr logger; Logger(std::shared_ptr l) : logger(std::move(l)) {} void NGCORE_API log( level::level_enum level, std::string && s); template std::string replace(std::string s, const T & t) { auto p0 = s.find_first_of('{'); auto p1 = s.find_first_of('}', p0); if(p0==std::string::npos || p1==std::string::npos) throw Exception("invalid format string"); s.replace(p0, p1-p0+1, ToString(t)); return s; } std::string log_helper(std::string s) { return s; } template std::string log_helper(std::string s, const T &t) { return replace(s,t); } template std::string log_helper( std::string s, const T &t, Args ... args) { return log_helper(replace(s,t), args...); } template void log( level::level_enum level, const char* str, Args ... args) { log(level, log_helper(std::string(str), args...)); } template void trace( const char* str, Args ... args) { log(level::level_enum::trace, str, args...); } template void debug( const char* str, Args ... args) { log(level::level_enum::debug, str, args...); } template void info( const char* str, Args ... args) { log(level::level_enum::info, str, args...); } template void warn( const char* str, Args ... args) { log(level::level_enum::warn, str, args...); } template void error( const char* str, Args ... args) { log(level::level_enum::err, str, args...); } template void critical( const char* str, Args ... args) { log(level::level_enum::critical, str, args...); } }; NGCORE_API std::shared_ptr GetLogger(const std::string& name); NGCORE_API void SetLoggingLevel(level::level_enum level, const std::string& name); NGCORE_API void AddFileSink(const std::string& filename, level::level_enum level, const std::string& logger); NGCORE_API void AddConsoleSink(level::level_enum level, const std::string& logger); NGCORE_API void ClearLoggingSinks(const std::string& logger); NGCORE_API void FlushOnLoggingLevel(level::level_enum level, const std::string& logger); } // namespace ngcore #endif // NETGEN_CORE_LOGGING_HPP ================================================ FILE: libsrc/core/memtracer.hpp ================================================ #ifndef NETGEN_CORE_MEMTRACER_HPP #define NETGEN_CORE_MEMTRACER_HPP #include #include #include #include "array.hpp" #include "logging.hpp" #include "paje_trace.hpp" #include "utils.hpp" namespace ngcore { class MemoryTracer; namespace detail { //Type trait to check if a class implements a 'void SetMemoryTacing(int)' function template struct has_StartMemoryTracing { private: template static constexpr auto check(T2*) -> typename std::is_same().StartMemoryTracing()),void>::type; template static constexpr std::false_type check(...); using type = decltype(check(nullptr)); // NOLINT public: static constexpr bool value = type::value; }; } // namespace detail class MemoryTracer { #if defined(NETGEN_TRACE_MEMORY) && !defined(__CUDA_ARCH__) NGCORE_API static std::vector names; NGCORE_API static std::vector parents; #if defined(NETGEN_CHECK_RANGE) NGCORE_API static std::atomic total_memory; mutable size_t allocated_memory = 0; #endif // NETGEN_CHECK_RANGE static int CreateId(const std::string& name = "") { int id = names.size(); names.push_back(name); parents.push_back(0); if(id==10*8*1024) std::cerr << "Allocated " << id << " MemoryTracer objects" << std::endl; return id; } mutable int id = 0; public: MemoryTracer( std::string name ) { id = CreateId(name); } MemoryTracer() { } MemoryTracer(const MemoryTracer & tracer) { (*this) = tracer; } MemoryTracer(MemoryTracer && tracer) { (*this) = std::move(tracer); } MemoryTracer & operator=(const MemoryTracer & tracer) { if(tracer.id) id = CreateId(names[tracer.id]); return *this; } MemoryTracer & operator=(MemoryTracer && tracer) { ngcore::Swap(id, tracer.id); #if defined(NETGEN_CHECK_RANGE) ngcore::Swap(allocated_memory, tracer.allocated_memory); #endif // NETGEN_CHECK_RANGE return *this; } template MemoryTracer( std::string name, TRest & ... rest ) { id = CreateId(name); Track(rest...); } #if defined(NETGEN_CHECK_RANGE) // check if all memory was freed when object is destroyed ~MemoryTracer() { NETGEN_CHECK_SAME(allocated_memory, 0); } #endif // NETGEN_CHECK_RANGE NETGEN_INLINE void Alloc(size_t size) const { #if defined(NETGEN_CHECK_RANGE) // Trace also nameless Memtracer objects if range checks are active if(!id && size) id = CreateId(); #endif // NETGEN_CHECK_RANGE if(id && trace) trace->AllocMemory(id, size); #if defined(NETGEN_CHECK_RANGE) if(id) { allocated_memory += size; total_memory += size; } #endif // NETGEN_CHECK_RANGE } void Free(size_t size) const { if(id && trace) trace->FreeMemory(id, size); #if defined(NETGEN_CHECK_RANGE) if(id) { // check if we have at least size bytes of memory currently allocated (such that allocated_memory doesn't get negative) NETGEN_CHECK_RANGE(allocated_memory, static_cast(size), std::numeric_limits::max()); allocated_memory -= size; total_memory -= size; #endif // NETGEN_CHECK_RANGE } } int GetId() const { return id; } template void Track( T1 & obj, const std::string& name, TRest & ... rest ) const { Track(obj, name); Track(rest...); } template void Track( T & obj, const std::string& name ) const { obj.GetMemoryTracer().Activate(obj, name); parents[obj.GetMemoryTracer().GetId()] = id; } static std::string GetName(int id) { return names[id]; } std::string GetName() const { return names[id]; } template void Activate(T& me, const std::string& name) const { if(!id) { const_cast(this)->id = CreateId(name); if constexpr(detail::has_StartMemoryTracing::value) me.StartMemoryTracing(); } else SetName(name); } void SetName(const std::string& name) const { names[id] = name; } static const std::vector & GetNames() { return names; } static const std::vector & GetParents() { return parents; } static size_t GetTotalMemory() { #if defined(NETGEN_CHECK_RANGE) return total_memory; #else return 0; #endif // NETGEN_CHECK_RANGE } #else // defined(NETGEN_TRACE_MEMORY) && !defined(__CUDA_ARCH__) public: NETGEN_INLINE MemoryTracer() {} NETGEN_INLINE MemoryTracer( std::string /* name */ ) {} template NETGEN_INLINE MemoryTracer( std::string /* name */, TRest & ... ) {} NETGEN_INLINE void Alloc(size_t /* size */) const {} NETGEN_INLINE void Free(size_t /* size */) const {} NETGEN_INLINE int GetId() const { return 0; } template NETGEN_INLINE void Track(TRest&...) const {} static std::string GetName(int /* id */) { return ""; } std::string GetName() const { return ""; } void SetName(std::string /* name */) const {} static size_t GetTotalMemory() { return 0; } #endif // NETGEN_TRACE_MEMORY }; } // namespace ngcore #endif // NETGEN_CORE_MEMTRACER_HPP ================================================ FILE: libsrc/core/mpi4py_pycapi.h ================================================ /* Author: Lisandro Dalcin */ /* Contact: dalcinl@gmail.com */ #ifndef MPI4PY_PYCAPI_H #define MPI4PY_PYCAPI_H #include #include #define _mpi4py_declare_pycapi(Type, star) \ static PyTypeObject *_mpi4py_PyMPI##Type = NULL; \ static PyObject *(*_mpi4py_PyMPI##Type##_New)(MPI_##Type star) = NULL; \ static MPI_##Type *(*_mpi4py_PyMPI##Type##_Get)(PyObject *) = NULL; #ifndef MPI4PY_LIMITED_API_SKIP_DATATYPE _mpi4py_declare_pycapi(Datatype,) #define PyMPIDatatype_Type (*_mpi4py_PyMPIDatatype) #define PyMPIDatatype_New _mpi4py_PyMPIDatatype_New #define PyMPIDatatype_Get _mpi4py_PyMPIDatatype_Get #endif #ifndef MPI4PY_LIMITED_API_SKIP_STATUS _mpi4py_declare_pycapi(Status,*) #define PyMPIStatus_Type (*_mpi4py_PyMPIStatus) #define PyMPIStatus_New _mpi4py_PyMPIStatus_New #define PyMPIStatus_Get _mpi4py_PyMPIStatus_Get #endif #ifndef MPI4PY_LIMITED_API_SKIP_REQUEST _mpi4py_declare_pycapi(Request,) #define PyMPIRequest_Type (*_mpi4py_PyMPIRequest) #define PyMPIRequest_New _mpi4py_PyMPIRequest_New #define PyMPIRequest_Get _mpi4py_PyMPIRequest_Get #endif #ifndef MPI4PY_LIMITED_API_SKIP_MESSAGE _mpi4py_declare_pycapi(Message,) #define PyMPIMessage_Type (*_mpi4py_PyMPIMessage) #define PyMPIMessage_New _mpi4py_PyMPIMessage_New #define PyMPIMessage_Get _mpi4py_PyMPIMessage_Get #endif #ifndef MPI4PY_LIMITED_API_SKIP_OP _mpi4py_declare_pycapi(Op,) #define PyMPIOp_Type (*_mpi4py_PyMPIOp) #define PyMPIOp_New _mpi4py_PyMPIOp_New #define PyMPIOp_Get _mpi4py_PyMPIOp_Get #endif #ifndef MPI4PY_LIMITED_API_SKIP_GROUP _mpi4py_declare_pycapi(Group,) #define PyMPIGroup_Type (*_mpi4py_PyMPIGroup) #define PyMPIGroup_New _mpi4py_PyMPIGroup_New #define PyMPIGroup_Get _mpi4py_PyMPIGroup_Get #endif #ifndef MPI4PY_LIMITED_API_SKIP_INFO _mpi4py_declare_pycapi(Info,) #define PyMPIInfo_Type (*_mpi4py_PyMPIInfo) #define PyMPIInfo_New _mpi4py_PyMPIInfo_New #define PyMPIInfo_Get _mpi4py_PyMPIInfo_Get #endif #ifndef MPI4PY_LIMITED_API_SKIP_ERRHANDLER _mpi4py_declare_pycapi(Errhandler,) #define PyMPIErrhandler_Type (*_mpi4py_PyMPIErrhandler) #define PyMPIErrhandler_New _mpi4py_PyMPIErrhandler_New #define PyMPIErrhandler_Get _mpi4py_PyMPIErrhandler_Get #endif #ifndef MPI4PY_LIMITED_API_SKIP_SESSION _mpi4py_declare_pycapi(Session,) #define PyMPISession_Type (*_mpi4py_PyMPISession) #define PyMPISession_New _mpi4py_PyMPISession_New #define PyMPISession_Get _mpi4py_PyMPISession_Get #endif #ifndef MPI4PY_LIMITED_API_SKIP_COMM _mpi4py_declare_pycapi(Comm,) #define PyMPIComm_Type (*_mpi4py_PyMPIComm) #define PyMPIComm_New _mpi4py_PyMPIComm_New #define PyMPIComm_Get _mpi4py_PyMPIComm_Get #endif #ifndef MPI4PY_LIMITED_API_SKIP_WIN _mpi4py_declare_pycapi(Win,) #define PyMPIWin_Type (*_mpi4py_PyMPIWin) #define PyMPIWin_New _mpi4py_PyMPIWin_New #define PyMPIWin_Get _mpi4py_PyMPIWin_Get #endif #ifndef MPI4PY_LIMITED_API_SKIP_FILE _mpi4py_declare_pycapi(File,) #define PyMPIFile_Type (*_mpi4py_PyMPIFile) #define PyMPIFile_New _mpi4py_PyMPIFile_New #define PyMPIFile_Get _mpi4py_PyMPIFile_Get #endif #undef _mpi4py_define_pycapi static int _mpi4py_ImportType(PyObject *module, const char *type_name, PyTypeObject **type) { PyObject *attr = NULL; attr = PyObject_GetAttrString(module, type_name); if (!attr) goto fn_fail; if (!PyType_Check(attr)) { PyErr_Format(PyExc_TypeError, "%.200s.%.200s is not a type object", PyModule_GetName(module), type_name); goto fn_fail; } *type = (PyTypeObject *)attr; return 0; fn_fail: Py_DecRef(attr); return -1; } static int _mpi4py_ImportFunc(PyObject *module, const char *func_name, const char *signature, void (**func)(void)) { PyObject *pyxcapi = NULL; PyObject *capsule = NULL; union { void *obj; void (*fcn)(void); } ptr; pyxcapi = PyObject_GetAttrString(module, (char *)"__pyx_capi__"); if (!pyxcapi) goto fn_fail; capsule = PyDict_GetItemString(pyxcapi, func_name); if (!capsule) { PyErr_Format(PyExc_ImportError, "%.200s does not export expected C function %.200s", PyModule_GetName(module), func_name); goto fn_fail; } if (!PyCapsule_CheckExact(capsule)) { PyErr_Format(PyExc_TypeError, "%.200s.%.200s is not a capsule", PyModule_GetName(module), func_name); } if (!signature) { signature = PyCapsule_GetName(capsule); } if (!PyCapsule_IsValid(capsule, signature)) { PyErr_Format(PyExc_TypeError, "C function %.200s.%.200s has wrong signature " "(expected %.500s, got %.500s)", PyModule_GetName(module), func_name, signature, PyCapsule_GetName(capsule)); goto fn_fail; } ptr.obj = PyCapsule_GetPointer(capsule, signature); if (!ptr.obj) goto fn_fail; *func = ptr.fcn; Py_DecRef(pyxcapi); return 0; fn_fail: Py_DecRef(pyxcapi); return -1; } static int import_mpi4py_MPI(void) { PyObject *module = PyImport_ImportModule("mpi4py.MPI"); if (!module) goto fn_fail; #define _mpi4py_import_pycapi(Type) do { \ if (_mpi4py_ImportType(module, #Type, &_mpi4py_PyMPI##Type) < 0) \ goto fn_fail; \ if (_mpi4py_ImportFunc(module, "PyMPI" #Type "_New", NULL, \ (void (**)(void))&_mpi4py_PyMPI##Type##_New) < 0) \ goto fn_fail; \ if (_mpi4py_ImportFunc(module, "PyMPI" #Type "_Get", NULL, \ (void (**)(void))&_mpi4py_PyMPI##Type##_Get) < 0) \ goto fn_fail; \ } while (0) #ifndef MPI4PY_LIMITED_API_SKIP_DATATYPE _mpi4py_import_pycapi(Datatype); #endif #ifndef MPI4PY_LIMITED_API_SKIP_STATUS _mpi4py_import_pycapi(Status); #endif #ifndef MPI4PY_LIMITED_API_SKIP_REQUEST _mpi4py_import_pycapi(Request); #endif #ifndef MPI4PY_LIMITED_API_SKIP_MESSAGE _mpi4py_import_pycapi(Message); #endif #ifndef MPI4PY_LIMITED_API_SKIP_OP _mpi4py_import_pycapi(Op); #endif #ifndef MPI4PY_LIMITED_API_SKIP_GROUP _mpi4py_import_pycapi(Group); #endif #ifndef MPI4PY_LIMITED_API_SKIP_INFO _mpi4py_import_pycapi(Info); #endif #ifndef MPI4PY_LIMITED_API_SKIP_ERRHANDLER _mpi4py_import_pycapi(Errhandler); #endif #ifndef MPI4PY_LIMITED_API_SKIP_SESSION _mpi4py_import_pycapi(Session); #endif #ifndef MPI4PY_LIMITED_API_SKIP_COMM _mpi4py_import_pycapi(Comm); #endif #ifndef MPI4PY_LIMITED_API_SKIP_WIN _mpi4py_import_pycapi(Win); #endif #ifndef MPI4PY_LIMITED_API_SKIP_FILE _mpi4py_import_pycapi(File); #endif #undef _mpi4py_import_pycapi Py_DecRef(module); return 0; fn_fail: Py_DecRef(module); return -1; } #define __PYX_HAVE_API__mpi4py__MPI #define import_mpi4py__MPI import_mpi4py_MPI #endif /* MPI4PY_PYCAPI_H */ ================================================ FILE: libsrc/core/mpi_wrapper.hpp ================================================ #ifndef NGCORE_MPIWRAPPER_HPP #define NGCORE_MPIWRAPPER_HPP #include #include #include "array.hpp" #include "table.hpp" #include "exception.hpp" #include "profiler.hpp" #include "ngstream.hpp" #include "ng_mpi.hpp" namespace ngcore { #ifdef PARALLEL template struct MPI_typetrait { }; template <> struct MPI_typetrait { static NG_MPI_Datatype MPIType () { return NG_MPI_INT; } }; template <> struct MPI_typetrait { static NG_MPI_Datatype MPIType () { return NG_MPI_SHORT; } }; template <> struct MPI_typetrait { static NG_MPI_Datatype MPIType () { return NG_MPI_CHAR; } }; template <> struct MPI_typetrait { static NG_MPI_Datatype MPIType () { return NG_MPI_CHAR; } }; template <> struct MPI_typetrait { static NG_MPI_Datatype MPIType () { return NG_MPI_CHAR; } }; template <> struct MPI_typetrait { static NG_MPI_Datatype MPIType () { return NG_MPI_UINT64_T; } }; template <> struct MPI_typetrait { static NG_MPI_Datatype MPIType () { return NG_MPI_DOUBLE; } }; template <> struct MPI_typetrait> { static NG_MPI_Datatype MPIType () { return NG_MPI_CXX_DOUBLE_COMPLEX; } }; template <> struct MPI_typetrait { static NG_MPI_Datatype MPIType () { return NG_MPI_C_BOOL; } }; template struct MPI_typetrait> { static NG_MPI_Datatype MPIType () { static NG_MPI_Datatype NG_MPI_T = 0; if (!NG_MPI_T) { NG_MPI_Type_contiguous ( S, MPI_typetrait::MPIType(), &NG_MPI_T); NG_MPI_Type_commit ( &NG_MPI_T ); } return NG_MPI_T; } }; template ::MPIType())> inline NG_MPI_Datatype GetMPIType () { return MPI_typetrait::MPIType(); } template inline NG_MPI_Datatype GetMPIType (T &) { return GetMPIType(); } class NgMPI_Request { NG_MPI_Request request; public: NgMPI_Request (NG_MPI_Request requ) : request{requ} { } NgMPI_Request (const NgMPI_Request&) = delete; NgMPI_Request (NgMPI_Request&&) = default; ~NgMPI_Request () { NG_MPI_Wait (&request, NG_MPI_STATUS_IGNORE); } void Wait() { NG_MPI_Wait (&request, NG_MPI_STATUS_IGNORE); } operator NG_MPI_Request() && { auto tmp = request; request = NG_MPI_REQUEST_NULL; return tmp; } }; class NgMPI_Requests { Array requests; public: NgMPI_Requests() = default; ~NgMPI_Requests() { WaitAll(); } void Reset() { requests.SetSize0(); } NgMPI_Requests & operator+= (NgMPI_Request && r) { requests += NG_MPI_Request(std::move(r)); return *this; } NgMPI_Requests & operator+= (NG_MPI_Request r) { requests += r; return *this; } void WaitAll() { static Timer t("NgMPI - WaitAll"); RegionTimer reg(t); if (!requests.Size()) return; NG_MPI_Waitall (requests.Size(), requests.Data(), NG_MPI_STATUSES_IGNORE); } int WaitAny () { int nr; NG_MPI_Waitany (requests.Size(), requests.Data(), &nr, NG_MPI_STATUS_IGNORE); return nr; } }; [[deprecated("use requests.WaitAll instread")]] inline void MyMPI_WaitAll (FlatArray requests) { static Timer t("MPI - WaitAll"); RegionTimer reg(t); if (!requests.Size()) return; NG_MPI_Waitall (requests.Size(), requests.Data(), NG_MPI_STATUSES_IGNORE); } [[deprecated("use requests.WaitAny instread")]] inline int MyMPI_WaitAny (FlatArray requests) { int nr; NG_MPI_Waitany (requests.Size(), requests.Data(), &nr, NG_MPI_STATUS_IGNORE); return nr; } class NgMPI_Comm { protected: NG_MPI_Comm comm; bool valid_comm; int * refcount; int rank, size; public: NgMPI_Comm () : valid_comm(false), refcount(nullptr), rank(0), size(1) { ; } NgMPI_Comm (NG_MPI_Comm _comm, bool owns = false) : comm(_comm), valid_comm(true) { int flag; NG_MPI_Initialized (&flag); if (!flag) { valid_comm = false; refcount = nullptr; rank = 0; size = 1; return; } if (!owns) refcount = nullptr; else refcount = new int{1}; NG_MPI_Comm_rank(comm, &rank); NG_MPI_Comm_size(comm, &size); } NgMPI_Comm (const NgMPI_Comm & c) : comm(c.comm), valid_comm(c.valid_comm), refcount(c.refcount), rank(c.rank), size(c.size) { if (refcount) (*refcount)++; } NgMPI_Comm (NgMPI_Comm && c) : comm(c.comm), valid_comm(c.valid_comm), refcount(c.refcount), rank(c.rank), size(c.size) { c.refcount = nullptr; } ~NgMPI_Comm() { if (refcount) if (--(*refcount) == 0) NG_MPI_Comm_free(&comm); } bool ValidCommunicator() const { return valid_comm; } NgMPI_Comm & operator= (const NgMPI_Comm & c) { if (refcount) if (--(*refcount) == 0) NG_MPI_Comm_free(&comm); refcount = c.refcount; if (refcount) (*refcount)++; comm = c.comm; valid_comm = c.valid_comm; size = c.size; rank = c.rank; return *this; } class InvalidCommException : public Exception { public: InvalidCommException() : Exception("Do not have a valid communicator") { ; } }; operator NG_MPI_Comm() const { if (!valid_comm) throw InvalidCommException(); return comm; } int Rank() const { return rank; } int Size() const { return size; } void Barrier() const { static Timer t("MPI - Barrier"); RegionTimer reg(t); if (size > 1) NG_MPI_Barrier (comm); } /** --- blocking P2P --- **/ template())> void Send (T & val, int dest, int tag) const { NG_MPI_Send (&val, 1, GetMPIType(), dest, tag, comm); } void Send (const std::string & s, int dest, int tag) const { NG_MPI_Send( const_cast (&s[0]), s.length(), NG_MPI_CHAR, dest, tag, comm); } template())> void Send(FlatArray s, int dest, int tag) const { NG_MPI_Send (s.Data(), s.Size(), GetMPIType(), dest, tag, comm); } template())> void Recv (T & val, int src, int tag) const { NG_MPI_Recv (&val, 1, GetMPIType(), src, tag, comm, NG_MPI_STATUS_IGNORE); } void Recv (std::string & s, int src, int tag) const { NG_MPI_Status status; int len; NG_MPI_Probe (src, tag, comm, &status); NG_MPI_Get_count (&status, NG_MPI_CHAR, &len); // s.assign (len, ' '); s.resize (len); NG_MPI_Recv( &s[0], len, NG_MPI_CHAR, src, tag, comm, NG_MPI_STATUS_IGNORE); } template ())> void Recv (FlatArray s, int src, int tag) const { NG_MPI_Recv (s.Data(), s.Size(), GetMPIType (), src, tag, comm, NG_MPI_STATUS_IGNORE); } template ())> void Recv (Array & s, int src, int tag) const { NG_MPI_Status status; int len; const NG_MPI_Datatype NG_MPI_T = GetMPIType (); NG_MPI_Probe (src, tag, comm, &status); NG_MPI_Get_count (&status, NG_MPI_T, &len); s.SetSize (len); NG_MPI_Recv (s.Data(), len, NG_MPI_T, src, tag, comm, NG_MPI_STATUS_IGNORE); } /** --- non-blocking P2P --- **/ template())> [[nodiscard]] NG_MPI_Request ISend (T & val, int dest, int tag) const { NG_MPI_Request request; NG_MPI_Isend (&val, 1, GetMPIType(), dest, tag, comm, &request); return request; } template())> [[nodiscard]] NG_MPI_Request ISend (FlatArray s, int dest, int tag) const { NG_MPI_Request request; NG_MPI_Isend (s.Data(), s.Size(), GetMPIType(), dest, tag, comm, &request); return request; } template())> [[nodiscard]] NG_MPI_Request IRecv (T & val, int dest, int tag) const { NG_MPI_Request request; NG_MPI_Irecv (&val, 1, GetMPIType(), dest, tag, comm, &request); return request; } template())> [[nodiscard]] NG_MPI_Request IRecv (FlatArray s, int src, int tag) const { NG_MPI_Request request; NG_MPI_Irecv (s.Data(), s.Size(), GetMPIType(), src, tag, comm, &request); return request; } /** --- collectives --- **/ template ())> T Reduce (T d, const NG_MPI_Op & op, int root = 0) const { static Timer t("MPI - Reduce"); RegionTimer reg(t); if (size == 1) return d; T global_d; NG_MPI_Reduce (&d, &global_d, 1, GetMPIType(), op, root, comm); return global_d; } template ())> T AllReduce (T d, const NG_MPI_Op & op) const { static Timer t("MPI - AllReduce"); RegionTimer reg(t); if (size == 1) return d; T global_d; NG_MPI_Allreduce ( &d, &global_d, 1, GetMPIType(), op, comm); return global_d; } template ())> void AllReduce (FlatArray d, const NG_MPI_Op & op) const { static Timer t("MPI - AllReduce Array"); RegionTimer reg(t); if (size == 1) return; NG_MPI_Allreduce (NG_MPI_IN_PLACE, d.Data(), d.Size(), GetMPIType(), op, comm); } template ())> void Bcast (T & s, int root = 0) const { if (size == 1) return; static Timer t("MPI - Bcast"); RegionTimer reg(t); NG_MPI_Bcast (&s, 1, GetMPIType(), root, comm); } template void Bcast (std::array & d, int root = 0) const { if (size == 1) return; if (S != 0) NG_MPI_Bcast (&d[0], S, GetMPIType(), root, comm); } template void Bcast (Array & d, int root = 0) const { if (size == 1) return; int ds = d.Size(); Bcast (ds, root); if (Rank() != root) d.SetSize (ds); if (ds != 0) NG_MPI_Bcast (d.Data(), ds, GetMPIType(), root, comm); } void Bcast (std::string & s, int root = 0) const { if (size == 1) return; int len = s.length(); Bcast (len, root); if (rank != 0) s.resize (len); NG_MPI_Bcast (&s[0], len, NG_MPI_CHAR, root, comm); } template [[nodiscard]] NgMPI_Request IBcast (std::array & d, int root = 0) const { NG_MPI_Request request; NG_MPI_Ibcast (&d[0], S, GetMPIType(), root, comm, &request); return request; } template [[nodiscard]] NgMPI_Request IBcast (FlatArray d, int root = 0) const { NG_MPI_Request request; int ds = d.Size(); NG_MPI_Ibcast (d.Data(), ds, GetMPIType(), root, comm, &request); return request; } template void AllToAll (FlatArray send, FlatArray recv) const { NG_MPI_Alltoall (send.Data(), 1, GetMPIType(), recv.Data(), 1, GetMPIType(), comm); } template void ScatterRoot (FlatArray send) const { if (size == 1) return; NG_MPI_Scatter (send.Data(), 1, GetMPIType(), NG_MPI_IN_PLACE, -1, GetMPIType(), 0, comm); } template void Scatter (T & recv) const { if (size == 1) return; NG_MPI_Scatter (NULL, 0, GetMPIType(), &recv, 1, GetMPIType(), 0, comm); } template void GatherRoot (FlatArray recv) const { recv[0] = T(0); if (size == 1) return; NG_MPI_Gather (NG_MPI_IN_PLACE, 1, GetMPIType(), recv.Data(), 1, GetMPIType(), 0, comm); } template void Gather (T send) const { if (size == 1) return; NG_MPI_Gather (&send, 1, GetMPIType(), NULL, 1, GetMPIType(), 0, comm); } template void AllGather (T val, FlatArray recv) const { if (size == 1) { recv[0] = val; return; } NG_MPI_Allgather (&val, 1, GetMPIType(), recv.Data(), 1, GetMPIType(), comm); } template void ExchangeTable (DynamicTable & send_data, DynamicTable & recv_data, int tag) { Array send_sizes(size); Array recv_sizes(size); for (int i = 0; i < size; i++) send_sizes[i] = send_data[i].Size(); AllToAll (send_sizes, recv_sizes); recv_data = DynamicTable (recv_sizes, true); NgMPI_Requests requests; for (int dest = 0; dest < size; dest++) if (dest != rank && send_data[dest].Size()) requests += ISend (FlatArray(send_data[dest]), dest, tag); for (int dest = 0; dest < size; dest++) if (dest != rank && recv_data[dest].Size()) requests += IRecv (FlatArray(recv_data[dest]), dest, tag); requests.WaitAll(); } NgMPI_Comm SubCommunicator (FlatArray procs) const { NG_MPI_Comm subcomm; NG_MPI_Group gcomm, gsubcomm; NG_MPI_Comm_group(comm, &gcomm); NG_MPI_Group_incl(gcomm, procs.Size(), procs.Data(), &gsubcomm); NG_MPI_Comm_create_group(comm, gsubcomm, 4242, &subcomm); return NgMPI_Comm(subcomm, true); } }; // class NgMPI_Comm #else // PARALLEL class NG_MPI_Comm { int nr; public: NG_MPI_Comm (int _nr = 0) : nr(_nr) { ; } operator int() const { return nr; } bool operator== (NG_MPI_Comm c2) const { return nr == c2.nr; } }; static NG_MPI_Comm NG_MPI_COMM_WORLD = 12345, NG_MPI_COMM_NULL = 10000; typedef int NG_MPI_Op; typedef int NG_MPI_Datatype; typedef int NG_MPI_Request; enum { NG_MPI_SUM = 0, NG_MPI_MIN = 1, NG_MPI_MAX = 2, NG_MPI_LOR = 4711 }; inline void NG_MPI_Type_contiguous ( int, NG_MPI_Datatype, NG_MPI_Datatype*) { ; } inline void NG_MPI_Type_commit ( NG_MPI_Datatype * ) { ; } template struct MPI_typetrait { static NG_MPI_Datatype MPIType () { return -1; } }; template inline NG_MPI_Datatype GetMPIType () { return -1; } class NgMPI_Request { public: NgMPI_Request() = default; NgMPI_Request(NgMPI_Request &&) { ; } NgMPI_Request(NG_MPI_Request &&) { ; } }; class NgMPI_Requests { public: NgMPI_Requests & operator+= (NgMPI_Request &&) { return *this; } NgMPI_Requests & operator+= (NG_MPI_Request r) { return *this; } void Reset() { ; } void WaitAll() { ; } int WaitAny() { return 0; } }; class NgMPI_Comm { public: NgMPI_Comm () { ; } NgMPI_Comm (NG_MPI_Comm _comm, bool owns = false) { ; } size_t Rank() const { return 0; } size_t Size() const { return 1; } bool ValidCommunicator() const { return false; } void Barrier() const { ; } operator NG_MPI_Comm() const { return NG_MPI_Comm(); } template void Send( T & val, int dest, int tag) const { ; } template void Send(FlatArray s, int dest, int tag) const { ; } template void Recv (T & val, int src, int tag) const { ; } template void Recv (FlatArray s, int src, int tag) const { ; } template void Recv (Array & s, int src, int tag) const { ; } template NG_MPI_Request ISend (T & val, int dest, int tag) const { return 0; } template NG_MPI_Request ISend (FlatArray s, int dest, int tag) const { return 0; } template NG_MPI_Request IRecv (T & val, int dest, int tag) const { return 0; } template NG_MPI_Request IRecv (FlatArray s, int src, int tag) const { return 0; } template T Reduce (T d, const NG_MPI_Op & op, int root = 0) const { return d; } template T AllReduce (T d, const NG_MPI_Op & op) const { return d; } template void AllReduce (FlatArray d, const NG_MPI_Op & op) const { ; } template void Bcast (T & s, int root = 0) const { ; } template void Bcast (std::array & d, int root = 0) const {} template void Bcast (Array & d, int root = 0) const { ; } template NG_MPI_Request IBcast (std::array & d, int root = 0) const { return 0; } template NG_MPI_Request IBcast (FlatArray d, int root = 0) const { return 0; } template void AllGather (T val, FlatArray recv) const { recv[0] = val; } template void ExchangeTable (DynamicTable & send_data, DynamicTable & recv_data, int tag) { ; } NgMPI_Comm SubCommunicator (FlatArray procs) const { return *this; } }; inline void MyMPI_WaitAll (FlatArray requests) { ; } inline int MyMPI_WaitAny (FlatArray requests) { return 0; } #endif // PARALLEL } // namespace ngcore #endif // NGCORE_MPIWRAPPER_HPP ================================================ FILE: libsrc/core/ng_mpi.cpp ================================================ #define OMPI_SKIP_MPICXX #include #include "ng_mpi.hpp" #include #include "array.hpp" #include "ngcore_api.hpp" #ifdef NG_PYTHON #include "pybind11/pytypes.h" #include "python_ngcore.hpp" #define MPI4PY_LIMITED_API 1 #define MPI4PY_LIMITED_API_SKIP_MESSAGE 1 #define MPI4PY_LIMITED_API_SKIP_SESSION 1 #include "mpi4py_pycapi.h" // mpi4py < 4.0.0 #endif #ifdef MSMPI_VER int MPI_Comm_create_group(MPI_Comm arg0, MPI_Group arg1, int arg2, MPI_Comm* arg3) { throw std::runtime_error( "MPI_Comm_create_group not supported on Microsoft MPI"); } static MPI_Datatype MPI_CXX_DOUBLE_COMPLEX; #endif // MSMPI_VER namespace ngcore { static_assert(sizeof(MPI_Status) <= sizeof(NG_MPI_Status), "Size mismatch"); static_assert(alignof(MPI_Status) <= alignof(NG_MPI_Status), "Size mismatch"); int mpi2ng(int value) { return value; } void* mpi2ng(void* ptr) { return ptr; } NG_MPI_Status* mpi2ng(MPI_Status* status) { return reinterpret_cast(status); } #if !defined(MPICH) && !defined(MSMPI_VER) NG_MPI_Comm mpi2ng(MPI_Comm comm) { return reinterpret_cast(comm); } #endif template void gather_strided_array(size_t count, char* data) { static_assert(size <= stride, "Size must be less than or equal to stride"); if constexpr (size < stride) { char* dst = data; char* src = data; for ( [[maybe_unused]] auto i : Range(count)) { memcpy(dst, src, size); dst += size; src += stride; } } } template T cast_ng2mpi(uintptr_t obj) { if constexpr (std::is_pointer_v) return reinterpret_cast(obj); else return static_cast(obj); } template T cast_ng2mpi(uintptr_t* ptr) { if constexpr (std::is_pointer_v) return reinterpret_cast(ptr); else return static_cast(ptr); } template T* cast_ng2mpi(TSrc* ptr, int count) { gather_strided_array(count, reinterpret_cast(ptr)); return reinterpret_cast(ptr); } MPI_Comm ng2mpi(NG_MPI_Comm comm) { static_assert(sizeof(MPI_Comm) <= sizeof(comm.value), "Size mismatch"); static_assert(alignof(MPI_Comm) <= alignof(NG_MPI_Comm), "Size mismatch"); return cast_ng2mpi(comm.value); } MPI_Group ng2mpi(NG_MPI_Group group) { static_assert(sizeof(MPI_Group) <= sizeof(group.value), "Size mismatch"); static_assert(alignof(MPI_Group) <= alignof(NG_MPI_Group), "Size mismatch"); return cast_ng2mpi(group.value); } MPI_Comm* ng2mpi(NG_MPI_Comm* comm) { return cast_ng2mpi(&comm->value); } MPI_Group* ng2mpi(NG_MPI_Group* group) { return cast_ng2mpi(&group->value); } MPI_Datatype* ng2mpi(NG_MPI_Datatype* type) { return cast_ng2mpi(&type->value); } MPI_Datatype* ng2mpi(NG_MPI_Datatype* type, int count) { return cast_ng2mpi(&type->value, count); } MPI_Request* ng2mpi(NG_MPI_Request* request) { return cast_ng2mpi(&request->value); } MPI_Request* ng2mpi(NG_MPI_Request* request, int count) { return cast_ng2mpi(&request->value, count); } MPI_Status* ng2mpi(NG_MPI_Status* status) { return reinterpret_cast(status); } MPI_Aint* ng2mpi(NG_MPI_Aint* aint) { return reinterpret_cast(aint); } MPI_Aint* ng2mpi(NG_MPI_Aint* aint, int count) { return cast_ng2mpi(aint, count); } MPI_Datatype ng2mpi(NG_MPI_Datatype type) { static_assert(sizeof(MPI_Datatype) <= sizeof(type.value), "Size mismatch"); return cast_ng2mpi(type.value); } MPI_Request ng2mpi(NG_MPI_Request request) { static_assert(sizeof(MPI_Request) <= sizeof(request.value), "Size mismatch"); return cast_ng2mpi(request.value); } MPI_Op ng2mpi(NG_MPI_Op op) { static_assert(sizeof(MPI_Op) <= sizeof(op.value), "Size mismatch"); return cast_ng2mpi(op.value); } MPI_Aint ng2mpi(NG_MPI_Aint aint) { static_assert(sizeof(MPI_Aint) <= sizeof(aint.value), "Size mismatch"); return cast_ng2mpi(aint.value); } void* ng2mpi(void* ptr) { return ptr; } char* ng2mpi(char* ptr) { return ptr; } char*** ng2mpi(char*** ptr) { return ptr; } int* ng2mpi(int* ptr) { return ptr; } int ng2mpi(int value) { return value; } } // namespace ngcore using namespace ngcore; extern "C" { NGCORE_API_EXPORT void ng_init_mpi(); } static bool imported_mpi4py = false; void ng_init_mpi() { #ifdef NG_PYTHON NG_MPI_CommFromMPI4Py = [](py::handle src, NG_MPI_Comm& dst) -> bool { if (!imported_mpi4py) { import_mpi4py__MPI(); imported_mpi4py = true; } PyObject* py_src = src.ptr(); [[maybe_unused]] auto type = Py_TYPE(py_src); if (PyObject_TypeCheck(py_src, &PyMPIComm_Type)) { dst = mpi2ng(*PyMPIComm_Get(py_src)); return !PyErr_Occurred(); } return false; }; NG_MPI_CommToMPI4Py = [](NG_MPI_Comm src) -> py::handle { if (!imported_mpi4py) { import_mpi4py__MPI(); imported_mpi4py = true; } return py::handle(PyMPIComm_New(ng2mpi(src))); }; #endif // NG_PYTHON #include "ng_mpi_generated_init.hpp" } ================================================ FILE: libsrc/core/ng_mpi.hpp ================================================ #ifndef NG_MPI_HPP_INCLUDED #define NG_MPI_HPP_INCLUDED #ifdef PARALLEL #include #include #include #include "ngcore_api.hpp" #ifndef NG_MPI_WRAPPER #define OMPI_SKIP_MPICXX #include #endif // NG_MPI_WRAPPER namespace ngcore { NGCORE_API bool MPI_Loaded(); NGCORE_API void InitMPI( std::optional mpi_lib_path = std::nullopt); #ifdef NG_MPI_WRAPPER inline void not_implemented() { throw std::runtime_error("Not implemented"); } struct NG_MPI_Status { uintptr_t data[4]; }; struct NG_MPI_Comm { uintptr_t value; NG_MPI_Comm() { value = 0; } NG_MPI_Comm(uintptr_t value_) : value(value_) {} NG_MPI_Comm(const NG_MPI_Comm &comm) : value(comm.value) {} void operator=(int value_) { value = value_; } void operator=(uintptr_t value_) { value = value_; } bool operator==(const NG_MPI_Comm &comm) const { return value == comm.value; } bool operator!=(const NG_MPI_Comm &comm) const { return value != comm.value; } }; struct NG_MPI_Datatype { uintptr_t value = 0; NG_MPI_Datatype() = default; NG_MPI_Datatype(uintptr_t value_) : value(value_) {} operator bool() const { return value != 0; } void operator=(NG_MPI_Datatype type) { value = type.value; } void operator=(uintptr_t value_) { value = value_; } void operator=(void *value_) { value = reinterpret_cast(value_); } }; struct NG_MPI_Request { uintptr_t value = 0; NG_MPI_Request() = default; NG_MPI_Request(uintptr_t value_) : value(value_) {} void operator=(uintptr_t value_) { value = value_; } void operator=(void *value_) { value = reinterpret_cast(value_); } }; struct NG_MPI_Op { uintptr_t value; NG_MPI_Op(uintptr_t value_) : value(value_) {} void operator=(uintptr_t value_) { value = value_; } void operator=(void *value_) { value = reinterpret_cast(value_); } }; struct NG_MPI_Group { uintptr_t value = 0; NG_MPI_Group(uintptr_t value_) : value(value_) {} NG_MPI_Group() = default; }; struct NG_MPI_Aint { intptr_t value = 0; NG_MPI_Aint(intptr_t value_) : value(value_) {} NG_MPI_Aint() = default; }; #else // NG_MPI_WRAPPER using NG_MPI_Comm = MPI_Comm; using NG_MPI_Status = MPI_Status; using NG_MPI_Datatype = MPI_Datatype; using NG_MPI_Request = MPI_Request; using NG_MPI_Op = MPI_Op; using NG_MPI_Group = MPI_Group; using NG_MPI_Aint = MPI_Aint; #endif // NG_MPI_WRAPPER #include "ng_mpi_generated_declarations.hpp" } // namespace ngcore #endif // PARALLEL #endif // NG_MPI_HPP_INCLUDED ================================================ FILE: libsrc/core/ng_mpi_generated_declarations.hpp ================================================ #ifdef NG_MPI_WRAPPER NGCORE_API extern double (*NG_MPI_Wtime)(); NGCORE_API extern int (*NG_MPI_Allgather)(void*, int, NG_MPI_Datatype, void*, int, NG_MPI_Datatype, NG_MPI_Comm); NGCORE_API extern int (*NG_MPI_Allreduce)(void*, void*, int, NG_MPI_Datatype, NG_MPI_Op, NG_MPI_Comm); NGCORE_API extern int (*NG_MPI_Alltoall)(void*, int, NG_MPI_Datatype, void*, int, NG_MPI_Datatype, NG_MPI_Comm); NGCORE_API extern int (*NG_MPI_Barrier)(NG_MPI_Comm); NGCORE_API extern int (*NG_MPI_Bcast)(void*, int, NG_MPI_Datatype, int, NG_MPI_Comm); NGCORE_API extern int (*NG_MPI_Ibcast)(void*, int, NG_MPI_Datatype, int, NG_MPI_Comm, NG_MPI_Request*); NGCORE_API extern int (*NG_MPI_Comm_c2f)(NG_MPI_Comm); NGCORE_API extern int (*NG_MPI_Comm_create)(NG_MPI_Comm, NG_MPI_Group, NG_MPI_Comm*); NGCORE_API extern int (*NG_MPI_Comm_create_group)(NG_MPI_Comm, NG_MPI_Group, int, NG_MPI_Comm*); NGCORE_API extern int (*NG_MPI_Comm_free)(NG_MPI_Comm*); NGCORE_API extern int (*NG_MPI_Comm_group)(NG_MPI_Comm, NG_MPI_Group*); NGCORE_API extern int (*NG_MPI_Comm_rank)(NG_MPI_Comm, int*); NGCORE_API extern int (*NG_MPI_Comm_size)(NG_MPI_Comm, int*); NGCORE_API extern int (*NG_MPI_Finalize)(); NGCORE_API extern int (*NG_MPI_Gather)(void*, int, NG_MPI_Datatype, void*, int, NG_MPI_Datatype, int, NG_MPI_Comm); NGCORE_API extern int (*NG_MPI_Gatherv)(void*, int, NG_MPI_Datatype, void*, int*, int*, NG_MPI_Datatype, int, NG_MPI_Comm); NGCORE_API extern int (*NG_MPI_Get_count)(NG_MPI_Status*, NG_MPI_Datatype, int*); NGCORE_API extern int (*NG_MPI_Get_processor_name)(char*, int*); NGCORE_API extern int (*NG_MPI_Group_incl)(NG_MPI_Group, int, int*, NG_MPI_Group*); NGCORE_API extern int (*NG_MPI_Init)(int*, char***); NGCORE_API extern int (*NG_MPI_Init_thread)(int*, char***, int, int*); NGCORE_API extern int (*NG_MPI_Initialized)(int*); NGCORE_API extern int (*NG_MPI_Iprobe)(int, int, NG_MPI_Comm, int*, NG_MPI_Status*); NGCORE_API extern int (*NG_MPI_Irecv)(void*, int, NG_MPI_Datatype, int, int, NG_MPI_Comm, NG_MPI_Request*); NGCORE_API extern int (*NG_MPI_Isend)(void*, int, NG_MPI_Datatype, int, int, NG_MPI_Comm, NG_MPI_Request*); NGCORE_API extern int (*NG_MPI_Probe)(int, int, NG_MPI_Comm, NG_MPI_Status*); NGCORE_API extern int (*NG_MPI_Query_thread)(int*); NGCORE_API extern int (*NG_MPI_Recv)(void*, int, NG_MPI_Datatype, int, int, NG_MPI_Comm, NG_MPI_Status*); NGCORE_API extern int (*NG_MPI_Recv_init)(void*, int, NG_MPI_Datatype, int, int, NG_MPI_Comm, NG_MPI_Request*); NGCORE_API extern int (*NG_MPI_Reduce)(void*, void*, int, NG_MPI_Datatype, NG_MPI_Op, int, NG_MPI_Comm); NGCORE_API extern int (*NG_MPI_Reduce_local)(void*, void*, int, NG_MPI_Datatype, NG_MPI_Op); NGCORE_API extern int (*NG_MPI_Request_free)(NG_MPI_Request*); NGCORE_API extern int (*NG_MPI_Scatter)(void*, int, NG_MPI_Datatype, void*, int, NG_MPI_Datatype, int, NG_MPI_Comm); NGCORE_API extern int (*NG_MPI_Send)(void*, int, NG_MPI_Datatype, int, int, NG_MPI_Comm); NGCORE_API extern int (*NG_MPI_Send_init)(void*, int, NG_MPI_Datatype, int, int, NG_MPI_Comm, NG_MPI_Request*); NGCORE_API extern int (*NG_MPI_Startall)(int, NG_MPI_Request*); NGCORE_API extern int (*NG_MPI_Type_commit)(NG_MPI_Datatype*); NGCORE_API extern int (*NG_MPI_Type_contiguous)(int, NG_MPI_Datatype, NG_MPI_Datatype*); NGCORE_API extern int (*NG_MPI_Type_create_resized)(NG_MPI_Datatype, NG_MPI_Aint, NG_MPI_Aint, NG_MPI_Datatype*); NGCORE_API extern int (*NG_MPI_Type_create_struct)(int, int*, NG_MPI_Aint*, NG_MPI_Datatype*, NG_MPI_Datatype*); NGCORE_API extern int (*NG_MPI_Type_free)(NG_MPI_Datatype*); NGCORE_API extern int (*NG_MPI_Type_get_extent)(NG_MPI_Datatype, NG_MPI_Aint*, NG_MPI_Aint*); NGCORE_API extern int (*NG_MPI_Type_indexed)(int, int*, int*, NG_MPI_Datatype, NG_MPI_Datatype*); NGCORE_API extern int (*NG_MPI_Type_size)(NG_MPI_Datatype, int*); NGCORE_API extern int (*NG_MPI_Wait)(NG_MPI_Request*, NG_MPI_Status*); NGCORE_API extern int (*NG_MPI_Waitall)(int, NG_MPI_Request*, NG_MPI_Status*); NGCORE_API extern int (*NG_MPI_Waitany)(int, NG_MPI_Request*, int*, NG_MPI_Status*); NGCORE_API extern NG_MPI_Comm NG_MPI_COMM_NULL; NGCORE_API extern NG_MPI_Comm NG_MPI_COMM_WORLD; NGCORE_API extern NG_MPI_Datatype NG_MPI_CHAR; NGCORE_API extern NG_MPI_Datatype NG_MPI_CXX_DOUBLE_COMPLEX; NGCORE_API extern NG_MPI_Datatype NG_MPI_C_BOOL; NGCORE_API extern NG_MPI_Datatype NG_MPI_DATATYPE_NULL; NGCORE_API extern NG_MPI_Datatype NG_MPI_DOUBLE; NGCORE_API extern NG_MPI_Datatype NG_MPI_FLOAT; NGCORE_API extern NG_MPI_Datatype NG_MPI_INT; NGCORE_API extern NG_MPI_Datatype NG_MPI_SHORT; NGCORE_API extern NG_MPI_Datatype NG_MPI_UINT64_T; NGCORE_API extern NG_MPI_Op NG_MPI_LOR; NGCORE_API extern NG_MPI_Op NG_MPI_MAX; NGCORE_API extern NG_MPI_Op NG_MPI_MIN; NGCORE_API extern NG_MPI_Op NG_MPI_SUM; NGCORE_API extern NG_MPI_Request NG_MPI_REQUEST_NULL; NGCORE_API extern NG_MPI_Status* NG_MPI_STATUSES_IGNORE; NGCORE_API extern NG_MPI_Status* NG_MPI_STATUS_IGNORE; NGCORE_API extern int NG_MPI_ANY_SOURCE; NGCORE_API extern int NG_MPI_ANY_TAG; NGCORE_API extern int NG_MPI_MAX_PROCESSOR_NAME; NGCORE_API extern int NG_MPI_PROC_NULL; NGCORE_API extern int NG_MPI_ROOT; NGCORE_API extern int NG_MPI_SUBVERSION; NGCORE_API extern int NG_MPI_THREAD_MULTIPLE; NGCORE_API extern int NG_MPI_THREAD_SINGLE; NGCORE_API extern int NG_MPI_VERSION; NGCORE_API extern void* NG_MPI_IN_PLACE; #else // NG_MPI_WRAPPER #define NG_MPI_Wtime MPI_Wtime #define NG_MPI_Allgather MPI_Allgather #define NG_MPI_Allreduce MPI_Allreduce #define NG_MPI_Alltoall MPI_Alltoall #define NG_MPI_Barrier MPI_Barrier #define NG_MPI_Bcast MPI_Bcast #define NG_MPI_Ibcast MPI_Ibcast #define NG_MPI_Comm_c2f MPI_Comm_c2f #define NG_MPI_Comm_create MPI_Comm_create #define NG_MPI_Comm_create_group MPI_Comm_create_group #define NG_MPI_Comm_free MPI_Comm_free #define NG_MPI_Comm_group MPI_Comm_group #define NG_MPI_Comm_rank MPI_Comm_rank #define NG_MPI_Comm_size MPI_Comm_size #define NG_MPI_Finalize MPI_Finalize #define NG_MPI_Gather MPI_Gather #define NG_MPI_Gatherv MPI_Gatherv #define NG_MPI_Get_count MPI_Get_count #define NG_MPI_Get_processor_name MPI_Get_processor_name #define NG_MPI_Group_incl MPI_Group_incl #define NG_MPI_Init MPI_Init #define NG_MPI_Init_thread MPI_Init_thread #define NG_MPI_Initialized MPI_Initialized #define NG_MPI_Iprobe MPI_Iprobe #define NG_MPI_Irecv MPI_Irecv #define NG_MPI_Isend MPI_Isend #define NG_MPI_Probe MPI_Probe #define NG_MPI_Query_thread MPI_Query_thread #define NG_MPI_Recv MPI_Recv #define NG_MPI_Recv_init MPI_Recv_init #define NG_MPI_Reduce MPI_Reduce #define NG_MPI_Reduce_local MPI_Reduce_local #define NG_MPI_Request_free MPI_Request_free #define NG_MPI_Scatter MPI_Scatter #define NG_MPI_Send MPI_Send #define NG_MPI_Send_init MPI_Send_init #define NG_MPI_Startall MPI_Startall #define NG_MPI_Type_commit MPI_Type_commit #define NG_MPI_Type_contiguous MPI_Type_contiguous #define NG_MPI_Type_create_resized MPI_Type_create_resized #define NG_MPI_Type_create_struct MPI_Type_create_struct #define NG_MPI_Type_free MPI_Type_free #define NG_MPI_Type_get_extent MPI_Type_get_extent #define NG_MPI_Type_indexed MPI_Type_indexed #define NG_MPI_Type_size MPI_Type_size #define NG_MPI_Wait MPI_Wait #define NG_MPI_Waitall MPI_Waitall #define NG_MPI_Waitany MPI_Waitany #define NG_MPI_COMM_NULL MPI_COMM_NULL #define NG_MPI_COMM_WORLD MPI_COMM_WORLD #define NG_MPI_CHAR MPI_CHAR #define NG_MPI_CXX_DOUBLE_COMPLEX MPI_CXX_DOUBLE_COMPLEX #define NG_MPI_C_BOOL MPI_C_BOOL #define NG_MPI_DATATYPE_NULL MPI_DATATYPE_NULL #define NG_MPI_DOUBLE MPI_DOUBLE #define NG_MPI_FLOAT MPI_FLOAT #define NG_MPI_INT MPI_INT #define NG_MPI_SHORT MPI_SHORT #define NG_MPI_UINT64_T MPI_UINT64_T #define NG_MPI_LOR MPI_LOR #define NG_MPI_MAX MPI_MAX #define NG_MPI_MIN MPI_MIN #define NG_MPI_SUM MPI_SUM #define NG_MPI_REQUEST_NULL MPI_REQUEST_NULL #define NG_MPI_STATUSES_IGNORE MPI_STATUSES_IGNORE #define NG_MPI_STATUS_IGNORE MPI_STATUS_IGNORE #define NG_MPI_ANY_SOURCE MPI_ANY_SOURCE #define NG_MPI_ANY_TAG MPI_ANY_TAG #define NG_MPI_MAX_PROCESSOR_NAME MPI_MAX_PROCESSOR_NAME #define NG_MPI_PROC_NULL MPI_PROC_NULL #define NG_MPI_ROOT MPI_ROOT #define NG_MPI_SUBVERSION MPI_SUBVERSION #define NG_MPI_THREAD_MULTIPLE MPI_THREAD_MULTIPLE #define NG_MPI_THREAD_SINGLE MPI_THREAD_SINGLE #define NG_MPI_VERSION MPI_VERSION #define NG_MPI_IN_PLACE MPI_IN_PLACE #endif // NG_MPI_WRAPPER ================================================ FILE: libsrc/core/ng_mpi_generated_dummy_init.hpp ================================================ decltype(NG_MPI_Wtime) NG_MPI_Wtime = []()->double { throw no_mpi(); }; decltype(NG_MPI_Allgather) NG_MPI_Allgather = [](void*, int, NG_MPI_Datatype, void*, int, NG_MPI_Datatype, NG_MPI_Comm)->int { throw no_mpi(); }; decltype(NG_MPI_Allreduce) NG_MPI_Allreduce = [](void*, void*, int, NG_MPI_Datatype, NG_MPI_Op, NG_MPI_Comm)->int { throw no_mpi(); }; decltype(NG_MPI_Alltoall) NG_MPI_Alltoall = [](void*, int, NG_MPI_Datatype, void*, int, NG_MPI_Datatype, NG_MPI_Comm)->int { throw no_mpi(); }; decltype(NG_MPI_Barrier) NG_MPI_Barrier = [](NG_MPI_Comm)->int { throw no_mpi(); }; decltype(NG_MPI_Bcast) NG_MPI_Bcast = [](void*, int, NG_MPI_Datatype, int, NG_MPI_Comm)->int { throw no_mpi(); }; decltype(NG_MPI_Ibcast) NG_MPI_Ibcast = [](void*, int, NG_MPI_Datatype, int, NG_MPI_Comm, NG_MPI_Request*)->int { throw no_mpi(); }; decltype(NG_MPI_Comm_c2f) NG_MPI_Comm_c2f = [](NG_MPI_Comm)->int { throw no_mpi(); }; decltype(NG_MPI_Comm_create) NG_MPI_Comm_create = [](NG_MPI_Comm, NG_MPI_Group, NG_MPI_Comm*)->int { throw no_mpi(); }; decltype(NG_MPI_Comm_create_group) NG_MPI_Comm_create_group = [](NG_MPI_Comm, NG_MPI_Group, int, NG_MPI_Comm*)->int { throw no_mpi(); }; decltype(NG_MPI_Comm_free) NG_MPI_Comm_free = [](NG_MPI_Comm*)->int { throw no_mpi(); }; decltype(NG_MPI_Comm_group) NG_MPI_Comm_group = [](NG_MPI_Comm, NG_MPI_Group*)->int { throw no_mpi(); }; decltype(NG_MPI_Comm_rank) NG_MPI_Comm_rank = [](NG_MPI_Comm, int*)->int { throw no_mpi(); }; decltype(NG_MPI_Comm_size) NG_MPI_Comm_size = [](NG_MPI_Comm, int*)->int { throw no_mpi(); }; decltype(NG_MPI_Finalize) NG_MPI_Finalize = []()->int { throw no_mpi(); }; decltype(NG_MPI_Gather) NG_MPI_Gather = [](void*, int, NG_MPI_Datatype, void*, int, NG_MPI_Datatype, int, NG_MPI_Comm)->int { throw no_mpi(); }; decltype(NG_MPI_Gatherv) NG_MPI_Gatherv = [](void*, int, NG_MPI_Datatype, void*, int*, int*, NG_MPI_Datatype, int, NG_MPI_Comm)->int { throw no_mpi(); }; decltype(NG_MPI_Get_count) NG_MPI_Get_count = [](NG_MPI_Status*, NG_MPI_Datatype, int*)->int { throw no_mpi(); }; decltype(NG_MPI_Get_processor_name) NG_MPI_Get_processor_name = [](char*, int*)->int { throw no_mpi(); }; decltype(NG_MPI_Group_incl) NG_MPI_Group_incl = [](NG_MPI_Group, int, int*, NG_MPI_Group*)->int { throw no_mpi(); }; decltype(NG_MPI_Init) NG_MPI_Init = [](int*, char***)->int { throw no_mpi(); }; decltype(NG_MPI_Init_thread) NG_MPI_Init_thread = [](int*, char***, int, int*)->int { throw no_mpi(); }; decltype(NG_MPI_Initialized) NG_MPI_Initialized = [](int*)->int { throw no_mpi(); }; decltype(NG_MPI_Iprobe) NG_MPI_Iprobe = [](int, int, NG_MPI_Comm, int*, NG_MPI_Status*)->int { throw no_mpi(); }; decltype(NG_MPI_Irecv) NG_MPI_Irecv = [](void*, int, NG_MPI_Datatype, int, int, NG_MPI_Comm, NG_MPI_Request*)->int { throw no_mpi(); }; decltype(NG_MPI_Isend) NG_MPI_Isend = [](void*, int, NG_MPI_Datatype, int, int, NG_MPI_Comm, NG_MPI_Request*)->int { throw no_mpi(); }; decltype(NG_MPI_Probe) NG_MPI_Probe = [](int, int, NG_MPI_Comm, NG_MPI_Status*)->int { throw no_mpi(); }; decltype(NG_MPI_Query_thread) NG_MPI_Query_thread = [](int*)->int { throw no_mpi(); }; decltype(NG_MPI_Recv) NG_MPI_Recv = [](void*, int, NG_MPI_Datatype, int, int, NG_MPI_Comm, NG_MPI_Status*)->int { throw no_mpi(); }; decltype(NG_MPI_Recv_init) NG_MPI_Recv_init = [](void*, int, NG_MPI_Datatype, int, int, NG_MPI_Comm, NG_MPI_Request*)->int { throw no_mpi(); }; decltype(NG_MPI_Reduce) NG_MPI_Reduce = [](void*, void*, int, NG_MPI_Datatype, NG_MPI_Op, int, NG_MPI_Comm)->int { throw no_mpi(); }; decltype(NG_MPI_Reduce_local) NG_MPI_Reduce_local = [](void*, void*, int, NG_MPI_Datatype, NG_MPI_Op)->int { throw no_mpi(); }; decltype(NG_MPI_Request_free) NG_MPI_Request_free = [](NG_MPI_Request*)->int { throw no_mpi(); }; decltype(NG_MPI_Scatter) NG_MPI_Scatter = [](void*, int, NG_MPI_Datatype, void*, int, NG_MPI_Datatype, int, NG_MPI_Comm)->int { throw no_mpi(); }; decltype(NG_MPI_Send) NG_MPI_Send = [](void*, int, NG_MPI_Datatype, int, int, NG_MPI_Comm)->int { throw no_mpi(); }; decltype(NG_MPI_Send_init) NG_MPI_Send_init = [](void*, int, NG_MPI_Datatype, int, int, NG_MPI_Comm, NG_MPI_Request*)->int { throw no_mpi(); }; decltype(NG_MPI_Startall) NG_MPI_Startall = [](int, NG_MPI_Request*)->int { throw no_mpi(); }; decltype(NG_MPI_Type_commit) NG_MPI_Type_commit = [](NG_MPI_Datatype*)->int { throw no_mpi(); }; decltype(NG_MPI_Type_contiguous) NG_MPI_Type_contiguous = [](int, NG_MPI_Datatype, NG_MPI_Datatype*)->int { throw no_mpi(); }; decltype(NG_MPI_Type_create_resized) NG_MPI_Type_create_resized = [](NG_MPI_Datatype, NG_MPI_Aint, NG_MPI_Aint, NG_MPI_Datatype*)->int { throw no_mpi(); }; decltype(NG_MPI_Type_create_struct) NG_MPI_Type_create_struct = [](int, int*, NG_MPI_Aint*, NG_MPI_Datatype*, NG_MPI_Datatype*)->int { throw no_mpi(); }; decltype(NG_MPI_Type_free) NG_MPI_Type_free = [](NG_MPI_Datatype*)->int { throw no_mpi(); }; decltype(NG_MPI_Type_get_extent) NG_MPI_Type_get_extent = [](NG_MPI_Datatype, NG_MPI_Aint*, NG_MPI_Aint*)->int { throw no_mpi(); }; decltype(NG_MPI_Type_indexed) NG_MPI_Type_indexed = [](int, int*, int*, NG_MPI_Datatype, NG_MPI_Datatype*)->int { throw no_mpi(); }; decltype(NG_MPI_Type_size) NG_MPI_Type_size = [](NG_MPI_Datatype, int*)->int { throw no_mpi(); }; decltype(NG_MPI_Wait) NG_MPI_Wait = [](NG_MPI_Request*, NG_MPI_Status*)->int { throw no_mpi(); }; decltype(NG_MPI_Waitall) NG_MPI_Waitall = [](int, NG_MPI_Request*, NG_MPI_Status*)->int { throw no_mpi(); }; decltype(NG_MPI_Waitany) NG_MPI_Waitany = [](int, NG_MPI_Request*, int*, NG_MPI_Status*)->int { throw no_mpi(); }; NG_MPI_Comm NG_MPI_COMM_NULL = 0; NG_MPI_Comm NG_MPI_COMM_WORLD = 0; NG_MPI_Datatype NG_MPI_CHAR = 0; NG_MPI_Datatype NG_MPI_CXX_DOUBLE_COMPLEX = 0; NG_MPI_Datatype NG_MPI_C_BOOL = 0; NG_MPI_Datatype NG_MPI_DATATYPE_NULL = 0; NG_MPI_Datatype NG_MPI_DOUBLE = 0; NG_MPI_Datatype NG_MPI_FLOAT = 0; NG_MPI_Datatype NG_MPI_INT = 0; NG_MPI_Datatype NG_MPI_SHORT = 0; NG_MPI_Datatype NG_MPI_UINT64_T = 0; NG_MPI_Op NG_MPI_LOR = 0; NG_MPI_Op NG_MPI_MAX = 0; NG_MPI_Op NG_MPI_MIN = 0; NG_MPI_Op NG_MPI_SUM = 0; NG_MPI_Request NG_MPI_REQUEST_NULL = 0; NG_MPI_Status* NG_MPI_STATUSES_IGNORE = 0; NG_MPI_Status* NG_MPI_STATUS_IGNORE = 0; int NG_MPI_ANY_SOURCE = 0; int NG_MPI_ANY_TAG = 0; int NG_MPI_MAX_PROCESSOR_NAME = 0; int NG_MPI_PROC_NULL = 0; int NG_MPI_ROOT = 0; int NG_MPI_SUBVERSION = 0; int NG_MPI_THREAD_MULTIPLE = 0; int NG_MPI_THREAD_SINGLE = 0; int NG_MPI_VERSION = 0; void* NG_MPI_IN_PLACE = 0; ================================================ FILE: libsrc/core/ng_mpi_generated_init.hpp ================================================ NG_MPI_Wtime = []()->double { return MPI_Wtime(); }; NG_MPI_Allgather = [](void* arg0, int arg1, NG_MPI_Datatype arg2, void* arg3, int arg4, NG_MPI_Datatype arg5, NG_MPI_Comm arg6)->int { return MPI_Allgather( arg0, arg1, ng2mpi(arg2), arg3, arg4, ng2mpi(arg5), ng2mpi(arg6)); }; NG_MPI_Allreduce = [](void* arg0, void* arg1, int arg2, NG_MPI_Datatype arg3, NG_MPI_Op arg4, NG_MPI_Comm arg5)->int { return MPI_Allreduce( arg0, arg1, arg2, ng2mpi(arg3), ng2mpi(arg4), ng2mpi(arg5)); }; NG_MPI_Alltoall = [](void* arg0, int arg1, NG_MPI_Datatype arg2, void* arg3, int arg4, NG_MPI_Datatype arg5, NG_MPI_Comm arg6)->int { return MPI_Alltoall( arg0, arg1, ng2mpi(arg2), arg3, arg4, ng2mpi(arg5), ng2mpi(arg6)); }; NG_MPI_Barrier = [](NG_MPI_Comm arg0)->int { return MPI_Barrier( ng2mpi(arg0)); }; NG_MPI_Bcast = [](void* arg0, int arg1, NG_MPI_Datatype arg2, int arg3, NG_MPI_Comm arg4)->int { return MPI_Bcast( arg0, arg1, ng2mpi(arg2), arg3, ng2mpi(arg4)); }; NG_MPI_Ibcast = [](void* arg0, int arg1, NG_MPI_Datatype arg2, int arg3, NG_MPI_Comm arg4, NG_MPI_Request* arg5)->int { return MPI_Ibcast( arg0, arg1, ng2mpi(arg2), arg3, ng2mpi(arg4), ng2mpi(arg5)); }; NG_MPI_Comm_c2f = [](NG_MPI_Comm arg0)->int { return MPI_Comm_c2f( ng2mpi(arg0)); }; NG_MPI_Comm_create = [](NG_MPI_Comm arg0, NG_MPI_Group arg1, NG_MPI_Comm* arg2)->int { return MPI_Comm_create( ng2mpi(arg0), ng2mpi(arg1), ng2mpi(arg2)); }; NG_MPI_Comm_create_group = [](NG_MPI_Comm arg0, NG_MPI_Group arg1, int arg2, NG_MPI_Comm* arg3)->int { return MPI_Comm_create_group( ng2mpi(arg0), ng2mpi(arg1), arg2, ng2mpi(arg3)); }; NG_MPI_Comm_free = [](NG_MPI_Comm* arg0)->int { return MPI_Comm_free( ng2mpi(arg0)); }; NG_MPI_Comm_group = [](NG_MPI_Comm arg0, NG_MPI_Group* arg1)->int { return MPI_Comm_group( ng2mpi(arg0), ng2mpi(arg1)); }; NG_MPI_Comm_rank = [](NG_MPI_Comm arg0, int* arg1)->int { return MPI_Comm_rank( ng2mpi(arg0), arg1); }; NG_MPI_Comm_size = [](NG_MPI_Comm arg0, int* arg1)->int { return MPI_Comm_size( ng2mpi(arg0), arg1); }; NG_MPI_Finalize = []()->int { return MPI_Finalize(); }; NG_MPI_Gather = [](void* arg0, int arg1, NG_MPI_Datatype arg2, void* arg3, int arg4, NG_MPI_Datatype arg5, int arg6, NG_MPI_Comm arg7)->int { return MPI_Gather( arg0, arg1, ng2mpi(arg2), arg3, arg4, ng2mpi(arg5), arg6, ng2mpi(arg7)); }; NG_MPI_Gatherv = [](void* arg0, int arg1, NG_MPI_Datatype arg2, void* arg3, int* arg4, int* arg5, NG_MPI_Datatype arg6, int arg7, NG_MPI_Comm arg8)->int { return MPI_Gatherv( arg0, arg1, ng2mpi(arg2), arg3, arg4, arg5, ng2mpi(arg6), arg7, ng2mpi(arg8)); }; NG_MPI_Get_count = [](NG_MPI_Status* arg0, NG_MPI_Datatype arg1, int* arg2)->int { return MPI_Get_count( ng2mpi(arg0), ng2mpi(arg1), arg2); }; NG_MPI_Get_processor_name = [](char* arg0, int* arg1)->int { return MPI_Get_processor_name( arg0, arg1); }; NG_MPI_Group_incl = [](NG_MPI_Group arg0, int arg1, int* arg2, NG_MPI_Group* arg3)->int { return MPI_Group_incl( ng2mpi(arg0), arg1, arg2, ng2mpi(arg3)); }; NG_MPI_Init = [](int* arg0, char*** arg1)->int { return MPI_Init( arg0, arg1); }; NG_MPI_Init_thread = [](int* arg0, char*** arg1, int arg2, int* arg3)->int { return MPI_Init_thread( arg0, arg1, arg2, arg3); }; NG_MPI_Initialized = [](int* arg0)->int { return MPI_Initialized( arg0); }; NG_MPI_Iprobe = [](int arg0, int arg1, NG_MPI_Comm arg2, int* arg3, NG_MPI_Status* arg4)->int { return MPI_Iprobe( arg0, arg1, ng2mpi(arg2), arg3, ng2mpi(arg4)); }; NG_MPI_Irecv = [](void* arg0, int arg1, NG_MPI_Datatype arg2, int arg3, int arg4, NG_MPI_Comm arg5, NG_MPI_Request* arg6)->int { return MPI_Irecv( arg0, arg1, ng2mpi(arg2), arg3, arg4, ng2mpi(arg5), ng2mpi(arg6)); }; NG_MPI_Isend = [](void* arg0, int arg1, NG_MPI_Datatype arg2, int arg3, int arg4, NG_MPI_Comm arg5, NG_MPI_Request* arg6)->int { return MPI_Isend( arg0, arg1, ng2mpi(arg2), arg3, arg4, ng2mpi(arg5), ng2mpi(arg6)); }; NG_MPI_Probe = [](int arg0, int arg1, NG_MPI_Comm arg2, NG_MPI_Status* arg3)->int { return MPI_Probe( arg0, arg1, ng2mpi(arg2), ng2mpi(arg3)); }; NG_MPI_Query_thread = [](int* arg0)->int { return MPI_Query_thread( arg0); }; NG_MPI_Recv = [](void* arg0, int arg1, NG_MPI_Datatype arg2, int arg3, int arg4, NG_MPI_Comm arg5, NG_MPI_Status* arg6)->int { return MPI_Recv( arg0, arg1, ng2mpi(arg2), arg3, arg4, ng2mpi(arg5), ng2mpi(arg6)); }; NG_MPI_Recv_init = [](void* arg0, int arg1, NG_MPI_Datatype arg2, int arg3, int arg4, NG_MPI_Comm arg5, NG_MPI_Request* arg6)->int { return MPI_Recv_init( arg0, arg1, ng2mpi(arg2), arg3, arg4, ng2mpi(arg5), ng2mpi(arg6)); }; NG_MPI_Reduce = [](void* arg0, void* arg1, int arg2, NG_MPI_Datatype arg3, NG_MPI_Op arg4, int arg5, NG_MPI_Comm arg6)->int { return MPI_Reduce( arg0, arg1, arg2, ng2mpi(arg3), ng2mpi(arg4), arg5, ng2mpi(arg6)); }; NG_MPI_Reduce_local = [](void* arg0, void* arg1, int arg2, NG_MPI_Datatype arg3, NG_MPI_Op arg4)->int { return MPI_Reduce_local( arg0, arg1, arg2, ng2mpi(arg3), ng2mpi(arg4)); }; NG_MPI_Request_free = [](NG_MPI_Request* arg0)->int { return MPI_Request_free( ng2mpi(arg0)); }; NG_MPI_Scatter = [](void* arg0, int arg1, NG_MPI_Datatype arg2, void* arg3, int arg4, NG_MPI_Datatype arg5, int arg6, NG_MPI_Comm arg7)->int { return MPI_Scatter( arg0, arg1, ng2mpi(arg2), arg3, arg4, ng2mpi(arg5), arg6, ng2mpi(arg7)); }; NG_MPI_Send = [](void* arg0, int arg1, NG_MPI_Datatype arg2, int arg3, int arg4, NG_MPI_Comm arg5)->int { return MPI_Send( arg0, arg1, ng2mpi(arg2), arg3, arg4, ng2mpi(arg5)); }; NG_MPI_Send_init = [](void* arg0, int arg1, NG_MPI_Datatype arg2, int arg3, int arg4, NG_MPI_Comm arg5, NG_MPI_Request* arg6)->int { return MPI_Send_init( arg0, arg1, ng2mpi(arg2), arg3, arg4, ng2mpi(arg5), ng2mpi(arg6)); }; NG_MPI_Startall = [](int arg0, NG_MPI_Request* arg1)->int { return MPI_Startall( arg0, ng2mpi(arg1, arg0)); }; NG_MPI_Type_commit = [](NG_MPI_Datatype* arg0)->int { return MPI_Type_commit( ng2mpi(arg0)); }; NG_MPI_Type_contiguous = [](int arg0, NG_MPI_Datatype arg1, NG_MPI_Datatype* arg2)->int { return MPI_Type_contiguous( arg0, ng2mpi(arg1), ng2mpi(arg2)); }; NG_MPI_Type_create_resized = [](NG_MPI_Datatype arg0, NG_MPI_Aint arg1, NG_MPI_Aint arg2, NG_MPI_Datatype* arg3)->int { return MPI_Type_create_resized( ng2mpi(arg0), ng2mpi(arg1), ng2mpi(arg2), ng2mpi(arg3)); }; NG_MPI_Type_create_struct = [](int arg0, int* arg1, NG_MPI_Aint* arg2, NG_MPI_Datatype* arg3, NG_MPI_Datatype* arg4)->int { return MPI_Type_create_struct( arg0, arg1, ng2mpi(arg2, arg0), ng2mpi(arg3, arg0), ng2mpi(arg4)); }; NG_MPI_Type_free = [](NG_MPI_Datatype* arg0)->int { return MPI_Type_free( ng2mpi(arg0)); }; NG_MPI_Type_get_extent = [](NG_MPI_Datatype arg0, NG_MPI_Aint* arg1, NG_MPI_Aint* arg2)->int { return MPI_Type_get_extent( ng2mpi(arg0), ng2mpi(arg1), ng2mpi(arg2)); }; NG_MPI_Type_indexed = [](int arg0, int* arg1, int* arg2, NG_MPI_Datatype arg3, NG_MPI_Datatype* arg4)->int { return MPI_Type_indexed( arg0, arg1, arg2, ng2mpi(arg3), ng2mpi(arg4)); }; NG_MPI_Type_size = [](NG_MPI_Datatype arg0, int* arg1)->int { return MPI_Type_size( ng2mpi(arg0), arg1); }; NG_MPI_Wait = [](NG_MPI_Request* arg0, NG_MPI_Status* arg1)->int { return MPI_Wait( ng2mpi(arg0), ng2mpi(arg1)); }; NG_MPI_Waitall = [](int arg0, NG_MPI_Request* arg1, NG_MPI_Status* arg2)->int { return MPI_Waitall( arg0, ng2mpi(arg1, arg0), ng2mpi(arg2)); }; NG_MPI_Waitany = [](int arg0, NG_MPI_Request* arg1, int* arg2, NG_MPI_Status* arg3)->int { return MPI_Waitany( arg0, ng2mpi(arg1, arg0), arg2, ng2mpi(arg3)); }; NG_MPI_COMM_NULL = mpi2ng(MPI_COMM_NULL); NG_MPI_COMM_WORLD = mpi2ng(MPI_COMM_WORLD); NG_MPI_CHAR = mpi2ng(MPI_CHAR); NG_MPI_CXX_DOUBLE_COMPLEX = mpi2ng(MPI_CXX_DOUBLE_COMPLEX); NG_MPI_C_BOOL = mpi2ng(MPI_C_BOOL); NG_MPI_DATATYPE_NULL = mpi2ng(MPI_DATATYPE_NULL); NG_MPI_DOUBLE = mpi2ng(MPI_DOUBLE); NG_MPI_FLOAT = mpi2ng(MPI_FLOAT); NG_MPI_INT = mpi2ng(MPI_INT); NG_MPI_SHORT = mpi2ng(MPI_SHORT); NG_MPI_UINT64_T = mpi2ng(MPI_UINT64_T); NG_MPI_LOR = mpi2ng(MPI_LOR); NG_MPI_MAX = mpi2ng(MPI_MAX); NG_MPI_MIN = mpi2ng(MPI_MIN); NG_MPI_SUM = mpi2ng(MPI_SUM); NG_MPI_REQUEST_NULL = mpi2ng(MPI_REQUEST_NULL); NG_MPI_STATUSES_IGNORE = mpi2ng(MPI_STATUSES_IGNORE); NG_MPI_STATUS_IGNORE = mpi2ng(MPI_STATUS_IGNORE); NG_MPI_ANY_SOURCE = mpi2ng(MPI_ANY_SOURCE); NG_MPI_ANY_TAG = mpi2ng(MPI_ANY_TAG); NG_MPI_MAX_PROCESSOR_NAME = mpi2ng(MPI_MAX_PROCESSOR_NAME); NG_MPI_PROC_NULL = mpi2ng(MPI_PROC_NULL); NG_MPI_ROOT = mpi2ng(MPI_ROOT); NG_MPI_SUBVERSION = mpi2ng(MPI_SUBVERSION); NG_MPI_THREAD_MULTIPLE = mpi2ng(MPI_THREAD_MULTIPLE); NG_MPI_THREAD_SINGLE = mpi2ng(MPI_THREAD_SINGLE); NG_MPI_VERSION = mpi2ng(MPI_VERSION); NG_MPI_IN_PLACE = mpi2ng(MPI_IN_PLACE); ================================================ FILE: libsrc/core/ng_mpi_native.hpp ================================================ #ifndef NG_MPI_NATIVE_HPP #define NG_MPI_NATIVE_HPP #include #include "mpi_wrapper.hpp" #include "ng_mpi.hpp" namespace ngcore { MPI_Comm NG_MPI_Native(NG_MPI_Comm comm) { return reinterpret_cast(comm.value); } MPI_Comm NG_MPI_Native(NgMPI_Comm comm) { return reinterpret_cast(static_cast(comm).value); } NG_MPI_Comm NG_MPI_From_Native (MPI_Comm comm) { return {reinterpret_cast(comm)}; } } // namespace ngcore #endif // NG_MPI_NATIVE_HPP ================================================ FILE: libsrc/core/ng_mpi_wrapper.cpp ================================================ #ifdef PARALLEL #include #include #include #include "ng_mpi.hpp" #include "ngstream.hpp" #ifdef NG_PYTHON #include "python_ngcore.hpp" #endif // NG_PYTHON #include "utils.hpp" using std::cerr; using std::cout; using std::endl; #ifndef NG_MPI_WRAPPER #ifdef NG_PYTHON #define MPI4PY_LIMITED_API 1 #define MPI4PY_LIMITED_API_SKIP_MESSAGE 1 #define MPI4PY_LIMITED_API_SKIP_SESSION 1 #include "mpi4py_pycapi.h" // mpi4py < 4.0.0 #endif // NG_PYTHON #endif // NG_MPI_WRAPPER namespace ngcore { #ifdef NG_MPI_WRAPPER static std::unique_ptr mpi_lib, ng_mpi_lib; static bool need_mpi_finalize = false; struct MPIFinalizer { ~MPIFinalizer() { if (need_mpi_finalize) { cout << IM(5) << "Calling MPI_Finalize" << endl; NG_MPI_Finalize(); } } } mpi_finalizer; bool MPI_Loaded() { return ng_mpi_lib != nullptr; } void InitMPI(std::optional mpi_lib_path) { if (ng_mpi_lib) return; cout << IM(3) << "InitMPI" << endl; std::string vendor = ""; std::string mpi4py_lib_file = ""; if (mpi_lib_path) { // Dynamic load of given shared MPI library // Then call MPI_Init, read the library version and set the vender name try { typedef int (*init_handle)(int *, char ***); typedef int (*mpi_initialized_handle)(int *); mpi_lib = std::make_unique(*mpi_lib_path, std::nullopt, true); auto mpi_init = mpi_lib->GetSymbol("MPI_Init"); auto mpi_initialized = mpi_lib->GetSymbol("MPI_Initialized"); int flag = 0; mpi_initialized(&flag); if (!flag) { typedef const char *pchar; int argc = 1; pchar args[] = {"netgen", nullptr}; pchar *argv = &args[0]; cout << IM(5) << "Calling MPI_Init" << endl; mpi_init(&argc, (char ***)argv); need_mpi_finalize = true; } char c_version_string[65536]; c_version_string[0] = '\0'; int result_len = 0; typedef void (*get_version_handle)(char *, int *); auto get_version = mpi_lib->GetSymbol("MPI_Get_library_version"); get_version(c_version_string, &result_len); std::string version = c_version_string; if (version.substr(0, 8) == "Open MPI") vendor = "Open MPI"; else if (version.substr(0, 5) == "MPICH") vendor = "MPICH"; else if (version.substr(0, 13) == "Microsoft MPI") vendor = "Microsoft MPI"; else if (version.substr(0, 12) == "Intel(R) MPI") vendor = "Intel MPI"; else throw std::runtime_error( std::string("Unknown MPI version: " + version)); } catch (std::runtime_error &e) { cerr << "Could not load MPI: " << e.what() << endl; throw e; } } else { #ifdef NG_PYTHON // Use mpi4py to init MPI library and get the vendor name auto mpi4py = py::module::import("mpi4py.MPI"); vendor = mpi4py.attr("get_vendor")()[py::int_(0)].cast(); #ifndef WIN32 // Load mpi4py library (it exports all MPI symbols) to have all MPI symbols // available before the ng_mpi wrapper is loaded This is not necessary on // windows as the matching mpi dll is linked to the ng_mpi wrapper directly mpi4py_lib_file = mpi4py.attr("__file__").cast(); mpi_lib = std::make_unique(mpi4py_lib_file, std::nullopt, true); #endif // WIN32 #endif // NG_PYTHON } std::string ng_lib_name = ""; if (vendor == "Open MPI") ng_lib_name = "ng_openmpi"; else if (vendor == "MPICH") ng_lib_name = "ng_mpich"; else if (vendor == "Microsoft MPI") ng_lib_name = "ng_microsoft_mpi"; else if (vendor == "Intel MPI") ng_lib_name = "ng_intel_mpi"; else throw std::runtime_error("Unknown MPI vendor: " + vendor); ng_lib_name += NETGEN_SHARED_LIBRARY_SUFFIX; // Load the ng_mpi wrapper and call ng_init_mpi to set all function pointers typedef void (*ng_init_handle)(); ng_mpi_lib = std::make_unique(ng_lib_name); ng_mpi_lib->GetSymbol("ng_init_mpi")(); std::cout << IM(3) << "MPI wrapper loaded, vendor: " << vendor << endl; } static std::runtime_error no_mpi() { return std::runtime_error("MPI not enabled"); } #ifdef NG_PYTHON decltype(NG_MPI_CommFromMPI4Py) NG_MPI_CommFromMPI4Py = [](py::handle py_obj, NG_MPI_Comm &ng_comm) -> bool { // If this gets called, it means that we want to convert an mpi4py // communicator to a Netgen MPI communicator, but the Netgen MPI wrapper // runtime was not yet initialized. // store the current address of this function auto old_converter_address = NG_MPI_CommFromMPI4Py; // initialize the MPI wrapper runtime, this sets all the function pointers InitMPI(); // if the initialization was successful, the function pointer should have // changed // -> call the actual conversion function if (NG_MPI_CommFromMPI4Py != old_converter_address) return NG_MPI_CommFromMPI4Py(py_obj, ng_comm); // otherwise, something strange happened throw no_mpi(); }; decltype(NG_MPI_CommToMPI4Py) NG_MPI_CommToMPI4Py = [](NG_MPI_Comm) -> py::handle { throw no_mpi(); }; #endif // NG_PYTHON #include "ng_mpi_generated_dummy_init.hpp" #else // NG_MPI_WRAPPER static bool imported_mpi4py = false; #ifdef NG_PYTHON decltype(NG_MPI_CommFromMPI4Py) NG_MPI_CommFromMPI4Py = [](py::handle src, NG_MPI_Comm &dst) -> bool { if (!imported_mpi4py) { import_mpi4py__MPI(); imported_mpi4py = true; } PyObject *py_src = src.ptr(); // auto type = Py_TYPE(py_src); if (PyObject_TypeCheck(py_src, &PyMPIComm_Type)) { dst = *PyMPIComm_Get(py_src); return !PyErr_Occurred(); } return false; }; decltype(NG_MPI_CommToMPI4Py) NG_MPI_CommToMPI4Py = [](NG_MPI_Comm src) -> py::handle { if (!imported_mpi4py) { import_mpi4py__MPI(); imported_mpi4py = true; } return py::handle(PyMPIComm_New(src)); }; #endif // NG_PYTHON bool MPI_Loaded() { return true; } void InitMPI(std::optional) {} #endif // NG_MPI_WRAPPER } // namespace ngcore #endif // PARALLEL ================================================ FILE: libsrc/core/ngcore.hpp ================================================ #ifndef NETGEN_CORE_NGCORE_HPP #define NETGEN_CORE_NGCORE_HPP #include "archive.hpp" #include "array.hpp" #include "bitarray.hpp" #include "exception.hpp" #include "flags.hpp" #include "table.hpp" #include "hashtable.hpp" #include "localheap.hpp" #include "logging.hpp" // #include "mpi_wrapper.hpp" #include "profiler.hpp" #include "signal.hpp" #include "simd.hpp" #include "autodiff.hpp" #include "autodiffdiff.hpp" #include "symboltable.hpp" #include "taskmanager.hpp" #include "version.hpp" #include "xbool.hpp" #include "ngstream.hpp" #include "utils.hpp" #include "ranges.hpp" #include "statushandler.hpp" #endif // NETGEN_CORE_NGCORE_HPP ================================================ FILE: libsrc/core/ngcore_api.hpp ================================================ #ifndef NETGEN_CORE_NGCORE_API_HPP #define NETGEN_CORE_NGCORE_API_HPP #include "netgen_config.hpp" #ifdef WIN32 // This function or variable may be unsafe. Consider using _ftime64_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details. #pragma warning(disable:4244) #pragma warning(disable:4996) // multiple inheritance via dominance #pragma warning(disable:4250) // needs to have dll-interface to be used by clients of class #pragma warning(disable:4251) // size_t to int conversion: #pragma warning(disable:4267) // non dll-interface class 'std::exception' used as base for dll-interface class #pragma warning(disable:4275) // C++ exception specification ignored except to indicate a function is not __declspec(nothrow) #pragma warning(disable:4290) // no suitable definition provided for explicit template instantiation request #pragma warning(disable:4661) // bool-int conversion #pragma warning(disable:4800) // '__declspec(dllexport)' and 'extern' are incompatible on an explicit instantiation #pragma warning(disable:4910) #endif // WIN32 #ifdef WIN32 #define NGCORE_API_EXPORT __declspec(dllexport) #define NGCORE_API_IMPORT __declspec(dllimport) #else #define NGCORE_API_EXPORT __attribute__((visibility("default"))) #define NGCORE_API_IMPORT __attribute__((visibility("default"))) #endif #ifdef NGCORE_EXPORTS #define NGCORE_API NGCORE_API_EXPORT #else #define NGCORE_API NGCORE_API_IMPORT #endif // Set __host__ __device__ for all inline functions #ifdef __CUDACC__ #define NETGEN_HD __host__ __device__ #else // __CUDACC__ #define NETGEN_HD #endif // __CUDACC__ #ifdef __CUDACC__ // partial override of overloaded function (Archive, MultAdd) #pragma nv_diag_suppress 611 #endif #ifdef __INTEL_COMPILER #define NETGEN_ALWAYS_INLINE __forceinline #define NETGEN_INLINE __forceinline inline #ifdef WIN32 #define NETGEN_LAMBDA_INLINE #else #define NETGEN_LAMBDA_INLINE __attribute__ ((__always_inline__)) #endif #else #ifdef __GNUC__ #define NETGEN_ALWAYS_INLINE __attribute__ ((__always_inline__)) #define NETGEN_INLINE __attribute__ ((__always_inline__)) inline NETGEN_HD #define NETGEN_LAMBDA_INLINE __attribute__ ((__always_inline__)) NETGEN_HD #define NETGEN_VLA #else #define NETGEN_ALWAYS_INLINE #define NETGEN_INLINE inline #define NETGEN_LAMBDA_INLINE #endif #endif #if defined(__amd64__) || defined(_M_AMD64) #define NETGEN_ARCH_AMD64 #endif #if defined(__aarch64__) || defined(_M_ARM64) #define NETGEN_ARCH_ARM64 #endif #if defined(__arm__) || defined(_M_ARM) #define NETGEN_ARCH_ARM #endif #ifdef __MAC_OS_X_VERSION_MIN_REQUIRED #if __MAC_OS_X_VERSION_MIN_REQUIRED < 101400 // The c++ standard library on MacOS 10.13 and earlier has no aligned new operator, // thus implement it here globally #include #ifdef __clang__ #pragma clang diagnostic ignored "-Winline-new-delete" #endif inline void * operator new (size_t s, std::align_val_t al) { if (int(al) > __STDCPP_DEFAULT_NEW_ALIGNMENT__) return _mm_malloc(s, int(al)); else return new char[s]; } inline void * operator new[] (size_t s, std::align_val_t al) { if (int(al) > __STDCPP_DEFAULT_NEW_ALIGNMENT__) return _mm_malloc(s, int(al)); else return new char[s]; } inline void operator delete ( void* ptr, std::align_val_t al ) noexcept { if (int(al) > __STDCPP_DEFAULT_NEW_ALIGNMENT__) _mm_free(ptr); else delete (char*)ptr; } inline void operator delete[]( void* ptr, std::align_val_t al ) noexcept { if (int(al) > __STDCPP_DEFAULT_NEW_ALIGNMENT__) _mm_free(ptr); else delete[] (char*)ptr; } inline void operator delete ( void* ptr, std::size_t sz, std::align_val_t al ) noexcept { if (int(al) > __STDCPP_DEFAULT_NEW_ALIGNMENT__) _mm_free(ptr); else delete (char*)ptr; } inline void operator delete[]( void* ptr, std::size_t sz, std::align_val_t al ) noexcept { if (int(al) > __STDCPP_DEFAULT_NEW_ALIGNMENT__) _mm_free(ptr); else delete[] (char*)ptr; } #endif // __MAC_OS_X_VERSION_MIN_REQUIRED #endif // __MAC_OS_X_VERSION_MIN_REQUIRED < 101300 #endif // NETGEN_CORE_NGCORE_API_HPP ================================================ FILE: libsrc/core/ngstream.hpp ================================================ #ifndef FILE_NGSTREAM #define FILE_NGSTREAM /**************************************************************************/ /* File: ng(s)stream.hpp */ /* Author: Joachim Schoeberl */ /* Date: 20. Jul. 2011 */ /**************************************************************************/ // #include // #include namespace ngcore { NGCORE_API extern int printmessage_importance; // important message class IM { int value; public: IM (int val) : value(val) { ; } int Value () const { return value; } }; class trunc { double eps; public: trunc (double aeps) : eps(aeps) { ; } double Eps() const { return eps; } }; class NGSOStream { std::ostream & ost; bool active; NGCORE_API static bool glob_active; double trunc; public: NGSOStream (std::ostream & aost, bool aactive) : ost(aost), active(aactive), trunc(-1) { ; } NGSOStream & SetTrunc (double atrunc) { trunc = atrunc; return *this; } double GetTrunc () const { return trunc; } bool Active () const { return active && glob_active; } std::ostream & GetStream () { return ost; } static void SetGlobalActive (bool b) { glob_active = b; } }; inline NGSOStream operator<< (std::ostream & ost, const IM & im) { return NGSOStream (ost, (im.Value() <= printmessage_importance)); } /* // doesn't work for matrices inline NGSOStream operator<< (ostream & ost, trunc tr) { cout << "set trunc modifier" << endl; return NGSOStream (ost, true).SetTrunc (tr.Eps()); } */ template inline NGSOStream operator<< (NGSOStream ngsost, const T & data) { if (ngsost.Active()) ngsost.GetStream() << data; return ngsost; } /* inline NGSOStream operator<< (NGSOStream ngsost, const double & data) { cout << "double out" << endl; if (ngsost.Active()) { double hdata = data; if (fabs (hdata) < ngsost.GetTrunc()) hdata = 0.0; ngsost.GetStream() << hdata; } return ngsost; } */ inline NGSOStream operator<< (NGSOStream ngsost, std::ostream& ( *pf )(std::ostream&)) { if ( ngsost.Active() ) ngsost.GetStream() << (*pf); return ngsost; } inline NGSOStream operator<< (NGSOStream ngsost, std::ios& ( *pf )(std::ios&)) { if ( ngsost.Active() ) ngsost.GetStream() << (*pf); return ngsost; } inline NGSOStream operator<< (NGSOStream ngsost, std::ios_base& ( *pf )(std::ios_base&)) { if ( ngsost.Active() ) ngsost.GetStream() << (*pf); return ngsost; } } #endif ================================================ FILE: libsrc/core/paje_trace.cpp ================================================ #include #include #include #include #include #include #include "archive.hpp" // for Demangle #include "paje_trace.hpp" #include "ng_mpi.hpp" #include "profiler.hpp" #include "mpi_wrapper.hpp" extern const char *header; constexpr int MPI_PAJE_WRITER = 1; constexpr int ASSUMED_MPI_MAX_PROCESSOR_NAME = 256; namespace ngcore { static std::string GetTimerName( int id ) { #ifndef PARALLEL return NgProfiler::GetName(id); #else // PARALLEL if(id PajeTrace::memory_events; // Produce no traces by default size_t PajeTrace::max_tracefile_size = 0; // If true, produce variable counting active threads // increases trace by a factor of two bool PajeTrace::trace_thread_counter = false; bool PajeTrace::trace_threads = true; bool PajeTrace::mem_tracing_enabled = true; bool PajeTrace::write_paje_file = true; PajeTrace :: PajeTrace(int anthreads, std::string aname) { nthreads = anthreads; tracefile_name = std::move(aname); int bytes_per_event=33; max_num_events_per_thread = std::min( static_cast(std::numeric_limits::max()), max_tracefile_size/bytes_per_event/(nthreads+1+trace_thread_counter*nthreads)*10/7); if(max_num_events_per_thread>0) { logger->info( "Tracefile size = {}MB", max_tracefile_size/1024/1024); logger->info( "Tracing {} events per thread", max_num_events_per_thread); } tasks.resize(nthreads); int reserve_size = std::min(1000000U, max_num_events_per_thread); for(auto & t : tasks) t.reserve(reserve_size); links.resize(nthreads); for(auto & l : links) l.reserve(reserve_size); jobs.reserve(reserve_size); timer_events.reserve(reserve_size); gpu_events.reserve(reserve_size); memory_events.reserve(1024*1024); // sync start time when running in parallel #ifdef PARALLEL if(MPI_Loaded()) { NgMPI_Comm comm(NG_MPI_COMM_WORLD); for([[maybe_unused]] auto i : Range(5)) comm.Barrier(); } #endif // PARALLEL start_time = GetTimeCounter(); tracing_enabled = true; mem_tracing_enabled = true; n_memory_events_at_start = memory_events.size(); } PajeTrace :: ~PajeTrace() { for(auto & ltask : tasks) for(auto & task : ltask) { task.time -= start_time; } for(auto & job : jobs) { job.start_time -= start_time; job.stop_time -= start_time; } for(auto & event : timer_events) event.time -= start_time; for(auto & event : user_events) { event.t_start -= start_time; event.t_end -= start_time; } for(auto & event : gpu_events) event.time -= start_time; for(auto & llink : links) for(auto & link : llink) link.time -= start_time; for(auto i : IntRange(n_memory_events_at_start, memory_events.size())) memory_events[i].time -= start_time; NgMPI_Comm comm; #ifdef PARALLEL if(MPI_Loaded()) comm = NgMPI_Comm(NG_MPI_COMM_WORLD); #endif if(comm.Size()==1) { Write(); } else { // make sure the timer id is unique across all ranks for(auto & event : timer_events) event.timer_id += NgProfiler::SIZE*comm.Rank(); for(auto & event : gpu_events) event.timer_id += NgProfiler::SIZE*comm.Rank(); if(comm.Rank() == MPI_PAJE_WRITER) Write(); else SendData(); } } void PajeTrace::StopTracing() { if(tracing_enabled && max_num_events_per_thread>0) { logger->warn("Maximum number of traces reached, tracing is stopped now."); } tracing_enabled = false; } class PajeFile { public: static void Hue2RGB ( double x, double &r, double &g, double &b ) { double d = 1.0/6.0; if(x logger = GetLogger("PajeTrace"); double ConvertTime(TTimePoint t) { // return time in milliseconds as double // return std::chrono::duration(t-start_time).count()*1000.0; // return std::chrono::duration(t-start_time).count() / 2.7e3; return 1000.0*static_cast(t) * seconds_per_tick; } enum PType { SET_VARIABLE=1, ADD_VARIABLE, SUB_VARIABLE, PUSH_STATE, POP_STATE, START_LINK, STOP_LINK }; struct PajeEvent { PajeEvent( int aevent_type, double atime, int atype, int acontainer, double avar_value ) : time(atime), var_value(avar_value), event_type(aevent_type), type(atype), container(acontainer) { } PajeEvent( int aevent_type, double atime, int atype, int acontainer, int avalue = 0, int aid = 0, bool avalue_is_alias = true ) : time(atime), event_type(aevent_type), type(atype), container(acontainer), value(avalue), id(aid), value_is_alias(avalue_is_alias) { } PajeEvent( int aevent_type, double atime, int atype, int acontainer, std::string as_value, int aid = 0 ) : time(atime), event_type(aevent_type), type(atype), container(acontainer), s_value(as_value), id(aid), value_is_alias(false), value_is_int(false) { } PajeEvent( int aevent_type, double atime, int atype, int acontainer, int avalue, int astart_container, int akey ) : time(atime), event_type(aevent_type), type(atype), container(acontainer), value(avalue), start_container(astart_container), id(akey) { } double time; double var_value = 0.0; int event_type; int type; int container; std::string s_value = ""; int value = 0; int start_container = 0; int id = 0; bool value_is_alias = true; bool value_is_int = true; bool operator < (const PajeEvent & other) const { /* // Same start and stop times can occur for very small tasks -> take "starting" events first (eg. PajePushState before PajePopState) if(time == other.time) { if(value == other.value) // same timer - first start, then stop return event_type < other.event_type; else // different timers - first stop, then start return event_type > other.event_type; } */ return (time < other.time); } int write(FILE *stream) { const int &key = id; const int &end_container = start_container; switch(event_type) { case PajeSetVariable: return fprintf( stream, "%d\t%.15g\ta%d\ta%d\t%.15g\n", PajeSetVariable, time, type, container, var_value ); // NOLINT case PajeAddVariable: return fprintf( stream, "%d\t%.15g\ta%d\ta%d\t%.15g\n", PajeAddVariable, time, type, container, var_value ); // NOLINT case PajeSubVariable: return fprintf( stream, "%d\t%.15g\ta%d\ta%d\t%.15g\n", PajeSubVariable, time, type, container, var_value ); // NOLINT case PajePushState: if(value_is_alias) return fprintf( stream, "%d\t%.15g\ta%d\ta%d\ta%d\t%d\n", PajePushState, time, type, container, value, id); // NOLINT else if(value_is_int) return fprintf( stream, "%d\t%.15g\ta%d\ta%d\t%d\t%d\n", PajePushState, time, type, container, value, id); // NOLINT else return fprintf( stream, "%d\t%.15g\ta%d\ta%d\t\"%s\"\t%d\n", PajePushState, time, type, container, s_value.c_str(), id); // NOLINT case PajePopState: return fprintf( stream, "%d\t%.15g\ta%d\ta%d\n", PajePopState, time, type, container ); // NOLINT case PajeStartLink: return fprintf( stream, "%d\t%.15g\ta%d\ta%d\t%d\ta%d\t%d\n", PajeStartLink, time, type, container, value, start_container, key ); // NOLINT case PajeEndLink: return fprintf( stream, "%d\t%.15g\ta%d\ta%d\t%d\ta%d\t%d\n", PajeEndLink, time, type, container, value, end_container, key ); // NOLINT } return 0; } }; std::vector events; public: PajeFile() = delete; PajeFile(const PajeFile &) = delete; PajeFile(PajeFile &&) = delete; void operator=(const PajeFile &) = delete; void operator=(PajeFile &&) = delete; PajeFile( const std::string & filename) { std::string fname = filename + ".trace"; ctrace_stream = fopen (fname.c_str(),"w"); // NOLINT fprintf(ctrace_stream, "%s", header ); // NOLINT alias_counter = 0; } ~PajeFile() { fclose (ctrace_stream); // NOLINT } int DefineContainerType ( int parent_type, const std::string & name ) { int alias = ++alias_counter; if(parent_type!=0) fprintf( ctrace_stream, "%d\ta%d\ta%d\t\"%s\"\n", PajeDefineContainerType, alias, parent_type, name.c_str() ); // NOLINT else fprintf( ctrace_stream, "%d\ta%d\t%d\t\"%s\"\n", PajeDefineContainerType, alias, parent_type, name.c_str() ); // NOLINT return alias; } int DefineVariableType ( int container_type, const std::string & name ) { int alias = ++alias_counter; fprintf( ctrace_stream, "%d\ta%d\ta%d\t\"%s\"\t\"1.0 1.0 1.0\"\n", PajeDefineVariableType, alias, container_type, name.c_str() ); // NOLINT return alias; } int DefineStateType ( int type, const std::string & name ) { int alias = ++alias_counter; fprintf( ctrace_stream, "%d\ta%d\ta%d\t\"%s\"\n", PajeDefineStateType, alias, type, name.c_str() ); // NOLINT return alias; } // int DefineEventType () // { // Write("event not implemented"); // } int DefineLinkType (int parent_container_type, int start_container_type, int stop_container_type, const std::string & name) { int alias = ++alias_counter; fprintf( ctrace_stream, "%d\ta%d\ta%d\ta%d\ta%d\t\"%s\"\n", PajeDefineLinkType, alias, parent_container_type, start_container_type, stop_container_type, name.c_str() ); // NOLINT return alias; } int DefineEntityValue (int type, const std::string & name, double hue = -1) { if(hue==-1) { std::hash shash; size_t h = shash(name); h ^= h>>32U; h = static_cast(h); hue = h*1.0/std::numeric_limits::max(); } int alias = ++alias_counter; double r; double g; double b; Hue2RGB( hue, r, g, b ); fprintf( ctrace_stream, "%d\ta%d\ta%d\t\"%s\"\t\"%.15g %.15g %.15g\"\n", PajeDefineEntityValue, alias, type, name.c_str(), r,g,b ); // NOLINT return alias; } int CreateContainer ( int type, int parent, const std::string & name ) { int alias = ++alias_counter; if(parent!=0) fprintf( ctrace_stream, "%d\t0\ta%d\ta%d\ta%d\t\"%s\"\n", PajeCreateContainer, alias, type, parent, name.c_str() ); // NOLINT else fprintf( ctrace_stream, "%d\t0\ta%d\ta%d\t%d\t\"%s\"\n", PajeCreateContainer, alias, type, parent, name.c_str() ); // NOLINT return alias; } void DestroyContainer () {} void SetVariable (TTimePoint time, int type, int container, double value ) { events.emplace_back( PajeEvent( PajeSetVariable, ConvertTime(time), type, container, value ) ); } void AddVariable (TTimePoint time, int type, int container, double value ) { events.emplace_back( PajeEvent( PajeAddVariable, ConvertTime(time), type, container, value ) ); } void SubVariable (TTimePoint time, int type, int container, double value ) { events.emplace_back( PajeEvent( PajeSubVariable, ConvertTime(time), type, container, value ) ); } void SetState () {} void PushState ( TTimePoint time, int type, int container, int value, int id = 0, bool value_is_alias = true ) { events.emplace_back( PajeEvent( PajePushState, ConvertTime(time), type, container, value, id, value_is_alias) ); } void PushState ( TTimePoint time, int type, int container, std::string value, int id = 0) { events.emplace_back( PajeEvent( PajePushState, ConvertTime(time), type, container, value, id) ); } void PopState ( TTimePoint time, int type, int container ) { events.emplace_back( PajeEvent( PajePopState, ConvertTime(time), type, container ) ); } void ResetState () {} void StartLink ( TTimePoint time, int type, int container, int value, int start_container, int key ) { events.emplace_back( PajeEvent( PajeStartLink, ConvertTime(time), type, container, value, start_container, key ) ); } void EndLink ( TTimePoint time, int type, int container, int value, int end_container, int key ) { events.emplace_back( PajeEvent( PajeEndLink, ConvertTime(time), type, container, value, end_container, key ) ); } void NewEvent () {} void WriteEvents() { logger->info("Sorting traces..."); // std::stable_sort (events.begin(), events.end()); logger->info("Writing traces... "); for (auto & event : events) { event.write( ctrace_stream ); // fprintf( ctrace_stream, "%s", buf ); // NOLINT } logger->info("Done"); } private: enum { PajeDefineContainerType = 0, PajeDefineVariableType = 1, PajeDefineStateType = 2, PajeDefineEventType = 3, PajeDefineLinkType = 4, PajeDefineEntityValue = 5, PajeCreateContainer = 6, PajeDestroyContainer = 7, PajeSetVariable = 8, PajeAddVariable = 9, PajeSubVariable = 10, PajeSetState = 11, PajePushState = 12, PajePopState = 13, PajeResetState = 14, PajeStartLink = 15, PajeEndLink = 16, PajeNewEvent = 17 }; }; NGCORE_API PajeTrace *trace; void PajeTrace::Write( ) { if(write_paje_file) WritePajeFile( tracefile_name ); WriteTimingChart(); #ifdef NETGEN_TRACE_MEMORY WriteMemoryChart(""); #endif // NETGEN_TRACE_MEMORY } void PajeTrace::WritePajeFile( const std::string & filename ) { auto n_events = jobs.size() + timer_events.size(); for(auto & vtasks : tasks) n_events += vtasks.size(); logger->info("{} events traced", n_events); if(n_events==0) { logger->info("No data traced, skip writing trace file"); return; } if(!tracing_enabled) { logger->warn("Tracing stopped during computation due to tracefile size limit of {} megabytes.", max_tracefile_size/1024/1024); } PajeFile paje(filename); const int container_type_task_manager = paje.DefineContainerType( 0, "Task Manager" ); const int container_type_node = paje.DefineContainerType( container_type_task_manager, "Node"); const int container_type_thread = paje.DefineContainerType( container_type_task_manager, "Thread"); const int container_type_timer = container_type_thread; //paje.DefineContainerType( container_type_task_manager, "Timers"); const int container_type_jobs = paje.DefineContainerType( container_type_task_manager, "Jobs"); const int container_type_memory = paje.DefineContainerType( container_type_task_manager, "Memory usage"); const int state_type_job = paje.DefineStateType( container_type_jobs, "Job" ); const int state_type_task = paje.DefineStateType( container_type_thread, "Task" ); const int state_type_timer = paje.DefineStateType( container_type_timer, "Timer state" ); int variable_type_active_threads = 0; if(trace_thread_counter) variable_type_active_threads = paje.DefineVariableType( container_type_jobs, "Active threads" ); const int container_task_manager = paje.CreateContainer( container_type_task_manager, 0, "The task manager" ); const int container_jobs = paje.CreateContainer( container_type_jobs, container_task_manager, "Jobs" ); int variable_type_memory = 0; const int container_memory = paje.CreateContainer( container_type_memory, container_task_manager, "Memory" ); if(mem_tracing_enabled) { variable_type_memory = paje.DefineVariableType( container_type_task_manager, "Memory [MB]" ); } int num_nodes = 1; //task_manager ? task_manager->GetNumNodes() : 1; std::vector thread_aliases; std::vector container_nodes; NgMPI_Comm comm; #ifdef PARALLEL if(MPI_Loaded()) comm = NgMPI_Comm(NG_MPI_COMM_WORLD); if(comm.Size()>1) { auto comm = NgMPI_Comm(NG_MPI_COMM_WORLD); nthreads = comm.Size(); thread_aliases.reserve(nthreads); std::array ahostname; int len; NG_MPI_Get_processor_name(ahostname.data(), &len); std::string hostname = ahostname.data(); std::map host_map; std::string name; for(auto i : IntRange(0, comm.Size())) { if(i!=MPI_PAJE_WRITER) comm.Recv(name, i, 0); else name = hostname; if(host_map.count(name)==0) { host_map[name] = container_nodes.size(); container_nodes.emplace_back( paje.CreateContainer( container_type_node, container_task_manager, name) ); } thread_aliases.emplace_back( paje.CreateContainer( container_type_thread, container_nodes[host_map[name]], "Rank " + ToString(i) ) ); } } else #endif { container_nodes.reserve(num_nodes); for(int i=0; i job_map; std::map job_task_map; for(Job & j : jobs) if(job_map.find(j.type) == job_map.end()) { std::string name = Demangle(j.type->name()); job_map[j.type] = paje.DefineEntityValue( state_type_job, name, -1 ); job_task_map[j.type] = paje.DefineEntityValue( state_type_task, name, -1 ); } for(Job & j : jobs) { paje.PushState( j.start_time, state_type_job, container_jobs, job_map[j.type] ); paje.PopState( j.stop_time, state_type_job, container_jobs ); } size_t memory_at_start = 0; for(const auto & i : IntRange(0, n_memory_events_at_start)) { if(memory_events[i].is_alloc) memory_at_start += memory_events[i].size; else memory_at_start -= memory_events[i].size; } paje.SetVariable( 0, variable_type_memory, container_memory, 1.0*memory_at_start/(1024*1024)); for(const auto & i : IntRange(n_memory_events_at_start, memory_events.size())) { auto & m = memory_events[i]; if(m.size==0) continue; double size = 1.0*m.size/(1024*1024); if(m.is_alloc) paje.AddVariable( m.time, variable_type_memory, container_memory, size); else paje.SubVariable( m.time, variable_type_memory, container_memory, size); } std::set timer_ids; std::map timer_aliases; std::map timer_names; for(auto & event : timer_events) timer_ids.insert(event.timer_id); for(auto & event : gpu_events) timer_ids.insert(event.timer_id); // Timer names for(auto & vtasks : tasks) for (Task & t : vtasks) if(t.id_type==Task::ID_TIMER) timer_ids.insert(t.id); for(auto id : timer_ids) timer_names[id] = GetTimerName(id); if(comm.Size()>1) { for(auto src : IntRange(0, comm.Size())) { if(src==MPI_PAJE_WRITER) continue; size_t n_timers; comm.Recv (n_timers, src, 0); int id; std::string name; for([[maybe_unused]]auto i : IntRange(n_timers)) { comm.Recv (id, src, 0); comm.Recv (name, src, 0); timer_ids.insert(id); timer_names[id] = name; } } } for(auto id : timer_ids) timer_aliases[id] = paje.DefineEntityValue( state_type_timer, timer_names[id], -1 ); int timerdepth = 0; int maxdepth = 0; for(auto & event : timer_events) { if(event.is_start) { timerdepth++; maxdepth = timerdepth>maxdepth ? timerdepth : maxdepth; } else timerdepth--; } std::vector timer_container_aliases; timer_container_aliases.resize(maxdepth); for(int i=0; i containers; for(auto i : Range(user_containers.size())) { auto & [name, parent] = user_containers[i]; int a_parent = parent == -1 ? container_task_manager : containers[parent]; containers[i] = paje.CreateContainer( container_type_timer, a_parent, name ); } for(auto ev : user_events) { if(containers[ev.container]==0) { std::string name = "User " + ToString(ev.container); containers[ev.container] = paje.CreateContainer( container_type_timer, container_task_manager, name ); } } int i_start = 0; for(auto i : Range(user_events.size())) { auto & event = user_events[i]; while(i_start < user_events.size() && user_events[i_start].t_start < event.t_end) { auto & ev = user_events[i_start]; paje.PushState( ev.t_start, state_type_timer, containers[ev.container], ev.data, ev.id ); i_start++; } paje.PopState( event.t_end, state_type_timer, containers[event.container]); } } for(auto & vtasks : tasks) { for (Task & t : vtasks) { int value_id = t.id; switch(t.id_type) { case Task::ID_JOB: value_id = job_task_map[jobs[t.id-1].type]; if(trace_thread_counter) { if(t.is_start) paje.AddVariable( t.time, variable_type_active_threads, container_jobs, 1.0 ); else paje.SubVariable( t.time, variable_type_active_threads, container_jobs, 1.0 ); } if(trace_threads) { if(t.is_start) paje.PushState( t.time, state_type_task, thread_aliases[t.thread_id], value_id, t.additional_value, true ); else paje.PopState( t.time, state_type_task, thread_aliases[t.thread_id] ); } break; case Task::ID_TIMER: value_id = timer_aliases[t.id]; if(t.is_start) paje.PushState( t.time, state_type_timer, thread_aliases[t.thread_id], value_id, t.additional_value, true ); else paje.PopState( t.time, state_type_timer, thread_aliases[t.thread_id] ); break; default: if(t.is_start) paje.PushState( t.time, state_type_task, thread_aliases[t.thread_id], value_id, t.additional_value, false ); else paje.PopState( t.time, state_type_task, thread_aliases[t.thread_id] ); break; } } } #ifdef PARALLEL if(comm.Size()>1) { for(auto & event : timer_events) { if(event.is_start) paje.PushState( event.time, state_type_timer, thread_aliases[MPI_PAJE_WRITER], timer_aliases[event.timer_id] ); else paje.PopState( event.time, state_type_timer, thread_aliases[MPI_PAJE_WRITER] ); } // Timer events Array timer_id; Array time; Array is_start; Array thread_id; for(auto src : IntRange(0, comm.Size())) { if(src==MPI_PAJE_WRITER) continue; comm.Recv (timer_id, src, 0); comm.Recv (time, src, 0); comm.Recv (is_start, src, 0); comm.Recv (thread_id, src, 0); for(auto i : Range(timer_id.Size())) { TimerEvent event; event.timer_id = timer_id[i]; event.time = time[i]; event.is_start = is_start[i]; event.thread_id = thread_id[i]; if(event.is_start) paje.PushState( event.time, state_type_timer, thread_aliases[src], timer_aliases[event.timer_id] ); else paje.PopState( event.time, state_type_timer, thread_aliases[src] ); } } } #endif // PARALLEL // Merge link event int nlinks = 0; for( auto & l : links) nlinks += l.size(); std::vector links_merged; links_merged.reserve(nlinks); std::vector pos(nthreads); int nlinks_merged = 0; while(nlinks_merged < nlinks) { int minpos = -1; TTimePoint mintime = -1; for (int t = 0; t started_links; int link_type = paje.DefineLinkType(container_type_node, container_type_thread, container_type_thread, "links"); // match links for ( auto & l : links_merged ) { if(l.is_start) { started_links.push_back(l); } else { unsigned int i = 0; while(i ahostname; int len; NG_MPI_Get_processor_name(ahostname.data(), &len); hostname = ahostname.data(); } comm.Send(hostname, MPI_PAJE_WRITER, 0); // Timer names std::set timer_ids; std::map timer_names; for(auto & event : timer_events) timer_ids.insert(event.timer_id); for(auto id : timer_ids) timer_names[id] = GetTimerName(id); size_t size = timer_ids.size(); comm.Send(size, MPI_PAJE_WRITER, 0); for(auto id : timer_ids) { comm.Send(id, MPI_PAJE_WRITER, 0); comm.Send(timer_names[id], MPI_PAJE_WRITER, 0); } // Timer events Array timer_id; Array time; Array is_start; Array thread_id; for(auto & event : timer_events) { timer_id.Append(event.timer_id); time.Append(event.time); is_start.Append(event.is_start); thread_id.Append(event.thread_id); } comm.Send (timer_id, MPI_PAJE_WRITER, 0); comm.Send (time, MPI_PAJE_WRITER, 0); comm.Send (is_start, MPI_PAJE_WRITER, 0); comm.Send (thread_id, MPI_PAJE_WRITER, 0); #endif // PARALLEL } /////////////////////////////////////////////////////////////////// // Write HTML file drawing a sunburst chart with cumulated timings struct TreeNode { int id = 0; std::map children; double chart_size = 0.0; // time without children (the chart lib accumulates children sizes again) double size = 0.0; double min_size = 1e99; double max_size = 0.0; std::string name; size_t calls = 0; TTimePoint start_time = 0; }; void PrintNode (const TreeNode &n, std::ofstream & f) { f << "{ name: \"" + n.name + "\""; f << ", calls: " << n.calls; f << ", size: " << n.chart_size; f << ", value: " << n.size; f << ", min: " << n.min_size; f << ", max: " << n.max_size; if(n.calls) f << ", avg: " << n.size/n.calls; int size = n.children.size(); if(size>0) { int i = 0; f << ", children: ["; for(auto & c : n.children) { PrintNode(c.second, f); if(++i )CODE_"; if(!time_or_memory) f << "Maximum Memory Consumption\n"; f << R"CODE_(
)CODE_" << std::endl; } #ifdef NETGEN_TRACE_MEMORY void PajeTrace::WriteMemoryChart( std::string fname ) { if(fname=="") fname = tracefile_name + "_memory"; size_t mem_allocated = 0; size_t max_mem_allocated = 0; size_t imax_mem_allocated = 0; const auto & names = MemoryTracer::GetNames(); const auto & parents = MemoryTracer::GetParents(); size_t N = names.size(); Array mem_allocated_id; mem_allocated_id.SetSize(N); mem_allocated_id = 0; // Find point with maximum memory allocation, check for missing allocs/frees for(auto i : IntRange(memory_events.size())) { const auto & ev = memory_events[i]; if(ev.is_alloc) { mem_allocated += ev.size; mem_allocated_id[ev.id] += ev.size; if(mem_allocated > max_mem_allocated && i>=n_memory_events_at_start) { imax_mem_allocated = i; max_mem_allocated = mem_allocated; } } else { if(ev.size > mem_allocated) { std::cerr << "Error in memory tracer: have total allocated memory < 0" << std::endl; mem_allocated = 0; } else mem_allocated -= ev.size; if(ev.size > mem_allocated_id[ev.id]) { std::cerr << "Error in memory tracer: have allocated memory < 0 in tracer " << names[ev.id] << std::endl; mem_allocated_id[ev.id] = 0; } else mem_allocated_id[ev.id] -= ev.size; } } // reconstruct again the memory consumption after event imax_mem_allocated mem_allocated_id = 0; for(auto i : IntRange(imax_mem_allocated+1)) { const auto & ev = memory_events[i]; if(ev.is_alloc) mem_allocated_id[ev.id] += ev.size; else { if(ev.size > mem_allocated_id[ev.id]) mem_allocated_id[ev.id] = 0; else mem_allocated_id[ev.id] -= ev.size; } } TreeNode root; root.name="all"; Array nodes; nodes.SetSize(N); nodes = nullptr; nodes[0] = &root; Array> children(N); Array sorting; // topological sorting (parents before children) sorting.SetAllocSize(N); for(auto i : IntRange(1, N)) children[parents[i]].Append(i); ArrayMem stack; sorting.Append(0); stack.Append(0); while(stack.Size()) { auto current = stack.Last(); stack.DeleteLast(); for(const auto child : children[current]) { sorting.Append(child); if(children[child].Size()) stack.Append(child); } } for(auto i : sorting) { if(i==0) continue; TreeNode * parent = nodes[parents[i]]; auto & node = parent->children[i]; nodes[i] = &node; node.id = i; node.chart_size = mem_allocated_id[i]; node.size = mem_allocated_id[i]; node.name = names[i]; } for(auto i_ : Range(sorting)) { // reverse topological order to accumulate total memory usage of all children auto i = sorting[sorting.Size()-1-i_]; if(i==0) continue; nodes[parents[i]]->size += nodes[i]->size; } WriteSunburstHTML( root, fname, false ); } #endif // NETGEN_TRACE_MEMORY void PajeTrace::WriteTimingChart( ) { std::vector events; TreeNode root; root.name="all"; TreeNode *current = &root; std::vector node_stack; node_stack.push_back(&root); TTimePoint stop_time = 0; for(auto & event : timer_events) { events.push_back(event); stop_time = std::max(event.time, stop_time); } std::map jobs_map; std::vector job_names; for(auto & job : jobs) { auto name = Demangle(job.type->name()); int id = job_names.size(); if(jobs_map.count(name)==0) { jobs_map[name] = id; job_names.push_back(name); } else id = jobs_map[name]; events.push_back(TimerEvent{job.start_time, -1, id, -1, true}); events.push_back(TimerEvent{job.stop_time, -1, id, -1, false}); stop_time = std::max(job.stop_time, stop_time); } std::stable_sort (events.begin(), events.end()); root.size = 1000.0*static_cast(stop_time) * seconds_per_tick; root.calls = 1; root.min_size = root.size; root.max_size = root.size; for(auto & event : events) { bool is_timer_event = event.timer_id != -1; int id = is_timer_event ? event.timer_id : event.thread_id; if(event.is_start) { bool need_init = !current->children.count(id); node_stack.push_back(current); current = ¤t->children[id]; if(need_init) { current->name = is_timer_event ? GetTimerName(id) : job_names[id]; current->size = 0.0; current->id = id; } current->start_time = event.time; } else { if(node_stack.size()==0) { std::cout << "node stack empty!" << std::endl; break; } double size = 1000.0*static_cast(event.time-current->start_time) * seconds_per_tick; current->size += size; current->chart_size += size; current->min_size = std::min(current->min_size, size); current->max_size = std::max(current->max_size, size); current->calls++; current = node_stack.back(); current->chart_size -= size; node_stack.pop_back(); } } root.chart_size = 0.0; ngcore::WriteSunburstHTML( root, tracefile_name, true ); } } // namespace ngcore const char *header = "%EventDef PajeDefineContainerType 0 \n" "% Alias string \n" "% Type string \n" "% Name string \n" "%EndEventDef \n" "%EventDef PajeDefineVariableType 1 \n" "% Alias string \n" "% Type string \n" "% Name string \n" "% Color color \n" "%EndEventDef \n" "%EventDef PajeDefineStateType 2 \n" "% Alias string \n" "% Type string \n" "% Name string \n" "%EndEventDef \n" "%EventDef PajeDefineEventType 3 \n" "% Alias string \n" "% Type string \n" "% Name string \n" "% Color color \n" "%EndEventDef \n" "%EventDef PajeDefineLinkType 4 \n" "% Alias string \n" "% Type string \n" "% StartContainerType string \n" "% EndContainerType string \n" "% Name string \n" "%EndEventDef \n" "%EventDef PajeDefineEntityValue 5 \n" "% Alias string \n" "% Type string \n" "% Name string \n" "% Color color \n" "%EndEventDef \n" "%EventDef PajeCreateContainer 6 \n" "% Time date \n" "% Alias string \n" "% Type string \n" "% Container string \n" "% Name string \n" "%EndEventDef \n" "%EventDef PajeDestroyContainer 7 \n" "% Time date \n" "% Type string \n" "% Name string \n" "%EndEventDef \n" "%EventDef PajeSetVariable 8 \n" "% Time date \n" "% Type string \n" "% Container string \n" "% Value double \n" "%EndEventDef\n" "%EventDef PajeAddVariable 9 \n" "% Time date \n" "% Type string \n" "% Container string \n" "% Value double \n" "%EndEventDef\n" "%EventDef PajeSubVariable 10 \n" "% Time date \n" "% Type string \n" "% Container string \n" "% Value double \n" "%EndEventDef\n" "%EventDef PajeSetState 11 \n" "% Time date \n" "% Type string \n" "% Container string \n" "% Value string \n" "%EndEventDef\n" "%EventDef PajePushState 12 \n" "% Time date \n" "% Type string \n" "% Container string \n" "% Value string \n" "% Id string \n" "%EndEventDef\n" "%EventDef PajePopState 13 \n" "% Time date \n" "% Type string \n" "% Container string \n" "%EndEventDef\n" "%EventDef PajeResetState 14 \n" "% Time date \n" "% Type string \n" "% Container string \n" "%EndEventDef\n" "%EventDef PajeStartLink 15 \n" "% Time date \n" "% Type string \n" "% Container string \n" "% Value string \n" "% StartContainer string \n" "% Key string \n" "%EndEventDef\n" "%EventDef PajeEndLink 16 \n" "% Time date \n" "% Type string \n" "% Container string \n" "% Value string \n" "% EndContainer string \n" "% Key string \n" "%EndEventDef\n" "%EventDef PajeNewEvent 17 \n" "% Time date \n" "% Type string \n" "% Container string \n" "% Value string \n" "%EndEventDef\n"; ================================================ FILE: libsrc/core/paje_trace.hpp ================================================ #ifndef NETGEN_CORE_PAJE_TRACE_HPP #define NETGEN_CORE_PAJE_TRACE_HPP #include #include #include #include "logging.hpp" // for logger #include "ngcore_api.hpp" // for NGCORE_API #include "utils.hpp" namespace ngcore { extern NGCORE_API class PajeTrace *trace; class PajeTrace { public: using TClock = std::chrono::system_clock; protected: std::shared_ptr logger = GetLogger("PajeTrace"); private: NGCORE_API static size_t max_tracefile_size; NGCORE_API static bool trace_thread_counter; NGCORE_API static bool trace_threads; NGCORE_API static bool mem_tracing_enabled; NGCORE_API static bool write_paje_file; bool tracing_enabled; TTimePoint start_time; int nthreads; size_t n_memory_events_at_start; public: NGCORE_API void Write(); NGCORE_API void WritePajeFile( const std::string & filename ); NGCORE_API void WriteTimingChart(); #ifdef NETGEN_TRACE_MEMORY NGCORE_API void WriteMemoryChart( std::string fname ); #endif // NETGEN_TRACE_MEMORY // Approximate number of events to trace. Tracing will // be stopped if any thread reaches this number of events unsigned int max_num_events_per_thread; static void SetTraceMemory( bool trace_memory ) { mem_tracing_enabled = trace_memory; } static void SetTraceThreads( bool atrace_threads ) { trace_threads = atrace_threads; } static void SetTraceThreadCounter( bool trace_threads ) { trace_thread_counter = trace_threads; } static void SetMaxTracefileSize( size_t max_size ) { max_tracefile_size = max_size; } static void SetWritePajeFile( bool write ) { write_paje_file = write; } std::string tracefile_name; struct Job { int job_id; const std::type_info *type; TTimePoint start_time; TTimePoint stop_time; }; struct Task { int thread_id; int id; int id_type; int additional_value; TTimePoint time; bool is_start; static constexpr int ID_NONE = -1; static constexpr int ID_JOB = 1; static constexpr int ID_TIMER = 2; }; struct TimerEvent { TTimePoint time; int timer_id; int thread_id; int custom_value = -1; bool is_start; bool operator < (const TimerEvent & other) const { return time < other.time; } }; struct UserEvent { TTimePoint t_start = 0, t_end = 0; std::string data = ""; int container = 0; int id = 0; bool operator < (const UserEvent & other) const { return t_start < other.t_start; } }; struct ThreadLink { int thread_id; int key; TTimePoint time; bool is_start; bool operator < (const ThreadLink & other) const { return time < other.time; } }; struct MemoryEvent { TTimePoint time; size_t size; int id; bool is_alloc; bool operator < (const MemoryEvent & other) const { return time < other.time; } }; std::vector > tasks; std::vector jobs; std::vector timer_events; std::vector user_events; std::vector> user_containers; std::vector gpu_events; std::vector > links; NGCORE_API static std::vector memory_events; public: NGCORE_API void StopTracing(); PajeTrace() = delete; PajeTrace(const PajeTrace &) = delete; PajeTrace(PajeTrace &&) = delete; NGCORE_API PajeTrace(int anthreads, std::string aname = ""); NGCORE_API ~PajeTrace(); void operator=(const PajeTrace &) = delete; void operator=(PajeTrace &&) = delete; int AddUserContainer(std::string name, int parent=-1) { if(auto pos = std::find(user_containers.begin(), user_containers.end(), std::tuple{name,parent}); pos != user_containers.end()) return pos - user_containers.begin(); int id = user_containers.size(); user_containers.push_back({name, parent}); return id; } void AddUserEvent(UserEvent ue) { if(!tracing_enabled) return; user_events.push_back(ue); } void StartGPU(int timer_id = 0, int user_value = -1) { if(!tracing_enabled) return; if(unlikely(gpu_events.size() == max_num_events_per_thread)) StopTracing(); gpu_events.push_back(TimerEvent{GetTimeCounter(), timer_id, 0, user_value, true}); } void StopGPU(int timer_id) { if(!tracing_enabled) return; if(unlikely(gpu_events.size() == max_num_events_per_thread)) StopTracing(); gpu_events.push_back(TimerEvent{GetTimeCounter(), timer_id, 0, -1, false}); } void StartTimer(int timer_id, int user_value = -1) { if(!tracing_enabled) return; if(unlikely(timer_events.size() == max_num_events_per_thread)) StopTracing(); timer_events.push_back(TimerEvent{GetTimeCounter(), timer_id, 0, user_value, true}); } void StopTimer(int timer_id) { if(!tracing_enabled) return; if(unlikely(timer_events.size() == max_num_events_per_thread)) StopTracing(); timer_events.push_back(TimerEvent{GetTimeCounter(), timer_id, 0, -1, false}); } void AllocMemory(int id, size_t size) { if(!mem_tracing_enabled) return; memory_events.push_back(MemoryEvent{GetTimeCounter(), size, id, true}); } void FreeMemory(int id, size_t size) { if(!mem_tracing_enabled) return; memory_events.push_back(MemoryEvent{GetTimeCounter(), size, id, false}); } void ChangeMemory(int id, long long size) { if(size>0) AllocMemory(id, size); if(size<0) FreeMemory(id, -size); } int StartTask(int thread_id, int id, int id_type = Task::ID_NONE, int additional_value = -1) { if(!tracing_enabled) return -1; if(!trace_threads && !trace_thread_counter) return -1; if(unlikely(tasks[thread_id].size() == max_num_events_per_thread)) StopTracing(); int task_num = tasks[thread_id].size(); tasks[thread_id].push_back( Task{thread_id, id, id_type, additional_value, GetTimeCounter(), true} ); return task_num; } void StopTask(int thread_id, int id, int id_type = Task::ID_NONE) { if(!trace_threads && !trace_thread_counter) return; tasks[thread_id].push_back( Task{thread_id, id, id_type, 0, GetTimeCounter(), false} ); } void StartJob(int job_id, const std::type_info & type) { if(!tracing_enabled) return; if(jobs.size() == max_num_events_per_thread) StopTracing(); jobs.push_back( Job{job_id, &type, GetTimeCounter()} ); } void StopJob() { if(tracing_enabled) jobs.back().stop_time = GetTimeCounter(); } void StartLink(int thread_id, int key) { if(!tracing_enabled) return; if(links[thread_id].size() == max_num_events_per_thread) StopTracing(); links[thread_id].push_back( ThreadLink{thread_id, key, GetTimeCounter(), true} ); } void StopLink(int thread_id, int key) { if(!tracing_enabled) return; if(links[thread_id].size() == max_num_events_per_thread) StopTracing(); links[thread_id].push_back( ThreadLink{thread_id, key, GetTimeCounter(), false} ); } void SendData(); // MPI parallel data reduction }; } // namespace ngcore #endif // NETGEN_CORE_PAJE_TRACE_HPP ================================================ FILE: libsrc/core/profiler.cpp ================================================ #include #include "profiler.hpp" namespace ngcore { std::vector NgProfiler::timers(NgProfiler::SIZE); // NOLINT std::string NgProfiler::filename; std::array NgProfiler::dummy_thread_times; size_t * NgProfiler::thread_times = NgProfiler::dummy_thread_times.data(); // NOLINT std::array NgProfiler::dummy_thread_flops; size_t * NgProfiler::thread_flops = NgProfiler::dummy_thread_flops.data(); // NOLINT std::shared_ptr NgProfiler::logger = GetLogger("Profiler"); // NOLINT NgProfiler :: NgProfiler() { for (auto & t : timers) { t.tottime = 0.0; t.usedcounter = 0; t.flops = 0.0; } } NgProfiler :: ~NgProfiler() { if (filename.length()) { logger->debug( "write profile to file {}", filename ); FILE *prof = fopen(filename.c_str(),"w"); // NOLINT Print (prof); fclose(prof); // NOLINT } if (getenv ("NGPROFILE")) { std::string filename = "netgen.prof"; #ifdef PARALLEL filename += "."+ToString(id); #endif if (id == 0) logger->info( "write profile to file {}", filename ); FILE *prof = fopen(filename.c_str(),"w"); // NOLINT Print (prof); fclose(prof); // NOLINT } } void NgProfiler :: Print (FILE * prof) { int i = 0; for (auto & t : timers) { if (t.count != 0 || t.usedcounter != 0) { fprintf(prof,"job %3i calls %8li, time %6.4f sec",i,t.count,t.tottime); // NOLINT if(t.flops != 0.0) fprintf(prof,", MFlops = %6.2f",t.flops / (t.tottime) * 1e-6); // NOLINT if(t.loads != 0.0) fprintf(prof,", MLoads = %6.2f",t.loads / (t.tottime) * 1e-6); // NOLINT if(t.stores != 0.0) fprintf(prof,", MStores = %6.2f",t.stores / (t.tottime) * 1e-6); // NOLINT if(t.usedcounter) fprintf(prof," %s",t.name.c_str()); // NOLINT fprintf(prof,"\n"); // NOLINT } i++; } } int NgProfiler :: CreateTimer (const std::string & name) { static std::mutex createtimer_mutex; int nr = -1; { std::lock_guard guard(createtimer_mutex); for (int i = SIZE-1; i > 0; i--) { auto & t = timers[i]; if (!t.usedcounter) { t.usedcounter = 1; t.name = name; nr = i; break; } } } if (nr > -1) return nr; static bool first_overflow = true; if (first_overflow) { first_overflow = false; NgProfiler::logger->warn( ("no more timer available ("+name+"), reusing last one").c_str()); } return 0; } void NgProfiler :: Reset () { for(auto & t : timers) { t.tottime = 0.0; t.count = 0; t.flops = 0.0; t.loads = 0; t.stores = 0; } } NgProfiler prof; // NOLINT #ifdef NETGEN_TRACE_MEMORY std::vector MemoryTracer::names{"all"}; std::vector MemoryTracer::parents{-1}; std::atomic MemoryTracer::total_memory{0}; #endif // NETGEN_TRACE_MEMORY } // namespace ngcore ================================================ FILE: libsrc/core/profiler.hpp ================================================ #ifndef NETGEN_CORE_PROFILER_HPP #define NETGEN_CORE_PROFILER_HPP #include #include #include #include #include "array.hpp" #include "logging.hpp" #include "paje_trace.hpp" #include "taskmanager.hpp" #include "utils.hpp" namespace ngcore { class NgProfiler { public: /// maximal number of timers enum { SIZE = 8*1024 }; struct TimerVal { TimerVal() = default; double tottime = 0.0; TTimePoint starttime=0; double flops = 0.0; double loads = 0.0; double stores = 0.0; long count = 0; std::string name = ""; int usedcounter = 0; }; NGCORE_API static std::vector timers; NGCORE_API static TTimePoint * thread_times; NGCORE_API static TTimePoint * thread_flops; NGCORE_API static std::shared_ptr logger; NGCORE_API static std::array dummy_thread_times; NGCORE_API static std::array dummy_thread_flops; private: NGCORE_API static std::string filename; public: NgProfiler(); ~NgProfiler(); NgProfiler(const NgProfiler &) = delete; NgProfiler(NgProfiler &&) = delete; void operator=(const NgProfiler &) = delete; void operator=(NgProfiler &&) = delete; static void SetFileName (const std::string & afilename) { filename = afilename; } /// create new timer, use integer index NGCORE_API static int CreateTimer (const std::string & name); NGCORE_API static void Reset (); /// start timer of index nr static void StartTimer (int nr) { timers[nr].starttime = GetTimeCounter(); timers[nr].count++; } /// stop timer of index nr static void StopTimer (int nr) { timers[nr].tottime += (GetTimeCounter()-timers[nr].starttime)*seconds_per_tick; } static void StartThreadTimer (size_t nr, size_t tid) { thread_times[tid*SIZE+nr] -= GetTimeCounter(); // NOLINT } static void StopThreadTimer (size_t nr, size_t tid) { thread_times[tid*SIZE+nr] += GetTimeCounter(); // NOLINT } static void AddThreadFlops (size_t nr, size_t tid, size_t flops) { thread_flops[tid*SIZE+nr] += flops; // NOLINT } /// if you know number of flops, provide them to obtain the MFlop - rate static void AddFlops (int nr, double aflops) { timers[nr].flops += aflops; } static void AddLoads (int nr, double aloads) { timers[nr].loads += aloads; } static void AddStores (int nr, double astores) { timers[nr].stores += astores; } static int GetNr (const std::string & name) { for (int i = SIZE-1; i >= 0; i--) if (timers[i].name == name) return i; return -1; } static double GetTime (int nr) { return timers[nr].tottime; } static double GetTime (const std::string & name) { for (int i = SIZE-1; i >= 0; i--) if (timers[i].name == name) return GetTime (i); return 0; } static long int GetCounts (int nr) { return timers[nr].count; } static double GetFlops (int nr) { return timers[nr].flops; } /// change name static void SetName (int nr, const std::string & name) { timers[nr].name = name; } static std::string GetName (int nr) { return timers[nr].name; } /// print profile NGCORE_API static void Print (FILE * prof); class RegionTimer { int nr; public: /// start timer RegionTimer (int anr) : nr(anr) { NgProfiler::StartTimer(nr); } /// stop timer ~RegionTimer () { NgProfiler::StopTimer(nr); } RegionTimer() = delete; RegionTimer(const RegionTimer &) = delete; RegionTimer(RegionTimer &&) = delete; void operator=(const RegionTimer &) = delete; void operator=(RegionTimer &&) = delete; }; }; struct TNoTracing{ static constexpr bool do_tracing=false; }; struct TTracing{ static constexpr bool do_tracing=true; }; struct TNoTiming{ static constexpr bool do_timing=false; }; struct TTiming{ static constexpr bool do_timing=true; }; namespace detail { template constexpr bool is_tracing_type_v = std::is_same_v || std::is_same_v; template constexpr bool is_timing_type_v = std::is_same_v || std::is_same_v; } [[maybe_unused]] static TNoTracing NoTracing; [[maybe_unused]] static TNoTiming NoTiming; template class Timer { int timernr; int Init( const std::string & name ) { return NgProfiler::CreateTimer (name); } public: static constexpr bool do_tracing = TTracing::do_tracing; static constexpr bool do_timing = TTiming::do_timing; Timer (const std::string & name) : timernr(Init(name)) { } template, bool> = false> Timer( const std::string & name, TTracing ) : timernr(Init(name)) { } template, bool> = false> Timer( const std::string & name, TTiming ) : timernr(Init(name)) { } Timer( const std::string & name, TTracing, TTiming ) : timernr(Init(name)) { } [[deprecated ("Use Timer(name, NoTracing/NoTiming) instead")]] Timer( const std::string & name, int ) : timernr(Init(name)) {} void SetName (const std::string & name) { NgProfiler::SetName (timernr, name); } void Start () const { Start(TaskManager::GetThreadId()); } void Stop () const { Stop(TaskManager::GetThreadId()); } void Start (int tid, int trace_value = -1) const { if(tid==0) { if constexpr(do_timing) NgProfiler::StartTimer (timernr); if constexpr(do_tracing) if(trace) trace->StartTimer(timernr, trace_value); } else { if constexpr(do_timing) NgProfiler::StartThreadTimer(timernr, tid); if constexpr(do_tracing) if(trace) trace->StartTask (tid, timernr, PajeTrace::Task::ID_TIMER, trace_value); } } void Stop (int tid) const { if(tid==0) { if constexpr(do_timing) NgProfiler::StopTimer (timernr); if constexpr(do_tracing) if(trace) trace->StopTimer(timernr); } else { if constexpr(do_timing) NgProfiler::StopThreadTimer(timernr, tid); if constexpr(do_tracing) if(trace) trace->StopTask (tid, timernr, PajeTrace::Task::ID_TIMER); } } void AddFlops (double aflops) { if constexpr(do_timing) NgProfiler::AddFlops (timernr, aflops); } double GetTime () { return NgProfiler::GetTime(timernr); } long int GetCounts () { return NgProfiler::GetCounts(timernr); } double GetMFlops () { return NgProfiler::GetFlops(timernr) / NgProfiler::GetTime(timernr) * 1e-6; } operator int () const { return timernr; } }; /** Timer object. Start / stop timer at constructor / destructor. */ template class RegionTimer { const TTimer & timer; int tid; public: /// start timer RegionTimer (const TTimer & atimer, int trace_value = -1) : timer(atimer) { tid = TaskManager::GetThreadId(); timer.Start(tid, trace_value); } /// stop timer ~RegionTimer () { timer.Stop(tid); } RegionTimer() = delete; RegionTimer(const RegionTimer &) = delete; RegionTimer(RegionTimer &&) = delete; void operator=(const RegionTimer &) = delete; void operator=(RegionTimer &&) = delete; }; class [[deprecated("Use RegionTimer instead (now thread safe)")]] ThreadRegionTimer { size_t nr; size_t tid; public: /// start timer ThreadRegionTimer (size_t _nr, size_t _tid) : nr(_nr), tid(_tid) { NgProfiler::StartThreadTimer(nr, tid); } /// stop timer ~ThreadRegionTimer () { NgProfiler::StopThreadTimer(nr, tid); } ThreadRegionTimer() = delete; ThreadRegionTimer(ThreadRegionTimer &&) = delete; ThreadRegionTimer(const ThreadRegionTimer &) = delete; void operator=(const ThreadRegionTimer &) = delete; void operator=(ThreadRegionTimer &&) = delete; }; class RegionTracer { int nr; int thread_id; int type; public: static constexpr int ID_JOB = PajeTrace::Task::ID_JOB; static constexpr int ID_NONE = PajeTrace::Task::ID_NONE; static constexpr int ID_TIMER = PajeTrace::Task::ID_TIMER; RegionTracer() = delete; RegionTracer(RegionTracer &&) = delete; RegionTracer(const RegionTracer &) = delete; void operator=(const RegionTracer &) = delete; void operator=(RegionTracer &&) = delete; /// start trace RegionTracer (int athread_id, int region_id, int id_type = ID_NONE, int additional_value = -1 ) : thread_id(athread_id) { if (trace) trace->StartTask (athread_id, region_id, id_type, additional_value); type = id_type; nr = region_id; } /// start trace with timer template RegionTracer (int athread_id, TTimer & timer, int additional_value = -1 ) : thread_id(athread_id) { nr = timer; type = ID_TIMER; if (trace) trace->StartTask (athread_id, nr, type, additional_value); } /// stop trace ~RegionTracer () { if (trace) trace->StopTask (thread_id, nr, type); } }; // Helper function for timings // Run f() at least min_iterations times until max_time seconds elapsed // returns minimum runtime for a call of f() template double RunTiming( TFunc f, double max_time = 0.5, int min_iterations = 10 ) { // Make sure the whole test run does not exceed maxtime double tend = WallTime()+max_time; // warmup f(); double tres = std::numeric_limits::max(); int iteration = 0; while(WallTime()(value)) { Flags nested_flags; for(auto item : value.cast()) SetFlag(nested_flags, item.first.cast(), item.second.cast()); flags.SetFlag(s, nested_flags); return; } else if (py::isinstance(value)) flags.SetFlag(s, value.cast()); else if (py::isinstance(value)) flags.SetFlag(s, value.cast()); else if (py::isinstance(value)) flags.SetFlag(s, double(value.cast())); else if (py::isinstance(value)) flags.SetFlag(s, value.cast()); else if (py::isinstance(value)) { auto vdl = py::cast(value); if (py::len(vdl) > 0) { if(py::isinstance(vdl[0]) || py::isinstance(vdl[0])) flags.SetFlag(s, makeCArray(vdl)); if(py::isinstance(vdl[0])) flags.SetFlag(s, makeCArray(vdl)); } else { Array dummystr; Array dummydbl; flags.SetFlag(s,dummystr); flags.SetFlag(s,dummydbl); } } else if (py::isinstance(value)) { auto vdt = py::cast(value); if (py::isinstance(value)) flags.SetFlag(s, makeCArray(vdt)); if (py::isinstance(value)) flags.SetFlag(s, makeCArray(vdt)); if (py::isinstance(value)) flags.SetFlag(s, makeCArray(vdt)); } else { flags.SetFlag(s, CastPyToAny(value)); } } Flags CreateFlagsFromKwArgs(const py::kwargs& kwargs, py::object pyclass, py::list info) { static std::shared_ptr logger = GetLogger("Flags"); py::dict flags_dict; if (kwargs.contains("flags")) { logger->warn("WARNING: using flags as kwarg is deprecated{}, use the flag arguments as kwargs instead!", pyclass.is_none() ? "" : std::string(" in ") + std::string(py::str(pyclass))); auto addflags = py::cast(kwargs["flags"]); for (auto item : addflags) flags_dict[item.first.cast().c_str()] = item.second; } py::dict special; if(!pyclass.is_none()) { auto flags_doc = pyclass.attr("__flags_doc__")(); for (auto item : kwargs) if (!flags_doc.contains(item.first.cast().c_str()) && !(item.first.cast() == "flags")) logger->warn("WARNING: kwarg '{}' is an undocumented flags option for class {}, maybe there is a typo?", item.first.cast(), std::string(py::str(pyclass))); if(py::hasattr(pyclass,"__special_treated_flags__")) special = pyclass.attr("__special_treated_flags__")(); } for (auto item : kwargs) { auto name = item.first.cast(); if (name != "flags") { if(!special.contains(name.c_str())) flags_dict[name.c_str()] = item.second; } } Flags flags; for(auto item : flags_dict) SetFlag(flags, item.first.cast(), item.second.cast()); for (auto item : kwargs) { auto name = item.first.cast(); if (name != "flags") { if(special.contains(name.c_str())) special[name.c_str()](item.second, &flags, info); } } return flags; } py::dict CreateDictFromFlags(const Flags& flags) { py::dict d; std::string key; for(auto i : Range(flags.GetNFlagsFlags())) { auto& f = flags.GetFlagsFlag(i, key); d[key.c_str()] = CreateDictFromFlags(f); } for(auto i : Range(flags.GetNStringListFlags())) { auto strlistflag = flags.GetStringListFlag(i, key); py::list lst; for(auto& val : *strlistflag) lst.append(val); d[key.c_str()] = lst; } for(auto i : Range(flags.GetNNumListFlags())) { auto numlistflag = flags.GetNumListFlag(i, key); py::list lst; for(auto& val : *numlistflag) lst.append(val); d[key.c_str()] = lst; } for(auto i : Range(flags.GetNStringFlags())) { auto val = flags.GetStringFlag(i, key); d[key.c_str()] = val; } for(auto i : Range(flags.GetNNumFlags())) { auto val = flags.GetNumFlag(i, key); d[key.c_str()] = val; } for(auto i : Range(flags.GetNDefineFlags())) { auto val = flags.GetDefineFlag(i, key); d[key.c_str()] = val; } for(auto i : Range(flags.GetNAnyFlags())) { auto& a = flags.GetAnyFlag(i, key); d[key.c_str()] = CastAnyToPy(a); } return d; } } // namespace ngcore ================================================ FILE: libsrc/core/python_ngcore.hpp ================================================ #ifndef NETGEN_CORE_PYTHON_NGCORE_HPP #define NETGEN_CORE_PYTHON_NGCORE_HPP #include "ngcore_api.hpp" // for operator new #include #include #include #include #include #include "array.hpp" #include "table.hpp" #include "archive.hpp" #include "flags.hpp" #include "ngcore_api.hpp" #include "ng_mpi.hpp" namespace py = pybind11; namespace ngcore { #ifdef PARALLEL NGCORE_API extern bool (*NG_MPI_CommFromMPI4Py)(py::handle, NG_MPI_Comm &); NGCORE_API extern py::handle (*NG_MPI_CommToMPI4Py)(NG_MPI_Comm); #endif // PARALLEL namespace detail { template struct HasPyFormat { private: template static auto check(T2*) -> std::enable_if_t>().format()), std::string>, std::true_type>; static auto check(...) -> std::false_type; public: static constexpr bool value = decltype(check((T*) nullptr))::value; }; } // namespace detail #ifdef PARALLEL struct mpi4py_comm { mpi4py_comm() = default; mpi4py_comm(NG_MPI_Comm value) : value(value) {} operator NG_MPI_Comm () { return value; } NG_MPI_Comm value; }; #endif // PARALLEL } // namespace ngcore //////////////////////////////////////////////////////////////////////////////// // automatic conversion of python list to Array<> namespace pybind11 { namespace detail { #ifdef PARALLEL template <> struct type_caster { public: PYBIND11_TYPE_CASTER(ngcore::mpi4py_comm, _("mpi4py_comm")); // Python -> C++ bool load(handle src, bool) { return ngcore::NG_MPI_CommFromMPI4Py(src, value.value); } // C++ -> Python static handle cast(ngcore::mpi4py_comm src, return_value_policy /* policy */, handle /* parent */) { // Create an mpi4py handle return ngcore::NG_MPI_CommToMPI4Py(src.value); } }; #endif // PARALLEL template struct ngcore_list_caster { using value_conv = make_caster; bool load(handle src, bool convert) { if (!isinstance(src) || isinstance(src)) return false; auto s = reinterpret_borrow(src); value.SetSize(s.size()); value.SetSize0(); for (auto it : s) { value_conv conv; if (!conv.load(it, convert)) return false; value.Append(cast_op(std::move(conv))); } return true; } public: template static handle cast(T &&src, return_value_policy policy, handle parent) { if (!std::is_lvalue_reference::value) policy = return_value_policy_override::policy(policy); list l(src.Size()); size_t index = 0; for (auto &&value : src) { auto value_ = reinterpret_steal(value_conv::cast(forward_like(value), policy, parent)); if (!value_) return handle(); PyList_SET_ITEM(l.ptr(), (ssize_t) index++, value_.release().ptr()); // steals a reference } return l.release(); } PYBIND11_TYPE_CASTER(Type, _("Array[") + value_conv::name + _("]")); }; template struct type_caster, enable_if_t::value>> : ngcore_list_caster, Type> { }; /* template struct type_caster>> { template static handle cast(T &&src, return_value_policy policy, handle parent) { std::cout << "handle called with type src = " << typeid(src).name() << std::endl; return handle(); // what so ever } PYBIND11_TYPE_CASTER(Type, _("Table[") + make_caster::name + _("]")); }; */ } // namespace detail } // namespace pybind11 //////////////////////////////////////////////////////////////////////////////// namespace ngcore { NGCORE_API extern bool ngcore_have_numpy; NGCORE_API extern bool parallel_pickling; // Python class name type traits template struct PyNameTraits { static const std::string & GetName() { static const std::string name = typeid(T).name(); return name; } }; template std::string GetPyName(const char *prefix = 0) { std::string s; if(prefix) s = std::string(prefix); s+= PyNameTraits::GetName(); return s; } template<> struct PyNameTraits { static std::string GetName() { return "I"; } }; template<> struct PyNameTraits { static std::string GetName() { return "U"; } }; template<> struct PyNameTraits { static std::string GetName() { return "F"; } }; template<> struct PyNameTraits { static std::string GetName() { return "D"; } }; template<> struct PyNameTraits { static std::string GetName() { return "S"; } }; template struct PyNameTraits> { static std::string GetName() { return std::string("sp_")+GetPyName(); } }; template class NGCORE_API_EXPORT PyArchive : public ARCHIVE { private: pybind11::list lst; size_t index = 0; std::map version_needed; protected: using ARCHIVE::stream; using ARCHIVE::version_map; public: PyArchive(const pybind11::object& alst = pybind11::none()) : ARCHIVE(std::make_shared()), lst(alst.is_none() ? pybind11::list() : pybind11::cast(alst)) { ARCHIVE::shallow_to_python = true; if(Input()) { stream = std::make_shared (pybind11::cast(lst[pybind11::len(lst)-1])); *this & version_needed; for(auto& libversion : version_needed) if(libversion.second > GetLibraryVersion(libversion.first)) throw Exception("Error in unpickling data:\nLibrary " + libversion.first + " must be at least " + libversion.second.to_string()); stream = std::make_shared (pybind11::cast(lst[pybind11::len(lst)-2])); *this & version_map; stream = std::make_shared (pybind11::cast(lst[pybind11::len(lst)-3])); } } void NeedsVersion(const std::string& library, const std::string& version) override { if(Output()) { version_needed[library] = version_needed[library] > version ? version_needed[library] : version; } } using ARCHIVE::Output; using ARCHIVE::Input; using ARCHIVE::FlushBuffer; using ARCHIVE::operator&; using ARCHIVE::operator<<; using ARCHIVE::GetVersion; void ShallowOutPython(const pybind11::object& val) override { lst.append(val); } void ShallowInPython(pybind11::object& val) override { val = lst[index++]; } pybind11::list WriteOut() { auto version_runtime = GetLibraryVersions(); FlushBuffer(); lst.append(pybind11::bytes(std::static_pointer_cast(stream)->str())); stream = std::make_shared(); *this & version_runtime; FlushBuffer(); lst.append(pybind11::bytes(std::static_pointer_cast(stream)->str())); stream = std::make_shared(); *this & version_needed; FlushBuffer(); lst.append(pybind11::bytes(std::static_pointer_cast(stream)->str())); return lst; } }; template auto NGSPickle() { return pybind11::pickle([](T* self) { PyArchive ar; ar.SetParallel(parallel_pickling); ar & self; auto output = pybind11::make_tuple(ar.WriteOut()); return output; }, [](const pybind11::tuple & state) { T* val = nullptr; PyArchive ar(state[0]); ar & val; return val; }); } template Array makeCArray(const py::object& obj) { Array arr; if(py::isinstance(obj)) for(auto& val : py::cast(obj)) arr.Append(py::cast(val)); else if(py::isinstance(obj)) for(auto& val : py::cast(obj)) arr.Append(py::cast(val)); else throw py::type_error("Cannot convert Python object to C Array"); return arr; } template // py::object makePyTuple (FlatArray ar) py::object makePyTuple (const BaseArrayObject & ar) { py::tuple res(ar.Size()); for (auto i : Range(ar)) res[i] = py::cast(ar[i]); return res; } template ::index_type> void ExportArray (py::module &m) { using TFlat = FlatArray; using TArray = Array; std::string suffix = GetPyName() + "_" + GetPyName(); std::string fname = std::string("FlatArray_") + suffix; auto flatarray_class = py::class_(m, fname.c_str(), py::buffer_protocol()) .def ("__len__", [] ( TFlat &self ) { return self.Size(); } ) .def ("__getitem__", [](TFlat & self, TIND i) -> T& { // static constexpr int base = IndexBASE(); auto reli = i - IndexBASE(); if (reli < 0 || reli >= self.Size()) throw py::index_error(); return self[i]; }, py::return_value_policy::reference) .def ("__setitem__", [](TFlat & self, TIND i, T val) -> T& { // static constexpr int base = IndexBASE(); auto reli = i - IndexBASE(); if (reli < 0 || reli >= self.Size()) throw py::index_error(); self[i] = val; return self[i]; }, py::return_value_policy::reference) .def ("__setitem__", [](TFlat & self, py::slice slice, T val) { size_t start, stop, step, slicelength; if (!slice.compute(self.Size(), &start, &stop, &step, &slicelength)) throw py::error_already_set(); static constexpr int base = IndexBASE(); if (start < base || start+(slicelength-1)*step >= self.Size()+base) throw py::index_error(); for (size_t i = 0; i < slicelength; i++, start+=step) self[start] = val; }) .def("__iter__", [] ( TFlat & self) { return py::make_iterator (self.begin(),self.end()); }, py::keep_alive<0,1>()) // keep array alive while iterator is used .def("__str__", [](TFlat& self) { return ToString(self); }) ; if constexpr (detail::HasPyFormat::value) { if(ngcore_have_numpy && !py::detail::npy_format_descriptor::dtype().is_none()) { flatarray_class .def_buffer([](TFlat& self) { return py::buffer_info( self.Addr(0), sizeof(T), py::format_descriptor::format(), 1, { self.Size() }, { sizeof(T) * (self.Addr(1) - self.Addr(0)) }); }) .def("NumPy", [](py::object self) { return py::module::import("numpy") .attr("frombuffer")(self, py::detail::npy_format_descriptor::dtype()); }) ; } } std::string aname = std::string("Array_") + suffix; auto arr = py::class_ (m, aname.c_str()) .def(py::init([] (size_t n) { return new TArray(n); }),py::arg("n"), "Makes array of given length") .def(py::init([] (std::vector const & x) { size_t s = x.size(); TArray tmp(s); for (size_t i : Range(tmp)) tmp[TIND(i)] = x[i]; return tmp; }), py::arg("vec"), "Makes array with given list of elements") ; if constexpr(is_archivable) arr.def(NGSPickle()); py::implicitly_convertible, TArray>(); } template void ExportTable (py::module &m) { py::class_, std::shared_ptr>> (m, ("Table_"+GetPyName()).c_str()) .def(py::init([] (py::list blocks) { size_t size = py::len(blocks); Array cnt(size); size_t i = 0; for (auto block : blocks) cnt[i++] = py::len(block); i = 0; Table blocktable(cnt); for (auto block : blocks) { auto row = blocktable[i++]; size_t j = 0; for (auto val : block) row[j++] = val.cast(); } // cout << "blocktable = " << *blocktable << endl; return blocktable; }), py::arg("blocks"), "a list of lists") .def ("__len__", [] (Table &self ) { return self.Size(); } ) .def ("__getitem__", [](Table & self, size_t i) -> FlatArray { if (i >= self.Size()) throw py::index_error(); return self[i]; }) .def("__str__", [](Table & self) { return ToString(self); }) ; } void NGCORE_API SetFlag(Flags &flags, std::string s, py::object value); // Parse python kwargs to flags Flags NGCORE_API CreateFlagsFromKwArgs(const py::kwargs& kwargs, py::object pyclass = py::none(), py::list info = py::list()); // Create python dict from kwargs py::dict NGCORE_API CreateDictFromFlags(const Flags& flags); } // namespace ngcore #endif // NETGEN_CORE_PYTHON_NGCORE_HPP ================================================ FILE: libsrc/core/python_ngcore_export.cpp ================================================ #include "archive.hpp" #include "python_ngcore.hpp" #include "bitarray.hpp" #include "taskmanager.hpp" #include "mpi_wrapper.hpp" using namespace ngcore; using namespace std; using namespace pybind11::literals; namespace pybind11 { namespace detail { }} // namespace pybind11::detail PYBIND11_MODULE(pyngcore, m) // NOLINT { try { auto numpy = py::module::import("numpy"); ngcore_have_numpy = !numpy.is_none(); } catch(...) {} ExportArray(m); ExportArray(m); ExportArray(m); ExportArray(m); ExportArray(m); ExportArray(m); ExportArray(m); ExportArray(m); ExportArray(m); // Compiler dependent implementation of size_t if constexpr(!is_same_v) ExportArray(m); ExportTable(m); #ifdef PARALLEL py::class_ (m, "_NG_MPI_Comm") ; m.def("InitMPI", &InitMPI, py::arg("mpi_library_path")=nullopt); #endif // PARALLEL py::class_> (m, "BitArray") .def(py::init([] (size_t n) { return make_shared(n); }),py::arg("n")) .def(py::init([] (const BitArray& a) { return make_shared(a); } ), py::arg("ba")) .def(py::init([] (const vector & a) { auto ba = make_shared(a.size()); ba->Clear(); for (size_t i = 0; i < a.size(); i++) if (a[i]) ba->SetBit(i); return ba; } ), py::arg("vec")) .def(NGSPickle()) .def("__str__", &ToString) .def("__len__", &BitArray::Size) .def("__getitem__", [] (BitArray & self, int i) { if (i < 0) i+=self.Size(); if (i < 0 || i >= self.Size()) throw py::index_error(); return self.Test(i); }, py::arg("pos"), "Returns bit from given position") .def("__setitem__", [] (BitArray & self, int i, bool b) { if (i < 0) i+=self.Size(); if (i < 0 || i >= self.Size()) throw py::index_error(); if (b) self.SetBit(i); else self.Clear(i); }, py::arg("pos"), py::arg("value"), "Clear/Set bit at given position") .def("__setitem__", [] (BitArray & self, py::slice inds, bool b) { size_t start, step, stop, n; if (!inds.compute(self.Size(), &start, &stop, &step, &n)) throw py::error_already_set(); if (start == 0 && n == self.Size() && step == 1) { // base branch if (b) self.Set(); else self.Clear(); } else { if (b) for (size_t i=0; i(m, "Flags") .def(py::init<>()) .def("__str__", &ToString) .def(py::init([](py::dict kwargs) { Flags flags; for (auto d : kwargs) SetFlag(flags, d.first.cast(), d.second.cast()); return flags; }), "Create flags from dict") .def(py::init([](py::kwargs kwargs) { Flags flags; for (auto d : kwargs) SetFlag(flags, d.first.cast(), d.second.cast()); return flags; }), "Create flags from kwargs") // .def(NGSPickle()) // in future versions we can kick out backward compatibility .def(py::pickle([](Flags &f) { PyArchive ar; ar.SetParallel(parallel_pickling); ar & f; auto output = py::make_tuple(ar.WriteOut()); return output; }, [](py::tuple& state) { if(py::isinstance(state[0])) { Flags flags; PyArchive ar(state[0]); ar & flags; return flags; } else { // flags have been pickled with old Netgen version string s = state[0].cast(); std::stringstream str(s); Flags flags; flags.LoadFlags(str); return flags; } } )) .def("Set",[](Flags & self,const py::dict & aflags)->Flags& { SetFlag(self, "", aflags); return self; }, py::arg("aflag"), "Set the flags by given dict") .def("Set",[](Flags & self, const char * akey, const py::object & value)->Flags& { SetFlag(self, akey, value); return self; }, py::arg("akey"), py::arg("value"), "Set flag by given value.") .def("keys", [](Flags & self) -> py::list { return CreateDictFromFlags(self).attr("keys")(); }) .def("__getitem__", [](Flags & self, const string& name) -> py::object { if(self.NumListFlagDefined(name)) return py::cast(self.GetNumListFlag(name)); if(self.StringListFlagDefined(name)) return py::cast(self.GetStringListFlag(name)); if(self.NumFlagDefined(name)) return py::cast(*self.GetNumFlagPtr(name)); if(self.StringFlagDefined(name)) return py::cast(self.GetStringFlag(name)); if(self.FlagsFlagDefined(name)) return py::cast(self.GetFlagsFlag(name)); if(self.AnyFlagDefined(name)) return CastAnyToPy(self.GetAnyFlag(name)); return py::cast(self.GetDefineFlag(name)); }, py::arg("name"), "Return flag by given name") .def("ToDict", [](const Flags& flags) { return CreateDictFromFlags(flags); }) .def("items", [](const Flags& flags) { return CreateDictFromFlags(flags).attr("items")(); }) ; py::implicitly_convertible(); py::class_(m, "xbool") .def(py::init<>()) .def(py::init(), py::arg("b")) .def("__str__", &ToString) .def_property_readonly("is_true", &xbool::IsTrue) .def_property_readonly("is_false", &xbool::IsFalse) .def_property_readonly("is_maybe", &xbool::IsMaybe) ; py::enum_(m, "LOG_LEVEL", "Logging level") .value("Trace", level::trace) .value("Debug", level::debug) .value("Info", level::info) .value("Warn", level::warn) .value("Error", level::err) .value("Critical", level::critical) .value("Off", level::off); m.def("SetLoggingLevel", &SetLoggingLevel, py::arg("level"), py::arg("logger")="", "Set logging level, if name is given only to the specific logger, else set the global logging level"); m.def("AddFileSink", &AddFileSink, py::arg("filename"), py::arg("level"), py::arg("logger")="", "Add File sink, either only to logger specified or globally to all loggers"); m.def("AddConsoleSink", &AddConsoleSink, py::arg("level"), py::arg("logger")="", "Add console output for specific logger or all if none given"); m.def("ClearLoggingSinks", &ClearLoggingSinks, py::arg("logger")="", "Clear sinks of specific logger, or all if none given"); m.def("FlushOnLoggingLevel", &FlushOnLoggingLevel, py::arg("level"), py::arg("logger")="", "Flush every message with level at least `level` for specific logger or all loggers if none given."); m.def("RunWithTaskManager", [](py::object lam) { GetLogger("TaskManager")->info("running Python function with task-manager"); RunWithTaskManager ([&] () { lam(); }); }, py::arg("lam"), R"raw_string( Parameters: lam : object input function )raw_string") ; m.def("SetNumThreads", &TaskManager::SetNumThreads, py::arg("threads"), R"raw_string( Set number of threads Parameters: threads : int input number of threads )raw_string"); // local TaskManager class to be used as context manager in Python class ParallelContextManager { int num_threads; public: ParallelContextManager() : num_threads(0) { TaskManager::SetPajeTrace(0); PajeTrace::SetMaxTracefileSize(0); }; ParallelContextManager(size_t pajesize) : num_threads(0) { TaskManager::SetPajeTrace(pajesize > 0); PajeTrace::SetMaxTracefileSize(pajesize); } void Enter() {num_threads = EnterTaskManager(); } void Exit(py::object exc_type, py::object exc_value, py::object traceback) { ExitTaskManager(num_threads); } }; py::class_(m, "TaskManager") .def(py::init<>()) .def(py::init(), "pajetrace"_a, "Run paje-tracer, specify buffersize in bytes") .def("__enter__", &ParallelContextManager::Enter) .def("__exit__", &ParallelContextManager::Exit) .def("__timing__", &TaskManager::Timing) ; py::class_(m, "SuspendTaskManager") .def(py::init(),py::arg("sleep_usecs")=1000, "sleep_usecs : int\n number of microseconds the worker threads sleep") .def("__enter__", [](SuspendTaskManager &self) -> SuspendTaskManager& { return self; }) .def("__exit__", [](SuspendTaskManager &self, py::object exc_type, py::object exc_value, py::object traceback) { return false; }); py::class_(m, "PajeTrace") .def(py::init( [] (string filename, size_t size_mb, bool threads, bool thread_counter, bool memory) { PajeTrace::SetMaxTracefileSize(size_mb*1014*1024); PajeTrace::SetTraceThreads(threads); PajeTrace::SetTraceMemory(memory); PajeTrace::SetTraceThreadCounter(thread_counter); trace = new PajeTrace(TaskManager::GetMaxThreads(), filename); return trace; }), py::arg("filename")="ng.trace", py::arg("size")=1000, py::arg("threads")=true, py::arg("thread_counter")=false, py::arg("memory")=true, "size in Megabytes" ) .def("__enter__", [](PajeTrace & self) { }) .def("__exit__", [](PajeTrace & self, py::args) { trace = nullptr; }) .def_static("SetTraceThreads", &PajeTrace::SetTraceThreads) .def_static("SetTraceThreadCounter", &PajeTrace::SetTraceThreadCounter) .def_static("SetMaxTracefileSize", &PajeTrace::SetMaxTracefileSize) #ifdef NETGEN_TRACE_MEMORY .def_static("WriteMemoryChart", [](string filename){ if(trace) trace->WriteMemoryChart(filename); }, py::arg("filename")="memory" ) #endif // NETGEN_TRACE_MEMORY ; m.def("GetTotalMemory", MemoryTracer::GetTotalMemory); py::class_> (m, "Timer") .def(py::init()) .def("Start", static_cast::*)()const>(&Timer<>::Start), "start timer") .def("Stop", static_cast::*)()const>(&Timer<>::Stop), "stop timer") .def_property_readonly("time", &Timer<>::GetTime, "returns time") .def("__enter__", static_cast::*)()const>(&Timer<>::Start)) .def("__exit__", [](Timer<>& t, py::object, py::object, py::object) { t.Stop(); }) ; m.def("Timers", []() { py::list timers; for (int i = 0; i < NgProfiler::SIZE; i++) if (!NgProfiler::timers[i].name.empty()) { py::dict timer; timer["name"] = py::str(NgProfiler::timers[i].name); timer["time"] = py::float_(NgProfiler::GetTime(i)); timer["counts"] = py::int_(NgProfiler::GetCounts(i)); timer["flops"] = py::float_(NgProfiler::GetFlops(i)); timer["Gflop/s"] = py::float_(NgProfiler::GetFlops(i)/NgProfiler::GetTime(i)*1e-9); timers.append(timer); } return timers; }, "Returns list of timers" ); m.def("ResetTimers", &NgProfiler::Reset); py::class_ (m, "MPI_Comm") #ifdef PARALLEL .def(py::init([] (mpi4py_comm comm) { return NgMPI_Comm(comm); })) .def("WTime", [](NgMPI_Comm & c) { return NG_MPI_Wtime(); }) .def_property_readonly ("mpi4py", [](NgMPI_Comm & self) { return NG_MPI_CommToMPI4Py(self); }) #endif // PARALLEL .def_property_readonly ("rank", &NgMPI_Comm::Rank) .def_property_readonly ("size", &NgMPI_Comm::Size) .def("Barrier", &NgMPI_Comm::Barrier) .def("Sum", [](NgMPI_Comm & c, double x) { return c.AllReduce(x, NG_MPI_SUM); }) .def("Min", [](NgMPI_Comm & c, double x) { return c.AllReduce(x, NG_MPI_MIN); }) .def("Max", [](NgMPI_Comm & c, double x) { return c.AllReduce(x, NG_MPI_MAX); }) .def("Sum", [](NgMPI_Comm & c, int x) { return c.AllReduce(x, NG_MPI_SUM); }) .def("Min", [](NgMPI_Comm & c, int x) { return c.AllReduce(x, NG_MPI_MIN); }) .def("Max", [](NgMPI_Comm & c, int x) { return c.AllReduce(x, NG_MPI_MAX); }) .def("Sum", [](NgMPI_Comm & c, size_t x) { return c.AllReduce(x, NG_MPI_SUM); }) .def("Min", [](NgMPI_Comm & c, size_t x) { return c.AllReduce(x, NG_MPI_MIN); }) .def("Max", [](NgMPI_Comm & c, size_t x) { return c.AllReduce(x, NG_MPI_MAX); }) .def("SubComm", [](NgMPI_Comm & c, std::vector proc_list) { Array procs(proc_list.size()); for (int i = 0; i < procs.Size(); i++) { procs[i] = proc_list[i]; } if (!procs.Contains(c.Rank())) { throw Exception("rank "+ToString(c.Rank())+" not in subcomm"); } return c.SubCommunicator(procs); }, py::arg("procs")); ; m.def("_GetArchiveRegisteredClasses", []() { const auto & reg = GetTypeRegister(); py::dict class_dict; for (const auto & [name, info] : reg) { class_dict[py::str(name)] = py::make_tuple( (uintptr_t)info.creator, (uintptr_t)info.upcaster, (uintptr_t)info.downcaster, (uintptr_t)info.cargs_archiver, (uintptr_t)info.anyToPyCaster, (uintptr_t)info.pyToAnyCaster ); } return class_dict; }); #ifdef PARALLEL py::implicitly_convertible(); #endif // PARALLEL } ================================================ FILE: libsrc/core/ranges.hpp ================================================ #ifndef NETGEN_CORE_RANGES_HPP #define NETGEN_CORE_RANGES_HPP #include namespace ngcore { template class AdapterRange { Iterator _begin,_end; public: AdapterRange(Iterator abegin, Iterator aend) : _begin(abegin), _end(aend) { ; } Iterator begin() const { return _begin; } Iterator end() const { return _end; } }; template class FilterAdapter { FUNC f; public: FilterAdapter(FUNC af) : f(af) { ; } FUNC GetFunction() const { return f; } }; template class FilterIterator { Iterator iter; Iterator end; FUNC f; public: FilterIterator(FUNC af, Iterator aiter, Iterator aend) : iter(aiter), end(aend), f(af) { while(iter!=end && !f(*iter)) ++iter; } inline FilterIterator& operator ++() { ++iter; while(iter!=end && !f(*iter)) ++iter; return *this; } inline bool operator !=(FilterIterator other) { return iter != other.iter; } inline bool operator ==(FilterIterator other) { return iter == other.iter; } inline decltype(auto) operator *() const { return *iter; } }; template FilterAdapter filter(FUNC f) { return {f}; } template auto operator |(Range&& range, FilterAdapter adapter) -> AdapterRange> { return {{adapter.GetFunction(),std::begin(range),std::end(range)}, {adapter.GetFunction(), std::end(range), std::end(range)}}; } template class TransformIterator { FUNC f; Iterator iter; public: TransformIterator(FUNC af, Iterator aiter) : f(af), iter(aiter) { ; } TransformIterator& operator++() { ++iter; } bool operator !=(TransformIterator other) { return iter != other.iter; } decltype(auto) operator *() const { return f(*iter); } }; template class TransformAdapter { FUNC f; public: TransformAdapter(FUNC af) : f(af) { ; } FUNC GetFunction() const { return f; } }; template TransformAdapter transform(FUNC f) { return {f}; } template auto operator |(Range&& range, TransformAdapter adapter) -> AdapterRange> { return {{adapter.GetFunction(), std::begin(range)}, {adapter.GetFunction(),std::end(range)}}; } } // namespace ngcore #endif // NETGEN_CORE_RANGES_HPP ================================================ FILE: libsrc/core/register_archive.hpp ================================================ #ifndef NETGEN_REGISTER_ARCHIVE_HPP #define NETGEN_REGISTER_ARCHIVE_HPP #ifdef NETGEN_PYTHON #include #include #include #endif // NETGEN_PYTHON #include #include "archive.hpp" namespace ngcore { // *************** Archiving functionality ************** #ifdef NETGEN_PYTHON template Archive& Archive :: Shallow(T& val) { static_assert(detail::is_any_pointer, "ShallowArchive must be given pointer type!"); if(shallow_to_python) { if(is_output) ShallowOutPython(pybind11::cast(val)); else { pybind11::object obj; ShallowInPython(obj); val = pybind11::cast(obj); } } else *this & val; return *this; } /* // now using has_shared_from_this2 in archive.hpp template struct has_shared_from_this { template static std::true_type check( decltype( sizeof(&C::shared_from_this )) ) { return std::true_type(); } template static std::false_type check(...) { return std::false_type(); } typedef decltype( check(sizeof(char)) ) type; static constexpr type value = type(); }; */ #endif // NETGEN_PYTHON template> class RegisterClassForArchive { public: RegisterClassForArchive() { static_assert(std::is_base_of::value || detail::is_base_of_tuple, "Second argument must be base class or tuple of base classes of T"); detail::ClassArchiveInfo info {}; info.creator = [](const std::type_info& ti, Archive& ar) -> void* { detail::TCargs args; ar &args; auto nT = detail::constructIfPossible(std::move(args)); return typeid(T) == ti ? nT : Archive::Caster::tryUpcast(ti, nT); }; info.upcaster = [](const std::type_info& ti, void* p) -> void* { return typeid(T) == ti ? p : Archive::Caster::tryUpcast(ti, static_cast(p)); }; info.downcaster = [](const std::type_info& ti, void* p) -> void* { return typeid(T) == ti ? p : Archive::Caster::tryDowncast(ti, p); }; info.cargs_archiver = [](Archive &ar, void* p) { if constexpr(detail::has_GetCArgs_v) ar << static_cast(p)->GetCArgs(); }; #ifdef NETGEN_PYTHON info.anyToPyCaster = [](const std::any &a) { if constexpr(has_shared_from_this2::value) { std::shared_ptr val = std::any_cast>(a); return pybind11::cast(val); } else { const T* val = std::any_cast(&a); return pybind11::cast(val); } }; info.pyToAnyCaster = [](pybind11::object &obj) { if constexpr(has_shared_from_this2::value || !std::is_copy_constructible::value) return std::any { obj.cast>() }; else return std::any { obj.cast() }; }; #endif // NETGEN_PYTHON Archive::SetArchiveRegister(std::string(Demangle(typeid(T).name())),info); } }; } // namespace ngcore #endif // NETGEN_REGISTER_ARCHIVE_HPP ================================================ FILE: libsrc/core/signal.hpp ================================================ #ifndef NGCORE_SIGNALS_HPP #define NGCORE_SIGNALS_HPP #include #include #include namespace ngcore { template class Signal { private: std::list> funcs; bool is_emitting; public: Signal() : is_emitting(true) {} template void Connect(Cls* self, FUNC f) { auto ptr = self->weak_from_this(); auto func = [ptr, f](ParameterTypes... args) { if (ptr.expired()) return false; f(args...); return true; }; funcs.push_back(func); } inline void Emit(ParameterTypes ...args) { if(is_emitting) funcs.remove_if([&](auto& f){ return !f(args...); }); } inline bool SetEmitting(bool emitting) { bool was_emitting = is_emitting; is_emitting = emitting; return was_emitting; } inline bool GetEmitting() const { return is_emitting; } }; class SimpleSignal { private: // std::map> funcs; std::list>> funcs; public: SimpleSignal() = default; template void Connect(void* var, FUNC f) { // funcs[var] = f; funcs.push_back ( { var, f } ); } void Remove(void* var) { // funcs.erase(var); funcs.remove_if([&] (auto var_f) { return var_f.first==var; }); } inline void Emit() { for (auto [key,f] : funcs) f(); } }; } // namespace ngcore #endif // NGCORE_SIGNALS_HPP ================================================ FILE: libsrc/core/simd.hpp ================================================ #ifndef NETGEN_CORE_SIMD_HPP #define NETGEN_CORE_SIMD_HPP /**************************************************************************/ /* File: simd.hpp */ /* Author: Joachim Schoeberl, Matthias Hochsteger */ /* Date: 25. Mar. 16 */ /**************************************************************************/ #include #include #include "ngcore_api.hpp" #include "simd_generic.hpp" #ifndef __CUDA_ARCH__ #ifdef NETGEN_ARCH_AMD64 #ifndef __SSE__ #define __SSE__ #endif #include "simd_sse.hpp" #endif #ifdef __AVX__ #include "simd_avx.hpp" #endif #ifdef __AVX512F__ #include "simd_avx512.hpp" #endif #ifdef __aarch64__ #include "simd_arm64.hpp" #endif #endif // __CUDA_ARCH__ namespace ngcore { #ifndef __CUDA_ARCH__ #ifdef NETGEN_ARCH_AMD64 /* NETGEN_INLINE auto HSum (SIMD v1, SIMD v2, SIMD v3, SIMD v4) { SIMD hsum1 = my_mm_hadd_pd (v1.Data(), v2.Data()); SIMD hsum2 = my_mm_hadd_pd (v3.Data(), v4.Data()); return SIMD (hsum1, hsum2); } */ NETGEN_INLINE auto GetMaskFromBits( unsigned int i ) { return SIMD::GetMaskFromBits(i); } #endif #endif // __CUDA_ARCH__ NETGEN_INLINE void SIMDTranspose (SIMD a1, SIMD a2, SIMD a3, SIMD a4, SIMD & b1, SIMD & b2, SIMD & b3, SIMD & b4) { if constexpr (sizeof(a1.Lo()) == 16) { auto [h1,h2] = Unpack(a1,a2); auto [h3,h4] = Unpack(a3,a4); b1 = SIMD (h1.Lo(), h3.Lo()); b2 = SIMD (h2.Lo(), h4.Lo()); b3 = SIMD (h1.Hi(), h3.Hi()); b4 = SIMD (h2.Hi(), h4.Hi()); } else { b1 = SIMD (a1[0], a2[0], a3[0], a4[0]); b2 = SIMD (a1[1], a2[1], a3[1], a4[1]); b3 = SIMD (a1[2], a2[2], a3[2], a4[2]); b4 = SIMD (a1[3], a2[3], a3[3], a4[3]); } } template NETGEN_INLINE auto HSum (SIMD s1, SIMD s2) { return SIMD(HSum(s1), HSum(s2)); } template NETGEN_INLINE auto HSum (SIMD s1, SIMD s2, SIMD s3, SIMD s4 ) { // return SIMD(HSum(s1), HSum(s2), HSum(s3), HSum(s4)); return SIMD(HSum(s1, s2), HSum(s3,s4)); } template class MakeSimdCl; template auto MakeSimd (std::array aa) { return MakeSimdCl(aa).Get(); } template class MakeSimdCl { std::array a; public: MakeSimdCl (std::array aa) : a(aa) { ; } auto Get() const { SIMD sa( [this] (auto i) { return (this->a)[i]; }); return sa; } }; template class MakeSimdCl,S> { std::array,S> a; public: MakeSimdCl (std::array,S> aa) : a(aa) { ; } auto Get() const { std::array a0; for (int i = 0; i < S; i++) a0[i] = std::get<0> (a[i]); if constexpr (std::tuple_size>::value == 1) { return std::tuple(MakeSimd(a0)); } else { std::array,S> arest; for (int i = 0; i < S; i++) arest[i] = skip_first(a[i]); return std::tuple_cat ( std::tuple (MakeSimd(a0)), MakeSimd(arest) ); } } template static auto skip_first(const std::tuple& t) { return std::apply([](auto first, auto... rest) { return std::make_tuple(rest...); }, t); } }; } #include "simd_math.hpp" #endif // NETGEN_CORE_SIMD_HPP ================================================ FILE: libsrc/core/simd_arm64.hpp ================================================ #include "arm_neon.h" namespace ngcore { template <> class SIMD { int64x2_t mask; public: SIMD (int i) { mask[0] = i > 0 ? -1 : 0; mask[1] = i > 1 ? -1 : 0; } SIMD (bool i0, bool i1) { mask[0] = i0 ? -1 : 0; mask[1] = i1 ? -1 : 0; } SIMD (SIMD i0, SIMD i1) { mask[0] = i0[0]; mask[1] = i1[0]; } // SIMD (float64x2_t _data) : mask{_data} { } SIMD (int64x2_t _data) : mask{_data} { } auto Data() const { return mask; } static constexpr int Size() { return 2; } // static NETGEN_INLINE SIMD GetMaskFromBits (unsigned int i); int64_t operator[] (int i) const { return mask[i]; } template int64_t Get() const { return mask[I]; } auto Lo() const { return mask[0]; } auto Hi() const { return mask[1]; } }; // *************************** int32 *************************** template<> class SIMD { int32x2_t data; public: static constexpr int Size() { return 2; } SIMD() {} SIMD (int32_t val) : data{val,val} {} SIMD (int32_t v0, int32_t v1) : data{v0,v1} { } SIMD (SIMD lo, SIMD hi) : data{lo[0], hi[0] } { } SIMD (std::array arr) : data{arr[0], arr[1]} { } SIMD (int32x2_t _data) { data = _data; } NETGEN_INLINE auto Data() const { return data; } NETGEN_INLINE auto & Data() { return data; } SIMD Lo() const { return Get<0>(); } SIMD Hi() const { return Get<1>(); } int32_t operator[] (int i) const { return data[i]; } int32_t & operator[] (int i) { return ((int32_t*)&data)[i]; } template int32_t Get() const { return data[I]; } static SIMD FirstInt(int n0=0) { return { n0+0, n0+1 }; } }; template<> class SIMD { int32x4_t data; public: static constexpr int Size() { return 4; } SIMD() {} SIMD (int32_t val) : data{val,val,val,val} {} SIMD (int32_t v0, int32_t v1, int32_t v2, int32_t v3) : data{v0,v1,v2,v3} { } SIMD (std::array arr) : data{arr[0], arr[1], arr[2], arr[3]} { } SIMD (int32x4_t _data) { data = _data; } SIMD (SIMD lo, SIMD hi) : data{vcombine_s32(lo.Data(), hi.Data())} {} SIMD (int32_t * p) : data{vld1q_s32(p)} { } NETGEN_INLINE auto Data() const { return data; } NETGEN_INLINE auto & Data() { return data; } SIMD Lo() const { return vget_low_s32(data); } SIMD Hi() const { return vget_high_s32(data); } int32_t operator[] (int i) const { return data[i]; } int32_t & operator[] (int i) { return ((int32_t*)&data)[i]; } void Store (int32_t * p) { vst1q_s32(p, data); } template int32_t Get() const { return data[I]; } static SIMD FirstInt(int n0=0) { return { n0+0, n0+1, n0+2, n0+3 }; } }; NETGEN_INLINE auto Min (SIMD a, SIMD b) { return SIMD(vmin_s32(a.Data(), b.Data())); } NETGEN_INLINE auto Max (SIMD a, SIMD b) { return SIMD(vmax_s32(a.Data(), b.Data())); } NETGEN_INLINE auto Min (SIMD a, SIMD b) { return SIMD(vminq_s32(a.Data(), b.Data())); } NETGEN_INLINE auto Max (SIMD a, SIMD b) { return SIMD(vmaxq_s32(a.Data(), b.Data())); } // *************************** int64 *************************** template<> class SIMD { int64x2_t data; public: static constexpr int Size() { return 2; } SIMD() {} SIMD (int64_t val) : data{val,val} {} SIMD (int64_t v0, int64_t v1) : data{vcombine_s64(int64x1_t{v0}, int64x1_t{v1})} { } SIMD (std::array arr) : data{arr[0], arr[1]} { } SIMD (int64x2_t _data) { data = _data; } NETGEN_INLINE auto Data() const { return data; } NETGEN_INLINE auto & Data() { return data; } int64_t Lo() const { return Get<0>(); } int64_t Hi() const { return Get<1>(); } int64_t operator[] (int i) const { return data[i]; } int64_t & operator[] (int i) { return ((int64_t*)&data)[i]; } template int64_t Get() const { return data[I]; } static SIMD FirstInt(int n0=0) { return { n0+0, n0+1 }; } }; NETGEN_INLINE SIMD operator& (SIMD a, SIMD b) { return vandq_s64(a.Data(), b.Data()); } NETGEN_INLINE SIMD operator+ (SIMD a, SIMD b) { return vaddq_s64(a.Data(), b.Data()); } NETGEN_INLINE SIMD operator== (SIMD a, SIMD b) { return vceqq_u64(a.Data(), b.Data()); } NETGEN_INLINE SIMD operator> (SIMD a, SIMD b) { return vcgtq_s64(a.Data(), b.Data()); } template SIMD operator<< (SIMD a, IC n) { return vshlq_n_s64(a.Data(), N); } // *************************** double *************************** template<> class SIMD { float64x2_t data; public: static constexpr int Size() { return 2; } SIMD () {} SIMD (const SIMD &) = default; // SIMD (double v0, double v1) : data{v0,v1} { } SIMD (double v0, double v1) : data{vcombine_f64(float64x1_t{v0}, float64x1_t{v1})} { } SIMD (SIMD v0, SIMD v1) : data{vcombine_f64(float64x1_t{v0.Data()}, float64x1_t{v1.Data()})} { } SIMD (std::array arr) : data{arr[0], arr[1]} { } SIMD & operator= (const SIMD &) = default; SIMD (double val) : data{val,val} { } SIMD (int val) : data{double(val),double(val)} { } SIMD (size_t val) : data{double(val),double(val)} { } SIMD (double const * p) { data = vld1q_f64(p); // data[0] = p[0]; // data[1] = p[1]; } SIMD (double const * p, SIMD mask) { data[0] = mask[0] ? p[0] : 0; data[1] = mask[1] ? p[1] : 0; } SIMD (float64x2_t _data) { data = _data; } template>::value, int>::type = 0> SIMD (const T & func) { data[0] = func(0); data[1] = func(1); } void Store (double * p) { vst1q_f64(p, data); /* p[0] = data[0]; p[1] = data[1]; */ } void Store (double * p, SIMD mask) { if (mask[0]) p[0] = data[0]; if (mask[1]) p[1] = data[1]; } // NETGEN_INLINE double operator[] (int i) const { return ((double*)(&data))[i]; } NETGEN_INLINE double operator[] (int i) const { return data[i]; } NETGEN_INLINE double & operator[] (int i) { return ((double*)&data)[i]; } template double Get() const { return data[I]; } NETGEN_INLINE auto Data() const { return data; } NETGEN_INLINE auto & Data() { return data; } operator std::tuple () { auto pdata = (double*)&data; return std::tuple(pdata[0], pdata[1]); } double Lo() const { return Get<0>(); } // data[0]; } double Hi() const { return Get<1>(); } // data[1]; } // double Hi() const { return vget_high_f64(data)[0]; } }; NETGEN_INLINE double HSum (SIMD sd) { return sd.Lo()+sd.Hi(); // sd[0]+sd[1]; } NETGEN_INLINE SIMD HSum (SIMD a, SIMD b) { // return SIMD (a[0]+a[1], b[0]+b[1]); return vpaddq_f64(a.Data(), b.Data()); } NETGEN_INLINE SIMD HSum(SIMD a, SIMD b, SIMD c, SIMD d) { return SIMD (HSum(a,b), HSum(c,d)); } NETGEN_INLINE SIMD SwapPairs (SIMD a) { return __builtin_shufflevector(a.Data(), a.Data(), 1, 0); } // a*b+c NETGEN_INLINE SIMD FMA (SIMD a, SIMD b, SIMD c) { return vmlaq_f64(c.Data(), a.Data(), b.Data()); } NETGEN_INLINE SIMD FMA (const double & a, SIMD b, SIMD c) { return FMA(SIMD (a), b, c); } // -a*b+c NETGEN_INLINE SIMD FNMA (SIMD a, SIMD b, SIMD c) { return vmlsq_f64(c.Data(), a.Data(), b.Data()); // return c-a*b; } NETGEN_INLINE SIMD FNMA (const double & a, SIMD b, SIMD c) { return FNMA(SIMD (a), b, c); } // ARM complex mult: // https://arxiv.org/pdf/1901.07294.pdf // c += a*b (a0re, a0im, a1re, a1im, ...), NETGEN_INLINE void FMAComplex (SIMD a, SIMD b, SIMD & c) { auto tmp = vcmlaq_f64(c.Data(), a.Data(), b.Data()); // are * b c = vcmlaq_rot90_f64(tmp, a.Data(), b.Data()); // += i*aim * b } NETGEN_INLINE void FMAComplex (SIMD a, SIMD b, SIMD & c) { SIMD clo = c.Lo(); SIMD chi = c.Hi(); FMAComplex (a.Lo(), b.Lo(), clo); FMAComplex (a.Hi(), b.Hi(), chi); c = SIMD (clo, chi); } NETGEN_INLINE SIMD operator+ (SIMD a, SIMD b) { return a.Data()+b.Data(); } NETGEN_INLINE SIMD operator- (SIMD a, SIMD b) { return a.Data()-b.Data(); } NETGEN_INLINE SIMD operator- (SIMD a) { return -a.Data(); } NETGEN_INLINE SIMD operator* (SIMD a, SIMD b) { return a.Data()*b.Data(); } NETGEN_INLINE SIMD operator/ (SIMD a, SIMD b) { return a.Data()/b.Data(); } NETGEN_INLINE SIMD sqrt (SIMD x) { return vsqrtq_f64(x.Data()); } NETGEN_INLINE SIMD round (SIMD x) { return vrndnq_f64(x.Data()); } NETGEN_INLINE SIMD lround (SIMD x) { return vcvtq_s64_f64(x.Data()); } NETGEN_INLINE SIMD rsqrt (SIMD x) { return 1.0 / sqrt(x); // SIMD y = vrsqrteq_f64(x.Data()); /* y = y * vrsqrtsq_f64( (x*y).Data(), y.Data()); y = y * vrsqrtsq_f64( (x*y).Data(), y.Data()); y = y * vrsqrtsq_f64( (x*y).Data(), y.Data()); */ /* auto x_half = 0.5*x; y = y * (1.5 - (x_half * y * y)); y = y * (1.5 - (x_half * y * y)); y = y * (1.5 - (x_half * y * y)); return y; */ } template <> NETGEN_INLINE SIMD Reinterpret (SIMD a) { return vreinterpretq_f64_s64(a.Data()); } NETGEN_INLINE SIMD If (SIMD a, SIMD b, SIMD c) { // return { a[0] ? b[0] : c[0], a[1] ? b[1] : c[1] }; uint64x2_t mask = vreinterpretq_u64_s64(a.Data()); return vbslq_f64(mask, b.Data(), c.Data()); } NETGEN_INLINE SIMD If (SIMD a, SIMD b, SIMD c) { // return SIMD (a[0] ? b[0] : c[0], a[1] ? b[1] : c[1]); uint64x2_t mask = vreinterpretq_u64_s64(a.Data()); return vbslq_s64(mask, b.Data(), c.Data()); } NETGEN_INLINE SIMD operator&& (SIMD a, SIMD b) { uint64x2_t m1 = vreinterpretq_u64_s64(a.Data()); uint64x2_t m2 = vreinterpretq_u64_s64(b.Data()); uint64x2_t res = vandq_u64 (m1, m2); return vreinterpretq_s64_u64(res); } } ================================================ FILE: libsrc/core/simd_avx.hpp ================================================ #ifndef NETGEN_CORE_SIMD_AVX_HPP #define NETGEN_CORE_SIMD_AVX_HPP /**************************************************************************/ /* File: simd_avx.hpp */ /* Author: Joachim Schoeberl, Matthias Hochsteger */ /* Date: 25. Mar. 16 */ /**************************************************************************/ #include namespace ngcore { #if defined(__GNUC__) && (__GNUC__ == 7) // GCC7 does not have intrinsic _mm256_set_m128i, see // https://stackoverflow.com/questions/32630458/setting-m256i-to-the-value-of-two-m128i-values NETGEN_INLINE auto _mm256_set_m128i(__m128i v0, __m128i v1) { return _mm256_insertf128_si256(_mm256_castsi128_si256(v1), (v0), 1); } #endif // defined(__GNUC__) && (__GNUC__ == 7) #if defined(__AVX2__) NETGEN_INLINE __m256i my_mm256_cmpeq_epi64 (__m256i a, __m256i b) { return _mm256_cmpeq_epi64 (a,b); } NETGEN_INLINE __m256i my_mm256_cmpgt_epi64 (__m256i a, __m256i b) { return _mm256_cmpgt_epi64 (a,b); } NETGEN_INLINE __m256i my_mm256_cvtepi32_epi64 (__m128i a) { return _mm256_cvtepi32_epi64 (a); } #else NETGEN_INLINE __m256i my_mm256_cmpeq_epi64 (__m256i a, __m256i b) { __m128i rlo = _mm_cmpeq_epi64(_mm256_extractf128_si256(a, 0), _mm256_extractf128_si256(b, 0)); __m128i rhi = _mm_cmpeq_epi64(_mm256_extractf128_si256(a, 1), _mm256_extractf128_si256(b, 1)); return _mm256_insertf128_si256 (_mm256_castsi128_si256(rlo), rhi, 1); } NETGEN_INLINE __m256i my_mm256_cmpgt_epi64 (__m256i a, __m256i b) { __m128i rlo = _mm_cmpgt_epi64(_mm256_extractf128_si256(a, 0), _mm256_extractf128_si256(b, 0)); __m128i rhi = _mm_cmpgt_epi64(_mm256_extractf128_si256(a, 1), _mm256_extractf128_si256(b, 1)); return _mm256_insertf128_si256 (_mm256_castsi128_si256(rlo), rhi, 1); } NETGEN_INLINE __m256i my_mm256_cvtepi32_epi64 (__m128i a) { __m128i rlo = _mm_cvtepi32_epi64(a); // First two 32-bit integers __m128i rhi = _mm_cvtepi32_epi64(_mm_shuffle_epi32(a, _MM_SHUFFLE(3, 2, 3, 2))); // Next two 32-bit integers return _mm256_insertf128_si256 (_mm256_castsi128_si256(rlo), rhi, 1); } #endif template <> class SIMD { __m256i mask; public: SIMD (int64_t i) : mask(my_mm256_cmpgt_epi64(_mm256_set1_epi64x(i), _mm256_set_epi64x(3, 2, 1, 0))) { ; } SIMD (__m256i _mask) : mask(_mask) { ; } SIMD (__m256d _mask) : mask(_mm256_castpd_si256(_mask)) { ; } __m256i Data() const { return mask; } static constexpr int Size() { return 4; } static SIMD GetMaskFromBits (unsigned int i); }; static SIMD masks_from_4bits[16] = { _mm256_set_epi64x (0,0,0,0), _mm256_set_epi64x (0,0,0,-1), _mm256_set_epi64x (0,0,-1,0), _mm256_set_epi64x (0,0,-1,-1), _mm256_set_epi64x (0,-1,0,0), _mm256_set_epi64x (0,-1,0,-1), _mm256_set_epi64x (0,-1,-1,0), _mm256_set_epi64x (0,-1,-1,-1), _mm256_set_epi64x (-1,0,0,0), _mm256_set_epi64x (-1,0,0,-1), _mm256_set_epi64x (-1,0,-1,0), _mm256_set_epi64x (-1,0,-1,-1), _mm256_set_epi64x (-1,-1,0,0), _mm256_set_epi64x (-1,-1,0,-1), _mm256_set_epi64x (-1,-1,-1,0), _mm256_set_epi64x (-1,-1,-1,-1) }; NETGEN_INLINE SIMD SIMD :: GetMaskFromBits (unsigned int i) { return masks_from_4bits[i & 15]; } template<> class alignas(32) SIMD { __m256i data; public: static constexpr int Size() { return 4; } SIMD () {} SIMD (const SIMD &) = default; SIMD & operator= (const SIMD &) = default; SIMD (int64_t val) { data = _mm256_set1_epi64x(val); } SIMD (int64_t v0, int64_t v1, int64_t v2, int64_t v3) { data = _mm256_set_epi64x(v3,v2,v1,v0); } SIMD (std::array a) : data{_mm256_set_epi64x(a[3],a[2],a[1],a[0])} {} SIMD (SIMD v0, SIMD v1) : data(_mm256_set_m128i(v1.Data(),v0.Data())) {} SIMD (__m256i _data) { data = _data; } NETGEN_INLINE auto operator[] (int i) const { return ((int64_t*)(&data))[i]; } NETGEN_INLINE __m256i Data() const { return data; } NETGEN_INLINE __m256i & Data() { return data; } SIMD Lo() const { return _mm256_extractf128_si256(data, 0); } SIMD Hi() const { return _mm256_extractf128_si256(data, 1); } static SIMD FirstInt(int n0=0) { return { n0+0, n0+1, n0+2, n0+3 }; } template double Get() const { static_assert(I>=0 && I<4, "Index out of range"); return (*this)[I]; } }; NETGEN_INLINE SIMD operator-(SIMD a) { return _mm256_sub_epi64(_mm256_setzero_si256(), a.Data()); } #ifdef __AVX2__ NETGEN_INLINE SIMD operator+ (SIMD a, SIMD b) { return _mm256_add_epi64(a.Data(),b.Data()); } NETGEN_INLINE SIMD operator- (SIMD a, SIMD b) { return _mm256_sub_epi64(a.Data(),b.Data()); } NETGEN_INLINE SIMD operator& (SIMD a, SIMD b) { return _mm256_castpd_si256(_mm256_and_pd (_mm256_castsi256_pd(a.Data()),_mm256_castsi256_pd( b.Data()))); } template SIMD operator<< (SIMD a, IC n) { return _mm256_sll_epi64(a.Data(),_mm_set_epi32(0,0,0,N)); } #endif // __AVX2__ template<> class alignas(32) SIMD { __m256d data; public: static constexpr int Size() { return 4; } SIMD () {} SIMD (const SIMD &) = default; SIMD & operator= (const SIMD &) = default; SIMD (double val) { data = _mm256_set1_pd(val); } SIMD (int val) { data = _mm256_set1_pd(val); } SIMD (size_t val) { data = _mm256_set1_pd(val); } SIMD (double v0, double v1, double v2, double v3) { data = _mm256_set_pd(v3,v2,v1,v0); } SIMD (SIMD v0, SIMD v1) : SIMD(v0[0], v0[1], v1[0], v1[1]) { ; } SIMD (double const * p) { data = _mm256_loadu_pd(p); } SIMD (double const * p, SIMD mask) { data = _mm256_maskload_pd(p, mask.Data()); } SIMD (__m256d _data) { data = _data; } SIMD (std::array a) : data{_mm256_set_pd(a[3],a[2],a[1],a[0])} {} void Store (double * p) { _mm256_storeu_pd(p, data); } void Store (double * p, SIMD mask) { _mm256_maskstore_pd(p, mask.Data(), data); } template>::value, int>::type = 0> SIMD (const T & func) { data = _mm256_set_pd(func(3), func(2), func(1), func(0)); } NETGEN_INLINE double operator[] (int i) const { return ((double*)(&data))[i]; } NETGEN_INLINE double & operator[] (int i) { return ((double*)(&data))[i]; } // [[deprecated("don't write to individual elements of SIMD")]] // NETGEN_INLINE double & operator[] (int i) { return ((double*)(&data))[i]; } NETGEN_INLINE __m256d Data() const { return data; } NETGEN_INLINE __m256d & Data() { return data; } SIMD Lo() const { return _mm256_extractf128_pd(data, 0); } SIMD Hi() const { return _mm256_extractf128_pd(data, 1); } operator std::tuple () { return std::tuple((*this)[0], (*this)[1], (*this)[2], (*this)[3]); } template double Get() const { static_assert(I>=0 && I<4, "Index out of range"); return (*this)[I]; } }; NETGEN_INLINE auto Unpack (SIMD a, SIMD b) { return std::make_tuple(SIMD(_mm256_unpacklo_pd(a.Data(),b.Data())), SIMD(_mm256_unpackhi_pd(a.Data(),b.Data()))); } NETGEN_INLINE SIMD operator- (SIMD a) { return _mm256_xor_pd(a.Data(), _mm256_set1_pd(-0.0)); } NETGEN_INLINE SIMD operator+ (SIMD a, SIMD b) { return _mm256_add_pd(a.Data(),b.Data()); } NETGEN_INLINE SIMD operator- (SIMD a, SIMD b) { return _mm256_sub_pd(a.Data(),b.Data()); } NETGEN_INLINE SIMD operator* (SIMD a, SIMD b) { return _mm256_mul_pd(a.Data(),b.Data()); } NETGEN_INLINE SIMD operator/ (SIMD a, SIMD b) { return _mm256_div_pd(a.Data(),b.Data()); } NETGEN_INLINE SIMD operator* (double a, SIMD b) { return _mm256_set1_pd(a)*b.Data(); } NETGEN_INLINE SIMD operator* (SIMD b, double a) { return _mm256_set1_pd(a)*b.Data(); } NETGEN_INLINE SIMD sqrt (SIMD a) { return _mm256_sqrt_pd(a.Data()); } NETGEN_INLINE SIMD floor (SIMD a) { return _mm256_floor_pd(a.Data()); } NETGEN_INLINE SIMD ceil (SIMD a) { return _mm256_ceil_pd(a.Data()); } NETGEN_INLINE SIMD fabs (SIMD a) { return _mm256_max_pd(a.Data(), (-a).Data()); } NETGEN_INLINE SIMD round(SIMD a) { return _mm256_round_pd(a.Data(), _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); } NETGEN_INLINE SIMD lround (SIMD a) { return my_mm256_cvtepi32_epi64(_mm256_cvtpd_epi32(_mm256_round_pd(a.Data(), _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC))); } #ifdef __FMA__ NETGEN_INLINE SIMD FMA (SIMD a, SIMD b, SIMD c) { return _mm256_fmadd_pd (a.Data(), b.Data(), c.Data()); } NETGEN_INLINE SIMD FMA (const double & a, SIMD b, SIMD c) { return _mm256_fmadd_pd (_mm256_set1_pd(a), b.Data(), c.Data()); } NETGEN_INLINE SIMD FNMA (SIMD a, SIMD b, SIMD c) { return _mm256_fnmadd_pd (a.Data(), b.Data(), c.Data()); } NETGEN_INLINE SIMD FNMA (const double & a, SIMD b, SIMD c) { return _mm256_fnmadd_pd (_mm256_set1_pd(a), b.Data(), c.Data()); } #endif #if defined(__FMA__) && !defined(__AVX512F__) // make sure to use the update-version of fma // important in matrix kernels using 12 sum-registers, 3 a-values and updated b-value // avx512 has enough registers, and gcc seems to use only the first 16 z-regs NETGEN_INLINE void FMAasm (SIMD a, SIMD b, SIMD & sum) { asm ("vfmadd231pd %[a], %[b], %[sum]" : [sum] "+x" (sum.Data()) : [a] "x" (a.Data()), [b] "x" (b.Data()) ); } NETGEN_INLINE void FNMAasm (SIMD a, SIMD b, SIMD & sum) { asm ("vfnmadd231pd %[a], %[b], %[sum]" : [sum] "+x" (sum.Data()) : [a] "x" (a.Data()), [b] "x" (b.Data()) ); } #endif #if defined(__FMA__) NETGEN_INLINE SIMD FMAddSub (SIMD a, SIMD b, SIMD c) { return _mm256_fmaddsub_pd(a.Data(), b.Data(), c.Data()); } #endif NETGEN_INLINE SIMD SwapPairs (SIMD a) { return _mm256_shuffle_pd (a.Data(), a.Data(), 0b0101); } NETGEN_INLINE SIMD operator<= (SIMD a , SIMD b) { return _mm256_cmp_pd (a.Data(), b.Data(), _CMP_LE_OQ); } NETGEN_INLINE SIMD operator< (SIMD a , SIMD b) { return _mm256_cmp_pd (a.Data(), b.Data(), _CMP_LT_OQ); } NETGEN_INLINE SIMD operator>= (SIMD a , SIMD b) { return _mm256_cmp_pd (a.Data(), b.Data(), _CMP_GE_OQ); } NETGEN_INLINE SIMD operator> (SIMD a , SIMD b) { return _mm256_cmp_pd (a.Data(), b.Data(), _CMP_GT_OQ); } NETGEN_INLINE SIMD operator== (SIMD a , SIMD b) { return _mm256_cmp_pd (a.Data(), b.Data(), _CMP_EQ_OQ); } NETGEN_INLINE SIMD operator!= (SIMD a , SIMD b) { return _mm256_cmp_pd (a.Data(), b.Data(), _CMP_NEQ_OQ); } NETGEN_INLINE SIMD operator<= (SIMD a , SIMD b) { return _mm256_xor_si256(_mm256_cmpgt_epi64(a.Data(),b.Data()),_mm256_set1_epi32(-1)); } NETGEN_INLINE SIMD operator< (SIMD a , SIMD b) { return my_mm256_cmpgt_epi64(b.Data(),a.Data()); } NETGEN_INLINE SIMD operator>= (SIMD a , SIMD b) { return _mm256_xor_si256(_mm256_cmpgt_epi64(b.Data(),a.Data()),_mm256_set1_epi32(-1)); } NETGEN_INLINE SIMD operator> (SIMD a , SIMD b) { return my_mm256_cmpgt_epi64(a.Data(),b.Data()); } NETGEN_INLINE SIMD operator== (SIMD a , SIMD b) { return my_mm256_cmpeq_epi64(a.Data(),b.Data()); } NETGEN_INLINE SIMD operator!= (SIMD a , SIMD b) { return _mm256_xor_si256(my_mm256_cmpeq_epi64(a.Data(),b.Data()),_mm256_set1_epi32(-1)); } #ifdef __AVX2__ NETGEN_INLINE SIMD operator&& (SIMD a, SIMD b) { return _mm256_and_si256 (a.Data(), b.Data()); } NETGEN_INLINE SIMD operator|| (SIMD a, SIMD b) { return _mm256_or_si256 (a.Data(), b.Data()); } NETGEN_INLINE SIMD operator! (SIMD a) { return _mm256_xor_si256 (a.Data(), _mm256_cmpeq_epi64(a.Data(),a.Data())); } #else //AVX2 is a superset of AVX. Without it, it is necessary to reinterpret the types NETGEN_INLINE SIMD operator&& (SIMD a, SIMD b) { return _mm256_castpd_si256(_mm256_and_pd (_mm256_castsi256_pd(a.Data()),_mm256_castsi256_pd( b.Data()))); } NETGEN_INLINE SIMD operator|| (SIMD a, SIMD b) { return _mm256_castpd_si256(_mm256_or_pd (_mm256_castsi256_pd(a.Data()), _mm256_castsi256_pd(b.Data()))); } NETGEN_INLINE SIMD operator! (SIMD a) { return _mm256_castpd_si256(_mm256_xor_pd (_mm256_castsi256_pd(a.Data()),_mm256_castsi256_pd( _mm256_cmpeq_epi64(a.Data(),a.Data())))); } #endif template <> NETGEN_INLINE SIMD Reinterpret (SIMD a) { return _mm256_castsi256_pd (a.Data()); } NETGEN_INLINE SIMD If (SIMD a, SIMD b, SIMD c) { return _mm256_blendv_pd(c.Data(), b.Data(), _mm256_castsi256_pd(a.Data())); } NETGEN_INLINE SIMD IfPos (SIMD a, SIMD b, SIMD c) { auto cp = _mm256_cmp_pd (a.Data(), _mm256_setzero_pd(), _CMP_GT_OS); return _mm256_blendv_pd(c.Data(), b.Data(), cp); } NETGEN_INLINE SIMD IfZero (SIMD a, SIMD b, SIMD c) { auto cp = _mm256_cmp_pd (a.Data(), _mm256_setzero_pd(), _CMP_EQ_OS); return _mm256_blendv_pd(c.Data(), b.Data(), cp); } NETGEN_INLINE double HSum (SIMD sd) { // __m128d hv = _mm_add_pd (_mm256_extractf128_pd(sd.Data(),0), _mm256_extractf128_pd(sd.Data(),1)); __m128d hv = (sd.Lo()+sd.Hi()).Data(); return _mm_cvtsd_f64 (_mm_hadd_pd (hv, hv)); } NETGEN_INLINE auto HSum (SIMD sd1, SIMD sd2) { __m256d hv = _mm256_hadd_pd(sd1.Data(), sd2.Data()); __m128d hv2 = _mm_add_pd (_mm256_extractf128_pd(hv,0), _mm256_extractf128_pd(hv,1)); return SIMD(_mm_cvtsd_f64 (hv2), _mm_cvtsd_f64(_mm_shuffle_pd (hv2, hv2, 3))); } NETGEN_INLINE auto HSum (SIMD v1, SIMD v2, SIMD v3, SIMD v4) { __m256d hsum1 = _mm256_hadd_pd (v1.Data(), v2.Data()); __m256d hsum2 = _mm256_hadd_pd (v3.Data(), v4.Data()); SIMD hsum = _mm256_add_pd (_mm256_permute2f128_pd (hsum1, hsum2, 1+2*16), _mm256_blend_pd (hsum1, hsum2, 12)); return hsum; // return make_tuple(hsum[0], hsum[1], hsum[2], hsum[3]); } /* // untested ... NETGEN_INLINE SIMD rsqrt (SIMD x) { // return 1.0 / sqrt(x); // SIMD y = _mm256_rsqrt14_pd(x.Data()); // only avx512 SIMD y = _mm256_cvtps_pd ( _mm_rsqrt_ps ( _mm256_cvtpd_ps (x.Data()))); auto x_half = 0.5*x; y = y * (1.5 - (x_half * y * y)); y = y * (1.5 - (x_half * y * y)); return y; } */ NETGEN_INLINE SIMD If (SIMD a, SIMD b, SIMD c) { return _mm256_castpd_si256(_mm256_blendv_pd(_mm256_castsi256_pd(c.Data()), _mm256_castsi256_pd(b.Data()), _mm256_castsi256_pd(a.Data()))); } } #endif // NETGEN_CORE_SIMD_AVX_HPP ================================================ FILE: libsrc/core/simd_avx512.hpp ================================================ #ifndef NETGEN_CORE_SIMD_AVX512_HPP #define NETGEN_CORE_SIMD_AVX512_HPP /**************************************************************************/ /* File: simd_avx512.hpp */ /* Author: Joachim Schoeberl, Matthias Hochsteger */ /* Date: 25. Mar. 16 */ /**************************************************************************/ #include namespace ngcore { template <> class SIMD { __mmask8 mask; public: SIMD (size_t i) : mask(_mm512_cmpgt_epi64_mask(_mm512_set1_epi64(i), _mm512_set_epi64(7, 6, 5, 4, 3, 2, 1, 0))) { ; } SIMD (int i) : mask(_mm512_cmpgt_epi64_mask(_mm512_set1_epi64(i), _mm512_set_epi64(7, 6, 5, 4, 3, 2, 1, 0))) { ; } SIMD (int64_t i) : mask(_mm512_cmpgt_epi64_mask(_mm512_set1_epi64(i), _mm512_set_epi64(7, 6, 5, 4, 3, 2, 1, 0))) { ; } SIMD (__mmask8 _mask) : mask(_mask) { ; } __mmask8 Data() const { return mask; } static constexpr int Size() { return 8; } static NETGEN_INLINE SIMD GetMaskFromBits (unsigned int i) { return SIMD(__mmask8(i)); } }; template<> class alignas(64) SIMD { __m512i data; public: static constexpr int Size() { return 8; } SIMD () {} SIMD (const SIMD &) = default; SIMD & operator= (const SIMD &) = default; SIMD (int64_t val) { data = _mm512_set1_epi64(val); } SIMD (int64_t v0, int64_t v1, int64_t v2, int64_t v3, int64_t v4, int64_t v5, int64_t v6, int64_t v7) { data = _mm512_set_epi64(v7,v6,v5,v4,v3,v2,v1,v0); } SIMD (__m512i _data) { data = _data; } template>::value, int>::type = 0> SIMD (const T & func) { data = _mm512_set_epi64(func(7), func(6), func(5), func(4), func(3), func(2), func(1), func(0)); } SIMD (SIMD v0, SIMD v1) : data(_mm512_castsi256_si512(v0.Data())) { data = _mm512_inserti64x4(data, v1.Data(), 1); } SIMD Lo() const { return _mm512_castsi512_si256(data); } SIMD Hi() const { return _mm512_extracti64x4_epi64(data, 1); } NETGEN_INLINE auto operator[] (int i) const { return ((int64_t*)(&data))[i]; } NETGEN_INLINE auto & operator[] (int i) { return ((int64_t*)(&data))[i]; } NETGEN_INLINE __m512i Data() const { return data; } NETGEN_INLINE __m512i & Data() { return data; } static SIMD FirstInt() { return { 0, 1, 2, 3, 4, 5, 6, 7 }; } }; NETGEN_INLINE SIMD operator-(SIMD a) { return _mm512_sub_epi64(_mm512_setzero_si512(), a.Data()); } NETGEN_INLINE SIMD operator+ (SIMD a, SIMD b) { return _mm512_add_epi64(a.Data(),b.Data()); } NETGEN_INLINE SIMD operator- (SIMD a, SIMD b) { return _mm512_sub_epi64(a.Data(),b.Data()); } NETGEN_INLINE SIMD If (SIMD a, SIMD b, SIMD c) { return _mm512_mask_blend_epi64(a.Data(), c.Data(), b.Data()); } template<> class alignas(64) SIMD { __m512d data; public: static constexpr int Size() { return 8; } SIMD () {} SIMD (const SIMD &) = default; SIMD & operator= (const SIMD &) = default; SIMD (double val) { data = _mm512_set1_pd(val); } SIMD (int val) { data = _mm512_set1_pd(val); } SIMD (size_t val) { data = _mm512_set1_pd(val); } SIMD (double const * p) { data = _mm512_loadu_pd(p); } SIMD (double const * p, SIMD mask) { data = _mm512_mask_loadu_pd(_mm512_setzero_pd(), mask.Data(), p); } SIMD (__m512d _data) { data = _data; } SIMD (SIMD v0, SIMD v1) : data(_mm512_set_pd(v1[3], v1[2], v1[1], v1[0], v0[3], v0[2], v0[1], v0[0])) {} SIMD (SIMD v0, SIMD v1) : data(_mm512_set_pd(v1[1], v1[0], v0[5], v0[4], v0[3], v0[2], v0[1], v0[0])) {} template>::value, int>::type = 0> SIMD (const T & func) { data = _mm512_set_pd(func(7), func(6), func(5), func(4), func(3), func(2), func(1), func(0)); } void Store (double * p) { _mm512_storeu_pd(p, data); } void Store (double * p, SIMD mask) { _mm512_mask_storeu_pd(p, mask.Data(), data); } template void SIMD_function (const Function & func, std::true_type) { data = (__m512d){ func(7), func(6), func(5), func(4), func(3), func(2), func(1), func(0) }; } // not a function void SIMD_function (double const * p, std::false_type) { data = _mm512_loadu_pd(p); } void SIMD_function (double val, std::false_type) { data = _mm512_set1_pd(val); } void SIMD_function (__m512d _data, std::false_type) { data = _data; } NETGEN_INLINE double operator[] (int i) const { return ((double*)(&data))[i]; } NETGEN_INLINE double & operator[] (int i) { return ((double*)(&data))[i]; } NETGEN_INLINE __m512d Data() const { return data; } NETGEN_INLINE __m512d & Data() { return data; } SIMD Lo() const { return _mm512_extractf64x4_pd(data, 0); } SIMD Hi() const { return _mm512_extractf64x4_pd(data, 1); } template double Get() const { static_assert(I>=0 && I<8, "Index out of range"); return (*this)[I]; } }; NETGEN_INLINE SIMD operator- (SIMD a) { return _mm512_xor_pd(a.Data(), _mm512_set1_pd(-0.0)); } //{ return -a.Data(); } NETGEN_INLINE SIMD operator+ (SIMD a, SIMD b) { return _mm512_add_pd(a.Data(),b.Data()); } NETGEN_INLINE SIMD operator- (SIMD a, SIMD b) { return _mm512_sub_pd(a.Data(),b.Data()); } NETGEN_INLINE SIMD operator* (SIMD a, SIMD b) { return _mm512_mul_pd(a.Data(),b.Data()); } NETGEN_INLINE SIMD operator/ (SIMD a, SIMD b) { return _mm512_div_pd(a.Data(),b.Data()); } NETGEN_INLINE SIMD operator* (double a, SIMD b) { return _mm512_set1_pd(a)*b.Data(); } NETGEN_INLINE SIMD operator* (SIMD b, double a) { return _mm512_set1_pd(a)*b.Data(); } NETGEN_INLINE SIMD sqrt (SIMD a) { return _mm512_sqrt_pd(a.Data()); } NETGEN_INLINE SIMD floor (SIMD a) { return _mm512_floor_pd(a.Data()); } NETGEN_INLINE SIMD ceil (SIMD a) { return _mm512_ceil_pd(a.Data()); } NETGEN_INLINE SIMD fabs (SIMD a) { return _mm512_max_pd(a.Data(), ( - a).Data()); } NETGEN_INLINE SIMD operator<= (SIMD a , SIMD b) { return _mm512_cmp_pd_mask (a.Data(), b.Data(), _CMP_LE_OQ); } NETGEN_INLINE SIMD operator< (SIMD a , SIMD b) { return _mm512_cmp_pd_mask (a.Data(), b.Data(), _CMP_LT_OQ); } NETGEN_INLINE SIMD operator>= (SIMD a , SIMD b) { return _mm512_cmp_pd_mask (a.Data(), b.Data(), _CMP_GE_OQ); } NETGEN_INLINE SIMD operator> (SIMD a , SIMD b) { return _mm512_cmp_pd_mask (a.Data(), b.Data(), _CMP_GT_OQ); } NETGEN_INLINE SIMD operator== (SIMD a , SIMD b) { return _mm512_cmp_pd_mask (a.Data(), b.Data(), _CMP_EQ_OQ); } NETGEN_INLINE SIMD operator!= (SIMD a , SIMD b) { return _mm512_cmp_pd_mask (a.Data(), b.Data(), _CMP_NEQ_OQ); } NETGEN_INLINE SIMD operator<= (SIMD a , SIMD b) { return _mm512_cmp_epi64_mask (a.Data(), b.Data(), _MM_CMPINT_LE); } NETGEN_INLINE SIMD operator< (SIMD a , SIMD b) { return _mm512_cmp_epi64_mask (a.Data(), b.Data(), _MM_CMPINT_LT); } NETGEN_INLINE SIMD operator>= (SIMD a , SIMD b) { return _mm512_cmp_epi64_mask (a.Data(), b.Data(), _MM_CMPINT_NLT); } NETGEN_INLINE SIMD operator> (SIMD a , SIMD b) { return _mm512_cmp_epi64_mask (a.Data(), b.Data(), _MM_CMPINT_NLE); } NETGEN_INLINE SIMD operator== (SIMD a , SIMD b) { return _mm512_cmp_epi64_mask (a.Data(), b.Data(), _MM_CMPINT_EQ); } NETGEN_INLINE SIMD operator!= (SIMD a , SIMD b) { return _mm512_cmp_epi64_mask (a.Data(), b.Data(), _MM_CMPINT_NE); } NETGEN_INLINE SIMD operator&& (SIMD a, SIMD b) { return (__mmask8)(a.Data() & b.Data()); } NETGEN_INLINE SIMD operator|| (SIMD a, SIMD b) { return (__mmask8)(a.Data() | b.Data()); } NETGEN_INLINE SIMD operator! (SIMD a) { return (__mmask8)(~a.Data()); } NETGEN_INLINE SIMD If (SIMD a, SIMD b, SIMD c) { return _mm512_mask_blend_pd(a.Data(), c.Data(), b.Data()); } NETGEN_INLINE SIMD IfPos (SIMD a, SIMD b, SIMD c) { auto k = _mm512_cmp_pd_mask(a.Data(),_mm512_setzero_pd(), _CMP_GT_OS); return _mm512_mask_blend_pd(k,c.Data(),b.Data()); } NETGEN_INLINE SIMD IfZero (SIMD a, SIMD b, SIMD c) { auto k = _mm512_cmp_pd_mask(a.Data(),_mm512_setzero_pd(), _CMP_EQ_OS); return _mm512_mask_blend_pd(k,c.Data(),b.Data()); } NETGEN_INLINE auto Unpack (SIMD a, SIMD b) { return std::make_tuple(SIMD(_mm512_unpacklo_pd(a.Data(),b.Data())), SIMD(_mm512_unpackhi_pd(a.Data(),b.Data()))); } NETGEN_INLINE double HSum (SIMD sd) { SIMD low = _mm512_extractf64x4_pd(sd.Data(),0); SIMD high = _mm512_extractf64x4_pd(sd.Data(),1); return HSum(low)+HSum(high); } NETGEN_INLINE auto HSum (SIMD sd1, SIMD sd2) { return SIMD(HSum(sd1), HSum(sd2)); } NETGEN_INLINE SIMD HSum (SIMD v1, SIMD v2, SIMD v3, SIMD v4) { SIMD lo,hi; std::tie(lo,hi) = Unpack(v1, v2); SIMD sum01 = lo+hi; std::tie(lo,hi) = Unpack(v3, v4); SIMD sum23 = lo+hi; // sum01 b a b a b a b a // sum23 d c d c d c d c // __m512 perm = _mm512_permutex2var_pd (sum01.Data(), _mm512_set_epi64(1,2,3,4,5,6,7,8), sum23.Data()); SIMD ab = _mm512_extractf64x4_pd(sum01.Data(),0) + _mm512_extractf64x4_pd(sum01.Data(),1); SIMD cd = _mm512_extractf64x4_pd(sum23.Data(),0) + _mm512_extractf64x4_pd(sum23.Data(),1); return _mm256_add_pd (_mm256_permute2f128_pd (ab.Data(), cd.Data(), 1 + 2 * 16), _mm256_blend_pd(ab.Data(), cd.Data(), 12)); } NETGEN_INLINE SIMD FMA (SIMD a, SIMD b, SIMD c) { return _mm512_fmadd_pd (a.Data(), b.Data(), c.Data()); } NETGEN_INLINE SIMD FMA (const double & a, SIMD b, SIMD c) { return _mm512_fmadd_pd (_mm512_set1_pd(a), b.Data(), c.Data()); } NETGEN_INLINE SIMD FNMA (SIMD a, SIMD b, SIMD c) { return _mm512_fnmadd_pd (a.Data(), b.Data(), c.Data()); } NETGEN_INLINE SIMD FNMA (const double & a, SIMD b, SIMD c) { return _mm512_fnmadd_pd (_mm512_set1_pd(a), b.Data(), c.Data()); } NETGEN_INLINE SIMD FMAddSub (SIMD a, SIMD b, SIMD c) { return _mm512_fmaddsub_pd(a.Data(), b.Data(), c.Data()); } NETGEN_INLINE SIMD SwapPairs (SIMD a) { return _mm512_shuffle_pd (a.Data(), a.Data(), 0b01010101); } } #endif // NETGEN_CORE_SIMD_AVX512_HPP ================================================ FILE: libsrc/core/simd_generic.hpp ================================================ #ifndef NETGEN_CORE_SIMD_GENERIC_HPP #define NETGEN_CORE_SIMD_GENERIC_HPP /**************************************************************************/ /* File: simd_base.hpp */ /* Author: Joachim Schoeberl, Matthias Hochsteger */ /* Date: 25. Mar. 16 */ /**************************************************************************/ #include #include #include #include #include "array.hpp" namespace ngcore { #if defined __AVX512F__ #define NETGEN_DEFAULT_SIMD_SIZE 8 #elif defined __AVX__ #define NETGEN_DEFAULT_SIMD_SIZE 4 #else #define NETGEN_DEFAULT_SIMD_SIZE 2 #endif constexpr int GetDefaultSIMDSize() { return NETGEN_DEFAULT_SIMD_SIZE; } constexpr bool IsNativeSIMDSize(int n) { if(n==1) return true; if(n==2) return true; #if defined __AVX__ if(n==4) return true; #endif #if defined __AVX512F__ if(n==8) return true; #endif return false; } // split n = k+l such that k is the largest natively supported simd size < n constexpr int GetLargestNativeSIMDPart(int n) { int k = n-1; while(!IsNativeSIMDSize(k)) k--; return k; } constexpr size_t LargestPowerOfTwo (size_t x) { size_t y = 1; while (2*y <= x) y *= 2; return y; } template class SIMD; class mask64; //////////////////////////////////////////////////////////////////////////// namespace detail { template auto array_range_impl(std::array const& arr, size_t first, std::index_sequence) -> std::array { return {arr[first + I]...}; } template auto array_range(std::array const& arr, size_t first) { return array_range_impl(arr, first, std::make_index_sequence{}); } } // namespace detail //////////////////////////////////////////////////////////////////////////// // mask template <> class SIMD { int64_t mask; public: SIMD (int64_t i) : mask(i > 0 ? -1 : 0) { ; } bool Data() const { return mask; } static constexpr int Size() { return 1; } auto operator[] (int /* i */) const { return mask; } }; template class alignas(GetLargestNativeSIMDPart(N)*sizeof(int64_t)) SIMD { // static constexpr int N1 = GetLargestNativeSIMDPart(N); static constexpr size_t N1 = LargestPowerOfTwo(N-1); static constexpr int N2 = N-N1; SIMD lo; SIMD hi; public: SIMD (int64_t i) : lo(i), hi(i-N1 ) { ; } SIMD (SIMD lo_, SIMD hi_) : lo(lo_), hi(hi_) { ; } SIMD Lo() const { return lo; } SIMD Hi() const { return hi; } static constexpr int Size() { return N; } }; template NETGEN_INLINE SIMD operator&& (SIMD a, SIMD b) { if constexpr(N==1) return a.Data() && b.Data(); else return { a.Lo() && b.Lo(), a.Hi() && b.Hi() }; } //////////////////////////////////////////////////////////////////////////// // int32 template<> class SIMD { int32_t data; public: static constexpr int Size() { return 1; } SIMD () {} SIMD (const SIMD &) = default; SIMD & operator= (const SIMD &) = default; // SIMD (int val) : data{val} {} SIMD (int32_t val) : data{val} {} SIMD (size_t val) : data(val) {} explicit SIMD (std::array arr) : data{arr[0]} {} int32_t operator[] (int i) const { return ((int32_t*)(&data))[i]; } auto Data() const { return data; } static SIMD FirstInt(int32_t n0=0) { return {n0}; } template int32_t Get() { static_assert(I==0); return data; } }; template class alignas(GetLargestNativeSIMDPart(N)*sizeof(int64_t)) SIMD { // static constexpr int N1 = GetLargestNativeSIMDPart(N); static constexpr size_t N1 = LargestPowerOfTwo(N-1); static constexpr int N2 = N-N1; SIMD lo; SIMD high; public: static constexpr int Size() { return N; } SIMD () {} SIMD (const SIMD &) = default; SIMD & operator= (const SIMD &) = default; // SIMD (int val) : lo{val}, high{val} { ; } SIMD (int32_t val) : lo{val}, high{val} { ; } SIMD (size_t val) : lo{val}, high{val} { ; } SIMD (int32_t * p) : lo{p}, high{p+N1} { ; } SIMD (SIMD lo_, SIMD high_) : lo(lo_), high(high_) { ; } explicit SIMD( std::array arr ) : lo(detail::array_range(arr, 0)), high(detail::array_range(arr, N1)) {} template explicit SIMD(const T... vals) : lo(detail::array_range(std::array{vals...}, 0)), high(detail::array_range(std::array{vals...}, N1)) { static_assert(sizeof...(vals)==N, "wrong number of arguments"); } template>::value, int>::type = 0> SIMD (const T & func) { for(auto i : IntRange(N1)) lo[i] = func(i); for(auto i : IntRange(N2)) high[i] = func(N1+i); } auto Lo() const { return lo; } auto Hi() const { return high; } int32_t operator[] (int i) const { return ((int32_t*)(&lo))[i]; } void Store (int32_t * p) { lo.Store(p); high.Store(p+N1); } /* operator tuple () { return tuple((*this)[0], (*this)[1], (*this)[2], (*this)[3]); } */ /* static SIMD FirstInt() { return { 0, 1, 2, 3 }; } */ static SIMD FirstInt(int32_t n0=0) { return {SIMD::FirstInt(n0), SIMD::FirstInt(n0+N1)}; } template int32_t Get() { static_assert(I>=0 && I(); else return high.template Get(); } }; //////////////////////////////////////////////////////////////////////////// // int64 template<> class SIMD { int64_t data; public: static constexpr int Size() { return 1; } SIMD () {} SIMD (const SIMD &) = default; SIMD & operator= (const SIMD &) = default; SIMD (int val) : data{val} {} SIMD (int64_t val) : data{val} {} SIMD (size_t val) : data(val) {} explicit SIMD (std::array arr) : data{arr[0]} {} int64_t operator[] (int i) const { return ((int64_t*)(&data))[i]; } auto Data() const { return data; } static SIMD FirstInt(int64_t n0=0) { return {n0}; } template int64_t Get() { static_assert(I==0); return data; } }; template class alignas(GetLargestNativeSIMDPart(N)*sizeof(int64_t)) SIMD { // static constexpr int N1 = GetLargestNativeSIMDPart(N); static constexpr size_t N1 = LargestPowerOfTwo(N-1); static constexpr int N2 = N-N1; SIMD lo; SIMD high; public: static constexpr int Size() { return N; } SIMD () {} SIMD (const SIMD &) = default; SIMD & operator= (const SIMD &) = default; SIMD (int val) : lo{val}, high{val} { ; } SIMD (int64_t val) : lo{val}, high{val} { ; } SIMD (size_t val) : lo{val}, high{val} { ; } SIMD (SIMD lo_, SIMD high_) : lo(lo_), high(high_) { ; } explicit SIMD( std::array arr ) : lo(detail::array_range(arr, 0)), high(detail::array_range(arr, N1)) {} template explicit SIMD(const T... vals) : lo(detail::array_range(std::array{vals...}, 0)), high(detail::array_range(std::array{vals...}, N1)) { static_assert(sizeof...(vals)==N, "wrong number of arguments"); } template>::value, int>::type = 0> SIMD (const T & func) { for(auto i : IntRange(N1)) lo[i] = func(i); for(auto i : IntRange(N2)) high[i] = func(N1+i); } auto Lo() const { return lo; } auto Hi() const { return high; } int64_t operator[] (int i) const { return ((int64_t*)(&lo))[i]; } /* operator tuple () { return tuple((*this)[0], (*this)[1], (*this)[2], (*this)[3]); } */ /* static SIMD FirstInt() { return { 0, 1, 2, 3 }; } */ static SIMD FirstInt(int64_t n0=0) { return {SIMD::FirstInt(n0), SIMD::FirstInt(n0+N1)}; } template int64_t Get() { static_assert(I>=0 && I(); else return high.template Get(); } }; //////////////////////////////////////////////////////////////////////////// // double template<> class SIMD { double data; public: static constexpr int Size() { return 1; } SIMD () {} SIMD (const SIMD &) = default; SIMD & operator= (const SIMD &) = default; SIMD (double val) { data = val; } SIMD (int val) { data = val; } SIMD (size_t val) { data = val; } SIMD (double const * p) { data = *p; } SIMD (double const * p, SIMD mask) { data = mask.Data() ? *p : 0.0; } explicit SIMD (std::array arr) : data{arr[0]} {} template >::value,int>::type = 0> SIMD (const T & func) { data = func(0); } template >::value,int>::type = 0> SIMD & operator= (const T & func) { data = func(0); return *this; } void Store (double * p) { *p = data; } void Store (double * p, SIMD mask) { if (mask.Data()) *p = data; } double operator[] (int i) const { return ((double*)(&data))[i]; } double Data() const { return data; } template double Get() { static_assert(I==0); return data; } }; template class alignas(GetLargestNativeSIMDPart(N)*sizeof(double)) SIMD { // static constexpr int N1 = GetLargestNativeSIMDPart(N); static constexpr size_t N1 = LargestPowerOfTwo(N-1); static constexpr int N2 = N-N1; SIMD lo; SIMD high; public: static constexpr int Size() { return N; } SIMD () {} SIMD (const SIMD &) = default; SIMD (SIMD lo_, SIMD hi_) : lo(lo_), high(hi_) { ; } template >::value,int>::type = 0> SIMD (const T & func) { double *p = (double*)this; for(auto i : IntRange(N)) p[i] = func(i); } template >::value,int>::type = 0> SIMD & operator= (const T & func) { double *p = (double*)this; for(auto i : IntRange(N)) p[i] = func(i); return *this; } SIMD & operator= (const SIMD &) = default; SIMD (double val) : lo{val}, high{val} { ; } SIMD (int val) : lo{val}, high{val} { ; } SIMD (size_t val) : lo{val}, high{val} { ; } SIMD (double const * p) : lo{p}, high{p+N1} { ; } SIMD (double const * p, SIMD mask) : lo{p, mask.Lo()}, high{p+N1, mask.Hi()} { } SIMD (double * p) : lo{p}, high{p+N1} { ; } SIMD (double * p, SIMD mask) : lo{p, mask.Lo()}, high{p+N1, mask.Hi()} { } explicit SIMD( std::array arr ) : lo(detail::array_range(arr, 0)), high(detail::array_range(arr, N1)) {} template explicit SIMD(const T... vals) : lo(detail::array_range(std::array{vals...}, 0)), high(detail::array_range(std::array{vals...}, N1)) { static_assert(sizeof...(vals)==N, "wrong number of arguments"); } void Store (double * p) { lo.Store(p); high.Store(p+N1); } void Store (double * p, SIMD mask) { lo.Store(p, mask.Lo()); high.Store(p+N1, mask.Hi()); } NETGEN_INLINE auto Lo() const { return lo; } NETGEN_INLINE auto Hi() const { return high; } double operator[] (int i) const { return ((double*)(&lo))[i]; } template> operator std::tuple () { double *p = (double*)this; return std::tuple(p[0], p[1]); } template> operator std::tuple () { return std::tuple((*this)[0], (*this)[1], (*this)[2], (*this)[3]); } template double Get() { static_assert(I>=0 && I(); else return high.template Get(); } auto Data() const { return *this; } }; // Generic operators for any arithmetic type/simd width template NETGEN_INLINE SIMD operator+ (SIMD a, SIMD b) { if constexpr(N==1) return a.Data()+b.Data(); else return { a.Lo()+b.Lo(), a.Hi()+b.Hi() }; } template NETGEN_INLINE SIMD operator- (SIMD a, SIMD b) { if constexpr(N==1) return a.Data()-b.Data(); else return { a.Lo()-b.Lo(), a.Hi()-b.Hi() }; } template NETGEN_INLINE SIMD operator- (SIMD a) { if constexpr(N==1) return -a.Data(); else return { -a.Lo(), -a.Hi() }; } template NETGEN_INLINE SIMD operator* (SIMD a, SIMD b) { if constexpr(N==1) return a.Data()*b.Data(); else return { a.Lo()*b.Lo(), a.Hi()*b.Hi() }; } template NETGEN_INLINE SIMD operator/ (SIMD a, SIMD b) { if constexpr(N==1) return a.Data()/b.Data(); else return { a.Lo()/b.Lo(), a.Hi()/b.Hi() }; } template NETGEN_INLINE SIMD operator< (SIMD a, SIMD b) { if constexpr(N==1) return a.Data() < b.Data(); else return { a.Lo() NETGEN_INLINE SIMD operator<= (SIMD a, SIMD b) { if constexpr(N==1) return a.Data() <= b.Data(); else return { a.Lo()<=b.Lo(), a.Hi()<=b.Hi() }; } template NETGEN_INLINE SIMD operator> (SIMD a, SIMD b) { if constexpr(N==1) return a.Data() > b.Data(); else return { a.Lo()>b.Lo(), a.Hi()>b.Hi() }; } template NETGEN_INLINE SIMD operator>= (SIMD a, SIMD b) { if constexpr(N==1) return a.Data() >= b.Data(); else return { a.Lo()>=b.Lo(), a.Hi()>=b.Hi() }; } template NETGEN_INLINE SIMD operator== (SIMD a, SIMD b) { if constexpr(N==1) return a.Data() == b.Data(); else return { a.Lo()==b.Lo(), a.Hi()==b.Hi() }; } template NETGEN_INLINE SIMD operator!= (SIMD a, SIMD b) { if constexpr(N==1) return a.Data() != b.Data(); else return { a.Lo()!=b.Lo(), a.Hi()!=b.Hi() }; } template NETGEN_INLINE SIMD operator& (SIMD a, SIMD b) { if constexpr(N==1) return a.Data() & b.Data(); else return { (a.Lo()&b.Lo()), (a.Hi()&b.Hi()) }; } template NETGEN_INLINE SIMD operator| (SIMD a, SIMD b) { if constexpr(N==1) return a.Data() & b.Data(); else return { (a.Lo()|b.Lo()), (a.Hi()|b.Hi()) }; } // int64_t operators with scalar operand (implement overloads to allow implicit casts for second operand) template NETGEN_INLINE SIMD operator+ (SIMD a, int64_t b) { return a+SIMD(b); } template NETGEN_INLINE SIMD operator+ (int64_t a, SIMD b) { return SIMD(a)+b; } template NETGEN_INLINE SIMD operator- (int64_t a, SIMD b) { return SIMD(a)-b; } template NETGEN_INLINE SIMD operator- (SIMD a, int64_t b) { return a-SIMD(b); } template NETGEN_INLINE SIMD operator* (int64_t a, SIMD b) { return SIMD(a)*b; } template NETGEN_INLINE SIMD operator* (SIMD b, int64_t a) { return SIMD(a)*b; } template NETGEN_INLINE SIMD operator/ (SIMD a, int64_t b) { return a/SIMD(b); } template NETGEN_INLINE SIMD operator/ (int64_t a, SIMD b) { return SIMD(a)/b; } template NETGEN_INLINE SIMD & operator+= (SIMD & a, SIMD b) { a=a+b; return a; } template NETGEN_INLINE SIMD & operator+= (SIMD & a, int64_t b) { a+=SIMD(b); return a; } template NETGEN_INLINE SIMD & operator-= (SIMD & a, SIMD b) { a = a-b; return a; } template NETGEN_INLINE SIMD & operator-= (SIMD & a, int64_t b) { a-=SIMD(b); return a; } template NETGEN_INLINE SIMD & operator*= (SIMD & a, SIMD b) { a=a*b; return a; } template NETGEN_INLINE SIMD & operator*= (SIMD & a, int64_t b) { a*=SIMD(b); return a; } template NETGEN_INLINE SIMD & operator/= (SIMD & a, SIMD b) { a = a/b; return a; } // double operators with scalar operand (implement overloads to allow implicit casts for second operand) template NETGEN_INLINE SIMD operator+ (SIMD a, double b) { return a+SIMD(b); } template NETGEN_INLINE SIMD operator+ (double a, SIMD b) { return SIMD(a)+b; } template NETGEN_INLINE SIMD operator- (double a, SIMD b) { return SIMD(a)-b; } template NETGEN_INLINE SIMD operator- (SIMD a, double b) { return a-SIMD(b); } template NETGEN_INLINE SIMD operator* (double a, SIMD b) { return SIMD(a)*b; } template NETGEN_INLINE SIMD operator* (SIMD b, double a) { return SIMD(a)*b; } template NETGEN_INLINE SIMD operator/ (SIMD a, double b) { return a/SIMD(b); } template NETGEN_INLINE SIMD operator/ (double a, SIMD b) { return SIMD(a)/b; } template NETGEN_INLINE SIMD & operator+= (SIMD & a, SIMD b) { a=a+b; return a; } template NETGEN_INLINE SIMD & operator+= (SIMD & a, double b) { a+=SIMD(b); return a; } template NETGEN_INLINE SIMD & operator-= (SIMD & a, SIMD b) { a = a-b; return a; } template NETGEN_INLINE SIMD & operator-= (SIMD & a, double b) { a-=SIMD(b); return a; } template NETGEN_INLINE SIMD & operator*= (SIMD & a, SIMD b) { a=a*b; return a; } template NETGEN_INLINE SIMD & operator*= (SIMD & a, double b) { a*=SIMD(b); return a; } template NETGEN_INLINE SIMD & operator/= (SIMD & a, SIMD b) { a = a/b; return a; } template NETGEN_INLINE auto operator> (SIMD & a, double b) { return a > SIMD(b); } // double functions template NETGEN_INLINE SIMD L2Norm2 (SIMD a) { return a*a; } template NETGEN_INLINE SIMD Trans (SIMD a) { return a; } template NETGEN_INLINE double HSum (SIMD a) { if constexpr(N==1) return a.Data(); else return HSum(a.Lo()) + HSum(a.Hi()); } template NETGEN_INLINE SIMD IfPos (SIMD a, SIMD b, SIMD c) { if constexpr(N==1) return a.Data()>0.0 ? b : c; else return { IfPos(a.Lo(), b.Lo(), c.Lo()), IfPos(a.Hi(), b.Hi(), c.Hi())}; } template NETGEN_INLINE SIMD IfZero (SIMD a, SIMD b, SIMD c) { if constexpr(N==1) return a.Data()==0.0 ? b : c; else return { IfZero(a.Lo(), b.Lo(), c.Lo()), IfZero(a.Hi(), b.Hi(), c.Hi())}; } template NETGEN_INLINE SIMD If (SIMD a, SIMD b, SIMD c) { if constexpr(N==1) return a.Data() ? b : c; else return { If(a.Lo(), b.Lo(), c.Lo()), If(a.Hi(), b.Hi(), c.Hi())}; } // a*b+c template NETGEN_INLINE auto FMA(T1 a, T2 b, T3 c) { return c+a*b; } template NETGEN_INLINE auto FNMA(T1 a, T2 b, T3 c) { return c-a*b; } // update form of fma template void FMAasm (SIMD a, SIMD b, SIMD & sum) { sum = FMA(a,b,sum); } // update form of fms template void FNMAasm (SIMD a, SIMD b, SIMD & sum) { // sum -= a*b; sum = FNMA(a,b,sum); } // c += a*b (a0re, a0im, a1re, a1im, ...), template void FMAComplex (SIMD a, SIMD b, SIMD & c) { auto [are, aim] = Unpack(a, a); SIMD bswap = SwapPairs(b); SIMD aim_bswap = aim*bswap; c += FMAddSub (are, b, aim_bswap); } template T get(SIMD a) { return a.template Get(); } template NETGEN_INLINE void Iterate2 (FUNC f) { if constexpr (NUM > 1) Iterate2 (f); if constexpr (NUM >= 1) f(std::integral_constant()); } template T2 BitCast(T1 a) { T2 result; static_assert(sizeof(T1) == sizeof(T2), "BitCast requires same size"); memcpy(&result, &a, sizeof(T1)); return result; } template SIMD Reinterpret (SIMD a) { if constexpr (N == 1) return SIMD ( * (T*)(void*) & a.Data()); else if constexpr (N == 2) return SIMD { BitCast (a.Lo()), BitCast (a.Hi()) }; else return SIMD (Reinterpret (a.Lo()), Reinterpret (a.Hi())); } using std::round; template SIMD round (SIMD x) { if constexpr (N == 1) return round(x); else return { round(x.Lo()), round(x.Hi()) }; } // NETGEN_INLINE int64_t RoundI (double x) { return lround(x); } using std::lround; template SIMD lround (SIMD x) { if constexpr (N == 1) return SIMD (lround(x)); else return { lround(x.Lo()), lround(x.Hi()) }; } /* reciprocal square root Quake III algorithm, or intrinsics */ // #ifndef __CUDACC__ NETGEN_INLINE double rsqrt (double x) { return 1.0/sqrt(x); } #endif template SIMD rsqrt (SIMD x) { if constexpr (N == 1) return 1.0/sqrt(x.Data()); else return { rsqrt(x.Lo()), rsqrt(x.Hi()) }; } template int64_t operator<< (int64_t a, IC n) { return a << n.value; } template SIMD operator<< (SIMD a, IC n) { if constexpr (S == 1) return SIMD (a.Data() << n); else return SIMD (a.Lo() << n, a.Hi() << n); } template auto Min (SIMD a, SIMD b) { if constexpr (N==1) return SIMD (std::min(a[0], b[0])); else return SIMD (Min(a.Lo(), b.Lo()), Min(a.Hi(), b.Hi())); } template auto Max (SIMD a, SIMD b) { if constexpr (N==1) return SIMD (std::max(a[0], b[0])); else return SIMD (Max(a.Lo(), b.Lo()), Max(a.Hi(), b.Hi())); } template ostream & operator<< (ostream & ost, SIMD simd) { /* ost << simd[0]; for (int i = 1; i < simd.Size(); i++) ost << " " << simd[i]; */ Iterate2 ([&] (auto I) { if (I.value != 0) ost << " "; ost << get(simd); }); return ost; } using std::sqrt; template NETGEN_INLINE ngcore::SIMD sqrt (ngcore::SIMD a) { if constexpr (N == 1) return sqrt(a.Data()); else return { sqrt(a.Lo()), sqrt(a.Hi()) }; // return ngcore::SIMD([a](int i)->double { return sqrt(a[i]); } ); } using std::fabs; template NETGEN_INLINE ngcore::SIMD fabs (ngcore::SIMD a) { return ngcore::SIMD([a](int i)->double { return fabs(a[i]); } ); } using std::floor; template NETGEN_INLINE ngcore::SIMD floor (ngcore::SIMD a) { return ngcore::SIMD([a](int i)->double { return floor(a[i]); } ); } using std::ceil; template NETGEN_INLINE ngcore::SIMD ceil (ngcore::SIMD a) { return ngcore::SIMD([a](int i)->double { return ceil(a[i]); } ); } using std::exp; template NETGEN_INLINE ngcore::SIMD exp (ngcore::SIMD a) { return ngcore::SIMD([a](int i)->double { return exp(a[i]); } ); } using std::log; template NETGEN_INLINE ngcore::SIMD log (ngcore::SIMD a) { return ngcore::SIMD([a](int i)->double { return log(a[i]); } ); } using std::erf; template NETGEN_INLINE ngcore::SIMD erf (ngcore::SIMD a) { return ngcore::SIMD([a](int i)->double { return erf(a[i]); } ); } using std::pow; template NETGEN_INLINE ngcore::SIMD pow (ngcore::SIMD a, double x) { return ngcore::SIMD([a,x](int i)->double { return pow(a[i],x); } ); } template NETGEN_INLINE ngcore::SIMD pow (ngcore::SIMD a, ngcore::SIMD b) { return ngcore::SIMD([a,b](int i)->double { return pow(a[i],b[i]); } ); } using std::sin; template NETGEN_INLINE ngcore::SIMD sin (ngcore::SIMD a) { return ngcore::SIMD([a](int i)->double { return sin(a[i]); } ); } using std::cos; template NETGEN_INLINE ngcore::SIMD cos (ngcore::SIMD a) { return ngcore::SIMD([a](int i)->double { return cos(a[i]); } ); } using std::tan; template NETGEN_INLINE ngcore::SIMD tan (ngcore::SIMD a) { return ngcore::SIMD([a](int i)->double { return tan(a[i]); } ); } using std::atan; template NETGEN_INLINE ngcore::SIMD atan (ngcore::SIMD a) { return ngcore::SIMD([a](int i)->double { return atan(a[i]); } ); } using std::atan2; template NETGEN_INLINE ngcore::SIMD atan2 (ngcore::SIMD y, ngcore::SIMD x) { return ngcore::SIMD([y,x](int i)->double { return atan2(y[i], x[i]); } ); } using std::acos; template NETGEN_INLINE ngcore::SIMD acos (ngcore::SIMD a) { return ngcore::SIMD([a](int i)->double { return acos(a[i]); } ); } using std::asin; template NETGEN_INLINE ngcore::SIMD asin (ngcore::SIMD a) { return ngcore::SIMD([a](int i)->double { return asin(a[i]); } ); } using std::sinh; template NETGEN_INLINE ngcore::SIMD sinh (ngcore::SIMD a) { return ngcore::SIMD([a](int i)->double { return sinh(a[i]); } ); } using std::cosh; template NETGEN_INLINE ngcore::SIMD cosh (ngcore::SIMD a) { return ngcore::SIMD([a](int i)->double { return cosh(a[i]); } ); } using std::asinh; template NETGEN_INLINE ngcore::SIMD asinh (ngcore::SIMD a) { return ngcore::SIMD([a](int i)->double { return asinh(a[i]); } ); } using std::acosh; template NETGEN_INLINE ngcore::SIMD acosh (ngcore::SIMD a) { return ngcore::SIMD([a](int i)->double { return acosh(a[i]); } ); } template using MultiSIMD = SIMD; template NETGEN_INLINE auto Unpack (SIMD a, SIMD b) { if constexpr(N==1) { return std::make_tuple(SIMD{a.Data()}, SIMD{b.Data()} ); } else if constexpr(N==2) { return std::make_tuple(SIMD{ a.Lo(), b.Lo() }, SIMD{ a.Hi(), b.Hi() }); } else { auto [a1,b1] = Unpack(a.Lo(), b.Lo()); auto [a2,b2] = Unpack(a.Hi(), b.Hi()); return std::make_tuple(SIMD{ a1, a2 }, SIMD{ b1, b2 }); } } // TODO: specialize for AVX, ... template NETGEN_INLINE auto SwapPairs (SIMD a) { if constexpr(N==1) { // static_assert(false); return a; } else if constexpr(N==2) { return SIMD (a.Hi(), a.Lo()); } else { return SIMD (SwapPairs(a.Lo()), SwapPairs(a.Hi())); } } template NETGEN_INLINE auto HSum128 (SIMD a) { if constexpr(N==1) { // static_assert(false); return a; } else if constexpr(N==2) { return a; } else { return HSum128(a.Lo()) + HSum128(a.Hi()); } } // TODO: specialize for AVX, ... // a*b+-c (even: -, odd: +) template NETGEN_INLINE auto FMAddSub (SIMD a, SIMD b, SIMD c) { if constexpr(N==1) { // static_assert(false); return a*b-c; } else if constexpr(N==2) { return SIMD (a.Lo()*b.Lo()-c.Lo(), a.Hi()*b.Hi()+c.Hi()); } else { return SIMD (FMAddSub(a.Lo(), b.Lo(), c.Lo()), FMAddSub(a.Hi(), b.Hi(), c.Hi())); } } template auto subtuple (const Tuple& tup, std::index_sequence) { return std::make_tuple(std::get(tup)...); } template auto Concat (std::tuple, Args...> tup) { constexpr size_t N = std::tuple_size, Args...>>(); if constexpr (N == 1) return get<0>(tup); else { static constexpr size_t N1 = LargestPowerOfTwo(N-1); static constexpr int N2 = N-N1; auto SEQ1 = std::make_index_sequence(); auto sub1 = subtuple<0>(tup, SEQ1); auto SEQ2 = std::make_index_sequence(); auto sub2 = subtuple(tup, SEQ2); auto S1 = Concat(sub1); auto S2 = Concat(sub2); return SIMD(S1, S2); } } } namespace std { // structured binding support template struct tuple_size> : std::integral_constant {}; template struct tuple_element> { using type = T; }; } #endif // NETGEN_CORE_SIMD_GENERIC_HPP ================================================ FILE: libsrc/core/simd_math.hpp ================================================ #ifndef NETGEN_CORE_SIMD_MATH_HPP #define NETGEN_CORE_SIMD_MATH_HPP #include #ifndef M_PI #define M_PI 3.14159265358979323846 #endif namespace ngcore { /* based on: Stephen L. Moshier: Methods and Programs For Mathematical Functions https://www.moshier.net/methprog.pdf CEPHES MATHEMATICAL FUNCTION LIBRARY https://www.netlib.org/cephes/ */ static constexpr double sincof[] = { 1.58962301576546568060E-10, -2.50507477628578072866E-8, 2.75573136213857245213E-6, -1.98412698295895385996E-4, 8.33333333332211858878E-3, -1.66666666666666307295E-1, }; static constexpr double coscof[6] = { -1.13585365213876817300E-11, 2.08757008419747316778E-9, -2.75573141792967388112E-7, 2.48015872888517045348E-5, -1.38888888888730564116E-3, 4.16666666666665929218E-2, }; // highly accurate on [-pi/4, pi/4] template auto sincos_reduced (SIMD x) { auto x2 = x*x; auto s = ((((( sincof[0]*x2 + sincof[1]) * x2 + sincof[2]) * x2 + sincof[3]) * x2 + sincof[4]) * x2 + sincof[5]); s = x + x*x*x * s; auto c = ((((( coscof[0]*x2 + coscof[1]) * x2 + coscof[2]) * x2 + coscof[3]) * x2 + coscof[4]) * x2 + coscof[5]); c = 1.0 - 0.5*x2 + x2*x2*c; return std::tuple{ s, c }; } template auto sincos (SIMD x) { auto y = round((2/M_PI) * x); auto q = lround(y); auto [s1,c1] = sincos_reduced(x - y * (M_PI/2)); auto s2 = If((q & SIMD(1)) == SIMD(0), s1, c1); auto s = If((q & SIMD(2)) == SIMD(0), s2, -s2); auto c2 = If((q & SIMD(1)) == SIMD(0), c1, -s1); auto c = If((q & SIMD(2)) == SIMD(0), c2, -c2); return std::tuple{ s, c }; } template SIMD exp_reduced (SIMD x) { static constexpr double P[] = { 1.26177193074810590878E-4, 3.02994407707441961300E-2, 9.99999999999999999910E-1, }; static constexpr double Q[] = { 3.00198505138664455042E-6, 2.52448340349684104192E-3, 2.27265548208155028766E-1, 2.00000000000000000009E0, }; /* // from: https://www.netlib.org/cephes/ rational approximation for exponential * of the fractional part: * e**x = 1 + 2x P(x**2)/( Q(x**2) - x P(x**2) ) xx = x * x; px = x * polevl( xx, P, 2 ); x = px/( polevl( xx, Q, 3 ) - px ); x = 1.0 + 2.0 * x; */ auto xx = x*x; auto px = (P[0]*xx + P[1]) * xx + P[2]; auto qx = ((Q[0]*xx+Q[1])*xx+Q[2])*xx+Q[3]; return 1.0 + 2.0*x * px / (qx- x * px); } template SIMD pow2_int64_to_float64(SIMD n) { // thx to deepseek // Step 1: Clamp the input to valid exponent range [-1022, 1023] // (We use saturated operations to handle out-of-range values) SIMD max_exp(1023); SIMD min_exp(-1022); n = If(n > max_exp, max_exp, n); n = If(min_exp > n, min_exp, n); // Step 2: Add exponent bias (1023) n = n + SIMD(1023); // Step 3: Shift to exponent bit position (bit 52) auto shifted_exp = (n << IC<52>()); // Step 4: Reinterpret as double return Reinterpret (shifted_exp); } template SIMD myexp (SIMD x) { constexpr double log2 = 0.693147180559945286; // log(2.0); auto r = round(1/log2 * x); auto rI = lround(r); r *= log2; SIMD pow2 = pow2_int64_to_float64 (rI); return exp_reduced(x-r) * pow2; // maybe better: // x = ldexp( x, n ); } /* inline auto Test1 (SIMD x) { return myexp(x); } inline auto Test2 (SIMD x) { return sincos(x); } inline auto Test3 (SIMD x) { return myexp(x); } inline auto Test4 (SIMD x) { return sincos(x); } */ } #endif ================================================ FILE: libsrc/core/simd_sse.hpp ================================================ #ifndef NETGEN_CORE_SIMD_SSE_HPP #define NETGEN_CORE_SIMD_SSE_HPP /**************************************************************************/ /* File: simd_sse.hpp */ /* Author: Joachim Schoeberl, Matthias Hochsteger */ /* Date: 25. Mar. 16 */ /**************************************************************************/ #include namespace ngcore { template <> class SIMD { __m128i mask; public: SIMD (int i) : mask(_mm_cmpgt_epi32(_mm_set1_epi32(i), _mm_set_epi32(1, 1, 0, 0))) { ; } SIMD (bool i0, bool i1) { mask = _mm_set_epi64x(i1?-1:0, i0?-1:0); } SIMD (__m128i _mask) : mask(_mask) { ; } __m128i Data() const { return mask; } static constexpr int Size() { return 2; } static NETGEN_INLINE SIMD GetMaskFromBits (unsigned int i); }; static SIMD masks_from_2bits[4] = { _mm_set_epi32 (0,0,0,0), _mm_set_epi32 (0,0,-1,0), _mm_set_epi32 (-1,0,0,0), _mm_set_epi32 (-1,0,-1,0), }; NETGEN_INLINE SIMD SIMD :: GetMaskFromBits (unsigned int i) { return masks_from_2bits[i & 3]; } template<> class alignas(16) SIMD { __m128i data; public: static constexpr int Size() { return 2; } SIMD () {} SIMD (const SIMD &) = default; SIMD (int64_t v0, int64_t v1) { data = _mm_set_epi64x(v1,v0); } SIMD (std::array arr) : data{_mm_set_epi64x(arr[1],arr[0])} {} SIMD & operator= (const SIMD &) = default; SIMD (int64_t val) { data = _mm_set1_epi64x(val); } SIMD (__m128i _data) { data = _data; } template>::value, int>::type = 0> SIMD (const T & func) { data = _mm_set_epi64(func(1), func(0)); } NETGEN_INLINE auto operator[] (int i) const { return ((int64_t*)(&data))[i]; } NETGEN_INLINE __m128i Data() const { return data; } NETGEN_INLINE __m128i & Data() { return data; } // NETGEN_INLINE int64_t Lo() const { return _mm_extract_epi64(data, 0); } // NETGEN_INLINE int64_t Hi() const { return _mm_extract_epi64(data, 1); } NETGEN_INLINE int64_t Lo() const { return ((int64_t*)(&data))[0]; } NETGEN_INLINE int64_t Hi() const { return ((int64_t*)(&data))[1]; } static SIMD FirstInt(int n0=0) { return { n0, n0+1 }; } }; NETGEN_INLINE SIMD operator-(SIMD a) { return _mm_sub_epi64(_mm_setzero_si128(), a.Data()); } NETGEN_INLINE SIMD operator+ (SIMD a, SIMD b) { return _mm_add_epi64(a.Data(),b.Data()); } NETGEN_INLINE SIMD operator- (SIMD a, SIMD b) { return _mm_sub_epi64(a.Data(),b.Data()); } template<> class alignas(16) SIMD { __m128d data; public: static constexpr int Size() { return 2; } SIMD () {} SIMD (const SIMD &) = default; SIMD (double v0, double v1) { data = _mm_set_pd(v1,v0); } SIMD (SIMD v0, SIMD v1) : data{_mm_set_pd(v0.Data(), v1.Data())} { } SIMD (std::array arr) : data{_mm_set_pd(arr[1], arr[0])} {} SIMD & operator= (const SIMD &) = default; SIMD (double val) { data = _mm_set1_pd(val); } SIMD (int val) { data = _mm_set1_pd(val); } SIMD (size_t val) { data = _mm_set1_pd(val); } SIMD (double const * p) { data = _mm_loadu_pd(p); } SIMD (double const * p, SIMD mask) { #ifdef __AVX__ data = _mm_maskload_pd(p, mask.Data()); #else // this versions segfaults if p points to the last allowed element // happened on Mac with the new SparseCholesky-factorization // data = _mm_and_pd(_mm_castsi128_pd(mask.Data()), _mm_loadu_pd(p)); auto pmask = (int64_t*)&mask; data = _mm_set_pd (pmask[1] ? p[1] : 0.0, pmask[0] ? p[0] : 0.0); #endif } SIMD (__m128d _data) { data = _data; } void Store (double * p) { _mm_storeu_pd(p, data); } void Store (double * p, SIMD mask) { #ifdef __AVX__ _mm_maskstore_pd(p, mask.Data(), data); #else /* _mm_storeu_pd (p, _mm_or_pd (_mm_and_pd(_mm_castsi128_pd(mask.Data()), data), _mm_andnot_pd(_mm_castsi128_pd(mask.Data()), _mm_loadu_pd(p)))); */ auto pmask = (int64_t*)&mask; if (pmask[0]) p[0] = (*this)[0]; if (pmask[1]) p[1] = (*this)[1]; #endif } template>::value, int>::type = 0> SIMD (const T & func) { data = _mm_set_pd(func(1), func(0)); } NETGEN_INLINE double operator[] (int i) const { return ((double*)(&data))[i]; } NETGEN_INLINE __m128d Data() const { return data; } NETGEN_INLINE __m128d & Data() { return data; } template double Get() const { static_assert(I>=0 && I<2, "Index out of range"); return (*this)[I]; } double Lo() const { return Get<0>(); } double Hi() const { return Get<1>(); } operator std::tuple () { auto pdata = (double*)&data; return std::tuple(pdata[0], pdata[1]); } }; NETGEN_INLINE SIMD operator- (SIMD a) { return _mm_xor_pd(a.Data(), _mm_set1_pd(-0.0)); } NETGEN_INLINE SIMD operator+ (SIMD a, SIMD b) { return _mm_add_pd(a.Data(),b.Data()); } NETGEN_INLINE SIMD operator- (SIMD a, SIMD b) { return _mm_sub_pd(a.Data(),b.Data()); } NETGEN_INLINE SIMD operator* (SIMD a, SIMD b) { return _mm_mul_pd(a.Data(),b.Data()); } NETGEN_INLINE SIMD operator/ (SIMD a, SIMD b) { return _mm_div_pd(a.Data(),b.Data()); } NETGEN_INLINE SIMD operator* (double a, SIMD b) { return _mm_set1_pd(a)*b; } NETGEN_INLINE SIMD operator* (SIMD b, double a) { return _mm_set1_pd(a)*b; } template<> NETGEN_INLINE auto Unpack (SIMD a, SIMD b) { return std::make_tuple(SIMD(_mm_unpacklo_pd(a.Data(),b.Data())), SIMD(_mm_unpackhi_pd(a.Data(),b.Data()))); } NETGEN_INLINE __m128d my_mm_hadd_pd(__m128d a, __m128d b) { #if defined(__SSE3__) || defined(__AVX__) return _mm_hadd_pd(a,b); #else return _mm_add_pd( _mm_unpacklo_pd(a,b), _mm_unpackhi_pd(a,b) ); #endif } #ifndef __AVX__ NETGEN_INLINE __m128i my_mm_cmpgt_epi64(__m128i a, __m128i b) { auto res_lo = _mm_cvtsi128_si64(a) > _mm_cvtsi128_si64(b) ? -1:0; auto res_hi = _mm_cvtsi128_si64(_mm_srli_si128(a,8)) > _mm_cvtsi128_si64(_mm_srli_si128(b,8)) ? -1 : 0; return _mm_set_epi64x(res_hi,res_lo); } #else NETGEN_INLINE __m128i my_mm_cmpgt_epi64(__m128i a, __m128i b) { return _mm_cmpgt_epi64(a,b); } #endif NETGEN_INLINE SIMD sqrt (SIMD a) { return _mm_sqrt_pd(a.Data()); } NETGEN_INLINE SIMD fabs (SIMD a) { return _mm_max_pd(a.Data(), (-a).Data()); } using std::floor; NETGEN_INLINE SIMD floor (SIMD a) { return ngcore::SIMD([&](int i)->double { return floor(a[i]); } ); } using std::ceil; NETGEN_INLINE SIMD ceil (SIMD a) { return ngcore::SIMD([&](int i)->double { return ceil(a[i]); } ); } NETGEN_INLINE SIMD operator<= (SIMD a , SIMD b) { return _mm_castpd_si128( _mm_cmple_pd(a.Data(),b.Data())); } NETGEN_INLINE SIMD operator< (SIMD a , SIMD b) { return _mm_castpd_si128( _mm_cmplt_pd(a.Data(),b.Data())); } NETGEN_INLINE SIMD operator>= (SIMD a , SIMD b) { return _mm_castpd_si128( _mm_cmpge_pd(a.Data(),b.Data())); } NETGEN_INLINE SIMD operator> (SIMD a , SIMD b) { return _mm_castpd_si128( _mm_cmpgt_pd(a.Data(),b.Data())); } NETGEN_INLINE SIMD operator== (SIMD a , SIMD b) { return _mm_castpd_si128( _mm_cmpeq_pd(a.Data(),b.Data())); } NETGEN_INLINE SIMD operator!= (SIMD a , SIMD b) { return _mm_castpd_si128( _mm_cmpneq_pd(a.Data(),b.Data())); } #ifdef __SSE4_2__ NETGEN_INLINE SIMD operator<= (SIMD a , SIMD b) { return _mm_xor_si128(_mm_cmpgt_epi64(a.Data(),b.Data()),_mm_set1_epi32(-1)); } NETGEN_INLINE SIMD operator< (SIMD a , SIMD b) { return my_mm_cmpgt_epi64(b.Data(),a.Data()); } NETGEN_INLINE SIMD operator>= (SIMD a , SIMD b) { return _mm_xor_si128(_mm_cmpgt_epi64(b.Data(),a.Data()),_mm_set1_epi32(-1)); } NETGEN_INLINE SIMD operator> (SIMD a , SIMD b) { return my_mm_cmpgt_epi64(a.Data(),b.Data()); } #endif #ifdef __SSE4_1__ NETGEN_INLINE SIMD operator== (SIMD a , SIMD b) { return _mm_cmpeq_epi64(a.Data(),b.Data()); } NETGEN_INLINE SIMD operator!= (SIMD a , SIMD b) { return _mm_xor_si128(_mm_cmpeq_epi64(a.Data(),b.Data()),_mm_set1_epi32(-1)); } #endif NETGEN_INLINE SIMD operator&& (SIMD a, SIMD b) { return _mm_castpd_si128(_mm_and_pd (_mm_castsi128_pd(a.Data()),_mm_castsi128_pd( b.Data()))); } NETGEN_INLINE SIMD operator|| (SIMD a, SIMD b) { return _mm_castpd_si128(_mm_or_pd (_mm_castsi128_pd(a.Data()), _mm_castsi128_pd(b.Data()))); } NETGEN_INLINE SIMD operator! (SIMD a) { return _mm_castpd_si128(_mm_xor_pd (_mm_castsi128_pd(a.Data()),_mm_castsi128_pd( _mm_cmpeq_epi64(a.Data(),a.Data())))); } #ifdef __SSE4_1__ NETGEN_INLINE SIMD If (SIMD a, SIMD b, SIMD c) { return _mm_blendv_pd(c.Data(), b.Data(), _mm_castsi128_pd(a.Data())); } #else NETGEN_INLINE SIMD If (SIMD a, SIMD b, SIMD c) { return _mm_or_pd( _mm_andnot_pd(_mm_castsi128_pd(a.Data()),c.Data()), _mm_and_pd(b.Data(),_mm_castsi128_pd(a.Data())) );} #endif // __SSE4_1__ NETGEN_INLINE SIMD IfPos (SIMD a, SIMD b, SIMD c) { return ngcore::SIMD([&](int i)->double { return a[i]>0 ? b[i] : c[i]; }); } NETGEN_INLINE SIMD IfZero (SIMD a, SIMD b, SIMD c) { return ngcore::SIMD([&](int i)->double { return a[i]==0. ? b[i] : c[i]; }); } NETGEN_INLINE double HSum (SIMD sd) { return _mm_cvtsd_f64 (my_mm_hadd_pd (sd.Data(), sd.Data())); } NETGEN_INLINE auto HSum (SIMD sd1, SIMD sd2) { __m128d hv2 = my_mm_hadd_pd(sd1.Data(), sd2.Data()); return SIMD (hv2); // return SIMD(_mm_cvtsd_f64 (hv2), _mm_cvtsd_f64(_mm_shuffle_pd (hv2, hv2, 3))); } NETGEN_INLINE SIMD If(SIMD a, SIMD b, SIMD c) { return _mm_or_si128( _mm_andnot_si128(a.Data(),c.Data()), _mm_and_si128(b.Data(),a.Data()) ); } } #endif // NETGEN_CORE_SIMD_SSE_HPP ================================================ FILE: libsrc/core/statushandler.cpp ================================================ #include "array.hpp" #include "statushandler.hpp" namespace ngcore { volatile multithreadt multithread; multithreadt :: multithreadt() { pause =0; testmode = 0; redraw = 0; drawing = 0; terminate = 0; running = 0; percent = 0; task = ""; } static Array msgstatus_stack(0); static Array threadpercent_stack(0); static std::string 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 std::string& s) { msgstatus_stack.Append(s); SetStatMsg(s); threadpercent_stack.Append(0); } void PopStatus() { if (msgstatus_stack.Size()) { if (msgstatus_stack.Size() > 1) // SetStatMsg (*msgstatus_stack.Last()); SetStatMsg (msgstatus_stack[msgstatus_stack.Size()-2]); 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 std::string& 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(std::string & 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"; } } ================================================ FILE: libsrc/core/statushandler.hpp ================================================ #ifndef NETGEN_CORE_STATUSHANDLER #define NETGEN_CORE_STATUSHANDLER #include #include "utils.hpp" namespace ngcore { class NGCORE_API multithreadt { public: int pause; int testmode; int redraw; int drawing; int terminate; int running; double percent; const char * task; bool demorunning; std::string * tcl_todo = new std::string(""); // tcl commands set from parallel thread multithreadt(); }; NGCORE_API extern volatile multithreadt multithread; extern NGCORE_API void SetStatMsg(const std::string& s); extern NGCORE_API void PushStatus(const std::string& s); extern NGCORE_API void PushStatusF(const std::string& s); extern NGCORE_API void PopStatus(); extern NGCORE_API void SetThreadPercent(double percent); extern NGCORE_API void GetStatus(std::string & s, double & percentage); } #endif ================================================ FILE: libsrc/core/symboltable.hpp ================================================ #ifndef NETGEN_CORE_SYMBOLTABLE_HPP #define NETGEN_CORE_SYMBOLTABLE_HPP #include #include #include #include "exception.hpp" #include "ngcore_api.hpp" namespace ngcore { /** A symbol table. The symboltable provides a mapping from string identifiers to the generic type T. The strings are copied. Complexity by name access is linear, by index is constant. */ template class SymbolTable { std::vector names; std::vector data; public: using value_type = T; using reference = typename std::vector::reference; using const_reference = typename std::vector::const_reference; /// Creates a symboltable SymbolTable () = default; SymbolTable (const SymbolTable &) = default; SymbolTable (SymbolTable &&) noexcept = default; ~SymbolTable() = default; SymbolTable& operator=(const SymbolTable&) = default; SymbolTable& operator=(SymbolTable&&) = default; template auto DoArchive(ARCHIVE& ar) -> typename std::enable_if_t, void> { ar & names & data; } /// INDEX of symbol name, throws exception if unused size_t Index (std::string_view name) const { for (size_t i = 0; i < names.size(); i++) if (names[i] == name) return i; throw RangeException("SymbolTable", name); } /// Index of symbol name, returns -1 if unused int CheckIndex (std::string_view name) const { for (int i = 0; i < names.size(); i++) if (names[i] == name) return i; return -1; } /// number of identifiers size_t Size() const { return data.size(); } /// Returns reference to element. exception for unused identifier reference operator[] (std::string_view name) { return data[Index (name)]; } const_reference operator[] (std::string_view name) const { return data[Index (name)]; } /// Returns reference to i-th element, range check only in debug build reference operator[] (size_t i) { NETGEN_CHECK_RANGE(i, 0, data.size()); return data[i]; } /// Returns const reference to i-th element, range check only in debug build const_reference operator[] (size_t i) const { NETGEN_CHECK_RANGE(i, 0, data.size()); return data[i]; } /// Returns name of i-th element, range check only in debug build const std::string & GetName (size_t i) const { NETGEN_CHECK_RANGE(i, 0, names.size()); return names[i]; } /// Associates el to the string name, overrides if name is used void Set (std::string_view name, const T & el) { int i = CheckIndex (name); if (i >= 0) data[i] = el; else { data.push_back(el); names.push_back(std::string(name)); } } /* bool Used (const std::string & name) const { return CheckIndex(name) >= 0; } */ bool Used (std::string_view name) const { return CheckIndex(name) >= 0; } /// Deletes symboltable inline void DeleteAll () { names.clear(); data.clear(); } // Adds all elements from other symboltable SymbolTable& Update(const SymbolTable& tbl2) { for (size_t i = 0; i < tbl2.Size(); i++) Set (tbl2.GetName(i), tbl2[i]); return *this; } }; template std::ostream & operator<< (std::ostream & ost, const SymbolTable & st) { for (int i = 0; i < st.Size(); i++) ost << st.GetName(i) << " : " << st[i] << std::endl; return ost; } } // namespace ngcore #endif // NETGEN_CORE_SYMBOLTABLE_HPP ================================================ FILE: libsrc/core/table.cpp ================================================ /**************************************************************************/ /* File: table.cpp */ /* Author: Joachim Schoeberl */ /* Date: 25. Mar. 2000 */ /**************************************************************************/ /* Abstract data type Table */ #include "table.hpp" namespace ngcore { template size_t * TablePrefixSum2 (FlatArray entrysize) { size_t size = entrysize.Size(); size_t * index = new size_t[size+1]; if (entrysize.Size() < 100) { size_t mysum = 0; for (size_t i = 0; i < entrysize.Size(); i++) { index[i] = mysum; mysum += entrysize[i]; } index[entrysize.Size()] = mysum; return index; } Array partial_sums(TaskManager::GetNumThreads()+1); partial_sums[0] = 0; ParallelJob ([&] (TaskInfo ti) { IntRange r = IntRange(size).Split(ti.task_nr, ti.ntasks); size_t mysum = 0; for (size_t i : r) mysum += entrysize[i]; partial_sums[ti.task_nr+1] = mysum; }); for (size_t i = 1; i < partial_sums.Size(); i++) partial_sums[i] += partial_sums[i-1]; ParallelJob ([&] (TaskInfo ti) { IntRange r = IntRange(size).Split(ti.task_nr, ti.ntasks); size_t mysum = partial_sums[ti.task_nr]; for (size_t i : r) { index[i] = mysum; mysum += entrysize[i]; } }); index[size] = partial_sums.Last(); return index; } NGCORE_API size_t * TablePrefixSum32 (FlatArray entrysize) { return TablePrefixSum2 (entrysize); } NGCORE_API size_t * TablePrefixSum64 (FlatArray entrysize) { return TablePrefixSum2 (entrysize); } /* BaseDynamicTable :: BaseDynamicTable (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; } BaseDynamicTable :: BaseDynamicTable (const Array & entrysizes, int elemsize) : data(entrysizes.Size()) { int cnt = 0; int n = entrysizes.Size(); for (int i = 0; i < n; i++) cnt += entrysizes[i]; oneblock = new char[elemsize * cnt]; cnt = 0; for (int i = 0; i < n; i++) { data[i].maxsize = entrysizes[i]; data[i].size = 0; data[i].col = &oneblock[elemsize * cnt]; cnt += entrysizes[i]; } } BaseDynamicTable :: ~BaseDynamicTable () { if (oneblock) delete [] oneblock; else for (int i = 0; i < data.Size(); i++) delete [] static_cast (data[i].col); } void BaseDynamicTable :: SetSize (int size) { for (int i = 0; i < data.Size(); i++) delete [] static_cast (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 BaseDynamicTable :: IncSize (IndexType i, int elsize) { if (i < 0 || i >= data.Size()) { std::cerr << "BaseDynamicTable::Inc: Out of range, i = " << i << ", size = " << data.Size() << std::endl; return; } linestruct & line = data[i]; if (line.size == line.maxsize) { void * p = new char [(2*line.maxsize+5) * elsize]; memcpy (p, line.col, line.maxsize * elsize); delete [] static_cast (line.col); line.col = p; line.maxsize = 2*line.maxsize+5; } line.size++; } void BaseDynamicTable :: DecSize (IndexType i) { if (i < 0 || i >= data.Size()) { std::cerr << "BaseDynamicTable::Dec: Out of range" << std::endl; return; } linestruct & line = data[i]; if (line.size == 0) { std::cerr << "BaseDynamicTable::Dec: EntrySize < 0" << std::endl; return; } line.size--; } */ void FilteredTableCreator::Add (size_t blocknr, int data) { if (!takedofs||takedofs->Test(data)) TableCreator::Add(blocknr,data); } void FilteredTableCreator::Add (size_t blocknr, IntRange range) { for (size_t i=range.First(); iTest(i)) TableCreator::Add(blocknr,i); } void FilteredTableCreator::Add (size_t blocknr, FlatArray dofs) { for (size_t i = 0; i < dofs.Size(); i++) if (!takedofs||takedofs->Test(dofs[i])) TableCreator::Add(blocknr,dofs[i]); } } // namespace ngcore ================================================ FILE: libsrc/core/table.hpp ================================================ #ifndef NETGEN_CORE_TABLE_HPP #define NETGEN_CORE_TABLE_HPP /**************************************************************************/ /* File: table.hpp */ /* Author: Joachim Schoeberl */ /* Date: 25. Mar. 2000 */ /**************************************************************************/ #include #include #include #include "array.hpp" #include "bitarray.hpp" #include "memtracer.hpp" #include "ngcore_api.hpp" #include "profiler.hpp" namespace ngcore { template class FlatTable { protected: static constexpr IndexType BASE = IndexBASE(); /// number of rows size_t size; /// pointer to first in row size_t * index; /// array of data T * data; public: FlatTable() = delete; FlatTable (const FlatTable &) = default; NETGEN_INLINE FlatTable(size_t as, size_t * aindex, T * adata) : size(as), index(aindex), data(adata) { ; } /// Size of table NETGEN_INLINE size_t Size() const { return size; } /// Access entry NETGEN_INLINE const FlatArray operator[] (IndexType i) const { return FlatArray (index[i-BASE+1]-index[i-BASE], data+index[i-BASE]); } NETGEN_INLINE T * Data() const { return data; } NETGEN_INLINE FlatArray AsArray() const { return FlatArray (index[size]-index[0], data+index[0]); } NETGEN_INLINE FlatArray IndexArray() const { return FlatArray (size+1, index); } /// takes range starting from position start of end-start elements NETGEN_INLINE FlatTable Range (size_t start, size_t end) const { return FlatTable (end-start, index+start-BASE, data); } /// takes range starting from position start of end-start elements NETGEN_INLINE FlatTable Range (T_Range range) const { return FlatTable (range.Size(), index+range.First()-BASE, data); } NETGEN_INLINE T_Range Range () const { return T_Range (BASE, size+BASE); } class Iterator { const FlatTable & tab; size_t row; public: Iterator (const FlatTable & _tab, size_t _row) : tab(_tab), row(_row) { ; } Iterator & operator++ () { ++row; return *this; } FlatArray operator* () const { return tab[row]; } bool operator!= (const Iterator & it2) { return row != it2.row; } }; Iterator begin() const { return Iterator(*this, BASE); } Iterator end() const { return Iterator(*this, BASE+size); } }; /* NGCORE_API extern size_t * TablePrefixSum32 (FlatArray entrysize); NGCORE_API extern size_t * TablePrefixSum64 (FlatArray entrysize); NETGEN_INLINE size_t * TablePrefixSum (FlatArray entrysize) { return TablePrefixSum32 (entrysize); } NETGEN_INLINE size_t * TablePrefixSum (FlatArray entrysize) { return TablePrefixSum32 (FlatArray (entrysize.Size(), (unsigned int*)(int*)(entrysize.Addr(0)))); } NETGEN_INLINE size_t * TablePrefixSum (FlatArray> entrysize) { return TablePrefixSum32 (FlatArray (entrysize.Size(), (unsigned int*)(std::atomic*)entrysize.Addr(0))); } NETGEN_INLINE size_t * TablePrefixSum (FlatArray entrysize) { return TablePrefixSum64 (entrysize); } */ NGCORE_API extern size_t * TablePrefixSum32 (FlatArray entrysize); NGCORE_API extern size_t * TablePrefixSum64 (FlatArray entrysize); template // TODO: enable_if T is integral NETGEN_INLINE size_t * TablePrefixSum (FlatArray entrysize) { if constexpr (sizeof(T) == 4) return TablePrefixSum32 ( { entrysize.Size(), (uint32_t*)(void*)entrysize.Addr(0) }); else return TablePrefixSum64 ( { entrysize.Size(), (uint64_t*)(void*)entrysize.Addr(0) }); } /** A compact Table container. A table contains size entries of variable size. The entry sizes must be known at construction. */ template class Table : public FlatTable { protected: using FlatTable::size; using FlatTable::index; using FlatTable::data; public: /// NETGEN_INLINE Table () : FlatTable (0,nullptr,nullptr) { ; } /// Construct table of uniform entrysize NETGEN_INLINE Table (size_t asize, size_t entrysize) : FlatTable( asize, new size_t[asize+1], new T[asize*entrysize] ) { for (size_t i : IntRange(size+1)) index[i] = i*entrysize; mt.Alloc(GetMemUsage()); } /// Construct table of variable entrysize template NETGEN_INLINE Table (FlatArray entrysize) : FlatTable (0, nullptr, nullptr) { size = entrysize.Size(); index = TablePrefixSum (FlatArray (entrysize.Size(), entrysize.Data())); size_t cnt = index[size]; data = new T[cnt]; mt.Alloc(GetMemUsage()); } explicit NETGEN_INLINE Table (const FlatTable & tab2) : FlatTable(0, nullptr, nullptr) { size = tab2.Size(); if (size == 0) return; index = new size_t[size+1]; this->IndexArray() = tab2.IndexArray(); // for (size_t i = 0; i <= size; i++) // index[i] = tab2.index[i]; size_t cnt = index[size]; data = new T[cnt]; this->AsArray() = tab2.AsArray(); mt.Alloc(GetMemUsage()); /* for (size_t i = 0; i < cnt; i++) data[i] = tab2.data[i]; */ } explicit NETGEN_INLINE Table (const Table & tab2) : FlatTable(0, nullptr, nullptr) { size = tab2.Size(); if (size == 0) return; index = new size_t[size+1]; for (size_t i = 0; i <= size; i++) index[i] = tab2.index[i]; size_t cnt = index[size]; data = new T[cnt]; for (size_t i = 0; i < cnt; i++) data[i] = tab2.data[i]; mt.Alloc(GetMemUsage()); } NETGEN_INLINE Table (Table && tab2) : FlatTable(0, nullptr, nullptr) { mt = std::move(tab2.mt); Swap (size, tab2.size); Swap (index, tab2.index); Swap (data, tab2.data); } template auto DoArchive(ARCHIVE& ar) { ar & size; if(size == 0) return; if(ar.Input()) { index = new IndexType[size+1]; mt.Alloc(sizeof(IndexType) * (size+1)); } ar.Do(index, size+1); if(ar.Input()) { data = new T[index[size]]; mt.Alloc(sizeof(T) * index[size]); } ar.Do(data, index[size]); } NETGEN_INLINE Table & operator= (Table && tab2) { mt = std::move(tab2.mt); Swap (size, tab2.size); Swap (index, tab2.index); Swap (data, tab2.data); return *this; } /// Delete data NETGEN_INLINE ~Table () { mt.Free(GetMemUsage()); delete [] data; delete [] index; } /// Size of table using FlatTable::Size; /// number of elements in all rows NETGEN_INLINE size_t NElements() const { return index[size]; } using FlatTable::operator[]; NETGEN_INLINE void StartMemoryTracing (int /* mem_id */) { mt.Alloc(GetMemUsage()); } const MemoryTracer& GetMemoryTracer() const { return mt; } private: NETGEN_INLINE size_t GetMemUsage() const { return size == 0 ? 0 : sizeof(T)*index[size] + sizeof(IndexType) * size+1; } MemoryTracer mt; }; /// Print table template inline ostream & operator<< (ostream & s, FlatTable table) { for (auto i : table.Range()) { s << i << ":"; for (auto el : table[i]) s << " " << el; s << "\n"; } s << std::flush; return s; } template class TableCreator { protected: int mode; // 1 .. cnt, 2 .. cnt entries, 3 .. fill table std::atomic nd; Array,IndexType> cnt; Table table; public: TableCreator() { nd = 0; mode = 1; } TableCreator (size_t acnt) { nd = acnt; SetMode(2); } Table MoveTable() { return std::move(table); } bool Done () { return mode > 3; } void operator++(int) { SetMode (mode+1); } int GetMode () const { return mode; } void SetMode (int amode) { mode = amode; if (mode == 2) { // cnt.SetSize(nd); // atomic has no copy cnt = Array,IndexType> (nd); for (auto & ci : cnt) ci.store (0, std::memory_order_relaxed); } if (mode == 3) { table = Table (cnt); // for (auto & ci : cnt) ci = 0; for (auto & ci : cnt) ci.store (0, std::memory_order_relaxed); // cnt = 0; } } void SetSize (size_t _nd) { if (mode == 1) nd = _nd; else { if (nd != _nd) throw Exception ("cannot change size of table-creator"); } } void Add (IndexType blocknr, const T & data) { switch (mode) { case 1: { size_t oldval = nd; while (blocknr-IndexBASE()+1>nd) { nd.compare_exchange_weak (oldval, blocknr-IndexBASE()+1); oldval = nd; } break; } case 2: cnt[blocknr]++; break; case 3: int ci = cnt[blocknr]++; table[blocknr][ci] = data; break; } } void Add (IndexType blocknr, IntRange range) { switch (mode) { case 1: { size_t oldval = nd; while (blocknr+1>nd) { nd.compare_exchange_weak (oldval, blocknr+1); oldval = nd; } break; } case 2: cnt[blocknr] += range.Size(); break; case 3: size_t ci = ( cnt[blocknr] += range.Size() ) - range.Size(); for (size_t j = 0; j < range.Size(); j++) table[blocknr][ci+j] = range.First()+j; break; } } void Add (IndexType blocknr, const FlatArray & dofs) { switch (mode) { case 1: { size_t oldval = nd; while (blocknr+1>nd) { nd.compare_exchange_weak (oldval, blocknr+1); oldval = nd; } break; } case 2: cnt[blocknr] += dofs.Size(); break; case 3: size_t ci = ( cnt[blocknr] += dofs.Size() ) - dofs.Size(); for (size_t j = 0; j < dofs.Size(); j++) table[blocknr][ci+j] = dofs[j]; break; } } }; template Table CreateTable( const TRange & range, const TFunc & func, std::optional< size_t > cnt ) { static Timer timer("CreateTable"); RegionTimer rt(timer); std::unique_ptr> pcreator; if(cnt) pcreator = std::make_unique>(*cnt); else pcreator = std::make_unique>(); auto & creator = *pcreator; for ( ; !creator.Done(); creator++) ParallelForRange (range, [&] (auto myrange) { for (auto i : myrange) func(creator, i); }, TasksPerThread(4) ); return creator.MoveTable(); } template Table CreateSortedTable( const TRange & range, const TFunc & func, std::optional< size_t > cnt ) { static Timer timer("CreateSortedTable"); RegionTimer rt(timer); Table table = CreateTable(range, func, cnt); ParallelForRange (table.Range(), [&] (auto myrange) { for (auto i : myrange) QuickSort(table[i]); }, TasksPerThread(4) ); return table; } class NGCORE_API FilteredTableCreator : public TableCreator { protected: const BitArray* takedofs; public: FilteredTableCreator(const BitArray* atakedofs) : TableCreator(), takedofs(atakedofs) { }; FilteredTableCreator(int acnt, const BitArray* atakedofs) : TableCreator(acnt),takedofs(atakedofs) { }; void SetFilter (const BitArray * atakedofs) { takedofs = atakedofs; } void Add (size_t blocknr, int data); void Add (size_t blocknr, IntRange range); void Add (size_t blocknr, FlatArray dofs); }; /** A dynamic table class. A DynamicTable contains entries of variable size. Entry sizes can be increased dynamically. */ template class DynamicTable { protected: static constexpr IndexType BASE = IndexBASE(); struct linestruct { int size; int maxsize; T * col; }; Array data; T * oneblock = nullptr; public: /// Creates table of size size DynamicTable (int size = 0) : data(size) { for (auto & d : data) { d.maxsize = 0; d.size = 0; d.col = nullptr; } oneblock = nullptr; } /// Creates table with a priori fixed entry sizes. DynamicTable (const Array & entrysizes, bool setentrysize=false) : data(entrysizes.Size()) { size_t cnt = 0; // size_t n = entrysizes.Size(); for (auto es : entrysizes) cnt += es; oneblock = new T[cnt]; cnt = 0; for (auto i : data.Range()) { data[i].maxsize = entrysizes[i]; if (setentrysize) data[i].size = entrysizes[i]; else data[i].size = 0; data[i].col = &oneblock[cnt]; cnt += entrysizes[i]; } } DynamicTable (DynamicTable && tab2) { Swap (data, tab2.data); Swap (oneblock, tab2.oneblock); } ~DynamicTable () { if (oneblock) delete [] oneblock; else for (auto & d : data) delete [] d.col; } DynamicTable & operator= (DynamicTable && tab2) { Swap (data, tab2.data); Swap (oneblock, tab2.oneblock); return *this; } /// Changes Size of table to size, deletes data void SetSize (int size) { for (auto & d : data) delete [] d.col; data.SetSize(size); for (auto & d : data) { d.maxsize = 0; d.size = 0; d.col = nullptr; } } void ChangeSize (size_t size) { if (oneblock) throw Exception ("cannot change size of oneblock dynamic table"); size_t oldsize = data.Size(); if (size == oldsize) return; if (size < oldsize) for (int i = size; i < oldsize; i++) delete [] data[i+BASE].col; data.SetSize(size); for (int i = oldsize; i < size; i++) { data[i+BASE].maxsize = 0; data[i+BASE].size = 0; data[i+BASE].col = nullptr; } } /// void IncSize (IndexType i) { NETGEN_CHECK_RANGE(i,BASE,data.Size()+BASE); linestruct & line = data[i]; if (line.size == line.maxsize) { T * p; if constexpr (std::is_default_constructible::value) p = new T[(2*line.maxsize+5)]; else p = reinterpret_cast(new char[(2*line.maxsize+5)*sizeof(T)]); for (size_t i = 0; i < line.maxsize; i++) p[i] = std::move(line.col[i]); // memcpy (p, line.col, line.maxsize * sizeof(T)); delete [] line.col; line.col = p; line.maxsize = 2*line.maxsize+5; } line.size++; } void DecSize (IndexType i) { NETGEN_CHECK_RANGE(i,BASE,data.Size()+BASE); linestruct & line = data[i]; #ifdef NETGEN_ENABLE_CHECK_RANGE if (line.size == 0) throw Exception ("BaseDynamicTable::Dec: EntrySize < 0"); #endif line.size--; } /// Inserts element acont into row i. Does not test if already used. void Add (IndexType i, const T & acont) { if (data[i].size == data[i].maxsize) this->IncSize (i); else data[i].size++; data[i].col[data[i].size-1] = acont; } /// Inserts element acont into row i, iff not yet exists. void AddUnique (IndexType i, const T & cont) { int es = EntrySize (i); T * line = data[i].col; for (int j = 0; j < es; j++) if (line[j] == cont) return; Add (i, cont); } /// Inserts element acont into row i. Does not test if already used. void AddEmpty (IndexType i) { IncSize (i); } /** Set the nr-th element in the i-th row to acont. Does not check for overflow. */ void Set (IndexType i, int nr, const T & acont) { data[i].col[nr] = acont; } /** Returns the nr-th element in the i-th row. Does not check for overflow. */ const T & Get (IndexType i, int nr) const { return data[i].col[nr]; } /** Returns pointer to the first element in row i. */ const T * GetLine (IndexType i) const { return data[i].col; } /// Returns size of the table. size_t Size () const { return data.Size(); } auto Range () const { return data.Range(); } /// Returns size of the i-th row. int EntrySize (IndexType i) const { return data[i].size; } /// void DecEntrySize (IndexType i) { DecSize(i); } /// Access entry i FlatArray operator[] (IndexType i) { return FlatArray (data[i].size, data[i].col); } /* typedef const FlatArray ConstFlatArray; /// Access entry i ConstFlatArray operator[] (int i) const { return FlatArray (data[i].size, static_cast (data[i].col)); } */ FlatArray operator[] (IndexType i) const { return FlatArray (data[i].size, data[i].col); } }; /// Print table template inline ostream & operator<< (ostream & s, const DynamicTable & table) { for (auto i : Range(table)) { s << i << ":"; for (int j = 0; j < table[i].Size(); j++) s << " " << table[i][j]; s << "\n"; } s << std::flush; return s; } // Helper function to calculate coloring of a set of indices for parallel processing of independent elements/points/etc. // Assigns a color to each of colors.Size() elements, such that two elements with the same color don't share a common 'dof', // the mapping from element to dofs is provided by the function getDofs(int) -> iterable // // Returns the number of used colors template int ComputeColoring( FlatArray colors, size_t ndofs, Tmask const & getDofs) { static Timer timer("ComputeColoring - "+Demangle(typeid(Tmask).name())); RegionTimer rt(timer); static_assert(sizeof(unsigned int)==4, "Adapt type of mask array"); size_t n = colors.Size(); Array mask(ndofs); size_t colored_blocks = 0; // We are coloring with 32 colors at once and use each bit to mask conflicts unsigned int check = 0; unsigned int checkbit = 0; int current_color = 0; colors = -1; int maxcolor = 0; while(colored_blocks-1) continue; check = 0; const auto & dofs = getDofs(i); // Check if adjacent dofs are already marked by current color for (auto dof : dofs) check|=mask[dof]; // Did we find a free color? if(check != 0xFFFFFFFF) { checkbit = 1; int color = current_color; // find the actual color, which is free (out of 32) while (check & checkbit) { color++; checkbit *= 2; } colors[i] = color; maxcolor = color > maxcolor ? color : maxcolor; colored_blocks++; // mask all adjacent dofs with the found color for (auto dof : dofs) mask[dof] |= checkbit; } } current_color+=32; } return maxcolor+1; } typedef DynamicTable IntTable; } // namespace ngcore #endif // NETGEN_CORE_TABLE_HPP ================================================ FILE: libsrc/core/taskmanager.cpp ================================================ /********************************************************************/ /* File: taskmanager.cpp */ /* Author: M. Hochsterger, J. Schoeberl */ /* Date: 10. Mar. 2015 */ /********************************************************************/ #include #include #include #include #include "concurrentqueue.h" #include "mpi_wrapper.hpp" #include "paje_trace.hpp" #include "profiler.hpp" #include "taskmanager.hpp" #ifdef USE_MKL #include #endif namespace ngcore { using std::mutex; using std::lock_guard; using std::memory_order_release; using std::memory_order_relaxed; using std::make_tuple; TaskManager * task_manager = nullptr; bool TaskManager :: use_paje_trace = false; int TaskManager :: max_threads = getenv("NGS_NUM_THREADS") ? atoi(getenv("NGS_NUM_THREADS")) : std::thread::hardware_concurrency(); int TaskManager :: num_threads = 1; thread_local int TaskManager :: thread_id = 0; const function * TaskManager::func; const function * TaskManager::startup_function = nullptr; const function * TaskManager::cleanup_function = nullptr; atomic TaskManager::ntasks; Exception * TaskManager::ex; atomic TaskManager::jobnr; atomic TaskManager::complete[8]; // max nodes atomic TaskManager::done; atomic TaskManager::active_workers; atomic TaskManager::workers_on_node[8]; // max nodes int TaskManager::sleep_usecs = 1000; bool TaskManager::sleep = false; TaskManager::NodeData *TaskManager::nodedata[8]; int TaskManager::num_nodes; static mutex copyex_mutex; int EnterTaskManager () { if (task_manager) { // no task manager started return 0; } task_manager = new TaskManager(); GetLogger("TaskManager")->info("task-based parallelization (C++11 threads) using {} threads", task_manager->GetNumThreads()); #ifdef USE_NUMA numa_run_on_node (0); #endif #if !defined(WIN32) && !defined(EMSCRIPTEN) // master has maximal priority ! int policy; struct sched_param param; pthread_getschedparam(pthread_self(), &policy, ¶m); param.sched_priority = sched_get_priority_max(policy); pthread_setschedparam(pthread_self(), policy, ¶m); #endif // !defined(WIN32) && !defined(EMSCRIPTEN) task_manager->StartWorkers(); ParallelFor (Range(100), [&] (int i) { ; }); // startup return task_manager->GetNumThreads(); } void ExitTaskManager (int num_threads) { if(num_threads > 0) { task_manager->StopWorkers(); delete task_manager; task_manager = nullptr; } } void RunWithTaskManager (function alg) { int num_threads = EnterTaskManager(); alg(); ExitTaskManager(num_threads); } void TaskManager :: SetNumThreads(int amax_threads) { if(task_manager && task_manager->active_workers>0) { std::cerr << "Warning: can't change number of threads while TaskManager active!" << std::endl; return; } max_threads = amax_threads; } TaskManager :: TaskManager() { num_threads = GetMaxThreads(); // if (MyMPI_GetNTasks() > 1) num_threads = 1; #ifdef USE_NUMA numa_available(); num_nodes = numa_max_node() + 1; if (num_nodes > num_threads) num_nodes = num_threads; for (int j = 0; j < num_nodes; j++) { void * mem = numa_alloc_onnode (sizeof(NodeData), j); nodedata[j] = new (mem) NodeData; complete[j] = -1; workers_on_node[j] = 0; } #else num_nodes = 1; nodedata[0] = new NodeData; complete[0] = -1; workers_on_node[0] = 0; #endif jobnr = 0; done = 0; sleep = false; sleep_usecs = 1000; active_workers = 0; static int cnt = 0; if (use_paje_trace) trace = new PajeTrace(num_threads, "ng" + ToString(cnt++)); } TaskManager :: ~TaskManager () { if (use_paje_trace) { delete trace; trace = nullptr; } num_threads = 1; #ifdef USE_NUMA for (int j = 0; j < num_nodes; j++) numa_free (nodedata[j], sizeof(NodeData)); #else delete nodedata[0]; #endif } #ifdef WIN32 int TaskManager :: GetThreadId() { return thread_id; } #endif void TaskManager :: StartWorkers() { done = false; for (int i = 1; i < num_threads; i++) { std::thread([this,i]() { this->Loop(i); }).detach(); } thread_id = 0; size_t alloc_size = num_threads*NgProfiler::SIZE; NgProfiler::thread_times = new size_t[alloc_size]; for (size_t i = 0; i < alloc_size; i++) NgProfiler::thread_times[i] = 0; NgProfiler::thread_flops = new size_t[alloc_size]; for (size_t i = 0; i < alloc_size; i++) NgProfiler::thread_flops[i] = 0; while (active_workers < num_threads-1) ; } static size_t calibrate_init_tsc = GetTimeCounter(); typedef std::chrono::system_clock TClock; static TClock::time_point calibrate_init_clock = TClock::now(); void TaskManager :: StopWorkers() { done = true; double delta_tsc = GetTimeCounter()-calibrate_init_tsc; double delta_sec = std::chrono::duration(TClock::now()-calibrate_init_clock).count(); double frequ = (delta_sec != 0) ? delta_tsc/delta_sec : 2.7e9; // cout << "cpu frequ = " << frequ << endl; // collect timings for (size_t i = 0; i < num_threads; i++) for (size_t j = NgProfiler::SIZE; j-- > 0; ) { if (!NgProfiler::timers[j].usedcounter) break; NgProfiler::timers[j].tottime += 1.0/frequ * NgProfiler::thread_times[i*NgProfiler::SIZE+j]; NgProfiler::timers[j].flops += NgProfiler::thread_flops[i*NgProfiler::SIZE+j]; } delete [] NgProfiler::thread_times; NgProfiler::thread_times = NgProfiler::dummy_thread_times.data(); delete [] NgProfiler::thread_flops; NgProfiler::thread_flops = NgProfiler::dummy_thread_flops.data(); while (active_workers) ; } /////////////////////// NEW: nested tasks using concurrent queue struct TNestedTask { const function * func; int mynr; int total; int producing_thread; atomic * endcnt; TNestedTask () { ; } TNestedTask (const function & _func, int _mynr, int _total, atomic & _endcnt, int prod_tid) : func(&_func), mynr(_mynr), total(_total), producing_thread(prod_tid), endcnt(&_endcnt) { ; } }; typedef moodycamel::ConcurrentQueue TQueue; typedef moodycamel::ProducerToken TPToken; typedef moodycamel::ConsumerToken TCToken; static TQueue taskqueue; void AddTask (const function & afunc, atomic & endcnt) { TPToken ptoken(taskqueue); int num = endcnt; auto tid = TaskManager::GetThreadId(); for (int i = 0; i < num; i++) taskqueue.enqueue (ptoken, { afunc, i, num, endcnt, tid }); } bool TaskManager :: ProcessTask() { // static Timer t("process task"); TNestedTask task; TCToken ctoken(taskqueue); if (taskqueue.try_dequeue(ctoken, task)) { TaskInfo ti; ti.task_nr = task.mynr; ti.ntasks = task.total; ti.thread_nr = TaskManager::GetThreadId(); ti.nthreads = TaskManager::GetNumThreads(); /* { lock_guard guard(m); cout << "process nested, nr = " << ti.task_nr << "/" << ti.ntasks << endl; } */ // if(trace && task.producing_thread != ti.thread_nr) // trace->StartTask (ti.thread_nr, t, PajeTrace::Task::ID_TIMER, task.producing_thread); (*task.func)(ti); --*task.endcnt; // if(trace && task.producing_thread != ti.thread_nr) // trace->StopTask (ti.thread_nr, t); return true; } return false; } void TaskManager :: CreateJob (const function & afunc, int antasks) { if (num_threads == 1 || !task_manager) // || func) { if (startup_function) (*startup_function)(); TaskInfo ti; ti.ntasks = antasks; ti.thread_nr = 0; ti.nthreads = 1; // ti.node_nr = 0; ti.nnodes = 1; for (ti.task_nr = 0; ti.task_nr < antasks; ti.task_nr++) afunc(ti); if (cleanup_function) (*cleanup_function)(); return; } if (func) { // we are already parallel, use nested tasks // startup for inner function not supported ... // if (startup_function) (*startup_function)(); if (antasks == 1) { TaskInfo ti; ti.task_nr = 0; ti.ntasks = 1; ti.thread_nr = 0; ti.nthreads = 1; afunc(ti); return; } atomic endcnt(antasks); AddTask (afunc, endcnt); while (endcnt > 0) { ProcessTask(); } // if (cleanup_function) (*cleanup_function)(); return; } class StartStop { public: StartStop(const function & afunc) { if (trace) trace->StartJob(jobnr, afunc.target_type()); } ~StartStop() { if (trace) trace->StopJob(); } }; if (antasks == 1) { StartStop startstop(afunc); //if (trace) // trace->StartJob(jobnr, afunc.target_type()); jobnr++; if (startup_function) (*startup_function)(); TaskInfo ti; ti.task_nr = 0; ti.ntasks = 1; ti.thread_nr = 0; ti.nthreads = 1; { RegionTracer t(ti.thread_nr, jobnr, RegionTracer::ID_JOB, ti.task_nr); afunc(ti); } if (cleanup_function) (*cleanup_function)(); // if (trace) // trace->StopJob(); return; } StartStop startstop(afunc); // if (trace) // trace->StartJob(jobnr, afunc.target_type()); func = &afunc; ntasks.store (antasks); // , memory_order_relaxed); ex = nullptr; nodedata[0]->start_cnt.store (0, memory_order_relaxed); jobnr++; for (int j = 0; j < num_nodes; j++) nodedata[j]->participate |= 1; if (startup_function) (*startup_function)(); int thd = 0; int thds = GetNumThreads(); int mynode = num_nodes * thd/thds; IntRange mytasks = Range(int(ntasks)).Split (mynode, num_nodes); NodeData & mynode_data = *(nodedata[mynode]); TaskInfo ti; ti.nthreads = thds; ti.thread_nr = thd; // ti.nnodes = num_nodes; // ti.node_nr = mynode; try { while (1) { int mytask = mynode_data.start_cnt++; if (mytask >= mytasks.Size()) break; ti.task_nr = mytasks.First()+mytask; ti.ntasks = ntasks; { RegionTracer t(ti.thread_nr, jobnr, RegionTracer::ID_JOB, ti.task_nr); (*func)(ti); } } } catch (Exception & e) { { lock_guard guard(copyex_mutex); delete ex; ex = new Exception (e); mynode_data.start_cnt = mytasks.Size(); } } if (cleanup_function) (*cleanup_function)(); for (int j = 0; j < num_nodes; j++) if (workers_on_node[j]) { while (complete[j] != jobnr) { #ifdef NETGEN_ARCH_AMD64 _mm_pause(); #endif // NETGEN_ARCH_AMD64 } } func = nullptr; if (ex) throw Exception (*ex); // if (trace) // trace->StopJob(); } void TaskManager :: Loop(int thd) { /* static Timer tADD("add entry counter"); static Timer tCASready1("spin-CAS ready tick1"); static Timer tCASready2("spin-CAS ready tick2"); static Timer tCASyield("spin-CAS yield"); static Timer tCAS1("spin-CAS wait"); static Timer texit("exit zone"); static Timer tdec("decrement"); */ thread_id = thd; int thds = GetNumThreads(); int mynode = num_nodes * thd/thds; NodeData & mynode_data = *(nodedata[mynode]); TaskInfo ti; ti.nthreads = thds; ti.thread_nr = thd; // ti.nnodes = num_nodes; // ti.node_nr = mynode; #ifdef USE_NUMA numa_run_on_node (mynode); #endif active_workers++; workers_on_node[mynode]++; int jobdone = 0; #ifdef USE_MKL auto mkl_max = mkl_get_max_threads(); mkl_set_num_threads_local(1); #endif size_t no_job_counter = 0; while (!done) { if (complete[mynode] > jobdone) jobdone = complete[mynode]; if (jobnr == jobdone) { no_job_counter++; // RegionTracer t(ti.thread_nr, tCASyield, ti.task_nr); while (ProcessTask()) no_job_counter = 0; // do the nested tasks if(sleep) std::this_thread::sleep_for(std::chrono::microseconds(sleep_usecs)); else if(no_job_counter > 30000) std::this_thread::sleep_for(std::chrono::microseconds(1000)); else if(no_job_counter > 20000) std::this_thread::sleep_for(std::chrono::microseconds(100)); else if(no_job_counter > 10000) std::this_thread::sleep_for(std::chrono::microseconds(10)); else { #ifdef WIN32 std::this_thread::yield(); #else // WIN32 sched_yield(); #endif // WIN32 } continue; } { // RegionTracer t(ti.thread_nr, tADD, ti.task_nr); // non-atomic fast check ... if ( (mynode_data.participate & 1) == 0) continue; int oldval = mynode_data.participate += 2; if ( (oldval & 1) == 0) { // job not active, going out again mynode_data.participate -= 2; continue; } } if (startup_function) (*startup_function)(); IntRange mytasks = Range(int(ntasks)).Split (mynode, num_nodes); try { while (1) { if (mynode_data.start_cnt >= mytasks.Size()) break; int mytask = mynode_data.start_cnt.fetch_add(1, memory_order_relaxed); if (mytask >= mytasks.Size()) break; ti.task_nr = mytasks.First()+mytask; ti.ntasks = ntasks; no_job_counter = 0; { RegionTracer t(ti.thread_nr, jobnr, RegionTracer::ID_JOB, ti.task_nr); (*func)(ti); } } } catch (Exception & e) { { // cout << "got exception in TM" << endl; lock_guard guard(copyex_mutex); delete ex; ex = new Exception (e); mynode_data.start_cnt = mytasks.Size(); } } #ifndef __MIC__ atomic_thread_fence (memory_order_release); #endif // __MIC__ if (cleanup_function) (*cleanup_function)(); jobdone = jobnr; mynode_data.participate-=2; { int oldpart = 1; if (mynode_data.participate.compare_exchange_strong (oldpart, 0)) { if (jobdone < jobnr.load()) { // reopen gate mynode_data.participate |= 1; } else { if (mynode != 0) mynode_data.start_cnt = 0; complete[mynode] = jobnr.load(); } } } } #ifdef USE_MKL mkl_set_num_threads_local(mkl_max); #endif workers_on_node[mynode]--; active_workers--; } std::list> TaskManager :: Timing () { /* list>timings; double time = RunTiming ( [&] () { ParallelJob ( [] (TaskInfo ti) { ; } , TasksPerThread(1) ); }); timings.push_back (make_tuple("parallel job with 1 task per thread", time*1e9)); time = RunTiming ( [&] () { ParallelJob ( [] (TaskInfo ti) { ; } , TasksPerThread(10) ); }); timings.push_back (make_tuple("parallel job with 10 tasks per thread", time*1e9)); time = RunTiming ( [&] () { ParallelJob ( [] (TaskInfo ti) { ; } , TasksPerThread(100) ); }); timings.push_back (make_tuple("parallel job with 100 tasks per thread", time*1e9)); return timings; */ // this is the old function moved from the py-interface: std::list>timings; double starttime, time; double maxtime = 0.5; size_t steps; starttime = WallTime(); steps = 0; do { for (size_t i = 0; i < 1000; i++) ParallelJob ( [] (TaskInfo ti) { ; }, TasksPerThread(1)); steps += 1000; time = WallTime()-starttime; } while (time < maxtime); timings.push_back(make_tuple("ParallelJob 1 task/thread", time/steps*1e9)); starttime = WallTime(); steps = 0; do { for (size_t i = 0; i < 1000; i++) ParallelJob ( [] (TaskInfo ti) { ; }, TasksPerThread(100)); steps += 1000; time = WallTime()-starttime; } while (time < maxtime); timings.push_back(make_tuple("ParallelJob 100 task/thread", time/steps*1e9)); starttime = WallTime(); steps = 0; do { for (int k = 0; k < 10000; k++) { SharedLoop2 sl(1000); steps += 1; } time = WallTime()-starttime; } while (time < maxtime); timings.push_back(make_tuple("SharedLoop init", time/steps*1e9)); starttime = WallTime(); steps = 0; do { for (int k = 0; k < 1000; k++) { SharedLoop sl(5); ParallelJob ( [&sl] (TaskInfo ti) { for (auto i : sl) (void)i; // silence warning } ); } steps += 1000; time = WallTime()-starttime; } while (time < maxtime); timings.push_back(make_tuple("short SharedLoop", time/steps*1e9)); starttime = WallTime(); steps = 0; do { for (int k = 0; k < 1000; k++) { SharedLoop sl1(5), sl2(5), sl3(5), sl4(5), sl5(5); ParallelJob ( [&sl1, &sl2, &sl3, &sl4, &sl5] (TaskInfo ti) { for (auto i : sl1) (void)i; // silence warning for (auto i : sl2) (void)i; // silence warning for (auto i : sl3) (void)i; // silence warning for (auto i : sl4) (void)i; // silence warning for (auto i : sl5) (void)i; // silence warning } ); } steps += 1000; time = WallTime()-starttime; } while (time < maxtime); timings.push_back(make_tuple("5 short SharedLoops", time/steps*1e9)); starttime = WallTime(); steps = 0; SharedLoop2 sl2(5); do { for (int k = 0; k < 1000; k++) { sl2.Reset(5); ParallelJob ( [&sl2] (TaskInfo ti) { for (auto i : sl2) (void)i; // silence warning } ); } steps += 1000; time = WallTime()-starttime; } while (time < maxtime); timings.push_back(make_tuple("short SharedLoop2", time/steps*1e9)); { starttime = WallTime(); steps = 0; SharedLoop2 sl1(5), sl2(5), sl3(5), sl4(5), sl5(5); do { for (int k = 0; k < 1000; k++) { sl1.Reset(5); sl2.Reset(5); sl3.Reset(5); sl4.Reset(5); sl5.Reset(5); ParallelJob ( [&sl1,&sl2,&sl3,&sl4,&sl5] (TaskInfo ti) { for (auto i : sl1) (void)i; // silence warning for (auto i : sl2) (void)i; // silence warning for (auto i : sl3) (void)i; // silence warning for (auto i : sl4) (void)i; // silence warning for (auto i : sl5) (void)i; // silence warning } ); } steps += 1000; time = WallTime()-starttime; } while (time < maxtime); timings.push_back(make_tuple("5 short SharedLoop2", time/steps*1e9)); } starttime = WallTime(); steps = 0; { SharedLoop2 sl(1000); do { for (int k = 0; k < 1000; k++) { sl.Reset(1000); ParallelJob ( [&sl] (TaskInfo ti) { for (auto i : sl) (void)i; // silence warning } ); steps += 1000; } time = WallTime()-starttime; } while (time < maxtime); timings.push_back(make_tuple("SharedLoop2 1000, time per iteration", time/steps*1e9)); } { starttime = WallTime(); steps = 0; SharedLoop2 sl(1000000); do { sl.Reset(1000000); ParallelJob ( [&sl] (TaskInfo ti) { for (auto i : sl) (void)i; // silence warning } ); steps += 1000000; time = WallTime()-starttime; } while (time < maxtime); timings.push_back(make_tuple("SharedLoop2 1000000, time per iteration", time/steps*1e9)); } return timings; } } ================================================ FILE: libsrc/core/taskmanager.hpp ================================================ #ifndef NETGEN_CORE_TASKMANAGER_HPP #define NETGEN_CORE_TASKMANAGER_HPP /*********************************************************************/ /* File: taskmanager.hpp */ /* Author: M. Hochsterger, J. Schoeberl */ /* Date: 10. Mar. 2015 */ /*********************************************************************/ #include #include #include #include #include #include #include "array.hpp" #include "paje_trace.hpp" #include "taskmanager.hpp" #ifdef USE_NUMA #include #include #endif namespace ngcore { using std::atomic; using std::function; class TaskInfo { public: int task_nr; int ntasks; int thread_nr; int nthreads; // int node_nr; // int nnodes; }; NGCORE_API extern class TaskManager * task_manager; class TaskManager { // PajeTrace *trace; class alignas(64) NodeData { public: atomic start_cnt{0}; atomic participate{0}; }; NGCORE_API static const function * func; NGCORE_API static const function * startup_function; NGCORE_API static const function * cleanup_function; NGCORE_API static atomic ntasks; NGCORE_API static Exception * ex; NGCORE_API static atomic jobnr; static atomic complete[8]; // max nodes static atomic done; static atomic active_workers; static atomic workers_on_node[8]; // max nodes // Array*> sync; NGCORE_API static int sleep_usecs; NGCORE_API static bool sleep; static NodeData *nodedata[8]; static int num_nodes; NGCORE_API static int num_threads; NGCORE_API static int max_threads; #ifdef WIN32 // no exported thread_local in dlls on Windows static thread_local int thread_id; #else NGCORE_API static thread_local int thread_id; #endif NGCORE_API static bool use_paje_trace; public: NGCORE_API TaskManager(); NGCORE_API ~TaskManager(); NGCORE_API void StartWorkers(); NGCORE_API void StopWorkers(); bool IsSleeping() const { return sleep; } int SuspendWorkers(int asleep_usecs = 1000 ) { int old_sleep_usecs = sleep_usecs; sleep_usecs = asleep_usecs; sleep = true; return old_sleep_usecs; } void ResumeWorkers() { sleep = false; } NGCORE_API static void SetNumThreads(int amax_threads); static int GetMaxThreads() { return max_threads; } // static int GetNumThreads() { return task_manager ? task_manager->num_threads : 1; } static int GetNumThreads() { return num_threads; } #ifdef WIN32 NGCORE_API static int GetThreadId(); #else static int GetThreadId() { return thread_id; } #endif int GetNumNodes() const { return num_nodes; } static void SetPajeTrace (bool use) { use_paje_trace = use; } NGCORE_API static bool ProcessTask(); NGCORE_API static void CreateJob (const function & afunc, int antasks = task_manager->GetNumThreads()); static void SetStartupFunction (const function & func) { startup_function = &func; } static void SetStartupFunction () { startup_function = nullptr; } static void SetCleanupFunction (const function & func) { cleanup_function = &func; } static void SetCleanupFunction () { cleanup_function = nullptr; } void Done() { done = true; } NGCORE_API void Loop(int thread_num); NGCORE_API static std::list> Timing (); }; NGCORE_API void RunWithTaskManager (function alg); // For Python context manager NGCORE_API int EnterTaskManager (); NGCORE_API void ExitTaskManager (int num_threads); class RegionTaskManager { int nthreads_before; int nthreads; bool started_taskmanager; public: RegionTaskManager(int anthreads=TaskManager::GetMaxThreads()) : nthreads(anthreads) { if(task_manager || nthreads==0) { // already running, no need to do anything started_taskmanager = false; return; } else { nthreads_before = TaskManager::GetMaxThreads(); TaskManager::SetNumThreads(nthreads); nthreads = EnterTaskManager(); started_taskmanager = true; } } ~RegionTaskManager() { if(started_taskmanager) { ExitTaskManager(nthreads); TaskManager::SetNumThreads(nthreads_before); } } }; class SuspendTaskManager { int old_sleep_usecs = 0; bool old_sleep = false; TaskManager * tm = nullptr; public: SuspendTaskManager(int asleep_usecs=1000) : tm(task_manager) { if(!tm) return; old_sleep = tm->IsSleeping(); old_sleep_usecs = tm->SuspendWorkers(asleep_usecs); } ~SuspendTaskManager() { if(!tm) return; if(old_sleep) // restore old sleep time tm->SuspendWorkers(old_sleep_usecs); else tm->ResumeWorkers(); } }; NETGEN_INLINE int TasksPerThread (int tpt) { // return task_manager ? tpt*task_manager->GetNumThreads() : 1; return tpt*TaskManager::GetNumThreads(); } class TotalCosts { size_t cost; public: TotalCosts (size_t _cost) : cost(_cost) { ; } size_t operator ()() { return cost; } }; template NETGEN_INLINE void ParallelFor (T_Range r, TFUNC f, int antasks = TaskManager::GetNumThreads(), TotalCosts costs = 1000) { // if (task_manager && costs() >= 1000) TaskManager::CreateJob ([r, f] (TaskInfo & ti) { auto myrange = r.Split (ti.task_nr, ti.ntasks); for (auto i : myrange) f(i); }, antasks); /* else for (auto i : r) f(i); */ } /* template NETGEN_INLINE void ParallelFor (size_t n, TFUNC f, int antasks = task_manager ? task_manager->GetNumThreads() : 0) { ParallelFor (IntRange (n), f, antasks); } */ template NETGEN_INLINE void ParallelFor (size_t n, Args...args) { ParallelFor (IntRange (n), args...); } template NETGEN_INLINE void ParallelForRange (T_Range r, TFUNC f, int antasks = TaskManager::GetNumThreads(), TotalCosts costs = 1000) { // if (task_manager && costs() >= 1000) TaskManager::CreateJob ([r, f] (TaskInfo & ti) { auto myrange = r.Split (ti.task_nr, ti.ntasks); f(myrange); }, antasks); /* else f(r); */ } /* template NETGEN_INLINE void ParallelForRange (size_t n, TFUNC f, int antasks = task_manager ? task_manager->GetNumThreads() : 0) { ParallelForRange (IntRange(n), f, antasks); } */ template NETGEN_INLINE void ParallelForRange (size_t n, Args...args) { ParallelForRange (IntRange(n), args...); } template NETGEN_INLINE void ParallelJob (TFUNC f, int antasks = TaskManager::GetNumThreads()) { TaskManager::CreateJob (f, antasks); } /* Usage example: ShareLoop myloop(100); task_manager->CreateJob ([]() { for (int i : myloop) cout << "i = " << i << endl; }); */ class SharedLoop { atomic cnt; IntRange r; class SharedIterator { atomic & cnt; int myval; int endval; public: SharedIterator (atomic & acnt, int aendval, bool begin_iterator) : cnt (acnt) { endval = aendval; myval = begin_iterator ? cnt++ : endval; if (myval > endval) myval = endval; } SharedIterator & operator++ () { myval = cnt++; if (myval > endval) myval = endval; return *this; } int operator* () const { return myval; } bool operator!= (const SharedIterator & it2) const { return myval != it2.myval; } }; public: SharedLoop (IntRange ar) : r(ar) { cnt = r.begin(); } SharedLoop (size_t s) : SharedLoop (IntRange{s}) { ; } SharedIterator begin() { return SharedIterator (cnt, r.end(), true); } SharedIterator end() { return SharedIterator (cnt, r.end(), false); } }; /* class alignas(4096) AtomicRange { mutex lock; int begin; int end; public: void Set (IntRange r) { lock_guard guard(lock); begin = r.begin(); end = r.end(); } IntRange Get() { lock_guard guard(lock); return IntRange(begin, end); } bool PopFirst (int & first) { lock_guard guard(lock); bool non_empty = end > begin; first = begin; if (non_empty) begin++; return non_empty; } bool PopHalf (IntRange & r) { lock_guard guard(lock); bool non_empty = end > begin; if (non_empty) { int mid = (begin+end+1)/2; r = IntRange(begin, mid); begin = mid; } return non_empty; } }; */ // lock free popfirst // faster for large loops, bug slower for small loops (~1000) ???? /* class alignas(4096) AtomicRange { mutex lock; atomic begin; int end; public: void Set (IntRange r) { lock_guard guard(lock); // begin = r.begin(); begin.store(r.begin(), std::memory_order_relaxed); end = r.end(); } void SetNoLock (IntRange r) { begin.store(r.begin(), std::memory_order_relaxed); end = r.end(); } // IntRange Get() // { // lock_guard guard(lock); // return IntRange(begin, end); // } bool PopFirst (int & first) { // int oldbegin = begin; int oldbegin = begin.load(std::memory_order_relaxed); if (oldbegin >= end) return false; while (!begin.compare_exchange_weak (oldbegin, oldbegin+1, std::memory_order_relaxed, std::memory_order_relaxed)) if (oldbegin >= end) return false; first = oldbegin; return true; } bool PopHalf (IntRange & r) { // int oldbegin = begin; int oldbegin = begin.load(std::memory_order_relaxed); if (oldbegin >= end) return false; lock_guard guard(lock); while (!begin.compare_exchange_weak (oldbegin, (oldbegin+end+1)/2, std::memory_order_relaxed, std::memory_order_relaxed)) if (oldbegin >= end) return false; r = IntRange(oldbegin, (oldbegin+end+1)/2); return true; } }; // inline ostream & operator<< (ostream & ost, AtomicRange & r) // { // ost << r.Get(); // return ost; // } */ class alignas(4096) AtomicRange { atomic begin; atomic end; public: void Set (IntRange r) { begin.store(std::numeric_limits::max(), std::memory_order_release); end.store(r.end(), std::memory_order_release); begin.store(r.begin(), std::memory_order_release); } void SetNoLock (IntRange r) { end.store(r.end(), std::memory_order_release); begin.store(r.begin(), std::memory_order_release); } // IntRange Get() // { // lock_guard guard(lock); // return IntRange(begin, end); // } bool PopFirst (size_t & hfirst) { // first = begin++; // return first < end; size_t first = begin.load(std::memory_order_relaxed); size_t nextfirst = first+1; if (first >= end) nextfirst = std::numeric_limits::max()-1; // while (!begin.compare_exchange_weak (first, nextfirst)) while (!begin.compare_exchange_weak (first, nextfirst, std::memory_order_relaxed, std::memory_order_relaxed)) { first = begin; nextfirst = first+1; if (nextfirst >= end) nextfirst = std::numeric_limits::max()-1; } hfirst = first; return first < end; } bool PopHalf (IntRange & r) { /* // int oldbegin = begin; size_t oldbegin = begin.load(std::memory_order_acquire); size_t oldend = end.load(std::memory_order_acquire); if (oldbegin >= oldend) return false; // lock_guard guard(lock); while (!begin.compare_exchange_weak (oldbegin, (oldbegin+oldend+1)/2, std::memory_order_relaxed, std::memory_order_relaxed)) { oldend = end.load(std::memory_order_acquire); if (oldbegin >= oldend) return false; } r = IntRange(oldbegin, (oldbegin+oldend+1)/2); return true; */ size_t oldbegin = begin; // .load(std::memory_order_acquire); size_t oldend = end; // .load(std::memory_order_acquire); if (oldbegin >= oldend) return false; size_t nextbegin = (oldbegin+oldend+1)/2; if (nextbegin >= oldend) nextbegin = std::numeric_limits::max()-1; while (!begin.compare_exchange_weak (oldbegin, nextbegin)) // std::memory_order_relaxed, std::memory_order_relaxed)) { oldend = end; // .load(std::memory_order_acquire); if (oldbegin >= oldend) return false; nextbegin = (oldbegin+oldend+1)/2; if (nextbegin >= oldend) nextbegin = std::numeric_limits::max()-1; } r = IntRange(oldbegin, (oldbegin+oldend+1)/2); return true; } }; class SharedLoop2 { Array ranges; atomic processed; atomic total; atomic participants; class SharedIterator { FlatArray ranges; atomic & processed; size_t total; size_t myval; size_t processed_by_me = 0; int me; int steal_from; public: SharedIterator (FlatArray _ranges, atomic & _processed, size_t _total, int _me, bool begin_it) : ranges(_ranges), processed(_processed), total(_total) { if (begin_it) { // me = TaskManager::GetThreadId(); me = _me; steal_from = me; GetNext(); } } ~SharedIterator() { if (processed_by_me) processed += processed_by_me; } SharedIterator & operator++ () { GetNext(); return *this;} void GetNext() { size_t nr; if (ranges[me].PopFirst(nr)) { processed_by_me++; myval = nr; return; } GetNext2(); } void GetNext2() { processed += processed_by_me; processed_by_me = 0; // done with my work, going to steal ... while (1) { if (processed >= total) return; steal_from++; if (steal_from == ranges.Size()) steal_from = 0; // steal half of the work reserved for 'from': IntRange steal; if (ranges[steal_from].PopHalf(steal)) { myval = steal.First(); processed_by_me++; if (myval+1 < steal.Next()) ranges[me].Set (IntRange(myval+1, steal.Next())); return; } } } size_t operator* () const { return myval; } bool operator!= (const SharedIterator & it2) const { return processed < total; } }; public: SharedLoop2 () : ranges(TaskManager::GetNumThreads()) { ; } SharedLoop2 (IntRange r) : ranges(TaskManager::GetNumThreads()) { Reset (r); } SharedLoop2 (size_t s) : SharedLoop2 (IntRange{s}) { } void Reset (IntRange r) { for (size_t i = 0; i < ranges.Size(); i++) ranges[i].SetNoLock (r.Split(i,ranges.Size())); total.store(r.Size(), std::memory_order_relaxed); participants.store(0, std::memory_order_relaxed); processed.store(0, std::memory_order_release); } void Reset (size_t s) { Reset(IntRange{s}); } SharedIterator begin() { /* int me = participants++; if (me < ranges.Size()) return SharedIterator (ranges, processed, total, me, true); else // more participants than buckets. set processed to total, and the loop is terminated immediately return SharedIterator (ranges, total, total, me, true); */ return SharedIterator (ranges, processed, total, TaskManager::GetThreadId(), true); } SharedIterator end() { return SharedIterator (ranges, processed, total, -1, false); } }; class Partitioning { Array part; size_t total_costs; public: Partitioning () { ; } template Partitioning (const Array & apart) { part = apart; } template Partitioning & operator= (const Array & apart) { part = apart; return *this; } size_t GetTotalCosts() const { return total_costs; } template void Calc (size_t n, TFUNC costs, int size = task_manager ? task_manager->GetNumThreads() : 1) { Array prefix (n); /* size_t sum = 0; for (auto i : ngstd::Range(n)) { sum += costs(i); prefix[i] = sum; } total_costs = sum; */ Array partial_sums(TaskManager::GetNumThreads()+1); partial_sums[0] = 0; ParallelJob ([&] (TaskInfo ti) { IntRange r = IntRange(n).Split(ti.task_nr, ti.ntasks); size_t mysum = 0; for (size_t i : r) { size_t c = costs(i); mysum += c; prefix[i] = c; } partial_sums[ti.task_nr+1] = mysum; }); for (size_t i = 1; i < partial_sums.Size(); i++) partial_sums[i] += partial_sums[i-1]; total_costs = partial_sums.Last(); ParallelJob ([&] (TaskInfo ti) { IntRange r = IntRange(n).Split(ti.task_nr, ti.ntasks); size_t mysum = partial_sums[ti.task_nr]; for (size_t i : r) { mysum += prefix[i]; prefix[i] = mysum; } }); part.SetSize (size+1); part[0] = 0; for (int i = 1; i <= size; i++) part[i] = BinSearch (prefix, total_costs*i/size); } size_t Size() const { return part.Size()-1; } IntRange operator[] (size_t i) const { return ngcore::Range(part[i], part[i+1]); } IntRange Range() const { return ngcore::Range(part[0], part[Size()]); } private: template int BinSearch(const Tarray & v, size_t i) { int n = v.Size(); if (n == 0) return 0; int first = 0; int last = n-1; if(v[0]>i) return 0; if(v[n-1] <= i) return n; while(last-first>1) { int m = (first+last)/2; if(v[m] NETGEN_INLINE void ParallelFor (const Partitioning & part, TFUNC f, int tasks_per_thread = 1) { if (task_manager) { int ntasks = tasks_per_thread * task_manager->GetNumThreads(); if (ntasks % part.Size() != 0) throw Exception ("tasks must be a multiple of part.size"); task_manager -> CreateJob ([&] (TaskInfo & ti) { int tasks_per_part = ti.ntasks / part.Size(); int mypart = ti.task_nr / tasks_per_part; int num_in_part = ti.task_nr % tasks_per_part; auto myrange = part[mypart].Split (num_in_part, tasks_per_part); for (auto i : myrange) f(i); }, ntasks); } else { for (auto i : part.Range()) f(i); } } template NETGEN_INLINE void ParallelForRange (const Partitioning & part, TFUNC f, int tasks_per_thread = 1, TotalCosts costs = 1000) { if (task_manager && costs() >= 1000) { int ntasks = tasks_per_thread * task_manager->GetNumThreads(); if (ntasks % part.Size() != 0) throw Exception ("tasks must be a multiple of part.size"); task_manager -> CreateJob ([&] (TaskInfo & ti) { int tasks_per_part = ti.ntasks / part.Size(); int mypart = ti.task_nr / tasks_per_part; int num_in_part = ti.task_nr % tasks_per_part; auto myrange = part[mypart].Split (num_in_part, tasks_per_part); f(myrange); }, ntasks); } else { f(part.Range()); } } template auto ParallelReduce (size_t n, FUNC f, OP op, T initial1) { typedef decltype (op(initial1,initial1)) TRES; TRES initial(initial1); /* for (size_t i = 0; i < n; i++) initial = op(initial, f(i)); */ Array part_reduce(TaskManager::GetNumThreads()); ParallelJob ([&] (TaskInfo ti) { auto r = Range(n).Split(ti.task_nr, ti.ntasks); auto var = initial; for (auto i : r) var = op(var, f(i)); part_reduce[ti.task_nr] = var; }); for (auto v : part_reduce) initial = op(initial, v); return initial; } // // some suggar for working with arrays // // template template // const FlatArray FlatArray::operator= (ParallelValue val) // { // ParallelForRange (Size(), // [this, val] (IntRange r) // { // for (auto i : r) // (*this)[i] = val; // }); // return *this; // } // // template template // const FlatArray FlatArray::operator= (ParallelFunction func) // { // ParallelForRange (Size(), // [this, func] (IntRange r) // { // for (auto i : r) // (*this)[i] = func(i); // }); // return *this; // } class Tasks { size_t num; public: explicit Tasks (size_t _num = TaskManager::GetNumThreads()) : num(_num) { ; } auto GetNum() const { return num; } }; /* // some idea, not yet supported using namespace std; template class ParallelValue { T val; public: ParallelValue (const T & _val) : val(_val) { ; } operator T () const { return val; } }; template class ParallelFunction { FUNC f; public: ParallelFunction (const FUNC & _f) : f(_f) { ; } operator FUNC () const { return f; } auto operator() (size_t i) const { return f(i); } }; */ /* currently not used, plus causing problems on MSVC 2017 template ::value, int>::type = 0> inline ParallelFunction operator| (const T & func, Tasks tasks) { return func; } template ::value, int>::type = 0> inline ParallelValue operator| (const T & obj, Tasks tasks) { return obj; } inline Tasks operator "" _tasks_per_thread (unsigned long long n) { return Tasks(n * TaskManager::GetNumThreads()); } */ /* thought to be used as: array = 1 | tasks class DefaultTasks { public: operator Tasks () const { return TaskManager::GetNumThreads(); } }; static DefaultTasks tasks; */ #ifdef USE_NUMA template class NumaInterleavedArray : public Array { T * numa_ptr; size_t numa_size; public: NumaInterleavedArray () { numa_size = 0; numa_ptr = nullptr; } NumaInterleavedArray (size_t s) : Array (s, (T*)numa_alloc_interleaved(s*sizeof(T))) { numa_ptr = this->data; numa_size = s; } ~NumaInterleavedArray () { numa_free (numa_ptr, numa_size*sizeof(T)); } NumaInterleavedArray & operator= (T val) { Array::operator= (val); return *this; } NumaInterleavedArray & operator= (NumaInterleavedArray && a2) { Array::operator= ((Array&&)a2); ngcore::Swap (numa_ptr, a2.numa_ptr); ngcore::Swap (numa_size, a2.numa_size); return *this; } void Swap (NumaInterleavedArray & b) { Array::Swap(b); ngcore::Swap (numa_ptr, b.numa_ptr); ngcore::Swap (numa_size, b.numa_size); } void SetSize (size_t size) { std::cerr << "************************* NumaDistArray::SetSize not overloaded" << std::endl; Array::SetSize(size); } }; template class NumaDistributedArray : public Array { T * numa_ptr; size_t numa_size; public: NumaDistributedArray () { numa_size = 0; numa_ptr = nullptr; } NumaDistributedArray (size_t s) : Array (s, (T*)numa_alloc_local(s*sizeof(T))) { numa_ptr = this->data; numa_size = s; /* int avail = */ numa_available(); // initialize libnuma int num_nodes = numa_num_configured_nodes(); size_t pagesize = numa_pagesize(); int npages = std::ceil ( double(s)*sizeof(T) / pagesize ); // cout << "size = " << numa_size << endl; // cout << "npages = " << npages << endl; for (int i = 0; i < num_nodes; i++) { int beg = (i * npages) / num_nodes; int end = ( (i+1) * npages) / num_nodes; // cout << "node " << i << " : [" << beg << "-" << end << ")" << endl; numa_tonode_memory(numa_ptr+beg*pagesize/sizeof(T), (end-beg)*pagesize, i); } } ~NumaDistributedArray () { numa_free (numa_ptr, numa_size*sizeof(T)); } NumaDistributedArray & operator= (NumaDistributedArray && a2) { Array::operator= ((Array&&)a2); ngcore::Swap (numa_ptr, a2.numa_ptr); ngcore::Swap (numa_size, a2.numa_size); return *this; } void Swap (NumaDistributedArray & b) { Array::Swap(b); ngcore::Swap (numa_ptr, b.numa_ptr); ngcore::Swap (numa_size, b.numa_size); } void SetSize (size_t size) { std::cerr << "************************* NumaDistArray::SetSize not overloaded" << std::endl; Array::SetSize(size); } }; template class NumaLocalArray : public Array { T * numa_ptr; size_t numa_size; public: NumaLocalArray () { numa_size = 0; numa_ptr = nullptr; } NumaLocalArray (size_t s) : Array (s, (T*)numa_alloc_local(s*sizeof(T))) { numa_ptr = this->data; numa_size = s; } ~NumaLocalArray () { numa_free (numa_ptr, numa_size*sizeof(T)); } NumaLocalArray & operator= (T val) { Array::operator= (val); return *this; } NumaLocalArray & operator= (NumaLocalArray && a2) { Array::operator= ((Array&&)a2); ngcore::Swap (numa_ptr, a2.numa_ptr); ngcore::Swap (numa_size, a2.numa_size); return *this; } void Swap (NumaLocalArray & b) { Array::Swap(b); ngcore::Swap (numa_ptr, b.numa_ptr); ngcore::Swap (numa_size, b.numa_size); } void SetSize (size_t size) { std::cerr << "************************* NumaDistArray::SetSize not overloaded" << std::endl; Array::SetSize(size); } }; #else // USE_NUMA template using NumaDistributedArray = Array; template using NumaInterleavedArray = Array; template using NumaLocalArray = Array; #endif // USE_NUMA } #endif // NETGEN_CORE_TASKMANAGER_HPP ================================================ FILE: libsrc/core/type_traits.hpp ================================================ #ifndef NETGEN_CORE_TYPE_TRAITS_HPP #define NETGEN_CORE_TYPE_TRAITS_HPP #include #include namespace ngcore { namespace detail { template struct _BoolArray{}; template constexpr bool all_of_tmpl = std::is_same<_BoolArray, _BoolArray<(vals || true)...>>::value; // NOLINT template struct is_any_pointer_impl : std::false_type {}; // check if second template argument is tuple of base classes to first // template argument, return constexpr bool template constexpr bool is_base_of_tuple = false; template constexpr bool is_base_of_tuple> = all_of_tmpl::value...>; template struct is_any_pointer_impl : std::true_type {}; template struct is_any_pointer_impl> : std::true_type {}; template struct is_any_pointer_impl> : std::true_type {}; template constexpr bool is_any_pointer = is_any_pointer_impl::value; } // namespace detail // Type trait to check if a class implements a 'range_type Range()' function namespace detail { template struct has_Range { private: template static constexpr auto check(T2*) -> std::enable_if_t().Range()), void>, std::true_type> { return std::true_type(); } template static constexpr std::false_type check(...); using type = decltype(check(nullptr)); // NOLINT public: NGCORE_API static constexpr bool value = type::value; }; } template constexpr bool has_range = detail::has_Range::value; } // namespace ngcore #endif // NETGEN_CORE_TYPE_TRAITS_HPP ================================================ FILE: libsrc/core/utils.cpp ================================================ #include "ngcore_api.hpp" #include "utils.hpp" #include "logging.hpp" #include "simd_generic.hpp" #ifdef WIN32 #define WIN32_LEAN_AND_MEAN #include #undef WIN32_LEAN_AND_MEAN #else // WIN32 #include #include #endif //WIN32 // #include #include #include #include #include #include #include "ngstream.hpp" namespace ngcore { namespace detail { // see https://github.com/RobotLocomotion/drake/blob/master/common/nice_type_name.cc static const auto demangle_regexes = std::array, 8>{ // Remove unwanted keywords and following space. (\b is word boundary.) std::make_pair(std::regex("\\b(class|struct|enum|union) "), ""), // Tidy up anonymous namespace. {std::regex("[`(]anonymous namespace[')]"), "(anonymous)"}, // Replace Microsoft __int64 with long long. {std::regex("\\b__int64\\b"), "long long"}, // Temporarily replace spaces we want to keep with "!". (\w is // alphanumeric or underscore.) {std::regex("(\\w) (\\w)"), "$1!$2"}, {std::regex(" "), ""}, // Delete unwanted spaces. // Some compilers throw in extra namespaces like "__1" or "__cxx11". // Delete them. {std::regex("\\b__[[:alnum:]_]+::"), ""}, {std::regex("!"), " "}, // Restore wanted spaces. // Recognize std::string's full name and abbreviate. {std::regex("\\bstd::basic_string," "std::allocator>"), "std::string"} }; std::string CleanupDemangledName( std::string s ) { for(const auto & [r, sub] : demangle_regexes) s = std::regex_replace (s,r,sub); #ifdef EMSCRIPTEN // for some reason regex_replace is not working at all std::string temp = s; s = ""; for(auto c : temp) if(c!=' ') s+=c; #endif // EMSCRIPTEN return s; } } // namespace detail // parallel netgen int id = 0, ntasks = 1; #ifdef WIN32 // windows does demangling in typeid(T).name() NGCORE_API std::string Demangle(const char* typeinfo) { std::string name = typeinfo; return detail::CleanupDemangledName(name); } #else NGCORE_API std::string Demangle(const char* typeinfo) { int status=0; try { char *s = abi::__cxa_demangle(typeinfo, nullptr, nullptr, &status); std::string result; if (s == nullptr) result = typeinfo; else { result = s; free(s); } result = detail::CleanupDemangledName(result); return result; } catch( const std::exception & e ) { GetLogger("utils")->warn("{}:{} cannot demangle {}, status: {}, error:{}", __FILE__, __LINE__, typeinfo, status, e.what()); } std::string name = typeinfo; return detail::CleanupDemangledName(name); } #endif double seconds_per_tick = [] () noexcept { auto tick_start = GetTimeCounter(); double tstart = WallTime(); double tend = WallTime()+0.001; // wait for 1ms and compare wall time with time counter while(WallTime()(tick_end-tick_start); }(); const std::chrono::time_point wall_time_start = TClock::now(); int printmessage_importance = getenv("NG_MESSAGE_LEVEL") ? atoi(getenv("NG_MESSAGE_LEVEL")) : 0; bool NGSOStream :: glob_active = true; NGCORE_API int GetCompiledSIMDSize() { return GetDefaultSIMDSize(); } NGCORE_API bool IsRangeCheckEnabled() { #ifdef NETGEN_ENABLE_CHECK_RANGE return true; #else return false; #endif } NGCORE_API std::filesystem::path GetTempFilename() { static int counter = 0; auto path = std::filesystem::temp_directory_path(); path += ".temp_netgen_file_"+ToString(counter++)+"_"+ToString(GetTimeCounter()); return path; } SharedLibrary :: SharedLibrary(const std::filesystem::path & lib_name_, std::optional directory_to_delete_, bool global ) : lib_name(lib_name_),directory_to_delete(directory_to_delete_) { Load(lib_name, global); } SharedLibrary :: ~SharedLibrary() { Unload(); if(directory_to_delete) for([[maybe_unused]] auto i : Range(5)) { // on Windows, a (detached?) child process of the compiler/linker might still block the directory // wait for it to finish (up to a second) try { std::filesystem::remove_all(*directory_to_delete); directory_to_delete = std::nullopt; break; } catch(const std::exception &e) { std::this_thread::sleep_for(std::chrono::milliseconds(200)); } } if(directory_to_delete) std::cerr << "Could not delete " << directory_to_delete->string() << std::endl; } void SharedLibrary :: Load( const std::filesystem::path & lib_name_, bool global ) { Unload(); lib_name = lib_name_; #ifdef WIN32 lib = LoadLibraryW(lib_name.wstring().c_str()); if (!lib) throw std::runtime_error(std::string("Could not load library ") + lib_name.string()); #else // WIN32 auto flags = RTLD_NOW; if (global) flags |= RTLD_GLOBAL; lib = dlopen(lib_name.c_str(), flags); if(lib == nullptr) throw std::runtime_error(dlerror()); #endif // WIN32 } void SharedLibrary :: Unload() { if(lib) { #ifdef WIN32 FreeLibrary((HMODULE)lib); #else // WIN32 int rc = dlclose(lib); if(rc != 0) std::cerr << "Failed to close library " << lib_name << std::endl; #endif // WIN32 } } void* SharedLibrary :: GetRawSymbol( std::string func_name ) { #ifdef WIN32 void* func = GetProcAddress((HMODULE)lib, func_name.c_str()); if(func == nullptr) throw std::runtime_error(std::string("Could not find function ") + func_name + " in library " + lib_name.string()); #else // WIN32 void* func = dlsym(lib, func_name.c_str()); if(func == nullptr) throw std::runtime_error(dlerror()); #endif // WIN32 return func; } void* GetRawSymbol( std::string func_name ) { void * func = nullptr; #ifdef WIN32 throw std::runtime_error("GetRawSymbol not implemented on WIN32"); #else // WIN32 func = dlsym(RTLD_DEFAULT, func_name.c_str()); if(func == nullptr) throw std::runtime_error(dlerror()); #endif // WIN32 return func; } } // namespace ngcore ================================================ FILE: libsrc/core/utils.hpp ================================================ #ifndef NETGEN_CORE_UTILS_HPP #define NETGEN_CORE_UTILS_HPP #include #include #include #include #include #include #include #include #include "ngcore_api.hpp" // for NGCORE_API and CPU arch macros #if defined(__APPLE__) && defined(NETGEN_ARCH_ARM64) #include #endif #ifdef NETGEN_ARCH_AMD64 #ifdef WIN32 #include // for __rdtsc() CPU time step counter #else #include // for __rdtsc() CPU time step counter #endif // WIN32 #endif // NETGEN_ARCH_AMD64 namespace ngcore { // MPI rank, nranks TODO: Rename // [[deprecated("don't use global id/ntasks")]] extern NGCORE_API int id; // [[deprecated("don't use global id/ntasks")]] extern NGCORE_API int ntasks; NGCORE_API std::string Demangle(const char* typeinfo); template std::string GetName(const T& obj) { return Demangle(typeid(obj).name()); } #if defined(__GNUC__) inline bool likely (bool x) { return bool(__builtin_expect(long(x), 1L)); } inline bool unlikely (bool x) { return bool(__builtin_expect(long(x), 0L)); } #else inline bool likely (bool x) { return x; } inline bool unlikely (bool x) { return x; } #endif using TClock = std::chrono::system_clock; extern NGCORE_API const std::chrono::time_point wall_time_start; // Time in seconds since program start inline double WallTime () noexcept { std::chrono::time_point now = TClock::now(); std::chrono::duration elapsed_seconds = now-wall_time_start; return elapsed_seconds.count(); } // High precision clock counter register using TTimePoint = size_t; extern NGCORE_API double seconds_per_tick; inline TTimePoint GetTimeCounter() noexcept { #if defined(NETGEN_ARCH_AMD64) return __rdtsc(); #elif defined(NETGEN_ARCH_ARM64) unsigned long long tics; __asm __volatile("mrs %0, CNTVCT_EL0" : "=&r" (tics)); return tics; #elif defined(__EMSCRIPTEN__) || (defined(_MSC_VER) && defined(_M_ARM64)) return std::chrono::high_resolution_clock::now().time_since_epoch().count(); #else #warning "Unsupported CPU architecture" return 0; #endif } template inline std::string ToString (const T& t) { std::stringstream ss; ss << t; return ss.str(); } inline std::string ToLower( const std::string & s ) { std::string res; res.reserve(s.size()); for(auto & c : s) res.push_back(tolower(c)); return res; } inline std::string ToLower( const std::filesystem::path & p ) { return ToLower(p.string()); } template void SaveBin (std::ostream & ost, const T & val) { const char * cp = reinterpret_cast (&val); for (unsigned j = 0; j < sizeof(T); j++) ost.put(cp[j]); } template void LoadBin (std::istream & ist, T & val) { char * cp = reinterpret_cast (&val); for (unsigned j = 0; j < sizeof(T); j++) ist.get(cp[j]); } template std::ostream& operator << (std::ostream& ost, const std::map& map) { for(auto& val : map) ost << "\n" << val.first << ": " << val.second; return ost; } template NETGEN_INLINE void Swap (T & a, T & b) { T temp = std::move(a); a = std::move(b); b = std::move(temp); } /// min of 2 values template NETGEN_INLINE T min2 (T a, T b) { return (a < b) ? a : b; } /// max of 2 values template NETGEN_INLINE T max2 (T a, T b) { return (a > b) ? a : b; } /// min of 3 values template NETGEN_INLINE T min3 (T a, T b, T c) { return (a < b) ? (a < c) ? a : c : (b < c) ? b : c; } /// max of 3 values template NETGEN_INLINE T max3 (T a, T b, T c) { /// return (a > b) ? ((a > c) ? a : c) : ((b > c) ? b : c); } /// sign of value (+1, 0, -1) template NETGEN_INLINE int sgn (T a) { return (a > 0) ? 1 : ( ( a < 0) ? -1 : 0 ); } /// square element template NETGEN_INLINE constexpr T sqr (const T a) { return a * a; } /// element to the third power template NETGEN_INLINE T pow3 (const T a) { return a * a * a; } NETGEN_INLINE double IfPos (double a, double b, double c) { return a>0 ? b : c; } NETGEN_INLINE double IfZero (double a, double b, double c) { return a==0. ? b : c; } // checks if string starts with sequence inline bool StartsWith(const std::string& str, const std::string& start) { if(start.size() > str.size()) return false; return std::equal(start.begin(), start.end(), str.begin()); } // checks if string ends with sequence inline bool EndsWith(const std::string& str, const std::string& end) { if(end.size() > str.size()) return false; return std::equal(end.rbegin(), end.rend(), str.rbegin()); } template NETGEN_INLINE std::atomic & AsAtomic (T & d) { return reinterpret_cast&> (d); } NETGEN_INLINE double AtomicAdd( double & sum, double val ) { std::atomic & asum = AsAtomic(sum); double current = asum.load(); while (!asum.compare_exchange_weak(current, current + val)) ; return current; } template NETGEN_INLINE T AtomicMin( T & minval, T val ) { std::atomic & aminval = AsAtomic(minval); T current = aminval.load(); while (!aminval.compare_exchange_weak(current, std::min(current, val))) ; return current; } template NETGEN_INLINE T AtomicMax( T & maxval, T val ) { std::atomic & amaxval = AsAtomic(maxval); T current = amaxval.load(); while (!amaxval.compare_exchange_weak(current, std::max(current, val))) ; return current; } template using IC = std::integral_constant; // needed for Iterate namespace detail { template struct IsIC_trait { static constexpr auto check() { return false; } }; template struct IsIC_trait> == true, int> > { static constexpr auto check() { return true; } }; } template constexpr bool is_IC() { return detail::IsIC_trait::check(); } template NETGEN_INLINE void Iterate (FUNC f) { if constexpr (NUM > 1) Iterate (f); if constexpr (NUM >= 1) f(IC()); } template NETGEN_INLINE void Switch (size_t nr, FUNC f) { if (NUM-1 == nr) f(IC()); if constexpr (NUM > 1) Switch (nr, f); } namespace detail { template struct IndexTypeHelper { private: template static constexpr auto check(T2* t) -> typename T2::index_type { return *t; } static constexpr size_t check(...); public: using type = decltype(check((T*) nullptr)); // NOLINT }; } // namespace detail // Get index type of object. If object has a typedef index_type it is this type, else size_t template using index_type = typename detail::IndexTypeHelper::type; class MyMutex { std::atomic m; public: MyMutex() { m.store(false, std::memory_order_relaxed); } void lock() { bool should = false; while (!m.compare_exchange_weak(should, true)) { should = false; #ifdef NETGEN_ARCH_AMD64 _mm_pause(); #endif // NETGEN_ARCH_AMD64 } } void unlock() { m = false; } }; class MyLock { MyMutex & mutex; public: MyLock (MyMutex & amutex) : mutex(amutex) { mutex.lock(); } ~MyLock () { mutex.unlock(); } }; NGCORE_API int GetCompiledSIMDSize(); NGCORE_API bool IsRangeCheckEnabled(); NGCORE_API std::filesystem::path GetTempFilename(); NGCORE_API void* GetRawSymbol( std::string func_name ); template TFunc GetSymbol( std::string func_name ) { return reinterpret_cast(GetRawSymbol(func_name)); } // Class to handle/load shared libraries class NGCORE_API SharedLibrary { std::filesystem::path lib_name; std::optional directory_to_delete = std::nullopt; void *lib = nullptr; public: SharedLibrary() = default; SharedLibrary(const std::filesystem::path & lib_name_, std::optional directory_to_delete_ = std::nullopt, bool global = false ); SharedLibrary(const SharedLibrary &) = delete; SharedLibrary & operator =(const SharedLibrary &) = delete; ~SharedLibrary(); template TFunc GetSymbol( std::string func_name ) { return reinterpret_cast(GetRawSymbol(func_name)); } void Load( const std::filesystem::path & lib_name_, bool global = true); void Unload(); void* GetRawSymbol( std::string func_name ); }; } // namespace ngcore #endif // NETGEN_CORE_UTILS_HPP ================================================ FILE: libsrc/core/version.cpp ================================================ #include #include #include "exception.hpp" #include "version.hpp" namespace ngcore { // clang-tidy should ignore this static object static std::map library_versions; // NOLINT const VersionInfo& GetLibraryVersion(const std::string& library) { return library_versions[library]; } const std::map& GetLibraryVersions() { return library_versions; } void SetLibraryVersion(const std::string& library, const VersionInfo& version) { if(library_versions.count(library) && (library_versions[library] != version)) throw Exception("Failed to set library version for " + library + " to " + version.to_string() + ": version already set to " + library_versions[library].to_string()); library_versions[library] = version; } static bool dummy = [](){ SetLibraryVersion("netgen", NETGEN_VERSION); return true; }(); } // namespace ngcore ================================================ FILE: libsrc/core/version.hpp ================================================ #ifndef NETGEN_CORE_VERSION_HPP #define NETGEN_CORE_VERSION_HPP #include #include #include #include "ngcore_api.hpp" namespace ngcore { class VersionInfo { private: size_t mayor_{}, minor_{}, release{}, patch{}; std::string git_hash{}; public: VersionInfo() = default; VersionInfo(std::string vstring) { minor_ = release = patch = 0; git_hash = ""; if(vstring.substr(0,1) == "v") vstring = vstring.substr(1,vstring.size()-1); auto dot = vstring.find('.'); mayor_ = std::stoi(vstring.substr(0,dot)); if(dot == size_t(-1)) vstring = ""; else vstring = vstring.substr(dot+1, vstring.size()-dot-1); if(!vstring.empty()) { dot = vstring.find('.'); minor_ = std::stoi(vstring.substr(0,dot)); if (dot == size_t(-1)) vstring = ""; else vstring = vstring.substr(dot+1, vstring.size()-dot-1); if(!vstring.empty()) { dot = vstring.find('-'); release = std::stoi(vstring.substr(0,dot)); if(dot == size_t(-1)) vstring = ""; else vstring = vstring.substr(dot+1,vstring.size()-dot-1); if(!vstring.empty()) { dot = vstring.find('-'); patch = std::stoi(vstring.substr(0,dot)); if(dot == size_t(-1)) vstring = ""; else vstring = vstring.substr(dot+1, vstring.size()-dot-1); if(!vstring.empty()) git_hash = vstring; } } } } VersionInfo(const char* cstr) : VersionInfo(std::string(cstr)) { } std::string to_string() const { std::string vstring = "v" + std::to_string(mayor_); if(minor_ || release || patch || !git_hash.empty()) { vstring += "." + std::to_string(minor_); if(release || patch || !git_hash.empty()) { vstring += "." + std::to_string(release); if(patch || !git_hash.empty()) { vstring += "-" + std::to_string(patch); if(!git_hash.empty()) vstring += "-" + git_hash; } } } return vstring; } bool operator <(const VersionInfo& other) const { return std::tie(mayor_, minor_, release, patch) < std::tie(other.mayor_, other.minor_, other.release, other.patch); } bool operator ==(const VersionInfo& other) const { return mayor_ == other.mayor_ && minor_ == other.minor_ && release == other.release && patch == other.patch; } bool operator !=(const VersionInfo& other) const { return !(*this==other); } bool operator >(const VersionInfo& other) const { return other < (*this); } bool operator <=(const VersionInfo& other) const { return !((*this) > other); } bool operator >=(const VersionInfo& other) const { return !((*this) < other); } }; inline std::ostream& operator << (std::ostream& ost, const VersionInfo& version) { return ost << version.to_string(); } NGCORE_API const VersionInfo& GetLibraryVersion(const std::string& library); NGCORE_API const std::map& GetLibraryVersions(); NGCORE_API void SetLibraryVersion(const std::string& library, const VersionInfo& version); } // namespace ngcore #endif // NETGEN_CORE_VERSION_HPP ================================================ FILE: libsrc/core/xbool.hpp ================================================ #ifndef NETGEN_CORE_XBOOL_HPP #define NETGEN_CORE_XBOOL_HPP /**************************************************************************/ /* File: xbool.hpp */ /* Author: Joachim Schoeberl */ /* Date: 14. Nov. 07 */ /**************************************************************************/ namespace ngcore { // an extended bool with values false/maybe/true struct TMAYBE { }; constexpr TMAYBE maybe; class xbool { uint8_t state; public: xbool (bool b) : state(b ? 2 : 0) { ; } xbool (TMAYBE /* x */) : state(1) { ; } xbool () = default; xbool (const xbool &) = default; xbool & operator= (bool b) { state = b ? 2 : 0; return *this; } xbool & operator= (TMAYBE /* x */) { state = 1; return *this; } bool IsTrue () const { return state == 2; } bool IsMaybe () const { return state == 1; } bool IsFalse () const { return state == 0; } bool IsMaybeTrue() const { return state >= 1; } bool IsMaybeFalse() const { return state <= 1; } friend ostream & operator<< (ostream & ost, xbool xb); }; static char output[] = "0?1"; inline ostream & operator<< (ostream & ost, xbool xb) { return ost << output[xb.state]; } } // namespace ngcore #endif // NETGEN_CORE_XBOOL_HPP ================================================ FILE: libsrc/csg/CMakeLists.txt ================================================ target_sources(nglib PRIVATE 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 zrefine.cpp python_csg.cpp splinesurface.cpp ) if(USE_GUI) target_sources(nggui PRIVATE vscsg.cpp csgpkg.cpp) endif(USE_GUI) install(FILES algprim.hpp brick.hpp csgeom.hpp csg.hpp csgparser.hpp curve2d.hpp edgeflw.hpp explicitcurve2d.hpp extrusion.hpp gencyl.hpp geoml.hpp identify.hpp manifold.hpp meshsurf.hpp polyhedra.hpp revolution.hpp singularref.hpp solid.hpp specpoin.hpp spline3d.hpp splinesurface.hpp surface.hpp triapprox.hpp vscsg.hpp DESTINATION ${NG_INSTALL_DIR_INCLUDE}/csg COMPONENT netgen_devel ) ================================================ FILE: libsrc/csg/algprim.cpp ================================================ #include #include #include #include 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 :: Print (ostream & ost) const { ost << "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, NgArray & 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 (NgArray & 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(&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, NgArray & 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 (NgArray & 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 (&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 { // if two spheres touch at exactly that point meshing fails. return c + r * Vec<3> (0.12345, 0.54321, 0.8304715488203073); } 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); } void Ellipsoid :: GetPrimitiveData (const char *& classname, NgArray & coeffs) const { classname = "ellipsoid"; coeffs.SetSize (12); for(auto i : Range(3)) { coeffs[i] = a(i); coeffs[3+i] = v1(i); coeffs[6+i] = v2(i); coeffs[9+i] = v3(i); } } void Ellipsoid :: SetPrimitiveData (NgArray & coeffs) { for(auto i : Range(3)) { a(i) = coeffs[i]; v1(i) = coeffs[3+i]; v2(i) = coeffs[6+i]; v3(i) = coeffs[9+i]; } CalcData(); } 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 (NgArray & 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; // ( - 2 + // - ^2 + 2 - ^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, NgArray & 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 (NgArray & 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); } void Cylinder :: Print (ostream & ost) const { ost << "cylinder(" << a << "; " << b << "; " << r << ")"; } int Cylinder :: IsIdentic (const Surface & s2, int & inv, double eps) const { const Cylinder * cyl2 = dynamic_cast (&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-1e-12) * v1.Length() * v2.Length()) return 0; if ( Cross(v1,v2).Length2() > 1e-20 * v1.Length2() * v2.Length2()) return 0; v2 = cyl2->b - a; // if ( fabs (v1 * v2) < (1-eps) * v1.Length() * v2.Length()) return 0; if ( Cross(v1,v2).Length2() > 1e-20 * v1.Length2() * v2.Length2()) 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(); // ( - 2 + // - ^2 + 2 - ^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 (NgArray & coeffs) { SetPrimitiveData(coeffs); } void EllipticCylinder :: GetPrimitiveData (const char *& classname, NgArray & 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 (NgArray & 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)); } int EllipticCylinder :: IsIdentic(const Surface& s2, int& inv, double eps) const { const EllipticCylinder* ps2 = dynamic_cast(&s2); if (!ps2) return 0; if((vl - ps2->vl).Length() > eps || (vs - ps2->vs).Length() > eps || (a-ps2->a).Length() > eps) return 0; return 1; } 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, NgArray & 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 (NgArray & 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 */, const MeshingParameters & mparam, 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)); } } /// Elliptic Cone /// Josephat Kalezhi (kalezhi@cbu.ac.zm) /// February 21st, 2018 /// EllipticCone :: EllipticCone (const Point<3> & aa, const Vec<3> & avl, const Vec<3> & avs, double ah, double avlr) { a = aa; h = ah; vlr = avlr; if (avl.Length2() >= avs.Length2()) { vl = avl; vs = avs; } else { vl = avs; vs = avl; } CalcData(); // Print (cout); } Primitive * EllipticCone :: CreateDefault () { return new EllipticCone (Point<3> (0,0,0), Vec<3> (1,0,0), Vec<3> (0,1,0), 1, 0.5); } void EllipticCone :: GetPrimitiveData (const char *& classname, NgArray & coeffs) const { classname = "ellipticcone"; coeffs.SetSize (11); coeffs.Elem(1) = a(0); coeffs.Elem(2) = a(1); coeffs.Elem(3) = a(2); coeffs.Elem(4) = vl(0); coeffs.Elem(5) = vl(1); coeffs.Elem(6) = vl(2); coeffs.Elem(7) = vs(0); coeffs.Elem(8) = vs(1); coeffs.Elem(9) = vs(2); coeffs.Elem(10) = h; coeffs.Elem(11) = vlr; } void EllipticCone :: SetPrimitiveData (NgArray & coeffs) { a(0) = coeffs.Elem(1); a(1) = coeffs.Elem(2); a(2) = coeffs.Elem(3); vl(0) = coeffs.Elem(4); vl(1) = coeffs.Elem(5); vl(2) = coeffs.Elem(6); vs(0) = coeffs.Elem(7); vs(1) = coeffs.Elem(8); vs(2) = coeffs.Elem(9); h = coeffs.Elem(10); vlr = coeffs.Elem(11); CalcData(); } void EllipticCone :: CalcData () { Vec<3> nh = Cross(vl, vs); nh.Normalize(); double lvl = vl.Length(); double lvs = vs.Length(); Vec<3> t1vec = lvl*(vlr -1)*(1/h)*nh; Vec<3> va (a); double t1 = lvl*(1 - (vlr -1)*(1/h)*(va*nh)); Vec<3> nvl = (1.0/lvl)*vl; Vec<3> nvs = (1.0/lvs)*vs; double ellipt2 = sqr(lvl/lvs); cxx = nvl(0)*nvl(0) + ellipt2*nvs(0)*nvs(0) - t1vec(0)*t1vec(0); cyy = nvl(1)*nvl(1) + ellipt2*nvs(1)*nvs(1) - t1vec(1)*t1vec(1); czz = nvl(2)*nvl(2) + ellipt2*nvs(2)*nvs(2) - t1vec(2)*t1vec(2); cxy = 2*(nvl(0)*nvl(1) + ellipt2*nvs(0)*nvs(1) - t1vec(0)*t1vec(1)); cxz = 2*(nvl(0)*nvl(2) + ellipt2*nvs(0)*nvs(2) - t1vec(0)*t1vec(2)); cyz = 2*(nvl(1)*nvl(2) + ellipt2*nvs(1)*nvs(2) - t1vec(1)*t1vec(2)); Vec<3> v = -2*((va*nvl)*nvl + ellipt2*(va*nvs)*nvs + t1*t1vec); cx = v(0); cy = v(1); cz = v(2); c1 = pow(va*nvl,2) + ellipt2*pow(va*nvs,2) - t1*t1; double lvltop = vlr*lvl; // double minlvl = (lvl < lvltop) ? lvl : lvltop; double maxlvl = max2( lvl,lvltop); cxx /= maxlvl; cyy /= maxlvl; czz /= maxlvl; cxy /= maxlvl; cxz /= maxlvl; cyz /= maxlvl; cx /= maxlvl; cy /= maxlvl; cz /= maxlvl; c1 /= maxlvl; } INSOLID_TYPE EllipticCone :: BoxInSolid (const BoxSphere<3> & box) const { double rp, dist; Vec<3> cv( box.Center()); Vec<3> nh = Cross(vl, vs); nh.Normalize(); double lvl = vl.Length(); Vec<3> t1vec = lvl*(vlr -1)*(1/h)*nh; Vec<3> va (a); double t1 = lvl*(1 - (vlr -1)*(1/h)*(va*nh)); rp = cv*t1vec + t1; double lvltop = vlr*lvl; double maxlvl = max2( lvl,lvltop); dist = sqrt( CalcFunctionValue(box.Center())*maxlvl + rp*rp) - rp; if (dist - box.Diam() > 0) return IS_OUTSIDE; if (dist + box.Diam() < 0) return IS_INSIDE; return DOES_INTERSECT; } double EllipticCone :: HesseNorm () const { return 1.0/min(vs.Length2 (),vl.Length2()); } double EllipticCone :: MaxCurvature () const { double a = vs.Length(); double b = vl.Length(); return max2(b/(a*a),a/(b*b)); } double EllipticCone :: MaxCurvatureLoc (const Point<3> & c, double rad) const { #ifdef JOACHIMxxx cout << "max curv local" << endl; return 0.02; #endif // saubere Loesung wird noch notwendig !!! double a = vs.Length(); double b = vl.Length(); return max2(b/(a*a),a/(b*b)); } Point<3> EllipticCone :: GetSurfacePoint () const { return a + vl; } void EllipticCone :: GetTriangleApproximation (TriangleApproximation & tas, const Box<3> & boundingbox, double facets) const { int i, j; double lg, bg; int n = int(facets) + 1; Vec<3> nh = Cross(vl, vs); nh.Normalize(); Vec<3> vh = h*nh; double lvl = vl.Length(); double lvs = vs.Length(); Vec<3> nvl = (1.0/lvl)*vl; Vec<3> nvs = (1.0/lvs)*vs; for ( j = 0; j <= n; j++ ) for (i = 0; i <= n; i++) { lg = 2 *M_PI * double (i) /n; bg = double(j) /n; Point<3> p = a + (bg *vh) + (( lvl*(1 + (vlr -1)*bg) * cos(lg)) * nvl) + (( lvs*(1 + (vlr -1)*bg)* sin(lg) ) * nvs); 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, NgArray & 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 (NgArray & 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 (&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; } RegisterClassForArchive regqs; RegisterClassForArchive regpl; RegisterClassForArchive regsph; RegisterClassForArchive regcyl; RegisterClassForArchive regelcyl; RegisterClassForArchive regell; RegisterClassForArchive regcone; RegisterClassForArchive regellcone; RegisterClassForArchive regtorus; } ================================================ FILE: libsrc/csg/algprim.hpp ================================================ #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 & str) const; virtual void Read (istream & ist); void PrintCoeff (ostream & ost) const; virtual void DoArchive(Archive& ar) { OneSurfacePrimitive::DoArchive(ar); ar & cxx & cyy & czz & cxy & cxz & cyz & cx & cy & cz & c1; } }; /// A Plane (i.e., the plane and everything behind it). class Plane : public QuadraticSurface { protected: /// 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); // default constructor for archive Plane() {} virtual void DoArchive(Archive& ar) { QuadraticSurface::DoArchive(ar); ar & p & n & eps_base; } Point<3> P() const { return p; } Vec<3> N() const { return n; } virtual void GetPrimitiveData (const char *& classname, NgArray & coeffs) const; virtual void SetPrimitiveData (NgArray & coeffs); static Primitive * CreateDefault (); virtual Primitive * Copy () const; virtual void Print (ostream & str) 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); // default constructor for archive Sphere() {} virtual void DoArchive(Archive& ar) { QuadraticSurface::DoArchive(ar); ar & c & r & invr; } virtual void GetPrimitiveData (const char *& classname, NgArray & coeffs) const; virtual void SetPrimitiveData (NgArray & 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 (NgArray & coeffs); // default constructor for archive Cylinder() {} virtual void DoArchive(Archive& ar) { QuadraticSurface::DoArchive(ar); ar & a & b & r & vab; } Point<3> A() const { return a; } Point<3> B() const { return b; } double R() const { return r; } virtual void GetPrimitiveData (const char *& classname, NgArray & coeffs) const; virtual void SetPrimitiveData (NgArray & coeffs); static Primitive * CreateDefault (); virtual Primitive * Copy () const; virtual void Print (ostream & str) 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 (NgArray & coeffs); // default constructor for archive EllipticCylinder() {} virtual void DoArchive(Archive& ar) { QuadraticSurface::DoArchive(ar); ar & a & vl & vs & vab & t0vec & t1vec & vabl & t0 & t1; } // static Primitive * CreateDefault (); virtual void GetPrimitiveData (const char *& classname, NgArray & coeffs) const; virtual void SetPrimitiveData (NgArray & 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 int IsIdentic (const Surface & s2, int & inv, double eps) 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); // default constructor for archive Ellipsoid() {} void DoArchive(Archive& ar) override { QuadraticSurface::DoArchive(ar); ar & a & v1 & v2 & v3 & rmin; } /// INSOLID_TYPE BoxInSolid (const BoxSphere<3> & box) const override; /// double HesseNorm () const override; /// double MaxCurvature () const override; /// Point<3> GetSurfacePoint () const override; void GetTriangleApproximation (TriangleApproximation & tas, const Box<3> & bbox, double facets) const override; void GetPrimitiveData (const char *& classname, NgArray & coeffs) const override; void SetPrimitiveData (NgArray & coeffs) override; 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); /// // default constructor for archive Cone() {} virtual void DoArchive(Archive& ar) { QuadraticSurface::DoArchive(ar); ar & a & b & ra & rb & minr & vab & t0vec & t1vec & vabl & t0 & t1 & cosphi; } static Primitive * CreateDefault (); virtual void GetPrimitiveData (const char *& classname, NgArray & coeffs) const; virtual void SetPrimitiveData (NgArray & 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, const MeshingParameters & mparam, double hmax) const; /// virtual Point<3> GetSurfacePoint () const; virtual void GetTriangleApproximation (TriangleApproximation & tas, const Box<3> & bbox, double facets) const; private: void CalcData(); }; /// /// Elliptic Cone /// Josephat Kalezhi (kalezhi@cbu.ac.zm) /// February 21st, 2018 /// /// class EllipticCone : public QuadraticSurface { Point<3> a; Vec<3> vl, vs; double h, vlr; public: /// EllipticCone (const Point<3> & aa, const Vec<3> & avl, const Vec<3> & avs, double ah, double avlr); // default constructor for archive EllipticCone() {} virtual void DoArchive(Archive& ar) { QuadraticSurface::DoArchive(ar); ar & a & vl & vs & h & vlr; } static Primitive * CreateDefault (); virtual void GetPrimitiveData (const char *& classname, NgArray & coeffs) const; virtual void SetPrimitiveData (NgArray & coeffs); /// virtual INSOLID_TYPE BoxInSolid (const BoxSphere<3> & box) const; /// virtual double HesseNorm () const; virtual double MaxCurvature () const; virtual double MaxCurvatureLoc (const Point<3> & /* c */ , double /* rad */) 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); // default constructor for archive Torus() {} virtual void DoArchive(Archive& ar) { OneSurfacePrimitive::DoArchive(ar); ar & c & n & R & r; } /// 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, NgArray & coeffs) const; /// OK virtual void SetPrimitiveData (NgArray & 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 ================================================ FILE: libsrc/csg/brick.cpp ================================================ #include #include #include #include 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, NgArray & 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 (NgArray & 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 } }; NgArray 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)); } RegisterClassForArchive regpar; RegisterClassForArchive regbrick; RegisterClassForArchive regob; } ================================================ FILE: libsrc/csg/brick.hpp ================================================ #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); // default constructor for archive Parallelogram3d() {} virtual ~Parallelogram3d (); virtual void DoArchive(Archive& ar) { Surface::DoArchive(ar); ar & p1 & p2 & p3 & p4 & v12 & v13 & n; } 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; // NgArray faces; NgArray faces; public: Brick (Point<3> ap1, Point<3> ap2, Point<3> ap3, Point<3> ap4); // default constructor for archive Brick() {} virtual ~Brick (); virtual void DoArchive(Archive& ar) { Primitive::DoArchive(ar); ar & p1 & p2 & p3 & p4 & v12 & v13 & v14 & faces; } 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, NgArray & coeffs) const; virtual void SetPrimitiveData (NgArray & 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); // default constructor for archive OrthoBrick() {} virtual void DoArchive(Archive& ar) { Brick::DoArchive(ar); ar & pmin & pmax; } virtual INSOLID_TYPE BoxInSolid (const BoxSphere<3> & box) const; virtual void Reduce (const BoxSphere<3> & box); }; } #endif ================================================ FILE: libsrc/csg/bspline2d.cpp ================================================ #include #include 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; } } ================================================ FILE: libsrc/csg/csg.hpp ================================================ #ifndef FILE_CSG #define FILE_CSG /* *************************************************************************/ /* File: geoml.hpp */ /* Author: Joachim Schoeberl */ /* Date: 21. Jun. 98 */ /* *************************************************************************/ #include #include #include // #include #include "../gprim/spline.hpp" #include "../gprim/splinegeometry.hpp" #include "surface.hpp" #include "solid.hpp" #include "identify.hpp" #include "singularref.hpp" #include "splinesurface.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 ================================================ FILE: libsrc/csg/csgeom.cpp ================================================ #include #include #include #include #include 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(); } PointGeomInfo CSGeometry :: ProjectPoint(int surfind, Point<3> & p) const { Point<3> hp = p; GetSurface(surfind)->Project (hp); p = hp; return PointGeomInfo(); } bool CSGeometry :: ProjectPointGI(int surfind, Point<3> & p, PointGeomInfo & gi) const { GetSurface(surfind)->Project (p); return true; } void CSGeometry :: ProjectPointEdge(int surfind, INDEX surfind2, Point<3> & p, EdgePointGeomInfo* /*unused*/) const { Point<3> hp = p; ProjectToEdge (GetSurface(surfind), GetSurface(surfind2), hp); p = hp; } Vec<3> CSGeometry :: GetNormal(int surfind, const Point<3> & p, const PointGeomInfo* /*unused*/) const { Vec<3> hn; GetSurface(surfind)->CalcGradient(p, hn); hn.Normalize(); return hn; } void CSGeometry :: 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) { GetSurface (surfi) -> Project (hnewp); newgi.trignum = 1; } newp = hnewp; } void CSGeometry :: PointBetweenEdge(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 (GetSurface(surfi1), 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) { GetSurface (surfi1) -> Project (hnewp); //(*testout) << "hnewp (a2) " << hnewp << endl; } newp = hnewp; }; Vec<3> CSGeometry :: GetTangent(const Point<3> & p, int surfi1, int surfi2, const EdgePointGeomInfo & ap1) const { Vec<3> n1 = GetSurface (surfi1)->GetNormalVector (p); Vec<3> n2 = GetSurface (surfi2)->GetNormalVector (p); Vec<3> tau = Cross (n1, n2).Normalize(); return tau; } void CSGeometry :: Clean () { NgArray< 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]; solids.DeleteAll (); splinecurves2d.DeleteAll(); splinecurves3d.DeleteAll(); /* for (int i = 0; i < surfaces.Size(); i++) delete surfaces[i]; surfaces.DeleteAll (); */ for(int i = 0; i & mesh, MeshingParameters & mparam); int CSGeometry :: GenerateMesh (shared_ptr & mesh, MeshingParameters & mparam) { if(restricted_h.Size()) { // copy so that we don't change mparam outside MeshingParameters mp = mparam; for(const auto& [pnt, maxh] : restricted_h) mp.meshsize_points.Append({pnt, maxh}); return CSGGenerateMesh (*this, mesh, mp); } else return CSGGenerateMesh (*this, mesh, mparam); } 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; NgArray 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 (const filesystem::path & filename) const { ofstream 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[150]; int ncoeff, i, j; NgArray 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++) { snprintf (sname, size(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 :: DoArchive(Archive& archive) { archive & surfaces & solids & toplevelobjects & userpoints & userpoints_ref_factor & identpoints & boundingbox & isidenticto & ideps & filename & spline_surfaces & splinecurves2d & splinecurves3d & surf2prim; if(archive.Input()) FindIdenticSurfaces(1e-8 * MaxSize()); } 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; } NgArray coeffs; const char * classname; out << "csgsurfaces " << GetNSurf() << "\n"; for(int i=0; i (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)); const SplineSurface * splines = dynamic_cast (GetSurface(i)); if (splines) { splines->GetBase()->GetPrimitiveData(classname,coeffs); out << classname << " " << coeffs.Size() << "\n"; for (int j=0; jGetCuts())) { cut->GetPrimitiveData(classname,coeffs); out << classname << " " << coeffs.Size() << "\n"; for (int j=0; jGetPrimitiveData(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; 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> classname; in >> size; coeffs.SetSize(size); for(int j=0; j> 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 == "ellipsoid") { Ellipsoid * ellipsoid = new Ellipsoid(dummypoint,dummyvec,dummyvec,dummyvec); ellipsoid->SetPrimitiveData(coeffs); AddSurface(ellipsoid); delete_them.Append(ellipsoid); } else if(classname == "ellipticcone") { EllipticCone * ellipticcone = new EllipticCone(dummypoint,dummyvec,dummyvec,dummydouble,dummydouble); ellipticcone->SetPrimitiveData(coeffs); AddSurface(ellipticcone); delete_them.Append(ellipticcone); } 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[20]; snprintf (name, size(name), "nnsurf%d", cntsurfs); AddSurface (name, surf); } void CSGeometry :: AddSurface (char * name, Surface * surf) { (*testout) << "Adding surface " << name << ": " << (*surf) << 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[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[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[name]; else return NULL; } const Solid * CSGeometry :: GetSolid (const string & name) const { if (solids.Used(name)) return solids[name]; else return NULL; } void CSGeometry :: SetSplineCurve (const char * name, shared_ptr> spl) { splinecurves2d.Set(name,spl); } void CSGeometry :: SetSplineCurve (const char * name, shared_ptr> spl) { splinecurves3d.Set(name,spl); } shared_ptr> CSGeometry :: GetSplineCurve2d (const string & name) const { if (splinecurves2d.Used(name)) return splinecurves2d[name]; else return NULL; } shared_ptr> CSGeometry :: GetSplineCurve3d (const string & name) const { if (splinecurves3d.Used(name)) return splinecurves3d[name]; 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) { toplevelobjects.Append (new TopLevelObject (sol, surf)); return toplevelobjects.Size()-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[solidname]; NgArray 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")) { auto& bcname = flags.GetStringListFlag("bcname"); Polyhedra * polyh; if(solid->S1()) polyh = dynamic_cast(solid->S1()->GetPrimitive()); else polyh = dynamic_cast(solid->GetPrimitive()); if(polyh) { NgArray < NgArray * > 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 auto& bcnum = flags.GetNumListFlag("bc"); Polyhedra * polyh; if(solid->S1()) polyh = dynamic_cast(solid->S1()->GetPrimitive()); else polyh = dynamic_cast(solid->GetPrimitive()); if(polyh) { NgArray < NgArray * > 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(); identicsurfaces.DeleteData(); isidenticto.SetSize(nsurf); for (int i = 0; i < nsurf; i++) isidenticto[i] = i; for (int i = 0; i < nsurf; i++) for (int j = i+1; j < nsurf; j++) { if (GetSurface(j) -> IsIdentic (*GetSurface(i), inv, eps)) { INDEX_2 i2(i, j); identicsurfaces.Set (i2, inv); isidenticto[j] = isidenticto[i]; } } (*testout) << "identicmap:" << endl; for (int i = 0; i < isidenticto.Size(); i++) (*testout) << i << " -> " << isidenticto[i] << endl; } void CSGeometry :: GetSurfaceIndices (const Solid * sol, const BoxSphere<3> & box, NgArray & locsurf) const { ReducePrimitiveIterator rpi(box); UnReducePrimitiveIterator urpi; const_cast (sol) -> IterateSolid (rpi); sol -> GetSurfaceIndices (locsurf); const_cast (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, NgArray & 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, NgArray & 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 (NgArray & 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); NgArray 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 (const std::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] << ")" < surfused(GetNSurf()); ReducePrimitiveIterator rpi(box); UnReducePrimitiveIterator urpi; locsol -> IterateSolid (rpi); // locsol -> GetSurfaceIndices (lsurfi); // IndexSet iset(GetNSurf()); locsol -> GetSurfaceIndices (iset); const NgArray & 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; } class CSGeometryRegister : public GeometryRegister { public: virtual NetgenGeometry * Load (const filesystem::path & filename) const; virtual NetgenGeometry * LoadFromMeshFile (istream & ist, string token) const; // virtual VisualScene * GetVisualScene (const NetgenGeometry * geom) const; }; extern CSGeometry * ParseCSG (istream & istr, CSGeometry *instance=nullptr); NetgenGeometry * CSGeometryRegister :: Load (const filesystem::path & filename) const { string extension = filename.extension().string(); if (extension == ".geo") { PrintMessage (1, "Load CSG geometry file ", filename); ifstream infile(filename); CSGeometry * hgeom = ParseCSG (infile); if (!hgeom) throw NgException ("geo-file should start with 'algebraic3d'"); hgeom -> FindIdenticSurfaces(1e-8 * hgeom->MaxSize()); return hgeom; } if (extension == ".ngg") { PrintMessage (1, "Load new CSG geometry file ", filename); ifstream infile(filename); CSGeometry * hgeom = new CSGeometry(""); hgeom -> Load (infile); return hgeom; } return NULL; } NetgenGeometry * CSGeometryRegister :: LoadFromMeshFile (istream & ist, string token) const { if (token != "csgsurfaces") return nullptr; CSGeometry * geometry = new CSGeometry (""); geometry -> LoadSurfaces(ist); return geometry; } class CSGInit { public: CSGInit() { GeometryRegister().Append (new CSGeometryRegister); } }; CSGInit csginit; static RegisterClassForArchive regcsg; } ================================================ FILE: libsrc/csg/csgeom.hpp ================================================ #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 DLL_HEADER 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); // default constructor for archive TopLevelObject() {} void DoArchive(Archive& archive) { archive & solid & surface & red & blue & green & visible & transp & maxh & material & layer & bc & bcname; } 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 DLL_HEADER CSGeometry : public NetgenGeometry { private: /// all surfaces SymbolTable surfaces; public: /// primitive of surface NgArray surf2prim; private: NgArray delete_them; /// all named solids SymbolTable solids; /// all 2d splinecurves SymbolTable>> splinecurves2d; /// all 3d splinecurves SymbolTable>> splinecurves3d; /// all top level objects: solids and surfaces NgArray toplevelobjects; public: /// additional points specified by user class UserPoint : public Point<3> { int index; string name; public: UserPoint() = default; UserPoint (Point<3> p, int _index) : Point<3>(p), index(_index) { ; } UserPoint (Point<3> p, const string & _name) : Point<3>(p), index(-1), name(_name) { ; } int GetIndex() const { return index; } const string & GetName() const { return name; } void DoArchive(Archive& archive) { archive & index & name; Point<3>::DoArchive(archive); } }; private: // NgArray > userpoints; NgArray userpoints; NgArray userpoints_ref_factor; mutable NgArray > identpoints; /// triangular approximation of top level objects NgArray 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 identicsurfaces; NgArray isidenticto; /// identification of boundaries (periodic, thin domains, ...) double ideps; /// filename of inputfile string filename; /// store splinesurfaces, such that added ones do not get deleted before geometry does NgArray> spline_surfaces; shared_ptr solid_ball = Solid::ball; public: CSGeometry (); CSGeometry (const string & afilename); virtual ~CSGeometry (); void Clean (); virtual void Save (const filesystem::path & filename) const override; void Save (ostream & ost) const; void Load (istream & ist); void SaveSurfaces (ostream & out) const; void LoadSurfaces (istream & in); virtual void SaveToMeshFile (ostream & ost) const override; PointGeomInfo ProjectPoint(INDEX surfind, Point<3> & p) const override; bool ProjectPointGI (int surfind, Point<3> & p, PointGeomInfo & gi) const override; void ProjectPointEdge(INDEX surfind, INDEX surfind2, Point<3> & p, EdgePointGeomInfo* gi = nullptr) const override; Vec<3> GetNormal(int surfind, const Point<3> & p, const PointGeomInfo* gi = nullptr) const override; 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 override; void PointBetweenEdge(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 override; Vec<3> GetTangent (const Point<3> & p, int surfi1, int surfi2, const EdgePointGeomInfo & ap1) const override; 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 & GetSolids () const { return solids; } void SetSplineCurve (const char * name, shared_ptr> spl); void SetSplineCurve (const char * name, shared_ptr> spl); shared_ptr> GetSplineCurve2d (const string & name) const; shared_ptr> GetSplineCurve3d (const string & name) const; void DoArchive(Archive& archive) override; 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 (UserPoint(p,userpoints.Size()+1)); userpoints_ref_factor.Append (ref_factor); } void AddUserPoint (const UserPoint up, double ref_factor = 0) { userpoints.Append (up); userpoints_ref_factor.Append (ref_factor); } int GetNUserPoints () const { return userpoints.Size(); } const UserPoint & 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: NgArray singfaces; NgArray singedges; NgArray singpoints; NgArray 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, NgArray & locsurf) const; /// void GetIndependentSurfaceIndices (const Solid * sol, const BoxSphere<3> & box, NgArray & locsurf) const; /// /* void GetIndependentSurfaceIndices (const Solid * sol, const Point<3> & p, Vec<3> & v, NgArray & locsurf) const; */ /// void GetIndependentSurfaceIndices (NgArray & 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; }; NgArray bcmodifications; map, string> named_edges; virtual int GenerateMesh (shared_ptr & mesh, MeshingParameters & mparam) override; void AddSplineSurface (shared_ptr ss) { spline_surfaces.Append(ss); } }; } #endif ================================================ FILE: libsrc/csg/csgparser.cpp ================================================ #include #include #include #include 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_ELLIPTICCONE, "ellipticcone" }, { 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_ELLIPTICCONE: { Point<3> a; Vec<3> vl, vs; double h, vlr; scan.ReadNext(); scan >> '(' >> a >> ';' >> vl >> ';' >> vs >> ';' >> h >>';' >> vlr >> ')'; OneSurfacePrimitive * surf = new EllipticCone ( a, vl, vs, h, vlr ); 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) { NgArray 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; iAddFace(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; iAddSurfaces (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 (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 void LoadSpline (SplineGeometry & spline, CSGScanner & scan) { double hd; Point x; int nump, numseg; //scan.ReadNext(); scan >> nump >> ';'; hd = 1; spline.geompoints.SetSize(nump); for(int i = 0; i> x(0) >> ',' >> x(1) >> ';'; else if(D==3) scan >> x(0) >> ',' >> x(1) >> ',' >> x(2) >> ';'; spline.geompoints[i] = GeomPoint(x,hd); } scan >> numseg;// >> ';'; spline.splines.SetSize(numseg); int pnums,pnum1,pnum2,pnum3; for(int i = 0; i> ';' >> pnums >> ','; if (pnums == 2) { scan >> pnum1 >> ',' >> pnum2;// >> ';'; spline.splines[i] = new LineSeg(spline.geompoints[pnum1-1], spline.geompoints[pnum2-1]); } else if (pnums == 3) { scan >> pnum1 >> ',' >> pnum2 >> ',' >> pnum3;// >> ';'; spline.splines[i] = new SplineSeg3(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(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 vals; vals.Append (ParseNumber(scan)); while (scan.GetToken() == ',') { scan.ReadNext(); vals.Append (ParseNumber(scan)); } ParseChar (scan, ']'); flags.SetFlag (name, vals); } else { // string list Array vals; vals.Append(scan.GetStringValue()); scan.ReadNext(); while (scan.GetToken() == ',') { scan.ReadNext(); vals.Append(scan.GetStringValue()); scan.ReadNext(); } ParseChar (scan, ']'); flags.SetFlag (name, vals); } } else if (scan.GetToken() == TOK_NUM) { flags.SetFlag (name.c_str(), scan.GetNumValue()); scan.ReadNext(); } } else { flags.SetFlag (name.c_str()); } } } /* Main parsing function for CSG geometry */ CSGeometry * ParseCSG (istream & istr, CSGeometry * instance=nullptr) { CSGScanner scan(istr); if (instance) { new (instance) CSGeometry; geom = instance; } else 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 & 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, ';'); NgArray 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 auto& col = flags.GetNumListFlag ("col"); tlo->SetRGB (col[0], col[1], col[2]); } 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, ';'); NgArray 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, ';'); NgArray 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, '('); auto newspline = make_shared>(); // 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, '('); auto newspline = make_shared>(); // 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; NgArray 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; NgArray 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); */ } }; ================================================ FILE: libsrc/csg/csgparser.hpp ================================================ #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_ELLIPTICCONE, 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 ================================================ FILE: libsrc/csg/csgpkg.cpp ================================================ #include #include #include #include #include #include #include "vscsg.hpp" extern "C" int Ng_CSG_Init (Tcl_Interp * interp); namespace netgen { extern DLL_HEADER shared_ptr ng_geometry; extern DLL_HEADER shared_ptr mesh; static VisualSceneGeometry vsgeom; char * err_needscsgeometry = (char*) "This operation needs an CSG geometry"; char * err_needsmesh = (char*) "This operation needs a mesh"; char * err_jobrunning = (char*) "Meshing Job already running"; int Ng_ParseGeometry (ClientData clientData, Tcl_Interp * interp, int argc, tcl_const char *argv[]) { CSGeometry * csgeom = dynamic_cast (ng_geometry.get()); 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 (ng_geometry.get()); 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(); snprintf (buf, size(buf), "%5.1lf", pmin.X()); Tcl_SetVar (interp, "::geooptions.minx", buf, 0); snprintf (buf, size(buf), "%5.1lf", pmin.Y()); Tcl_SetVar (interp, "::geooptions.miny", buf, 0); snprintf (buf, size(buf), "%5.1lf", pmin.Z()); Tcl_SetVar (interp, "::geooptions.minz", buf, 0); snprintf (buf, size(buf), "%5.1lf", pmax.X()); Tcl_SetVar (interp, "::geooptions.maxx", buf, 0); snprintf (buf, size(buf), "%5.1lf", pmax.Y()); Tcl_SetVar (interp, "::geooptions.maxy", buf, 0); snprintf (buf, size(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 (ng_geometry.get()); 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 (ng_geometry.get()); if (!geometry) { Tcl_SetResult (interp, err_needscsgeometry, TCL_STATIC); return TCL_ERROR; } tcl_const char * name = argv[1]; tcl_const char * value = argv[2]; NgArray 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 (ng_geometry.get()); 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 (ng_geometry.get()); 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; NgArray 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 (ng_geometry.get()); 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 (ng_geometry.get()); 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 (ng_geometry.get()); 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 (ng_geometry.get()); 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 (ng_geometry.get()); 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]; snprintf (varname, size(varname), "%s(red)", propvar); double red = atof (Tcl_GetVar (interp, varname, 0)); snprintf (varname, size(varname), "%s(blue)", propvar); double blue = atof (Tcl_GetVar (interp, varname, 0)); snprintf (varname, size(varname), "%s(green)", propvar); double green = atof (Tcl_GetVar (interp, varname, 0)); tlo -> SetRGB (red, green, blue); snprintf (varname, size(varname), "%s(visible)", propvar); tlo -> SetVisible (bool(atoi (Tcl_GetVar (interp, varname, 0)))); snprintf (varname, size(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]; snprintf (varname, size(varname), "%s(red)", propvar); snprintf (varval, size(varval), "%lf", tlo->GetRed()); Tcl_SetVar (interp, varname, varval, 0); snprintf (varname, size(varname), "%s(green)", propvar); snprintf (varval, size(varval), "%lf", tlo->GetGreen()); Tcl_SetVar (interp, varname, varval, 0); snprintf (varname, size(varname), "%s(blue)", propvar); snprintf (varval, size(varval), "%lf", tlo->GetBlue()); Tcl_SetVar (interp, varname, varval, 0); snprintf (varname, size(varname), "%s(visible)", propvar); snprintf (varval, size(varval), "%d", tlo->GetVisible()); Tcl_SetVar (interp, varname, varval, 0); snprintf (varname, size(varname), "%s(transp)", propvar); snprintf (varval, size(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 (ng_geometry.get()); if (!geometry) { Tcl_SetResult (interp, err_needscsgeometry, TCL_STATIC); return TCL_ERROR; } if (!mesh) { 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, 1e99 /* globh*/); return TCL_OK; } int Ng_SingularPointMS (ClientData clientData, Tcl_Interp * interp, int argc, tcl_const char *argv[]) { CSGeometry * geometry = dynamic_cast (ng_geometry.get()); 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, 1e99 /* 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 CSGeometryVisRegister : public GeometryRegister { public: virtual NetgenGeometry * Load (const filesystem::path & filename) const { return NULL; } virtual VisualScene * GetVisualScene (const NetgenGeometry * geom) const; }; VisualScene * CSGeometryVisRegister :: GetVisualScene (const NetgenGeometry * geom) const { const CSGeometry * geometry = dynamic_cast (geom); if (geometry) { vsgeom.SetGeometry (const_cast(geometry)); return &vsgeom; } return NULL; } } using namespace netgen; int Ng_CSG_Init (Tcl_Interp * interp) { GeometryRegister().Append(new CSGeometryVisRegister); if (interp == NULL) return TCL_OK; 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; } ================================================ FILE: libsrc/csg/curve2d.cpp ================================================ #include #include #include 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(); } } ================================================ FILE: libsrc/csg/curve2d.hpp ================================================ #ifndef FILE_CURVE2D #define FILE_CURVE2D /**************************************************************************/ /* File: curve2d.hh */ /* Author: Joachim Schoeberl */ /* Date: 24. Jul. 96 */ /**************************************************************************/ namespace netgen { /* 2D Curve representation */ /// 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 ================================================ FILE: libsrc/csg/edgeflw.cpp ================================================ #include #include #include // #undef DEVELOP // #define DEVELOP namespace netgen { EdgeCalculation :: EdgeCalculation (const CSGeometry & ageometry, NgArray & aspecpoints, MeshingParameters & amparam) : geometry(ageometry), specpoints(aspecpoints), mparam(amparam) { 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 (PointIndex pi : mesh.Points().Range()) meshpoint_tree->Insert (mesh[pi], pi); // add all special points before edge points (important for periodic identification) // JS, Jan 2007 const double di=1e-7*geometry.MaxSize(); NgArray 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) { NgArray hsp(specpoints.Size()); NgArray glob2hsp(specpoints.Size()); NgArray startpoints, endpoints; int pos, ep; int layer; Point<3> p, np; int pi1, s1, s2, s1_orig, s2_orig; NgArray > edgepoints; NgArray curvelength; int copyedge = 0, copyfromedge = -1, copyedgeidentification = -1; NgArray 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 identification_used(100); // identification i already used for startpoint j mesh.GetIdentifications().Delete(); TABLE 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 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 " <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; // identifiable 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]->IdentifiableCandidate (specpoints[startpoints[j]]) && geometry.identifications[i]->IdentifiableCandidate (specpoints[endpoints[j]])) { int pi1cand = 0; double mindist = 1e10; for (int k = 0; k < hsp.Size() && !pi1; k++) { //(*testout) << " ? identifiable 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] ->Identifiable(specpoints[startpoints[j]], specpoints[hsp[k]], specpoint2tlo, specpoint2surface) || geometry.identifications[i] ->Identifiable(specpoints[hsp[k]], specpoints[startpoints[j]], specpoint2tlo, specpoint2surface)) { #ifdef DEVELOP (*testout) << "identifiable: " << 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 edge ? 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--; } */ } NgArray refedges; NgArray 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; refedges[i].index = 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); } { // named edge ? // cout << "check edge name, size = " << geometry.named_edges.size() << endl; // for (auto pair : geometry.named_edges) // cout << "key = " << get<0> (pair.first) << "-" << get<1> (pair.first) << ", val = " << pair.second << endl; Surface * sp1 = const_cast (geometry.GetSurface(s1)); Surface * sp2 = const_cast (geometry.GetSurface(s2)); // cout << "sp1 = " << sp1 << ", sp2 = " << sp2 << endl; auto ptr = geometry.named_edges.find(tuple(sp1, sp2)); if (ptr != geometry.named_edges.end()) for (int i = 0; i < refedges.Size(); i++) mesh.SetCD2Name(refedges[i].edgenr, ptr->second); ptr = geometry.named_edges.find(tuple(sp2, sp1)); if (ptr != geometry.named_edges.end()) for (int i = 0; i < refedges.Size(); i++) mesh.SetCD2Name(refedges[i].edgenr, ptr->second); } for(int i=0; i(geometry.GetSurface(refedges[i].surfnr1)); if(splinesurface) { auto name = splinesurface->GetBCNameOf(specpoints[startpoints.Get(refedges[i].edgenr)].p,specpoints[endpoints.Get(refedges[i].edgenr)].p); mesh.SetCD2Name(refedges[i].edgenr,name); } else { auto splinesurface2 = dynamic_cast(geometry.GetSurface(refedges[i].surfnr2)); if(splinesurface2) { auto name = splinesurface2->GetBCNameOf(specpoints[startpoints.Get(refedges[i].edgenr)].p,specpoints[endpoints.Get(refedges[i].edgenr)].p); mesh.SetCD2Name(refedges[i].edgenr,name); } } } /* // 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 osedges(cntedge); INDEX_2_HASHTABLE 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++) { PointIndices<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 (PointIndex pi = IndexBASE(); pi < mesh.GetNP()+IndexBASE(); 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(PointIndex(i2.I1())) << " - " << mesh.Point(PointIndex(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++) for (Segment & seg : mesh.LineSegments()) { // 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 NgArray & hsp, double h, const Mesh & mesh, NgArray > & edgepoints, NgArray & curvelength) { int s1, s2, s1_rep, s2_rep; double len, steplen, cursteplen, loch; Point<3> p, np, pnp; Vec<3> a1, a2, t; NgArray 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, mparam, h), geometry.GetSurface(s2) -> LocH (p, 3, 1, mparam, 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, mparam, h), geometry.GetSurface(s2_rep) -> LocH (np, 3, 1, mparam, 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 NgArray > & edgepoints, NgArray & refedges, NgArray & refedgesinv) { Segment seg; NgArray locsurfind, locsurfind2; NgArray 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); auto locsol = sol -> TangentialSolid (hp, 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 -> 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); 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; ArrayMem pre_ok(2); bool flip = false; do { eps *= 0.5; auto in00 = locsol -> VectorIn2 (hp, m, n, eps); auto in01 = locsol -> VectorIn2 (hp, m, -1. * n, eps); pre_ok[0] = in00 == IS_OUTSIDE && in01 == IS_INSIDE; if(in00 == IS_INSIDE && in01 == IS_OUTSIDE) pre_ok[0] = flip = true; auto in10 = locsol -> VectorIn2 (hp, -1.*m, n, eps); auto in11 = locsol -> VectorIn2 (hp, -1.*m, -1. * n, eps); pre_ok[1] = (in10 == IS_OUTSIDE && in11 == IS_INSIDE); if(in10 == IS_INSIDE && in11 == IS_OUTSIDE) pre_ok[1] = flip = true; if (debug) { *testout << "eps = " << eps << endl; *testout << "in,1 = " << in00 << endl; *testout << "in,1 = " << in01 << endl; *testout << "in,1 = " << in10 << endl; *testout << "in,1 = " << in11 << 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; auto locsol2 = locsol -> TangentialSolid3 (hp, m, m2, 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; refedges.Append (seg); hi = refedges.Size(); 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) { bool inside = sameasref; if(flip) inside = !inside; if (inside) refedges.Elem(hi).domin = i; else refedges.Elem(hi).domout = i; } else { refedges.Elem(hi).tlosurf = i; for(int kk = 0; kk < geometry.GetNTopLevelObjects(); kk++) { auto othersolid = geometry.GetTopLevelObject(kk)->GetSolid(); auto othersurf = geometry.GetTopLevelObject(kk)->GetSurface(); if(!othersurf && dynamic_cast(othersurf)) { if(othersolid->IsIn(edgepoints[0]) && othersolid->IsIn(edgepoints[edgepoints.Size()-1])) { refedges.Elem(hi).domin = kk; refedges.Elem(hi).domout = kk; } } } } 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; } if(refedges.Size() == 0) throw Exception("No edges found, something wrong."); NgBitArray todelete(refedges.Size()); todelete.Clear(); for(int i=0; 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 NgArray & refedges, const NgArray & refedgesinv, const NgArray > & edgepoints, const NgArray & 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 = PointIndex::INVALID; /* for (pi = IndexBASE(); pi < mesh.GetNP()+IndexBASE(); pi++) if (Dist (mesh[pi], p) < 1e-6) { lastpi = pi; break; } */ const double di=1e-7*geometry.MaxSize(); NgArray 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.IsValid()) { 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 = PointIndex::INVALID; if (i == ne) { /* for (pi = IndexBASE(); pi < mesh.GetNP()+IndexBASE(); 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.IsValid()) { 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.index = refedges.Get(k).index; 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 NgArray & refedges, const NgArray & refedgesinv, const NgArray > & edgepoints, const NgArray & 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 = PointIndex::INVALID; for (PointIndex pi = IndexBASE(); pi < mesh.GetNP()+IndexBASE(); pi++) if (Dist (mesh[pi], p) < 1e-6*geometry.MaxSize()) { pi1 = pi; break; } if (!pi1.IsValid()) { pi1 = mesh.AddPoint (p, layer, FIXEDPOINT); meshpoint_tree -> Insert (p, pi1); // (*testout) << "test3, store point " << pi1 << ", p = " << p << endl; } p = edgepoints.Last(); PointIndex pi2 = PointIndex::INVALID; for (pi = IndexBASE(); pi < mesh.GetNP()+IndexBASE(); pi++) if (Dist (mesh[pi], p) < 1e-6*geometry.MaxSize()) { pi2 = pi; break; } if (!pi2.IsValid()) { 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.index = refedges.Get(k).index; 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 NgArray & refedges, const NgArray & 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 = PointIndex::INVALID; PointIndex topi = PointIndex::INVALID; for (PointIndex pi = IndexBASE(); pi < mesh.GetNP()+IndexBASE(); pi++) { if (Dist2 (mesh[pi], fromp) <= 1e-16*size) frompi = pi; if (Dist2 (mesh[pi], top) <= 1e-16*size) topi = pi; } if (!topi.IsValid()) { topi = mesh.AddPoint (top, layer, FIXEDPOINT); meshpoint_tree -> Insert (top, topi); } const Identification & csi = (*geometry.identifications.Get(copyedgeidentification)); if (csi.Identifiable (mesh[frompi], mesh[topi])) mesh.GetIdentifications().Add(frompi, topi, copyedgeidentification); else if (csi.Identifiable (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; PointIndex pi1 = oldseg[0]; PointIndex pi2 = oldseg[1]; PointIndex npi1 = geometry.identifications.Get(copyedgeidentification) -> GetIdentifiedPoint (mesh, pi1); PointIndex 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.index = refedges.Get(k).index; 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 nsurf = geometry.GetNSurf(); int layer = 0; // Solid * tansol; NgArray tansurfind; double size = geometry.MaxSize(); int nsol = geometry.GetNTopLevelObjects(); NgBitArray pointatsurface (nsurf); pointatsurface.Clear(); for (int i = 1; i <= mesh.GetNSeg(); i++) { const Segment & seg = mesh.LineSegment(i); #ifdef DEVELOP (*testout) << seg.surfnr1 << ", " << seg.surfnr2 << ", si = " << seg.si << endl; #endif int classrep = geometry.GetSurfaceClassRepresentant (seg.si); pointatsurface.Set (classrep); } for (int i = 0; i < nsurf; i++) { int classrep = geometry.GetSurfaceClassRepresentant (i); if (!pointatsurface.Test(classrep)) { const Surface * s = geometry.GetSurface(i); Point<3> p1 = s -> GetSurfacePoint(); Vec<3> nv = s -> GetNormalVector (p1); double hloc = min2 (s->LocH (p1, 3, 1, mparam, h), mesh.GetH(p1)); 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 (int 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); auto tansol = sol -> TangentialSolid (p1, tansurfind, ideps*size); layer = geometry.GetTopLevelObject(j)->GetLayer(); if (tansol) { tansol -> GetSurfaceIndices (tansurfind); if (tansurfind.Size() == 1 && tansurfind.Get(1) == i) { hloc = min2 (hloc, geometry.GetTopLevelObject(j)->GetMaxH()); if (!tansol->VectorIn(p1, nv)) { seg1.domin = j; seg2.domin = j; seg1.tlosurf = -1; seg2.tlosurf = -1; } else { seg1.domout = j; seg2.domout = j; seg1.tlosurf = -1; seg2.tlosurf = -1; } // seg.s2 = i; // seg.invs1 = surfaces[i] -> Inverse(); // seg.invs2 = ! (surfaces[i] -> Inverse()); } // delete tansol; } } Vec<3> tv = nv.GetNormal (); tv *= (hloc / tv.Length()); Point<3> p2 = p1 + tv; s->Project (p2); if (seg1.domin != -1 || seg1.domout != -1) { seg1[0] = mesh.AddPoint (p1, layer, EDGEPOINT); seg1[1] = mesh.AddPoint (p2, layer, EDGEPOINT); seg2[0] = seg1[1]; seg2[1] = seg1[0]; 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 } } } } } ================================================ FILE: libsrc/csg/edgeflw.hpp ================================================ #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 NgArray & specpoints, double h, Mesh & mesh); class EdgeCalculation { const CSGeometry & geometry; NgArray & specpoints; Point3dTree * searchtree; Point3dTree * meshpoint_tree; int cntedge; double ideps; MeshingParameters & mparam; public: EdgeCalculation (const CSGeometry & ageometry, NgArray & aspecpoints, MeshingParameters & amparam); ~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 NgArray & hsp, const NgArray & hsp, double h, const Mesh & mesh, NgArray > & edgepoints, NgArray & curvelength); void AnalyzeEdge (int s1, int s2, int s1_rep, int s2_rep, int pos, int layer, const NgArray > & edgepoints, NgArray & refedges, NgArray & refedgesinv); void StoreEdge (const NgArray & refedges, const NgArray & refedgesinv, const NgArray > & edgepoints, const NgArray & curvelength, int layer, Mesh & mesh); void StoreShortEdge (const NgArray & refedges, const NgArray & refedgesinv, const NgArray > & edgepoints, const NgArray & curvelength, int layer, Mesh & mesh); void CopyEdge (const NgArray & refedges, const NgArray & 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 ================================================ FILE: libsrc/csg/explicitcurve2d.cpp ================================================ #include #include 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; } } ================================================ FILE: libsrc/csg/explicitcurve2d.hpp ================================================ #ifndef FILE_EXPLICITCURVE2D #define FILE_EXPLICITCURVE2D /**************************************************************************/ /* File: explicitcurve2d.hh */ /* Author: Joachim Schoeberl */ /* Date: 14. Oct. 96 */ /**************************************************************************/ namespace netgen { /* Explicit 2D Curve representation */ /// 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 { /// NgArray > points; /// NgArray 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 ================================================ FILE: libsrc/csg/extrusion.cpp ================================================ #include #include #include #include namespace netgen { NgArray > 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; iGetNSplines(); 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; } } double cum_angle = 0.; for(auto i : Range(path->GetSplines())) { const auto& sp = path->GetSpline(i); auto t1 = sp.GetTangent(0.); t1.Normalize(); auto t2 = sp.GetTangent(1.); t2.Normalize(); cum_angle += acos(t1 * t2); angles.Append(cum_angle); } 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 NgArray & raw_data) { deletable = true; int pos=0; NgArray< Point<2> > p(3); int ptype = int(raw_data[pos]); pos++; for(int i=0; i(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(&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 { static mutex set_latest_point; auto eps = 1e-25 * Dist2(path->GetSpline(0).StartPI(), path->GetSpline(0).EndPI()); if (Dist2 (point3d, latest_point3d) < eps) { std::lock_guard guard(set_latest_point); if (Dist2 (point3d, latest_point3d) < eps) { point2d = latest_point2d; seg = latest_seg; t = latest_t; return; } } double cutdist = -1; NgArray 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; iGetNSplines(); i++) { if(mindist[i] > cutdist*(1+1e-10)) 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; } } std::lock_guard guard(set_latest_point); latest_seg = seg; latest_t = t; latest_point2d = point2d; latest_point3d = point3d; } 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; iGetNSplines(); 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()); } bool ExtrusionFace :: PointInFace (const Point<3> & p, const double eps) const { Point<3> hp = p; Project(hp); return Dist2(p,hp) < sqr(eps); } 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)); NgArray < 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 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(NgArray & 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; } void ExtrusionFace :: DefineTangentialPlane(const Point<3>& ap1, const Point<3>& ap2) { Surface::DefineTangentialPlane(ap1, ap2); tangential_plane_seg = latest_seg; } void ExtrusionFace :: ToPlane(const Point<3>& p3d, Point<2>& p2d, double h, int& zone) const { Surface::ToPlane(p3d, p2d, h, zone); double angle = angles[tangential_plane_seg] - angles[latest_seg]; if(fabs(angle) > 3.14/2.) zone = -1; } Extrusion :: Extrusion(shared_ptr> path_in, shared_ptr> 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; jGetNSplines(); j++) { ExtrusionFace * face = new ExtrusionFace(&(profile->GetSpline(j)), path.get(), z_direction); faces.Append(face); surfaceactive.Append(true); surfaceids.Append(0); } } Extrusion :: ~Extrusion() { for(int i=0; i & box) const { for(int i=0; iBoxIntersectsFace(box)) return DOES_INTERSECT; } return PointInSolid(box.Center(),0); } INSOLID_TYPE Extrusion :: PointInSolid (const Point<3> & p, const double eps, NgArray * 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; iLineIntersections(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); } void Extrusion :: GetTangentialSurfaceIndices (const Point<3> & p, NgArray & surfind, double eps) const { for (int j = 0; j < faces.Size(); j++) if (faces[j] -> PointInFace(p, eps)) if (!surfind.Contains (GetSurfaceId(j))) surfind.Append (GetSurfaceId(j)); } INSOLID_TYPE Extrusion :: VecInSolid (const Point<3> & p, const Vec<3> & v, double eps) const { NgArray 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,eps); 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; } RegisterClassForArchive regexf; RegisterClassForArchive regextr; } ================================================ FILE: libsrc/csg/extrusion.hpp ================================================ #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; Array angles; bool deletable; int tangential_plane_seg; NgArray< const SplineSeg3<3> * > spline3_path; NgArray< const LineSeg<3> * > line_path; mutable NgArray < Vec<3> > x_dir, y_dir, z_dir, loc_z_dir; mutable NgArray < 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 NgArray & raw_data); // default constructor for archive ExtrusionFace() {} ~ExtrusionFace(); void DoArchive(Archive& ar) override { Surface::DoArchive(ar); ar & profile & path & glob_z_direction & deletable & spline3_path & line_path & x_dir & y_dir & z_dir & loc_z_dir & p0 & profile_tangent & profile_par & profile_spline_coeff & latest_seg & latest_t & latest_point2d & latest_point3d; } int IsIdentic (const Surface & s2, int & inv, double eps) const override; double CalcFunctionValue (const Point<3> & point) const override; void CalcGradient (const Point<3> & point, Vec<3> & grad) const override; void CalcHesse (const Point<3> & point, Mat<3> & hesse) const override; double HesseNorm () const override; double MaxCurvature () const override; //virtual double MaxCurvatureLoc (const Point<3> & /* c */ , // double /* rad */) const; void Project (Point<3> & p) const override; Point<3> GetSurfacePoint () const override; void Print (ostream & str) const override; void GetTriangleApproximation (TriangleApproximation & tas, const Box<3> & boundingbox, double facets) const override; 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; bool PointInFace (const Point<3> & p, const double eps) 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(NgArray & 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; void DefineTangentialPlane(const Point<3>& ap1, const Point<3>& ap2) override; void ToPlane(const Point<3>& p3d, Point<2>& p2d, double h, int& zone) const override; }; class Extrusion : public Primitive { private: shared_ptr> path; shared_ptr> profile; // closed, clockwise oriented curve Vec<3> z_direction; NgArray faces; mutable int latestfacenum; public: Extrusion(shared_ptr> path_in, shared_ptr> profile_in, const Vec<3> & z_dir); // default constructor for archive Extrusion() {} ~Extrusion(); void DoArchive(Archive& ar) override { Primitive::DoArchive(ar); ar & path & profile & z_direction & faces & latestfacenum; } INSOLID_TYPE BoxInSolid (const BoxSphere<3> & box) const override; INSOLID_TYPE PointInSolid (const Point<3> & p, double eps) const override; INSOLID_TYPE PointInSolid (const Point<3> & p, double eps, NgArray * const facenums) const; void GetTangentialSurfaceIndices (const Point<3> & p, NgArray & surfind, double eps) const override; INSOLID_TYPE VecInSolid (const Point<3> & p, const Vec<3> & v, double eps) const override; // checks if lim s->0 lim t->0 p + t(v1 + s v2) in solid INSOLID_TYPE VecInSolid2 (const Point<3> & p, const Vec<3> & v1, const Vec<3> & v2, double eps) const override; int GetNSurfaces() const override; Surface & GetSurface (int i = 0) override; const Surface & GetSurface (int i = 0) const override; void Reduce (const BoxSphere<3> & box) override; void UnReduce () override; }; } #endif //_EXTRUSION_HPP ================================================ FILE: libsrc/csg/gencyl.cpp ================================================ #include #include 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); } } ================================================ FILE: libsrc/csg/gencyl.hpp ================================================ #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 ================================================ FILE: libsrc/csg/genmesh.cpp ================================================ #include #include #include #include #include namespace netgen { DLL_HEADER NgArray global_specpoints; // for visualization //static NgArray spoints; #define TCL_OK 0 #define TCL_ERROR 1 static void FindPoints (CSGeometry & geom, NgArray & specpoints, NgArray & spoints, Mesh & mesh) { PrintMessage (1, "Start Findpoints"); const char * savetask = multithread.task; multithread.task = "Find points"; mesh.pointelements.SetSize(0); for (int i = 0; i < geom.GetNUserPoints(); i++) { auto up = geom.GetUserPoint(i); auto pnum = mesh.AddPoint(up); mesh.Points().Last().Singularity (geom.GetUserPointRefFactor(i)); mesh.AddLockedPoint (pnum); int index = up.GetIndex(); if (index == -1) index = mesh.AddCD3Name (up.GetName())+1; // cout << "adding 0d element, pnum = " << pnum << ", material index = " << index << endl; mesh.pointelements.Append (Element0d(pnum, index)); } SpecialPointCalculation spc; spc.SetIdEps(geom.GetIdEps()); if (spoints.Size() == 0) spc.CalcSpecialPoints (geom, spoints); PrintMessage (2, "Analyze spec points"); spc.AnalyzeSpecialPoints (geom, spoints, specpoints); { static mutex mut; lock_guard guard(mut); global_specpoints = 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, NgArray & specpoints, NgArray & spoints, MeshingParameters & mparam, const bool setmeshsize = false) { EdgeCalculation ec (geom, specpoints, mparam); 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; } for(int k = 1; k<=mesh.GetNFD(); k++) { *testout << "face: " << k << endl << "FD: " << mesh.GetFaceDescriptor(k) << 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); BoxTree<3> 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); } } NgArray 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, MeshingParameters & mparam) { const char * savetask = multithread.task; multithread.task = "Surface meshing"; NgArray segments; int noldp = mesh.GetNP(); double starttime = GetTime(); // find master faces from identified NgArray masterface(mesh.GetNFD()); for (int i = 1; i <= mesh.GetNFD(); i++) masterface.Elem(i) = i; NgArray 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 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(geom, *surf, mparam, geom.BoundingBox()); meshing.SetStartTime (starttime); double eps = 1e-8 * geom.MaxSize(); for (PointIndex pi = IndexBASE(); pi < noldp+IndexBASE(); 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 " < BuildSurfaceElements(segments, mesh, surf); } for (int si = 0; si < segments.Size(); si++) { PointGeomInfo gi; gi.trignum = k; meshing.AddBoundaryElement (segments[si][0] + 1 - IndexBASE(), segments[si][1] + 1 - IndexBASE(), 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); auto n_illegal_trigs = mesh.FindIllegalTrigs(); PrintMessage (3, n_illegal_trigs, " illegal triangles"); // 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; { MeshOptimize2d meshopt(mesh); meshopt.SetFaceIndex (k); meshopt.SetImproveEdges (0); meshopt.SetMetricWeight (mparam.elsizeweight); meshopt.SetWriteStatus (0); meshopt.EdgeSwapping (i > mparam.optsteps2d/2); } if (multithread.terminate) return; { // mesh.CalcSurfacesOfNode(); MeshOptimize2d meshopt(mesh); meshopt.SetFaceIndex (k); meshopt.SetImproveEdges (0); meshopt.SetMetricWeight (mparam.elsizeweight); meshopt.SetWriteStatus (0); meshopt.ImproveMesh(mparam); } { MeshOptimize2d meshopt(mesh); meshopt.SetFaceIndex (k); meshopt.SetImproveEdges (0); meshopt.SetMetricWeight (mparam.elsizeweight); meshopt.SetWriteStatus (0); meshopt.CombineImprove(); // mesh.CalcSurfacesOfNode(); } if (multithread.terminate) return; { MeshOptimize2d meshopt(mesh); meshopt.SetFaceIndex (k); meshopt.SetImproveEdges (0); meshopt.SetMetricWeight (mparam.elsizeweight); meshopt.SetWriteStatus (0); meshopt.ImproveMesh(mparam); } } } PrintMessage (3, (mesh.GetNSE() - oldnf), " elements, ", mesh.GetNP(), " points"); mparam.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"); } mparam.Render(); } while (changed); mesh.SplitSeparatedFaces(); mesh.CalcSurfacesOfNode(); multithread.task = savetask; } int CSGGenerateMesh (CSGeometry & geom, shared_ptr & mesh, MeshingParameters & mparam) { NgArray specpoints; NgArray spoints; if (mesh && mesh->GetNSE() && !geom.GetNSolids()) { if (mparam.perfstepsstart < MESHCONST_MESHVOLUME) mparam.perfstepsstart = MESHCONST_MESHVOLUME; } if (mparam.perfstepsstart <= MESHCONST_ANALYSE) { if (mesh) mesh -> DeleteMesh(); else mesh = make_shared(); mesh->SetGlobalH (mparam.maxh); mesh->SetMinimalH (mparam.minh); NgArray 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); for (auto mspnt : mparam.meshsize_points) mesh -> RestrictLocalH (mspnt.pnt, mspnt.h, mspnt.layer); } spoints.SetSize(0); FindPoints (geom, specpoints, spoints, *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 || mparam.perfstepsend <= MESHCONST_ANALYSE) return TCL_OK; if (mparam.perfstepsstart <= MESHCONST_MESHEDGES) { FindEdges (geom, *mesh, specpoints, spoints, mparam, 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, specpoints, spoints, *mesh); if (multithread.terminate) return TCL_OK; FindEdges (geom, *mesh, specpoints, spoints, mparam, true); if (multithread.terminate) return TCL_OK; mesh->DeleteMesh(); FindPoints (geom, specpoints, spoints, *mesh); if (multithread.terminate) return TCL_OK; FindEdges (geom, *mesh, specpoints, spoints, mparam); if (multithread.terminate) return TCL_OK; } } if (multithread.terminate || mparam.perfstepsend <= MESHCONST_MESHEDGES) return TCL_OK; if (mparam.perfstepsstart <= MESHCONST_MESHSURFACE) { MeshSurface (geom, *mesh, mparam); 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) { mesh->CalcLocalH(mparam.grading); mesh->DeleteMesh(); FindPoints (geom, *mesh); if (multithread.terminate) return TCL_OK; FindEdges (geom, *mesh, mparam); if (multithread.terminate) return TCL_OK; MeshSurface (geom, *mesh, mparam); 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 || mparam.perfstepsend <= MESHCONST_OPTSURFACE) return TCL_OK; if (mparam.perfstepsstart <= MESHCONST_MESHVOLUME) { multithread.task = "Volume meshing"; for (int i = 0; i < geom.GetNTopLevelObjects(); i++) mesh->SetMaterial (i+1, geom.GetTopLevelObject(i)->GetMaterial().c_str()); MESHING3_RESULT res = MeshVolume (mparam, *mesh); if (res != MESHING3_OK) return TCL_ERROR; if (multithread.terminate) return TCL_OK; RemoveIllegalElements (*mesh); if (multithread.terminate) return TCL_OK; MeshQuality3d (*mesh); #ifdef STAT_STREAM (*statout) << GetTime() << " & "; #endif #ifdef LOG_STREAM (*logout) << "Volume meshed" << endl << "time = " << GetTime() << " sec" << endl << "points: " << mesh->GetNP() << endl; #endif } if (multithread.terminate || mparam.perfstepsend <= MESHCONST_MESHVOLUME) return TCL_OK; if (mparam.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 } mesh -> OrderElements(); return TCL_OK; } } ================================================ FILE: libsrc/csg/geoml.hpp ================================================ #ifndef FILE_GEOML #define FILE_GEOML /* *************************************************************************/ /* File: geoml.hh */ /* Author: Joachim Schoeberl */ /* Date: 21. Jun. 98 */ /* *************************************************************************/ #include #include #include #include #include #endif ================================================ FILE: libsrc/csg/identify.cpp ================================================ #include #include #include #include #include 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 (NgArray & points) { ; } */ int Identification :: Identifiable (const SpecialPoint & sp1, const SpecialPoint & sp2, const TABLE & specpoint2solid, const TABLE & specpoint2surface) const { cout << "Identification::Identifiable called for base-class" << endl; return 0; } int Identification :: Identifiable (const Point<3> & p1, const Point<3> & sp2) const { cout << "Identification::Identifiable called for base-class" << endl; return 0; } int Identification :: IdentifiableCandidate (const SpecialPoint & sp1) const { return 1; } int Identification :: ShortEdge (const SpecialPoint & sp1, const SpecialPoint & sp2) const { return 0; } PointIndex Identification :: GetIdentifiedPoint (class Mesh & mesh, PointIndex pi) { cout << "Identification::GetIdentifiedPoint called for base-class" << endl; return PointIndex::INVALID; } 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 (NgArray & segs, Mesh & mesh, const Surface * surf) { cout << "Identification::BuildSurfaceElements called for base-class" << endl; ; } void Identification :: BuildVolumeElements (NgArray & surfels, class Mesh & mesh) { ; } void Identification :: GetIdentifiedFaces (NgArray & 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, Transformation<3> atrafo) : Identification(anr, ageom), trafo(atrafo) { inv_trafo = trafo.CalcInverse(); s1 = as1; s2 = as2; } PeriodicIdentification :: ~PeriodicIdentification () { ; } /* void PeriodicIdentification :: IdentifySpecialPoints (NgArray & 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 :: Identifiable (const SpecialPoint & sp1, const SpecialPoint & sp2, const TABLE & specpoint2solid, const TABLE & specpoint2surface) const { SpecialPoint hsp1 = sp1; SpecialPoint hsp2 = sp2; for (int 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; if ((trafo(hsp1.v)-hsp2.v).Length2() > 1e-12) return false; double d2typ = Dist2(hsp1.p, hsp2.p); if (Dist2 (trafo(hsp1.p),hsp2.p) < 1e-18*d2typ) return true; if (Dist2 (hsp1.p, trafo(hsp1.p)) < 1e-18*d2typ) { // old style without trafo, but normal projection Vec<3> v = hsp2.p - hsp1.p; double vl = v.Length(); double cl = fabs (v*n1); double val1 = 1 - cl*cl/(vl*vl); double val2 = (hsp1.v - hsp2.v).Length(); if (val1 < 1e-10 && val2 < 1e-6) return true; } } return false; } int PeriodicIdentification :: Identifiable (const Point<3> & p1, const Point<3> & p2) const { return (s1->PointOnSurface (p1) && s2->PointOnSurface (p2)); } PointIndex PeriodicIdentification :: GetIdentifiedPoint (class Mesh & mesh, PointIndex pi) { const Surface *snew; const Point<3> & p = mesh.Point (pi); Point<3> hp = p; if (s1->PointOnSurface (p)) { snew = s2; hp = trafo(hp); } else { if (s2->PointOnSurface (p)) { snew = s1; hp = inv_trafo(hp); } else { throw NgException("GetIdenfifiedPoint: Not possible"); } } // project to other surface snew->Project (hp); PointIndex newpi(PointIndex::INVALID); for (PointIndex pi : Range(mesh.Points())) if (Dist2 (mesh.Point(pi), hp) < 1e-12) { newpi = pi; break; } if (!newpi.IsValid()) 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) { Point3d p1, p2; mesh.GetBox(p1, p2); auto eps = 1e-6 * (p2-p1).Length(); /* for (int i = 1; i <= mesh.GetNP(); i++) { Point<3> p = mesh.Point(i); if (s1->PointOnSurface (p)) { Point<3> pp = p; pp = trafo(pp); s2->Project (pp); for (int j = 1; j <= mesh.GetNP(); j++) if (Dist2(mesh.Point(j), pp) < eps) { mesh.GetIdentifications().Add (i, j, nr); } } } */ for (auto pi : Range(mesh.Points())) { Point<3> p = mesh[pi]; if (s1->PointOnSurface (p)) { Point<3> pp = p; pp = trafo(pp); s2->Project (pp); for (PointIndex pj : Range(mesh.Points())) if (Dist2(mesh[pj], pp) < eps) mesh.GetIdentifications().Add (pi, pj, nr); } } 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().Used (seg1[0], seg2[0]) && mesh.GetIdentifications().Used (seg1[1], seg2[1])) { foundother = 1; break; } if (mesh.GetIdentifications().Used (seg1[0], seg2[1]) && mesh.GetIdentifications().Used (seg1[1], seg2[0])) { foundother = 1; break; } } else { if (mesh.GetIdentifications().Used (seg2[0], seg1[0]) && mesh.GetIdentifications().Used (seg2[1], seg1[1])) { foundother = 1; break; } if (mesh.GetIdentifications().Used (seg2[0], seg1[1]) && mesh.GetIdentifications().Used (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 (NgArray & 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) { NgArray 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; i0 && 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 (NgArray & 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 :: Identifiable (const SpecialPoint & sp1, const SpecialPoint & sp2, const TABLE & specpoint2solid, const TABLE & specpoint2surface) const { //(*testout) << "identcheck: " << sp1.p << "; " << sp2.p << endl; if (!dom_surf_valid) { const_cast (dom_surf_valid) = 1; NgArray & hsurf = const_cast&> (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 :: Identifiable (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 :: IdentifiableCandidate (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; } PointIndex CloseSurfaceIdentification :: GetIdentifiedPoint (class Mesh & mesh, PointIndex pi) { const Surface *snew; const Point<3> & p = mesh.Point (pi); idmap_type identmap(mesh.GetNP()); mesh.GetIdentifications().GetMap (nr, identmap); /* if (identmap.Get(pi)) return identmap.Get(pi); */ if (identmap[pi].IsValid()) return identmap[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(); NgArray points_on_surf2; for (int i2 = 1; i2 <= np; i2++) if (s2->PointOnSurface (mesh.Point(i2))) points_on_surf2.Append (i2); NgArray 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); } NgArray segs_on_face1, segs_on_face2; identfaces.DeleteData(); //(*testout) << "identify faces, nr = " << nr << endl; for (int i = 1; i <= mesh.GetNFD(); i++) { auto & fdi = mesh.GetFaceDescriptor(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++) { auto & fdj = mesh.GetFaceDescriptor(j); int surfj = mesh.GetFaceDescriptor(j).SurfNr(); if (surfi == surfj) continue; if (s2rep != surfj) continue; bool have_common = false; if (fdi.DomainIn() != 0) if (fdi.DomainIn() == fdj.DomainIn() || fdi.DomainIn() == fdj.DomainOut()) have_common = true; if (fdi.DomainOut() != 0) if (fdi.DomainOut() == fdj.DomainIn() || fdi.DomainOut() == fdj.DomainOut()) have_common = true; if (!have_common) 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().Used (seg1[0], seg2[0]) && mesh.GetIdentifications().Used (seg1[1], seg2[1])) { foundother = 1; break; } if (mesh.GetIdentifications().Used (seg1[0], seg2[1]) && mesh.GetIdentifications().Used (seg1[1], seg2[0])) { foundother = 1; break; } } else { if (mesh.GetIdentifications().Used (seg2[0], seg1[0]) && mesh.GetIdentifications().Used (seg2[1], seg1[1])) { foundother = 1; break; } if (mesh.GetIdentifications().Used (seg2[0], seg1[1]) && mesh.GetIdentifications().Used (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 (NgArray & segs, Mesh & mesh, const Surface * surf) { bool found = 0; int cntquads = 0; idmap_type 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; //NgArray 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))) { Vec<3> ns = surf->GetNormalVector (mesh[s1[0]]); Vec<3> t1 = mesh[s1[1]] - mesh[s1[0]]; // Vec<3> t2 = mesh[s2[1]] - mesh[s2[0]]; Vec<3> nst1 = Cross(t1, ns); // Vec<3> nst2 = Cross(t2, ns); Vec<3> dvec = Center(mesh[s1[0]], mesh[s1[1]])-Center(mesh[s2[0]], mesh[s2[1]]); if (nst1 * dvec < 0) continue; Element2d el(s1[0], s1[1], s2[0], s2[1]); el.SetIndex(s1.si); Vec<3> n = Cross (mesh[el[1]] - mesh[el[0]], mesh[el[3]] - 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); //NgArray aux; //for(int i=0; i & 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::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 (NgArray & 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 (NgArray & 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 :: Identifiable (const SpecialPoint & sp1, const SpecialPoint & sp2, const TABLE & specpoint2solid, const TABLE & 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 (NgArray & 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().Used (s1[0], s2[1]) && mesh.GetIdentifications().Used (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); } } ================================================ FILE: libsrc/csg/identify.hpp ================================================ #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 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 (NgArray & points); /// can identify both special points (fixed direction) /// (identified points, same tangent) virtual int Identifiable (const SpecialPoint & sp1, const SpecialPoint & sp2, const TABLE & specpoint2solid, const TABLE & specpoint2surface) const; /// virtual int Identifiable (const Point<3> & p1, const Point<3> & sp2) const; /// is it possible to identify sp1 with some other ? virtual int IdentifiableCandidate (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 PointIndex GetIdentifiedPoint (class Mesh & mesh, PointIndex pi1); /// copy surfaces, or fill rectangles virtual void BuildSurfaceElements (NgArray & segs, class Mesh & mesh, const Surface * surf); /// insert volume elements in thin layers virtual void BuildVolumeElements (NgArray & surfels, class Mesh & mesh); /// get list of identified faces virtual void GetIdentifiedFaces (NgArray & idfaces) const; friend ostream & operator<< (ostream & ost, Identification & ident); }; class PeriodicIdentification : public Identification { const Surface * s1; const Surface * s2; Transformation<3> trafo; // from s1 to s2 Transformation<3> inv_trafo; // from s2 to s1 public: PeriodicIdentification (int anr, const CSGeometry & ageom, const Surface * as1, const Surface * as2, Transformation<3> atrafo = Vec<3>(0,0,0)); virtual ~PeriodicIdentification () override; virtual void Print (ostream & ost) const override; virtual void GetData (ostream & ost) const override; // virtual void IdentifySpecialPoints (NgArray & points); virtual int Identifiable (const SpecialPoint & sp1, const SpecialPoint & sp2, const TABLE & specpoint2solid, const TABLE & specpoint2surface) const override; virtual int Identifiable (const Point<3> & p1, const Point<3> & sp2) const override; virtual PointIndex GetIdentifiedPoint (class Mesh & mesh, PointIndex pi1) override; virtual void IdentifyPoints (class Mesh & mesh) override; virtual void IdentifyFaces (class Mesh & mesh) override; virtual void BuildSurfaceElements (NgArray & segs, class Mesh & mesh, const Surface * surf) override; }; /// 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 slices; /// used only for domain-local identification: NgArray 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 (NgArray & points); virtual int Identifiable (const SpecialPoint & sp1, const SpecialPoint & sp2, const TABLE & specpoint2solid, const TABLE & specpoint2surface) const; virtual int Identifiable (const Point<3> & p1, const Point<3> & sp2) const; virtual int IdentifiableCandidate (const SpecialPoint & sp1) const; virtual int ShortEdge (const SpecialPoint & sp1, const SpecialPoint & sp2) const; virtual PointIndex GetIdentifiedPoint (class Mesh & mesh, PointIndex pi1); const Array & GetSlices () const { return slices; } virtual void IdentifyPoints (class Mesh & mesh); virtual void IdentifyFaces (class Mesh & mesh); virtual void BuildSurfaceElements (NgArray & segs, class Mesh & mesh, const Surface * surf); void BuildSurfaceElements2 (NgArray & segs, class Mesh & mesh, const Surface * surf); virtual void BuildVolumeElements (NgArray & 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 (NgArray & points); virtual int Identifiable (const SpecialPoint & sp1, const SpecialPoint & sp2, const TABLE & specpoint2solid, const TABLE & specpoint2surface) const; virtual void IdentifyPoints (class Mesh & mesh); virtual void BuildSurfaceElements (NgArray & segs, class Mesh & mesh, const Surface * surf); }; } #endif ================================================ FILE: libsrc/csg/manifold.cpp ================================================ #include namespace netgen { Manifold :: Manifold () { ; } Manifold :: ~Manifold () { ; } } ================================================ FILE: libsrc/csg/manifold.hpp ================================================ #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 ================================================ FILE: libsrc/csg/meshsurf.cpp ================================================ #include #include #include namespace netgen { /* Meshing2Surfaces :: Meshing2Surfaces (const Surface & asurface) : surface(asurface) { ; } */ Meshing2Surfaces :: Meshing2Surfaces (const CSGeometry& geo, const Surface & asurf, const MeshingParameters & mp, const Box<3> & abb) : Meshing2(geo, mp, abb), surface(asurf), mparam (mp) { ; } void Meshing2Surfaces :: DefineTransformation (const Point<3> & p1, const Point<3> & p2, const PointGeomInfo * geominfo1, const PointGeomInfo * geominfo2) { ((Surface&)surface).DefineTangentialPlane (p1, p2); } void Meshing2Surfaces :: TransformToPlain (const Point<3> & locpoint, const MultiPointGeomInfo & geominfo, Point<2> & planepoint, double h, int & zone) { surface.ToPlane (locpoint, planepoint, h, zone); } int Meshing2Surfaces :: TransformFromPlain (const Point<2> & planepoint, Point<3> & locpoint, PointGeomInfo & gi, double h) { surface.FromPlane (planepoint, locpoint, h); gi.trignum = 1; return 0; } double Meshing2Surfaces :: CalcLocalH (const Point<3> & p, double gh) const { return surface.LocH (p, 3, 1, mparam, gh); /* double loch = mesh.lochfunc->GetH(p); if (gh < loch) loch = gh; return loch; */ } } ================================================ FILE: libsrc/csg/meshsurf.hpp ================================================ #ifndef FILE_MESHSURF #define FILE_MESHSURF namespace netgen { /// class Meshing2Surfaces : public Meshing2 { /// const Surface & surface; /// should be movec to base ... const MeshingParameters & mparam; public: /// // Meshing2Surfaces (const Surface & asurf); /// Meshing2Surfaces (const CSGeometry& geo, const Surface & asurf, const MeshingParameters & mp, const Box<3> & aboundingbox); protected: /// void DefineTransformation(const Point<3> & p1, const Point<3> & p2, const PointGeomInfo * geominfo1, const PointGeomInfo * geominfo2) override; /// void TransformToPlain(const Point<3> & locpoint, const MultiPointGeomInfo & geominfo, Point<2> & plainpoint, double h, int & zone) override; /// int TransformFromPlain(const Point<2>& plainpoint, Point<3>& locpoint, PointGeomInfo & gi, double h) override; /// double CalcLocalH(const Point<3> & p, double gh) const override; }; } #endif ================================================ FILE: libsrc/csg/polyhedra.cpp ================================================ #include #include #include namespace netgen { Polyhedra::Face::Face (int pi1, int pi2, int pi3, const NgArray > & 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()); } // check how many faces a ray starting in p intersects INSOLID_TYPE Polyhedra :: PointInSolid (const Point<3> & p, double eps) const { if (!poly_bbox.IsIn (p, eps)) return IS_OUTSIDE; // random (?) direction: Vec<3> n(-0.424621, 0.1543, 0.89212238); int cnt = 0; for (auto & face : faces) { Vec<3> v0 = p - points[face.pnums[0]]; double lam3 = face.nn * v0; if (fabs(lam3) < eps) // point is in plance of face { double lam1 = face.w1 * v0; double lam2 = face.w2 * v0; if (lam1 >= -eps_base1 && lam2 >= -eps_base1 && lam1+lam2 <= 1+eps_base1) return DOES_INTERSECT; } else { double lam3 = -(face.n * v0) / (face.n * n); if (lam3 < 0) continue; // ray goes not in direction of face Vec<3> rs = v0 + lam3 * n; double lam1 = face.w1 * rs; double lam2 = face.w2 * rs; if (lam1 >= 0 && lam2 >= 0 && lam1+lam2 <= 1) cnt++; } } return (cnt % 2) ? IS_INSIDE : IS_OUTSIDE; } void Polyhedra :: GetTangentialSurfaceIndices (const Point<3> & p, NgArray & surfind, double eps) const { for (int i = 0; i < faces.Size(); i++) { auto & face = faces[i]; const Point<3> & p1 = points[face.pnums[0]]; Vec<3> v0 = p - p1; double lam3 = -(face.nn * v0); // n->nn if (fabs (lam3) > eps) continue; double lam1 = (face.w1 * v0); double lam2 = (face.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 :: VecInSolidOld (const Point<3> & p, const Vec<3> & v, double eps) const { NgArray 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 eps && (first || dist < mindist)) { mindist = dist; first = false; } } } Point<3> p2 = p + (1e-4*mindist) * vn; res = PointInSolid (p2, eps); // (*testout) << "mindist " << mindist << " res " << res << endl; return res; } // check how many faces a ray starting in p+alpha*v intersects INSOLID_TYPE Polyhedra :: VecInSolidNew (const Point<3> & p, const Vec<3> & v, double eps, bool printing) const { if (!poly_bbox.IsIn (p, eps)) return IS_OUTSIDE; // random (?) direction: Vec<3> n(-0.424621, 0.1543, 0.89212238); int cnt = 0; for (auto & face : faces) { Vec<3> v0 = p - points[face.pnums[0]]; if (printing) { *testout << "face: "; for (int j = 0; j < 3; j++) *testout << points[face.pnums[j]] << " "; *testout << endl; } double lamn = face.nn * v0; if (fabs(lamn) < eps) // point is in plane of face { double lam1 = face.w1 * v0; double lam2 = face.w2 * v0; double lam3 = 1-lam1-lam2; if (printing) *testout << "lam = " << lam1 << " " << lam2 << " " << lam3 << endl; if (lam1 >= -eps_base1 && lam2 >= -eps_base1 && lam3 >= -eps_base1) { // point is close to triangle, perturbed by alpha*v double dlamn = face.nn*v; if (fabs(dlamn) < 1e-8) // vec also in plane { if (printing) *testout << "tang in plane" << endl; double dlam1 = face.w1 * v; double dlam2 = face.w2 * v; double dlam3 = -dlam1-dlam2; if (printing) *testout << "dlam = " << dlam1 << " " << dlam2 << " " << dlam3 << endl; bool in1 = lam1 > eps_base1 || dlam1 > -eps_base1; bool in2 = lam2 > eps_base1 || dlam2 > -eps_base1; bool in3 = lam3 > eps_base1 || dlam3 > -eps_base1; if (in1 && in2 && in3) return DOES_INTERSECT; } else // vec out of plane { if (printing) *testout << "out of plane"; double dlamn = -(face.n * v) / (face.n * n); if (printing) *testout << "dlamn = " << dlamn << endl; if (dlamn < 0) continue; // ray goes not in direction of face Vec<3> drs = v + dlamn * n; if (printing) { *testout << "drs = " << drs << endl; *testout << "face.w1 = " << face.w1 << endl; *testout << "face.w2 = " << face.w2 << endl; } double dlam1 = face.w1 * drs; double dlam2 = face.w2 * drs; double dlam3 = -dlam1-dlam2; if (printing) *testout << "dlam = " << dlam1 << " " << dlam2 << " " << dlam3 << endl; bool in1 = lam1 > eps_base1 || dlam1 > -eps_base1; bool in2 = lam2 > eps_base1 || dlam2 > -eps_base1; bool in3 = lam3 > eps_base1 || dlam3 > -eps_base1; if (in1 && in2 && in3) { if (printing) *testout << "hit" << endl; cnt++; } } } } else { double lamn = -(face.n * v0) / (face.n * n); if (lamn < 0) continue; // ray goes not in direction of face Vec<3> rs = v0 + lamn * n; double lam1 = face.w1 * rs; double lam2 = face.w2 * rs; double lam3 = 1-lam1-lam2; if (lam1 >= 0 && lam2 >= 0 && lam3 >= 0) { if (printing) *testout << "hit" << endl; cnt++; } } } return (cnt % 2) ? IS_INSIDE : IS_OUTSIDE; } INSOLID_TYPE Polyhedra :: VecInSolid (const Point<3> & p, const Vec<3> & v, double eps) const { return VecInSolidNew (p, v, eps); /* auto oldval = VecInSolidOld (p, v, eps); auto newval = VecInSolidNew (p, v, eps); if (oldval != newval) { *testout << "different decision: oldval = " << oldval << " newval = " << newval << endl; *testout << "p = " << p << ", v = " << v << endl; VecInSolidNew (p, v, eps, true); *testout << "Poly:" << endl; for (auto & face : faces) { for (int j = 0; j < 3; j++) *testout << points[face.pnums[j]] << " "; *testout << endl; } } return newval; */ } /* 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); } */ // #define OLDVECINSOLID2 #ifdef OLDVECINSOLID2 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 = " < v1n = v1; v1n.Normalize(); Vec<3> v2n = v2 - (v2 * v1n) * v1n; v2n.Normalize(); double cosv2, cosv2max = -99; 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); } #else // check how many faces a ray starting in p+alpha*v+alpha^2/2 v2 intersects: // if p + alpha v is in plane, use v2 INSOLID_TYPE Polyhedra :: VecInSolid2 (const Point<3> & p, const Vec<3> & v, const Vec<3> & v2, double eps) const { if (!poly_bbox.IsIn (p, eps)) return IS_OUTSIDE; // random (?) direction: Vec<3> n(-0.424621, 0.1543, 0.89212238); int cnt = 0; for (auto & face : faces) { Vec<3> v0 = p - points[face.pnums[0]]; double lamn = face.nn * v0; if (fabs(lamn) < eps) // point is in plane of face { double lam1 = face.w1 * v0; double lam2 = face.w2 * v0; double lam3 = 1-lam1-lam2; if (lam1 >= -eps_base1 && lam2 >= -eps_base1 && lam3 >= -eps_base1) { // point is close to triangle, perturbed by alpha*v double dlamn = face.nn*v; if (fabs(dlamn) < 1e-8) // vec also in plane { double dlam1 = face.w1 * v; double dlam2 = face.w2 * v; double dlam3 = -dlam1-dlam2; bool in1 = lam1 > eps_base1 || dlam1 > -eps_base1; bool in2 = lam2 > eps_base1 || dlam2 > -eps_base1; bool in3 = lam3 > eps_base1 || dlam3 > -eps_base1; // and the same thing for v2 if (in1 && in2 && in3) { double ddlamn = face.nn*v2; if (fabs(ddlamn) < 1e-8) // vec2 also in plane { double ddlam1 = face.w1 * v2; double ddlam2 = face.w2 * v2; double ddlam3 = -ddlam1-ddlam2; bool ddin1 = lam1 > eps_base1 || dlam1 > eps_base1 || ddlam1 > -eps_base1; bool ddin2 = lam2 > eps_base1 || dlam2 > eps_base1 || ddlam2 > -eps_base1; bool ddin3 = lam3 > eps_base1 || dlam3 > eps_base1 || ddlam3 > -eps_base1; if (ddin1 && ddin2 && ddin3) return DOES_INTERSECT; } else // vec2 out of plane { double ddlamn = -(face.n * v2) / (face.n * n); if (ddlamn < 0) continue; // ray goes not in direction of face Vec<3> drs = v; // + dlamn * n; but dlamn==0 Vec<3> ddrs = v2 + ddlamn * n; double dlam1 = face.w1 * drs; double dlam2 = face.w2 * drs; double dlam3 = -dlam1-dlam2; double ddlam1 = face.w1 * ddrs; double ddlam2 = face.w2 * ddrs; double ddlam3 = -ddlam1-ddlam2; bool ddin1 = lam1 > eps_base1 || dlam1 > eps_base1 || ddlam1 > -eps_base1; bool ddin2 = lam2 > eps_base1 || dlam2 > eps_base1 || ddlam2 > -eps_base1; bool ddin3 = lam3 > eps_base1 || dlam3 > eps_base1 || ddlam3 > -eps_base1; if (ddin1 && ddin2 && ddin3) cnt++; } } } else // vec out of plane { double dlamn = -(face.n * v) / (face.n * n); if (dlamn < 0) continue; // ray goes not in direction of face Vec<3> drs = v + dlamn * n; double dlam1 = face.w1 * drs; double dlam2 = face.w2 * drs; double dlam3 = -dlam1-dlam2; bool in1 = lam1 > eps_base1 || dlam1 > -eps_base1; bool in2 = lam2 > eps_base1 || dlam2 > -eps_base1; bool in3 = lam3 > eps_base1 || dlam3 > -eps_base1; if (in1 && in2 && in3) cnt++; } } } else { double lamn = -(face.n * v0) / (face.n * n); if (lamn < 0) continue; // ray goes not in direction of face Vec<3> rs = v0 + lamn * n; double lam1 = face.w1 * rs; double lam2 = face.w2 * rs; double lam3 = 1-lam1-lam2; if (lam1 >= 0 && lam2 >= 0 && lam3 >= 0) cnt++; } } return (cnt % 2) ? IS_INSIDE : IS_OUTSIDE; } #endif INSOLID_TYPE Polyhedra :: VecInSolid3 (const Point<3> & p, const Vec<3> & v1, const Vec<3> & v2, double eps) const { return VecInSolid2 (p, v1, v2, eps); } INSOLID_TYPE Polyhedra :: VecInSolid4 (const Point<3> & p, const Vec<3> & v, const Vec<3> & v2, const Vec<3> & m, double eps) const { auto res = VecInSolid2 (p, v, v2, eps); if (res == DOES_INTERSECT) // following edge second order, let m decide return VecInSolid2 (p, v, m, eps); return res; } void Polyhedra :: GetTangentialVecSurfaceIndices2 (const Point<3> & p, const Vec<3> & v1, const Vec<3> & v2, NgArray & 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, NgArray & 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 (NgArray & /* 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); points.Append (p); return points.Size(); } 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(NgArray < NgArray * > & polysurfs) { int maxnum = -1; for(int i = 0; i maxnum) maxnum = faces[i].inputnr; } polysurfs.SetSize(maxnum+1); for(int i=0; i; for(int i = 0; iAppend(faces[i].planenr); } void Polyhedra::CalcSpecialPoints (NgArray > & pts) const { for (int i = 0; i < points.Size(); i++) pts.Append (points[i]); } void Polyhedra :: AnalyzeSpecialPoint (const Point<3> & /* pt */, NgArray > & /* 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); } } ================================================ FILE: libsrc/csg/polyhedra.hpp ================================================ #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 NgArray > & points, int ainputnr); }; NgArray > points; NgArray faces; NgArray planes; Box<3> poly_bbox; double eps_base1; public: Polyhedra (); virtual ~Polyhedra () override; static Primitive * CreateDefault (); virtual INSOLID_TYPE BoxInSolid (const BoxSphere<3> & box) const override; virtual INSOLID_TYPE PointInSolid (const Point<3> & p, double eps) const override; virtual INSOLID_TYPE VecInSolidNew (const Point<3> & p, const Vec<3> & v, double eps, bool printing = false) const; virtual INSOLID_TYPE VecInSolidOld (const Point<3> & p, const Vec<3> & v, double eps) const; virtual INSOLID_TYPE VecInSolid (const Point<3> & p, const Vec<3> & v, double eps) const override; virtual INSOLID_TYPE VecInSolid2 (const Point<3> & p, const Vec<3> & v1, const Vec<3> & v2, double eps) const override; virtual INSOLID_TYPE VecInSolid3 (const Point<3> & p, const Vec<3> & v1, const Vec<3> & v2, double eps) const override; virtual INSOLID_TYPE VecInSolid4 (const Point<3> & p, const Vec<3> & v, const Vec<3> & v2, const Vec<3> & m, double eps) const override; virtual void GetTangentialSurfaceIndices (const Point<3> & p, NgArray & surfind, double eps) const override; virtual void GetTangentialVecSurfaceIndices2 (const Point<3> & p, const Vec<3> & v1, const Vec<3> & v2, NgArray & surfind, double eps) const override; virtual void CalcSpecialPoints (NgArray > & pts) const override; virtual void AnalyzeSpecialPoint (const Point<3> & pt, NgArray > & specpts) const override; virtual Vec<3> SpecialPointTangentialVector (const Point<3> & p, int s1, int s2) const override; virtual int GetNSurfaces() const override { return planes.Size(); } virtual Surface & GetSurface (int i) override { return *planes[i]; } virtual const Surface & GetSurface (int i) const override { return *planes[i]; } virtual void GetPrimitiveData (const char *& classname, NgArray & coeffs) const override; virtual void SetPrimitiveData (NgArray & coeffs) override; virtual void Reduce (const BoxSphere<3> & box) override; virtual void UnReduce () override; int AddPoint (const Point<3> & p); int AddFace (int pi1, int pi2, int pi3, int inputnum); void GetPolySurfs(NgArray < NgArray * > & polysurfs); protected: int FaceBoxIntersection (int fnr, const BoxSphere<3> & box) const; // void CalcData(); }; } #endif ================================================ FILE: libsrc/csg/python_csg.cpp ================================================ #ifdef NG_PYTHON #include "../general/ngpython.hpp" #include "../core/python_ngcore.hpp" #include "csg.hpp" #include "../meshing/python_mesh.hpp" #include "../general/gzstream.h" using namespace netgen; using namespace pybind11::literals; namespace netgen { extern shared_ptr ng_geometry; } // a shadow solid tree using shared pointers. class SPSolid { shared_ptr s1, s2; Solid * solid; int bc = -1; string bcname = ""; double maxh = -1; string material; bool owner; double red = 0, green = 0, blue = 1; bool transp = false; public: enum optyp { TERM, SECTION, UNION, SUB, EXISTING }; SPSolid (Solid * as) : solid(as), owner(true), op(TERM) { ; } SPSolid (Solid * as, int /*dummy*/) : solid(as), owner(false), op(EXISTING) { ; } ~SPSolid () { ; // if (owner) delete solid; } SPSolid (optyp aop, shared_ptr as1, shared_ptr as2) : s1(as1), s2(as2), owner(true), op(aop) { if (aop == UNION) solid = new Solid (Solid::UNION, s1->GetSolid(), s2->GetSolid()); else if (aop == SECTION) solid = new Solid (Solid::SECTION, s1->GetSolid(), s2->GetSolid()); else if (aop == SUB) solid = new Solid (Solid::SUB, s1->GetSolid()); // , s2->GetSolid()); } Solid * GetSolid() { return solid; } const Solid * GetSolid() const { return solid; } void GiveUpOwner() { owner = false; if (s1) s1 -> GiveUpOwner(); if (s2) s2 -> GiveUpOwner(); } void AddSurfaces(CSGeometry & geom) { if (op == TERM) geom.AddSurfaces (solid->GetPrimitive()); if (s1) s1 -> AddSurfaces (geom); if (s2) s2 -> AddSurfaces (geom); } void SetMaterial (string mat) { material = mat; } string GetMaterial () { if (!material.empty()) return material; if (s1) { string s1mat = s1->GetMaterial(); if (!s1mat.empty()) return s1mat; } if (s2) { string s2mat = s2->GetMaterial(); if (!s2mat.empty()) return s2mat; } return material; } void SetBC(int abc) { if (bc == -1) { bc = abc; if (s1) s1 -> SetBC(bc); if (s2) s2 -> SetBC(bc); if (op == TERM) { Primitive * prim = solid -> GetPrimitive(); for (int i = 0; i < prim->GetNSurfaces(); i++) prim->GetSurface(i).SetBCProperty (abc); // cout << "set " << prim->GetNSurfaces() << " surfaces to bc " << bc << endl; } } } void SetBCName(string name) { if (bcname == "") { bcname = name; if (s1) s1 -> SetBCName(name); if (s2) s2 -> SetBCName(name); if (op == TERM) { Primitive * prim = solid -> GetPrimitive(); for (int i = 0; i < prim->GetNSurfaces(); i++) prim->GetSurface(i).SetBCName (name); // cout << "set " << prim->GetNSurfaces() << " surfaces to bc " << bc << endl; } } } void SetMaxH(double amaxh) { if (maxh == -1) { maxh = amaxh; if (s1) s1 -> SetMaxH(maxh); if (s2) s2 -> SetMaxH(maxh); if (op == TERM) { Primitive * prim = solid -> GetPrimitive(); for (int i = 0; i < prim->GetNSurfaces(); i++) prim->GetSurface(i).SetMaxH (maxh); } } } void SetColor(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() { transp = true; } bool IsTransparent() { return transp; } private: optyp op; }; inline ostream & operator<< (ostream & ost, const SPSolid & sol) { ost << *sol.GetSolid(); return ost; } namespace netgen { extern CSGeometry * ParseCSG (istream & istr, CSGeometry *instance=nullptr); } DLL_HEADER void ExportCSG(py::module &m) { py::class_, shared_ptr>> (m, "SplineCurve2d") .def(py::init<>()) .def ("AddPoint", FunctionPointer ([] (SplineGeometry<2> & self, double x, double y) { self.geompoints.Append (GeomPoint<2> (Point<2> (x,y))); return self.geompoints.Size()-1; })) .def ("AddSegment", [] (SplineGeometry<2> & self, int i1, int i2, string bcname, double maxh) { self.splines.Append (new LineSeg<2> (self.geompoints[i1], self.geompoints[i2], maxh, bcname)); }, "p1"_a, "p2"_a, "bcname"_a="default", "maxh"_a=1e99) .def ("AddSegment", [] (SplineGeometry<2> & self, int i1, int i2, int i3, string bcname, double maxh) { self.splines.Append (new SplineSeg3<2> (self.geompoints[i1], self.geompoints[i2], self.geompoints[i3], bcname, maxh)); }, "p1"_a, "p2"_a, "p3"_a, "bcname"_a="default", "maxh"_a=1e99) ; py::class_,shared_ptr>> (m,"SplineCurve3d") .def(py::init<>()) .def ("AddPoint", FunctionPointer ([] (SplineGeometry<3> & self, double x, double y, double z) { self.geompoints.Append (GeomPoint<3> (Point<3> (x,y,z))); return self.geompoints.Size()-1; })) .def ("AddSegment", FunctionPointer ([] (SplineGeometry<3> & self, int i1, int i2) { self.splines.Append (new LineSeg<3> (self.geompoints[i1], self.geompoints[i2])); })) .def ("AddSegment", FunctionPointer ([] (SplineGeometry<3> & self, int i1, int i2, int i3) { self.splines.Append (new SplineSeg3<3> (self.geompoints[i1], self.geompoints[i2], self.geompoints[i3])); })) ; py::class_> (m, "SplineSurface", "A surface for co dim 2 integrals on the splines") .def(py::init([](shared_ptr base, py::list cuts) { auto primitive = dynamic_cast (base->GetSolid()->GetPrimitive()); auto acuts = make_shared>>(); for(int i = 0; i> sps(cuts[i]); if(!sps.check()) throw NgException("Cut must be SurfacePrimitive in constructor of SplineSurface!"); auto sp = dynamic_cast(sps()->GetSolid()->GetPrimitive()); if(sp) acuts->Append(shared_ptr(sp)); else throw Exception("Cut must be SurfacePrimitive in constructor of SplineSurface!"); } if(!primitive) throw Exception("Base is not a SurfacePrimitive in constructor of SplineSurface!"); return make_shared(shared_ptr(primitive),acuts); }),py::arg("base"), py::arg("cuts")=py::list()) .def("AddPoint", FunctionPointer ([] (SplineSurface & self, double x, double y, double z, bool hpref) { self.AppendPoint(Point<3>(x,y,z),hpref); return self.GetNP()-1; }), py::arg("x"),py::arg("y"),py::arg("z"),py::arg("hpref")=false) .def("AddSegment", [] (SplineSurface & self, int i1, int i2, string bcname, double maxh) { auto seg = make_shared>(self.GetPoint(i1),self.GetPoint(i2)); self.AppendSegment(seg,bcname,maxh); }, py::arg("pnt1"),py::arg("pnt2"),py::arg("bcname")="default", py::arg("maxh")=-1.) .def("AddSegment", [] (SplineSurface& self, int i1, int i2, int i3, string bcname, double maxh) { auto seg = make_shared>(self.GetPoint(i1), self.GetPoint(i2), self.GetPoint(i3)); self.AppendSegment(seg, bcname, maxh); }, py::arg("pnt1"),py::arg("pnt2"), py::arg("pnt3"),py::arg("bcname")="default", py::arg("maxh")=-1.) ; py::class_> (m, "Solid") .def ("__str__", &ToString) .def ("__add__", FunctionPointer( [] ( shared_ptr self, shared_ptr other) { return make_shared (SPSolid::UNION, self, other); })) .def ("__mul__", FunctionPointer( [] ( shared_ptr self, shared_ptr other) { return make_shared (SPSolid::SECTION, self, other); })) .def ("__sub__", FunctionPointer ([] ( shared_ptr self, shared_ptr other) { return make_shared (SPSolid::SECTION, self, make_shared (SPSolid::SUB, other, nullptr)); })) .def ("bc", FunctionPointer([](shared_ptr & self, int nr) -> shared_ptr { self->SetBC(nr); return self; })) .def ("bc", FunctionPointer([](shared_ptr & self, string name) -> shared_ptr { self->SetBCName(name); return self; })) .def ("maxh", FunctionPointer([](shared_ptr & self, double maxh) -> shared_ptr { self->SetMaxH(maxh); return self; })) .def ("mat", FunctionPointer([](shared_ptr & self, string mat) -> shared_ptr { self->SetMaterial(mat); return self; })) .def ("mat", &SPSolid::GetMaterial) .def("col", FunctionPointer([](shared_ptr & self, py::list rgb) -> shared_ptr { py::extract red(rgb[0]); py::extract green(rgb[1]); py::extract blue(rgb[2]); self->SetColor(red(),green(),blue()); return self; })) .def("transp", FunctionPointer([](shared_ptr & self)->shared_ptr < SPSolid > { self->SetTransparent(); return self; })) ; m.def ("Sphere", FunctionPointer([](Point<3> c, double r) { Sphere * sp = new Sphere (c, r); Solid * sol = new Solid (sp); return make_shared (sol); })); m.def ("Ellipsoid", FunctionPointer([](Point<3> m, Vec<3> a, Vec<3> b, Vec<3> c) { Ellipsoid * ell = new Ellipsoid (m, a, b, c); Solid * sol = new Solid (ell); return make_shared (sol); })); m.def ("Plane", FunctionPointer([](Point<3> p, Vec<3> n) { Plane * sp = new Plane (p,n); Solid * sol = new Solid (sp); return make_shared (sol); })); m.def ("Cone", FunctionPointer([](Point<3> a, Point<3> b, double ra, double rb) { Cone * cyl = new Cone (a, b, ra, rb); Solid * sol = new Solid (cyl); return make_shared (sol); })); m.def ("Cylinder", FunctionPointer([](Point<3> a, Point<3> b, double r) { Cylinder * cyl = new Cylinder (a, b, r); Solid * sol = new Solid (cyl); return make_shared (sol); })); m.def ("OrthoBrick", FunctionPointer([](Point<3> p1, Point<3> p2) { OrthoBrick * brick = new OrthoBrick (p1,p2); Solid * sol = new Solid (brick); return make_shared (sol); })); m.def ("Torus", FunctionPointer([](Point<3> c, Vec<3> n, double R, double r) { Torus * torus = new Torus (c,n,R,r); Solid * sol = new Solid (torus); return make_shared (sol); })); m.def ("Revolution", [](Point<3> p1, Point<3> p2, shared_ptr> spline) { Revolution * rev = new Revolution (p1, p2, spline); Solid * sol = new Solid(rev); return make_shared (sol); }); m.def ("Extrusion", [](shared_ptr> path, shared_ptr> profile, Vec<3> d) { Extrusion * extr = new Extrusion (path,profile,d); Solid * sol = new Solid(extr); return make_shared (sol); }, py::arg("path"), py::arg("profile"), py::arg("d"), R"delimiter(A body of extrusion is defined by its profile (which has to be a closed, clockwiseoriented 2D curve), by a path (a 3D curve) and a vector d. It is constructed as follows: Take a point p on the path and denote the (unit-)tangent of the path in this point by t. If we cut the body by the plane given by p and t as normal vector, the cut is the profile. The profile is oriented by the (local) y-direction `y:=d−(d·t)t` and the (local) x-direction `x:=t \times y`. The following points have to be noticed: * If the path is not closed, then also the body is NOT closed. In this case e.g. planes or orthobricks have to be used to construct a closed body. * The path has to be smooth, i.e. the tangents at the end- resp. start-point of two consecutive spline or line patches have to have the same directions. )delimiter"); m.def("EllipticCone", [](const Point<3>& a, const Vec<3>& v, const Vec<3>& w, double h, double r) { auto ellcone = new EllipticCone(a,v,w,h,r); auto sol = new Solid(ellcone); return make_shared(sol); }, py::arg("a"), py::arg("vl"), py::arg("vs"), py::arg("h"), py::arg("r"), R"raw_string( An elliptic cone, given by the point 'a' at the base of the cone along the main axis, the vectors v and w of the long and short axis of the ellipse, respectively, the height of the cone, h, and ratio of base long axis length to top long axis length, r Note: The elliptic cone has to be truncated by planes similar to a cone or an elliptic cylinder. When r =1, the truncated elliptic cone becomes an elliptic cylinder. When r tends to zero, the truncated elliptic cone tends to a full elliptic cone. However, when r = 0, the top part becomes a point(tip) and meshing fails! )raw_string"); m.def("Polyhedron", [](py::list points, py::list faces) { auto poly = new Polyhedra(); for(auto p : points) poly->AddPoint(py::cast>(p)); int fnr = 0; for(auto face : faces) { auto lface = py::cast(face); if(py::len(lface) == 3) poly->AddFace(py::cast(lface[0]), py::cast(lface[1]), py::cast(lface[2]), fnr++); else if(py::len(lface) == 4) { poly->AddFace(py::cast(lface[0]), py::cast(lface[1]), py::cast(lface[2]), fnr); poly->AddFace(py::cast(lface[0]), py::cast(lface[2]), py::cast(lface[3]), fnr++); } } return make_shared(new Solid(poly)); }); m.def ("Or", FunctionPointer([](shared_ptr s1, shared_ptr s2) { return make_shared (SPSolid::UNION, s1, s2); })); m.def ("And", FunctionPointer([](shared_ptr s1, shared_ptr s2) { return make_shared (SPSolid::SECTION, s1, s2); })); py::class_> (m, "CSGeometry") .def(py::init<>()) .def(py::init([](const string& filename) { ifstream ist (filename); auto geo = make_shared(); ParseCSG(ist, geo.get()); geo->FindIdenticSurfaces(1e-8 * geo->MaxSize()); return geo; }), py::arg("filename")) .def(NGSPickle()) .def("Save", FunctionPointer([] (CSGeometry & self, string filename) { cout << "save geometry to file " << filename << endl; self.Save (filename); })) .def("Add", [] (CSGeometry & self, shared_ptr solid, py::list bcmod, double maxh, py::tuple col, bool transparent, int layer) { solid->AddSurfaces (self); solid->GiveUpOwner(); int tlonr = self.SetTopLevelObject (solid->GetSolid()); self.GetTopLevelObject(tlonr) -> SetMaterial(solid->GetMaterial()); self.GetTopLevelObject(tlonr) -> SetRGB(solid->GetRed(),solid->GetGreen(),solid->GetBlue()); // self.GetTopLevelObject(tlonr)->SetTransparent(solid->IsTransparent()); self.GetTopLevelObject(tlonr)->SetTransparent(transparent); self.GetTopLevelObject(tlonr)->SetMaxH(maxh); self.GetTopLevelObject(tlonr)->SetLayer(layer); // cout << "rgb = " << py::len(rgb) << endl; if (py::len(col)==3) self.GetTopLevelObject(tlonr) -> SetRGB(py::cast(col[0]), py::cast(col[1]), py::cast(col[2])); // bcmod is list of tuples ( solid, bcnr ) for (int i = 0; i < py::len(bcmod); i++) { py::tuple tup = py::extract (bcmod[i]) (); auto mod_solid = py::extract> (tup[0]) (); int mod_nr = -1; string * bcname = nullptr; py::object val = tup[1]; if (py::extract(val).check()) mod_nr = py::extract (val)(); if (py::extract(val).check()) bcname = new string ( py::extract (val)()); NgArray si; mod_solid -> GetSolid() -> GetSurfaceIndices (si); // cout << "change bc on surfaces: " << si << " to " << mod_nr << endl; for (int j = 0; j < si.Size(); j++) { CSGeometry::BCModification bcm; bcm.bcname = bcname ? new string (*bcname) : nullptr; bcm.tlonr = tlonr; bcm.si = si[j]; bcm.bcnr = mod_nr; self.bcmodifications.Append (bcm); } delete bcname; } return tlonr; }, py::arg("solid"), py::arg("bcmod")=py::list(), py::arg("maxh")=1e99, py::arg("col")=py::tuple(), py::arg("transparent")=false, py::arg("layer")=1 ) .def("AddSurface", FunctionPointer ([] (CSGeometry & self, shared_ptr surface, shared_ptr solid) { solid->AddSurfaces (self); solid->GiveUpOwner(); Surface & surf = surface->GetSolid()->GetPrimitive()->GetSurface(); int tlonr = self.SetTopLevelObject (solid->GetSolid(), &surf); // self.GetTopLevelObject(tlonr) -> SetMaterial(solid->GetMaterial()); self.GetTopLevelObject(tlonr) -> SetBCProp(surf.GetBCProperty()); self.GetTopLevelObject(tlonr) -> SetBCName(surf.GetBCName()); self.GetTopLevelObject(tlonr) -> SetRGB(solid->GetRed(),solid->GetGreen(),solid->GetBlue()); self.GetTopLevelObject(tlonr)->SetTransparent(solid->IsTransparent()); }), py::arg("surface"), py::arg("solid") ) .def("AddSplineSurface", FunctionPointer ([] (CSGeometry & self, shared_ptr surf) { auto cuttings = surf->CreateCuttingSurfaces(); auto spsol = make_shared(new Solid(surf.get())); for(auto cut : (*cuttings)){ spsol = make_shared(SPSolid::SECTION,spsol,make_shared(new Solid(cut.get()))); } spsol->AddSurfaces(self); int tlonr = self.SetTopLevelObject(spsol->GetSolid(), surf.get()); self.GetTopLevelObject(tlonr) -> SetBCProp(surf->GetBase()->GetBCProperty()); self.GetTopLevelObject(tlonr) -> SetBCName(surf->GetBase()->GetBCName()); self.GetTopLevelObject(tlonr) -> SetMaxH(surf->GetBase()->GetMaxH()); NgArray> non_midpoints; for(auto spline : surf->GetSplines()) { non_midpoints.Append(spline->GetPoint(0)); } for(auto p : non_midpoints) self.AddUserPoint(p); self.AddSplineSurface(surf); }), py::arg("SplineSurface")) .def("SingularFace", [] (CSGeometry & self, shared_ptr sol, shared_ptr surfaces, double factor) { int tlonum = -1; for (int i = 0; i < self.GetNTopLevelObjects(); i++) if (self.GetTopLevelObject(i)->GetSolid() == sol->GetSolid()) tlonum = i; if (tlonum == -1) throw NgException("not a top-level-object"); if (!surfaces) surfaces = sol; auto singface = new SingularFace(tlonum+1, surfaces->GetSolid(), factor); self.singfaces.Append(singface); }, py::arg("solid"), py::arg("surfaces")=nullptr, py::arg("factor")=0.25) .def("SingularEdge", [] (CSGeometry & self, shared_ptr s1,shared_ptr s2, double factor) { auto singedge = new SingularEdge(1, -1, self, s1->GetSolid(), s2->GetSolid(), factor); self.singedges.Append (singedge); }) .def("SingularPoint", [] (CSGeometry & self, shared_ptr s1,shared_ptr s2, shared_ptr s3, double factor) { auto singpoint = new SingularPoint(1, s1->GetSolid(), s2->GetSolid(), s3->GetSolid(), factor); self.singpoints.Append (singpoint); }) .def("CloseSurfaces", FunctionPointer ([] (CSGeometry & self, shared_ptr s1, shared_ptr s2, py::list aslices ) { NgArray si1, si2; s1->GetSolid()->GetSurfaceIndices (si1); s2->GetSolid()->GetSurfaceIndices (si2); Flags flags; try { int n = py::len(aslices); Array slices(n); for(int i=0; i(aslices[i])(); } flags.SetFlag("slices", slices); } catch( py::error_already_set const & ) { cout << "caught python error:" << endl; PyErr_Print(); } const TopLevelObject * domain = nullptr; self.AddIdentification (new CloseSurfaceIdentification (self.GetNIdentifications()+1, self, self.GetSurface (si1[0]), self.GetSurface (si2[0]), domain, flags)); }), py::arg("solid1"), py::arg("solid2"), py::arg("slices") ) .def("CloseSurfaces", FunctionPointer ([] (CSGeometry & self, shared_ptr s1, shared_ptr s2, int reflevels, shared_ptr domain_solid) { NgArray si1, si2; s1->GetSolid()->GetSurfaceIndices (si1); s2->GetSolid()->GetSurfaceIndices (si2); cout << IM(3) << "surface ids1 = " << si1 << endl; cout << IM(3) << "surface ids2 = " << si2 << endl; Flags flags; const TopLevelObject * domain = nullptr; if (domain_solid) domain = self.GetTopLevelObject(domain_solid->GetSolid()); self.AddIdentification (new CloseSurfaceIdentification (self.GetNIdentifications()+1, self, self.GetSurface (si1[0]), self.GetSurface (si2[0]), domain, flags)); }), py::arg("solid1"), py::arg("solid2"), py::arg("reflevels")=2, py::arg("domain")=nullptr ) .def("PeriodicSurfaces", FunctionPointer ([] (CSGeometry & self, shared_ptr s1, shared_ptr s2, Transformation<3> trafo) { NgArray si1, si2; s1->GetSolid()->GetSurfaceIndices (si1); s2->GetSolid()->GetSurfaceIndices (si2); cout << "identify surfaces " << si1[0] << " and " << si2[0] << endl; self.AddIdentification (new PeriodicIdentification (self.GetNIdentifications()+1, self, self.GetSurface (si1[0]), self.GetSurface (si2[0]), trafo)); }), py::arg("solid1"), py::arg("solid2"), py::arg("trafo")=Transformation<3>(Vec<3>(0,0,0)) ) .def("NameEdge", [] (CSGeometry & self, shared_ptr s1, shared_ptr s2, string name) { Array surfs1, surfs2; s1->GetSolid()->ForEachSurface( [&surfs1] (Surface * s, bool inv) { surfs1.Append(s); }); s2->GetSolid()->ForEachSurface( [&surfs2] (Surface * s, bool inv) { surfs2.Append(s); }); for (auto s1 : surfs1) for (auto s2 : surfs2) self.named_edges[tuple(s1,s2)] = name; }) .def("AddPoint", [] (CSGeometry & self, Point<3> p, variant index) -> CSGeometry& { if (auto pint = std::get_if (&index)) self.AddUserPoint(CSGeometry::UserPoint(p, *pint)); if (auto pstr = std::get_if (&index)) self.AddUserPoint(CSGeometry::UserPoint(p, *pstr)); return self; }) .def("GetTransparent", FunctionPointer ([] (CSGeometry & self, int tlonr) { return self.GetTopLevelObject(tlonr)->GetTransparent(); }), py::arg("tlonr") ) .def("SetTransparent", FunctionPointer ([] (CSGeometry & self, int tlonr, bool transparent) { self.GetTopLevelObject(tlonr)->SetTransparent(transparent); }), py::arg("tlonr"), py::arg("transparent") ) .def("GetVisible", FunctionPointer ([] (CSGeometry & self, int tlonr) { return self.GetTopLevelObject(tlonr)->GetVisible(); }), py::arg("tlonr") ) .def("SetVisible", FunctionPointer ([] (CSGeometry & self, int tlonr, bool visible) { self.GetTopLevelObject(tlonr)->SetVisible(visible); }), py::arg("tlonr"), py::arg("visible") ) .def("SetBoundingBox", FunctionPointer ([] (CSGeometry & self, Point<3> pmin, Point<3> pmax) { self.SetBoundingBox(Box<3> (pmin, pmax)); }), py::arg("pmin"), py::arg("pmax") ) .def("Draw", FunctionPointer ([] (shared_ptr self) { self->FindIdenticSurfaces(1e-8 * self->MaxSize()); self->CalcTriangleApproximation(0.01, 20); ng_geometry = self; }) ) .def("GetSolids", [](CSGeometry& self) { py::list lst; for(auto i : Range(self.GetSolids().Size())) lst.append(make_shared(self.GetSolids()[i], 1234)); return lst; }) .def_property_readonly ("ntlo", &CSGeometry::GetNTopLevelObjects) .def("_visualizationData", [](shared_ptr csg_geo) { std::vector vertices; std::vector trigs; std::vector normals; std::vector min = {std::numeric_limits::max(), std::numeric_limits::max(), std::numeric_limits::max()}; std::vector max = {std::numeric_limits::lowest(), std::numeric_limits::lowest(), std::numeric_limits::lowest()}; std::vector surfnames; for (int i = 0; i < csg_geo->GetNSurf(); i++) { auto surf = csg_geo->GetSurface(i); surfnames.push_back(surf->GetBCName()); } csg_geo->FindIdenticSurfaces(1e-8 * csg_geo->MaxSize()); csg_geo->CalcTriangleApproximation(0.01,20); auto nto = csg_geo->GetNTopLevelObjects(); size_t np = 0; size_t ntrig = 0; for (int i = 0; i < nto; i++){ np += csg_geo->GetTriApprox(i)->GetNP(); ntrig += csg_geo->GetTriApprox(i)->GetNT(); } vertices.reserve(np*3); trigs.reserve(ntrig*4); normals.reserve(np*3); int offset_points = 0; for (int i = 0; i < nto; i++) { auto triapprox = csg_geo->GetTriApprox(i); for (int j = 0; j < triapprox->GetNP(); j++) for(int k = 0; k < 3; k++) { float val = triapprox->GetPoint(j)[k]; vertices.push_back(val); min[k] = min2(min[k], val); max[k] = max2(max[k],val); normals.push_back(triapprox->GetNormal(j)[k]); } for (int j = 0; j < triapprox->GetNT(); j++) { for(int k = 0; k < 3; k++) trigs.push_back(triapprox->GetTriangle(j)[k]+offset_points); trigs.push_back(triapprox->GetTriangle(j).SurfaceIndex()); } offset_points += triapprox->GetNP(); } py::gil_scoped_acquire ac; py::dict res; py::list snames; for(auto name : surfnames) snames.append(py::cast(name)); res["vertices"] = MoveToNumpy(vertices); res["triangles"] = MoveToNumpy(trigs); res["normals"] = MoveToNumpy(normals); res["surfnames"] = snames; res["min"] = MoveToNumpy(min); res["max"] = MoveToNumpy(max); return res; }, py::call_guard()) .def("GenerateMesh", [](shared_ptr geo, MeshingParameters* pars, py::kwargs kwargs) { MeshingParameters mp; if(pars) mp = *pars; CreateMPfromKwargs(mp, kwargs); py::gil_scoped_release gil_rel; auto mesh = make_shared(); SetGlobalMesh (mesh); mesh->SetGeometry(geo); ng_geometry = geo; geo->FindIdenticSurfaces(1e-8 * geo->MaxSize()); auto result = geo->GenerateMesh (mesh, mp); if(result != 0) throw Exception("Meshing failed!"); return mesh; }, py::arg("mp") = nullptr, meshingparameter_description.c_str()) ; m.def("Save", FunctionPointer ([](const Mesh & self, const string & filename, const CSGeometry & geom) { ostream * outfile; if (filename.substr (filename.length()-3, 3) == ".gz") outfile = new ogzstream (filename.c_str()); else outfile = new ofstream (filename.c_str()); self.Save (*outfile); *outfile << endl << endl << "endmesh" << endl << endl; geom.SaveToMeshFile (*outfile); delete outfile; }),py::call_guard()) ; m.def("ZRefinement", FunctionPointer ([](Mesh & mesh, CSGeometry & geom) { ZRefinementOptions opt; opt.minref = 5; ZRefinement (mesh, &geom, opt); }),py::call_guard()) ; } PYBIND11_MODULE(libcsg, m) { ExportCSG(m); } #endif ================================================ FILE: libsrc/csg/revolution.cpp ================================================ #include #include #include #include namespace netgen { void RevolutionFace :: Init(void) { const LineSeg<2> * line = dynamic_cast*>(spline); const SplineSeg3<2> * spline3 = dynamic_cast*>(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_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; maxh = spline_in.GetMaxh(); bcname = spline_in.GetBCName(); Init(); } RevolutionFace :: RevolutionFace(const NgArray & raw_data) { deletable = true; int pos = 0; NgArray< Point<2> > p(3); int stype = int(raw_data[pos]); pos++; for(int i=0; i(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 & 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(&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); if(spline_coefficient_shifted.Size() == 0) spline->GetCoeff(spline_coefficient_shifted, spline->StartPI()); Point<2> p; CalcProj(point,p); /* double val = 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); */ Vec<2> pr = p-spline->StartPI(); // cout << "spline_coefficinet = " << spline_coefficient << endl; // cout << "shifted = " << spline_coefficient_shifted << endl; double val2 = spline_coefficient_shifted(0)*pr(0)*pr(0) + spline_coefficient_shifted(1)*pr(1)*pr(1) + spline_coefficient_shifted(2)*pr(0)*pr(1) + spline_coefficient_shifted(3)*pr(0) + spline_coefficient_shifted(4)*pr(1) + spline_coefficient_shifted(5); // cout << "val = " << val << " =?= " << val2 << endl; return val2; } void RevolutionFace :: CalcGradient (const Point<3> & point, Vec<3> & grad) const { if(spline_coefficient.Size() == 0) spline->GetCoeff(spline_coefficient); if(spline_coefficient_shifted.Size() == 0) spline->GetCoeff(spline_coefficient_shifted, spline->StartPI()); 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("< 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 < 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(); NgArray < Point<2> > checkpoints; const SplineSeg3<2> * ss3 = dynamic_cast *>(spline); const LineSeg<2> * ls = dynamic_cast *>(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 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: NgArray testt; if(!isfirst) testt.Append(0); if(!islast) testt.Append(1); const SplineSegment3 * s3 = dynamic_cast(&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 & 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 & 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(&spline); const SplineSegment3 * spline3 = dynamic_cast(&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 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 */ bool RevolutionFace :: PointInFace (const Point<3> & p, const double eps) const { Point<2> p2d; CalcProj(p,p2d); if (!spline -> InConvexHull(p2d, eps)) return false; /* 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); */ Vec<2> pr = p2d - spline->StartPI(); double val = spline_coefficient_shifted(0)*pr(0)*pr(0) + spline_coefficient_shifted(1)*pr(1)*pr(1) + spline_coefficient_shifted(2)*pr(0)*pr(1) + spline_coefficient_shifted(3)*pr(0) + spline_coefficient_shifted(4)*pr(1) + spline_coefficient_shifted(5); return (fabs(val) < eps); /* if(val > eps) return IS_OUTSIDE; if(val < -eps) return IS_INSIDE; return DOES_INTERSECT; */ } void RevolutionFace :: GetRawData(NgArray & 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, shared_ptr> spline_in) : p0(p0_in), p1(p1_in), splinegeo(spline_in) { auto nsplines = spline_in->GetNSplines(); surfaceactive.SetSize(0); surfaceids.SetSize(0); v_axis = p1-p0; v_axis.Normalize(); if(spline_in->GetSpline(0).StartPI()(1) <= 0. && spline_in->GetSpline(nsplines-1).EndPI()(1) <= 0.) type = 2; else if (Dist(spline_in->GetSpline(0).StartPI(), spline_in->GetSpline(nsplines-1).EndPI()) < 1e-7) type = 1; else cerr << "Surface of revolution cannot be constructed" << endl; for(int i=0; iGetNSplines(); i++) { faces.Append(new RevolutionFace (spline_in->GetSpline(i), p0,v_axis, type==2 && i==0, type==2 && i==spline_in->GetNSplines()-1)); surfaceactive.Append(1); surfaceids.Append(0); } // checking if (type == 2) { auto t0 = spline_in->GetSpline(0).GetTangent(0); cout << "tstart (must be vertically): " << t0 << endl; auto tn = spline_in->GetSpline(nsplines-1).GetTangent(1); cout << "tend (must be vertically): " << tn << endl; for (int i = 0; i < nsplines-1; i++) { auto ta = spline_in->GetSpline(i).GetTangent(1); auto tb = spline_in->GetSpline(i+1).GetTangent(0); cout << "sin (must not be 0) = " << abs(ta(0)*tb(1)-ta(1)*tb(0)) / (Abs(ta)*Abs(tb)); } } } Revolution::~Revolution() { for(int i=0; i & box) const { for(int i=0; iBoxIntersectsFace(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) && iBoxIntersectsFace(box2d,thisuncertain); intersection = intersection || thisintersects; if(thisintersects && !thisuncertain) uncertain = false; } if(intersection) { if(!uncertain) return DOES_INTERSECT; else { NgArray < 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); [[maybe_unused]] int intersections_before(0), intersections_after(0); double randomx = 7.42357; double randomy = 1.814756; double randomlen = sqrt(randomx*randomx+randomy*randomy); randomx *= 1./randomlen; randomy *= 1./randomlen; const double a = randomy; const double b = -randomx; const double c = -a*p2d(0)-b*p2d(1); NgArray < Point<2> > points; //(*testout) << "face intersections at: " << endl; for(int i=0; iGetSpline().LineIntersections(a,b,c,points,eps); for(int j=0; j eps ) intersections_after++; else { intersecting_face = i; return DOES_INTERSECT; } } } if(intersections_after % 2 == 0) return IS_OUTSIDE; else return IS_INSIDE; } void Revolution :: GetTangentialSurfaceIndices (const Point<3> & p, NgArray & surfind, double eps) const { for (int j = 0; j < faces.Size(); j++) if (faces[j] -> PointInFace(p, eps)) if (!surfind.Contains (GetSurfaceId(j))) surfind.Append (GetSurfaceId(j)); } 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; } NgArray intersecting_faces; for(int i=0; iPointInFace(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 *>(&faces[intersecting_faces[0]]->GetSpline()); const LineSeg<2> * linesegment = dynamic_cast *>(&faces[intersecting_faces[0]]->GetSpline()); Vec<2> t1(0),t2(0); if(linesegment) t1 = linesegment->StartPI() - linesegment->EndPI(); else if(splinesegment3) t1 = splinesegment3->TangentPoint() - splinesegment3->EndPI(); linesegment = dynamic_cast *>(&faces[intersecting_faces[1]]->GetSpline()); splinesegment3 = dynamic_cast *>(&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); } void Revolution :: GetTangentialVecSurfaceIndices2 (const Point<3> & p, const Vec<3> & v1, const Vec<3> & v2, NgArray & surfind, double eps) const { *testout << "tangentialvecsurfind2, p = " << p << endl; for (int i = 0; i < faces.Size(); i++) if (faces[i]->PointInFace (p, eps)) { *testout << "check face " << i << endl; Point<2> p2d; Vec<2> v12d; faces[i]->CalcProj(p,p2d,v1,v12d); *testout << "v12d = " << v12d << endl; auto & spline = faces[i]->GetSpline(); if (Dist2 (spline.StartPI(), p2d) < sqr(eps)) { *testout << "start pi" << endl; Vec<2> tang = spline.GetTangent(0); double ip = tang*v12d; *testout << "ip = " << ip << endl; if (ip > eps) surfind.Append(GetSurfaceId(i)); else if (ip > -eps) { Vec<2> v22d; faces[i]->CalcProj(p,p2d,v2,v22d); double ip2 = tang*v22d; *testout << "ip2 = " << ip2 << endl; if (ip2 > -eps) surfind.Append(GetSurfaceId(i)); } } else if (Dist2 (faces[i]->GetSpline().EndPI(), p2d) < sqr(eps)) { *testout << "end pi" << endl; Vec<2> tang = spline.GetTangent(1); double ip = tang*v12d; *testout << "ip = " << ip << endl; if (ip < -eps) surfind.Append(GetSurfaceId(i)); else if (ip < eps) { Vec<2> v22d; faces[i]->CalcProj(p,p2d,v2,v22d); double ip2 = tang*v22d; *testout << "ip2 = " << ip2 << endl; if (ip2 < eps) surfind.Append(GetSurfaceId(i)); } } else { *testout << "inner point" << endl; surfind.Append(GetSurfaceId(i)); } } } 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; iBoxIntersectsFace(box)); //surfaceactive[i] = (faces[i]->BoxIntersectsFace(box,dummy)); } void Revolution :: UnReduce () { for(int i=0; i regrevf; RegisterClassForArchive regrev; } ================================================ FILE: libsrc/csg/revolution.hpp ================================================ #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; // coefficient for implicizt polynomial mutable Vector spline_coefficient; mutable Vector spline_coefficient_shifted; NgArray < Vec<2>* > checklines_vec; NgArray < Point<2>* > checklines_start; NgArray < 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 NgArray & raw_data); // default constructor for archive RevolutionFace() {} ~RevolutionFace(); virtual void DoArchive(Archive& ar) { Surface::DoArchive(ar); ar & isfirst & islast & spline & deletable & p0 & v_axis & id & spline_coefficient & spline_coefficient_shifted & checklines_vec & checklines_start & checklines_normal; } 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; Point<3> P0() const { return p0; } Vec<3> Axis() const { return v_axis; } 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 */ bool PointInFace (const Point<3> & p, const double eps) const; void GetRawData(NgArray & data) const; }; /* Primitive of revolution */ class Revolution : public Primitive { private: Point<3> p0,p1; Vec<3> v_axis; // 1 ... torus-like // 2 ... sphere-like int type; Array faces; shared_ptr> splinegeo; mutable int intersecting_face; public: Revolution(const Point<3> & p0_in, const Point<3> & p1_in, shared_ptr> spline_in); // default constructor for archive Revolution() {} ~Revolution(); virtual void DoArchive(Archive& ar) { Primitive::DoArchive(ar); ar & p0 & p1 & v_axis & type & faces & intersecting_face; } /* 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 void GetTangentialSurfaceIndices (const Point<3> & p, NgArray & surfind, 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 GetTangentialVecSurfaceIndices2 (const Point<3> & p, const Vec<3> & v1, const Vec<3> & v2, NgArray & surfind, 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 ================================================ FILE: libsrc/csg/singularref.cpp ================================================ #include #include #include #include #include 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); NgArray 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++) { PointIndices<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[i2.I1()]); points.Append (mesh[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); NgArray surfk, surf; for (PointIndex pi = IndexBASE(); pi < mesh.GetNP()+IndexBASE(); 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; } auto tansol = solk -> TangentialSolid (p, 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); } } ================================================ FILE: libsrc/csg/singularref.hpp ================================================ #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 boundary layer mesh refinement. All elements in subdomain domnr will get a boundary layer on faces sharing the solid sol */ class DLL_HEADER SingularFace { public: int domnr; const Solid *sol; double factor; // NgArray > points; // NgArray 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 DLL_HEADER SingularEdge { public: double beta; int domnr; const CSGeometry& geom; const Solid *sol1, *sol2; NgArray > points; NgArray 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 DLL_HEADER SingularPoint { public: double beta; const Solid *sol1, *sol2, *sol3; NgArray > 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 ================================================ FILE: libsrc/csg/solid.cpp ================================================ #include #include #include namespace netgen { // int Solid :: cntnames = 0; Solid :: Solid (Primitive * aprim) { op = TERM; prim = aprim; s1 = s2 = NULL; maxh = 1e10; name = NULL; num_surfs = prim->GetNSurfaces(); } Solid :: Solid (optyp aop, Solid * as1, Solid * as2) { op = aop; s1 = as1; s2 = as2; prim = NULL; name = NULL; maxh = 1e10; num_surfs = 0; if (s1) num_surfs += s1->num_surfs; if (s2) num_surfs += s2->num_surfs; } 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 } } INSOLID_TYPE Solid :: PointInSolid (const Point<3> & p, double eps) const { switch (op) { case TERM: case TERM_REF: return prim->PointInSolid (p, eps); case SECTION: return Intersection (s1->PointInSolid (p, eps), s2->PointInSolid (p, eps)); case UNION: return Union (s1->PointInSolid (p, eps), s2->PointInSolid (p, eps)); case SUB: return Complement (s1->PointInSolid (p, eps)); case ROOT: return s1->PointInSolid (p, eps); } throw Exception("PointInSolid: invalid op"); } INSOLID_TYPE Solid :: VecInSolid (const Point<3> & p, const Vec<3> & v, double eps) const { switch (op) { case TERM: case TERM_REF: return prim->VecInSolid (p, v, eps); case SECTION: return Intersection (s1->VecInSolid (p, v, eps), s2->VecInSolid (p, v, eps)); case UNION: return Union (s1->VecInSolid (p, v, eps), s2->VecInSolid (p, v, eps)); case SUB: return Complement (s1->VecInSolid (p, v, eps)); case ROOT: return s1->VecInSolid (p, v, eps); } throw Exception("VecInSolid: invalid op"); } // checks if lim s->0 lim t->0 p + t(v1 + s v2) in solid INSOLID_TYPE Solid :: VecInSolid2 (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); case SECTION: return Intersection (s1->VecInSolid2 (p, v1, v2, eps), s2->VecInSolid2 (p, v1, v2, eps)); case UNION: return Union (s1->VecInSolid2 (p, v1, v2, eps), s2->VecInSolid2 (p, v1, v2, eps)); case SUB: return Complement (s1->VecInSolid2 (p, v1, v2, eps)); case ROOT: return s1->VecInSolid2 (p, v1, v2, eps); } throw Exception("VecInSolid2: invalid op"); } bool Solid :: IsIn (const Point<3> & p, double eps) const { return PointInSolid (p,eps) != IS_OUTSIDE; /* 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 { return PointInSolid (p,eps) == IS_INSIDE; /* 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 { return VecInSolid (p,v,eps) != IS_OUTSIDE; /* 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 { return VecInSolid (p,v,eps) == IS_INSIDE; /* 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; } */ bool Solid::VectorIn2 (const Point<3> & p, const Vec<3> & v1, const Vec<3> & v2, double eps) const { return VecInSolid2 (p,v1,v2,eps) != IS_OUTSIDE; /* switch (op) { case TERM: case TERM_REF: { auto res = prim->VecInSolid2 (p, v1, v2, eps); return res != IS_OUTSIDE; } case SECTION: return s1->VectorIn2 (p, v1, v2, eps) && s2->VectorIn2 (p, v1, v2, eps); case UNION: return s1->VectorIn2 (p, v1, v2, eps) || s2->VectorIn2 (p, v1, v2, eps); case SUB: return !s1->VectorStrictIn2 (p, v1, v2, eps); case ROOT: return s1->VectorIn2 (p, v1, v2, eps); } // return 0; */ } bool Solid :: VectorStrictIn2 (const Point<3> & p, const Vec<3> & v1, const Vec<3> & v2, double eps) const { return VecInSolid2 (p,v1,v2,eps) == IS_INSIDE; /* switch (op) { case TERM: case TERM_REF: { auto res = prim->VecInSolid2 (p, v1, v2, eps); return (res == IS_INSIDE); } case SECTION: return s1->VectorStrictIn2 (p, v1, v2, eps) && s2->VectorStrictIn2 (p, v1, v2, eps); case UNION: return s1->VectorStrictIn2 (p, v1, v2, eps) || s2->VectorStrictIn2 (p, v1, v2, eps); case SUB: return !s1->VectorIn2 (p, v1, v2, eps); case ROOT: return s1->VectorStrictIn2 (p, v1, v2, eps); } */ } 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 & solids); static Solid * CreateSolidTerm (istream & ist, const SymbolTable & solids); static Solid * CreateSolidPrim (istream & ist, const SymbolTable & 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 & 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 & 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 & 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[str]; if (s1) { // cout << "primitive: " << str << endl; return s1; } cerr << "syntax error" << endl; return NULL; } Solid * Solid :: CreateSolid (istream & ist, const SymbolTable & 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, NgArray & bounds) const { int in, strin; bounds.SetSize (0); RecBoundaries (p, bounds, in, strin); } void Solid :: RecBoundaries (const Point<3> & p, NgArray & 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; NgArray 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; NgArray 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; } } } unique_ptr Solid :: TangentialSolid (const Point<3> & p, NgArray & surfids, double eps) const { bool in, strin; Solid * tansol = nullptr; RecTangentialSolid (p, tansol, surfids, in, strin, eps); surfids.SetSize (0); if (tansol) tansol -> GetTangentialSurfaceIndices (p, surfids, eps); return unique_ptr (tansol); } void Solid :: RecTangentialSolid (const Point<3> & p, Solid *& tansol, NgArray & surfids, bool & in, bool & 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: { bool 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: { bool 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: { bool 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; } } } unique_ptr Solid :: TangentialSolid2 (const Point<3> & p, const Vec<3> & t, NgArray & surfids, double eps) const { Solid * tansol = nullptr; bool in, strin; surfids.SetSize (0); RecTangentialSolid2 (p, t, tansol, surfids, in, strin, eps); if (tansol) tansol -> GetTangentialSurfaceIndices2 (p, t, surfids, eps); return unique_ptr (tansol); } void Solid :: RecTangentialSolid2 (const Point<3> & p, const Vec<3> & t, Solid *& tansol, NgArray & surfids, bool & in, bool & strin, double eps) const { tansol = nullptr; 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: { bool 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: { bool 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: { bool 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; } } } unique_ptr Solid :: TangentialSolid3 (const Point<3> & p, const Vec<3> & t, const Vec<3> & t2, NgArray & surfids, double eps) const { bool in, strin; Solid * tansol = nullptr; surfids.SetSize (0); RecTangentialSolid3 (p, t, t2, tansol, surfids, in, strin, eps); if (tansol) tansol -> GetTangentialSurfaceIndices3 (p, t, t2, surfids, eps); return unique_ptr(tansol); } void Solid :: RecTangentialSolid3 (const Point<3> & p, const Vec<3> & t, const Vec<3> & t2, Solid *& tansol, NgArray & surfids, bool & in, bool & strin, double eps) const { tansol = nullptr; 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: { bool 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: { bool 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: { bool 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; } } } unique_ptr Solid :: TangentialEdgeSolid (const Point<3> & p, const Vec<3> & t, const Vec<3> & t2, const Vec<3> & m, NgArray & surfids, double eps) const { Solid * tansol = nullptr; bool 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); return unique_ptr (tansol); } void Solid :: RecTangentialEdgeSolid (const Point<3> & p, const Vec<3> & t, const Vec<3> & t2, const Vec<3> & m, Solid *& tansol, NgArray & surfids, bool & in, bool & 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: { bool 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: { bool 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: { bool 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 { bool in, strin; int 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 { bool in, strin; int faces; RecEdge (p, v, in, strin, faces, eps); return faces >= 1; } void Solid :: RecEdge (const Point<3> & p, const Vec<3> & v, bool & in, bool & 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: { bool in1, in2, strin1, strin2; int 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: { bool in1, in2, strin1, strin2; int 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: { bool 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 { if (num_surfs <= 2) { // checking special case for degenerated plane - cylinder, Dec 2014 int cnt_plane = 0, cnt_cyl = 0; bool inv_plane, inv_cyl; Plane * plane; Cylinder * cyl; ForEachSurface ( [&] (Surface * surf, bool inv) { if (dynamic_cast(surf)) { cnt_plane++; plane = dynamic_cast(surf); inv_plane = inv; } if (dynamic_cast(surf)) { cnt_cyl++; cyl = dynamic_cast(surf); inv_cyl = inv; } }); if (cnt_plane == 1 && cnt_cyl == 1) { double scala = (cyl->A()-plane->P()) * plane->N(); double scalb = (cyl->B()-plane->P()) * plane->N(); double scal = plane->N() * plane->N(); if ( ( fabs (scala*scala - cyl->R()*cyl->R()*scal) < 1e-10*cyl->R()*cyl->R() ) && ( fabs (scalb*scalb - cyl->R()*cyl->R()*scal) < 1e-10*cyl->R()*cyl->R() ) ) { // intersection edge in box ? Point<3> p0 = cyl->A() - (scala/scal) * plane->N(); Vec<3> vedge = cyl->B() - cyl->A(); Vec<3> ve_center = box.Center()-p0; // dist(lam) = \| ve_center \|^2 - 2 lam (vedge, ve_center) + lam^2 \| vedge \|^2 double num = vedge*ve_center; double den = vedge*vedge; double dist_edge_center2 = ve_center*ve_center - num * num /den; bool edge_in_box = dist_edge_center2 < sqr (box.Diam()); if (!edge_in_box) { if (op == SECTION) { // cout << "solid = " << *this << endl; if (!inv_cyl && !inv_plane && scala < 0) { // cout << "fix for degenerated cyl-plane edge: just the cylinder" << endl; Solid * sol = new Solid (cyl); sol -> op = TERM_REF; return sol; } } if (op == UNION) { // cout << "solid = " << *this << ", inv_plane = " << inv_plane << " inv_cyl = " << inv_cyl << " scalb " << scalb << endl; if (!inv_plane && !inv_cyl && (scala < 0)) { // cout << "fix for degenerated cyl-plane edge: just the plane" << endl; // return new Solid (plane); Solid * sol = new Solid (plane); sol -> op = TERM_REF; return sol; } } ; // *testout << "have 1 plane and 1 cyl, degenerated" << endl; } } } } 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 (NgArray & surfind) const { surfind.SetSize (0); RecGetSurfaceIndices (surfind); } void Solid :: RecGetSurfaceIndices (NgArray & 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 :: ForEachSurface (const std::function & lambda, bool inv) const { switch (op) { case TERM: case TERM_REF: { for (int j = 0; j < prim->GetNSurfaces(); j++) if (prim->SurfaceActive (j)) lambda (&prim->GetSurface(j), inv); break; } case UNION: case SECTION: { s1 -> ForEachSurface (lambda, inv); s2 -> ForEachSurface (lambda, inv); break; } case SUB: { s1 -> ForEachSurface (lambda, !inv); break; } case ROOT: { s1 -> ForEachSurface (lambda, inv); break; } } } void Solid :: GetTangentialSurfaceIndices (const Point<3> & p, NgArray & surfind, double eps) const { surfind.SetSize (0); RecGetTangentialSurfaceIndices (p, surfind, eps); } void Solid :: RecGetTangentialSurfaceIndices (const Point<3> & p, NgArray & 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, NgArray & surfind, double eps) const { surfind.SetSize (0); RecGetTangentialSurfaceIndices2 (p, v, surfind, eps); } void Solid :: RecGetTangentialSurfaceIndices2 (const Point<3> & p, const Vec<3> & v, NgArray & 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, NgArray & 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, NgArray & 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, NgArray & 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, NgArray > & 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 (NgArray > & 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)); shared_ptr Solid :: ball = make_shared(sizeof (Solid)); } ================================================ FILE: libsrc/csg/solid.hpp ================================================ #ifndef FILE_SOLID #define FILE_SOLID /**************************************************************************/ /* File: solid.hh */ /* Author: Joachim Schoeberl */ /* Date: 1. Dez. 95 */ /**************************************************************************/ #include namespace netgen { /* Constructive Solid Model (csg) */ class Solid; class SolidIterator { public: SolidIterator () { ; } virtual ~SolidIterator () { ; } virtual void Do (Solid * sol) = 0; }; inline INSOLID_TYPE Intersection (INSOLID_TYPE ina, INSOLID_TYPE inb) { if (ina == IS_INSIDE && inb == IS_INSIDE) return IS_INSIDE; if (ina == IS_OUTSIDE || inb == IS_OUTSIDE) return IS_OUTSIDE; return DOES_INTERSECT; } inline INSOLID_TYPE Union (INSOLID_TYPE ina, INSOLID_TYPE inb) { if (ina == IS_INSIDE || inb == IS_INSIDE) return IS_INSIDE; if (ina == IS_OUTSIDE && inb == IS_OUTSIDE) return IS_OUTSIDE; return DOES_INTERSECT; } inline INSOLID_TYPE Complement (INSOLID_TYPE in) { if (in == IS_INSIDE) return IS_OUTSIDE; if (in == IS_OUTSIDE) return IS_INSIDE; return DOES_INTERSECT; } 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; int num_surfs; // static int cntnames; public: Solid (Primitive * aprim); Solid (optyp aop, Solid * as1, Solid * as2 = NULL); // default constructor for archive Solid () {} ~Solid (); void DoArchive(Archive& archive) { archive & name & prim & s1 & s2 & visited & maxh & num_surfs; if(archive.Output()) archive << int(op); else { int iop; archive & iop; op = optyp(iop); } } 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, NgArray & bounds) const; int NumPrimitives () const; void GetSurfaceIndices (NgArray & surfind) const; void GetSurfaceIndices (IndexSet & iset) const; void GetTangentialSurfaceIndices (const Point<3> & p, NgArray & surfids, double eps) const; void GetTangentialSurfaceIndices2 (const Point<3> & p, const Vec<3> & v, NgArray & surfids, double eps) const; void GetTangentialSurfaceIndices3 (const Point<3> & p, const Vec<3> & v, const Vec<3> & v2, NgArray & surfids, double eps) const; void ForEachSurface (const std::function & lambda, bool inv = false) 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 INSOLID_TYPE PointInSolid (const Point<3> & p, double eps) const; 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 INSOLID_TYPE VecInSolid2 (const Point<3> & p, const Vec<3> & v1, const Vec<3> & v2, double eps) const; 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; */ bool VectorStrictIn2 (const Point<3> & p, const Vec<3> & v1, const Vec<3> & v2, double eps) const; /// compute localization in point p unique_ptr TangentialSolid (const Point<3> & p, NgArray & surfids, double eps) const; /// compute localization in point p tangential to vector t unique_ptr TangentialSolid2 (const Point<3> & p, const Vec<3> & t, NgArray & surfids, double eps) const; /** compute localization in point p, with second order approximation to edge p + s t + s*s/2 t2 **/ unique_ptr TangentialSolid3 (const Point<3> & p, const Vec<3> & t, const Vec<3> & t2, NgArray & 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 **/ unique_ptr TangentialEdgeSolid (const Point<3> & p, const Vec<3> & t, const Vec<3> & t2, const Vec<3> & m, NgArray & surfids, double eps) const; void CalcOnePrimitiveSpecialPoints (const Box<3> & box, NgArray > & 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 & solids); static shared_ptr 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, NgArray & bounds, int & in, int & strin) const; /// void RecTangentialSolid (const Point<3> & p, Solid *& tansol, NgArray & surfids, bool & in, bool & strin, double eps) const; void RecTangentialSolid2 (const Point<3> & p, const Vec<3> & vec, Solid *& tansol, NgArray & surfids, bool & in, bool & strin, double eps) const; /// void RecTangentialSolid3 (const Point<3> & p, const Vec<3> & vec,const Vec<3> & vec2, Solid *& tansol, NgArray & surfids, bool & in, bool & strin, double eps) const; /// void RecTangentialEdgeSolid (const Point<3> & p, const Vec<3> & t, const Vec<3> & t2, const Vec<3> & m, Solid *& tansol, NgArray & surfids, bool & in, bool & strin, double eps) const; /// void RecEdge (const Point<3> & p, const Vec<3> & v, bool & in, bool & strin, int & faces, double eps) const; /// void CalcSurfaceInverseRec (int inv); /// Solid * RecGetReducedSolid (const BoxSphere<3> & box, INSOLID_TYPE & in) const; /// void RecGetSurfaceIndices (NgArray & surfind) const; void RecGetTangentialSurfaceIndices (const Point<3> & p, NgArray & surfids, double eps) const; void RecGetTangentialSurfaceIndices2 (const Point<3> & p, const Vec<3> & v, NgArray & surfids, double eps) const; void RecGetTangentialSurfaceIndices3 (const Point<3> & p, const Vec<3> & v, const Vec<3> & v2, NgArray & surfids, double eps) const; void RecGetTangentialEdgeSurfaceIndices (const Point<3> & p, const Vec<3> & v, const Vec<3> & v2, const Vec<3> & m, NgArray & surfids, double eps) const; void RecGetSurfaceIndices (IndexSet & iset) const; void RecCalcOnePrimitiveSpecialPoints (NgArray > & 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 { 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 ================================================ FILE: libsrc/csg/specpoin.cpp ================================================ #include #include #include /* 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 { DLL_HEADER NgArray > boxes; // for visualization 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 NgArray numprim_hist; SpecialPointCalculation :: SpecialPointCalculation () { ideps = 1e-9; } void SpecialPointCalculation :: CalcSpecialPoints (const CSGeometry & ageometry, NgArray & 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()) { NgArray > 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(geometry->identifications[i]); if(!ident || !ident->IsSkewIdentification()) continue; for(int j=0; jSize(); 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()); } if (level == 40 || level == 41 || level == 45) { *testout << "level = " << level << " cp = " << calccp << " ep = " << calcep << ", box = " << box << ", solid = " << *sol << endl; } bool decision; bool possiblecrossp, possibleexp; // possible cross or extremalpoint bool surecrossp = 0, sureexp = 0; // sure ... // static NgArray locsurf; // attention: array is static NgArrayMem locsurf; // 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 (geometry->GetSurface(locsurf[i])); if (qsurfi) nquad++; if (dynamic_cast (qsurfi)) nplane++; else { quadi = i; qsurf = qsurfi; } if (dynamic_cast (qsurfi)) nsphere++; } /* if (nquad == numprim && nplane == numprim-2) return; */ #ifdef DEVELOP (*testout) << "nquad " << nquad << " nplane " << nplane << endl; #endif if (nquad == numprim && nplane >= numprim-1) { NgArray > pts; NgArray 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 (geometry->GetSurface(locsurf[k1])), dynamic_cast (geometry->GetSurface(locsurf[k2])), dynamic_cast (geometry->GetSurface(locsurf[k3])), pts); for (auto pnt : pts) if (Dist (pnt, box.Center()) < box.Diam()/2) { auto tansol = sol -> TangentialSolid (pnt, surfids, 1e-9*size); if (tansol) { 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 (auto surfid : surfids) { int actrep = geometry->GetSurfaceClassRepresentant(surfid); if (actrep == rep1) ok1 = true; if (actrep == rep2) ok2 = true; if (actrep == rep3) ok3 = true; } if (ok1 && ok2 && ok3) if (AddPoint (pnt, layer)) (*testout) << "cross point found, 1: " << pnt << endl; } } } 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 (geometry->GetSurface(locsurf[k1])), dynamic_cast (geometry->GetSurface(locsurf[k2])), qsurf, pts); //(*testout) << "checking pot. crosspoints: " << pts << endl; for (auto pnt : pts) if (Dist (pnt, box.Center()) < box.Diam()/2) { auto tansol = sol -> TangentialSolid (pnt, surfids, 1e-9*size); if (tansol) { bool ok1 = false, ok2 = false, ok3 = true;//false; int rep1 = geometry->GetSurfaceClassRepresentant(locsurf[k1]); int rep2 = geometry->GetSurfaceClassRepresentant(locsurf[k2]); for (auto surfid : surfids) { int actrep = geometry->GetSurfaceClassRepresentant(surfid); if (actrep == rep1) ok1 = true; if (actrep == rep2) ok2 = true; } if (ok1 && ok2 && ok3) if (AddPoint (pnt, layer)) (*testout) << "cross point found, 2: " << pnt << endl; } } } for (int k1 = 0; k1 < numprim; k1++) if (k1 != quadi) { ComputeExtremalPoints (dynamic_cast (geometry->GetSurface(locsurf[k1])), qsurf, pts); for (int j = 0; j < pts.Size(); j++) if (Dist (pts[j], box.Center()) < box.Diam()/2) { auto tansol = sol -> TangentialSolid (pts[j], surfids, 1e-9*size); if (tansol) if (AddPoint (pts[j], layer)) (*testout) << "extremal point found, 1: " << pts[j] << endl; } } } return; } if (nsphere == numprim) // && calccp == false) { NgArray > pts; NgArray 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 (geometry->GetSurface(locsurf[k1])), dynamic_cast (geometry->GetSurface(locsurf[k2])), dynamic_cast (geometry->GetSurface(locsurf[k3])), pts); for (int j = 0; j < pts.Size(); j++) if (Dist (pts[j], box.Center()) < box.Diam()/2) { auto tansol = sol -> TangentialSolid (pts[j], 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; jjGetSurfaceClassRepresentant(surfids[jj]); if(actrep == rep1) ok1 = true; if(actrep == rep2) ok2 = true; if(actrep == rep3) ok3 = true; } if (ok1 && ok2 && ok3) if (AddPoint (pts[j], layer)) (*testout) << "cross point found, 1: " << pts[j] << endl; } } for (int k1 = 0; k1 < numprim; k1++) for (int k2 = 0; k2 < k1; k2++) { ComputeExtremalPoints (dynamic_cast (geometry->GetSurface(locsurf[k1])), dynamic_cast (geometry->GetSurface(locsurf[k2])), pts); for (int j = 0; j < pts.Size(); j++) if (Dist (pts[j], box.Center()) < box.Diam()/2) { auto tansol = sol -> TangentialSolid (pts[j], surfids, 1e-9*size); if (tansol) if (AddPoint (pts[j], layer)) (*testout) << "extremal point found, spheres: " << pts[j] << endl; } } return; } if (numprim == 2) { auto rev0 = dynamic_cast (geometry->GetSurface(locsurf[0])); auto rev1 = dynamic_cast (geometry->GetSurface(locsurf[1])); if (rev0 && rev1) { NgArray> pts; bool check = ComputeExtremalPoints (rev0, rev1, pts); if (check) { for (auto p : pts) if (box.IsIn(p)) AddPoint (p, layer); return; } } } } // end if (numprim <= check_crosspoint) 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(); NgArray 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; } } #ifdef DEVELOP (*testout) << "edgepnt decision = " << decision << " sure = " << sureexp << endl; #endif 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 << "box.diam = " << box.Diam() << ", dist = " << Dist(pp,box.Center()) << 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 decidable: 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; if ( Abs2 (Cross(g1,g2)) < 1e-10 * Abs2 (g1) * Abs2 (g2)) // same, but stable { if (Abs2(vrs) < 1e-12*sqr(size)) // degenerate only if on both surfaces return 1; else return 0; } 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, NgArray > & 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, NgArray > & 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, NgArray > & 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, NgArray > & 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, NgArray > & 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)) < fabs(v12(dir))) dir = j; 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 :: ComputeExtremalPoints (const RevolutionFace * rev1, const RevolutionFace * rev2, NgArray > & pts) { // if (rev1 -> P0() != rev2 -> P0()) return false; // missing ???? if (Dist2 (rev1 -> P0(), rev2 -> P0()) > 1e-20*sqr(size)) return false; // if (rev1 -> Axis() != rev2 -> Axis()) return false; if ( (rev1 -> Axis()-rev2 -> Axis()).Length2() > 1e-16) return false; Point<2> p1s = rev1->GetSpline().StartPI(); Point<2> p1e = rev1->GetSpline().EndPI(); Point<2> p2s = rev2->GetSpline().StartPI(); Point<2> p2e = rev2->GetSpline().EndPI(); Point<2> p2d; if (Dist2(p1s,p2e) < 1e-20*sqr(size)) p2d = p1s; else if (Dist2(p1e, p2s) < 1e-20*sqr(size)) p2d = p1e; else return false; *testout << "Norm axis = " << rev1->Axis().Length() << endl; Point<3> center = rev1->P0() + p2d(0)*rev1->Axis(); Vec<3> n = rev1->Axis(); // extremal points of circle, center, normal axis, radius p2d(1) // Lagrange: // L(x, lam1, lam2) = x_i + lam1 * (x-c)*v + lam2 * ( |x-c|^2 - r^2 ) for (double i = 0; i < 3; i++) { double lam1 = -n(i) / n.Length2(); Vec<3> ei(0,0,0); ei(i) = 1; // double lam2 = 1/(2*p2d(1)) * sqrt(1 - sqr(n(i))/n.Length2()); double fac = 1-sqr(n(i))/n.Length2(); // if (fabs(lam2) > 1e-10) if (fac > 1e-10) { double lam2 = 1/(2*p2d(1)) * sqrt(fac); Point<3> x = center - 1.0/(2*lam2) * (ei + lam1*n); pts.Append (x); x = center + 1.0/(2*lam2) * (ei + lam1*n); pts.Append (x); /* // check: Point<2> p2d; rev1 -> CalcProj (x, p2d); *testout << "special solution, p2d = " << p2d << endl; rev2 -> CalcProj (x, p2d); *testout << "special solution, p2d = " << p2d << endl; */ } } return true; } /* 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, NgArray & apoints, NgArray & specpoints) { static int timer = NgProfiler::CreateTimer ("CSG: analyze special points"); NgProfiler::RegionTimer reg (timer); NgArray surfind, rep_surfind, surfind2, rep_surfind2, surfind3; NgArray > normalvecs; Vec<3> nsurf = 0.0; NgArray 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); NgArray 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()); NgArray 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; auto locsol = sol -> TangentialSolid (p, 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 = false; for (int m = 0; m < surfind.Size(); m++) if (ageometry.GetSurface(surfind[m]) == surf) hassurf = true; 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 (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-16) { // cerr << "normal vectors degenerated" << endl; 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; #ifdef DEVELOP *testout << "t = " << t << ", t2 = " << t2 << endl; #endif /* ageometry.GetIndependentSurfaceIndices (locsol, p, t, surfind2); */ auto locsol2 = locsol -> TangentialSolid3 (p, t, t2, 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 NgArray 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; // locsol2 -> TangentialSolid2 (p, m1, locsol3, surfind3, 1e-9*geomsize); auto locsol3 = locsol -> TangentialEdgeSolid (p, t, t2, m1, surfind3, ideps*geomsize); #ifdef DEVELOP (*testout) << "m1 = " << m1 << ", surfind3 = " << surfind3 << endl; #endif //ageometry.GetIndependentSurfaceIndices (surfind3); if (surfind3.Contains(surfind2[l])) isface1 = 1; // locsol2 -> TangentialSolid2 (p, m2, locsol3, surfind3, 1e-9*geomsize); locsol3 = locsol -> TangentialEdgeSolid (p, t, t2, m2, surfind3, ideps*geomsize); #ifdef DEVELOP (*testout) << "m2 = " << m2 << ", surfind3 = " << surfind3 << endl; #endif // ageometry.GetIndependentSurfaceIndices (surfind3); if (surfind3.Contains(surfind2[l])) isface2 = 1; if (isface1 != isface2) cnt_tang_faces++; } #ifdef DEVELOP (*testout) << "cnt_tang = " << cnt_tang_faces << endl; #endif if (cnt_tang_faces < 1) ok = false; 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 isfaceold = (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 isfacenew = locsol -> VecInSolid2(p, t, s, 1e-6*geomsize) == DOES_INTERSECT || locsol -> VecInSolid2(p, t, -s, 1e-6*geomsize) == DOES_INTERSECT; /* (locsol->VectorIn2 (p, t, s, 1e-6*geomsize) && !locsol->VectorStrictIn2 (p, t, s, 1e-6*geomsize)) || (locsol->VectorIn2 (p, t, -s, 1e-6*geomsize) && !locsol->VectorStrictIn2 (p, t, -s, 1e-6*geomsize)); */ bool isface = isfacenew; if (isfaceold != isfacenew) { *testout << "different, p = " << p << ", t = " << t << ", s = " << s << endl; *testout << "tlo = " << si << endl; *testout << "isface, old = " << isface << ", isfacenew = " << isfacenew << endl; *testout << "t2a = " << t2a << endl; *testout << "vecin(p,t2a) = " << locsol->VectorIn (p, t2a, 1e-6*geomsize) << endl; *testout << "vecstrictin(p,t2a) = " << locsol->VectorStrictIn (p, t2a, 1e-6*geomsize) << endl; *testout << "vectorin2 = " << locsol->VectorIn2 (p, t, s, 1e-6*geomsize) << endl; *testout << "vectorstrictin2 = " << locsol->VectorStrictIn2 (p, t, s, 1e-6*geomsize) << endl; *testout << "t2b = " << t2b << endl; *testout << "vecin(p,t2b) = " << locsol->VectorIn (p, t2b, 1e-6*geomsize) << endl; *testout << "vecstrictin(p,t2b) = " << locsol->VectorStrictIn (p, t2b, 1e-6*geomsize) << endl; *testout << "vectorin2- = " << locsol->VectorIn2 (p, t, -s, 1e-6*geomsize) << endl; *testout << "vectorstrictin2- = " << locsol->VectorStrictIn2 (p, t, -s, 1e-6*geomsize) << endl; } /* 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]) < sqr(1e-8*geomsize) && Abs2(specpoints[locsearch[m]].v - t) < 1e-8) { spi = locsearch[m]; break; } } if (spi == -1) { specpoints.Append (SpecialPoint()); spi = specpoints.Size()-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; } } } } } // 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.SetBit (specpoint2point[i]); for (int i = 0; i < specpoints.Size(); i++) specpoints[i].unconditional = uncond.Test (specpoint2point[i]); } } ================================================ FILE: libsrc/csg/specpoin.hpp ================================================ #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; /// NgArray * points; /// NgArray boxesinlevel; /// double size; /// double relydegtest; // maximal dimension of bisection interval 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, NgArray & points); /// void AnalyzeSpecialPoints (const CSGeometry & geometry, NgArray & points, NgArray & 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, NgArray > & pts); void ComputeExtremalPoints (const Sphere * sphere1, const Sphere * sphere2, NgArray > & pts); bool ComputeExtremalPoints (const RevolutionFace * rev1, const RevolutionFace * rev2, NgArray > & pts); void ComputeCrossPoints (const Plane * plane1, const Plane * plane2, const Plane * plane3, NgArray > & pts); void ComputeCrossPoints (const Plane * plane1, const Plane * plane2, const QuadraticSurface * quadratic, NgArray > & pts); void ComputeCrossPoints (const Sphere * sphere1, const Sphere * sphere2, const Sphere * sphere3, NgArray > & pts); }; } #endif ================================================ FILE: libsrc/csg/spline3d.cpp ================================================ #include #include #include #include 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; } } ================================================ FILE: libsrc/csg/spline3d.hpp ================================================ 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 { /// NgArray 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; }; } ================================================ FILE: libsrc/csg/splinesurface.cpp ================================================ #include #include namespace netgen { void SplineSurface :: AppendPoint(const Point<3> & p, const double reffac, const bool hpref) { auto pp = p; Project(pp); geompoints.Append(GeomPoint<3>(pp,reffac)); geompoints.Last().hpref = hpref; } void SplineSurface :: AppendSegment(shared_ptr> sp, string & bcname, double amaxh) { splines.Append(sp); bcnames.Append(bcname); maxh.Append(amaxh); } string SplineSurface :: GetBCNameOf (Point<3> p1, Point<3> p2) const { for(int i=0; i(splines[i]->GetPoint(0)); Project(pp1); auto pp2 = Point<3>(splines[i]->GetPoint(1)); Project(pp2); double eps = (p1-p2).Length() * 1e-4; if (((pp1-p1).Length()>> SplineSurface :: CreateCuttingSurfaces() { if(all_cuts) return all_cuts; auto cuttings = make_shared>>(); for (auto cut : *cuts) cuttings->Append(cut); for(int i = 0; i*>(spline.get()); if(lineseg) { auto p1 = Point<3>(spline->GetPoint(0)); Project(p1); auto p2 = Point<3>(spline->GetPoint(1)); Project(p2); auto vec = Vec<3>(p2)-Vec<3>(p1); auto plane = make_shared(p1,-Cross(vec,baseprimitive->GetNormalVector(p1))); if(maxh[i]>0) { plane->SetMaxH(maxh[i]); } cuttings->Append(plane); } else { auto spline3 = dynamic_cast*>(spline.get()); if(spline3) { auto p1 = Point<3>(spline3->StartPI()); Project(p1); auto p2 = Point<3>(spline3->TangentPoint()); Project(p2); auto p3 = Point<3>(spline3->EndPI()); Project(p3); Vec<3> v1 = p2-p1; Vec<3> v2 = p2-p3; Point<3> mid = p1 - v2; cout << "mid point = " << mid << endl; cout << "v1 = " << v1 << endl; cout << "v2 = " << v2 << endl; auto cyl = make_shared(mid, v1, v2); if(maxh[i] > 0) cyl->SetMaxH(maxh[i]); cuttings->Append(cyl); } else throw NgException("Spline type not implemented for SplineSurface!"); } } all_cuts = cuttings; return cuttings; } void SplineSurface :: Print(ostream & str) const { str << "SplineSurface with base " << *baseprimitive << endl; } static RegisterClassForArchive regss; } ================================================ FILE: libsrc/csg/splinesurface.hpp ================================================ #ifndef FILE_SPLINESURFACE #define FILE_SPLINESURFACE namespace netgen { class SplineSurface : public OneSurfacePrimitive { protected: NgArray> geompoints; NgArray>> splines; NgArray bcnames; NgArray maxh; shared_ptr baseprimitive; shared_ptr>> cuts; shared_ptr>> all_cuts; public: SplineSurface(shared_ptr abaseprimitive, shared_ptr>> acuts) : OneSurfacePrimitive(), baseprimitive(abaseprimitive), cuts(acuts) { ; } // default constructor for archive SplineSurface() {} virtual ~SplineSurface() { ; } const auto & GetSplines() const { return splines; } int GetNSplines() const { return splines.Size(); } const NgArray>& GetPoints() const { return geompoints; } string GetSplineType(const int i) const { return splines[i]->GetType(); } SplineSeg<3> & GetSpline(const int i) { return *splines[i]; } const SplineSeg<3> & GetSpline(const int i) const { return *splines[i]; } int GetNP() const { return geompoints.Size(); } const GeomPoint<3> & GetPoint(int i) const { return geompoints[i]; } string GetBCName(int i) const { return bcnames[i]; } string GetBCNameOf(Point<3> p1, Point<3> p2) const; DLL_HEADER void AppendPoint(const Point<3> & p, const double reffac = 1., const bool hpref=false); void AppendSegment(shared_ptr> spline, string & bcname, double amaxh = -1); const shared_ptr>> CreateCuttingSurfaces(); const shared_ptr>> GetCuts() const { return all_cuts; } const shared_ptr GetBase() const { return baseprimitive; } virtual void Project (Point<3> & p3d) const { baseprimitive->Project(p3d); } virtual double CalcFunctionValue (const Point<3> & point) const { return baseprimitive->CalcFunctionValue (point); } virtual void CalcGradient (const Point<3> & point, Vec<3> & grad) const { baseprimitive->CalcGradient (point,grad); } virtual double HesseNorm () const { return baseprimitive->HesseNorm(); } virtual Point<3> GetSurfacePoint () const { return baseprimitive->GetSurfacePoint(); } virtual void CalcSpecialPoints(NgArray> & pts) const { baseprimitive->CalcSpecialPoints(pts); } virtual INSOLID_TYPE BoxInSolid(const BoxSphere<3> & box) const { return baseprimitive->BoxInSolid(box); } virtual void DoArchive(Archive& ar) { ar & geompoints & splines & bcnames & maxh & baseprimitive & cuts & all_cuts; } /* virtual void Project (Point<3> & p3d) const; virtual double CalcFunctionValue (const Point<3> & point) const; virtual void CalcGradient (const Point<3> & point, Vec<3> & grad) const; virtual double HesseNorm () const; virtual Point<3> GetSurfacePoint () const; virtual void CalcSpecialPoints(NgArray> & pts) const; virtual INSOLID_TYPE BoxInSolid(const BoxSphere<3> & box) const; */ virtual void Print (ostream & str) const; }; } #endif ================================================ FILE: libsrc/csg/surface.cpp ================================================ #include #include #include #include #include #include namespace netgen { Surface :: Surface () { maxh = 1e10; name = new char[7]; strcpy (name, "noname"); bcprop = -1; bcname = "default"; inverse = false; } 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, const MeshingParameters & mparam, 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, NgArray & coeffs) const { classname = "undef"; coeffs.SetSize (0); } void Primitive :: SetPrimitiveData (NgArray & 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 << "Primitive::CreatePrimitive not implemented for " << classname << endl; throw NgException (ost.str()); } Primitive * Primitive :: Copy () const { stringstream ost; ost << "Primitive::Copy not implemented for " << typeid(*this).name() << endl; throw NgException (ost.str()); } void Primitive :: Transform (Transformation<3> & trans) { stringstream ost; ost << "Primitive::Transform not implemented for " << typeid(*this).name() << endl; throw NgException (ost.str()); } void Primitive :: GetTangentialSurfaceIndices (const Point<3> & p, NgArray & 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, NgArray & 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, NgArray & 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 <= -eps) return IS_INSIDE; if (hv2 >= eps) return IS_OUTSIDE; return DOES_INTERSECT; /* 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; } } RegisterClassForArchive regsurf; RegisterClassForArchive regprim; RegisterClassForArchive> regosf; } ================================================ FILE: libsrc/csg/surface.hpp ================================================ #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: virtual void DoArchive(Archive& archive) { archive & inverse & maxh & name & bcprop & bcname & p1 & p2 & ex & ey & ez; } 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, const MeshingParameters & mparam, 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 { protected: NgArray surfaceids; NgArray surfaceactive; public: Primitive (); virtual ~Primitive(); virtual void DoArchive(Archive& archive) { archive & surfaceids & surfaceactive; } /* 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, NgArray & 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; // for a point p in the surface, into which (closed) surfaces does v point into ? virtual void GetTangentialVecSurfaceIndices (const Point<3> & p, const Vec<3> & v, NgArray & surfind, double eps) const; // a point p in the surface, and v a tangential vector // for arbitrary small, but positive t consider q := Project(p+t*v) // into which (closed) surfaces does v2 point into, when starting from q ? virtual void GetTangentialVecSurfaceIndices2 (const Point<3> & p, const Vec<3> & v1, const Vec<3> & v2, NgArray & surfind, double eps) const; virtual void CalcSpecialPoints (NgArray > & /* pts */) const { ; } virtual void AnalyzeSpecialPoint (const Point<3> & /* pt */, NgArray > & /* 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; 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, NgArray & coeffs) const; virtual void SetPrimitiveData (NgArray & 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 void DoArchive(Archive& archive) { Surface::DoArchive(archive); Primitive::DoArchive(archive); } 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 described 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 ================================================ FILE: libsrc/csg/triapprox.cpp ================================================ #include #include #include #include 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 () { NgBitArray used(GetNP()); NgArray 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); } } ================================================ FILE: libsrc/csg/triapprox.hpp ================================================ #ifndef FILE_TRIAPPROX #define FILE_TRIAPPROX /**************************************************************************/ /* File: triapprox.hh */ /* Author: Joachim Schoeberl */ /* Date: 2. Mar. 98 */ /**************************************************************************/ namespace netgen { /** Triangulated approximation 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 { NgArray > points; NgArray > normals; NgArray 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 ================================================ FILE: libsrc/csg/vscsg.cpp ================================================ #include #include "incopengl.hpp" #include #include #include #include #include #include "vscsg.hpp" namespace netgen { /* *********************** Draw Geometry **************** */ DLL_HEADER extern shared_ptr mesh; DLL_HEADER extern NgArray global_specpoints; NgArray & specpoints = global_specpoints; DLL_HEADER extern NgArray > boxes; VisualSceneGeometry :: VisualSceneGeometry () : VisualScene() { selsurf = 0; } VisualSceneGeometry :: ~VisualSceneGeometry () { ; } void VisualSceneGeometry :: SelectSurface (int aselsurf) { selsurf = aselsurf; DrawScene(); } void VisualSceneGeometry :: DrawScene () { 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(); glMultMatrixd (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 (int i = 0; i < geometry->GetNTopLevelObjects(); i++) { const TopLevelObject * tlo = geometry -> GetTopLevelObject (i); if (tlo->GetVisible() && !tlo->GetTransparent()) { float mat_col[] = { float(tlo->GetRed()), float(tlo->GetGreen()), float(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 (int i = 0; i < geometry->GetNTopLevelObjects(); i++) { const TopLevelObject * tlo = geometry -> GetTopLevelObject (i); if (tlo->GetVisible() && tlo->GetTransparent()) { float mat_col[] = { float(tlo->GetRed()), float(tlo->GetGreen()), float(tlo->GetBlue()), float(transp) }; glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_col); glCallList (trilists[i]); } } glDisable (GL_POLYGON_OFFSET_FILL); glPopMatrix(); glDisable(GL_CLIP_PLANE0); DrawCoordinateCross (); DrawNetgenLogo (); glFinish(); } void VisualSceneGeometry :: BuildScene (int zoomall) { VisualScene::BuildScene(zoomall); // setting light ... 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) { glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(3, GL_DOUBLE, 0, &ta->GetPoint(0)(0)); glEnableClientState(GL_NORMAL_ARRAY); glNormalPointer(GL_DOUBLE, 0, &ta->GetNormal(0)(0)); for (int j = 0; j < ta->GetNT(); j++) glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, & (ta->GetTriangle(j)[0])); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); /* for (int j = 0; j < ta.GetNT(); j++) { glBegin (GL_TRIANGLES); for (int k = 0; k < 3; k++) { int pi = ta.GetTriangle(j)[k]; glNormal3dv (ta.GetNormal(pi)); glVertex3dv (ta.GetPoint(pi)); cout << "v = " << ta.GetPoint(pi) << endl; } 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(); glMultMatrixd (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] = { GLfloat(1 - backcolor), GLfloat(1 - backcolor), GLfloat(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()); snprintf (buf, sizeof(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]); } */ for (Point<3> p : mesh->Points()) { glRasterPos3d (p(0), p(1), p(2)); glBitmap (7, 7, 3, 3, 0, 0, &knoedel[0]); } } if (vispar.drawedpointnrs) { glEnable (GL_COLOR_MATERIAL); GLfloat textcol[3] = { GLfloat(1 - backcolor), GLfloat(1 - backcolor), GLfloat(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++) for (auto i : mesh->Points().Range()) { const Point3d & p = mesh->Point(i); glRasterPos3d (p.X(), p.Y(), p.Z()); snprintf (buf, sizeof(buf), "%d", int(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-IndexBASE() >= 0 && vispar.centerpoint-IndexBASE() < 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(); } } #ifdef NG_PYTHON #include <../general/ngpython.hpp> NGGUI_API void ExportCSGVis(py::module &m) { using namespace netgen; py::class_> (m, "VisualSceneGeometry") .def("Draw", &VisualSceneGeometry::DrawScene) ; m.def("SetBackGroundColor", &VisualSceneGeometry::SetBackGroundColor); m.def("VS", [](CSGeometry & geom) { geom.FindIdenticSurfaces(1e-6); geom.CalcTriangleApproximation(0.01, 20); auto vs = make_shared(); vs->SetGeometry(&geom); return vs; }); m.def("MouseMove", [](VisualSceneGeometry &vsgeom, int oldx, int oldy, int newx, int newy, char mode) { vsgeom.MouseMove(oldx, oldy, newx, newy, mode); }); } PYBIND11_MODULE(libcsgvis, m) { ExportCSGVis(m); } #endif ================================================ FILE: libsrc/csg/vscsg.hpp ================================================ #ifndef FILE_VSCSG #define FILE_VSCSG /**************************************************************************/ /* File: vscsg.hpp */ /* Author: Joachim Schoeberl */ /* Date: 05. Jan. 2011 */ /**************************************************************************/ namespace netgen { class NGGUI_API VisualSceneGeometry : public VisualScene { class CSGeometry * geometry; NgArray 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 ================================================ FILE: libsrc/csg/zrefine.cpp ================================================ #include #include "meshing.hpp" #include namespace netgen { // find singular edges void SelectSingularEdges (const Mesh & mesh, const CSGeometry & geom, INDEX_2_HASHTABLE & 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 & singedges) { // volume elements // for (int i = 1; i <= mesh.GetNE(); i++) for (ElementIndex ei = 0; ei < mesh.GetNE(); ei++) { Element & el = mesh.VolumeElement(ei); 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 (SurfaceElementIndex sei = 0; sei < mesh.GetNSE(); sei++) { Element2d & el = mesh.SurfaceElement(sei); 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 (ElementIndex ei = 0; ei < mesh.GetNE(); ei++) { Element & el = mesh.VolumeElement(ei); if (el.GetType() == TET) { 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 (mesh.GetIdentifications().UsedSymmetric (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 (int j = 0; j <= 1; j++) { PointIndex pi1 = el.PNum( (j+0) % 4 + 1); PointIndex pi2 = el.PNum( (j+1) % 4 + 1); PointIndex pi3 = el.PNum( (j+2) % 4 + 1); PointIndex pi4 = el.PNum( (j+3) % 4 + 1); PointIndex pi5 = el.PNum(5); INDEX_2 edge1(pi1, pi4); INDEX_2 edge2(pi2, pi3); edge1.Sort(); edge2.Sort(); if (mesh.GetIdentifications().UsedSymmetric (pi1, pi4) && mesh.GetIdentifications().UsedSymmetric (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 (SurfaceElementIndex sei = 0; sei < mesh.GetNSE(); sei++) { Element2d & el = mesh.SurfaceElement(sei); 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 (mesh.GetIdentifications().UsedSymmetric (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 & cornernodes) { int i, j; int nseg = mesh.GetNSeg(); NgArray 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 NgArray ref_uniform; NgArray ref_singular; NgArray ref_slices; NgBitArray first_id(geom->identifications.Size()); first_id.Set(); // if (mesh.GetIdentifications().HasIdentifiedPoints()) { auto & identpts = mesh.GetIdentifications().GetIdentifiedPoints (); /* for (int i = 1; i <= identpts.GetNBags(); i++) for (int j = 1; j <= identpts.GetBagSize(i); j++) { INDEX_3 pair; int dummy; identpts.GetData(i, j, pair, dummy); */ for (auto [hash, val] : identpts)\ { auto [hash_pts, idnr] = hash; auto [pi1, pi2] = hash_pts; // auto idnr = pair[2]; const CloseSurfaceIdentification * csid = dynamic_cast (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())); */ ref_uniform.Append (INDEX_3 (pi1, pi2, csid->RefLevels())); ref_singular.Append (INDEX_3 (pi1, pi2, csid->RefLevels1())); ref_singular.Append (INDEX_3 (pi2, pi1, csid->RefLevels2())); } } else { //const NgArray & slices = csid->GetSlices(); INDEX_4 i4; // i4[0] = pair.I1(); // i4[1] = pair.I2(); i4[0] = pi1; i4[1] = pi2; i4[2] = idnr; i4[3] = csid->GetSlices().Size(); ref_slices.Append (i4); } } } } NgArray epgi; while (1) { cnt++; PrintMessage (3, "Z-Refinement, level = ", cnt); INDEX_2_HASHTABLE refedges(mesh.GetNSE()+1); found = 0; // mark prisms due to close surface flags: int oldsize = ref_uniform.Size(); for (int 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 (int 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 (int 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 (geom->identifications.Get(idnr)); INDEX_2 edge(pi1, pi2); edge.Sort(); if (!refedges.Used(edge)) { const auto& slices = csid->GetSlices(); //(*testout) << "idnr " << idnr << " i " << i << endl; //(*testout) << "slices " << slices << endl; double slicefac = slices[slicenr-1]; double slicefaclast = (slicenr == slices.Size()) ? 1 : slices[slicenr]; 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 (ElementIndex ei = 0; ei < mesh.GetNE(); ei++) { Element & el = mesh.VolumeElement (ei); if (el.GetType() != PRISM) continue; for (int 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 (ElementIndex ei = 0; ei < mesh.GetNE(); ei++) { Element & el = mesh.VolumeElement (ei); if (el.GetType() != PRISM) continue; bool hasref = 0, hasnonref = 0; for (int 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 (int 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 (int 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 (ElementIndex ei = 0; ei < oldne; ei++) { Element & el = mesh.VolumeElement (ei); if (el.GetNP() != 6) continue; int npi[3]; for (int 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 (int 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 (ei) = nel1; mesh.AddVolumeElement (nel2); } } PrintMessage (5, "Elements done, NE = ", mesh.GetNE()); // do surface elements int oldnse = mesh.GetNSE(); // cout << "oldnse = " << oldnse << endl; for (SurfaceElementIndex sei = 0; sei < oldnse; sei++) { Element2d & el = mesh.SurfaceElement (sei); if (el.GetType() != QUAD) continue; int index = el.GetIndex(); int npi[2]; for (int 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 (int 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 (sei) = 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])); } } mesh.RebuildSurfaceElementLists(); PrintMessage (5, "Surface elements done, NSE = ", mesh.GetNSE()); } } void CombineSingularPrisms(Mesh& mesh) { for(ElementIndex ei = 0; ei < mesh.GetNE(); ei++) { Element& el = mesh.VolumeElement(ei); if(el.GetType() != PRISM) continue; if(el.PNum(3) == el.PNum(6)) { if(el.PNum(2) == el.PNum(5)) { el.SetType(TET); } else { el.SetType(PYRAMID); int pnr5 = el.PNum(3); el.PNum(3) = el.PNum(5); el.PNum(5) = pnr5; } } } } void ZRefinement (Mesh & mesh, const NetgenGeometry * hgeom, ZRefinementOptions & opt) { const CSGeometry * geom = dynamic_cast (hgeom); if (!geom) return; INDEX_2_HASHTABLE singedges(mesh.GetNSeg()); SelectSingularEdges (mesh, *geom, singedges, opt); //MakePrismsSingEdge (mesh, singedges); MakePrismsClosePoints (mesh); RefinePrisms (mesh, geom, opt); CombineSingularPrisms(mesh); } ZRefinementOptions :: ZRefinementOptions() { minref = 0; } } ================================================ FILE: libsrc/general/CMakeLists.txt ================================================ target_sources(nglib PRIVATE gzstream.cpp hashtabl.cpp mystring.cpp ngbitarray.cpp optmem.cpp parthreads.cpp seti.cpp sort.cpp spbita2d.cpp table.cpp ) # dynamicmem.cpp install(FILES ngarray.hpp autodiff.hpp autoptr.hpp ngbitarray.hpp hashtabl.hpp myadt.hpp mystring.hpp netgenout.hpp ngpython.hpp optmem.hpp parthreads.hpp seti.hpp sort.hpp spbita2d.hpp stack.hpp table.hpp template.hpp gzstream.h DESTINATION ${NG_INSTALL_DIR_INCLUDE}/general COMPONENT netgen_devel ) # dynamicmem.hpp ================================================ FILE: libsrc/general/autodiff.hpp ================================================ #ifndef FILE_AUTODIFF #define FILE_AUTODIFF /**************************************************************************/ /* File: autodiff.hpp */ /* Author: Joachim Schoeberl */ /* Date: 24. Oct. 02 */ /**************************************************************************/ // Automatic differentiation datatype namespace netgen { /** Datatype for automatic differentiation. Contains function value and D derivatives. Algebraic operations are overloaded by using product-rule etc. etc. **/ template class AutoDiff { SCAL val; SCAL dval[D]; public: typedef AutoDiff 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 & operator+= (const AutoDiff & y) throw() { val += y.val; for (int i = 0; i < D; i++) dval[i] += y.dval[i]; return *this; } /// AutoDiff & operator-= (const AutoDiff & y) throw() { val -= y.val; for (int i = 0; i < D; i++) dval[i] -= y.dval[i]; return *this; } /// AutoDiff & operator*= (const AutoDiff & 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 & operator*= (const SCAL & y) throw() { val *= y; for (int i = 0; i < D; i++) dval[i] *= y; return *this; } /// AutoDiff & 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 inline ostream & operator<< (ostream & ost, const AutoDiff & x) { ost << x.Value() << ", D = "; for (int i = 0; i < D; i++) ost << x.DValue(i) << " "; return ost; } /// AutoDiff plus AutoDiff template inline AutoDiff operator+ (const AutoDiff & x, const AutoDiff & y) throw() { AutoDiff res; res.Value () = x.Value()+y.Value(); // AutoDiff 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 inline AutoDiff operator- (const AutoDiff & x, const AutoDiff & y) throw() { AutoDiff res; res.Value() = x.Value()-y.Value(); // AutoDiff 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 inline AutoDiff operator+ (double x, const AutoDiff & y) throw() { AutoDiff 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 inline AutoDiff operator+ (const AutoDiff & y, double x) throw() { AutoDiff res; res.Value() = x+y.Value(); for (int i = 0; i < D; i++) res.DValue(i) = y.DValue(i); return res; } /// minus AutoDiff template inline AutoDiff operator- (const AutoDiff & x) throw() { AutoDiff res; res.Value() = -x.Value(); for (int i = 0; i < D; i++) res.DValue(i) = -x.DValue(i); return res; } /// AutoDiff minus double template inline AutoDiff operator- (const AutoDiff & x, double y) throw() { AutoDiff res; res.Value() = x.Value()-y; for (int i = 0; i < D; i++) res.DValue(i) = x.DValue(i); return res; } /// template inline AutoDiff operator- (double x, const AutoDiff & y) throw() { AutoDiff 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 inline AutoDiff operator* (double x, const AutoDiff & y) throw() { AutoDiff 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 inline AutoDiff operator* (const AutoDiff & y, double x) throw() { AutoDiff 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 inline AutoDiff operator* (const AutoDiff & x, const AutoDiff & y) throw() { AutoDiff 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; } /// Inverse of AutoDiff template inline AutoDiff Inv (const AutoDiff & x) { AutoDiff 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 inline AutoDiff operator/ (const AutoDiff & x, const AutoDiff & y) { return x * Inv (y); } /// AutoDiff div double template inline AutoDiff operator/ (const AutoDiff & x, double y) { return (1/y) * x; } /// double div AutoDiff template inline AutoDiff operator/ (double x, const AutoDiff & y) { return x * Inv(y); } } // namespace netgen namespace ngcore { /// AutoDiff times AutoDiff template inline netgen::AutoDiff sqr (const netgen::AutoDiff & x) throw() { netgen::AutoDiff 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; } } // namespace ngcore namespace std { template inline netgen::AutoDiff fabs (const netgen::AutoDiff & x) { double abs = fabs (x.Value()); netgen::AutoDiff 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; } } // namespace std #endif ================================================ FILE: libsrc/general/autoptr.hpp ================================================ braucht man nicht mehr #ifndef FILE_AUTOPTR #define FILE_AUTOPTR /**************************************************************************/ /* File: autoptr.hpp */ /* Author: STL, Joachim Schoeberl */ /* Date: 29. Dec. 02 */ /**************************************************************************/ namespace netgen { /* template 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 ================================================ FILE: libsrc/general/dynamicmem.cpp ================================================ #include 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; name = NULL; 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(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(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 } ================================================ FILE: libsrc/general/dynamicmem.hpp ================================================ not needed anymore ? #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; } 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 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 (BaseDynamicMem::Ptr()); } */ const T * Ptr() { return reinterpret_cast (BaseDynamicMem::Ptr()); } /* operator const T* () const { return reinterpret_cast (BaseDynamicMem::Ptr()); } */ operator T* () const { return reinterpret_cast (BaseDynamicMem::Ptr()); } void Swap (DynamicMem & m2) { BaseDynamicMem::Swap (m2); } protected: DynamicMem (const DynamicMem & m); DynamicMem & operator= (const DynamicMem & m); }; } #endif ================================================ FILE: libsrc/general/gzstream.cpp ================================================ // ============================================================================ // gzstream, C++ iostream classes wrapping the zlib compression library. // Copyright (C) 2001 Deepak Bandyopadhyay, Lutz Kettner // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // ============================================================================ // // File : gzstream.C // Revision : $Revision: 1.7 $ // Revision_date : $Date: 2003/01/08 14:41:27 $ // Author(s) : Deepak Bandyopadhyay, Lutz Kettner // // Standard streambuf implementation following Nicolai Josuttis, "The // Standard C++ Library". // ============================================================================ #include #include #include "gzstream.h" //#include //#include // for memcpy #ifdef GZSTREAM_NAMESPACE namespace GZSTREAM_NAMESPACE { #endif // ---------------------------------------------------------------------------- // Internal classes to implement gzstream. See header file for user classes. // ---------------------------------------------------------------------------- // -------------------------------------- // class gzstreambuf: // -------------------------------------- gzstreambuf* gzstreambuf::open( const std::filesystem::path & name, int open_mode) { if ( is_open()) return (gzstreambuf*)0; mode = open_mode; // no append nor read/write mode if ((mode & std::ios::ate) || (mode & std::ios::app) || ((mode & std::ios::in) && (mode & std::ios::out))) return (gzstreambuf*)0; char fmode[10]; char* fmodeptr = fmode; if ( mode & std::ios::in) *fmodeptr++ = 'r'; else if ( mode & std::ios::out) *fmodeptr++ = 'w'; *fmodeptr++ = 'b'; *fmodeptr = '\0'; #ifdef WIN32 file = gzopen_w( name.c_str(), fmode); #else // WIN32 file = gzopen( name.c_str(), fmode); #endif // WIN32 if (file == 0) return (gzstreambuf*)0; opened = 1; return this; } gzstreambuf * gzstreambuf::close() { if ( is_open()) { sync(); opened = 0; if ( gzclose( file) == Z_OK) return this; } return (gzstreambuf*)0; } int gzstreambuf::underflow() { // used for input buffer only if ( gptr() && ( gptr() < egptr())) return * reinterpret_cast( gptr()); if ( ! (mode & std::ios::in) || ! opened) return EOF; // Josuttis' implementation of inbuf int n_putback = gptr() - eback(); if ( n_putback > 4) n_putback = 4; memcpy( buffer + (4 - n_putback), gptr() - n_putback, n_putback); int num = gzread( file, buffer+4, bufferSize-4); if (num <= 0) // ERROR or EOF return EOF; // reset buffer pointers setg( buffer + (4 - n_putback), // beginning of putback area buffer + 4, // read position buffer + 4 + num); // end of buffer // return next character return * reinterpret_cast( gptr()); } int gzstreambuf::flush_buffer() { // Separate the writing of the buffer from overflow() and // sync() operation. int w = pptr() - pbase(); if ( gzwrite( file, pbase(), w) != w) return EOF; pbump( -w); return w; } int gzstreambuf::overflow( int c) { // used for output buffer only if ( ! ( mode & std::ios::out) || ! opened) return EOF; if (c != EOF) { *pptr() = c; pbump(1); } if ( flush_buffer() == EOF) return EOF; return c; } int gzstreambuf::sync() { // Changed to use flush_buffer() instead of overflow( EOF) // which caused improper behavior with std::endl and flush(), // bug reported by Vincent Ricard. if ( pptr() && pptr() > pbase()) { if ( flush_buffer() == EOF) return -1; } return 0; } // -------------------------------------- // class gzstreambase: // -------------------------------------- gzstreambase::gzstreambase( const std::filesystem::path & name, int mode) { init( &buf); open( name.c_str(), mode); } gzstreambase::~gzstreambase() { buf.close(); } void gzstreambase::open( const std::filesystem::path & name, int open_mode) { if ( ! buf.open( name.c_str(), open_mode)) clear( rdstate() | std::ios::badbit); } void gzstreambase::close() { if ( buf.is_open()) if ( ! buf.close()) clear( rdstate() | std::ios::badbit); } #ifdef GZSTREAM_NAMESPACE } // namespace GZSTREAM_NAMESPACE #endif // ============================================================================ // EOF // ================================================ FILE: libsrc/general/gzstream.h ================================================ // ============================================================================ // gzstream, C++ iostream classes wrapping the zlib compression library. // Copyright (C) 2001 Deepak Bandyopadhyay, Lutz Kettner // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // ============================================================================ // // File : gzstream.h // Revision : $Revision: 1.5 $ // Revision_date : $Date: 2002/04/26 23:30:15 $ // Author(s) : Deepak Bandyopadhyay, Lutz Kettner // // Standard streambuf implementation following Nicolai Josuttis, "The // Standard C++ Library". // ============================================================================ #ifndef GZSTREAM_H #define GZSTREAM_H 1 // standard C++ with new header file names and std:: namespace #include #include #include #ifdef GZSTREAM_NAMESPACE namespace GZSTREAM_NAMESPACE { #endif // ---------------------------------------------------------------------------- // Internal classes to implement gzstream. See below for user classes. // ---------------------------------------------------------------------------- class gzstreambuf : public std::streambuf { private: static const int bufferSize = 47+256; // size of data buff // totals 512 bytes under g++ for igzstream at the end. gzFile file; // file handle for compressed file char buffer[bufferSize]; // data buffer char opened; // open/close state of stream int mode; // I/O mode int flush_buffer(); public: gzstreambuf() : opened(0) { setp( buffer, buffer + (bufferSize-1)); setg( buffer + 4, // beginning of putback area buffer + 4, // read position buffer + 4); // end position // ASSERT: both input & output capabilities will not be used together } int is_open() { return opened; } gzstreambuf* open( const std::filesystem::path & name, int open_mode); gzstreambuf* close(); ~gzstreambuf() { close(); } virtual int overflow( int c = EOF); virtual int underflow(); virtual int sync(); }; class DLL_HEADER gzstreambase : virtual public std::ios { protected: gzstreambuf buf; public: gzstreambase() { init(&buf); } gzstreambase( const std::filesystem::path & name, int open_mode); ~gzstreambase(); void open( const std::filesystem::path & name, int open_mode); void close(); gzstreambuf* rdbuf() { return &buf; } }; // ---------------------------------------------------------------------------- // User classes. Use igzstream and ogzstream analogously to ifstream and // ofstream respectively. They read and write files based on the gz* // function interface of the zlib. Files are compatible with gzip compression. // ---------------------------------------------------------------------------- class DLL_HEADER igzstream : public gzstreambase, public std::istream { public: igzstream() : std::istream( &buf) {} igzstream( const std::filesystem::path & name, int open_mode = std::ios::in) : gzstreambase( name, open_mode), std::istream( &buf) {} gzstreambuf* rdbuf() { return gzstreambase::rdbuf(); } void open( const std::filesystem::path & name, int open_mode = std::ios::in) { gzstreambase::open( name, open_mode); } }; class DLL_HEADER ogzstream : public gzstreambase, public std::ostream { public: ogzstream() : std::ostream( &buf) {} ogzstream( const std::filesystem::path & name, int mode = std::ios::out) : gzstreambase( name, mode), std::ostream( &buf) {} gzstreambuf* rdbuf() { return gzstreambase::rdbuf(); } void open( const std::filesystem::path & name, int open_mode = std::ios::out) { gzstreambase::open( name, open_mode); } }; #ifdef GZSTREAM_NAMESPACE } // namespace GZSTREAM_NAMESPACE #endif #endif // GZSTREAM_H // ============================================================================ // EOF // ================================================ FILE: libsrc/general/hashtabl.cpp ================================================ /**************************************************************************/ /* File: hashtabl.cpp */ /* Author: Joachim Schoeberl */ /* Date: 01. Jun. 95 */ /**************************************************************************/ /* Abstract data type HASHTABLE */ #include #include #include 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. access 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 (size_t size) : hash(RoundUp2(size)) { size = hash.Size(); mask = size-1; // hash.SetName ("i2-hashtable, hash"); invalid = -1; for (size_t i = 0; i < size; i++) hash[i].I1() = invalid; } void BASE_INDEX_2_CLOSED_HASHTABLE :: BaseSetSize (int size) { size = RoundUp2 (size); mask = size-1; hash.SetSize(size); for (size_t i = 0; i < size; i++) hash[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; } } bool 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; */ 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"); } } 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; } BASE_INDEX_3_CLOSED_HASHTABLE :: BASE_INDEX_3_CLOSED_HASHTABLE (size_t size) : hash(RoundUp2(size)) { // cout << "orig size = " << size // << ", roundup size = " << hash.Size(); size = hash.Size(); mask = size-1; // cout << "mask = " << mask << endl; invalid = -1; for (size_t i = 0; i < size; i++) hash[i].I1() = invalid; } void BASE_INDEX_3_CLOSED_HASHTABLE :: BaseSetSize (int size) { size = RoundUp2 (size); mask = size-1; 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"); } } } ================================================ FILE: libsrc/general/hashtabl.hpp ================================================ #ifndef FILE_HASHTABL #define FILE_HASHTABL /**************************************************************************/ /* File: hashtabl.hh */ /* Author: Joachim Schoeberl */ /* Date: 01. Jun. 95 */ /**************************************************************************/ #include "table.hpp" namespace netgen { /** Abstract data type HASHTABLE. Hash is done by one INDEX */ class BASE_INDEX_HASHTABLE { protected: /// keys are stored in this table TABLE 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 INDEX_HASHTABLE : private BASE_INDEX_HASHTABLE { /// TABLE 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 hash; public: /// BASE_INDEX_2_HASHTABLE () { ; } 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 { for (int i = 1; i <= hash.EntrySize (bnr); i++) if (hash.Get(bnr, i) == ind) return i; return 0; } }; /// template class INDEX_2_HASHTABLE : public BASE_INDEX_2_HASHTABLE { /// TABLE cont; public: /// INDEX_2_HASHTABLE () { ; } 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); } T & Get (const INDEX_2 & ahash) { 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) > 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; } Iterator operator++ (int) { Iterator it(ht, bagnr, pos); ++(*this); return it; } Iterator& operator++() { pos++; while (bagnr < ht.GetNBags() && pos == ht.GetBagSize(bagnr+1)) { pos = 0; bagnr++; } return *this; } std::pair operator*() { return std::make_pair(ht.hash[bagnr][pos], ht.cont[bagnr][pos]); } bool operator != (int i) const { return bagnr != i; } }; Iterator Begin () const { Iterator it(*this, 0, -1); it++; return it; } int End() const { return GetNBags(); } 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()]; } void DoArchive (Archive & ar) { ar & hash & cont; } }; template inline ostream & operator<< (ostream & ost, const INDEX_2_HASHTABLE & ht) { for (typename INDEX_2_HASHTABLE::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 hash; public: /// BASE_INDEX_3_HASHTABLE () { ; } 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 INDEX_3_HASHTABLE : private BASE_INDEX_3_HASHTABLE { /// TABLE cont; public: /// inline INDEX_3_HASHTABLE () { ; } 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; } Iterator operator++ (int) { Iterator it(ht, bagnr, pos); ++(*this); return it; } Iterator& operator++() { pos++; while (bagnr < ht.GetNBags() && pos == ht.GetBagSize(bagnr+1)) { pos = 0; bagnr++; } return *this; } std::pair operator*() { return std::make_pair(ht.hash[bagnr][pos], ht.cont[bagnr][pos]); } bool operator != (int i) const { return bagnr != i; } }; Iterator Begin () const { Iterator it(*this, 0, -1); it++; return it; } int End() const { return GetNBags(); } 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()]; } void DoArchive (Archive & ar) { ar & hash & cont; } }; template inline ostream & operator<< (ostream & ost, const INDEX_3_HASHTABLE & ht) { for (typename INDEX_3_HASHTABLE::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 hash; NgArray 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 position 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 INDEX_CLOSED_HASHTABLE : public BASE_INDEX_CLOSED_HASHTABLE { /// // MoveableArray cont; NgArray 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); } }; inline size_t RoundUp2 (size_t i) { size_t res = 1; while (res < i) res *= 2; // hope it will never be too large return res; } /// Closed Hashing HT class BASE_INDEX_2_CLOSED_HASHTABLE { protected: /// // MoveableArray hash; NgArray hash; /// int invalid; size_t mask; public: /// DLL_HEADER BASE_INDEX_2_CLOSED_HASHTABLE (size_t size); int Size() const { return hash.Size(); } bool UsedPos0 (int pos) const { return ! (hash[pos].I1() == invalid); } int UsedElements () const; /// int HashValue (const INDEX_2 & ind) const { // return (ind.I1() + 71 * ind.I2()) % hash.Size() + 1; return (ind.I1() + 71 * ind.I2()) & mask; } int Position0 (const INDEX_2 & ind) const { int i = HashValue(ind); while (1) { if (hash[i] == ind) return i; if (hash[i].I1() == invalid) return -1; i = (i+1) & mask; /* i++; if (i > hash.Size()) i = 1; */ } } // returns 1, if new position is created bool PositionCreate0 (const INDEX_2 & 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: /// DLL_HEADER int Position2 (const INDEX_2 & ind) const; DLL_HEADER bool PositionCreate2 (const INDEX_2 & ind, int & apos); DLL_HEADER void BaseSetSize (int asize); }; template class INDEX_2_CLOSED_HASHTABLE : public BASE_INDEX_2_CLOSED_HASHTABLE { NgArray cont; public: INDEX_2_CLOSED_HASHTABLE (size_t size) : BASE_INDEX_2_CLOSED_HASHTABLE(size), cont(RoundUp2(size)) { ; } void Set (const INDEX_2 & ahash, const T & acont) { int pos; PositionCreate0 (ahash, pos); hash[pos] = ahash; cont[pos] = acont; } const T & Get (const INDEX_2 & ahash) const { int pos = Position0 (ahash); return cont[pos]; } inline bool Used (const INDEX_2 & ahash) const { int pos = Position0 (ahash); return (pos != -1); } inline optional GetIfUsed (const INDEX_2 & ahash) const { int pos = Position0 (ahash); if (pos != -1) return cont[pos]; else return nullopt; } inline void SetData0 (int pos, const INDEX_2 & ahash, const T & acont) { hash[pos] = ahash; cont[pos] = acont; } /// inline void GetData0 (int pos, INDEX_2 & ahash, T & acont) const { ahash = hash[pos]; acont = cont[pos]; } inline void SetData0 (int pos, const T & acont) { cont[pos] = acont; } inline void GetData0 (int pos, T & acont) const { acont = cont[pos]; } /// const T & GetData0 (int pos) { return cont[pos]; } /// inline void SetSize (size_t size) { BaseSetSize(size); cont.SetSize(RoundUp2(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 inline ostream & operator<< (ostream & ost, const INDEX_2_CLOSED_HASHTABLE & ht) { for (int i = 0; i < ht.Size(); i++) if (ht.UsedPos(i)) { // INDEX_2 hash; // T data; // ht.GetData0 (i, hash, data); auto [hash,data] = ht.GetBoth(i); ost << "hash = " << hash << ", data = " << data << endl; } return ost; } class BASE_INDEX_3_CLOSED_HASHTABLE { protected: NgArray hash; int invalid; size_t mask; protected: BASE_INDEX_3_CLOSED_HASHTABLE (size_t size); /* : hash(RoundUp2(size)) { // cout << "orig size = " << size // << ", roundup size = " << hash.Size(); size = hash.Size(); mask = size-1; // cout << "mask = " << mask << endl; invalid = -1; for (size_t 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(); return (ind.I1() + 15 * ind.I2() + 41 * ind.I3()) & mask; } 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(); i = (i+1) & mask; } } 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(); i = (i+1) & mask; c++; } } // returns true, if new position 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); } void DeleteData() { size_t size = hash.Size(); for (size_t i = 0; i < size; i++) hash[i].I1() = invalid; } protected: bool PositionCreate2 (const INDEX_3 & ind, int & apos); void BaseSetSize (int asize); }; template class INDEX_3_CLOSED_HASHTABLE : public BASE_INDEX_3_CLOSED_HASHTABLE { // MoveableArray cont; NgArray cont; public: INDEX_3_CLOSED_HASHTABLE (int size) : BASE_INDEX_3_CLOSED_HASHTABLE(size), cont(RoundUp2(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(hash.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 inline ostream & operator<< (ostream & ost, const INDEX_3_CLOSED_HASHTABLE & ht) { for (int i = 0; i < ht.Size(); i++) if (ht.UsedPos(i)) { /* INDEX_3 hash; T data; ht.GetData (i, hash, data); */ auto [hash, data] = ht.GetBoth(); ost << "hash = " << hash << ", data = " << data << endl; } return ost; } template inline INDEX_3_HASHTABLE :: INDEX_3_HASHTABLE (int size) : BASE_INDEX_3_HASHTABLE (size), cont(size) { ; } template inline int INDEX_3_HASHTABLE :: 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 inline void INDEX_3_HASHTABLE :: 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 inline const T & INDEX_3_HASHTABLE :: Get (const INDEX_3 & ahash) const { int bnr = HashValue (ahash); int pos = Position (bnr, ahash); return cont.Get (bnr, pos); } template inline bool INDEX_3_HASHTABLE :: Used (const INDEX_3 & ahash) const { return (Position (HashValue (ahash), ahash)) ? 1 : 0; } template inline int INDEX_3_HASHTABLE :: GetNBags () const { return cont.Size(); } template inline int INDEX_3_HASHTABLE :: GetBagSize (int bnr) const { return cont.EntrySize (bnr); } template inline void INDEX_3_HASHTABLE :: GetData (int bnr, int colnr, INDEX_3 & ahash, T & acont) const { ahash = hash.Get(bnr, colnr); acont = cont.Get(bnr, colnr); } template inline void INDEX_3_HASHTABLE :: SetData (int bnr, int colnr, const INDEX_3 & ahash, const T & acont) { hash.Set(bnr, colnr, ahash); cont.Set(bnr, colnr, acont); } template inline void INDEX_3_HASHTABLE :: SetSize (int size) { hash.SetSize (size); cont.SetSize (size); } template inline void INDEX_3_HASHTABLE :: DeleteData () { int n = hash.Size(); hash.SetSize (n); cont.SetSize (n); } template inline void INDEX_3_HASHTABLE :: PrepareSet (const INDEX_3 & ahash) { int bnr = HashValue (ahash); hash.IncSizePrepare (bnr-1); cont.IncSizePrepare (bnr-1); } template inline void INDEX_3_HASHTABLE :: AllocateElements () { hash.AllocateElementsOneBlock(); cont.AllocateElementsOneBlock(); } template inline void INDEX_3_HASHTABLE :: PrintMemInfo (ostream & ost) const { ost << "Hash: " << endl; hash.PrintMemInfo (ost); ost << "Cont: " << endl; cont.PrintMemInfo (ost); } template inline INDEX_HASHTABLE :: INDEX_HASHTABLE (int size) : BASE_INDEX_HASHTABLE (size), cont(size) { ; } template inline void INDEX_HASHTABLE :: 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 inline const T & INDEX_HASHTABLE :: Get (const INDEX & ahash) const { int bnr = HashValue (ahash); int pos = Position (bnr, ahash); return cont.Get (bnr, pos); } template inline bool INDEX_HASHTABLE :: Used (const INDEX & ahash) const { return (Position (HashValue (ahash), ahash)) ? 1 : 0; } template inline int INDEX_HASHTABLE :: GetNBags () const { return hash.Size(); } template inline int INDEX_HASHTABLE :: GetBagSize (int bnr) const { return hash.EntrySize(bnr); } template inline void INDEX_HASHTABLE :: GetData (int bnr, int colnr, INDEX & ahash, T & acont) const { ahash = hash.Get(bnr, colnr); acont = cont.Get(bnr, colnr); } template inline void INDEX_HASHTABLE :: PrintMemInfo (ostream & ost) const { ost << "Hash: " << endl; hash.PrintMemInfo (ost); ost << "Cont: " << endl; cont.PrintMemInfo (ost); } /* *********** Closed Hashing ************************* */ template inline void INDEX_2_CLOSED_HASHTABLE :: 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 inline INDEX_3_CLOSED_HASHTABLE :: INDEX_3_CLOSED_HASHTABLE (int size) : BASE_INDEX_3_CLOSED_HASHTABLE(size), cont(size) { cont.SetName ("i3-hashtable, contents"); } template inline void INDEX_3_CLOSED_HASHTABLE :: Set (const INDEX_3 & ahash, const T & acont) { int pos; PositionCreate (ahash, pos); hash.Elem(pos) = ahash; cont.Elem(pos) = acont; } template inline const T & INDEX_3_CLOSED_HASHTABLE :: Get (const INDEX_3 & ahash) const { int pos = Position (ahash); return cont[pos]; } template inline bool INDEX_3_CLOSED_HASHTABLE :: Used (const INDEX_3 & ahash) const { int pos = Position (ahash); return (pos != 0); } template inline void INDEX_3_CLOSED_HASHTABLE :: SetData (int pos, const INDEX_3 & ahash, const T & acont) { hash.Elem(pos) = ahash; cont.Elem(pos) = acont; } template inline void INDEX_3_CLOSED_HASHTABLE :: GetData (int pos, INDEX_3 & ahash, T & acont) const { ahash = hash.Get(pos); acont = cont.Get(pos); } template inline void INDEX_3_CLOSED_HASHTABLE :: SetData (int pos, const T & acont) { cont.Elem(pos) = acont; } template inline void INDEX_3_CLOSED_HASHTABLE :: GetData (int pos, T & acont) const { acont = cont.Get(pos); } template inline const T & INDEX_3_CLOSED_HASHTABLE :: GetData (int pos) const { return cont.Get(pos); } template inline void INDEX_3_CLOSED_HASHTABLE :: SetSize (int size) { BaseSetSize(size); cont.SetSize(size); } template inline void INDEX_3_CLOSED_HASHTABLE :: PrintMemInfo (ostream & ost) const { cout << "Hashtable: " << Size() << " entries of size " << sizeof(INDEX_3) << " + " << sizeof(T) << " = " << Size() * (sizeof(INDEX_3) + sizeof(T)) << " bytes" << endl; } */ inline void SetInvalid (INDEX & i) { i = -1; } inline bool IsInvalid (INDEX i) { return i == -1; } inline size_t HashValue (INDEX i, size_t size) { return (113*size_t(i)) % size; } inline void SetInvalid (INDEX_2 & i2) { i2[0] = -1; } inline bool IsInvalid (INDEX_2 i2) { return i2[0] == -1; } inline size_t HashValue (INDEX_2 i2, size_t size) { return (113*size_t(i2[0])+size_t(i2[1])) % size; } inline void SetInvalid (INDEX_3 & i3) { i3[0] = -1; } inline bool IsInvalid (INDEX_3 i3) { return i3[0] == -1; } inline size_t HashValue (INDEX_3 i3, size_t size) { return (i3[0]+15*size_t(i3[1])+41*size_t(i3[2])) % size; } /** A closed hash-table. All information is stored in one fixed array. The array should be allocated with the double size of the expected number of entries. */ template class NgClosedHashTable { protected: /// size_t size; /// size_t used; /// NgArray hash; /// NgArray cont; public: /// NgClosedHashTable (size_t asize = 128) : size(asize), used(0), hash(asize), cont(asize) { for (auto & v : hash) SetInvalid(v); } NgClosedHashTable (NgClosedHashTable && ht2) = default; NgClosedHashTable (NgFlatArray _hash, NgFlatArray _cont) : size(_hash.Size()), used(0), hash(_hash.Size(), _hash.Addr(0)), cont(_cont.Size(), _cont.Addr(0)) { for (auto & v : hash) SetInvalid(v); } NgClosedHashTable & operator= (NgClosedHashTable && ht2) = default; /// size_t Size() const { return size; } /// is position used bool UsedPos (size_t pos) const { return ! (IsInvalid(hash[pos])); } /// number of used elements size_t UsedElements () const { return used; } size_t Position (const T_HASH ind) const { size_t i = HashValue(ind, size); while (1) { if (hash[i] == ind) return i; if (IsInvalid(hash[i])) return size_t(-1); i++; if (i >= size) i = 0; } } void DoubleSize() { NgClosedHashTable tmp(2*Size()); for (auto both : *this) tmp[both.first] = both.second; *this = std::move(tmp); } // returns true if new position is created bool PositionCreate (const T_HASH ind, size_t & apos) { if (UsedElements()*2 > Size()) DoubleSize(); size_t i = HashValue (ind, size); while (1) { if (IsInvalid(hash[i])) { hash[i] = ind; apos = i; used++; return true; } if (hash[i] == ind) { apos = i; return false; } i++; if (i >= size) i = 0; } } /// void Set (const T_HASH & ahash, const T & acont) { size_t pos; PositionCreate (ahash, pos); hash[pos] = ahash; cont[pos] = acont; } /// const T & Get (const T_HASH & ahash) const { size_t pos = Position (ahash); if (pos == size_t(-1)) throw Exception (string("illegal key: ") + ToString(ahash) ); return cont[pos]; } /// bool Used (const T_HASH & ahash) const { return (Position (ahash) != size_t(-1)); } void SetData (size_t pos, const T_HASH & ahash, const T & acont) { hash[pos] = ahash; cont[pos] = acont; } void GetData (size_t pos, T_HASH & ahash, T & acont) const { ahash = hash[pos]; acont = cont[pos]; } void SetData (size_t pos, const T & acont) { cont[pos] = acont; } void GetData (size_t pos, T & acont) const { acont = cont[pos]; } pair GetBoth (size_t pos) const { return pair (hash[pos], cont[pos]); } const T & operator[] (T_HASH key) const { return Get(key); } T & operator[] (T_HASH key) { size_t pos; PositionCreate(key, pos); return cont[pos]; } void SetSize (size_t asize) { size = asize; hash.Alloc(size); cont.Alloc(size); // for (size_t i = 0; i < size; i++) // hash[i] = invalid; // hash = T_HASH(invalid); for (auto & v : hash) SetInvalid(v); } void Delete (T_HASH key) { size_t pos = Position(key); if (pos == size_t(-1)) return; SetInvalid (hash[pos]); used--; while (1) { size_t nextpos = pos+1; if (nextpos == size) nextpos = 0; if (IsInvalid(hash[nextpos])) break; auto key = hash[nextpos]; auto val = cont[nextpos]; SetInvalid (hash[nextpos]); used--; Set (key, val); pos = nextpos; } } void DeleteData() { for (auto & v : hash) SetInvalid(v); used = 0; } class Iterator { const NgClosedHashTable & tab; size_t nr; public: Iterator (const NgClosedHashTable & _tab, size_t _nr) : tab(_tab), nr(_nr) { while (nr < tab.Size() && !tab.UsedPos(nr)) nr++; } Iterator & operator++() { nr++; while (nr < tab.Size() && !tab.UsedPos(nr)) nr++; return *this; } bool operator!= (const Iterator & it2) { return nr != it2.nr; } auto operator* () const { T_HASH hash; T val; tab.GetData(nr, hash,val); return std::make_pair(hash,val); } }; Iterator begin() const { return Iterator(*this, 0); } Iterator end() const { return Iterator(*this, Size()); } }; template ostream & operator<< (ostream & ost, const NgClosedHashTable & tab) { for (size_t i = 0; i < tab.Size(); i++) if (tab.UsedPos(i)) { T_HASH key; T val; tab.GetData (i, key, val); ost << key << ": " << val << ", "; } return ost; } } #endif ================================================ FILE: libsrc/general/myadt.hpp ================================================ #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 namespace netgen { using namespace ngcore; using NgException = Exception; } #include "parthreads.hpp" // #include "moveablemem.hpp" // #include "dynamicmem.hpp" #include "template.hpp" #include "ngarray.hpp" #include "table.hpp" #include "hashtabl.hpp" #include "ngbitarray.hpp" #include "spbita2d.hpp" #include "seti.hpp" #include "optmem.hpp" // #include "autoptr.hpp" #include "sort.hpp" #include "stack.hpp" #include "mystring.hpp" // #include "mpi_interface.hpp" #include "netgenout.hpp" #endif ================================================ FILE: libsrc/general/mystring.cpp ================================================ //************************************************************** // // filename: mystring.cpp // // project: doctoral thesis // // author: Dipl.-Ing. Gerstmayr Johannes // // generated: 20.12.98 // last change: 20.12.98 // description: implementation for strings // remarks: // //************************************************************** // string class #include #include #include #include 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]; snprintf(buffer, 32, "%d", i); length = unsigned(strlen(buffer)); if (length > SHORTLEN) str = new char[length + 1]; else str = shortstr; strcpy(str, buffer); } /* MyStr::MyStr(unsigned 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]; snprintf(buffer, 32, "%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(size_t l) { char buffer[32]; snprintf(buffer, 32, "%zu", 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;} snprintf(buffer, 32, "%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;} snprintf(buffer, 80, "[%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;} snprintf(buffer, 80, "[%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(string_view sv) { length = unsigned(sv.length()); if (length > SHORTLEN) str = new char[length + 1]; else str = shortstr; strcpy (str, sv.data()); } MyStr::MyStr(const filesystem::path & path) : MyStr(path.string()) { } 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 */ } ================================================ FILE: libsrc/general/mystring.hpp ================================================ //************************************************************** // // filename: mystring.h // // project: doctoral thesis, program smart // // author: 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 #include 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; DLL_HEADER MyStr operator + (const MyStr &, const MyStr &); DLL_HEADER int operator == (const MyStr &, const MyStr &); DLL_HEADER int operator < (const MyStr &, const MyStr &); DLL_HEADER int operator <= (const MyStr &, const MyStr &); DLL_HEADER int operator > (const MyStr &, const MyStr &); DLL_HEADER int operator >= (const MyStr &, const MyStr &); DLL_HEADER int operator != (const MyStr &, const MyStr &); DLL_HEADER ostream& operator << (ostream &, const MyStr &); DLL_HEADER istream& operator >> (istream &, MyStr &); class DLL_HEADER MyStr { public: MyStr(); MyStr(const char *); MyStr(char); MyStr(const MyStr &); MyStr(int); MyStr(size_t); MyStr(void *); // MyStr(long); // MyStr(unsigned long); MyStr(double); MyStr(const Point3d& p); MyStr(const Vec3d& p); MyStr(const string & st); MyStr(string_view sv); MyStr(const filesystem::path & 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 &); DLL_HEADER 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; DLL_HEADER friend int operator == (const MyStr &, const MyStr &); DLL_HEADER friend int operator < (const MyStr &, const MyStr &); DLL_HEADER friend int operator <= (const MyStr &, const MyStr &); DLL_HEADER friend int operator > (const MyStr &, const MyStr &); DLL_HEADER friend int operator >= (const MyStr &, const MyStr &); DLL_HEADER friend int operator != (const MyStr &, const MyStr &); DLL_HEADER friend ostream& operator << (ostream &, const MyStr &); DLL_HEADER 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 ================================================ FILE: libsrc/general/netgenout.hpp ================================================ #ifndef NETGEN_OUT_STREAM_HPP__ #define NETGEN_OUT_STREAM_HPP__ // #include // #include // #include // #include "mpi_interface.hpp" namespace netgen { //DLL_HEADER extern int printmessage_importance; DLL_HEADER extern int printdots; 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::NgFlatArray procs; public: Procs ( const netgen::NgFlatArray & aprocs ) : procs (aprocs) { ; } const netgen::NgFlatArray & 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 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 ); */ inline NetgenOutStream operator<< ( ostream & ost, Imp imp ) { return ( NetgenOutStream ( &ost, imp ) ); } inline NetgenOutStream operator<< ( ostream & ost, Proc proc ) { return ( NetgenOutStream ( &ost, proc ) ); } inline NetgenOutStream operator<< ( ostream & ost, Procs & procs ) { return ( NetgenOutStream ( &ost, procs ) ); } // { // return ( NetgenOutStream ( &ost, imp.GetImp() ) ); // } // template // NetgenOutStream& operator<< (NetgenOutStream& out, T c ) // { // out.OStream() << c << endl; // return out; // } } #endif ================================================ FILE: libsrc/general/ngarray.hpp ================================================ #ifndef NGARRAY_HPP_INCLUDED #define NGARRAY_HPP_INCLUDED /**************************************************************************/ /* File: ngarray.hpp */ /* Author: Joachim Schoeberl */ /* Date: 01. Jun. 95 */ /**************************************************************************/ #include namespace netgen { using namespace ngcore; // template class IndirectArray; template class NgIndirectArray; template class ArrayRangeIterator { TSIZE ind; public: ArrayRangeIterator (TSIZE ai) : ind(ai) { ; } ArrayRangeIterator operator++ (int) { return ind++; } ArrayRangeIterator operator++ () { return ++ind; } TSIZE operator*() const { return ind; } bool operator != (ArrayRangeIterator d2) { return ind != d2.ind; } }; /// a range of integers template class T_Range { T first, next; public: T_Range (T f, T n) : first(f), next(n) {;} T Size() const { return next-first; } T operator[] (T i) const { return first+i; } bool Contains (T i) const { return ((i >= first) && (i < next)); } T_Range Modify (int inc_begin, int inc_end) const { return T_Range(first+inc_begin, next+inc_end); } ArrayRangeIterator begin() const { return first; } ArrayRangeIterator end() const { return next; } }; template class NgFlatArray; template class ArrayIterator { NgFlatArray ar; TIND ind; public: ArrayIterator (NgFlatArray aar, TIND ai) : ar(aar), ind(ai) { ; } ArrayIterator operator++ (int) { return ArrayIterator(ar, ind++); } ArrayIterator operator++ () { return ArrayIterator(ar, ++ind); } T operator*() const { return ar[ind]; } T & operator*() { return ar[ind]; } bool operator != (ArrayIterator d2) { return ind != d2.ind; } bool operator == (ArrayIterator d2) { return ind == d2.ind; } }; /** A simple array container. NgArray 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 NgFlatArray { protected: /// the size size_t size; /// the data T * data; public: typedef T TELEM; using index_type = TIND; /// provide size and memory NgFlatArray (size_t asize, T * adata) : size(asize), data(adata) { ; } /// the size size_t Size() const { return size; } ArrayIterator begin() const { return ArrayIterator (*this, BASE); } ArrayIterator end() const { return ArrayIterator (*this, BASE+size); } // TIND Begin() const { return TIND(BASE); } // TIND End() const { return TIND(size+BASE); } T_Range Range() const { return T_Range(BASE, size+BASE); } [[deprecated("Use *Range().begin() instead")]] auto Begin() const { return *Range().begin(); } [[deprecated("Use *Range().end() instead")]] auto End() const { return *Range().end(); } /// Access array. BASE-based T & operator[] (TIND i) const { NETGEN_CHECK_RANGE(i,BASE,size+BASE); return data[i-BASE]; } template NgIndirectArray > operator[] (const NgFlatArray & ia) const { return NgIndirectArray > (*this, ia); } /// Access array, one-based (old fashioned) T & Elem (int i) { NETGEN_CHECK_RANGE(i,1,size+1); return ((T*)data)[i-1]; } /// Access array, one-based (old fashioned) // [[deprecated("Use operator[] instead")]] const T & Get (int i) const { NETGEN_CHECK_RANGE(i,1,size+1); return ((const T*)data)[i-1]; } /// Access array, one-based (old fashioned) void Set (int i, const T & el) { NETGEN_CHECK_RANGE(i,1,size+1); ((T*)data)[i-1] = el; } /// access first element T & First () const { NETGEN_CHECK_RANGE(0,0,size); return data[0]; } /// access last element. check by macro CHECK_RANGE T & Last () const { NETGEN_CHECK_RANGE(size-1,0,size); return data[size-1]; } /// Fill array with value val NgFlatArray & 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 NgFlatArray Range (TIND start, TIND end) { return NgFlatArray (end-start, data+start); } /// first position of element elem, returns -1 if element not contained in array TIND Pos(const T & elem) const { TIND pos = -1; for(TIND 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 ); } operator ngcore::FlatArray () const { static_assert (BASE==0); return ngcore::FlatArray(size, data); } }; // print array template inline ostream & operator<< (ostream & s, const NgFlatArray & a) { // for (TIND i = a.Begin(); i < a.End(); i++) for (auto i : a.Range()) s << i << ": " << a[i] << endl; return s; } /** Dynamic array container. NgArray 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 NgArray : public NgFlatArray { protected: using NgFlatArray::size; using NgFlatArray::data; /// physical size of array size_t allocsize = 0; /// memory is responsibility of container bool ownmem; public: /// Generate array of logical and physical size asize explicit NgArray() : NgFlatArray (0, NULL) { allocsize = 0; ownmem = 1; } explicit NgArray(size_t asize) : NgFlatArray (asize, asize ? new T[asize] : nullptr) { allocsize = asize; ownmem = (asize == 0) ? 0 : 1; } /// Generate array in user data NgArray(TIND asize, T* adata) : NgFlatArray (asize, adata) { allocsize = asize; ownmem = 0; } /// array copy explicit NgArray (const NgArray & a2) : NgFlatArray (a2.Size(), a2.Size() ? new T[a2.Size()] : 0) { allocsize = size; ownmem = 1; for (TIND i = BASE; i < size+BASE; i++) (*this)[i] = a2[i]; } /// array move NgArray (NgArray && a2) : NgFlatArray (a2.size, a2.data), allocsize(a2.allocsize), ownmem(a2.ownmem) { a2.size = 0; a2.data = nullptr; a2.allocsize = 0; a2.ownmem = false; } /// if responsible, deletes memory ~NgArray() { if (ownmem) delete [] data; } /// Change logical size. If necessary, do reallocation. Keeps contents. void SetSize(size_t nsize) { if (nsize > allocsize) ReSize (nsize); size = nsize; } void SetSize0() { size = 0; } /// Change physical size. Keeps logical size. Keeps contents. void SetAllocSize (size_t nallocsize) { if (nallocsize > allocsize) ReSize (nallocsize); } /// Add element at end of array. reallocation if necessary. void Append (const T & el) { if (size == allocsize) ReSize (size+1); data[size] = el; size++; // return size; } template void Append (NgFlatArray 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 (TIND i) { NETGEN_CHECK_RANGE(i,0,size); data[i] = std::move(data[size-1]); size--; // DeleteElement (i+1); } /// Delete element i (1-based). Move last element to position i. void DeleteElement (TIND i) { NETGEN_CHECK_RANGE(i,1,size+1); data[i-1] = std::move(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 NgArray & operator= (const T & val) { NgFlatArray::operator= (val); return *this; } /// array copy NgArray & operator= (const NgArray & a2) { SetSize (a2.Size()); for (TIND i (BASE); i < size+BASE; i++) (*this)[i] = a2[i]; return *this; } /// array copy NgArray & operator= (const NgFlatArray & a2) { SetSize (a2.Size()); for (TIND i = BASE; i < size+BASE; i++) (*this)[i] = a2[i]; return *this; } NgArray & operator= (NgArray && a2) { ngcore::Swap (data, a2.data); ngcore::Swap (size, a2.size); ngcore::Swap (allocsize, a2.allocsize); ngcore::Swap (ownmem, a2.ownmem); return *this; } T * Release() { ownmem = false; return data; } // Only provide this function if T is archivable template auto DoArchive(ARCHIVE& archive) -> typename std::enable_if_t, void> { if(archive.Output()) archive << size; else { size_t s; archive & s; SetSize(s); } archive.Do(data, size); } private: /// resize array, at least to size minsize. copy contents void ReSize (size_t minsize) { size_t nsize = 2 * allocsize; if (nsize < minsize) nsize = minsize; if (data) { T * p = new T[nsize]; size_t mins = (nsize < size) ? nsize : size; if constexpr(std::is_trivially_copyable::value) memcpy (p, data, sizeof(T)*mins); else for (size_t i = 0; i < mins; i++) p[i] = std::move(data[i]); if (ownmem) delete [] data; ownmem = 1; data = p; } else { data = new T[nsize]; ownmem = 1; } allocsize = nsize; } }; template class NgArrayMem : public NgArray { using NgArray::size; using NgArray::data; using NgArray::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 NgArrayMem(size_t asize = 0) : NgArray (S, static_cast (static_cast(&mem[0]))) { size = asize; if (asize > S) { data = new T[asize]; ownmem = 1; } // SetSize (asize); } NgArrayMem & operator= (const T & val) { NgArray::operator= (val); return *this; } /// array copy NgArrayMem & operator= (const NgFlatArray & a2) { this->SetSize (a2.Size()); for (size_t i = 0; i < size; i++) (*this)[i] = a2[i]; return *this; } }; /* template class IndirectArray { const NgFlatArray & array; const NgFlatArray & ia; public: IndirectArray (const NgFlatArray & aa, const NgFlatArray & aia) : array(aa), ia(aia) { ; } int Size() const { return ia.Size(); } const T & operator[] (int i) const { return array[ia[i]]; } }; */ template class NgIndirectArray { const TA1 & array; const TA2 & ia; public: NgIndirectArray (const TA1 & aa, const TA2 & aia) : array(aa), ia(aia) { ; } int Size() const { return ia.Size(); } [[deprecated("Use *Range().begin() instead")]] int Begin() const { return ia.Begin(); } [[deprecated("Use *Range().end() instead")]] int End() const { return ia.End(); } const typename TA1::TELEM & operator[] (int i) const { return array[ia[i]]; } auto Range() const { return ia.Range(); } // auto begin() const { return ia.begin(); } // auto end() const { return ia.end(); } }; template inline ostream & operator<< (ostream & s, const NgIndirectArray & ia) { for (int i = ia.Begin(); i < ia.End(); i++) s << i << ": " << ia[i] << endl; return s; } /* /// template class MoveableArray { int size; int allocsize; DynamicMem 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 inline ostream & operator<< (ostream & ost, MoveableArray & a) { for (int i = 0; i < a.Size(); i++) ost << i << ": " << a[i] << endl; return ost; } */ /// bubble sort array template inline void BubbleSort (const NgFlatArray & 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 inline void BubbleSort (NgFlatArray & data, NgFlatArray & index) { 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 = index[i]; index[i] = index[j]; index[j] = hvs; } } template void QuickSortRec (NgFlatArray & data, NgFlatArray & index, 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) { ngcore::Swap (data[i], data[j]); ngcore::Swap (index[i], index[j]); i++; j--; } } while (i <= j); if (left < j) QuickSortRec (data, index, left, j); if (i < right) QuickSortRec (data, index, i, right); } template void QuickSort (NgFlatArray & data, NgFlatArray & index) { if (data.Size() > 1) QuickSortRec (data, index, 0, data.Size()-1); } template void Intersection (const NgFlatArray & in1, const NgFlatArray & in2, NgArray & out) { out.SetSize(0); for(int i=0; i void Intersection (const NgFlatArray & in1, const NgFlatArray & in2, const NgFlatArray & in3, NgArray & out) { out.SetSize(0); for(int i=0; i #include namespace netgen { //using namespace netgen; NgBitArray :: NgBitArray () { size = 0; data = NULL; } NgBitArray :: NgBitArray (int asize) { size = 0; data = NULL; SetSize (asize); } NgBitArray :: ~NgBitArray () { delete [] data; } void NgBitArray :: SetSize (int asize) { if (size == asize) return; delete [] data; size = asize; data = new unsigned char [Addr (size)+1]; } void NgBitArray :: Set () { if (!size) return; for (int i = 0; i <= Addr (size); i++) data[i] = UCHAR_MAX; } void NgBitArray :: Clear () { if (!size) return; for (int i = 0; i <= Addr (size); i++) data[i] = 0; } void NgBitArray :: Invert () { if (!size) return; for (int i = 0; i <= Addr (size); i++) data[i] ^= 255; } void NgBitArray :: And (const NgBitArray & ba2) { if (!size) return; for (int i = 0; i <= Addr (size); i++) data[i] &= ba2.data[i]; } void NgBitArray :: Or (const NgBitArray & ba2) { if (!size) return; for (int i = 0; i <= Addr (size); i++) data[i] |= ba2.data[i]; } } ================================================ FILE: libsrc/general/ngbitarray.hpp ================================================ #ifndef FILE_BitArray #define FILE_BitArray /**************************************************************************/ /* File: bitarray.hpp */ /* Author: Joachim Schoeberl */ /* Date: 01. Jun. 95 */ /**************************************************************************/ #include namespace netgen { /** data type NgBitArray NgBitArray 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 occurring bit. No range checking is done. index ranges from 0 to size-1 */ class NgBitArray { INDEX size; unsigned char * data; public: // [[ deprecated ("use BitArray instead")]] DLL_HEADER NgBitArray (); /// // [[ deprecated ("use BitArray instead")]] DLL_HEADER NgBitArray (INDEX asize); /// DLL_HEADER ~NgBitArray (); /// DLL_HEADER void SetSize (INDEX asize); /// INDEX Size () const { return size; } /// DLL_HEADER void Set (); /// void Set (INDEX i) { data[Addr(i)] |= Mask(i); } DLL_HEADER 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 NgBitArray & ba2); /// void Or (const NgBitArray & 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); } /// NgBitArray & operator= (NgBitArray &); /// NgBitArray (const NgBitArray &); }; // print bitarray inline ostream & operator<< (ostream & s, const NgBitArray & 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 NgBitArray :: Size () const { return size; } inline unsigned char NgBitArray :: Mask (INDEX i) const { return char(1) << (i % CHAR_BIT); } inline INDEX NgBitArray :: Addr (INDEX i) const { return (i / CHAR_BIT); } inline void NgBitArray :: Set (INDEX i) { data[Addr(i)] |= Mask(i); } inline void NgBitArray :: Clear (INDEX i) { data[Addr(i)] &= ~Mask(i); } inline int NgBitArray :: Test (INDEX i) const { return (data[i / CHAR_BIT] & (char(1) << (i % CHAR_BIT) ) ) ? 1 : 0; } */ } #endif ================================================ FILE: libsrc/general/ngpython.hpp ================================================ #ifdef NG_PYTHON #include #include #include #include #include #include // using namespace ngcore; template py::array MoveToNumpy(std::vector& vec) { auto newvec = new std::vector(); std::swap(*newvec, vec); auto capsule = py::capsule(newvec, [](void *v) { delete reinterpret_cast*>(v); }); return py::array(newvec->size(), newvec->data(), capsule); } namespace PYBIND11_NAMESPACE { template bool CheckCast( py::handle obj ) { try{ obj.cast(); return true; } catch (py::cast_error &e) { return false; } } template struct extract { py::handle obj; extract( py::handle aobj ) : obj(aobj) {} bool check() { return CheckCast(obj); } T operator()() { return obj.cast(); } }; } struct NGDummyArgument {}; inline void NOOP_Deleter(void *) { ; } namespace netgen { ////////////////////////////////////////////////////////////////////// // Lambda to function pointer conversion template struct function_traits : public function_traits {}; template struct function_traits { typedef ReturnType (*pointer)(Args...); typedef ReturnType return_type; }; template typename function_traits::pointer FunctionPointer (const Function& lambda) { return static_cast::pointer>(lambda); } } // namespace netgen #endif ================================================ FILE: libsrc/general/optmem.cpp ================================================ /**************************************************************************/ /* File: optmem.cpp */ /* Author: Joachim Schoeberl */ /* Date: 04. Apr. 97 */ /**************************************************************************/ /* Abstract data type NgArray */ #include #include namespace netgen { // static mutex block_allocator_mutex; BlockAllocator :: BlockAllocator (unsigned asize, unsigned ablocks) : bablocks (0) { if (asize < sizeof(void*)) asize = sizeof(void*); size = asize; blocks = ablocks; freelist = NULL; } BlockAllocator :: ~BlockAllocator () { lock_guard guard(block_allocator_mutex); // cout << "****************** delete BlockAllocator " << endl; for (int i = 0; i < bablocks.Size(); i++) delete [] bablocks[i]; bablocks.SetSize(0); } void * BlockAllocator :: Alloc () { void * p; { lock_guard guard(block_allocator_mutex); // 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; } p = freelist; freelist = *(void**)freelist; } return p; } void BlockAllocator :: Free (void * p) { { lock_guard guard(block_allocator_mutex); if (bablocks.Size()) { *(void**)p = freelist; freelist = p; } } } } ================================================ FILE: libsrc/general/optmem.hpp ================================================ #ifndef FILE_OPTMEM #define FILE_OPTMEM /**************************************************************************/ /* File: optmem.hh */ /* Author: Joachim Schoeberl */ /* Date: 04. Apr. 97 */ /**************************************************************************/ #include #include "ngarray.hpp" namespace netgen { /** Optimized Memory allocation classes */ class BlockAllocator { private: /// unsigned size, blocks; /// void * freelist; /// NgArray bablocks; mutex block_allocator_mutex; public: /// DLL_HEADER BlockAllocator (unsigned asize, unsigned ablocks = 100); /// DLL_HEADER ~BlockAllocator (); /// DLL_HEADER void * Alloc (); /// DLL_HEADER void Free (void * p); }; } #endif ================================================ FILE: libsrc/general/parthreads.cpp ================================================ /**************************************************************************/ /* File: parthreads.cpp */ /* Author: Joachim Schoeberl */ /* Date: 01. Jun. 95 */ /**************************************************************************/ #include #include /* 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 } */ ================================================ FILE: libsrc/general/parthreads.hpp ================================================ #ifndef FILE_PARTHREADS #define FILE_PARTHREADS /**************************************************************************/ /* File: parthreads.hh */ /* Author: Joachim Schoeberl */ /* Date: 22. Nov. 2000 */ /**************************************************************************/ /* Parallel thread, Mutex, */ #include namespace netgen { #ifdef NO_PARALLEL_THREADS class NgMutex { }; class NgLock { public: NgLock (NgMutex & mut, bool lock = 0) { ; } void Lock () { ; } void UnLock () { ; } }; #else typedef std::mutex NgMutex; class NgLock { NgMutex & mut; bool locked; public: NgLock (NgMutex & ngmut, bool lock = false) : mut (ngmut) { if (lock) mut.lock(); locked = lock; }; ~NgLock() { if (locked) mut.unlock(); } void Lock () { mut.lock(); locked = true; } void UnLock () { mut.unlock(); locked = false; } /* int TryLock () { return mut.try_lock(); } */ }; #endif // Simple ParallelFor function to replace OpenMP template void ParallelFor( int first, int next, const TFunc & f ) { int nthreads = std::thread::hardware_concurrency(); std::thread * threads = new std::thread[nthreads]; for (int i=0; i); typedef void (*NgTracer)(std::string, bool); // false .. start, true .. stop inline void DummyTaskManager (std::function func) { func(0,2); func(1,2); } inline void DummyTracer (std::string, bool) { ; } template inline void ParallelFor (NgTaskManager tm, size_t n, FUNC func) { (*tm) ([n,func] (size_t nr, size_t nums) { size_t begin = nr*n / nums; size_t end = (nr+1)*n / nums; for (size_t i = begin; i < end; i++) func(i); }); } template inline void ParallelForRange (NgTaskManager tm, size_t n, FUNC func) { (*tm) ([n,func] (size_t nr, size_t nums) { size_t begin = nr*n / nums; size_t end = (nr+1)*n / nums; func(begin, end); }); } } #endif ================================================ FILE: libsrc/general/seti.cpp ================================================ #include #include 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); } } ================================================ FILE: libsrc/general/seti.hpp ================================================ #ifndef FILE_SETI #define FILE_SETI /**************************************************************************/ /* File: seti.hh */ /* Author: Joachim Schoeberl */ /* Date: 20. Mar. 98 */ /**************************************************************************/ namespace netgen { /** Set of Integers */ class IndexSet { NgArray set; NgBitArray 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 NgArray & GetArray() { return set; } }; } #endif ================================================ FILE: libsrc/general/sort.cpp ================================================ /**************************************************************************/ /* File: sort.cc */ /* Author: Joachim Schoeberl */ /* Date: 07. Jan. 00 */ /**************************************************************************/ /* Sorting */ #include #include #include namespace netgen { void Sort (const NgArray & values, NgArray & 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 NgArray & values, NgArray & 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 NgArray & values, NgArray & 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()); } } ================================================ FILE: libsrc/general/sort.hpp ================================================ #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 NgArray & values, NgArray & order); extern void QuickSort (const NgArray & values, NgArray & order); template 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 inline void BubbleSort (NgArray & data) { if(data.Size() > 0) // BubbleSort (data.Size(), &data[data.Begin()]); BubbleSort (data.Size(), &data[*data.Range().begin()]); } } #endif ================================================ FILE: libsrc/general/spbita2d.cpp ================================================ /**************************************************************************/ /* File: spbita2d.cpp */ /* Author: Joachim Schoeberl */ /* Date: 01. Jun. 95 */ /**************************************************************************/ /* Implementation of sparse 2 dimensional bitarray */ #include #include 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"); } } } } ================================================ FILE: libsrc/general/spbita2d.hpp ================================================ #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 ================================================ FILE: libsrc/general/stack.hpp ================================================ #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 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: /// NgArray elems; /// INDEX size; }; /* Stack class, based on a resizable array */ template inline STACK :: STACK (INDEX asize, INDEX ainc) : elems(asize, ainc) { size = 0; } template inline STACK :: ~STACK () { ; } template inline void STACK :: Push (const T & el) { if (size < elems.Size()) elems.Elem(++size) = el; else { elems.Append(el); size++; } } template inline T & STACK :: Pop () { return elems.Elem(size--); } template const inline T & STACK :: Top () const { return elems.Get(size); } template inline int STACK :: IsEmpty () const { return (size == 0); } template inline void STACK :: MakeEmpty () { size = 0; } } #endif ================================================ FILE: libsrc/general/table.cpp ================================================ /**************************************************************************/ /* File: table.cpp */ /* Author: Joachim Schoeberl */ /* Date: 01. Jun. 95 */ /**************************************************************************/ /* Abstract data type TABLE */ #include #include 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 NgFlatArray & entrysizes, int elemsize) : data(entrysizes.Size()) { size_t cnt = 0; size_t n = entrysizes.Size(); for (size_t i = 0; i < n; i++) cnt += entrysizes[i]; oneblock = new char[elemsize * cnt]; // mem_total_alloc_table += elemsize * cnt; cnt = 0; for (size_t 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]; if (line.maxsize && 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) { size_t cnt = 0; size_t n = data.Size(); for (size_t i = 0; i < n; i++) cnt += data[i].maxsize; oneblock = new char[elemsize * cnt]; cnt = 0; for (size_t i = 0; i < n; i++) { data[i].size = 0; data[i].col = &oneblock[elemsize * cnt]; cnt += data[i].maxsize; } } size_t BASE_TABLE :: AllocatedElements () const { size_t els = 0; for (size_t i = 0; i < data.Size(); i++) els += data[i].maxsize; return els; } size_t BASE_TABLE :: UsedElements () const { size_t els = 0; for (size_t 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; } void BASE_TABLE :: DoArchive (Archive & ar, int elemsize) { if (ar.Output()) { size_t entries = 0, size = data.Size(); for (size_t i = 0; i < data.Size(); i++) entries += data[i].size; ar & size & entries; for (size_t i = 0; i < data.Size(); i++) { ar & data[i].size; ar.Do ((unsigned char*)data[i].col, data[i].size*elemsize); /* for (size_t j = 0; j < data[i].size*elemsize; j++) ar & ((unsigned char*) data[i].col)[j]; cout << "write " << data[i].size*elemsize << " chars" << endl; */ } } else { size_t entries, size; ar & size & entries; data.SetSize(size); oneblock = new char [entries*elemsize]; size_t cnt = 0; for (size_t i = 0; i < size; i++) { ar & data[i].size; data[i].col = oneblock+cnt; data[i].maxsize = data[i].size; ar.Do ((unsigned char*)(oneblock+cnt), data[i].size*elemsize); cnt += data[i].size*elemsize; } } } } ================================================ FILE: libsrc/general/table.hpp ================================================ #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; }; /// NgArray data; char * oneblock; public: /// BASE_TABLE (BASE_TABLE && table2) : data(std::move(table2.data)), oneblock(table2.oneblock) { table2.oneblock = nullptr; } DLL_HEADER BASE_TABLE (int size); /// DLL_HEADER BASE_TABLE (const NgFlatArray & entrysizes, int elemsize); /// DLL_HEADER ~BASE_TABLE (); BASE_TABLE & operator= (BASE_TABLE && table2) { data = std::move(table2.data); Swap (oneblock, table2.oneblock); return *this; } /// 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); size_t AllocatedElements () const; size_t UsedElements () const; void SetElementSizesToMaxSizes (); void DoArchive (Archive & ar, int elemsize); }; /** 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 TABLE : public BASE_TABLE { public: /// Creates table. inline TABLE () : BASE_TABLE(0) { ; } /// Creates table of size size inline TABLE (int size) : BASE_TABLE (size) { ; } TABLE (TABLE && tab2) : BASE_TABLE(move(tab2)) { } /// Creates fixed maximal element size table inline TABLE (const NgFlatArray & entrysizes) : BASE_TABLE (NgFlatArray (entrysizes.Size(), entrysizes.Size() ? const_cast(&entrysizes[BASE]) : nullptr), sizeof(T)) { ; } TABLE & operator= (TABLE && tab2) { BASE_TABLE::operator=(move(tab2)); return *this; } /// 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) { NETGEN_CHECK_RANGE(i, BASE, data.Size()+BASE); ((T*)data[i-BASE].col)[data[i-BASE].size] = acont; data[i-BASE].size++; } inline void ParallelAdd (int i, const T & acont) { auto oldval = AsAtomic (data[i-BASE].size)++; ((T*)data[i-BASE].col)[oldval] = acont; } /// 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]; } inline T & Get (int i, int nr) { 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: allocated " << els << " a " << sizeof(T) << " Byts = " << els * sizeof(T) << " bytes in " << Size() << " bags." << " used: " << UsedElements() << endl; } /// Access entry. NgFlatArray 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 NgFlatArray (data[i-BASE].size, (T*)data[i-BASE].col); } void DoArchive (Archive & ar) { BASE_TABLE::DoArchive(ar, sizeof(T)); } }; template inline ostream & operator<< (ostream & ost, const TABLE & table) { for (int i = BASE; i < table.Size()+BASE; i++) { ost << i << ": "; NgFlatArray row = table[i]; ost << "(" << row.Size() << ") "; for (int j = 0; j < row.Size(); j++) ost << row[j] << " "; ost << endl; } return ost; } } #endif ================================================ FILE: libsrc/general/template.hpp ================================================ #ifndef FILE_TEMPLATE #define FILE_TEMPLATE /**************************************************************************/ /* File: template.hh */ /* Author: Joachim Schoeberl */ /* Date: 01. Jun. 95 */ /**************************************************************************/ #include namespace netgen { using namespace ngcore; /* templates, global types, defines and variables */ DLL_HEADER extern const std::string netgen_version; /// The following value may be adapted to the hardware ! #ifndef CLOCKS_PER_SEC #define CLOCKS_PER_SEC 1000000 #endif // #include /** output stream for testing. testout is opened by main */ /** use instead of cout */ DLL_HEADER extern ostream * mycout; /** error output stream */ DLL_HEADER 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. */ DLL_HEADER extern void MyBeep (int nr = 1); /** 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: /// // protected: INDEX_2 () { } INDEX_2 (const INDEX_2&) = default; public: INDEX_2 (INDEX_2&&) = default; INDEX_2 & operator= (const INDEX_2&) = default; INDEX_2 & operator= (INDEX_2&&) = default; /// constexpr INDEX_2 (INDEX ai1, INDEX ai2) : i{ai1, ai2} { } // { i[0] = ai1; i[1] = ai2; } /// // constexpr INDEX_2 (const INDEX_2 & in2) // : i{in2.i[0], in2.i[1]} { } // { 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]; } /// constexpr 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); } operator std::array() { return { i[0], i[1] }; } /// 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]; } /// constexpr const int & operator[] (int j) const { return i[j]; } /// friend ostream & operator<<(ostream & s, const INDEX_2 & i2); }; /* inline INDEX_2 Sort (const INDEX_2 & i2) { INDEX_2 tmp = i2; tmp.Sort(); return tmp; } */ inline INDEX_2 Sort (INDEX_2 i2) { i2.Sort(); return i2; } inline bool operator< (const INDEX_2 ia, const INDEX_2 ib) { if (ia[0] < ib[0]) return true; if (ia[0] > ib[0]) return false; if (ia[1] < ib[1]) return true; return false; } /// class INDEX_3 { /// INDEX i[3]; public: /// INDEX_3 () { } /// constexpr INDEX_3 (INDEX ai1, INDEX ai2, INDEX ai3) : i{ai1, ai2, ai3} { } /// constexpr INDEX_3 (const INDEX_3 & in2) : i{in2.i[0], in2.i[1], 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 inline T min2 (T a, T b) { /// return (a < b) ? a : b; } /// template inline T max2 (T a, T b) { /// return (a > b) ? a : b; } /// template inline T min3 (T a, T b, T c) { /// return (a < b) ? (a < c) ? a : c : (b < c) ? b : c; } /// template inline T max3 (T a, T b, T c) { /// return (a > b) ? ((a > c) ? a : c) : ((b > c) ? b : c); } /// /// template inline int sgn (T a) { return (a > 0) ? 1 : ( ( a < 0) ? -1 : 0 ); } /// template inline T sqr (const T a) { return a * a; } /// template inline T pow3 (const T a) { return a * a * a; } */ /* template void BubbleSort (int size, T * data); template void MergeSort (int size, T * data, T * help); */ } namespace ngcore { // template <> // constexpr inline netgen::INDEX_2 InvalidHash () { return netgen::INDEX_2{-1,-1}; } template <> struct CHT_trait { constexpr static inline netgen::INDEX_2 Invalid() { return { -1, -1 } ; } constexpr static inline size_t HashValue (const netgen::INDEX_2 & hash, size_t mask) { return HashValue2(IVec<2,netgen::INDEX>(hash[0], hash[1]), mask); } }; } namespace netgen { /* inline size_t HashValue2 (const netgen::INDEX_2 & ind, size_t mask) { return HashValue2(IVec<2,netgen::INDEX>(ind[0], ind[1]), mask); } */ inline size_t HashValue2 (const netgen::INDEX_3 & ind, size_t mask) { return HashValue2(IVec<3,netgen::INDEX>(ind[0], ind[1], ind[2]), mask); } } #endif ================================================ FILE: libsrc/geom2d/CMakeLists.txt ================================================ target_sources(nglib PRIVATE csg2d.cpp genmesh2d.cpp geometry2d.cpp python_geom2d.cpp ) if(USE_GUI) target_sources(nggui PRIVATE vsgeom2d.cpp geom2dpkg.cpp) endif(USE_GUI) install(FILES geometry2d.hpp spline2d.hpp vsgeom2d.hpp csg2d.hpp DESTINATION ${NG_INSTALL_DIR_INCLUDE}/geom2d COMPONENT netgen_devel ) ================================================ FILE: libsrc/geom2d/csg2d.cpp ================================================ #include #include #include #include #include #include "csg2d.hpp" // Polygon clipping algorithm based on: // Foster, Erich & Hormann, Kai & Popa, Romeo. (2019). Clipping Simple Polygons with Degenerate Intersections. Computers & Graphics: X. 2. 100007. 10.1016/j.cagx.2019.100007. // extended to handle quadratic spline segments namespace netgen { constexpr static double EPSILON=0.000000001; void ComputeWeight( Spline & s, Point<2> p ) { Point<2> a = s.StartPI(); Point<2> b = s.TangentPoint(); Point<2> c = s.EndPI(); double A = (p[1]-a[1])*(b[0]-p[0]) - (p[0]-a[0])*(b[1]-p[1]); double B = (p[1]-c[1])*(b[0]-p[0]) - (p[0]-c[0])*(b[1]-p[1]); double det = sqrt(-A*B); double tt = fabs(A+det) fabs(v[1]) ? 0 : 1; double weight = fabs(tt*(p[dim]-a[dim])/v[dim] + 1.0/tt*(p[dim]-c[dim])/v[dim]); s.SetWeight(weight); } void ToggleLabel(EntryExitLabel& status) { if (status == ENTRY) { status = EXIT; return; } if (status == EXIT) { status = ENTRY; return; } } Spline Split( const Spline & s, double t0, double t1 ) { if(t0==0.0 && t1==1.0) return s; Point<2> a = s.StartPI(); if(t0!=0.0) a = s.GetPoint(t0); Point<2> c = s.EndPI(); if(t1!=1.0) c = s.GetPoint(t1); // Find new midpoints by cutting the tangents at the new end points auto tang0 = s.GetTangent(t0); auto tang1 = s.GetTangent(t1); netgen::Mat<2,2> m, minv; m(0,0) = tang0[0]; m(1,0) = tang0[1]; m(0,1) = -tang1[0]; m(1,1) = -tang1[1]; CalcInverse(m, minv); Vec<2> lam = minv*(c-a); Point<2> b = a+lam[0]*tang0; auto res = Spline{a, b, c}; // compute weight of new spline such that p lies on it Point<2> p = s.GetPoint(0.5*(t0+t1)); ComputeWeight(res, p); return res; } Vertex * Vertex :: Insert(Point<2> p, double lam) { auto vnew = make_unique(p); vnew->lam = lam; Vertex * current = this; if(lam > -1.0) { do { current = current->next; } while (!current->is_source && current->lam < lam); } else current = current->next; auto pre = current->prev; if(lam > -1.0) vnew->info = pre->info; pre->next = vnew.get(); vnew->prev = pre; vnew->next = current; vnew->pnext = std::move(current->prev->pnext); current->prev = vnew.get(); pre->pnext = std::move(vnew); return pre->next; } IntersectionType ClassifyNonOverlappingIntersection( double alpha, double beta ) { // classify alpha bool alpha_is_0 = false; bool alpha_in_0_1 = false; if ( (alpha > EPSILON) && (alpha < 1.0-EPSILON) ) alpha_in_0_1 = true; else if (fabs(alpha) <= EPSILON) alpha_is_0 = true; // classify beta bool beta_is_0 = false; bool beta_in_0_1 = false; if ( (beta > EPSILON) && (beta < 1.0-EPSILON) ) beta_in_0_1 = true; else if (fabs(beta) <= EPSILON) beta_is_0 = true; // distinguish intersection types if (alpha_in_0_1 && beta_in_0_1) return (X_INTERSECTION); if (alpha_is_0 && beta_in_0_1) return (T_INTERSECTION_Q); if (beta_is_0 && alpha_in_0_1) return (T_INTERSECTION_P); if (alpha_is_0 && beta_is_0) return (V_INTERSECTION); return NO_INTERSECTION; } IntersectionType ClassifyOverlappingIntersection( double alpha, double beta ) { // classify alpha bool alpha_is_0 = false; bool alpha_in_0_1 = false; bool alpha_not_in_0_1 = false; if ( (alpha > EPSILON) && (alpha < 1.0-EPSILON) ) alpha_in_0_1 = true; else if (fabs(alpha) <= EPSILON) alpha_is_0 = true; else alpha_not_in_0_1 = true; // classify beta bool beta_is_0 = false; bool beta_in_0_1 = false; bool beta_not_in_0_1 = false; if ( (beta > EPSILON) && (beta < 1.0-EPSILON) ) beta_in_0_1 = true; else if (fabs(alpha) <= EPSILON) beta_is_0 = true; else beta_not_in_0_1 = true; // distinguish intersection types if (alpha_in_0_1 && beta_in_0_1) return (X_OVERLAP); if (alpha_not_in_0_1 && beta_in_0_1) return (T_OVERLAP_Q); if (beta_not_in_0_1 && alpha_in_0_1) return (T_OVERLAP_P); if (alpha_is_0 && beta_is_0) return (V_OVERLAP); return NO_INTERSECTION; } IntersectionType intersect(const Point<2> P1, const Point<2> P2, const Point<2> Q1, const Point<2> Q2, double& alpha, double& beta) { double AP1 = Area(P1,Q1,Q2); double AP2 = Area(P2,Q1,Q2); if (fabs(AP1-AP2) > EPSILON) { // (P1,P2) and (Q1,Q2) are not parallel double AQ1 = Area(Q1,P1,P2); double AQ2 = Area(Q2,P1,P2); alpha = AP1 / (AP1-AP2); beta = AQ1 / (AQ1-AQ2); return ClassifyNonOverlappingIntersection(alpha, beta); } else if (fabs(AP1) < EPSILON) { // (P1,P2) and (Q1,Q2) are collinear auto dP = P2-P1; auto dQ = Q2-Q1; auto PQ = Q1-P1; alpha = (PQ*dP) / (dP*dP); beta = -(PQ*dQ) / (dQ*dQ); return ClassifyOverlappingIntersection(alpha, beta); } return NO_INTERSECTION; } IntersectionType IntersectSplineSegment( const Spline & s, const Point<2> & r0, const Point<2> & r1, double& alpha, double& beta ) { Point<2> p0 = s.StartPI(); Point<2> p1 = s.TangentPoint(); Point<2> p2 = s.EndPI(); auto vr = r1-r0; double a0 = vr[1]*(p0[0] - r0[0]) - vr[0]*(p0[1] - r0[1]); double a1 = vr[1]*(p1[0] - r0[0]) - vr[0]*(p1[1] - r0[1]); double a2 = vr[1]*(p2[0] - r0[0]) - vr[0]*(p2[1] - r0[1]); a1 *= s.GetWeight(); double a_ = a0-a1+a2; double b_ = a1-2*a0; double c_ = a0; double det = b_*b_ - 4*a_*c_; if(det<0.0) return NO_INTERSECTION; double t; if(fabs(a_)>EPSILON) { double sqrt_det = sqrt(det); double t1 = 1.0/(2*a_) * (-b_ + sqrt_det); double t2 = 1.0/(2*a_) * (-b_ - sqrt_det); t = min(t1, t2); if(t fabs(vr[1]) ? 0 : 1; beta = 1.0/vr[dim] * (s.GetPoint(t)[dim] - r0[dim]); return ClassifyNonOverlappingIntersection(alpha, beta); } IntersectionType IntersectSplineSegment1( const Spline & s, const Point<2> & r0, const Point<2> & r1, double& alpha, double& beta, bool first=false) { Point<2> p0 = s.StartPI(); Point<2> p1 = s.TangentPoint(); Point<2> p2 = s.EndPI(); auto vr = r1-r0; double a0 = vr[1]*(p0[0] - r0[0]) - vr[0]*(p0[1] - r0[1]); double a1 = vr[1]*(p1[0] - r0[0]) - vr[0]*(p1[1] - r0[1]); double a2 = vr[1]*(p2[0] - r0[0]) - vr[0]*(p2[1] - r0[1]); a1 *= s.GetWeight(); double a_ = a0-a1+a2; double b_ = a1-2*a0; double c_ = a0; double det = b_*b_ - 4*a_*c_; if(det<-EPSILON) return NO_INTERSECTION; if(detEPSILON) { vbeta[0] = 1.0/(2*a_) * (-b_ + sqrt_det); vbeta[1] = 1.0/(2*a_) * (-b_ - sqrt_det); } else // degenerate quadratic equation vbeta[0] = vbeta[1] = -c_/b_; int dim = fabs(vr[0]) > fabs(vr[1]) ? 0 : 1; double valpha[2]; valpha[0] = 1.0/vr[dim] * (s.GetPoint(vbeta[0])[dim] - r0[dim]); valpha[1] = 1.0/vr[dim] * (s.GetPoint(vbeta[1])[dim] - r0[dim]); IntersectionType vtype[2]; vtype[0] = ClassifyNonOverlappingIntersection(valpha[0], vbeta[0]); vtype[1] = ClassifyNonOverlappingIntersection(valpha[1], vbeta[1]); if(valpha[0]>valpha[1]) { swap(valpha[0], valpha[1]); swap(vbeta[0], vbeta[1]); swap(vtype[0], vtype[1]); } int choice = 0; if(!first) { if(vtype[0]==NO_INTERSECTION && vtype[1]!=NO_INTERSECTION) choice = 1; if(valpha[0] < alpha+EPSILON) choice = 1; } if(valpha[choice] < alpha+EPSILON) return NO_INTERSECTION; alpha = valpha[choice]; beta = vbeta[choice]; return vtype[choice]; } bool IsOverlapping( Spline p, Spline s, double & alpha, double & beta, IntersectionType & type ) { auto p_mid = Center(p.StartPI(), p.EndPI()); auto s_mid = Center(s.StartPI(), s.EndPI()); double lam0 = -1e3*EPSILON; double lam1 = -1e3*EPSILON; double lam2 = -1e3*EPSILON; double lam3 = -1e3*EPSILON; alpha=-1e8; beta=-1e8; double alpha_mid=-1e8; double beta_mid=-1e8; // Check if s.p0 lies on p and vice versa, also check if tangents are in same direction (TODO: TEST) // If so, assume overlapping splines // TODO: Better checks! False positives could happen here! if(Dist(s.StartPI(), p.StartPI())eps) return false; if(fabs(lam1)>eps) return false; if(fabs(lam2)>eps) return false; if(fabs(lam3)>eps) return false; if(fabs(1.0-err)>eps) return false; type = ClassifyOverlappingIntersection( alpha, beta ); return true; } bool IsInsideTrig( const array,3> & t, Point<2> r ) { int w = 0; Point<2> trig[4] = {t[0],t[1],t[2],t[0]}; for(auto i : Range(3)) w += CalcSide(trig[i], trig[i+1], r); return ( (w % 2) != 0 ); } bool IsCloseToTrig( const array,3> & t, Point<2> r, double eps=1e-4 ) { r += eps * (Center(t[0], t[1], t[2])-r); // move point a bit to center of trig return IsInsideTrig( t, r ); } bool IsLeft( const Spline & s, Point<2> p ) { Point<2> a = s.StartPI(); Point<2> b = s.TangentPoint(); Point<2> c = s.EndPI(); // simple check by approximating spline with segment bool is_left = Area(p, a, c) > 0.0; // not close to spline -> simple check valid if(!IsCloseToTrig( {a, b, c} , p )) return is_left; // p is control point -> simple check valid auto bp = p-b; if(bp.Length2() < EPSILON) return is_left; double sab = Area(p, a, b); double sbc = Area(p, b, c); if(fabs(sab) same side of spline as control point, simple test gives correct result // weight decreases -> opposite side of spline as control point, adding control point to test polygon gives correct result double old_weight = s.GetWeight(); auto s_tmp = s; ComputeWeight( s_tmp, p ); double new_weight = s_tmp.GetWeight(); if(new_weight>old_weight) return is_left; double sabc = Area(a, b, c); if (sabc > 0) { // chain makes a left turn if (sab > 0 && sbc > 0) return true; else return false; } else { // chain makes a right turn (or is straight) if (sab < 0 && sbc < 0) return false; else return true; } } IntersectionType IntersectTrig( Point<2> p0, Point<2> p1, const array,3> & trig) { Point<2> lt[4] = { trig[0], trig[1], trig[2], trig[0] }; double alpha, beta; for(auto i : IntRange(3)) { auto type = intersect(p0, p1, lt[i], lt[i+1], alpha, beta); if(type != NO_INTERSECTION) return type; } return NO_INTERSECTION; } bool IntersectTrigs( const array,3> & trig0, const array,3> & trig1) { Point<2> lt0[4] = { trig0[0], trig0[1], trig0[2], trig0[0] }; for(auto i : IntRange(3)) { if(IntersectTrig(lt0[i], lt0[i+1], trig1)) return true; if(IsInsideTrig(trig0, trig1[i])) return true; if(IsInsideTrig(trig1, trig0[i])) return true; } return false; } bool BisectIntersect( Spline p, Spline s, double &t0, double &t1, double &s0, double &s1, int depth=-50) { if(depth==0) { s0 = s1; t0 = t1; return true; } bool side = depth%2==0; double & lam0 = side ? t0 : s0; double & lam1 = side ? t1 : s1; Spline & spline = side ? p : s; Spline & spline_other = side ? s : p; double lam_mid = 0.5*(lam0+lam1); auto left = Split(spline, lam0, lam_mid); auto right = Split(spline, lam_mid, lam1); double & lam0_other = side ? s0 : t0; double & lam1_other = side ? s1 : t1; auto curr = Split(spline_other, lam0_other, lam1_other); bool left_hull_intersecting = IntersectTrigs( {left.StartPI(), left.TangentPoint(), left.EndPI()}, {curr.StartPI(), curr.TangentPoint(), curr.EndPI()}); bool right_hull_intersecting = IntersectTrigs( {right.StartPI(), right.TangentPoint(), right.EndPI()}, {curr.StartPI(), curr.TangentPoint(), curr.EndPI()}); // TODO: Additionally check if one spline intersects with convex hull of other? // // Check if one spline intersects with convex hull of spline // if(left_hull_intersecting) // { // double a,b; // left_hull_intersecting = left.Intersect( curr.p0, curr.p1, a, b ); // left_hull_intersecting |= left.Intersect( curr.p1, curr.p2, a, b ); // left_hull_intersecting |= left.Intersect( curr.p2, curr.p0, a, b ); // } // // if(right_hull_intersecting) // { // double a,b; // right_hull_intersecting = right.Intersect( curr.p0, curr.p1, a, b ); // right_hull_intersecting |= right.Intersect( curr.p1, curr.p2, a, b ); // right_hull_intersecting |= right.Intersect( curr.p2, curr.p0, a, b ); // } if(!left_hull_intersecting && !right_hull_intersecting) return false; if(left_hull_intersecting && right_hull_intersecting) { // cout << "intersect both sides " << endl; double temp_lam; temp_lam = lam1; lam1 = lam_mid; double t0_ = t0; double t1_ = t1; double s0_ = s0; double s1_ = s1; // cout << "recursive bisect " << t0 << ',' << t1 << ',' << s0 << ',' << s1 << endl; bool first_intersecting = BisectIntersect(p, s, t0_, t1_, s0_, s1_, depth+1); if(first_intersecting) { t0 = t0_; t1 = t1_; s0 = s0_; s1 = s1_; return true; } else { // cout << "search other side " << endl; // no first intersection -> search other side lam1 = temp_lam; left_hull_intersecting = false; } } if(left_hull_intersecting) lam1 = lam_mid; else lam0 = lam_mid; return BisectIntersect(p, s, t0, t1, s0, s1, depth+1); } bool NewtonIntersect( Spline p, Spline s, double & alpha, double & beta ) { Point<2> p0, s0; Vec<2> dp, ds, ddp, dds; p.GetDerivatives(alpha, p0, dp, ddp); s.GetDerivatives(beta, s0, ds, dds); netgen::Mat<2,2> m, minv; m(0,0) = dp[0]; m(1,0) = dp[1]; m(0,1) = -ds[0]; m(1,1) = -ds[1]; CalcInverse(m, minv); Vec<2> res = s0-p0; Vec<2> h = minv*res; alpha +=h[0]; beta +=h[1]; return true; } IntersectionType Intersect( Spline p, Spline s, double &alpha, double &beta) { bool is_convex_hull_intersecting = IntersectTrigs( {p.StartPI(), p.TangentPoint(), p.EndPI()}, {s.StartPI(), s.TangentPoint(), s.EndPI()}); if(!is_convex_hull_intersecting) return NO_INTERSECTION; { // Check if splines overlap double alpha_ = alpha; double beta_ = beta; IntersectionType overlap_type; bool have_overlap = IsOverlapping( p, s, alpha_, beta_, overlap_type ); if(have_overlap) { alpha = alpha_; beta = beta_; return overlap_type; } } // Bisection double t1 = 1.0; double s1 = 1.0; bool have_intersection = false; if(alpha>0.0) // alpha > 0 means, we have found one intersection already { // reverse parametrization of first spline to make sure, we find the second intersection first auto p_ = Spline{p.EndPI(), p.TangentPoint(), p.StartPI(), p.GetWeight()}; t1 = 1.0-alpha; alpha = 0.0; beta = 0.0; have_intersection = BisectIntersect(p_,s,alpha,t1,beta,s1); alpha = 1.0-alpha; } else have_intersection = BisectIntersect(p,s,alpha,t1,beta,s1); if(have_intersection) { for([[maybe_unused]] auto i : IntRange(10)) NewtonIntersect(p, s, alpha, beta); return ClassifyNonOverlappingIntersection( alpha, beta ); } return NO_INTERSECTION; } IntersectionType intersect(const Edge& edgeP, const Edge& edgeQ, double& alpha, double& beta) { const Point<2>& P1 = *edgeP.v0; const Point<2>& P2 = *edgeP.v1; const Point<2>& Q1 = *edgeQ.v0; const Point<2>& Q2 = *edgeQ.v1; if(edgeP.v0->spline) { if(edgeQ.v0->spline) return Intersect(*edgeP.v0->spline, *edgeQ.v0->spline, alpha, beta); else return IntersectSplineSegment(*edgeP.v0->spline, Q1, Q2, alpha, beta); } else { if(edgeQ.v0->spline) return IntersectSplineSegment1(*edgeQ.v0->spline, P1, P2, alpha, beta); else return intersect(P1, P2, Q1, Q2, alpha, beta); } } void AddIntersectionPoint(Edge edgeP, Edge edgeQ, IntersectionType i, double alpha, double beta) { Point<2> I; Vertex* I_P; Vertex* I_Q; Vertex* P1 = edgeP.v0; Vertex* Q1 = edgeQ.v0; switch(i) { case X_INTERSECTION: if(edgeP.v0->spline) I = edgeP.v0->spline->GetPoint(alpha); else I = *edgeP.v0 + alpha*(*edgeP.v1 - *edgeP.v0); I_P = edgeP.v0->Insert(I, alpha); I_Q = edgeQ.v0->Insert(I, beta); I_P->Link(I_Q); break; case X_OVERLAP: I_Q = edgeQ.v0->Insert(*P1, beta); P1->Link( I_Q); I_P = edgeP.v0->Insert(*Q1, alpha); I_P->Link( Q1); break; case T_INTERSECTION_Q: case T_OVERLAP_Q: I_Q = edgeQ.v0->Insert(*P1, beta); P1->Link( I_Q); break; case T_INTERSECTION_P: case T_OVERLAP_P: I_P = edgeP.v0->Insert(*Q1, alpha); I_P->Link( Q1); break; case V_INTERSECTION: case V_OVERLAP: P1->Link(Q1); break; default: break; } } void RemoveDuplicates(Loop & poly) { if(poly.first==nullptr) return; Vertex * last = poly.first->prev; for(auto v : poly.Vertices(ALL)) { if(Dist2(*v, *last)spline) continue; Spline ori{*v->spline}; Vertex * curr = v; do { auto next = curr->next; if(!curr->is_source || !next->is_source) { double t0 = curr->is_source ? 0.0 : curr->lam; double t1 = next->is_source ? 1.0 : next->lam; curr->spline = Split(ori, t0, t1); curr->lam = -1; curr->is_source = true; } curr = next; } while(!curr->is_source); }; RemoveDuplicates(l); } void ComputeIntersections(Edge edgeP , Loop & l2) { for (Edge edgeQ : l2.Edges(SOURCE)) { double alpha = -EPSILON; double beta = -EPSILON; IntersectionType i = intersect(edgeP, edgeQ, alpha, beta); AddIntersectionPoint(edgeP, edgeQ, i, alpha, beta); if(i==X_INTERSECTION && (edgeP.v0->spline || edgeQ.v0->spline)) { double alpha1 = alpha+1e2*EPSILON; double beta1 = 0.0; //beta+1e2*EPSILON; // search for possible second intersection i = intersect(edgeP, edgeQ, alpha1, beta1); if(i!=NO_INTERSECTION && alpha+EPSILON MP; if(edgeP.v0->spline) { MP = edgeP.v0->spline->GetPoint(alpha_mid); edgeP.v0->Insert(MP, alpha_mid); } else MP = edgeQ.v0->spline->GetPoint(beta_mid); if(edgeQ.v0->spline) edgeQ.v0->Insert(MP, beta_mid); AddIntersectionPoint(edgeP, edgeQ, i, alpha1, beta1); } } } } void ComputeIntersections(Loop & l1, Loop & l2) { static Timer t_intersect("find intersections"); static Timer t_split("split splines"); t_intersect.Start(); for (Edge edgeP : l1.Edges(SOURCE)) ComputeIntersections(edgeP, l2); t_intersect.Stop(); RegionTimer rt_split(t_split); SplitSplines(l1); SplitSplines(l2); } void ComputeIntersections(Solid2d & s1, Solid2d & s2) { static Timer tall("ComputeIntersections"); RegionTimer rtall(tall); for (Loop& l1 : s1.polys) for (Edge edgeP : l1.Edges(SOURCE)) for (Loop& l2 : s2.polys) ComputeIntersections(edgeP, l2); for (Loop& l1 : s1.polys) SplitSplines(l1); for (Loop& l2 : s2.polys) SplitSplines(l2); } enum RelativePositionType { LEFT, RIGHT, IS_P_m, IS_P_p }; inline RelativePositionType oracle_decide( double s1, double s2, double s3 ) { if (s3 > 0) { // chain makes a left turn if (s1 > 0 && s2 > 0) return(LEFT); else return(RIGHT); } else { // chain makes a right turn (or is straight) if (s1 < 0 && s2 < 0) return(RIGHT); else return(LEFT); } } // no splines involved here // decides if Point q is left or right of chain (p1,p2,p3) RelativePositionType oracle_simple(Point<2> q, Point<2> p1, Point<2> p2, Point<2> p3) { double s1 = Area( q, p1, p2); double s2 = Area( q, p2, p3); double s3 = Area( p1, p2, p3); // check relative position of q with respect to chain (p1,p2,p3) return oracle_decide(s1, s2, s3); } // (p1,p2) or (p2,p3) is a spline segment, compare with tangent (p1t,p2) instead of Segment (p1,p2) // BUT take care if tangent is collinear with (q,p2) (then use the segment (p1,p2) again) RelativePositionType oracle_spline_p(Point<2> q, Point<2> p1, Point<2> p1t, Point<2> p2, Point<2> p3, Point<2> p3t) { double s1 = Area( q, p1t, p2); double s2 = Area( q, p2, p3t); if(fabs(s1) < EPSILON) { p1t = p1; s1 = Area( q, p1t, p2 ); } if(fabs(s2) < EPSILON) { p3t = p3; s2 = Area( q, p2, p3t ); } double s3 = Area( p1t, p2, p3t); return oracle_decide(s1, s2, s3); } // (q,p2) is a spline segment, compare with tangent (qt,p2) instead of Segment (q,p2) // BUT take care if tangent at p2 is collinear with either (p1,p2) or (p2,p3) (then use the segment (q,p2) again) RelativePositionType oracle_spline_q(Point<2> q, Point<2> qt, Point<2> p1, Point<2> p2, Point<2> p3) { double s1 = Area( qt, p1, p2); double s2 = Area( qt, p2, p3); double s3 = Area( p1, p2, p3); if(fabs(s1) < EPSILON) s1 = Area( q, p1, p2 ); if(fabs(s2) < EPSILON) s2 = Area( q, p2, p3 ); return oracle_decide(s1, s2, s3); } // splines at (Q,P2) and either (P1,P2) or (P2,P3) // first use tangents to decide local orientation // if tangents of two splines match, use IsLeft(spline, other end point) // if tangent of spline and segment match, use simple methond (just end points) RelativePositionType oracle_spline(bool prev, Vertex *Q, Vertex *P1, Vertex *P2, Vertex *P3) { Point<2> p1t = *P1; Point<2> p3t = *P3; auto sq = prev ? Q->spline : Q->prev->spline; auto qt = sq->TangentPoint(); if(P1->spline) p1t = P1->spline->TangentPoint(); if(P2->spline) p3t = P2->spline->TangentPoint(); // Check using tangent directions first double s1 = Area( qt, p1t, *P2 ); double s2 = Area( qt, *P2 , p3t); double s3 = Area( p1t, *P2, p3t); // tangents are facing in same direction if(fabs(s1) < EPSILON) { if(P1->spline) s1 = IsLeft(*P1->spline, *Q) ? 1 : -1; else s1 = Area( *Q, *P1, *P2 ); } // tangents are facing in same direction if(fabs(s2) < EPSILON) { if(P2->spline) s2 = IsLeft(*P2->spline, *Q) ? 1 : -1; else s2 = Area( *Q, *P2, *P3 ); } return oracle_decide(s1, s2, s3); } RelativePositionType oracle(bool prev, Vertex* P2) { auto Q = prev ? P2->neighbour->prev : P2->neighbour->next; auto sq = prev ? Q->spline : Q->prev->spline; Vertex* P1 = P2->prev; Vertex* P3 = P2->next; // is Q linked to P1 ? if ( P1->is_intersection && (P1->neighbour == Q) ) return(IS_P_m); // is Q linked to P2 ? if ( P3->is_intersection && (P3->neighbour == Q) ) return(IS_P_p); // no splines -> simple variant if(!P1->spline && !P2->spline && !Q->spline) return oracle_simple(*Q, *P1, *P2, *P3); Point<2> qt=*Q, p1t=*P1, p3t=*P3; // splines -> also consider tangent points if( sq) qt = Q->spline->TangentPoint(); if(P1->spline) p1t = P1->spline->TangentPoint(); if(P2->spline) p3t = P2->spline->TangentPoint(); // only spline at Q if(!P1->spline && !P2->spline && Q->spline) return oracle_spline_q(*Q, qt, *P1, *P2, *P3); // only spline at P if((P1->spline || !P2->spline) && !Q->spline) return oracle_spline_p(*Q, *P1, p1t, *P2, *P3, p3t); // spline at Q and P1 or P2 return oracle_spline(prev, Q, P1, P2, P3); } void LabelIntersections(Solid2d & sp, Solid2d & sq, Solid2d & sr, bool UNION) { auto & PP = sp.polys; auto & QQ = sq.polys; auto & RR = sr.polys; // 1) initial classification for (Loop& P : PP) for (Vertex* I : P.Vertices(INTERSECTION)) { // determine local configuration at this intersection vertex // check positions of Q- and Q+ relative to (P-, I, P+) RelativePositionType Q_m_type = oracle(true, I); RelativePositionType Q_p_type = oracle(false, I); // check non-overlapping cases if ((Q_m_type == LEFT && Q_p_type == RIGHT) || (Q_m_type == RIGHT && Q_p_type == LEFT )) { I->label = CROSSING; } if ((Q_m_type == LEFT && Q_p_type == LEFT ) || (Q_m_type == RIGHT && Q_p_type == RIGHT)) { I->label = BOUNCING; } // check overlapping cases if ( ( (Q_p_type == IS_P_p) && (Q_m_type == RIGHT) ) || ( (Q_m_type == IS_P_p) && (Q_p_type == RIGHT) ) ) I->label = LEFT_ON; if ( ( (Q_p_type == IS_P_p) && (Q_m_type == LEFT) ) || ( (Q_m_type == IS_P_p) && (Q_p_type == LEFT) ) ) I->label = RIGHT_ON; if ( ( (Q_p_type == IS_P_p) && (Q_m_type == IS_P_m) ) || ( (Q_m_type == IS_P_p) && (Q_p_type == IS_P_m) ) ) I->label = ON_ON; if ( ( (Q_m_type == IS_P_m) && (Q_p_type == RIGHT) ) || ( (Q_p_type == IS_P_m) && (Q_m_type == RIGHT) ) ) I->label = ON_LEFT; if ( ( (Q_m_type == IS_P_m) && (Q_p_type == LEFT) ) || ( (Q_p_type == IS_P_m) && (Q_m_type == LEFT) ) ) I->label = ON_RIGHT; } // 2) classify intersection chains for (Loop& P : PP) for (Vertex* I : P.Vertices(INTERSECTION)) { // start of an intersection chain ? if (I->label == LEFT_ON || I->label == RIGHT_ON) { // remember status of the first chain vertex and vertex itself RelativePositionType x; if (I->label == LEFT_ON) x = LEFT; else x = RIGHT; Vertex* X = I; // proceed to end of intersection chain and mark all visited vertices as NONE do { I->label = NONE; I = I->next; } while (I->label == ON_ON); RelativePositionType y; if (I->label == ON_LEFT) y = LEFT; else y = RIGHT; // determine type of intersection chain IntersectionLabel chainType; if (x != y) chainType = DELAYED_CROSSING; else chainType = DELAYED_BOUNCING; // mark both ends of an intersection chain with chainType (i.e., as DELAYED_*) X->label = chainType; I->label = chainType; } } // 3) copy labels from P to Q // loop over intersection vertices of P for (Loop& P : PP) for (Vertex* I : P.Vertices(INTERSECTION)) I->neighbour->label = I->label; // 3.5) check for special cases set noIntersection[2]; set identical[2]; for (int i=0; i<2; ++i) { Array* P_or_Q = &PP; // if i=0, then do it for P w.r.t. Q Array* Q_or_P = &QQ; if (i==1) { // if i=1, then do it for Q w.r.t. P P_or_Q = &QQ; Q_or_P = &PP; } // loop over all components of P (or Q) for (Loop& P : *P_or_Q) if (P.noCrossingVertex(UNION)) { // P_ has no crossing vertex (but may have bounces or delayed bounces, except for UNION), // hence it does not intersect with Q_or_P noIntersection[i].insert(&P); // remember component, and ignore it later in step 4 // is P identical to some component of and Q_or_P? if (P.allOnOn()) { identical[i].insert(&P); // -> remember for further processing below } else { // is P inside Q_or_P? bool isInside = false; auto p = P.getNonIntersectionPoint(); for (Loop& Q : *Q_or_P) if ( Q.IsInside(p) ) isInside = !isInside; if (isInside ^ UNION) RR.Append(P); // -> add P to the result } } } // handle components of P that are identical to some component of Q for (Loop* P : identical[0]) { // is P a hole? bool P_isHole = false; for (Loop& P_ : PP) if ( ( P_.first.get() != P->first.get() ) && (P_.IsInside(*P->first)) ) P_isHole = !P_isHole; for (Loop* Q : identical[1]) for (Vertex* V : Q->Vertices(ALL)) if (V == P->first->neighbour) { // found Q that matches P // is Q a hole? bool Q_isHole = false; for (Loop& Q_ : QQ) if ( ( Q_.first.get() != Q->first.get() ) && (Q_.IsInside(*Q->first)) ) Q_isHole = !Q_isHole; // if P and Q are both holes or both are not holes if (P_isHole == Q_isHole) RR.Append(*P); // -> add P to the result goto next_P; } next_P: ; } // 4) set entry/exit flags set split[2]; // split vertex candidates for P and Q set crossing[2]; // CROSSING vertex candidates for P and Q for (int i=0; i<2; ++i) { Array* P_or_Q = &PP; // if i=0, then do it for P w.r.t. Q Array* Q_or_P = &QQ; if (i==1) { // if i=1, then do it for Q w.r.t. P P_or_Q = &QQ; Q_or_P = &PP; } // loop over all components of P (or Q) for (Loop& P : *P_or_Q) { // ignore P if it does not intersect with Q_or_P (detected in step 3.5 above) if(noIntersection[i].find(&P) != noIntersection[i].end()) continue; // start at a non-intersection vertex of P Vertex* V = P.getNonIntersectionVertex(); // check if it is inside or outside Q (or P) // and set ENTRY/EXIT status accordingly EntryExitLabel status = ENTRY; for (Loop& Q : *Q_or_P) if (Q.IsInside(*V)) ToggleLabel(status); // starting at V, loop over those vertices of P, that are either // a crossing intersection or marked as ends of an intersection chain bool first_chain_vertex = true; // needed for dealing with crossing chains for (Vertex* I : P.Vertices(INTERSECTION, V)) { // in the case of normal crossings, we... if (I->label == CROSSING) { // mark vertex with current ENTRY/EXIT status I->enex = status; // toggle status from ENTRY to EXIT or vice versa ToggleLabel(status); } // identify split vertex candidates (INTERIOR bouncing vertices) if ( (I->label == BOUNCING) && ((status == EXIT) ^ UNION) ) split[i].insert(I); // // in the case of a delayed crossing chain, we // mark both end points of the chain with the current ENTRY/EXIT status, // toggling the status only at the end last chain vertex, // and, in case of a delayed EXIT crossing, the first vertex // or, in case of a delayed ENTRY crossing, the last vertex, // of the chain as CROSSING // if (I->label == DELAYED_CROSSING) { // mark vertex with current ENTRY/EXIT status I->enex = status; if (first_chain_vertex) { // are we at the first vertex of a delayed crossing chain? if ((status == EXIT) ^ UNION) I->label = CROSSING; // mark first vertex as CROSSING first_chain_vertex = false; } else { // here we are at the last vertex of a delayed crossing chain if ((status == ENTRY) ^ UNION) I->label = CROSSING; // mark last vertex as CROSSING first_chain_vertex = true; // toggle status from ENTRY to EXIT or vice versa (only for last chain vertex) ToggleLabel(status); } } // // in the case of a delayed bouncing chain, we // mark both end points of the chain with the current ENTRY/EXIT status // toggling the status at both end points of the chain, // and, in case of a delayed INTERIOR bouncing, both end points // of the chain as CROSSING candidates // if (I->label == DELAYED_BOUNCING) { // mark vertex with current ENTRY/EXIT status I->enex = status; if (first_chain_vertex) { // are we at the first vertex of a delayed crossing chain? if ((status == EXIT) ^ UNION) crossing[i].insert(I); // mark first EXIT vertex as CROSSING candidate first_chain_vertex = false; } else { // here we are at the last vertex of a delayed crossing chain if ((status == ENTRY) ^ UNION) crossing[i].insert(I); // mark last ENTRY vertex as CROSSING candidate first_chain_vertex = true; } // toggle status from ENTRY to EXIT or vice versa (for first AND last chain vertex) ToggleLabel(status); } } } } // 5) handle split vertex pairs // loop over P's split candidates for (Vertex* I_P : split[0]) { Vertex* I_Q = I_P->neighbour; // check if the neighbour on Q is also a split candidate if (split[1].find(I_Q) != split[1].end()) { // compute areas to compare local orientation Point<2> p_prev = *I_P->prev; if(I_P->prev->spline) p_prev = I_P->prev->spline->TangentPoint(); Point<2> p_next = *I_P->next; if(I_P->spline) p_next = I_P->spline->TangentPoint(); Point<2> q_prev = *I_Q->prev; if(I_Q->prev->spline) q_prev = I_Q->prev->spline->TangentPoint(); Point<2> q_next = *I_Q->next; if(I_Q->spline) q_next = I_Q->spline->TangentPoint(); double sP = Area( p_prev, *I_P, p_next ); double sQ = Area( q_prev, *I_Q, q_next ); // add duplicate vertices to P and Q auto V_P = I_P->Insert(*I_P, I_P->lam); V_P->spline = I_P->spline; V_P->pinfo = I_P->pinfo; auto V_Q = I_Q->Insert(*I_Q, I_Q->lam); V_Q->spline = I_Q->spline; V_Q->pinfo = I_Q->pinfo; // link vertices correctly if (sP*sQ > 0) { // same local orientation I_P->Link( V_Q); I_Q->Link( V_P); } else { // different local orientation V_P->Link( V_Q); } // mark all four vertices correctly if (!UNION) { I_P->enex = EXIT; V_P->enex = ENTRY; I_Q->enex = EXIT; V_Q->enex = ENTRY; } else { I_P->enex = ENTRY; V_P->enex = EXIT; I_Q->enex = ENTRY; V_Q->enex = EXIT; } I_P->label = CROSSING; V_P->label = CROSSING; I_Q->label = CROSSING; V_Q->label = CROSSING; } } // 6) handle CROSSING vertex candidates // loop over P's CROSSING candidates for (Vertex* I_P : crossing[0]) { Vertex* I_Q = I_P->neighbour; // check if the neighbour on Q is also a CROSSING candidate if (crossing[1].find(I_Q) != crossing[1].end()) { // mark CROSSING candidate pair as such I_P->label = CROSSING; I_Q->label = CROSSING; } } } void CreateResult(Solid2d & sp, Solid2d & sr, bool UNION) { auto & PP = sp.polys; auto & RR = sr.polys; // // for all crossing vertices // // NOTE: all crossing vertices that are visited while constructing a // component of the result polygon are marked as "not intersection", // so that they cannot serve as start vertex of another component // for (Loop& P : PP) { for (Vertex* I : P.Vertices(CROSSING_INTERSECTION)) { Loop R; // result polygon component Vertex* V = I; // start traversal at I V->is_intersection = false; // mark visited vertices do { EntryExitLabel status = V->enex; ToggleLabel(status); while ( !(V->enex == status)) // ... we arrive at a vertex with opposite entry/exit flag, or { auto & vnew = R.AppendVertex(*V); if ((status == EXIT) ^ UNION) { vnew.info = V->info; vnew.pinfo = V->pinfo; if(V->spline) vnew.spline = *V->spline; else vnew.spline = nullopt; V = V->next; // move forward from an ENTRY vertex to the next EXIT vertex V->is_intersection = false; // mark visited vertices } else { V = V->prev; // move backward from an EXIT vertex to the next ENTRY vertex if(V->spline) { auto & s = *V->spline; vnew.spline = Spline{s.EndPI(), s.TangentPoint(), s.StartPI(), s.GetWeight()}; } else vnew.spline = nullopt; vnew.info = V->info; vnew.pinfo = V->pinfo; V->is_intersection = false; // mark visited vertices } if(V == I) break; } if (V != I) { V = V->neighbour; // switch from P to Q or vice versa V->is_intersection = false; // mark visited vertices } } while (V != I); // the result polygon component is complete, // if we are back to the initial vertex I RR.Append(R); } } } // Check if vertex v is not necessary (i.e. is on the line v->prev, v->next and has same info as v->prev and no pinfo bool canRemoveVertex( Vertex * v ) { return false; if(v->spline) return false; if(v->pinfo.name != POINT_NAME_DEFAULT) return false; if(v->pinfo.maxh != MAXH_DEFAULT) return false; if(v->info.bc != v->prev->info.bc || v->info.maxh != v->prev->info.maxh ) return false; if(fabs(Area(*v->prev,*v,*v->next)) >= EPSILON) return false; return true; } void CleanUpResult(Solid2d & sr) { auto & RR = sr.polys; for (Loop& R : RR) { while ( (R.first.get() != NULL) && canRemoveVertex(R.first.get())) R.Remove(R.first.get()); if (R.first.get() != NULL) for (Vertex* V : R.Vertices(ALL)) if (canRemoveVertex(V)) R.Remove(V); } for (int i = RR.Size()-1; i>=0; i--) if(RR[i].Size()==0) RR.RemoveElement(i); } Loop RectanglePoly(double x0, double x1, double y0, double y1, string bc) { Loop r; r.Append( {x0, y0} ); r.Append( {x1, y0} ); r.Append( {x1, y1} ); r.Append( {x0, y1} ); r.SetBC(bc); return r; } Solid2d Rectangle(Point<2> p0, Point<2> p1, string name, string bc) { using P = Point<2>; return { {p0, P{p1[0],p0[1]}, p1, P{p0[0],p1[1]}}, name, bc }; } Solid2d Circle(Point<2> center, double r, string name, string bc) { double x = center[0]; double y = center[1]; using P = Point<2>; Point<2> p[] = { {x+r, y+0}, {x+0, y+r}, {x-r, y+0}, {x+0, y-r}, }; EdgeInfo cp[] = { P{x+r, y+r}, P{x-r, y+r}, P{x-r, y-r}, P{x+r, y-r} }; return Solid2d( { p[0], cp[0], p[1], cp[1], p[2], cp[2], p[3], cp[3] }, name, bc ); } void AddIntersectionPoints ( Solid2d & s1, Solid2d & s2 ) { ComputeIntersections(s1, s2); RemoveDuplicates(s1); RemoveDuplicates(s2); } void AddIntersectionPoints ( Loop & l1, Loop & l2 ) { ComputeIntersections(l1, l2); RemoveDuplicates(l1); RemoveDuplicates(l2); } Solid2d ClipSolids ( const Solid2d & s1, const Solid2d & s2, char op) { return ClipSolids(Solid2d{s1}, Solid2d{s2}, op); } Solid2d ClipSolids ( const Solid2d & s1, Solid2d && s2, char op) { return ClipSolids(Solid2d{s1}, std::move(s2), op); } Solid2d ClipSolids ( Solid2d && s1, const Solid2d & s2, char op) { return ClipSolids(std::move(s1), Solid2d{s2}, op); } Solid2d ClipSolids ( Solid2d && s1, Solid2d && s2, char op) { static Timer tall("ClipSolids"); RegionTimer rtall(tall); static Timer t0("copy"); static Timer t02("tree"); static Timer t03("search intersections"); static Timer t01("prepare"); static Timer t1("intersection"); static Timer t2("label"); static Timer t3("cut"); static Timer t4("cleanup"); static Timer t6("trivial union"); bool intersect = (op=='*' || op=='-'); Solid2d res; res.name = s1.name; t0.Start(); // Try to quickly handle parts of both solids that cannot intersect with the other one int n1 = s1.polys.Size(); int n2 = s2.polys.Size(); Array res_polys(n1+n2); res_polys.SetSize(0); t02.Start(); auto s1_box = s1.GetBoundingBox(); netgen::BoxTree <2, int> tree1(s1_box); for(auto li : IntRange(n1)) { auto box = s1.polys[li].GetBoundingBox(); tree1.Insert(box, li); } auto s2_box = s2.GetBoundingBox(); netgen::BoxTree <2, int> tree2(s2.GetBoundingBox()); for(auto li : IntRange(n2)) { auto box = s2.polys[li].GetBoundingBox(); tree2.Insert(box, li); } t02.Stop(); t03.Start(); for(auto li : IntRange(n1)) { bool have_intersections = false; auto & poly = s1.polys[li]; auto box = poly.GetBoundingBox(); tree2.GetFirstIntersecting(box.PMin(), box.PMax(), [&] (int li2) { return have_intersections = true; }); if(!have_intersections) { if(op=='+' || op=='-') res_polys.Append(std::move(poly)); else poly.Clear(); } } t03.Stop(); for(auto li: IntRange(n1)) while(s1.polys.Size()>li && s1.polys[li].Size()==0) s1.polys.DeleteElement(li); t03.Start(); for(auto li : IntRange(n2)) { bool have_intersections = false; auto & poly = s2.polys[li]; auto box = poly.GetBoundingBox(); tree1.GetFirstIntersecting(box.PMin(), box.PMax(), [&] (int li2) { return have_intersections = true; }); if(!have_intersections) { if(op=='+') res_polys.Append(std::move(poly)); else poly.Clear(); } } t03.Stop(); for(auto li: IntRange(n2)) while(s2.polys.Size()>li && s2.polys[li].Size()==0) s2.polys.DeleteElement(li); t0.Stop(); if(s1.polys.Size()==0 || s2.polys.Size()==0) { res.polys = std::move(res_polys); return res; } t01.Start(); if(op=='-') { // take complement of s2 by adding loop around everything auto box = s1_box; box.Add(s2_box.PMin()); box.Add(s2_box.PMax()); box.Increase(2); auto pmin = box.PMin(); auto pmax = box.PMax(); s2.Append(RectanglePoly(pmin[0], pmax[0], pmin[1], pmax[1], "JUST_FOR_CLIPPING")); } for(auto & poly : s1.polys) for(auto v : poly.Vertices(ALL)) { v->is_source = true; v->neighbour = nullptr; v->lam = -1.0; v->is_intersection = false; v->label = NONE; v->enex = NEITHER; } for(auto & poly : s2.polys) for(auto v : poly.Vertices(ALL)) { v->is_source = true; v->neighbour = nullptr; v->lam = -1.0; v->is_intersection = false; v->label = NONE; v->enex = NEITHER; } t01.Stop(); t1.Start(); ComputeIntersections(s1, s2); t1.Stop(); t2.Start(); LabelIntersections(s1, s2, res, !intersect); t2.Stop(); t3.Start(); CreateResult(s1, res, !intersect); t3.Stop(); t4.Start(); CleanUpResult(res); RemoveDuplicates(res); t4.Stop(); res.polys.Append(std::move(res_polys)); return res; } Vertex* Loop :: getNonIntersectionVertex() { for (Vertex* v : Vertices(ALL)) if (!v->is_intersection) return(v); // no non-intersection vertex found -> generate and return temporary vertex for (Vertex* v : Vertices(ALL)) // make sure that edge from V to V->next is not collinear with other polygon if ( (v->next->neighbour != v->neighbour->prev) && (v->next->neighbour != v->neighbour->next) ) { // add edge midpoint as temporary vertex if(v->spline) { auto p = v->spline->GetPoint(0.5); auto s = *v->spline; v->spline = Split(s, 0, 0.5); auto vnew = v->Insert(p); vnew->info = v->info; vnew->spline = Split(s, 0.5, 1.0); return vnew; } else { auto p = Center(*v, *v->next); auto vnew = v->Insert(p); vnew->info = v->info; return vnew; } } return(NULL); } bool Loop :: IsInside( Point<2> r ) const { int w = 0; for(auto e : Edges(ALL)) { int w_simple = CalcSide(*e.v0, *e.v1, r); if(!e.v0->spline) w += w_simple; else { auto s = *e.v0->spline; auto s0 = s.StartPI(); auto s1 = s.TangentPoint(); auto s2 = s.EndPI(); if(!IsCloseToTrig( {s0, s1, s2} , r )) w += w_simple; else { // r close to spline, need exact test // idea: compute weight, such that r lies on spline // weight increases -> same side of spline as control point, simple test gives correct result // weight decreases -> opposite side of spline as control point, adding control point to test polygon gives correct result double old_weight = s.GetWeight(); ComputeWeight( s, r ); double new_weight = s.GetWeight(); if(new_weight >= old_weight) w += w_simple; else w += CalcSide(s0, s1, r) + CalcSide(s1, s2, r); } } } return ( (w % 2) != 0 ); } Solid2d :: Solid2d(const Array, EdgeInfo, PointInfo>> & points, string name_, string bc) : name(name_) { Loop l; for (auto & v : points) { if(auto point = std::get_if>(&v)) l.Append(*point, true); if(auto edge_info = std::get_if(&v)) l.first->prev->info.Assign( *edge_info ); if(auto point_info = std::get_if(&v)) l.first->prev->pinfo.Assign(*point_info); } for(auto v : l.Vertices(ALL)) { if(v->info.bc==BC_DEFAULT) v->info.bc = bc; if(v->info.control_point) v->spline = Spline(*v, *v->info.control_point, *v->next); } polys.Append(l); } Solid2d Solid2d :: operator+(const Solid2d & other) const { static Timer t("Solid2d::operator+"); RegionTimer rt(t); return ClipSolids(*this, other, '+'); } Solid2d Solid2d :: operator*(const Solid2d & other) const { static Timer t("Solid2d::operator*"); RegionTimer rt(t); return ClipSolids(*this, other, '*'); } Solid2d Solid2d :: operator-(const Solid2d & other) const { static Timer t("Solid2d::operator-"); RegionTimer rt(t); return ClipSolids(*this, other, '-'); } Solid2d & Solid2d :: operator+=(const Solid2d & other) { static Timer t("Solid2d::operator+="); RegionTimer rt(t); *this = ClipSolids(std::move(*this), other, '+'); return *this; } Solid2d & Solid2d :: operator*=(const Solid2d & other) { *this = ClipSolids(std::move(*this), other, '*'); return *this; } Solid2d & Solid2d :: operator-=(const Solid2d & other) { *this = ClipSolids(std::move(*this), other, '-'); return *this; } Solid2d & Solid2d :: Move( Vec<2> v ) { return Transform( [v](Point<2> p) -> Point<2> { return p+v; } ); } Solid2d & Solid2d :: Scale( double s ) { return Transform( [s](Point<2> p) -> Point<2> { return{p[0]*s, p[1]*s}; } ); } Solid2d & Solid2d :: Scale( Vec<2> s ) { return Transform( [s](Point<2> p) -> Point<2> { return{p[0]*s[0], p[1]*s[1]}; } ); } Solid2d & Solid2d :: RotateRad( double ang, Point<2> center ) { double sina = sin(ang); double cosa = cos(ang); Vec<2> c = { center[0], center[1] }; return Transform( [c, sina, cosa](Point<2> p) -> Point<2> { p -= c; double x = p[0]; double y = p[1]; p[0] = cosa*x-sina*y; p[1] = sina*x+cosa*y; p += c; return p; } ); } bool Solid2d :: IsInside( Point<2> r ) const { int w = 0; for(auto & poly : polys) w += poly.IsInside(r); return ( (w % 2) != 0 ); } bool Loop :: IsLeftInside( const Vertex & p0 ) { auto & p1 = *p0.next; if(p0.spline) { auto s = *p0.spline; auto v = s.GetTangent(0.5); auto n = Vec<2>{-v[1], v[0]}; auto q = s.GetPoint(0.5) + 1e-6*n; return IsInside(q); } auto v = p1-p0; auto n = Vec<2>{-v[1], v[0]}; auto q = p0 + 0.5*v + 1e-6*n; return IsInside(q); } bool Loop :: IsRightInside( const Vertex & p0 ) { auto & p1 = *p0.next; if(p0.spline) { auto s = *p0.spline; auto v = s.GetTangent(0.5); auto n = Vec<2>{v[1], -v[0]}; auto q = s.GetPoint(0.5) + 1e-6*n; return IsInside(q); } auto v = p1-p0; auto n = Vec<2>{v[1], -v[0]}; auto q = p0 + 0.5*v + 1e-6*n; return IsInside(q); } bool Solid2d :: IsLeftInside( const Vertex & p0 ) { auto & p1 = *p0.next; if(p0.spline) { auto s = *p0.spline; auto v = s.GetTangent(0.5); auto n = Vec<2>{-v[1], v[0]}; auto q = s.GetPoint(0.5) + 1e-6*n; return IsInside(q); } auto v = p1-p0; auto n = Vec<2>{-v[1], v[0]}; auto q = p0 + 0.5*v + 1e-6*n; return IsInside(q); } bool Solid2d :: IsRightInside( const Vertex & p0 ) { auto & p1 = *p0.next; if(p0.spline) { auto s = *p0.spline; auto v = s.GetTangent(0.5); auto n = Vec<2>{v[1], -v[0]}; auto q = s.GetPoint(0.5) + 1e-6*n; return IsInside(q); } auto v = p1-p0; auto n = Vec<2>{v[1], -v[0]}; auto q = p0 + 0.5*v + 1e-6*n; return IsInside(q); } netgen::Box<2> Solid2d :: GetBoundingBox() const { static Timer tall("Solid2d::GetBoundingBox"); RegionTimer rtall(tall); netgen::Box<2> box(netgen::Box<2>::EMPTY_BOX); for(auto & poly : polys) { auto pbox = poly.GetBoundingBox(); box.Add(pbox.PMin()); box.Add(pbox.PMax()); } return box; } shared_ptr CSG2d :: GenerateSplineGeometry() { static Timer tall("CSG2d - GenerateSplineGeometry()"); static Timer t_points("add points"); static Timer t_segments_map("build segments map"); static Timer t_is_inside("is inside check"); static Timer t_segments("add segments"); static Timer t_intersections("add intersections"); static Timer t_segtree("seg trees"); RegionTimer rt(tall); struct Seg { int p0; int p1; int left; int right; int bc; int p2; double weight; double maxh = 1e99; }; auto geo = std::make_shared(); std::map, Seg> seg_map; Array bcnames; Array points; // Cut each solid with each other one to add all possible intersection points and have conforming edges from both domains t_intersections.Start(); // First build bounding boxes for each solid to skip non-overlapping pairs netgen::Box<2> box(netgen::Box<2>::EMPTY_BOX); for(auto i : Range(solids)) { auto sbox = solids[i].GetBoundingBox(); box.Add(sbox.PMin()); box.Add(sbox.PMax()); } netgen::BoxTree <2> solid_tree(box); Array> loop_list; for(auto i : Range(solids)) for(auto li : Range(solids[i].polys)) { solid_tree.Insert(solids[i].polys[li].GetBoundingBox(), loop_list.Size()); loop_list.Append(IVec<2>(i, li)); } for(auto i1 : Range(solids)) for(auto li1 : Range(solids[i1].polys)) { auto & poly1 = solids[i1].polys[li1]; auto box = poly1.GetBoundingBox(); solid_tree.GetFirstIntersecting(box.PMin(), box.PMax(), [&] (int ii) { auto i2 = loop_list[ii][0]; auto li2 = loop_list[ii][1]; if(i1 ptree(box); auto getPoint = [&](Point<2> p ) { int res = -1; ptree.GetFirstIntersecting(p, p, [&] (int pi) { res = pi; return true; }); return res; }; t_points.Start(); auto insertPoint = [&](const Vertex& p ) { int pi = getPoint(p); if(pi==-1) { // not found -> insert to tree netgen::GeomPoint<2> gp(p); geo->geompoints.Append(gp); pi = geo->geompoints.Size()-1; ptree.Insert(p,p,geo->geompoints.Size()-1); } geo->geompoints[pi].hmax = min2(geo->geompoints[pi].hmax, p.pinfo.maxh); if(p.pinfo.name != POINT_NAME_DEFAULT) geo->geompoints[pi].name = p.pinfo.name; }; for(auto & s : solids) for(auto & poly : s.polys) for(auto v : poly.Vertices(ALL)) { box.Add(*v); insertPoint(*v); if(v->spline) insertPoint(v->spline->TangentPoint()); } t_points.Stop(); // Generate segments from polygon edges and find left/right domain of each segment t_segments_map.Start(); int dom = 0; int bc = 1; for(auto & s : solids) { dom++; bool is_solid_degenerated = true; // Don't create new domain for degenerated solids for(auto & poly : s.polys) { bool first = true; bool is_poly_left_inside = false; bool is_poly_right_inside = false; for(auto v : poly.Vertices(ALL)) { auto & p0 = *v; auto & p1 = *v->next; auto pi0 = getPoint(p0); auto pi1 = getPoint(p1); int pi2 = -1; double weight = 0.0; if(v->spline) { auto p2 = v->spline->TangentPoint(); pi2 = getPoint(p2); weight = v->spline->GetWeight(); } bool flip = false; if(pi1SetMaterial(dom, s.name); geo->SetDomainMaxh(dom, s.maxh); if(s.layer != 1) geo->SetDomainLayer(dom, s.layer); } else dom--; // degenerated solid, use same domain index again } t_segments_map.Stop(); for(auto bc : Range(bcnames)) geo->SetBCName(bc+1, bcnames[bc]); t_segments.Start(); for(auto const &m : seg_map) { auto ls = m.second; netgen::SplineSegExt * seg; if(ls.p2!=-1) { // spline segment auto * seg3 = new netgen::SplineSeg3<2>( geo->GetPoint(ls.p0), geo->GetPoint(ls.p2), geo->GetPoint(ls.p1), ls.weight ); seg = new netgen::SplineSegExt(*seg3); } else { // line segment auto * l = new netgen::LineSeg<2>(geo->GetPoint(ls.p0), geo->GetPoint(ls.p1)); seg = new netgen::SplineSegExt(*l); } seg->leftdom = ls.left; seg->rightdom = ls.right; seg->bc = ls.bc; seg->reffak = 1; seg->copyfrom = -1; seg->hmax = ls.maxh; seg->hpref_left = 0.; seg->hpref_right = 0.; geo->AppendSegment(seg); } t_segments.Stop(); return geo; } shared_ptr CSG2d :: GenerateMesh(MeshingParameters & mp) { auto geo = GenerateSplineGeometry(); auto mesh = make_shared(); geo->GenerateMesh(mesh, mp); return mesh; } } ================================================ FILE: libsrc/geom2d/csg2d.hpp ================================================ #ifndef NETGEN_CSG2D_HPP_INCLUDED #define NETGEN_CSG2D_HPP_INCLUDED #include #include "geometry2d.hpp" namespace netgen { using namespace std; using namespace ngcore; using netgen::Point; using netgen::Vec; using Spline = SplineSeg3<2>; using netgen::Box; inline double Area(const Point<2>& P, const Point<2>& Q, const Point<2>& R) { return (Q[0]-P[0]) * (R[1]-P[1]) - (Q[1]-P[1]) * (R[0]-P[0]); } // compute weight of spline such that p lies on it void ComputeWeight( Spline & s, Point<2> p ); enum IntersectionType { // types of intersection (detected in the first phase) NO_INTERSECTION = 0, X_INTERSECTION, T_INTERSECTION_Q, T_INTERSECTION_P, V_INTERSECTION, X_OVERLAP, // Q0 -- P1 -- Q1 -- P0 (different direction) T_OVERLAP_Q, // same direction or P inside Q T_OVERLAP_P, // same direction or Q inside P V_OVERLAP // one common point }; enum IntersectionLabel { // for the classification of intersection vertices in the second phase NONE, CROSSING, BOUNCING, LEFT_ON, RIGHT_ON, ON_ON, ON_LEFT, ON_RIGHT, DELAYED_CROSSING, DELAYED_BOUNCING }; enum EntryExitLabel { // for marking intersection vertices as "entry" or "exit" EXIT, ENTRY, NEITHER }; enum IteratorType { SOURCE, INTERSECTION, CROSSING_INTERSECTION, ALL }; inline constexpr const double MAXH_DEFAULT{1e99}; inline const string POINT_NAME_DEFAULT{""}; inline const string BC_DEFAULT{""}; inline const string MAT_DEFAULT{""}; struct EdgeInfo { optional> control_point = nullopt; // for spline segments double maxh = MAXH_DEFAULT; string bc = BC_DEFAULT; EdgeInfo() = default; EdgeInfo(Point<2> p) : control_point(p) {} EdgeInfo(double h) : maxh(h) {} EdgeInfo(string s) : bc(s) {} EdgeInfo(optional> p, double h, string s) : control_point(p), maxh(h), bc(s) {} void Assign( EdgeInfo other ) { if(other.control_point != nullopt) control_point = other.control_point; if(other.bc != BC_DEFAULT) bc = other.bc; if(other.maxh != MAXH_DEFAULT) maxh = min(maxh, other.maxh); } }; struct PointInfo { double maxh = MAXH_DEFAULT; string name = POINT_NAME_DEFAULT; PointInfo() = default; PointInfo(const PointInfo& other) = default; PointInfo(double amaxh) : maxh(amaxh) {} PointInfo(string aname) : name(aname) {} PointInfo(double amaxh, string aname) : maxh(amaxh), name(aname) {} void Assign(const PointInfo& other) { maxh = min(maxh, other.maxh); if(other.name != POINT_NAME_DEFAULT) name = other.name; } }; struct Vertex : Point<2> { Vertex (Point<2> p) : Point<2>(p) {} Vertex (const Vertex & v) : Point<2>(v) { spline = v.spline; info = v.info; pinfo = v.pinfo; is_source = true; } Vertex * prev = nullptr; Vertex * next = nullptr; unique_ptr pnext = nullptr; Vertex * neighbour = nullptr; // same vertex in other polygon (at intersections) double lam = -1.0; bool is_intersection = false; bool is_source = false; IntersectionLabel label = NONE; // type of intersection vertex EntryExitLabel enex = NEITHER; // entry/exit "flag" // In case the edge this - next is curved, store the spline information here optional spline = nullopt; EdgeInfo info; PointInfo pinfo; DLL_HEADER Vertex * Insert(Point<2> p, double lam = -1.0); void Link( Vertex * v ) { neighbour = v; v->neighbour = this; is_intersection = true; v->is_intersection = true; } }; struct VertexIterator { struct iterator { iterator(Vertex* root, IteratorType IterType) : root(root), V(NULL), iterType(IterType) { if (root == NULL) return; if (nextVertex() == NULL) // no (source/intersection) vertex found root = V = NULL; // -> mark iterator as "end" } const iterator& operator++() { nextVertex(); return *this; } Vertex* operator*() { return V; } bool operator!=(const iterator& other) const { return (root != other.root) || (V != other.V); } private: Vertex* root; Vertex* V; IteratorType iterType; // // find the next vertex // if iterType is ALL, then it is just the next vertex // if iterType is SOURCE, then it is the next source vertex // if iterType is INTERSECTION, then it is the next intersection vertex // if iterType is CROSSING_INTERSECTION, then it is the next intersection vertex with CROSSING label // Vertex* nextVertex() { bool nextFound = false; if (V == NULL) { // find first (source/intersection) vertex V = root; switch(iterType) { case ALL: nextFound = true; break; case SOURCE: if (V->is_source) nextFound = true; break; case INTERSECTION: if (V->is_intersection) nextFound = true; break; case CROSSING_INTERSECTION: if (V->is_intersection && (V->label == CROSSING)) nextFound = true; break; } } while (!nextFound) { // find next (source/intersection) vertex switch(iterType) { case ALL: V = V->next; break; case SOURCE: do { V = V->next; } while (!V->is_source && V != root); break; case INTERSECTION: do { V = V->next; } while (!V->is_intersection && V != root); break; case CROSSING_INTERSECTION: do { V = V->next; } while ( ( !V->is_intersection || (V->label != CROSSING) ) && V != root); break; } if (V == root) { // back at the root vertex? root = V = NULL; // -> mark iterator as "end" return(V); } switch(iterType) { case ALL: nextFound = true; break; case SOURCE: if (V->is_source) nextFound = true; break; case INTERSECTION: if (V->is_intersection) nextFound = true; break; case CROSSING_INTERSECTION: if (V->is_intersection && (V->label == CROSSING)) nextFound = true; break; } } return(V); } }; public: VertexIterator() : root(NULL) {}; iterator begin() { return iterator(root, iterType); } iterator end() { return iterator(NULL, iterType); } Vertex* root; IteratorType iterType; }; struct Edge { Vertex * v0 = nullptr; Vertex * v1 = nullptr; Edge (Vertex* v, Vertex* w) : v0(v), v1(w) { }; }; struct EdgeIterator { struct iterator { iterator(Vertex* root, IteratorType IterType) : root(root), one(NULL), two(NULL), iterType(IterType) { if (root == NULL) return; if (nextEdge() == NULL) // no source edge found root = one = two = NULL; // -> mark iterator as "end" } const iterator& operator++() { nextEdge(); return *this; } Edge operator*() { return Edge(one,two); } bool operator!=(const iterator& other) const { return (root != other.root) || (one != other.one) || (two != other.two); } private: Vertex* root; Vertex* one; Vertex* two; IteratorType iterType; // // find the next vertex, starting at curr // if iterType is ALL, then it is just the next vertex // if iterType is SOURCE, then it is the next source vertex // Vertex* nextVertex(Vertex* curr) { if (curr == NULL) return(NULL); switch(iterType) { case ALL: curr = curr->next; break; case SOURCE: do { curr = curr->next; } while (!curr->is_source); break; default: ; } return(curr); } // // find the next edge // Vertex* nextEdge() { if (root == NULL) // empty polygon? return (NULL); if (one == NULL) { // find one (source) vertex one = root; // note: root is always a (source) vertex two = nextVertex(one); if (two == one) // just one (source) vertex return(NULL); // -> no (source) edges return(one); } if (two == root) { // back at the root vertex? root = one = two = NULL; // -> mark iterator as "end" return(NULL); } one = two; two = nextVertex(one); return (one); } }; public: EdgeIterator() : root(NULL) {}; iterator begin() { return iterator(root, iterType); } iterator end() { return iterator(NULL, iterType); } Vertex* root; IteratorType iterType; }; inline int CalcSide( const Point<2> & p0, const Point<2> & p1, const Point<2> & r ) { if ( (p0[1] < r[1]) != (p1[1] < r[1]) ) { if (p0[0] >= r[0]) { if (p1[0] > r[0]) return 2 * (p1[1] > p0[1]) - 1; else if ( (Area(p0,p1,r) > 0) == (p1[1] > p0[1]) ) return 2 * (p1[1] > p0[1]) - 1; } else { if (p1[0] > r[0]) if ( (Area(p0,p1,r) > 0) == (p1[1] > p0[1]) ) return 2 * (p1[1] > p0[1]) - 1; } } return 0; } struct Loop { unique_ptr first = nullptr; unique_ptr> bbox = nullptr; Loop() = default; Loop(const Loop & p) : first(nullptr) { for(auto v : p.Vertices(ALL)) AppendVertex(*v); } Loop(Loop && p) = default; Loop & operator=(Loop && p) = default; Loop & operator=(const Loop & p) { // static Timer t("Loop::operator="); RegionTimer rt(t); first = nullptr; if(p.first) { size_t n = p.Size(); Array> new_verts(n); { size_t i = 0; for(const auto v : p.Vertices(ALL)) new_verts[i++] = make_unique(*v); } for(auto i : IntRange(n-1)) { Vertex * v = new_verts[i].get(); Vertex * vn = new_verts[i+1].get(); v->next = vn; vn->prev = v; } Vertex * vfirst = new_verts[0].get(); Vertex * vlast = new_verts[n-1].get(); vfirst->prev = vlast; vlast->next = vfirst; for(auto i : IntRange(1,n)) new_verts[n-1-i]->pnext = std::move(new_verts[n-i]); first = std::move(new_verts[0]); } bbox = nullptr; return *this; } void Clear() { first = nullptr; } Vertex & AppendVertex(const Vertex & v) { auto & vnew = Append( static_cast>(v), true ); vnew.info = v.info; vnew.pinfo = v.pinfo; if(v.spline) vnew.spline = *v.spline; if(bbox) bbox->Add(v); return vnew; } Vertex & Append(Point<2> p, bool source = false) { Vertex * vnew; if(first==nullptr) { first = make_unique(p); first->next = first.get(); first->prev = first.get(); vnew = first.get(); } else { vnew = first->prev->Insert(p); } vnew->is_source = source; // cout << "size after " << Size() << endl; if(bbox) bbox->Add(p); return *vnew; } void Remove (Vertex* v) { v->prev->next = v->next; v->next->prev = v->prev; if(first.get() == v) first = std::move(v->pnext); else v->prev->pnext = std::move(v->pnext); bbox.reset(); } bool IsInside( Point<2> r ) const; bool IsLeftInside( const Vertex & p0 ); bool IsRightInside( const Vertex & p0 ); EdgeIterator Edges(IteratorType iterType) const { EdgeIterator it; it.iterType = iterType; it.root = first.get(); return it; } VertexIterator Vertices(IteratorType iterType, Vertex* first_ = nullptr) const { VertexIterator it; it.iterType = iterType; it.root = (first_ == nullptr) ? first.get() : first_; return it; } // // check, if all vertices have the ON_ON label // bool allOnOn() { for (Vertex* v : Vertices(ALL)) if (v->label != ON_ON) return(false); return(true); } // // check, if the polygon does not contain any crossing intersection vertex // or crossing intersection chain or (if we want to compute the union instead // of the intersection) a bouncing vertex or a bouncing intersection chain // bool noCrossingVertex(bool union_case = false) { for (Vertex* v : Vertices(ALL)) if (v->is_intersection) { if ( (v->label == CROSSING) || (v->label == DELAYED_CROSSING) ) return(false); if (union_case && ( (v->label == BOUNCING) || (v->label == DELAYED_BOUNCING) ) ) return(false); } return(true); } // // return a non-intersection point // Point<2> getNonIntersectionPoint() { for (Vertex* v : Vertices(ALL)) if (!v->is_intersection) return *v; // no non-intersection vertex found -> find suitable edge midpoint for (Vertex* v : Vertices(ALL)) // make sure that edge from V to V->next is not collinear with other polygon if ( (v->next->neighbour != v->neighbour->prev) && (v->next->neighbour != v->neighbour->next) ) // return edge midpoint return Center(*v, *v->next); throw Exception("no point found"); } // // return and insert a non-intersection vertex // Vertex* getNonIntersectionVertex(); void SetBC(string bc) { for(auto v : Vertices(ALL)) v->info.bc = bc; } size_t Size() const { if(first==nullptr) return 0; size_t cnt = 0; for([[maybe_unused]] auto v : Vertices(ALL)) cnt++; return cnt; } const Box<2> & GetBoundingBox() { if(bbox==nullptr) { static Timer tall("Loop::GetBoundingBox"); RegionTimer rt(tall); bbox = make_unique>(Box<2>::EMPTY_BOX); for(auto v : Vertices(ALL)) { bbox->Add(*v); if(v->spline) bbox->Add(v->spline->TangentPoint()); } } return *bbox; } }; struct Solid2d { Array polys; int layer = 1; string name = MAT_DEFAULT; double maxh = MAXH_DEFAULT; Solid2d() = default; Solid2d(string name_) : name(name_) {} DLL_HEADER Solid2d(const Array, EdgeInfo, PointInfo>> & points, string name_=MAT_DEFAULT, string bc_=BC_DEFAULT); Solid2d(Solid2d && other) = default; Solid2d(const Solid2d & other) = default; DLL_HEADER Solid2d operator+(const Solid2d & other) const; DLL_HEADER Solid2d operator*(const Solid2d & other) const; DLL_HEADER Solid2d operator-(const Solid2d & other) const; Solid2d& operator=(Solid2d && other) = default; Solid2d& operator=(const Solid2d & other) = default; DLL_HEADER Solid2d& operator+=(const Solid2d & other); DLL_HEADER Solid2d& operator*=(const Solid2d & other); DLL_HEADER Solid2d& operator-=(const Solid2d & other); void Append( const Loop & poly ) { polys.Append(poly); } bool IsInside( Point<2> r ) const; bool IsLeftInside( const Vertex & p0 ); bool IsRightInside( const Vertex & p0 ); template Solid2d & Transform( const TFunc & func ) { for(auto & poly : polys) for(auto v : poly.Vertices(ALL)) { auto p = func(*v); (*v)[0] = p[0]; (*v)[1] = p[1]; if(v->spline) { auto &s = *v->spline; auto pmid = func(s.GetPoint(0.5)); s = Spline(func(s.StartPI()), func(s.TangentPoint()), func(s.EndPI())); ComputeWeight(s, pmid); } } return *this; } Solid2d & Move( Vec<2> v ); Solid2d & Scale( double s ); Solid2d & Scale( Vec<2> s ); Solid2d & RotateRad( double ang, Point<2> center = {0,0} ); Solid2d & RotateDeg( double ang, Point<2> center = {0,0} ) { return RotateRad( ang/180.*M_PI, center ); } Solid2d & BC(string bc) { for(auto & p : polys) for(auto v : p.Vertices(ALL)) v->info.bc = bc; return *this; } Solid2d & Maxh(double maxh) { this->maxh = maxh; for(auto & p : polys) for(auto v : p.Vertices(ALL)) v->info.maxh = maxh; return *this; } Solid2d & Mat(string mat) { name = mat; return *this; } Solid2d & Layer(int layer_) { layer = layer_; return *this; } Box<2> GetBoundingBox() const; }; class CSG2d { public: Array solids; void Add ( Solid2d s ) { solids.Append(s); } DLL_HEADER shared_ptr GenerateSplineGeometry(); DLL_HEADER shared_ptr GenerateMesh(MeshingParameters & mp); }; DLL_HEADER Solid2d Circle( Point<2> center, double r, string name="", string bc=""); DLL_HEADER Solid2d Rectangle( Point<2> p0, Point<2> p1, string mat=MAT_DEFAULT, string bc=BC_DEFAULT ); DLL_HEADER void AddIntersectionPoints ( Solid2d & s1, Solid2d & s2 ); DLL_HEADER Solid2d ClipSolids ( const Solid2d & s1, const Solid2d & s2, char op); DLL_HEADER Solid2d ClipSolids ( const Solid2d & s1, Solid2d && s2, char op); DLL_HEADER Solid2d ClipSolids ( Solid2d && s1, const Solid2d & s2, char op); DLL_HEADER Solid2d ClipSolids ( Solid2d && s1, Solid2d && s2, char op); DLL_HEADER IntersectionType intersect(const Point<2> P1, const Point<2> P2, const Point<2> Q1, const Point<2> Q2, double& alpha, double& beta); } #endif // NETGEN_CSG2D_HPP_INCLUDED ================================================ FILE: libsrc/geom2d/genmesh2d.cpp ================================================ #include #include namespace netgen { // extern DLL_HEADER MeshingParameters mparam; extern void Optimize2d (Mesh & mesh, MeshingParameters & mp, int faceindex=0); void CalcPartition (const SplineSegExt & spline, // double l, MeshingParameters & mp, Mesh & mesh, // double h, double h1, double h2, double hcurve, double elto0, NgArray & points) { double fperel, oldf, f; int n = 1; NgArray > xi; NgArray hi; // do one extra step int not_fine_enough = 2; while(not_fine_enough && n < 10000) { not_fine_enough--; n*=4; xi.SetSize(n); hi.SetSize(n); for (int i = 0; i < n; i++) { xi[i] = spline.GetPoint ( (i+0.5) / n ); hi[i] = mesh.GetH (Point<3> (xi[i](0), xi[i](1), 0)); } // limit slope double gradh = min(1/elto0,mp.grading); for (int i = 0; i < n-1; i++) { double hnext = hi[i] + gradh * (xi[i+1]-xi[i]).Length(); if(hnext > 2*hi[i]) not_fine_enough = 2; hi[i+1] = min(hi[i+1], hnext); } for (int i = n-1; i > 1; i--) { double hnext = hi[i] + gradh * (xi[i-1]-xi[i]).Length(); if(hnext > 2*hi[i]) not_fine_enough = 2; hi[i-1] = min(hi[i-1], hnext); } } points.SetSize (0); double len = spline.Length(); double dt = len / n; double sum = 0; for (int i = 1; i <= n; i++) { // double t = (i-0.5)*dt; double fun = hi[i-1]; sum += dt / fun; } int nel = int (sum+0.5); if (nel == 0) nel = 1; fperel = sum / nel; points.Append (0); int i = 1; oldf = 0; for (int j = 1; j <= n && i < nel; j++) { // double t = (j-0.5)*dt; double fun = hi[j-1]; f = oldf + dt / fun; while (i * fperel < f && i < nel) { points.Append ( dt * (j-1) + (i * fperel - oldf) * fun); i++; } oldf = f; // t += dt; } points.Append (len); } // partitionizes spline curve void Partition (const SplineSegExt & spline, MeshingParameters & mp, double hxxx, double elto0, Mesh & mesh, Point3dTree & searchtree, int segnr) { int n = 100; Point<2> mark, oldmark; NgArray curvepoints; double edgelength, edgelengthold; CalcPartition (spline, mp, mesh, elto0, curvepoints); double dt = 1.0 / n; int j = 1; Point<2> pold = spline.GetPoint (0); double lold = 0; oldmark = pold; edgelengthold = 0; NgArray locsearch; for (int i = 1; i <= n; i++) { Point<2> p = spline.GetPoint (i*dt); double l = lold + Dist (p, pold); while (j < curvepoints.Size() && (l >= curvepoints[j] || i == n)) { double frac = (curvepoints[j]-lold) / (l-lold); edgelength = i*dt + (frac-1)*dt; mark = spline.GetPoint (edgelength); { PointIndex pi1{PointIndex::INVALID}; PointIndex pi2{PointIndex::INVALID}; Point3d mark3(mark(0), mark(1), 0); Point3d oldmark3(oldmark(0), oldmark(1), 0); double h = mesh.GetH (Point<3> (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]; 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 (!pi1.IsValid()) { pi1 = mesh.AddPoint(oldmark3, spline.layer); searchtree.Insert (oldmark3, pi1); } if (!pi2.IsValid()) { pi2 = mesh.AddPoint(mark3, spline.layer); searchtree.Insert (mark3, pi2); } Segment seg; seg.edgenr = segnr; seg.index = spline.bc; 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 (MeshingParameters & mp, double h, Mesh & mesh2d) { enum { D = 2 }; Box 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 (point(0), point(1), 0), point.hmax); for (int i = 0; i < splines.Size(); i++) { const SplineSegExt & spline = GetSpline(i); const GeomPoint<2> & p1 = spline.StartPI(); const GeomPoint<2> & p2 = spline.EndPI(); double h1 = min (p1.hmax, h/p1.refatpoint); mesh2d.RestrictLocalH (Point<3>(p1(0),p1(1),0), h1); double h2 = min (p2.hmax, h/p2.refatpoint); mesh2d.RestrictLocalH (Point<3>(p2(0),p2(1),0), h2); double len = spline.Length(); mesh2d.RestrictLocalHLine (Point<3>(p1(0),p1(1),0), Point<3>(p2(0),p2(1),0), len/mp.segmentsperedge); double hcurve = min (spline.hmax, h/spline.reffak); double hl = GetDomainMaxh (spline.leftdom); if (hl > 0) hcurve = min2 (hcurve, hl); double hr = GetDomainMaxh (spline.rightdom); if (hr > 0) hcurve = min2 (hcurve, hr); // skip curvature restrictions for straight lines if(spline.MaxCurvature()==0) { mesh2d.RestrictLocalHLine (Point<3>(p1(0),p1(1),0), Point<3>(p2(0),p2(1),0), hcurve); } else { int np = 1000; for (double t = 0.5/np; t < 1; t += 1.0/np) { Point<2> x = spline.GetPoint(t); double hc = 1.0/mp.curvaturesafety / (1e-99+spline.CalcCurvature (t)); mesh2d.RestrictLocalH (Point<3> (x(0), x(1), 0), min2(hc, hcurve)); } } } for (auto mspnt : mp.meshsize_points) mesh2d.RestrictLocalH (mspnt.pnt, mspnt.h); // add point elements for (auto & point : geompoints) if (point.name.length()) { Point<3> newp(point(0), point(1), 0); PointIndex npi = mesh2d.AddPoint (newp, 1, FIXEDPOINT); mesh2d.AddLockedPoint(npi); Element0d el(npi, npi); el.name = point.name; mesh2d.SetCD2Name(npi-IndexBASE()+1, point.name); mesh2d.pointelements.Append (el); searchtree.Insert (newp, npi); } // first add all vertices (for compatible orientation on periodic bnds) { double diam2 = Dist2(pmin, pmax); for (int i = 0; i < splines.Size(); i++) for (int j : { 1, 2 }) { Point<2> hnewp = (j == 1) ? splines[i]->StartPI() : splines[i]->EndPI(); Point<3> newp(hnewp(0), hnewp(1), 0); int layer = GetSpline(i).layer; PointIndex npi(PointIndex::INVALID); for (PointIndex pi = IndexBASE(); pi < mesh2d.GetNP()+IndexBASE(); pi++) if (Dist2 (mesh2d.Point(pi), newp) < 1e-12 * diam2 && mesh2d.Point(pi).GetLayer() == layer) npi = pi; if (!npi.IsValid()) { npi = mesh2d.AddPoint (newp, layer); searchtree.Insert (newp, npi); mesh2d.AddLockedPoint(npi); Element0d el(npi, npi-IndexBASE()+1); el.name = ""; mesh2d.SetCD2Name(npi-IndexBASE()+1, ""); mesh2d.pointelements.Append (el); } } } 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 hl = GetDomainMaxh ( GetSpline(i).leftdom ); double hr = GetDomainMaxh ( GetSpline(i).rightdom ); double useh = h; if (hl > 0) useh = min2 (h, hl); if (hr > 0) useh = min2 (h, hr); Partition(GetSpline(i), mp, useh, 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) { Array mappoints (mesh.GetNP()); Array param (mesh.GetNP()); mappoints = PointIndex::INVALID; param = 0; Point3d pmin, pmax; mesh.GetBox (pmin, pmax); double diam2 = Dist2(pmin, pmax); PrintMessage(3, string("Copy edge, from ") + ToString(from) + " to " + ToString(to)); for (const auto& seg : mesh.LineSegments()) { if (seg.edgenr == from) { mappoints[seg[0]] = 1; param[seg[0]] = seg.epgeominfo[0].dist; mappoints[seg[1]] = 1; param[seg[1]] = seg.epgeominfo[1].dist; } } bool mapped = false; for (auto i : Range(mappoints)) { if (mappoints[i].IsValid()) { Point<2> newp = splines.Get(to)->GetPoint (param[i]); Point<3> newp3 (newp(0), newp(1), 0); PointIndex npi = PointIndex::INVALID; for (auto pi : Range(mesh.Points())) if (Dist2 (mesh.Point(pi), newp3) < 1e-12 * diam2) npi = pi; if (!npi.IsValid()) { npi = mesh.AddPoint (newp3); searchtree.Insert (newp3, npi); } mappoints[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 (int 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.index = GetSpline(to-1).bc; // ??? nseg[0] = mappoints[seg[0]]; nseg[1] = mappoints[seg[1]]; nseg.domin = GetSpline(to-1).leftdom; nseg.domout = GetSpline(to-1).rightdom; nseg.epgeominfo[0].edgenr = to; nseg.epgeominfo[0].dist = param[seg[0]]; nseg.epgeominfo[1].edgenr = to; nseg.epgeominfo[1].dist = param[seg[1]]; mesh.AddSegment (nseg); } } } void MeshFromSpline2D (SplineGeometry2d & geometry, shared_ptr & mesh, MeshingParameters & mp) { static Timer tall("MeshFromSpline2D"); RegionTimer rtall(tall); static Timer t_h("SetH"); static Timer t_tensor("tensor domain meshing"); static Timer t_part_boundary("PartitionBoundary"); static Timer t_hpref("mark hpref points"); PrintMessage (1, "Generate Mesh from spline geometry"); Box<2> bbox = geometry.GetBoundingBox (); bbox.Increase (1e-2*bbox.Diam()); t_h.Start(); if (bbox.Diam() < mp.maxh) mp.maxh = bbox.Diam(); // double h = mp.maxh; // mesh = make_shared(); mesh->SetDimension (2); Point3d pmin(bbox.PMin()(0), bbox.PMin()(1), -bbox.Diam()); Point3d pmax(bbox.PMax()(0), bbox.PMax()(1), bbox.Diam()); mesh->SetLocalH (pmin, pmax, mp.grading); mesh->SetGlobalH (mp.maxh); t_part_boundary.Start(); geometry.PartitionBoundary (mp, mp.maxh, *mesh); t_part_boundary.Stop(); PrintMessage (3, "Boundary mesh done, np = ", mesh->GetNP()); t_hpref.Start(); // 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 = IndexBASE(); pi < mesh->GetNP()+IndexBASE(); pi++) if (Dist2(gp3, (*mesh)[pi]) < mindist) { mpi = pi; mindist = Dist2(gp3, (*mesh)[pi]); } (*mesh)[mpi].Singularity(geometry.GetPoint(i).hpref); } t_hpref.Stop(); 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; } TableCreator dom2seg_creator(maxdomnr+1); for ( ; !dom2seg_creator.Done(); dom2seg_creator++) for (const Segment & seg : mesh->LineSegments()) { dom2seg_creator.Add (seg.domin, &seg); if (seg.domin != seg.domout) dom2seg_creator.Add (seg.domout, &seg); } auto dom2seg = dom2seg_creator.MoveTable(); mesh->ClearFaceDescriptors(); for (int i = 1; i <= maxdomnr; i++) mesh->AddFaceDescriptor (FaceDescriptor (i, 0, 0, i)); // set NgArray 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 ) ); mesh->CalcLocalH(mp.grading); t_h.Stop(); int bnp = mesh->GetNP(); // boundary points // auto BndPntRange = mesh->Points().Range(); int hquad = mp.quad; for (int domnr = 1; domnr <= maxdomnr; domnr++) if (geometry.GetDomainTensorMeshing (domnr)) { // tensor product mesh RegionTimer rt(t_tensor); Array nextpi(bnp); Array 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++) for (PointIndex pi : si2.Range()) 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]); NgArray pts ( (nex+1) * (ney+1) ); // x ... inner loop pts = -1; int i = 0; for (PointIndex pi = c1; pi != c2; pi = nextpi[pi], i++) pts[i] = pi; i = 0; for (PointIndex pi = c2; pi != c3; pi = nextpi[pi], i++) pts[(nex+1)*i+nex] = pi; i = 0; for (PointIndex pi = c3; pi != c4; pi = nextpi[pi], i++) pts[(nex+1)*(ney+1)-i-1] = pi; i = 0; for (PointIndex pi = c4; 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++) { Point<3> px = (*mesh)[pix]; for (PointIndex piy = nextpi[c2], iy = 0; piy != c3; piy = nextpi[piy], iy++) { double lam = Dist((*mesh)[piy],(*mesh)[c2]) / Dist((*mesh)[c3],(*mesh)[c2]); auto pix1 = pts[(nex+1)*ney+ix+1]; auto pnew = px + lam*((*mesh)[pix1]-px); pts[(nex+1)*(iy+1) + ix+1] = mesh -> AddPoint (pnew, 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); } char* material; geometry.GetMaterial(domnr, material); if(material) mesh->SetMaterial(domnr, material); } static Timer t_domain("Mesh domain"); static Timer t_points("Mesh domain - find points"); for (int domnr = 1; domnr <= maxdomnr; domnr++) { RegionTimer rt(t_domain); if (geometry.GetDomainTensorMeshing (domnr)) continue; double h = mp.maxh; if ( geometry.GetDomainMaxh ( domnr ) > 0 ) h = geometry.GetDomainMaxh(domnr); PrintMessage (3, "Meshing domain ", domnr, " / ", maxdomnr); int oldnf = mesh->GetNSE(); mp.quad = hquad || geometry.GetDomainQuadMeshing (domnr); Meshing2 meshing (geometry, mp, Box<3> (pmin, pmax)); NgArray compress(mesh->GetNP()); compress = -1; int cnt = 0; t_points.Start(); /* for (SegmentIndex si = 0; si < mesh->GetNSeg(); si++) { const auto & s = (*mesh)[si]; if ( s.domin==domnr || s.domout==domnr ) { for (auto pi : {s[0], s[1]}) { if(compress[pi]==-1) { meshing.AddPoint((*mesh)[pi], pi); cnt++; compress[pi] = cnt; } } } } */ for (const Segment * seg : dom2seg[domnr]) if (seg->domin==domnr || seg->domout==domnr ) for (auto pi : {(*seg)[0], (*seg)[1]}) if (compress[pi]==-1) { 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); } } */ for (const Segment * seg : dom2seg[domnr]) { if (seg->domin == domnr) meshing.AddBoundaryElement (compress[(*seg)[0]], compress[(*seg)[1]], gi, gi); if (seg->domout == domnr) meshing.AddBoundaryElement (compress[(*seg)[1]], compress[(*seg)[0]], gi, gi); } t_points.Stop(); if(mp.delaunay2d && cnt>1) meshing.Delaunay(*mesh, domnr, mp); else { // mp.checkoverlap = 0; auto res = meshing.GenerateMesh (*mesh, mp, h, domnr); if (res != 0) throw NgException("meshing failed"); } 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); } mesh->Compress(); mp.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->OrderElements(); mesh -> SetNextMajorTimeStamp(); mp.Render(); } } ================================================ FILE: libsrc/geom2d/geom2dpkg.cpp ================================================ #include #include #include #include #include "vsgeom2d.hpp" // extern "C" int Ng_CSG_Init (Tcl_Interp * interp); namespace netgen { // extern DLL_HEADER NetgenGeometry * ng_geometry; static VisualSceneGeometry2d vsgeom2d; class SplineGeometryVisRegister : public GeometryRegister { public: virtual NetgenGeometry * Load (const filesystem::path & filename) const { return NULL; } virtual VisualScene * GetVisualScene (const NetgenGeometry * geom) const; }; VisualScene * SplineGeometryVisRegister :: GetVisualScene (const NetgenGeometry * geom) const { const SplineGeometry2d * geometry = dynamic_cast (geom); 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 SplineGeometryVisRegister); return TCL_OK; } ================================================ FILE: libsrc/geom2d/geometry2d.cpp ================================================ /* 2d Spline curve for Mesh generator */ #include #include #include namespace netgen { SplineGeometry2d :: ~SplineGeometry2d() { for ( int i = 0; i < bcnames.Size(); i++ ) delete bcnames[i]; for (int i=0; i & p, EdgePointGeomInfo* gi) const { if (!gi) return; // copied from PointBetween, but should work easier auto spline = GetSplines().Get(gi->edgenr); const SplineSeg3<2> * ss3; const LineSeg<2> * ls; auto ext = dynamic_cast(spline); if(ext) { ss3 = dynamic_cast *>(ext->seg); ls = dynamic_cast *>(ext->seg); } else { ss3 = dynamic_cast *>(spline); ls = dynamic_cast *>(spline); } Point<2> p2d(p(0),p(1)); Point<2> p_proj(0.0,0.0); double t_proj = 0.0; if(ss3) ss3->Project(p2d,p_proj,t_proj); else if(ls) ls->Project(p2d,p_proj,t_proj); p(0) = p_proj(0); p(1) = p_proj(1); gi->dist = t_proj; } void SplineGeometry2d :: PointBetweenEdge(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; double newdist; auto spline = GetSplines().Get(ap1.edgenr); if( (ap1.dist == 0.0) && (ap2.dist == 0.0) ) { // used for manually generated meshes const SplineSeg3<2> * ss3; const LineSeg<2> * ls; auto ext = dynamic_cast(spline); if(ext) { ss3 = dynamic_cast *>(ext->seg); ls = dynamic_cast *>(ext->seg); } else { ss3 = dynamic_cast *>(spline); ls = dynamic_cast *>(spline); } Point<2> p12d(p1(0),p1(1)), p22d(p2(0),p2(1)); Point<2> p1_proj(0.0,0.0), p2_proj(0.0,0.0); double t1_proj = 0.0; double t2_proj = 0.0; if(ss3) { ss3->Project(p12d,p1_proj,t1_proj); ss3->Project(p22d,p2_proj,t2_proj); } else if(ls) { ls->Project(p12d,p1_proj,t1_proj); ls->Project(p22d,p2_proj,t2_proj); } p2d = spline->GetPoint (((1-secpoint)*t1_proj+secpoint*t2_proj)); newdist = (1-secpoint)*t1_proj+secpoint*t2_proj; } else { p2d = spline->GetPoint (((1-secpoint)*ap1.dist+secpoint*ap2.dist)); newdist = (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 = newdist; }; Vec<3> SplineGeometry2d :: GetTangent(const Point<3> & p, int surfi1, int surfi2, const EdgePointGeomInfo & ap1) const { Vec<2> t2d = GetSplines().Get(ap1.edgenr) -> GetTangent(ap1.dist); return Vec<3> (t2d(0), t2d(1), 0); } Vec<3> SplineGeometry2d :: GetNormal(int surfi1, const Point<3> & p, const PointGeomInfo* gi) const { return Vec<3> (0,0,1); } void SplineGeometry2d :: Load (const filesystem::path & filename) { ifstream infile; Point<2> x; char buf[50]; infile.open (filename); if ( ! infile.good() ) throw NgException(string ("Input file '") + filename.string() + 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 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> 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(x, hd)); geompoints.Last().hpref = flags.GetDefineFlag ("hpref"); geompoints.Last().hmax = flags.GetNumFlag("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 * 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 segment if (strcmp (buf, "2") == 0) { // a line infile >> hi1 >> hi2; spline = new LineSeg(geompoints[hi1-1], geompoints[hi2-1]); } else if (strcmp (buf, "3") == 0) { // a rational spline infile >> hi1 >> hi2 >> hi3; spline = new SplineSeg3 (geompoints[hi1-1], geompoints[hi2-1], geompoints[hi3-1]); } else if (strcmp (buf, "4") == 0) { // an arc infile >> hi1 >> hi2 >> hi3; spline = new CircleSeg (geompoints[hi1-1], geompoints[hi2-1], geompoints[hi3-1]); // break; } else if (strcmp (buf, "discretepoints") == 0) { int npts; infile >> npts; NgArray< Point > pts(npts); for (int j = 0; j < npts; j++) for(int k=0; k> pts[j](k); spline = new DiscretePointsSeg (pts); } SplineSegExt * spex = new SplineSegExt (*spline); infile >> spex->reffak; spex -> leftdom = leftdom; spex -> rightdom = rightdom; 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","") ); } spex -> hmax = flags.GetNumFlag("hmax", 1e99); } } void SplineGeometry2d :: LoadDataNew ( ifstream & infile ) { enum { D = 2 }; int nump, numseg, leftdom, rightdom; Point 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> 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(x, hd)); geompoints[pointnr-1] = GeomPoint(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 * 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 segment if (strcmp (buf, "2") == 0) { // a line infile >> hi1 >> hi2; spline = new LineSeg (geompoints[hi1-1], geompoints[hi2-1]); } else if (strcmp (buf, "3") == 0) { // a rational spline infile >> hi1 >> hi2 >> hi3; spline = new SplineSeg3 (geompoints[hi1-1], geompoints[hi2-1], geompoints[hi3-1]); } else if (strcmp (buf, "4") == 0) { // an arc infile >> hi1 >> hi2 >> hi3; spline = new CircleSeg (geompoints[hi1-1], geompoints[hi2-1], geompoints[hi3-1]); // break; } else if (strcmp (buf, "discretepoints") == 0) { int npts; infile >> npts; NgArray< Point > pts(npts); for (int j = 0; j < npts; j++) for(int k=0; k> pts[j](k); spline = new DiscretePointsSeg (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 ) ; maxh = 1e99; TestComment ( infile ); for ( int i=0; i> 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", 1e99); } 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 x; int hi1, hi2, hi3; double hd; char buf[50], ch; int pointnr; string keyword; NgArray < GeomPoint > infilepoints (0); NgArray 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> 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(x, hd)); infilepoints.Append ( GeomPoint(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 * spline = 0; TestComment ( infile ); infile >> leftdom >> rightdom; if ( leftdom > numdomains ) numdomains = leftdom; if ( rightdom > numdomains ) numdomains = rightdom; infile >> buf; // type of spline segment if (strcmp (buf, "2") == 0) { // a line infile >> hi1 >> hi2; spline = new LineSeg(geompoints[hi1-1], geompoints[hi2-1]); } else if (strcmp (buf, "3") == 0) { // a rational spline infile >> hi1 >> hi2 >> hi3; spline = new SplineSeg3 (geompoints[hi1-1], geompoints[hi2-1], geompoints[hi3-1]); } else if (strcmp (buf, "4") == 0) { // an arc infile >> hi1 >> hi2 >> hi3; spline = new CircleSeg (geompoints[hi1-1], geompoints[hi2-1], geompoints[hi3-1]); } else if (strcmp (buf, "discretepoints") == 0) { int npts; infile >> npts; NgArray< Point > pts(npts); for (int j = 0; j < npts; j++) for(int k=0; k> pts[j](k); spline = new DiscretePointsSeg (pts); } else if (strcmp (buf, "bsplinepoints") == 0) { int npts,order; infile >> npts; infile >> order; NgArray< Point > pts(npts); for (int j = 0; j < npts; j++) for(int k=0; k> pts[j](k); if(order<2) cerr<<"Minimum order of 2 is required!!"< (pts); else if(order==3) spline = new BSplineSeg (pts); else if(order==4) spline = new BSplineSeg (pts); else if(order>4) cerr<<"Maximum allowed order is 4!!"<> 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> 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 (const SplineSegExt & spline, double l, double h, double h1, double h2, double hcurve, double elto0, NgArray & points) { double fperel, oldf, f; int n = 1000; points.SetSize (0); double dt = l / n; double sum = 0; for (int i = 1; i <= n; i++) { double t = (i-0.5)*dt; double fun = min3 (hcurve, t/elto0 + h1, (l-t)/elto0 + h2); double curv = spline.CalcCurvature (t/l); cout << "curv = " << curv << endl; if (curv < 1e-10) curv = 1e-10; fun = min2 (fun, 0.1/curv); sum += dt / fun; } int nel = int (sum+1); fperel = sum / nel; points.Append (0); int i = 1; oldf = 0; // t = 0.5 * dt; for (int j = 1; j <= n && i < nel; j++) { double t = (j-0.5)*dt; double fun = min3 (hcurve, t/elto0 + h1, (l-t)/elto0 + h2); double curv = spline.CalcCurvature (t/l); if (curv < 1e-10) curv = 1e-10; fun = min2 (fun, 0.1/curv); f = oldf + dt / fun; while (i * fperel < f && i < nel) { points.Append ( dt * (j-1) + (i * fperel - oldf) * fun); i++; } oldf = f; t += dt; } points.Append (l); } */ void SplineGeometry2d :: SetBCName (int bcnr, string name) { if (bcnr < 1) throw NgException ("Illegal nr in SetBCName"); int new_to_add = bcnr - bcnames.Size(); for (int i = 0; i < new_to_add; i++) bcnames.Append (new string("default")); delete bcnames[bcnr-1]; bcnames[bcnr-1] = new string(name); } string SplineGeometry2d :: GetBCName( int bcnr ) const { if (bcnames.Size() >= bcnr) if (bcnames[bcnr-1] ) return *bcnames[bcnr-1]; return "default"; } string * SplineGeometry2d :: BCNamePtr( int bcnr ) { if ( bcnr > bcnames.Size() ) return nullptr; else return bcnames[bcnr-1]; } int SplineGeometry2d :: GetBCNumber (string name) const { for (int i = 0; i < bcnames.Size(); i++) if (*bcnames[i] == name) return i+1; return 0; } int SplineGeometry2d :: AddBCName (string name) { bcnames.Append (new string(name)); return bcnames.Size(); } void SplineGeometry2d :: GetMaterial (int domnr, char* & material ) { if ( materials.Size() >= domnr) material = materials[domnr-1]; else material = 0; } void SplineGeometry2d :: SetMaterial (int domnr, const string & material) { int oldsize = materials.Size(); if (domnr > materials.Size()) materials.SetSize (domnr); for (int i = oldsize; i < domnr; i++) materials[i] = nullptr; if (domnr >= 1) // && domnr <= materials.Size()) { delete materials[domnr-1]; materials[domnr-1] = new char[material.size()+1]; strcpy(materials[domnr-1], material.c_str()); } else throw NgException ("material index out of range"); } double SplineGeometry2d :: GetDomainMaxh (const int domnr ) { if ( maxh.Size() >= domnr && domnr > 0) return maxh[domnr-1]; else return -1; } void SplineGeometry2d :: SetDomainMaxh (int domnr, double h) { int oldsize = maxh.Size(); if (domnr > maxh.Size()) maxh.SetSize (domnr); for (int i = oldsize; i < domnr; i++) maxh[i] = 1e99; if (domnr >= 1) maxh[domnr-1] = h; else throw NgException ("material index out of range"); } extern void MeshFromSpline2D (SplineGeometry2d & geometry, shared_ptr & mesh, MeshingParameters & mp); int SplineGeometry2d :: GenerateMesh (shared_ptr & mesh, MeshingParameters & mparam) { if(restricted_h.Size()) { // copy so that we don't change mparam outside MeshingParameters mp = mparam; for(const auto& [pnt, maxh] : restricted_h) mp.meshsize_points.Append({pnt, maxh}); MeshFromSpline2D (*this, mesh, mp); } else MeshFromSpline2D (*this, mesh, mparam); return 0; } class SplineGeometryRegister : public GeometryRegister { public: virtual NetgenGeometry * Load (const filesystem::path & filename) const; }; NetgenGeometry * SplineGeometryRegister :: Load (const filesystem::path & filename) const { string ext = ToLower(filename.extension()); if (ext == ".in2d") { PrintMessage (1, "Load 2D-Spline geometry file ", filename); ifstream infile(filename); SplineGeometry2d * hgeom = new SplineGeometry2d(); hgeom -> Load (filename); return hgeom; } return NULL; } class SplineGeoInit { public: SplineGeoInit() { GeometryRegister().Append(new SplineGeometryRegister); } }; SplineGeoInit sginit; static RegisterClassForArchive, NetgenGeometry>> regspg2; static RegisterClassForArchive> regssext; } ================================================ FILE: libsrc/geom2d/geometry2d.hpp ================================================ #ifndef FILE_GEOMETRY2D #define FILE_GEOMETRY2D /* *************************************************************************/ /* File: geometry2d.hpp */ /* Author: Joachim Schoeberl */ /* Date: 20. Jul. 02 */ /* *************************************************************************/ #include #include #include // #include "../gprim/spline.hpp" // #include "../gprim/splinegeometry.hpp" namespace netgen { class SplineSegExt : public SplineSeg<2> { public: 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; /// perform anisotropic refinement (hp-refinement) to edge double hpref_left; /// perform anisotropic refinement (hp-refinement) to edge double hpref_right; /// int layer; SplineSegExt (SplineSeg<2> & hseg) : seg(&hseg) { layer = 1; } // default constructor for archive SplineSegExt() {} ~SplineSegExt () { delete seg; } virtual void DoArchive(Archive& ar) { ar & seg & leftdom & rightdom & reffak & hmax & bc & copyfrom & hpref_left & hpref_right & layer; } 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, NgArray > & points) const { seg->GetPoints (n, points); } virtual double MaxCurvature () const { return seg->MaxCurvature(); } virtual string GetType () const { return seg->GetType(); } virtual double CalcCurvature (double t) const { Point<2> point; Vec<2> first, second; GetDerivatives (t, point, first, second); double curv = fabs(first(0)*second(1)-first(1)*second(0)) / pow(first.Length(), 3); return curv; } virtual bool InConvexHull (Point<2> p, double eps) const { return seg->InConvexHull (p, eps); } }; class DLL_HEADER SplineGeometry2d : public SplineGeometry<2>, public NetgenGeometry { protected: NgArray materials; NgArray maxh; NgArray quadmeshing; Array tensormeshing; NgArray layer; NgArray bcnames; double elto0 = 1.0; public: virtual ~SplineGeometry2d(); void Load (const filesystem::path & filename); void LoadData( ifstream & infile ); void LoadDataNew ( ifstream & infile ); void LoadDataV2 ( ifstream & infile ); void TestComment ( ifstream & infile ) ; void DoArchive(Archive& ar) override { SplineGeometry<2>::DoArchive(ar); ar & materials & maxh & quadmeshing & tensormeshing & layer & bcnames & elto0; } bool ProjectPointGI (int surfind, Point<3> & p, PointGeomInfo & gi) const override { p(2) = 0.0; return true; } void ProjectPointEdge (int surfind, int surfind2, Point<3> & p, EdgePointGeomInfo* gi = nullptr) const override; 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 override { newp = p1+secpoint*(p2-p1); newgi.trignum = 1; } void PointBetweenEdge(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 override; Vec<3> GetTangent (const Point<3> & p, int surfi1, int surfi2, const EdgePointGeomInfo & ap1) const override; Vec<3> GetNormal(int surfi1, const Point<3> & p, const PointGeomInfo* gi) const override; const SplineSegExt & GetSpline (const int i) const { return dynamic_cast (*splines[i]); } SplineSegExt & GetSpline (const int i) { return dynamic_cast (*splines[i]); } int GenerateMesh (shared_ptr & mesh, MeshingParameters & mparam) override; void PartitionBoundary (MeshingParameters & mp, double h, Mesh & mesh2d); void CopyEdgeMesh (int from, int to, Mesh & mesh2d, Point3dTree & searchtree); size_t GetNDomains() const { return materials.Size(); } void GetMaterial (int domnr, char* & material ); void SetMaterial (int domnr, const string & material); double GetDomainMaxh ( const int domnr ); void SetDomainMaxh ( const int domnr, double maxh ); bool GetDomainQuadMeshing ( int domnr ) { if ( quadmeshing.Size() ) return quadmeshing[domnr-1]; else return false; } void SetDomainQuadMeshing ( int domnr, bool quad_meshing ) { auto oldsize = quadmeshing.Size(); if ( oldsize=domnr ) return tensormeshing[domnr-1]; else return false; } void SetDomainTensorMeshing ( int domnr, bool tm ) { if ( tensormeshing.Size() old_size) { layer.SetSize(domnr); for(size_t i = old_size; i < domnr; i++) layer[i] = 1; } layer[domnr-1] = layernr; } string GetBCName (int bcnr) const; void SetBCName (int bcnr, string name); int GetBCNumber (string name) const; // 0 if not exists int AddBCName (string name); string * BCNamePtr ( const int bcnr ); }; } #endif ================================================ FILE: libsrc/geom2d/python_geom2d.cpp ================================================ #ifdef NG_PYTHON #include "../general/ngpython.hpp" #include "../core/python_ngcore.hpp" #include "../meshing/python_mesh.hpp" #include "../include/meshing.hpp" #include "../include/geometry2d.hpp" #include "csg2d.hpp" using namespace netgen; using namespace pybind11::literals; namespace netgen { extern std::shared_ptr ng_geometry; } NGCORE_API_EXPORT void ExportGeom2d(py::module &m) { py::class_> (m, "Spline", "Spline of a SplineGeometry object") .def_property("leftdom", [] (SplineSegExt& self) { return self.leftdom; }, [](SplineSegExt& self, int dom) { self.leftdom = dom; }) .def_property("rightdom", [] (SplineSegExt& self) { return self.rightdom; }, [](SplineSegExt& self, int dom) { self.rightdom = dom; }) .def_property_readonly("bc", [] (SplineSegExt& self) { return self.bc; }) .def("GetNormal", [](SplineSegExt& self, double t) { auto tang = self.GetTangent(t).Normalize(); return Vec<2>(tang[1], -tang[0]); }) .def("StartPoint", [](SplineSegExt& self) { return Point<2>(self.StartPI()); }) .def("EndPoint", [](SplineSegExt& self) { return Point<2>(self.EndPI()); }) ; py::class_> (m, "SplineGeometry", "a 2d boundary representation geometry model by lines and splines", py::multiple_inheritance()) .def(py::init<>()) .def(py::init([](const string& filename) { auto geo = make_shared(); geo->Load(filename.c_str()); ng_geometry = geo; return geo; })) .def(NGSPickle()) .def("Load",&SplineGeometry2d::Load) .def("SetDomainLayer", &SplineGeometry2d::SetDomainLayer) .def("AppendPoint", FunctionPointer ([](SplineGeometry2d &self, double px, double py, double maxh, double hpref, string name) { Point<2> p; p(0) = px; p(1) = py; GeomPoint<2> gp(p); gp.hmax = maxh; gp.hpref = hpref; gp.name = name; self.geompoints.Append(gp); return self.geompoints.Size()-1; }), py::arg("x"), py::arg("y"), py::arg("maxh") = 1e99, py::arg("hpref")=0, py::arg("name")="") .def("Append", FunctionPointer([](SplineGeometry2d &self, py::list segment, int leftdomain, int rightdomain, optional> bc, optional copy, double maxh, double hpref, double hprefleft, double hprefright) { SplineSegExt * seg; if(py::isinstance(segment[0])) { auto segtype = py::cast(segment[0]); if (segtype == "line") { LineSeg<2> * l = new LineSeg<2>(self.GetPoint(py::cast(segment[1])), self.GetPoint(py::cast(segment[2]))); seg = new SplineSegExt(*l); } else if (segtype == "spline3") { SplineSeg3<2> * seg3 = new SplineSeg3<2>(self.GetPoint(py::cast(segment[1])), self.GetPoint(py::cast(segment[2])), self.GetPoint(py::cast(segment[3]))); seg = new SplineSegExt(*seg3); } else throw Exception("Appended segment is not a line or a spline3"); } else { if(py::len(segment) == 2) { auto l = new LineSeg<2>(self.GetPoint(py::cast(segment[0])), self.GetPoint(py::cast(segment[1]))); seg = new SplineSegExt(*l); } else if(py::len(segment) == 3) { SplineSeg3<2> * seg3 = new SplineSeg3<2>(self.GetPoint(py::cast(segment[0])), self.GetPoint(py::cast(segment[1])), self.GetPoint(py::cast(segment[2]))); seg = new SplineSegExt(*seg3); } else throw Exception("Appended segment must either have 2 or 3 points"); } seg->leftdom = leftdomain; seg->rightdom = rightdomain; seg->hmax = maxh; seg->hpref_left = max(hpref, hprefleft); seg->hpref_right = max(hpref,hprefright); seg->reffak = 1; seg->copyfrom = -1; if (copy.has_value()) seg->copyfrom = *copy+1; if (bc.has_value()) { if(auto intptr = get_if(&*bc); intptr) seg->bc = *intptr; else { auto bcname = get_if(&*bc); seg->bc = self.GetNSplines() + 1; self.SetBCName(seg->bc, *bcname); } } else seg->bc = self.GetNSplines()+1; self.AppendSegment(seg); return self.GetNSplines()-1; }), py::arg("point_indices"), py::arg("leftdomain") = 1, py::arg("rightdomain") = py::int_(0), py::arg("bc")=nullopt, py::arg("copy")=nullopt, py::arg("maxh")=1e99, py::arg("hpref")=0,py::arg("hprefleft")=0,py::arg("hprefright")=0) .def("AppendSegment", FunctionPointer([](SplineGeometry2d &self, py::list point_indices, int leftdomain, int rightdomain) { int npts = py::len(point_indices); SplineSegExt * seg; //int a = py::extract(point_indices[0]); if (npts == 2) { LineSeg<2> * l = new LineSeg<2>(self.GetPoint(py::extract(point_indices[0])()), self.GetPoint(py::extract(point_indices[1])())); seg = new SplineSegExt(*l); } else if (npts == 3) { SplineSeg3<2> * seg3 = new SplineSeg3<2>(self.GetPoint(py::extract(point_indices[0])()), self.GetPoint(py::extract(point_indices[1])()), self.GetPoint(py::extract(point_indices[2])())); seg = new SplineSegExt(*seg3); } else throw Exception("Can only append segments with 2 or 3 points!"); seg->leftdom = leftdomain; seg->rightdom = rightdomain; seg->hmax = 1e99; seg->reffak = 1; seg->copyfrom = -1; self.AppendSegment(seg); }), py::arg("point_indices"), py::arg("leftdomain") = 1, py::arg("rightdomain") = py::int_(0)) .def("AddCurve", [] (SplineGeometry2d & self, py::object func, int leftdomain, int rightdomain, py::object bc, double maxh) { int n = 1000; NgArray> points; for (int i = 0; i <= n; i++) { double t = double(i)/n; py::tuple xy = func(t); double x = py::cast(xy[0]); double y = py::cast(xy[1]); points.Append (Point<2>(x,y)); } auto spline = new DiscretePointsSeg<2> (points); SplineSegExt * spex = new SplineSegExt (*spline); spex -> leftdom = leftdomain; spex -> rightdom = rightdomain; spex->hmax = maxh; spex->reffak = 1; spex->copyfrom = -1; if (py::extract(bc).check()) spex->bc = py::extract(bc)(); else if (py::extract(bc).check()) { string bcname = py::extract(bc)(); spex->bc = self.GetNSplines()+1; self.SetBCName(spex->bc, bcname); } else spex->bc = self.GetNSplines()+1; self.AppendSegment (spex); }, py::arg("func"), py::arg("leftdomain") = 1, py::arg("rightdomain") = py::int_(0), py::arg("bc")=NGDummyArgument(), py::arg("maxh")=1e99, "Curve is given as parametrization on the interval [0,1]") .def("SetMaterial", &SplineGeometry2d::SetMaterial) .def("SetDomainMaxH", &SplineGeometry2d::SetDomainMaxh) .def("GetBCName", [](SplineGeometry2d& self, size_t index) { return self.GetBCName(index); }) .def("GetNDomains", [](SplineGeometry2d& self) { return self.GetNDomains(); }) .def("GetNSplines", [](SplineGeometry2d& self) { return self.splines.Size(); }) .def("GetSpline", [](SplineGeometry2d& self, size_t index) { return shared_ptr(&self.GetSpline(index), NOOP_Deleter); }, py::return_value_policy::reference_internal) .def("GetNPoints", [](SplineGeometry2d& self) { return self.GetNP(); }) .def("GetPoint", [](SplineGeometry2d& self, size_t index) { return Point<2>(self.GetPoint(index)); }) .def("PlotData", FunctionPointer([](SplineGeometry2d &self) { Box<2> box(self.GetBoundingBox()); double xdist = box.PMax()(0) - box.PMin()(0); double ydist = box.PMax()(1) - box.PMin()(1); py::tuple xlim = py::make_tuple(box.PMin()(0) - 0.1*xdist, box.PMax()(0) + 0.1*xdist); py::tuple ylim = py::make_tuple(box.PMin()(1) - 0.1*ydist, box.PMax()(1) + 0.1*ydist); py::list xpoints, ypoints; for (int i = 0; i < self.splines.Size(); i++) { py::list xp, yp; if (self.splines[i]->GetType().compare("line")==0) { GeomPoint<2> p1 = self.splines[i]->StartPI(); GeomPoint<2> p2 = self.splines[i]->EndPI(); xp.append(py::cast(p1(0))); xp.append(py::cast(p2(0))); yp.append(py::cast(p1(1))); yp.append(py::cast(p2(1))); } else if (self.splines[i]->GetType().compare("spline3")==0) { double len = self.splines[i]->Length(); int n = floor(len/(0.05*min(xdist,ydist))); for (int j = 0; j <= n; j++) { GeomPoint<2> point = self.splines[i]->GetPoint(j*1./n); xp.append(py::cast(point(0))); yp.append(py::cast(point(1))); } } else { cout << "spline is neither line nor spline3" << endl; } xpoints.append(xp); ypoints.append(yp); } return py::tuple(py::make_tuple(xlim, ylim, xpoints, ypoints)); })) .def("_visualizationData", [](SplineGeometry2d &self) { Box<2> box(self.GetBoundingBox()); double xdist = box.PMax()(0) - box.PMin()(0); double ydist = box.PMax()(1) - box.PMin()(1); py::dict data; py::dict segment_data; auto min_val = py::make_tuple(box.PMin()(0), box.PMin()(1),0); auto max_val = py::make_tuple(box.PMax()(1),box.PMax()(1),0); py::list vertices; py::list domains; py::list segment_points; py::list segment_normals; py::list leftdom; py::list rightdom; int max_bcnr = 0; for(int i = 0; i < self.splines.Size(); i++) { std::vector> lst; if (self.splines[i]->GetType().compare("line") == 0) lst = { self.splines[i]->StartPI(), self.splines[i]->EndPI() }; else if(self.splines[i]->GetType().compare("spline3") == 0) { double len = self.splines[i]->Length(); int n = floor(len/(0.05*min(xdist,ydist))); n = max(3, n); lst.push_back(self.splines[i]->StartPI()); for (int j = 1; j < n; j++){ lst.push_back(self.splines[i]->GetPoint(j*1./n)); lst.push_back(self.splines[i]->GetPoint(j*1./n)); } lst.push_back(self.splines[i]->EndPI()); } else { throw NgException("Spline is neither line nor spline3"); } for (auto point : lst) { for(auto val : {point(0), point(1), 0.}) vertices.append(val); int bcnr = self.GetSpline(i).bc; max_bcnr = max2(max_bcnr, bcnr); domains.append(bcnr); domains.append(self.GetSpline(i).leftdom); domains.append(self.GetSpline(i).rightdom); } // segment data auto pnt = self.splines[i]->GetPoint(0.5); segment_points.append(py::make_tuple(pnt(0),pnt(1))); auto normal = self.GetSpline(i).GetTangent(0.5); std::swap(normal(0),normal(1)); normal(1) *= -1; normal *= 1./sqrt(normal(0) * normal(0) + normal(1)*normal(1)); segment_normals.append(py::make_tuple(normal(0),normal(1))); leftdom.append(self.GetSpline(i).leftdom); rightdom.append(self.GetSpline(i).rightdom); } py::list bcnames; for (int i = 1; i point = self.splines[i]->GetPoint(0.5); Vec<2> normal = self.GetSpline(i).GetTangent(0.5); double temp = normal(0); normal(0) = normal(1); normal(1) = -temp; leftdom.append(py::cast(self.GetSpline(i).leftdom)); rightdom.append(py::cast(self.GetSpline(i).rightdom)); rightpoints.append(py::make_tuple(point(0), point(1), normal(0)<0, normal(1)<0)); leftpoints.append(py::make_tuple(point(0), point(1), normal(0)<0, normal(1)<0)); } return py::tuple(py::make_tuple(leftpoints, rightpoints, leftdom, rightdom)); })) .def("Print", FunctionPointer([](SplineGeometry2d &self) { for (int i = 0; i < self.geompoints.Size(); i++) { cout << i << " : " << self.geompoints[i][0] << " , " << self.geompoints[i][1] << endl; } //Box<2> box(self.GetBoundingBox()); //cout << box.PMin() << endl; //cout << box.PMax() << endl; cout << self.splines.Size() << endl; for (int i = 0; i < self.splines.Size(); i++) { cout << self.splines[i]->GetType() << endl; //cout << i << " : " << self.splines[i]->GetPoint(0.1) << " , " << self.splines[i]->GetPoint(0.5) << endl; } })) .def("Draw", FunctionPointer ([] (shared_ptr self) { ng_geometry = self; py::module::import("netgen").attr("Redraw")(); }) ) .def("GenerateMesh", [](shared_ptr self, optional pars, py::kwargs kwargs) { MeshingParameters mp; if(pars) mp = *pars; CreateMPfromKwargs(mp, kwargs); py::gil_scoped_release gil_release; auto mesh = make_shared(); mesh->SetGeometry(self); SetGlobalMesh (mesh); ng_geometry = self; auto result = self->GenerateMesh(mesh, mp); if(result != 0) throw Exception("Meshing failed!"); return mesh; }, py::arg("mp") = nullopt, meshingparameter_description.c_str()) .def("_SetDomainTensorMeshing", &SplineGeometry2d::SetDomainTensorMeshing) ; py::class_(m, "Solid2d") .def(py::init<>()) .def(py::init, EdgeInfo, PointInfo>>, std::string, std::string>(), py::arg("points"), py::arg("mat")=MAT_DEFAULT, py::arg("bc")=BC_DEFAULT) .def(py::self+py::self) .def(py::self-py::self) .def(py::self*py::self) .def(py::self+=py::self) // .def(py::self-=py::self) // false clange warning, see https://github.com/pybind/pybind11/issues/1893 .def("__isub__", [](Solid2d& lhs, const Solid2d& rhs) { return lhs -= rhs; }, py::is_operator()) .def(py::self*=py::self) .def("Mat", &Solid2d::Mat) .def("BC", &Solid2d::BC) .def("Maxh", &Solid2d::Maxh) .def("Layer", &Solid2d::Layer) .def("Copy", [](Solid2d & self) -> Solid2d { return self; }) .def("Move", &Solid2d::Move) .def("Scale", static_cast(&Solid2d::Scale)) .def("Scale", static_cast)>(&Solid2d::Scale)) .def("Rotate", &Solid2d::RotateDeg, py::arg("angle"), py::arg("center")=Point<2>{0,0}) ; m.def("Rectangle", [](Point<2> p0, Point<2> p1, string mat, string bc, optional bottom, optional right, optional top, optional left) -> Solid2d { using P = Point<2>; return { { p0, EdgeInfo{bottom ? *bottom : bc}, P{p1[0],p0[1]}, EdgeInfo {right ? *right : bc}, p1, EdgeInfo {top ? *top : bc}, P{p0[0],p1[1]}, EdgeInfo {left ? *left : bc}, }, mat}; }, "pmin"_a, "pmax"_a, "mat"_a=MAT_DEFAULT, "bc"_a=BC_DEFAULT, "bottom"_a=nullopt, "right"_a=nullopt, "top"_a=nullopt, "left"_a=nullopt ); m.def("Circle", Circle, py::arg("center"), py::arg("radius"), py::arg("mat")=MAT_DEFAULT, py::arg("bc")=BC_DEFAULT); py::class_(m, "CSG2d") .def(py::init<>()) .def("GenerateSplineGeometry", &CSG2d::GenerateSplineGeometry) .def("Add", &CSG2d::Add) .def("GenerateMesh", [](CSG2d & self, optional pars, py::kwargs kwargs) { MeshingParameters mp; if(pars) mp = *pars; CreateMPfromKwargs(mp, kwargs); py::gil_scoped_release gil_release; auto mesh = make_shared(); auto geo = self.GenerateSplineGeometry(); mesh->SetGeometry(geo); SetGlobalMesh (mesh); ng_geometry = geo; auto result = geo->GenerateMesh(mesh, mp); if(result != 0) throw Exception("Meshing failed!"); return mesh; }, py::arg("mp") = nullopt, meshingparameter_description.c_str()) ; py::class_(m, "EdgeInfo") .def(py::init<>()) .def(py::init&>(), py::arg("control_point")) .def(py::init(), py::arg("maxh")) .def(py::init(), py::arg("bc")) .def(py::init>, double, string>(), py::arg("control_point")=nullopt, py::arg("maxh")=MAXH_DEFAULT, py::arg("bc")=BC_DEFAULT) ; py::class_(m, "PointInfo") .def(py::init<>()) .def(py::init(), "maxh"_a) .def(py::init(), "name"_a) .def(py::init(), "maxh"_a, "name"_a) ; } PYBIND11_MODULE(libgeom2d, m) { ExportGeom2d(m); } #endif ================================================ FILE: libsrc/geom2d/spline2d.hpp ================================================ 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; /// perform 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, NgArray > & points); /** calculates lineintersections: for lines $$ a x + b y + c = 0 $$ the intersecting points are calculated and stored in points */ virtual void LineIntersections (const double a, const double b, const double c, NgArray < 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, NgArray < 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, NgArray < 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, NgArray < Point<2> > & points, const double eps) const; virtual double MaxCurvature(void) const {return 1./radius;} }; /// class DiscretePointsSegment : public SplineSegment { NgArray > pts; GeomPoint2d p1, p2; public: /// DiscretePointsSegment (const NgArray > & 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 ================================================ FILE: libsrc/geom2d/vsgeom2d.cpp ================================================ #include #include #include #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(); glMultMatrixd (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); NgArray > points, otherpoints; for (int i = 1; i <= geometry2d->GetSplines().Size(); i++) { geometry2d->GetSplines().Get(i)->GetPoints (200, 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(); } } ================================================ FILE: libsrc/geom2d/vsgeom2d.hpp ================================================ #ifndef FILE_VSGEOM2D #define FILE_VSGEOM2D /**************************************************************************/ /* File: vsgeom2d.hpp */ /* Author: Joachim Schoeberl */ /* Date: 05. Jan. 2011 */ /**************************************************************************/ namespace netgen { class NGGUI_API 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 ================================================ FILE: libsrc/gprim/CMakeLists.txt ================================================ target_sources(nglib PRIVATE adtree.cpp geom2d.cpp geom3d.cpp geomfuncs.cpp geomtest3d.cpp spline.cpp splinegeometry.cpp transform3d.cpp ) install(FILES adtree.hpp geom2d.hpp geom3d.hpp geomfuncs.hpp geomobjects.hpp geomops.hpp geomtest3d.hpp gprim.hpp splinegeometry.hpp spline.hpp transform3d.hpp DESTINATION ${NG_INSTALL_DIR_INCLUDE}/gprim COMPONENT netgen_devel ) ================================================ FILE: libsrc/gprim/adtree.cpp ================================================ #include #include // class DenseMatrix; #include 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 (NgArray & 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, NgArray & pis) const { ArrayMem stack(1000); ArrayMem stackdir(1000); ADTreeNode3 * node; int dir, stacks; // stack.SetSize (1000); // stackdir.SetSize(1000); pis.SetSize(0); stack[0] = root; stackdir[0] = 0; stacks = 0; while (stacks >= 0) { node = stack[stacks]; dir = stackdir[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[stacks] = node->left; stackdir[stacks] = ndir; } if (node->right && bmax[dir] >= node->sep) { stacks++; stack[stacks] = node->right; stackdir[stacks] = ndir; } } } void ADTree3 :: PrintRec (ostream & ost, const ADTreeNode3 * node) const { // if (node->data) // true anyway { 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, NgArray & pis) const { static NgArray stack(1000); static NgArray 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, NgArray & pis) const { static NgArray stack(1000); static NgArray 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, NgArray & pis) const { static NgArray 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, NgArray & pis) const { static NgArray 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, NgArray & pis) const { // static NgArray stack(10000); // stack.SetSize (10000); NgArrayMem stack(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) // true anyway { 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; } /* template T_ADTree :: T_ADTree (Point acmin, Point acmax) // : ela(0) { cmin = acmin; cmax = acmax; root = new T_ADTreeNode; root->sep = (cmin[0] + cmax[0]) / 2; } */ /* template T_ADTree :: ~T_ADTree () { root->DeleteChilds(); delete root; } */ /* template void T_ADTree :: Insert (Point p, T pi) { T_ADTreeNode *node(NULL); T_ADTreeNode *next; int dir; int lr(0); Point bmin = cmin; Point bmax = cmax; next = root; dir = 0; while (next) { node = next; if (IsInvalid(node->pi)) { // memcpy (node->data, p, dim * sizeof(float)); node->data = p; 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 T_ADTreeNode; // memcpy (next->data, p, dim * sizeof(float)); next->data = p; 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; } } */ /* template void T_ADTree :: DeleteElement (T pi) { T_ADTreeNode * node = ela[pi]; ela.Delete(pi); SetInvalid(node->pi); // = -1; node = node->father; while (node) { node->nchilds--; node = node->father; } } */ /* template void T_ADTree :: PrintMemInfo (ostream & ost) const { ost << Elements() << " elements a " << sizeof(ADTreeNode6) << " Bytes = " << Elements() * sizeof(T_ADTreeNode) << endl; ost << "maxind = " << ela.Size() << " = " << sizeof(T_ADTreeNode*) * ela.Size() << " Bytes" << endl; } */ /* template class inttn { public: int dir; T_ADTreeNode * node; }; template void T_ADTree :: GetIntersecting (Point bmin, Point bmax, NgArray & pis) const { // static NgArray stack(10000); // stack.SetSize (10000); NgArrayMem,10000> stack(10000); pis.SetSize(0); stack[0].node = root; stack[0].dir = 0; int stacks = 0; while (stacks >= 0) { T_ADTreeNode * node = stack[stacks].node; int dir = stack[stacks].dir; stacks--; if (!IsInvalid(node->pi)) // != -1) { bool found = true; for (int i = 0; i < dim/2; i++) if (node->data[i] > bmax[i]) found = false; for (int i = dim/2; i < dim; i++) if (node->data[i] < bmin[i]) found = false; if (found) pis.Append (node->pi); // if (node->data[0] > bmax[0] || // node->data[1] > bmax[1] || // node->data[2] > bmax[2] || // node->data[3] < bmin[3] || // node->data[4] < bmin[4] || // node->data[5] < bmin[5]) // ; // else // { // pis.Append (node->pi); // } } int ndir = (dir+1) % dim; 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; } } } */ /* template void T_ADTree :: PrintRec (ostream & ost, const T_ADTreeNode * node) const { // if (node->data) // true anyway { ost << node->pi << ": "; ost << node->nchilds << " childs, "; for (int i = 0; i < dim; i++) ost << node->data[i] << " "; ost << endl; } if (node->left) PrintRec (ost, node->left); if (node->right) PrintRec (ost, node->right); } template int T_ADTree :: DepthRec (const T_ADTreeNode * 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); } template int T_ADTree :: ElementsRec (const T_ADTreeNode * 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, NgArray & pis) const { static NgArray 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, NgArray & 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); } /* template BoxTree :: BoxTree (const Box & abox) { boxpmin = abox.PMin(); boxpmax = abox.PMax(); Point<2*dim> tpmin, tpmax; for (int i = 0; i < dim; i++) { tpmin(i) = tpmin(i+dim) = boxpmin(i); tpmax(i) = tpmax(i+dim) = boxpmax(i); } tree = new T_ADTree<2*dim,T> (tpmin, tpmax); } */ /* template BoxTree :: BoxTree (const Point & apmin, const Point & apmax) { boxpmin = apmin; boxpmax = apmax; Point<2*dim> tpmin, tpmax; for (int i = 0; i < dim; i++) { tpmin(i) = tpmin(i+dim) = boxpmin(i); tpmax(i) = tpmax(i+dim) = boxpmax(i); } tree = new T_ADTree<2*dim,T> (tpmin, tpmax); } template BoxTree :: ~BoxTree () { delete tree; } template void BoxTree :: Insert (const Point & bmin, const Point & bmax, T pi) { Point<2*dim> tp; for (size_t i = 0; i < dim; i++) { tp(i) = bmin(i); tp(i+dim) = bmax(i); } tree->Insert (tp, pi); } */ /* template void BoxTree ::GetIntersecting (const Point & pmin, const Point & pmax, NgArray & pis) const { Point<2*dim> tpmin, tpmax; double tol = Tolerance(); for (size_t i = 0; i < dim; i++) { tpmin(i) = boxpmin(i); tpmax(i) = pmax(i)+tol; tpmin(i+dim) = pmin(i)-tol; tpmax(i+dim) = boxpmax(i); } tree->GetIntersecting (tpmin, tpmax, pis); } */ /* template<> BlockAllocator T_ADTreeNode<4,INDEX> :: ball(sizeof (T_ADTreeNode<4,INDEX>)); template class T_ADTree<4,INDEX>; template class BoxTree<2,INDEX>; template<> BlockAllocator T_ADTreeNode<4,INDEX_2> :: ball(sizeof (T_ADTreeNode<4,INDEX_2>)); template class T_ADTree<4,INDEX_2>; template class BoxTree<2,INDEX_2>; template<> BlockAllocator T_ADTreeNode<6,INDEX> :: ball(sizeof (T_ADTreeNode<6,INDEX>)); template class T_ADTree<6,INDEX>; template class BoxTree<3,INDEX>; */ } ================================================ FILE: libsrc/gprim/adtree.hpp ================================================ #ifndef FILE_ADTREE #define FILE_ADTREE /* *************************************************************************/ /* File: adtree.hh */ /* Author: Joachim Schoeberl */ /* Date: 16. Feb. 98 */ /* Redesigned by Wolfram Muehlhuber, May 1998 */ /* *************************************************************************/ #include #include #include #include "geomfuncs.hpp" 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; NgArray ela; const ADTreeCriterion * criterion; NgArray stack; NgArray 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, // NgArray & pis) const; void SetCriterion (ADTreeCriterion & acriterion); void Reset (); int Next (); void GetMatch (NgArray & 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]; NgArray 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, NgArray & 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]; NgArray 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, NgArray & 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]; NgArray 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, NgArray & 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]; NgArray 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, NgArray & 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]; NgArray 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, NgArray & 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]; NgArray 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, NgArray & 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; }; template class T_ADTreeNode { public: T_ADTreeNode *left, *right, *father; float sep; // float data[DIM]; Point data; T pi; int nchilds; T_ADTreeNode () { // pi = -1; SetInvalid(pi); left = NULL; right = NULL; father = NULL; nchilds = 0; } void DeleteChilds (BlockAllocator & ball) { if (left) { left->DeleteChilds(ball); ball.Free(left); left = NULL; } if (right) { right->DeleteChilds(ball); ball.Free(right); right = NULL; } } }; template class T_ADTree { T_ADTreeNode * root; // float cmin[dim], cmax[dim]; Point cmin, cmax; // NgArray*> ela; NgClosedHashTable*> ela; BlockAllocator ball{sizeof(T_ADTreeNode)}; public: T_ADTree (Point acmin, Point acmax) { cmin = acmin; cmax = acmax; root = new (ball.Alloc()) T_ADTreeNode; root->sep = (cmin[0] + cmax[0]) / 2; } ~T_ADTree () { root->DeleteChilds(ball); ball.Free(root); } void Insert (Point p, T pi) { T_ADTreeNode *node(NULL); T_ADTreeNode *next; int dir; int lr(0); Point bmin = cmin; Point bmax = cmax; next = root; dir = 0; while (next) { node = next; if (IsInvalid(node->pi)) { // memcpy (node->data, p, dim * sizeof(float)); node->data = p; 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 (ball.Alloc()) T_ADTreeNode; next->data = p; 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; } } class inttn { public: int dir; T_ADTreeNode * node; }; void GetIntersecting (Point bmin, Point bmax, NgArray & pis) const { NgArrayMem stack(10000); pis.SetSize(0); stack[0].node = root; stack[0].dir = 0; int stacks = 0; while (stacks >= 0) { T_ADTreeNode * node = stack[stacks].node; int dir = stack[stacks].dir; stacks--; if (!IsInvalid(node->pi)) // != -1) { bool found = true; for (int i = 0; i < dim/2; i++) if (node->data[i] > bmax[i]) found = false; for (int i = dim/2; i < dim; i++) if (node->data[i] < bmin[i]) found = false; if (found) pis.Append (node->pi); /* if (node->data[0] > bmax[0] || node->data[1] > bmax[1] || node->data[2] > bmax[2] || node->data[3] < bmin[3] || node->data[4] < bmin[4] || node->data[5] < bmin[5]) ; else { pis.Append (node->pi); } */ } int ndir = (dir+1) % dim; 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 DeleteElement (T pi) { T_ADTreeNode * node = ela[pi]; ela.Delete(pi); SetInvalid(node->pi); // = -1; node = node->father; while (node) { node->nchilds--; node = node->father; } } 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 T_ADTreeNode * node) const { // if (node->data) // true anyway { ost << node->pi << ": "; ost << node->nchilds << " childs, "; for (int i = 0; i < dim; i++) ost << node->data[i] << " "; ost << endl; } if (node->left) PrintRec (ost, node->left); if (node->right) PrintRec (ost, node->right); } int DepthRec (const T_ADTreeNode * 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 ElementsRec (const T_ADTreeNode * node) const { int els = 1; if (node->left) els += ElementsRec(node->left); if (node->right) els += ElementsRec(node->right); return els; } void PrintMemInfo (ostream & ost) const { ost << Elements() << " elements a " << sizeof(ADTreeNode6) << " Bytes = " << Elements() * sizeof(T_ADTreeNode) << endl; ost << "maxind = " << ela.Size() << " = " << sizeof(T_ADTreeNode*) * ela.Size() << " Bytes" << endl; } }; /* 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]; NgArray 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, NgArray & 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, NgArray & pis) const; const ADTree3 & Tree() const { return *tree; }; }; template class BoxTree { public: // Number of entries per leaf static constexpr int N = 100; struct Node; struct Leaf { Point<2*dim> p[N]; T index[N]; int n_elements; Leaf() : n_elements(0) { } void Add( NgClosedHashTable &leaf_index, const Point<2*dim> &ap, T aindex ) { p[n_elements] = ap; index[n_elements] = aindex; n_elements++; leaf_index[aindex] = this; } }; struct Node { union { Node *children[2]; Leaf *leaf; }; double sep; int level; Node() : children{nullptr,nullptr} { } ~Node() { } Leaf *GetLeaf() const { return children[1] ? nullptr : leaf; } }; private: Node root; NgClosedHashTable leaf_index; Point global_min, global_max; double tol; size_t n_leaves; size_t n_nodes; BlockAllocator ball_nodes; BlockAllocator ball_leaves; public: BoxTree (const Point & pmin, const Point & pmax) : global_min(pmin), global_max(pmax), n_leaves(1), n_nodes(1), ball_nodes(sizeof(Node)), ball_leaves(sizeof(Leaf)) { root.leaf = (Leaf*) ball_leaves.Alloc(); new (root.leaf) Leaf(); root.level = 0; tol = 1e-7 * Dist(pmax, pmin); } BoxTree (const Box & box) : BoxTree(box.PMin(), box.PMax()) { } void SetTolerance(double _tol) { tol = _tol; } double GetTolerance() { return tol; } size_t GetNLeaves() { return n_leaves; } size_t GetNNodes() { return n_nodes; } template void GetFirstIntersecting (const Point & pmin, const Point & pmax, TFunc func=[](auto pi){return false;}) const { // static Timer timer("BoxTree::GetIntersecting"); RegionTimer rt(timer); // static Timer timer1("BoxTree::GetIntersecting-LinearSearch"); ArrayMem stack; ArrayMem dir_stack; Point<2*dim> tpmin, tpmax; for (size_t i : IntRange(dim)) { tpmin(i) = global_min(i); tpmax(i) = pmax(i)+tol; tpmin(i+dim) = pmin(i)-tol; tpmax(i+dim) = global_max(i); } stack.SetSize(0); stack.Append(&root); dir_stack.SetSize(0); dir_stack.Append(0); while(stack.Size()) { const Node *node = stack.Last(); stack.DeleteLast(); int dir = dir_stack.Last(); dir_stack.DeleteLast(); if(Leaf *leaf = node->GetLeaf()) { // RegionTimer rt1(timer1); for (auto i : IntRange(leaf->n_elements)) { bool intersect = true; const auto p = leaf->p[i]; for (int d = 0; d < dim; d++) if (p[d] > tpmax[d]) intersect = false; for (int d = dim; d < 2*dim; d++) if (p[d] < tpmin[d]) intersect = false; if(intersect) if(func(leaf->index[i])) return; } } else { int newdir = dir+1; if(newdir==2*dim) newdir = 0; if (tpmin[dir] <= node->sep) { stack.Append(node->children[0]); dir_stack.Append(newdir); } if (tpmax[dir] >= node->sep) { stack.Append(node->children[1]); dir_stack.Append(newdir); } } } } void GetIntersecting (const Point & pmin, const Point & pmax, NgArray & pis) const { pis.SetSize(0); GetFirstIntersecting(pmin, pmax, [&pis](auto pi) { pis.Append(pi); return false;}); } void GetIntersecting(const Point & pmin, const Point & pmax, Array & pis) const { pis.SetSize0(); GetFirstIntersecting(pmin, pmax, [&pis](auto pi) { pis.Append(pi); return false;}); } void Insert (const Box & box, T pi) { Insert (box.PMin(), box.PMax(), pi); } void Insert (const Point & pmin, const Point & pmax, T pi) { // static Timer timer("BoxTree::Insert"); RegionTimer rt(timer); int dir = 0; Point<2*dim> p; for (auto i : IntRange(dim)) { p(i) = pmin[i]; p(i+dim) = pmax[i]; } Node * node = &root; Leaf * leaf = node->GetLeaf(); // search correct leaf to add point while(!leaf) { node = p[dir] < node->sep ? node->children[0] : node->children[1]; dir++; if(dir==2*dim) dir = 0; leaf = node->GetLeaf(); } // add point to leaf if(leaf->n_elements < N) leaf->Add(leaf_index, p,pi); else // assume leaf->n_elements == N { // add two new nodes and one new leaf int n_elements = leaf->n_elements; ArrayMem coords(n_elements); ArrayMem order(n_elements); // separate points in two halves, first sort all coordinates in direction dir for (auto i : IntRange(n_elements)) { order[i] = i; coords[i] = leaf->p[i][dir]; } QuickSortI(coords, order); int isplit = N/2; Leaf *leaf1 = (Leaf*) ball_leaves.Alloc(); new (leaf1) Leaf(); Leaf *leaf2 = (Leaf*) ball_leaves.Alloc(); new (leaf2) Leaf(); for (auto i : order.Range(0, isplit)) leaf1->Add(leaf_index, leaf->p[i], leaf->index[i] ); for (auto i : order.Range(isplit, N)) leaf2->Add(leaf_index, leaf->p[i], leaf->index[i] ); Node *node1 = (Node*) ball_nodes.Alloc(); new (node1) Node(); node1->leaf = leaf1; node1->level = node->level+1; Node *node2 = (Node*) ball_nodes.Alloc(); new (node2) Node(); node2->leaf = leaf2; node2->level = node->level+1; node->children[0] = node1; node->children[1] = node2; node->sep = 0.5 * (leaf->p[order[isplit-1]][dir] + leaf->p[order[isplit]][dir]); // add new point to one of the new leaves if (p[dir] < node->sep) leaf1->Add( leaf_index, p, pi ); else leaf2->Add( leaf_index, p, pi ); ball_leaves.Free(leaf); n_leaves++; n_nodes+=2; } } void DeleteElement (T pi) { // static Timer timer("BoxTree::DeleteElement"); RegionTimer rt(timer); Leaf *leaf = leaf_index[pi]; leaf_index.Delete(pi); auto & n_elements = leaf->n_elements; auto & index = leaf->index; auto & p = leaf->p; for (auto i : IntRange(n_elements)) { if(index[i] == pi) { n_elements--; if(i!=n_elements) { index[i] = index[n_elements]; p[i] = p[n_elements]; } return; } } } }; // template // class BoxTree // { // T_ADTree<2*dim,T> * tree; // Point boxpmin, boxpmax; // public: // BoxTree (const Box & abox) // { // boxpmin = abox.PMin(); // boxpmax = abox.PMax(); // Point<2*dim> tpmin, tpmax; // for (int i = 0; i < dim; i++) // { // tpmin(i) = tpmin(i+dim) = boxpmin(i); // tpmax(i) = tpmax(i+dim) = boxpmax(i); // } // tree = new T_ADTree<2*dim,T> (tpmin, tpmax); // } // // BoxTree (const Point & apmin, const Point & apmax) // { // boxpmin = apmin; // boxpmax = apmax; // Point<2*dim> tpmin, tpmax; // for (int i = 0; i < dim; i++) // { // tpmin(i) = tpmin(i+dim) = boxpmin(i); // tpmax(i) = tpmax(i+dim) = boxpmax(i); // } // tree = new T_ADTree<2*dim,T> (tpmin, tpmax); // } // // ~BoxTree () // { // delete tree; // } // // void Insert (const Point & bmin, const Point & bmax, T pi) // { // Point<2*dim> tp; // // for (size_t i = 0; i < dim; i++) // { // tp(i) = bmin(i); // tp(i+dim) = bmax(i); // } // // tree->Insert (tp, pi); // } // // void Insert (const Box & box, T pi) // { // Insert (box.PMin(), box.PMax(), pi); // } // // void DeleteElement (T pi) // { // tree->DeleteElement(pi); // } // // void GetIntersecting (const Point & pmin, const Point & pmax, // NgArray & pis) const // { // Point<2*dim> tpmin, tpmax; // double tol = Tolerance(); // for (size_t i = 0; i < dim; i++) // { // tpmin(i) = boxpmin(i); // tpmax(i) = pmax(i)+tol; // // tpmin(i+dim) = pmin(i)-tol; // tpmax(i+dim) = boxpmax(i); // } // // tree->GetIntersecting (tpmin, tpmax, pis); // } // // // double Tolerance() const { return 1e-7 * Dist(boxpmax, boxpmin); } // single precision // const auto & Tree() const { return *tree; }; // auto & Tree() { return *tree; }; // }; template class DelaunayTree { public: // Number of entries per leaf static constexpr int N = 100; struct Node; struct Leaf { Point<2*dim, TSCAL> p[N]; T index[N]; int n_elements; int nr; Leaf() : n_elements(0) { } void Add( Array &leaves, Array &leaf_index, const Point<2*dim> &ap, T aindex ) { p[n_elements] = ap; index[n_elements] = aindex; n_elements++; if(leaf_index.Size() leaves; Array leaf_index; Point global_min, global_max; double tol; size_t n_leaves; size_t n_nodes; BlockAllocator ball_nodes; BlockAllocator ball_leaves; public: DelaunayTree (const Point & pmin, const Point & pmax) : global_min(pmin), global_max(pmax), n_leaves(1), n_nodes(1), ball_nodes(sizeof(Node)), ball_leaves(sizeof(Leaf)) { root.leaf = (Leaf*) ball_leaves.Alloc(); new (root.leaf) Leaf(); root.leaf->nr = 0; leaves.Append(root.leaf); root.level = 0; tol = 1e-7 * Dist(pmax, pmin); } DelaunayTree (const Box & box) : DelaunayTree(box.PMin(), box.PMax()) { } double GetTolerance() { return tol; } size_t GetNLeaves() { return n_leaves; } size_t GetNNodes() { return n_nodes; } template void GetFirstIntersecting (const Point & pmin, const Point & pmax, TFunc func=[](auto pi){return false;}) const { // static Timer timer("DelaunayTree::GetIntersecting"); RegionTimer rt(timer); // static Timer timer1("DelaunayTree::GetIntersecting-LinearSearch"); ArrayMem stack; ArrayMem dir_stack; Point<2*dim> tpmin, tpmax; for (size_t i : IntRange(dim)) { tpmin(i) = global_min(i); tpmax(i) = pmax(i)+tol; tpmin(i+dim) = pmin(i)-tol; tpmax(i+dim) = global_max(i); } stack.SetSize(0); stack.Append(&root); dir_stack.SetSize(0); dir_stack.Append(0); while(stack.Size()) { const Node *node = stack.Last(); stack.DeleteLast(); int dir = dir_stack.Last(); dir_stack.DeleteLast(); if(Leaf *leaf = node->GetLeaf()) { // RegionTimer rt1(timer1); for (auto i : IntRange(leaf->n_elements)) { bool intersect = true; const auto p = leaf->p[i]; for (int d = 0; d < dim; d++) if (p[d] > tpmax[d]) intersect = false; for (int d = dim; d < 2*dim; d++) if (p[d] < tpmin[d]) intersect = false; if(intersect) if(func(leaf->index[i])) return; } } else { int newdir = dir+1; if(newdir==2*dim) newdir = 0; if (tpmin[dir] <= node->sep) { stack.Append(node->children[0]); dir_stack.Append(newdir); } if (tpmax[dir] >= node->sep) { stack.Append(node->children[1]); dir_stack.Append(newdir); } } } } void GetIntersecting (const Point & pmin, const Point & pmax, NgArray & pis) const { pis.SetSize(0); GetFirstIntersecting(pmin, pmax, [&pis](auto pi) { pis.Append(pi); return false;}); } void Insert (const Box & box, T pi) { Insert (box.PMin(), box.PMax(), pi); } void Insert (const Point & pmin, const Point & pmax, T pi) { // static Timer timer("DelaunayTree::Insert"); RegionTimer rt(timer); int dir = 0; Point<2*dim> p; for (auto i : IntRange(dim)) { p(i) = pmin[i]; p(i+dim) = pmax[i]; } Node * node = &root; Leaf * leaf = node->GetLeaf(); // search correct leaf to add point while(!leaf) { node = p[dir] < node->sep ? node->children[0] : node->children[1]; dir++; if(dir==2*dim) dir = 0; leaf = node->GetLeaf(); } // add point to leaf if(leaf->n_elements < N) leaf->Add(leaves, leaf_index, p,pi); else // assume leaf->n_elements == N { // add two new nodes and one new leaf int n_elements = leaf->n_elements; ArrayMem coords(n_elements); ArrayMem order(n_elements); // separate points in two halves, first sort all coordinates in direction dir for (auto i : IntRange(n_elements)) { order[i] = i; coords[i] = leaf->p[i][dir]; } QuickSortI(coords, order); int isplit = N/2; Leaf *leaf1 = (Leaf*) ball_leaves.Alloc(); new (leaf1) Leaf(); Leaf *leaf2 = (Leaf*) ball_leaves.Alloc(); new (leaf2) Leaf(); leaf1->nr = leaf->nr; leaf2->nr = leaves.Size(); leaves.Append(leaf2); leaves[leaf1->nr] = leaf1; for (auto i : order.Range(0,isplit)) leaf1->Add(leaves, leaf_index, leaf->p[i], leaf->index[i] ); for (auto i : order.Range(isplit, N)) leaf2->Add(leaves, leaf_index, leaf->p[i], leaf->index[i] ); Node *node1 = (Node*) ball_nodes.Alloc(); new (node1) Node(); node1->leaf = leaf1; node1->level = node->level+1; Node *node2 = (Node*) ball_nodes.Alloc(); new (node2) Node(); node2->leaf = leaf2; node2->level = node->level+1; node->children[0] = node1; node->children[1] = node2; node->sep = 0.5 * (leaf->p[order[isplit-1]][dir] + leaf->p[order[isplit]][dir]); // add new point to one of the new leaves if (p[dir] < node->sep) leaf1->Add( leaves, leaf_index, p, pi ); else leaf2->Add( leaves, leaf_index, p, pi ); ball_leaves.Free(leaf); n_leaves++; n_nodes+=2; } } void DeleteElement (T pi) { // static Timer timer("DelaunayTree::DeleteElement"); RegionTimer rt(timer); Leaf *leaf = leaves[leaf_index[pi]]; leaf_index[pi] = -1; auto & n_elements = leaf->n_elements; auto & index = leaf->index; auto & p = leaf->p; for (auto i : IntRange(n_elements)) { if(index[i] == pi) { n_elements--; if(i!=n_elements) { index[i] = index[n_elements]; p[i] = p[n_elements]; } return; } } } }; } #endif ================================================ FILE: libsrc/gprim/geom2d.cpp ================================================ #include #include #include 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= -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 } ================================================ FILE: libsrc/gprim/geom2d.hpp ================================================ #ifndef FILE_GEOM2D #define FILE_GEOM2D /* *************************************************************************/ /* File: geom2d.hh */ /* Author: Joachim Schoeberl */ /* Date: 5. Aug. 95 */ /* *************************************************************************/ #include #include #include "geomobjects.hpp" #include namespace netgen { /* Geometric Algorithms */ #define EPSGEOM 1E-5 DLL_HEADER 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, double eps); /// 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 /** 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 ================================================ FILE: libsrc/gprim/geom3d.cpp ================================================ #include #include #include #include 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()); } /* gcc4.8.3 warning: array subscript is above array bounds [-Warray-bounds] */ #ifdef __GNUC__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Warray-bounds" #endif 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; */ } #ifdef __GNUC__ #pragma GCC diagnostic pop #endif 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 NgArray & p, NgArray & 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(); } } ================================================ FILE: libsrc/gprim/geom3d.hpp ================================================ #ifndef FILE_GEOM3D #define FILE_GEOM3D /* *************************************************************************/ /* File: geom3d.hh */ /* Author: Joachim Schoeberl */ /* Date: 5. Aug. 95 */ /* *************************************************************************/ #include #include "geom2d.hpp" 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 DLL_HEADER 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 () { }; /// DLL_HEADER Box3d ( double aminx, double amaxx, double aminy, double amaxy, double aminz, double amaxz ); /// DLL_HEADER Box3d ( const Box3d & b2 ); /// DLL_HEADER Box3d (const Point3d& p1, const Point3d& p2); /// DLL_HEADER 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 NgArray & p, NgArray & pp) const; /// void FromPlain (const Point3d & pp, Point3d & p) const; }; } #endif ================================================ FILE: libsrc/gprim/geomfuncs.cpp ================================================ #include #include #include 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 = M_PI; 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; } } ================================================ FILE: libsrc/gprim/geomfuncs.hpp ================================================ #ifndef FILE_GEOMFUNCS #define FILE_GEOMFUNCS /* *************************************************************************/ /* File: geomfuncs.hpp */ /* Author: Joachim Schoeberl */ /* Date: 20. Jul. 02 */ /* *************************************************************************/ #include "geomobjects.hpp" #include "geomops.hpp" namespace netgen { template inline double Abs (const Vec & v) { double sum = 0; for (int i = 0; i < D; i++) sum += v(i) * v(i); return sqrt (sum); } template inline double Abs2 (const Vec & v) { double sum = 0; for (int i = 0; i < D; i++) sum += v(i) * v(i); return sum; } template inline double Dist (const Point & a, const Point & b) { return Abs (a-b); } template inline double Dist2 (const Point & a, const Point & b) { return Abs2 (a-b); } template inline Point Center (const Point & a, const Point & b) { Point res; for (int i = 0; i < D; i++) res(i) = 0.5 * (a(i) + b(i)); return res; } template inline Point Center (const Point & a, const Point & b, const Point & c) { Point res; for (int i = 0; i < D; i++) res(i) = (1.0/3.0) * (a(i) + b(i) + c(i)); return res; } template inline Point Center (const Point & a, const Point & b, const Point & c, const Point & d) { Point 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) template inline Vec<3,T> Cross (Vec<3,T> v1, Vec<3,T> v2) { return Vec<3,T> ( 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 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) { Vec<3> a0 = m.Row(0); Vec<3> a1 = m.Row(1); Vec<3> n = Cross(a0, a1); Vec<3> d0 = Cross(a1, n); Vec<3> d1 = Cross(a0, n); double s0 = 1.0/(a0*d0); double s1 = 1.0/(a1*d1); for (int i = 0; i < 3; i++) { inv(i,0) = s0*d0(i); inv(i,1) = s1*d1(i); } /* 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 DLL_HEADER void EigenValues (const Mat<3,3> & m, Vec<3> & ev); DLL_HEADER void EigenValues (const Mat<2,2> & m, Vec<3> & ev); template Vec<3,T> StableSolve (Mat<2,3,T> mat, Vec<2,T> rhs) { Vec<3> a0 = mat.Row(0); Vec<3> a1 = mat.Row(1); /* Vec<3> d = Cross ( Cross (a0, a1), a0); double alpha = rhs(0) / a0.Length2(); double beta = (rhs(1)-alpha* (a0*a1)) / (d*a1); return alpha * a0 + beta * d; */ Vec<3> n = Cross(a0, a1); Vec<3> d0 = Cross(a1, n); Vec<3> d1 = Cross(a0, n); double alpha = rhs(0) / (a0*d0); double beta = rhs(1) / (a1*d1); return alpha * d0 + beta * d1; } } #endif ================================================ FILE: libsrc/gprim/geomobjects.hpp ================================================ #ifndef FILE_OBJECTS #define FILE_OBJECTS /* *************************************************************************/ /* File: geomobjects.hpp */ /* Author: Joachim Schoeberl */ /* Date: 20. Jul. 02 */ /* *************************************************************************/ #include #include namespace netgen { using namespace ngcore; template class Vec; template class Point; template class Point { protected: T x[D]; public: Point () { ; } Point (T ax) { for (int i = 0; i < D; i++) x[i] = ax; } Point (T ax, T ay) { // static_assert(D==2, "Point constructor with 2 args called"); x[0] = ax; x[1] = ay; } Point (T ax, T ay, T az) { // static_assert(D==3, "Point constructor with 3 args called"); x[0] = ax; x[1] = ay; x[2] = az; } Point (T ax, T ay, T az, T au) { x[0] = ax; x[1] = ay; x[2] = az; x[3] = au;} template Point (const Point & p2) { for (int i = 0; i < D; i++) x[i] = p2(i); } explicit Point (const Vec & v) { for (int i = 0; i < D; i++) x[i] = v(i); } template Point & operator= (const Point & p2) { for (int i = 0; i < D; i++) x[i] = p2(i); return *this; } Point & operator= (T val) { for (int i = 0; i < D; i++) x[i] = val; return *this; } T & operator() (int i) { return x[i]; } const T & operator() (int i) const { return x[i]; } T& operator[] (int i) { return x[i]; } const T& operator[] (int i) const { return x[i]; } operator const T* () const { return x; } template void DoArchive(ARCHIVE& archive) { for(int i=0; i class Vec { protected: T x[D]; public: Vec () { ; } // for (int i = 0; i < D; i++) x[i] = 0; } Vec (T ax) { for (int i = 0; i < D; i++) x[i] = ax; } Vec (T ax, T ay) { // static_assert(D==2, "Vec constructor with 2 args called"); x[0] = ax; x[1] = ay; } Vec (T ax, T ay, T az) { // static_assert(D==3, "Vec constructor with 3 args called"); x[0] = ax; x[1] = ay; x[2] = az; } Vec (T ax, T ay, T az, T au) { x[0] = ax; x[1] = ay; x[2] = az; x[3] = au; } Vec (const Vec & p2) { for (int i = 0; i < D; i++) x[i] = p2.x[i]; } explicit Vec (const Point & p) { for (int i = 0; i < D; i++) x[i] = p(i); } explicit Vec(const Point& p1, const Point& p2) { for(int i=0; i Vec & operator= (const Vec & p2) { for (int i = 0; i < D; i++) x[i] = p2(i); return *this; } Vec & operator= (T s) { for (int i = 0; i < D; i++) x[i] = s; return *this; } bool operator== (const Vec &a) const { bool res = true; for (auto i : Range(D)) res &= (x[i]==a.x[i]); return res; } T & operator() (int i) { return x[i]; } const T & operator() (int i) const { return x[i]; } T& operator[] (int i) { return x[i]; } const T& operator[] (int i) const { return x[i]; } operator const T* () const { return x; } template void DoArchive(ARCHIVE& archive) { for(int i=0; i GetNormal () const; }; template inline ostream & operator<< (ostream & ost, const Vec & a) { ost << "("; for (int i = 0; i < D-1; i++) ost << a(i) << ", "; ost << a(D-1) << ")"; return ost; } template inline ostream & operator<< (ostream & ost, const Point & a) { ost << "("; for (int i = 0; i < D-1; i++) ost << a(i) << ", "; ost << a(D-1) << ")"; return ost; } template inline Vec operator-(const Point& p1, const Point& p2) { Vec result; for(auto i : Range(D)) result[i] = p1[i] - p2[i]; return result; } template inline Vec operator*(const Vec& v, double d) { Vec result; for(auto i : Range(D)) result[i] = d*v[i]; return result; } inline double Cross2(const Vec<2>& v1, const Vec<2>& v2) { return v1[0] * v2[1] - v1[1] * v2[0]; } // are points clockwise? inline bool CW(const Point<2>& p1, const Point<2>& p2, const Point<2>& p3) { return Cross2(p2-p1, p3-p2) < 0; } // are points counterclockwise? inline bool CCW(const Point<2>& p1, const Point<2>& p2, const Point<2>& p3) { return Cross2(p2-p1, p3-p2) > 0; } // are strictly points counterclockwise? inline bool CCW(const Point<2>& p1, const Point<2>& p2, const Point<2>& p3, double eps) { auto v1 = p2-p1; auto v2 = p3-p2; return Cross2(v1, v2) > eps*eps*max2(v1.Length2(), v2.Length2()); } template class Mat { protected: T x[H*W]; public: Mat () { ; } Mat (const Mat & b) { for (int i = 0; i < H*W; i++) x[i] = b.x[i]; } Mat & operator= (T 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; } T & operator() (int i, int j) { return x[i*W+j]; } const T & operator() (int i, int j) const { return x[i*W+j]; } T & operator() (int i) { return x[i]; } const T & operator() (int i) const { return x[i]; } Vec Col (int i) const { Vec hv; for (int j = 0; j < H; j++) hv(j) = x[j*W+i]; return hv; } Vec Row (int i) const { Vec hv; for (int j = 0; j < W; j++) hv(j) = x[i*W+j]; return hv; } void Solve (const Vec & rhs, Vec & sol) const { Mat inv; CalcInverse (*this, inv); sol = inv * rhs; } template void DoArchive(ARCHIVE & ar) { ar.Do(x, H*W); } }; template class Box { protected: Point pmin, pmax; public: Box () { ; } Box ( const Point & p1) { for (int i = 0; i < D; i++) pmin(i) = pmax(i) = p1(i); } Box ( const Point & p1, const Point & p2) { for (int i = 0; i < D; i++) { pmin(i) = min2(p1(i), p2(i)); pmax(i) = max2(p1(i), p2(i)); } } Box (const Point & p1, const Point & p2, const Point & p3) : Box(p1,p2) { Add (p3); } enum EB_TYPE { EMPTY_BOX = 1 }; Box ( EB_TYPE et ) { for (int i = 0; i < D; i++) { pmin(i) = 1e99; pmax(i) = -1e99; } } const Point & PMin () const { return pmin; } const Point & PMax () const { return pmax; } void Set (const Point & p) { pmin = pmax = p; } void Add (const Point & 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); // optimization invalid for empty-box ! } } template void Set (const NgIndirectArray & points) { // Set (points[points.Begin()]); Set (points[*points.Range().begin()]); // for (int i = points.Begin()+1; i < points.End(); i++) for (int i : points.Range().Modify(1,0)) Add (points[i]); } template void Add (const NgIndirectArray & points) { // for (int i = points.Begin(); i < points.End(); i++) for (int i : points.Range()) Add (points[i]); } Point Center () const { Point 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 GetPointNr (int nr) const { Point p; for (int i = 0; i < D; i++) { p(i) = (nr & 1) ? pmax(i) : pmin(i); nr >>= 1; } return p; } bool Intersect (const Box & 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 & p) const { for (int i = 0; i < D; i++) if (p(i) < pmin(i) || p(i) > pmax(i)) return false; return true; } // is point in eps-increased box bool IsIn (const Point & p, double eps) const { for (int i = 0; i < D; i++) if (p(i) < pmin(i)-eps || p(i) > pmax(i)+eps) return false; return true; } void Increase (double dist) { for (int i = 0; i < D; i++) { pmin(i) -= dist; pmax(i) += dist; } } void Scale (double factor) { auto center = Center(); pmin = center + factor*(pmin-center); pmax = center + factor*(pmax-center); } template void DoArchive(ARCHIVE & archive) { archive & pmin & pmax; } }; template class BoxSphere : public Box { protected: /// Point c; /// double diam; /// double inner; public: /// BoxSphere () { }; /// BoxSphere (const Box & box) : Box (box) { CalcDiamCenter(); }; /// BoxSphere ( Point apmin, Point apmax ) : Box (apmin, apmax) { CalcDiamCenter(); } /// const Point & 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::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); } }; #ifdef PARALLEL_OLD template <> inline MPI_Datatype MyGetMPIType > () { 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; }; #endif } #endif ================================================ FILE: libsrc/gprim/geomops.hpp ================================================ #ifndef FILE_GEOMOPS #define FILE_GEOMOPS /* *************************************************************************/ /* File: geomops.hpp */ /* Author: Joachim Schoeberl */ /* Date: 20. Jul. 02 */ /* *************************************************************************/ namespace netgen { /* Point - Vector operations */ template inline Vec operator+ (Vec a, Vec b) { Vec res; for (int i = 0; i < D; i++) res(i) = a(i) + b(i); return res; } template inline Point operator+ (Point a, Vec b) { Point res; for (int i = 0; i < D; i++) res(i) = a(i) + b(i); return res; } template inline Vec operator- (Point a, Point b) { Vec res; for (int i = 0; i < D; i++) res(i) = a(i) - b(i); return res; } template inline Point operator- (Point a, Vec b) { Point res; for (int i = 0; i < D; i++) res(i) = a(i) - b(i); return res; } template inline Vec operator- (Vec a, Vec b) { Vec res; for (int i = 0; i < D; i++) res(i) = a(i) - b(i); return res; } template inline Vec operator* (T s, Vec b) { Vec res; for (int i = 0; i < D; i++) res(i) = s * b(i); return res; } template inline Vec> operator* (SIMD s, Vec b) { Vec> res; for (int i = 0; i < D; i++) res(i) = s * b(i); return res; } template inline double operator* (Vec a, Vec b) { double sum = 0; for (int i = 0; i < D; i++) sum += a(i) * b(i); return sum; } template inline Vec operator- (Vec b) { Vec res; for (int i = 0; i < D; i++) res(i) = -b(i); return res; } template inline Point & operator+= (Point & a, Vec b) { for (int i = 0; i < D; i++) a(i) += b(i); return a; } template inline Vec & operator+= (Vec & a, Vec b) { for (int i = 0; i < D; i++) a(i) += b(i); return a; } template inline Point & operator-= (Point & a, const Vec & b) { for (int i = 0; i < D; i++) a(i) -= b(i); return a; } template inline Vec & operator-= (Vec & a, const Vec & b) { for (int i = 0; i < D; i++) a(i) -= b(i); return a; } template inline Vec & operator*= (Vec & a, T2 s) { for (int i = 0; i < D; i++) a(i) *= s; return a; } template inline Vec & operator/= (Vec & a, double s) { for (int i = 0; i < D; i++) a(i) /= s; return a; } // Matrix - Vector operations /* template inline Vec operator* (const Mat & m, const Vec & v) { Vec 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 inline Mat operator* (const Mat & a, const Mat & b) { Mat 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; } */ template inline Mat<2,2,T> operator* (const Mat<2,2,T> & a, const Mat<2,2,T> & b) { Mat<2,2,T> m; for (int i = 0; i < 2; i++) for (int j = 0; j < 2; j++) { T 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; } template inline Mat<3,2,T> operator* (const Mat<3,2,T> & a, const Mat<2,2,T> & b) { Mat<3,2,T> m; for (int i = 0; i < 3; i++) for (int j = 0; j < 2; j++) { T sum(0.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; } template inline Mat<3,3,T> operator* (const Mat<3,3,T> & a, const Mat<3,3,T> & b) { Mat<3,3,T> m; for (int i = 0; i < 3; i++) for (int j = 0; j < 3; j++) { T sum = T(0); for (int k = 0; k < 3; k++) sum += a(i,k) * b(k, j); m(i,j) = sum; } return m; } template inline Mat Trans (const Mat & m) { Mat res; for (int i = 0; i < H; i++) for (int j = 0; j < W; j++) res(j,i) = m(i,j); return res; } template inline ostream & operator<< (ostream & ost, const Vec & a) { ost << "("; for (int i = 0; i < D-1; i++) ost << a(i) << ", "; ost << a(D-1) << ")"; return ost; } template inline ostream & operator<< (ostream & ost, const Point & a) { ost << "("; for (int i = 0; i < D-1; i++) ost << a(i) << ", "; ost << a(D-1) << ")"; return ost; } template inline ostream & operator<< (ostream & ost, const Box & b) { ost << b.PMin() << " - " << b.PMax(); return ost; } template inline ostream & operator<< (ostream & ost, const Mat & 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 ================================================ FILE: libsrc/gprim/geomtest3d.cpp ================================================ #include #include #include #include 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); Mat<3,3> a, ainv; Vec<3> rs, lami; 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 det = Det(a); 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); lami = ainv * rs; // (*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(0) * vl ) << endl << " = " << ( *tri[0] + lami(1) * vt1 + lami(2) * 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 MinDistLP2 (const Point3d & lp1, const Point3d & lp2, const Point3d & p, double & lam) { 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) { lam = 0.0; return Dist2 (lp1, p); } if (num >= den) { lam = 1.0; return Dist2 (lp2, p); } lam = num/den; 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, double & lam1, double & lam2 ) { // 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 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, lam1); lam2 = 0.; hv = MinDistLP2 (l1p1, l1p2, l2p2, lam1); if (hv < minv) { lam2 = 1.; minv = hv; } hv = MinDistLP2 (l2p1, l2p2, l1p1, lam2); if (hv < minv) { lam1 = 0.; minv = hv; } hv = MinDistLP2 (l2p1, l2p2, l1p2, lam2); if (hv < minv) { lam1 = 1.; minv = hv; } return minv; } } ================================================ FILE: libsrc/gprim/geomtest3d.hpp ================================================ #ifndef FILE_GEOMTEST3D #define FILE_GEOMTEST3D /* *************************************************************************/ /* File: geomtest3d.hh */ /* Author: Joachim Schoeberl */ /* Date: 13. Feb. 98 */ /* *************************************************************************/ #include "geom3d.hpp" #include "geomobjects.hpp" 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] DLL_HEADER double MinDistLP2 (const Point2d & lp1, const Point2d & lp2, const Point2d & p); /// Minimal distance of point p to the line segment [lp1,lp2] DLL_HEADER double MinDistLP2 (const Point3d & lp1, const Point3d & lp2, const Point3d & p); /// Minimal distance of point p to the triangle segment [tp1,tp2,pt3] DLL_HEADER double MinDistTP2 (const Point3d & tp1, const Point3d & tp2, const Point3d & tp3, const Point3d & p); inline double MinDistTP2 (const Point<2> & tp1, const Point<2> & tp2, const Point<2> & tp3, const Point<2> & p) { return MinDistTP2 (Point<3> (tp1(0), tp1(1),0), Point<3> (tp2(0), tp2(1),0), Point<3> (tp3(0), tp3(1),0), Point<3> (p(0), p(1),0)); } /// 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); extern double MinDistLL2 (const Point3d & l1p1, const Point3d & l1p2, const Point3d & l2p1, const Point3d & l2p2, double & lam1, double & lam2 ); } #endif ================================================ FILE: libsrc/gprim/gprim.hpp ================================================ #ifndef FILE_GPRIM #define FILE_GPRIM /* *************************************************************************/ /* File: gprim.hpp */ /* Author: Joachim Schoeberl */ /* Date: 14. Aug. 97 */ /* *************************************************************************/ #include #include #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 ================================================ FILE: libsrc/gprim/spline.cpp ================================================ /* Spline curve for Mesh generator */ #include #include #include #include "spline.hpp" #include namespace netgen { // just for testing (JS) template void ProjectTrivial (const SplineSeg3 & seg, const Point point, Point & point_on_curve, double & t) { double mindist = -1; for (int i = 0; i <= 1000; i++) { double ht = double(i)/1000; Point 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, NgArray < 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, NgArray < 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; NgArray 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 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 SplineSeg3 :: SplineSeg3 (const GeomPoint & ap1, const GeomPoint & ap2, const GeomPoint & ap3, string bcname, double maxh) : SplineSeg(maxh, bcname), 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 SplineSeg3 :: SplineSeg3 (const GeomPoint & ap1, const GeomPoint & ap2, const GeomPoint & ap3, double aweight, string bcname, double maxh) : SplineSeg(maxh, bcname), p1(ap1), p2(ap2), p3(ap3), weight(aweight) { proj_latest_t = 0.5; } template Point SplineSeg3 :: GetPoint (double t) const { double b1, b2, b3; b1 = (1-t)*(1-t); b2 = weight * t * (1-t); b3 = t * t; Vec hp = b1 * Vec(p1) + b2 * Vec(p2) + b3 * Vec(p3); double w = b1+b2+b3; return Point ((1.0/w)*hp); /* double x, y, w; 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 (x/w, y/w, z/w); } else return Point (x/w, y/w); */ } template Vec SplineSeg3 :: 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 retval; for(int i=0; i void SplineSeg3 :: 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 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 p0 = GetPoint(0); Vec 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 void SplineSeg3 :: GetCoeff (Vector & u, Point pref) 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) { Vec p = GetPoint (t)-pref; 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 p0 = GetPoint(0); Vec ht = GetTangent(0); Vec<2> tang(ht(0), ht(1)); double gradx = u(3); double grady = u(4); // 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 void SplineSeg3 :: Project (const Point point, Point & 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; */ double tmin = 1; double dist_min2 = Dist2 (GetPoint(tmin), point); for (double ti = 0; ti < 0.99; ti += 0.25) { double di = Dist2(GetPoint(ti), point); if (di < dist_min2) { tmin = ti; dist_min2 = di; } } t = tmin; Point phi; Vec 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::GetPoint(t); double dist = Dist(point,point_on_curve); phi = SplineSeg3 ::GetPoint(0); double auxdist = Dist(phi,point); if(auxdist < dist) { t = 0.; point_on_curve = phi; dist = auxdist; } phi = SplineSeg3 ::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 ::GetPoint(t0); d0 = Dist(phi,point); phi = SplineSeg3 ::GetPoint(t1); d1 = Dist(phi,point); phi = SplineSeg3 ::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 ::GetPoint(t0); d0 = Dist(phi,point); phi = SplineSeg3 ::GetPoint(t1); d1 = Dist(phi,point); phi = SplineSeg3 ::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 ::GetPoint(t); } //(*testout) << " latest_t " << proj_latest_t << " t " << t << endl; proj_latest_t = t; /* // test it by trivial sampling double ht; Point 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 void SplineSeg3 :: GetDerivatives (const double t, Point & point, Vec & first, Vec & second) const { Vec 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 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 void SplineSeg3 :: LineIntersections (const double a, const double b, const double c, NgArray < Point > & 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 :: GetRawData (NgArray & data) const { data.Append(3); for(int i=0; i; template class SplineSeg3<3>; RegisterClassForArchive> regss2; RegisterClassForArchive> regss3; RegisterClassForArchive, SplineSeg<2>> regls2; RegisterClassForArchive, SplineSeg<3>> regls3; RegisterClassForArchive, SplineSeg<2>> regsss2; RegisterClassForArchive, SplineSeg<3>> regsss3; } ================================================ FILE: libsrc/gprim/spline.hpp ================================================ #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 { public: /// refinement factor at point double refatpoint; /// max mesh-size at point double hmax; /// hp-refinement double hpref; /// string name; /// GeomPoint () { ; } /// GeomPoint (const Point & ap, double aref = 1, double ahpref=0) : Point(ap), refatpoint(aref), hmax(1e99), hpref(ahpref) { ; } void DoArchive(Archive& ar) { Point::DoArchive(ar); ar & refatpoint & hmax & hpref; } }; /// base class for 2d - segment template < int D > class SplineSeg { double maxh; string bcname; public: SplineSeg (double amaxh = 1e99, string abcname = "default") : maxh(amaxh), bcname(abcname) { ; } /// virtual ~SplineSeg() { ; } /// calculates length of curve virtual double Length () const; /// returns point at curve, 0 <= t <= 1 virtual Point GetPoint (double t) const = 0; /// returns a (not necessarily unit-length) tangent vector for 0 <= t <= 1 virtual Vec GetTangent (const double t) const { cerr << "GetTangent not implemented for spline base-class" << endl; Vec dummy; return dummy; } virtual void GetDerivatives (const double t, Point & point, Vec & first, Vec & second) const { double eps = 1e-6; point = GetPoint (t); Point pl = GetPoint (t-eps); Point pr = GetPoint (t+eps); first = 1.0/(2*eps) * (pr-pl); second = 1.0/sqr(eps) * ( (pr-point)+(pl-point)); } virtual void DoArchive(Archive& ar) = 0; /// returns initial point on curve virtual const GeomPoint & StartPI () const = 0; /// returns terminal point on curve virtual const GeomPoint & 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 GetCoeff (Vector & coeffs, Point p0) const { ; } virtual void GetPoints (int n, NgArray > & points) const; /** calculates (2D) lineintersections: for lines $$ a x + b y + c = 0 $$ the intersecting points are calculated and stored in points */ virtual void LineIntersections (const double a, const double b, const double c, NgArray < Point > & points, const double eps) const {points.SetSize(0);} // is the point in the convex hull (increased by eps) of the spline ? virtual bool InConvexHull (Point p, double eps) const = 0; virtual double MaxCurvature(void) const = 0; virtual string GetType(void) const {return "splinebase";} virtual void Project (const Point point, Point & point_on_curve, double & t) const { cerr << "Project not implemented for spline base-class" << endl;} virtual void GetRawData (NgArray & data) const { cerr << "GetRawData not implemented for spline base-class" << endl;} double GetMaxh() const { return maxh; } string GetBCName() const { return bcname; } }; /// Straight line form p1 to p2 template< int D > class LineSeg : public SplineSeg { /// GeomPoint p1, p2; public: /// LineSeg (const GeomPoint & ap1, const GeomPoint & ap2, double maxh=1e99, string bcname="default"); /// // default constructor for archive LineSeg() {} virtual void DoArchive(Archive& ar) { ar & p1 & p2; } virtual double Length () const; /// inline virtual Point GetPoint (double t) const; /// virtual Vec GetTangent (const double t) const; virtual void GetDerivatives (const double t, Point & point, Vec & first, Vec & second) const; /// virtual const GeomPoint & StartPI () const { return p1; }; /// virtual const GeomPoint & EndPI () const { return p2; } /// virtual void GetCoeff (Vector & coeffs) const; virtual void GetCoeff (Vector & coeffs, Point p0) const; virtual string GetType(void) const {return "line";} virtual void LineIntersections (const double a, const double b, const double c, NgArray < Point > & points, const double eps) const; virtual bool InConvexHull (Point p, double eps) const { return MinDistLP2 (p1, p2, p) < sqr(eps); } virtual double MaxCurvature(void) const {return 0;} virtual void Project (const Point point, Point & point_on_curve, double & t) const; virtual void GetRawData (NgArray & data) const; }; /// curve given by a rational, quadratic spline (including ellipses) template< int D > class SplineSeg3 : public SplineSeg { /// GeomPoint p1, p2, p3; double weight; mutable double proj_latest_t; public: /// DLL_HEADER SplineSeg3 (const GeomPoint & ap1, const GeomPoint & ap2, const GeomPoint & ap3, string bcname="default", double maxh=1e99); DLL_HEADER SplineSeg3 (const GeomPoint & ap1, const GeomPoint & ap2, const GeomPoint & ap3, double aweight, string bcname="default", double maxh=1e99); // default constructor for archive SplineSeg3() {} /// virtual void DoArchive(Archive& ar) { ar & p1 & p2 & p3 & weight & proj_latest_t; } /// double GetWeight () const { return weight; } void SetWeight (double w) { weight = w; } /// DLL_HEADER virtual Point GetPoint (double t) const; /// DLL_HEADER virtual Vec GetTangent (const double t) const; DLL_HEADER virtual void GetDerivatives (const double t, Point & point, Vec & first, Vec & second) const; /// DLL_HEADER virtual const GeomPoint & StartPI () const { return p1; }; /// DLL_HEADER virtual const GeomPoint & EndPI () const { return p3; } /// DLL_HEADER virtual void GetCoeff (Vector & coeffs) const; DLL_HEADER virtual void GetCoeff (Vector & coeffs, Point p0) const; virtual string GetType(void) const {return "spline3";} const GeomPoint & TangentPoint (void) const { return p2; } DLL_HEADER virtual void LineIntersections (const double a, const double b, const double c, NgArray < Point > & points, const double eps) const; virtual bool InConvexHull (Point p, double eps) const { return MinDistTP2 (p1, p2, p3, p) < sqr(eps); } DLL_HEADER virtual double MaxCurvature(void) const; DLL_HEADER virtual void Project (const Point point, Point & point_on_curve, double & t) const; DLL_HEADER virtual void GetRawData (NgArray & data) const; }; // Gundolf Haase 8/26/97 /// A circle template < int D > class CircleSeg : public SplineSeg { /// private: GeomPoint p1, p2, p3; //const GeomPoint &p1, &p2, &p3; Point pm; double radius, w1,w3; public: /// CircleSeg (const GeomPoint & ap1, const GeomPoint & ap2, const GeomPoint & ap3); // default constructor for archive CircleSeg() {} virtual void DoArchive(Archive& ar) { ar & p1 & p2 & p3 & pm & radius & w1 & w3; } /// virtual Point GetPoint (double t) const; /// virtual const GeomPoint & StartPI () const { return p1; } /// virtual const GeomPoint & 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 & MidPoint(void) const {return pm; } virtual string GetType(void) const {return "circle";} virtual void LineIntersections (const double a, const double b, const double c, NgArray < Point > & points, const double eps) const; virtual bool InConvexHull (Point p, double eps) const { return (Dist2 (p, pm) < sqr(radius+eps)); } virtual double MaxCurvature(void) const {return 1./radius;} }; /// template class DiscretePointsSeg : public SplineSeg { NgArray > pts; GeomPoint p1n, p2n; public: /// DiscretePointsSeg (const NgArray > & apts); // default constructor for archive DiscretePointsSeg() {} virtual void DoArchive(Archive& ar) { ar & pts & p1n & p2n; } /// virtual ~DiscretePointsSeg (); /// virtual Point GetPoint (double t) const; /// virtual const GeomPoint & StartPI () const { return p1n; }; /// virtual const GeomPoint & EndPI () const { return p2n; } /// virtual void GetCoeff (Vector & coeffs) const {;} virtual double MaxCurvature(void) const {return 1;} // needs implementation ... virtual bool InConvexHull (Point p, double eps) const { return true; } }; // calculates length of spline-curve template double SplineSeg :: Length () const { int n = 100; double dt = 1.0 / n; Point pold = GetPoint (0); double l = 0; for (int i = 1; i <= n; i++) { Point p = GetPoint (i * dt); l += Dist (p, pold); pold = p; } return l; } template void SplineSeg :: GetPoints (int n, NgArray > & points) const { points.SetSize (n); if (n >= 2) for (int i = 0; i < n; i++) points[i] = GetPoint(double(i) / (n-1)); } template void SplineSeg :: 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 LineSeg :: LineSeg (const GeomPoint & ap1, const GeomPoint & ap2, double maxh, string bcname) : SplineSeg(maxh, bcname), p1(ap1), p2(ap2) { ; } template inline Point LineSeg :: GetPoint (double t) const { return p1 + t * (p2 - p1); } template Vec LineSeg :: GetTangent (const double t) const { return p2-p1; } template void LineSeg :: GetDerivatives (const double t, Point & point, Vec & first, Vec & second) const { first = p2 - p1; point = p1 + t * first; second = 0; } template double LineSeg :: Length () const { return Dist (p1, p2); } template void LineSeg :: 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 void LineSeg :: GetCoeff (Vector & coeffs, Point p) 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)-p(1)) + dy * (p1(0)-p(0)); } template void LineSeg :: LineIntersections (const double a, const double b, const double c, NgArray < Point > & 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 void LineSeg :: Project (const Point point, Point & point_on_curve, double & t) const { Vec 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 void LineSeg :: GetRawData (NgArray & data) const { data.Append(2); for(int i=0; i double SplineSeg3 :: MaxCurvature(void) const { Vec v1 = p1-p2; Vec 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 CircleSeg :: CircleSeg (const GeomPoint & ap1, const GeomPoint & ap2, const GeomPoint & ap3) : p1(ap1), p2(ap2), p3(ap3) { Vec v1,v2; v1 = p1 - p2; v2 = p3 - p2; Point p1t(p1+v1); Point 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 Point CircleSeg :: GetPoint (double t) const { if (t >= 1.0) { return p3; } double phi = StartAngle() + t*(EndAngle()-StartAngle()); Vec tmp(cos(phi),sin(phi)); return pm + Radius()*tmp; } */ template<> inline Point<3> CircleSeg<3> :: GetPoint (double t) const { // not really useful, but keep it as it was ... if (t >= 1.0) { return p3; } double phi = StartAngle() + t*(EndAngle()-StartAngle()); Vec<3> tmp(cos(phi),sin(phi),0); return pm + Radius()*tmp; } template<> inline Point<2> CircleSeg<2> :: GetPoint (double t) const { if (t >= 1.0) { return p3; } double phi = StartAngle() + t*(EndAngle()-StartAngle()); Vec<2> tmp(cos(phi),sin(phi)); return pm + Radius()*tmp; } template void CircleSeg :: 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 DiscretePointsSeg :: DiscretePointsSeg (const NgArray > & apts) : pts (apts) { for(int i=0; i DiscretePointsSeg :: ~DiscretePointsSeg () { ; } template Point DiscretePointsSeg :: 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(pts[segnr+1]-pts[segnr]); } // ************************************* // Template for B-Splines of order ORDER // thx to Gerhard Kitzler // ************************************* template class BSplineSeg : public SplineSeg { NgArray > pts; GeomPoint p1n, p2n; NgArray ti; public: /// BSplineSeg (const NgArray > & apts); /// //default constructor for archive BSplineSeg() {} virtual ~BSplineSeg(); /// virtual void DoArchive(Archive& ar) { ar & pts & p1n & p2n & ti; } virtual Point GetPoint (double t) const; /// virtual const GeomPoint & StartPI () const { return p1n; }; /// virtual const GeomPoint & EndPI () const { return p2n; } /// virtual void GetCoeff (Vector & coeffs) const {;} virtual double MaxCurvature(void) const {return 1;} // needs implementation ... virtual bool InConvexHull (Point p, double eps) const { return true; } }; // Constructor template BSplineSeg :: BSplineSeg (const NgArray > & apts) : pts (apts) { /* for(int i=0; i BSplineSeg :: ~BSplineSeg () { ; } // GetPoint Method...(evaluation of BSpline Curve) template Point BSplineSeg :: 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 p = 0.0; for(int i=0; i < ORDER; i++) p += b[i] * Vec (pts[i+interval_nr-ORDER+1]); return p; } } #endif ================================================ FILE: libsrc/gprim/splinegeometry.cpp ================================================ /* 2d Spline curve for Mesh generator */ #include #include #include #include #include "splinegeometry.hpp" namespace netgen { template SplineGeometry :: ~SplineGeometry() { for(int i = 0; i < splines.Size(); i++) delete splines[i]; } template void SplineGeometry :: GetRawData (NgArray & raw_data) const { raw_data.Append(D); // raw_data.Append(elto0); raw_data.Append(splines.Size()); for(int i=0; iGetRawData(raw_data); } template int SplineGeometry :: Load (const NgArray & 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++; NgArray< Point > pts(3); for(int i=0; i(GeomPoint(pts[0],1), GeomPoint(pts[1],1)); } else if (type == 3) { splines[i] = new SplineSeg3(GeomPoint(pts[0],1), GeomPoint(pts[1],1), GeomPoint(pts[2],1)); } else throw NgException("something wrong with spline raw data"); } return pos; } template void SplineGeometry :: GetBoundingBox (Box & box) const { if (!splines.Size()) { Point auxp = 0.; box.Set (auxp); return; } NgArray > 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 void SplineGeometry :: SetGrading (const double grading) { elto0 = grading; } */ template void SplineGeometry :: AppendPoint (const Point & p, const double reffac, const bool hpref) { geompoints.Append (GeomPoint(p, reffac)); geompoints.Last().hpref = hpref; } template class SplineGeometry<2>; template class SplineGeometry<3>; static RegisterClassForArchive> regsp2; static RegisterClassForArchive> regsp3; } ================================================ FILE: libsrc/gprim/splinegeometry.hpp ================================================ /* 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 DLL_HEADER SplineGeometry { // protected: public: NgArray < GeomPoint > geompoints; NgArray < SplineSeg* > splines; SplineGeometry() : geompoints{}, splines{} { ; } virtual ~SplineGeometry(); int Load (const NgArray & raw_data, const int startpos = 0); virtual void DoArchive(Archive& ar) { ar & geompoints & splines; } void GetRawData (NgArray & raw_data) const; const NgArray*> & GetSplines () const { return splines; } int GetNSplines (void) const { return splines.Size(); } string GetSplineType (const int i) const { return splines[i]->GetType(); } SplineSeg & GetSpline (const int i) {return *splines[i];} const SplineSeg & GetSpline (const int i) const {return *splines[i];} void GetBoundingBox (Box & box) const; Box GetBoundingBox () const { Box box; GetBoundingBox (box); return box; } int GetNP () const { return geompoints.Size(); } const GeomPoint & GetPoint(int i) const { return geompoints[i]; } // void SetGrading (const double grading); void AppendPoint (const Point & p, const double reffac = 1., const bool hpref = false); void AppendSegment(SplineSeg * spline) { splines.Append (spline); } }; } #endif // _FILE_SPLINEGEOMETRY ================================================ FILE: libsrc/gprim/transform3d.cpp ================================================ #include #include #include #include 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; } template <> Transformation<3> :: Transformation (const Point<3> & c, const Vec<3> & axes, double angle) { Vec<3> vc(c); Transformation<3> tc(vc); Transformation<3> tcinv(-vc); Transformation<3> r, ht, ht2; // r.SetAxisRotation (3, alpha); Vec<3> naxes = axes; naxes.Normalize(); Vec<3> n1 = naxes.GetNormal(); Vec<3> n2 = Cross(naxes, n1); r.v = Vec<3>(0,0,0); double co = cos(angle); double si = sin(angle); for (int i = 0; i < 3; i++) for (int j = 0; j < 3; j++) r.m(i,j) = naxes(i)*naxes(j) + co*(n1(i)*n1(j)+n2(i)*n2(j)) + si*( (n2(i)*n1(j)-n2(j)*n1(i)) ); ht.Combine (tc, r); Combine (ht, tcinv); } template Transformation :: Transformation (const Point * pp) { v = Vec (pp[0]); for (int i = 0; i < D; i++) for (int j = 0; j < D; j++) m(j,i) = pp[i+1](j)-pp[0](j); } template class Transformation<3>; } ================================================ FILE: libsrc/gprim/transform3d.hpp ================================================ #ifndef FILE_TRANSFORM3D #define FILE_TRANSFORM3D /* *************************************************************************/ /* File: transform3d.hh */ /* Author: Joachim Schoeberl */ /* Date: 22. Mar. 98 */ /* *************************************************************************/ /* Affine - Linear mapping in 3D space */ #include "geom3d.hpp" #include "geomfuncs.hpp" 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 described by pp Transformation3d (const Point3d ** pp); /// Unit tet is mapped to tet described 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 class Transformation { Mat m; Vec v; public: /// Transformation () { m = 0; v = 0; } /// Unit tet is mapped to tet described by pp Transformation (const Point * pp); /// translation Transformation (const Vec & translate) { v = translate; m = 0; for (int i = 0; i < D; i++) m(i,i) = 1; } Transformation (const Point & c, const Vec<3> & axes, double angle); // rotation with ... Transformation (const Point & 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 vc(c); Transformation tc(vc); Transformation tcinv(-vc); // tc.CalcInverse (tcinv); Transformation 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; } Mat & GetMatrix() { return m; } Vec & GetVector() { return v; } void DoArchive(Archive& ar) { ar & m & v; } /// Transformation CalcInverse () const { Transformation inv; // inv.m = Inv(m); ::netgen::CalcInverse (m, inv.m); inv.v = inv.m * (-v); return inv; } /// 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 & from, Point & to) const { to = Point (v + m * Vec(from)); } void Transform (Point & p) const { p = Point (v + m * Vec(p)); } /// transform vector, apply only linear part, not offset void Transform (const Vec & from, Vec & to) const { to = m * from; } Point operator() (Point from) const { Point to; Transform(from, to); return to; } Vec operator() (Vec from) const { Vec to; Transform(from, to); return to; } }; template ostream & operator<< (ostream & ost, Transformation & trans); } #endif ================================================ FILE: libsrc/include/CMakeLists.txt ================================================ install(FILES nginterface.h nginterface_v2.hpp mydefs.hpp DESTINATION ${NG_INSTALL_DIR_INCLUDE} COMPONENT netgen_devel) install(FILES acisgeom.hpp csg.hpp geometry2d.hpp gprim.hpp incopengl.hpp inctcl.hpp incvis.hpp linalg.hpp meshing.hpp myadt.hpp mydefs.hpp mystdlib.h nginterface_v2_impl.hpp occgeom.hpp ngsimd.hpp opti.hpp parallel.hpp stlgeom.hpp visual.hpp DESTINATION ${NG_INSTALL_DIR_INCLUDE}/include COMPONENT netgen_devel ) ================================================ FILE: libsrc/include/acisgeom.hpp ================================================ #ifdef ACIS #include "../acisgeom/acisgeom.hpp" #endif ================================================ FILE: libsrc/include/csg.hpp ================================================ #include "../csg/csg.hpp" ================================================ FILE: libsrc/include/geometry2d.hpp ================================================ #include "../geom2d/geometry2d.hpp" ================================================ FILE: libsrc/include/gprim.hpp ================================================ #include "../gprim/gprim.hpp" ================================================ FILE: libsrc/include/incopengl.hpp ================================================ #ifndef INCOPENGL_HPP___ #define INCOPENGL_HPP___ #define GL_GLEXT_PROTOTYPES #include #include #ifdef WIN32 #define WIN32_LEAN_AND_MEAN #include #endif # ifdef __APPLE__ #define GL_SILENCE_DEPRECATION #define GL_DO_NOT_WARN_IF_MULTI_GL_VERSION_HEADERS_INCLUDED # include # include # else # include # include # endif #ifdef TOGL_X11 // parallel #define GLX_GLXEXT_PROTOTYPES #include #include #endif #ifdef WIN32 // part of OpenGL 1.2, but not in Microsoft's OpenGL 1.1 header: // GL version should be checked at runtime #define GL_CLAMP_TO_EDGE 0x812F #define GL_ARRAY_BUFFER 0x8892 #define GL_ELEMENT_ARRAY_BUFFER 0x8893 #define GL_STATIC_DRAW 0x88E4 #define GL_FRAMEBUFFER_COMPLETE 0x8CD5 #define GL_FRAMEBUFFER 0x8D40 #define GL_RENDERBUFFER 0x8D41 #define GL_DEPTH_ATTACHMENT 0x8D00 #define GL_COLOR_ATTACHMENT0 0x8CE0 typedef ptrdiff_t GLintptr; typedef ptrdiff_t GLsizeiptr; extern void (*glBindBuffer) (GLenum a, GLuint b); extern void (*glDeleteBuffers) (GLsizei a, const GLuint *b); extern void (*glGenBuffers) (GLsizei a, GLuint *b); extern void (*glBufferData) (GLenum a, GLsizeiptr b, const GLvoid *c, GLenum d); extern void (*glBufferSubData) (GLenum a, GLintptr b, GLsizeiptr c, const GLvoid *d); extern GLenum (*glCheckFramebufferStatus) (GLenum target); extern void (*glBindFramebuffer) (GLenum target, GLuint framebuffer); extern void (*glBindRenderbuffer) (GLenum target, GLuint renderbuffer); extern void (*glDeleteFramebuffers) (GLsizei n, const GLuint *framebuffers); extern void (*glDeleteRenderbuffers) (GLsizei n, const GLuint *renderbuffers); extern void (*glGenFramebuffers) (GLsizei n, GLuint *framebuffers); extern void (*glGenRenderbuffers) (GLsizei n, GLuint *renderbuffers); extern void (*glRenderbufferStorage) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); extern void (*glFramebufferRenderbuffer) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); #endif DLL_HEADER void LoadOpenGLFunctionPointers(); #endif // INCOPENGL_HPP___ ================================================ FILE: libsrc/include/inctcl.hpp ================================================ #ifdef WIN32 #define WIN32_LEAN_AND_MEAN #include #endif #include #include #if TK_MAJOR_VERSION==8 && TK_MINOR_VERSION>=4 #define tcl_const const #else #define tcl_const #endif ================================================ FILE: libsrc/include/incvis.hpp ================================================ // libraries for User interface: nicht mehr verwendet #include "inctcl.hpp" #include "incopengl.hpp" ================================================ FILE: libsrc/include/linalg.hpp ================================================ #include "../linalg/linalg.hpp" ================================================ FILE: libsrc/include/meshing.hpp ================================================ #include <../meshing/meshing.hpp> ================================================ FILE: libsrc/include/myadt.hpp ================================================ #include <../general/myadt.hpp> ================================================ FILE: libsrc/include/mydefs.hpp ================================================ #ifndef FILE_MYDEFS #define FILE_MYDEFS /**************************************************************************/ /* File: mydefs.hh */ /* Author: Joachim Schoeberl */ /* Date: 10. Mar. 98 */ /**************************************************************************/ /* defines for graphics, testmodes, ... */ #include #define PACKAGE_VERSION "6.2-dev" // #define DEBUG #if defined(nglib_EXPORTS) #define DLL_HEADER NGCORE_API_EXPORT #else #define DLL_HEADER NGCORE_API_IMPORT #endif #ifndef __assume #ifdef __GNUC__ #define __assume(cond) if (!(cond)) __builtin_unreachable(); else; #else #define __assume(cond) #endif #endif #ifndef NG_INLINE #ifdef __INTEL_COMPILER #ifdef WIN32 #define NG_INLINE __forceinline inline #else #define NG_INLINE __forceinline inline #endif #else #ifdef __GNUC__ #define NG_INLINE __attribute__ ((__always_inline__)) inline #define VLA #else #define NG_INLINE inline #endif #endif #endif // #define BASE0 // #define DEBUG #define noDEMOVERSION #define noDEVELOP #define noSTEP #define noSOLIDGEOM #define noDEMOAPP #define noMODELLER #define noSTAT_STREAM #define noLOG_STREAM #endif ================================================ FILE: libsrc/include/mystdlib.h ================================================ #ifndef FILE_MYSTDLIB #define FILE_MYSTDLIB #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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 # else // # include // # include # endif // MSVC_EXPRESS # endif // # include # undef WIN32_LEAN_AND_MEAN // # include #else // Not using MC VC++ #endif // using namespace std; namespace netgen { using namespace std; } #endif ================================================ FILE: libsrc/include/nginterface.h ================================================ #ifndef NGINTERFACE #define NGINTERFACE /**************************************************************************/ /* File: nginterface.h */ /* Author: Joachim Schoeberl */ /* Date: 20. Nov. 99 */ /**************************************************************************/ #include "mydefs.hpp" #include /* Application program interface to Netgen */ // max number of nodes per element #define NG_ELEMENT_MAXPOINTS 20 // max number of nodes per surface element #define NG_SURFACE_ELEMENT_MAXPOINTS 8 // #ifndef PARALLEL // typedef int MPI_Comm; // #endif // namespace netgen { extern DLL_HEADER ngcore::NgMPI_Comm ng_comm; } // implemented element types: enum NG_ELEMENT_TYPE { NG_PNT = 0, NG_SEGM = 1, NG_SEGM3 = 2, NG_TRIG = 10, NG_QUAD=11, NG_TRIG6 = 12, NG_QUAD6 = 13, NG_QUAD8 = 14, NG_TET = 20, NG_TET10 = 21, NG_PYRAMID = 22, NG_PRISM = 23, NG_PRISM12 = 24, NG_PRISM15 = 27, NG_PYRAMID13 = 28, NG_HEX = 25, NG_HEX20 = 26, NG_HEX7 = 29 }; 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 geometry from file DLL_HEADER void Ng_LoadGeometry (const char * filename); // load netgen mesh DLL_HEADER void Ng_LoadMesh (const char * filename, ngcore::NgMPI_Comm comm = ngcore::NgMPI_Comm{}); // 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 coordinates, 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 const char * Ng_GetElementMaterial (int ei); // Get Material of domain dom DLL_HEADER const 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 BCName for bc-number of co dim 2 DLL_HEADER char * Ng_GetCD2NumCD2Name (int cd2nr); // 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 element ei curved ? DLL_HEADER int Ng_IsElementCurved (int ei); // is element sei curved ? DLL_HEADER int Ng_IsSurfaceElementCurved (int sei); /// Curved Elements: /// 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 Elements: /// 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 Elements: /// 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(); [[deprecated("orientation is not supported anymore")]] DLL_HEADER int Ng_GetElement_Edges (int elnr, int * edges, int * orient = 0); // [[deprecated("orientation is not supported anymore")]] DLL_HEADER int Ng_GetElement_Faces (int elnr, int * faces, int * orient = 0); [[deprecated("orientation is not supported anymore")]] DLL_HEADER int Ng_GetSurfaceElement_Edges (int selnr, int * edges, int * orient = 0); // [[deprecated("orientation is not supported anymore")]] 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 // the following functions are 0-base !! // number on distant processor // returns pairs (dist_proc, num_on_dist_proc) int NgPar_GetDistantNodeNums ( int nodetype, int locnum, int * pnums ); int NgPar_GetNDistantNodeNums ( int nodetype, int locnum ); DLL_HEADER int NgPar_GetGlobalNodeNum (int nodetype, int locnum); #endif namespace netgen { // #include "../visualization/soldata.hpp" class SolutionData; class MouseEventHandler; class UserVisualizationObject; } 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 { std::string name; // name of gridfunction std::string title = ""; // name of gridfunction ( printed on top of window ) std::string number_format = "%.3e"; // printf-style string to format colormap values std::string unit = ""; // string to append to last number in colormap (ASCII only) 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; std::shared_ptr draw_surfaces, draw_volumes; 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(bool blocking = false); /// DLL_HEADER void Ng_TclCmd(std::string cmd); /// DLL_HEADER void Ng_SetMouseEventHandler (netgen::MouseEventHandler * handler); /// DLL_HEADER void Ng_SetUserVisualizationObject (netgen::UserVisualizationObject * vis); // 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); #define NG_STATUS_USES_STD_STRING DLL_HEADER void Ng_PushStatus (const std::string& str); DLL_HEADER void Ng_PopStatus (); DLL_HEADER void Ng_SetThreadPercentage (double percent); DLL_HEADER void Ng_GetStatus (std::string& 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); DLL_HEADER void Ng_GetArgs (int & argc, char ** &argv); #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); } #ifdef __cplusplus #include namespace ngcore { NGCORE_API extern int printmessage_importance; } #endif ================================================ FILE: libsrc/include/nginterface_v2.hpp ================================================ #ifndef NGINTERFACE_V2 #define NGINTERFACE_V2 /**************************************************************************/ /* File: nginterface_v2.hpp */ /* Author: Joachim Schoeberl */ /* Date: May 09 */ /**************************************************************************/ #include "mydefs.hpp" #include /* C++ interface to Netgen */ #ifndef NGINTERFACE // implemented element types: enum NG_ELEMENT_TYPE { NG_PNT = 0, NG_SEGM = 1, NG_SEGM3 = 2, NG_TRIG = 10, NG_QUAD=11, NG_TRIG6 = 12, NG_QUAD6 = 13, NG_QUAD8 = 14, NG_TET = 20, NG_TET10 = 21, NG_PYRAMID = 22, NG_PRISM = 23, NG_PRISM12 = 24, NG_PRISM15 = 27, NG_PYRAMID13 = 28, NG_HEX = 25, NG_HEX20 = 26, NG_HEX7 = 29 }; enum NG_REFINEMENT_TYPE { NG_REFINE_H = 0, NG_REFINE_P = 1, NG_REFINE_HP = 2 }; #endif // #ifndef PARALLEL // typedef int MPI_Comm; // #endif namespace netgen { using namespace std; using namespace ngcore; static constexpr int POINTINDEX_BASE = 1; typedef int T_EDGE2; typedef int T_FACE2; template class Ng_Buffer { size_t s; T * data; public: Ng_Buffer (size_t as, T * adata) : s(as), data(adata) { ; } Ng_Buffer (Ng_Buffer && buffer) : s(buffer.Size()), data(buffer.Release()) { ; } ~Ng_Buffer () { delete [] data; } size_t Size() const { return s; } T * Release() { T * hd = data; data = nullptr; return hd; } }; template class Ng_BufferMS { size_t s; T data[S]; public: Ng_BufferMS (size_t as) : s(as) { ; } size_t Size() const { return s; } T & operator[] (size_t i) { return data[i]; } T operator[] (size_t i) const { return data[i]; } }; class Ng_Element { class Ng_Points { public: size_t num; const int * ptr; size_t Size() const { return num; } int operator[] (size_t i) const { return ptr[i]-POINTINDEX_BASE; } }; class Ng_Vertices { public: size_t num; const int * ptr; size_t Size() const { return num; } int operator[] (size_t i) const { return ptr[i]-POINTINDEX_BASE; } }; class Ng_Facets { public: size_t num; int base; const int * ptr; size_t Size() const { return num; } int operator[] (size_t i) const { return ptr[i]-base; } }; public: NG_ELEMENT_TYPE type; int index; // material / boundary condition string_view mat; // material / boundary label NG_ELEMENT_TYPE GetType() const { return type; } int GetIndex() const { return index-1; } Ng_Points points; // all points Ng_Vertices vertices; FlatArray edges; FlatArray faces; Ng_Facets facets; bool is_curved; int8_t newest_vertex; }; class Ng_Point { double * pt; public: Ng_Point (double * apt) : pt(apt) { ; } double operator[] (size_t i) { return pt[i]; } operator const double * () { return pt; } }; template class Ng_Node; template <> class Ng_Node<0> { class Ng_Elements { public: size_t ne; const int * ptr; size_t Size() const { return ne; } int operator[] (size_t i) const { return ptr[i]; } }; public: Ng_Elements elements; Ng_Elements bnd_elements; }; template <> class Ng_Node<1> { class Ng_Vertices { public: const int * ptr; size_t Size() const { return 2; } int operator[] (size_t i) const { return ptr[i]-POINTINDEX_BASE; } }; public: Ng_Vertices vertices; }; template <> class Ng_Node<2> { class Ng_Vertices { public: size_t nv; const int * ptr; size_t Size() const { return nv; } int operator[] (size_t i) const { return ptr[i]-POINTINDEX_BASE; } }; /* class Ng_Edges { public: size_t ned; const int * ptr; size_t Size() const { return ned; } int operator[] (size_t i) const { return ptr[i]-1; } }; */ public: Ng_Vertices vertices; // Ng_Edges edges; int surface_el; // -1 if face not on surface }; class Mesh; inline void DummyTaskManager2 (function func) { func(0,1); } inline void DummyTracer2 (string, bool) { ; } class DLL_HEADER Ngx_Mesh { private: shared_ptr mesh; public: // Ngx_Mesh () { ; } // Ngx_Mesh(class Mesh * amesh) : mesh(amesh) { ; } /** reuse a netgen-mesh **/ Ngx_Mesh (shared_ptr amesh); /** load a new mesh **/ Ngx_Mesh (string filename, NgMPI_Comm acomm = NgMPI_Comm{}); void LoadMesh (const string & filename, NgMPI_Comm comm = NgMPI_Comm{}); void LoadMesh (istream & str, NgMPI_Comm comm = NgMPI_Comm{}); void SaveMesh (ostream & str) const; void UpdateTopology (); void DoArchive (Archive & archive); const NgMPI_Comm & GetCommunicator() const; virtual ~Ngx_Mesh(); bool Valid () const { return mesh != NULL; } int GetDimension() const; int GetNLevels() const; size_t GetNVLevel (int level) const; int GetNElements (int dim) const; int GetNNodes (int nt) const; Ng_Point GetPoint (int nr) const; template Ng_Element GetElement (size_t nr) const; template int GetElementIndex (size_t nr) const; /// material/boundary label of region, template argument is co-dimension template string_view GetMaterialCD (int region_nr) const; /// Curved Elements: /// elnr .. element nr /// xi..... DIM_EL local coordinates /// x ..... DIM_SPACE global coordinates /// dxdxi...DIM_SPACE x DIM_EL Jacobian matrix (row major storage) template void ElementTransformation (int elnr, const double * xi, double * x, double * dxdxi) const; /// Curved Elements: /// elnr .. element nr /// npts .. number of points /// 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 void MultiElementTransformation (int elnr, int npts, const T * xi, size_t sxi, T * x, size_t sx, T * dxdxi, size_t sdxdxi) const; template const Ng_Node GetNode (int nr) const; Ng_BufferMS GetFaceEdges (int fnr) const; template int GetNNodes (); // returns domain numbers of domains next to boundary bnr -> (domin, domout) // 3D only // std::pair GetBoundaryNeighbouringDomains (int bnr); template void SetRefinementFlag (size_t elnr, bool flag); void Curve (int order); int GetCurveOrder (); void EnableTable (string name, bool set); void Refine (NG_REFINEMENT_TYPE reftype, bool onlyonce, void (*taskmanager)(function) = &DummyTaskManager2, void (*tracer)(string, bool) = &DummyTracer2); int GetHPElementLevel (int ei, int dir) const; void GetParentNodes (int ni, int * parents) const; int GetParentElement (int ei) const; int GetParentSElement (int ei) const; bool HasParentEdges() const; std::tuple> GetParentEdges (int enr) const; std::tuple> GetParentFaces (int fnr) const; int GetNIdentifications() const; int GetIdentificationType(int idnr) const; Ng_Buffer GetPeriodicVertices(int idnr) const; // Find element of point, returns local coordinates template int FindElementOfPoint (double * p, double * lami, bool build_searchtrees = false, int * const indices = NULL, int numind = 0, double tol = 1e-4) const; // for MPI-parallel FlatArray GetDistantProcs (int nodetype, int locnum) const; size_t GetGlobalVertexNum (int locnum) const; shared_ptr GetMesh () const { return mesh; } shared_ptr SelectMesh () const; inline auto GetTimeStamp() const; // also added from nginterface.h, still 1-based, need redesign void HPRefinement (int levels, double parameter = 0.125, bool setorders = true,bool ref_level = false); void SplitAlfeld (); size_t GetNP() const; int GetSurfaceElementSurfaceNumber (size_t ei) const; int GetSurfaceElementFDNumber (size_t ei) const; int GetElementOrder (int enr) const; void GetElementOrders (int enr, int * ox, int * oy, int * oz) const; void SetElementOrder (int enr, int order); void SetElementOrders (int enr, int ox, int oy, int oz); int GetSurfaceElementOrder (int enr) const; void GetSurfaceElementOrders (int enr, int * ox, int * oy) const; void SetSurfaceElementOrder (int enr, int order); void SetSurfaceElementOrders (int enr, int ox, int oy); int GetClusterRepVertex (int vi) const; int GetClusterRepEdge (int edi) const; int GetClusterRepFace (int fai) const; int GetClusterRepElement (int eli) const; // just copied from nginterface, now 0-based int GetElement_Faces (int elnr, int * faces, int * orient = 0) const; int GetSurfaceElement_Face (int selnr, int * orient = 0) const; }; DLL_HEADER Ngx_Mesh * LoadMesh (const string & filename); } #ifdef HAVE_NETGEN_SOURCES #include namespace netgen { #ifdef __GNUC__ #define NGX_INLINE __attribute__ ((__always_inline__)) inline #else #define NGX_INLINE inline #endif #include } #endif #endif ================================================ FILE: libsrc/include/nginterface_v2_impl.hpp ================================================ NGX_INLINE DLL_HEADER Ng_Point Ngx_Mesh :: GetPoint (int nr) const { return Ng_Point (&mesh->Point(PointIndex(nr+PointIndex::BASE))(0)); } template <> NGX_INLINE DLL_HEADER int Ngx_Mesh :: GetElementIndex<0> (size_t nr) const { return (*mesh).pointelements[nr].index; } template <> NGX_INLINE DLL_HEADER int Ngx_Mesh :: GetElementIndex<1> (size_t nr) const { /* if(mesh->GetDimension()==3) return (*mesh)[SegmentIndex(nr)].edgenr; else return (*mesh)[SegmentIndex(nr)].si; */ /* if(mesh->GetDimension()==3) return mesh->LineSegments()[nr].edgenr; else return mesh->LineSegments()[nr].si; */ return mesh->LineSegments()[nr].GetIndex(); } template <> NGX_INLINE DLL_HEADER int Ngx_Mesh :: GetElementIndex<2> (size_t nr) const { // int ind = (*mesh)[SurfaceElementIndex(nr)].GetIndex(); // return mesh->GetFaceDescriptor(ind).BCProperty(); const Element2d & el = (*mesh)[SurfaceElementIndex(nr)]; return mesh->GetFaceDescriptor(el).BCProperty(); } template <> NGX_INLINE DLL_HEADER int Ngx_Mesh :: GetElementIndex<3> (size_t nr) const { return (*mesh)[ElementIndex(nr)].GetIndex(); } template <> NGX_INLINE DLL_HEADER Ng_Element Ngx_Mesh :: GetElement<0> (size_t nr) const { const Element0d & el = mesh->pointelements[nr]; Ng_Element ret; ret.type = NG_PNT; ret.index = el.index; ret.mat = el.name; ret.points.num = 1; ret.points.ptr = (int*)&el.pnum; ret.vertices.num = 1; ret.vertices.ptr = (int*)&el.pnum; /* ret.edges.num = 0; ret.edges.ptr = NULL; */ ret.edges.Assign ( FlatArray (0, nullptr) ); /* ret.faces.num = 0; ret.faces.ptr = NULL; */ ret.faces.Assign ( { 0, nullptr } ); ret.facets.num = 1; ret.facets.base = POINTINDEX_BASE; ret.facets.ptr = (int*)&el.pnum; /* if (mesh->GetDimension() == 1) ret.mat = *(mesh->GetBCNamePtr(el.index-1)); else if (mesh->GetDimension() == 2) ret.mat = *(mesh->GetCD2NamePtr(el.index-1)); else ret.mat = *(mesh->GetCD3NamePtr(el.index-1)); */ ret.mat = mesh->GetRegionName(0, el.index); ret.is_curved = false; return ret; } template <> NGX_INLINE DLL_HEADER Ng_Element Ngx_Mesh :: GetElement<1> (size_t nr) const { // const Segment & el = mesh->LineSegment (SegmentIndex(nr)); const Segment & el = mesh->LineSegments()[nr]; Ng_Element ret; ret.type = NG_ELEMENT_TYPE(el.GetType()); /* if(mesh->GetDimension()==3) ret.index = el.edgenr; else ret.index = el.si; */ ret.index = el.GetIndex(); /* if (mesh->GetDimension() == 2) ret.mat = *(mesh->GetBCNamePtr(el.si-1)); else { if (mesh->GetDimension() == 3) ret.mat = *(mesh->GetCD2NamePtr(el.edgenr-1)); else ret.mat = *(mesh->GetMaterialPtr(el.si)); } */ ret.mat = mesh->GetRegionName(1, ret.index); 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.edges.Assign ( FlatArray (1, const_cast((const int*) mesh->GetTopology().GetSegmentElementEdgesPtr (nr)))); /* ret.faces.num = 0; ret.faces.ptr = NULL; */ ret.faces.Assign ( { 0, nullptr }); if (mesh->GetDimension() == 3) { ret.facets.num = 0; ret.facets.base = 0; ret.facets.ptr = nullptr; } else if (mesh->GetDimension() == 2) { ret.facets.num = 1; ret.facets.base = 0; ret.facets.ptr = ret.edges.Data(); } else { ret.facets.num = 2; ret.facets.base = POINTINDEX_BASE; ret.facets.ptr = (int*)&(el[0]); } // ret.is_curved = mesh->GetCurvedElements().IsSegmentCurved(nr); ret.is_curved = el.IsCurved(); return ret; } template <> NGX_INLINE DLL_HEADER Ng_Element Ngx_Mesh :: GetElement<2> (size_t nr) const { const Element2d & el = mesh->SurfaceElements()[nr]; Ng_Element ret; ret.type = NG_ELEMENT_TYPE(el.GetType()); const FaceDescriptor & fd = mesh->GetFaceDescriptor(el); // .GetIndex()); ret.index = fd.BCProperty(); if (mesh->GetDimension() == 3) ret.mat = fd.GetBCName(); else ret.mat = *(mesh -> GetMaterialPtr(ret.index)); 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.edges.Assign (mesh->GetTopology().GetEdges (SurfaceElementIndex(nr))); auto hedges = mesh->GetTopology().GetEdges (SurfaceElementIndex(nr)); ret.edges.Assign ( { hedges.Size(), (int*)hedges.Data() } ); /* ret.faces.num = MeshTopology::GetNFaces (el.GetType()); ret.faces.ptr = mesh->GetTopology().GetSurfaceElementFacesPtr (nr); */ // ret.faces.Assign ( { 1, const_cast(mesh->GetTopology().GetSurfaceElementFacesPtr (nr)) }); ret.faces.Assign ( { 1, (int*)(mesh->GetTopology().GetSurfaceElementFacesPtr (nr)) }); if (mesh->GetDimension() == 3) { ret.facets.num = ret.faces.Size(); ret.facets.base = 0; ret.facets.ptr = ret.faces.Data(); } else { ret.facets.num = ret.edges.Size(); ret.facets.base = 0; ret.facets.ptr = ret.edges.Data(); } ret.is_curved = el.IsCurved(); ret.newest_vertex = el.NewestVertex(); return ret; } template <> NGX_INLINE DLL_HEADER Ng_Element Ngx_Mesh :: GetElement<3> (size_t nr) const { const Element & el = mesh->VolumeElements()[nr]; Ng_Element ret; ret.type = NG_ELEMENT_TYPE(el.GetType()); ret.index = el.GetIndex(); ret.mat = *(mesh -> GetMaterialPtr(ret.index)); 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.edges.Assign (mesh->GetTopology().GetEdges (ElementIndex(nr))); auto hedges = mesh->GetTopology().GetEdges (ElementIndex(nr)); ret.edges.Assign ( { hedges.Size(), (int*)hedges.Data() } ); /* ret.faces.num = MeshTopology::GetNFaces (el.GetType()); ret.faces.ptr = mesh->GetTopology().GetElementFacesPtr (nr); */ // ret.faces.Assign (mesh->GetTopology().GetFaces (ElementIndex(nr))); auto hfaces = mesh->GetTopology().GetFaces (ElementIndex(nr)); ret.faces.Assign ( { hfaces.Size(), (int*)hfaces.Data() } ); ret.facets.num = ret.faces.Size(); ret.facets.base = 0; ret.facets.ptr = ret.faces.Data(); ret.is_curved = el.IsCurved(); ret.newest_vertex = el.NewestVertex(); return ret; } template <> NGX_INLINE DLL_HEADER string_view Ngx_Mesh :: GetMaterialCD<0> (int region_nr) const { return mesh->GetMaterial(region_nr+1); } template <> NGX_INLINE DLL_HEADER string_view Ngx_Mesh :: GetMaterialCD<1> (int region_nr) const { return mesh->GetBCName(region_nr); } template <> NGX_INLINE DLL_HEADER string_view Ngx_Mesh :: GetMaterialCD<2> (int region_nr) const { return mesh->GetCD2Name(region_nr); } template <> NGX_INLINE DLL_HEADER string_view Ngx_Mesh :: GetMaterialCD<3> (int region_nr) const { return mesh->GetCD3Name(region_nr); } template <> NGX_INLINE DLL_HEADER int Ngx_Mesh :: GetNNodes<1> () { return mesh->GetTopology().GetNEdges(); } template <> NGX_INLINE DLL_HEADER int Ngx_Mesh :: GetNNodes<2> () { return mesh->GetTopology().GetNFaces(); } template <> NGX_INLINE DLL_HEADER const Ng_Node<0> Ngx_Mesh :: GetNode<0> (int vnr_) const { Ng_Node<0> node; PointIndex vnr = IndexBASE() + vnr_; switch (mesh->GetDimension()) { case 3: { auto ia = mesh->GetTopology().GetVertexElements(vnr); node.elements.ne = ia.Size(); node.elements.ptr = (int*)ia.Data(); auto bia = mesh->GetTopology().GetVertexSurfaceElements(vnr); node.bnd_elements.ne = bia.Size(); node.bnd_elements.ptr = (int*)bia.Data(); break; } case 2: { auto ia = mesh->GetTopology().GetVertexSurfaceElements(vnr); node.elements.ne = ia.Size(); node.elements.ptr = (int*)ia.Data(); auto bia = mesh->GetTopology().GetVertexSegments(vnr); node.bnd_elements.ne = bia.Size(); node.bnd_elements.ptr = (int*)bia.Data(); break; } case 1: { auto ia = mesh->GetTopology().GetVertexSegments(vnr); node.elements.ne = ia.Size(); node.elements.ptr = (int*)ia.Data(); auto bia = mesh->GetTopology().GetVertexPointElements(vnr); node.bnd_elements.ne = bia.Size(); node.bnd_elements.ptr = (int*)bia.Data(); break; } default: ; } return node; } template <> NGX_INLINE DLL_HEADER const Ng_Node<1> Ngx_Mesh :: GetNode<1> (int nr) const { Ng_Node<1> node; node.vertices.ptr = (const int*)mesh->GetTopology().GetEdgeVerticesPtr(nr); return node; } template <> NGX_INLINE DLL_HEADER const Ng_Node<2> Ngx_Mesh :: GetNode<2> (int nr) const { Ng_Node<2> node; node.vertices.ptr = (const int*)mesh->GetTopology().GetFaceVerticesPtr(nr); node.vertices.nv = (node.vertices.ptr[3]+1 == PointIndex::BASE) ? 3 : 4; node.surface_el = mesh->GetTopology().GetFace2SurfaceElement (nr); return node; } NGX_INLINE DLL_HEADER Ng_Buffer Ngx_Mesh :: GetPeriodicVertices(int idnr) const { NgArray apairs; mesh->GetIdentifications().GetPairs (idnr+1, apairs); for(auto& ind : apairs) { ind.I1() -= IndexBASE(); ind.I2() -= IndexBASE(); } typedef int ti2[2]; return { apairs.Size(), (ti2*)(void*)apairs.Release() }; } NGX_INLINE void Ngx_Mesh :: GetParentNodes (int ni, int * parents) const { if (ni < mesh->mlbetweennodes.Size()) for (int j = 0; j < 2; j++) parents[j] = mesh->mlbetweennodes[IndexBASE()+ni][j] - IndexBASE(); else parents[0] = parents[1] = -1; } inline bool Ngx_Mesh :: HasParentEdges() const { return mesh->GetTopology().HasParentEdges(); } inline tuple> Ngx_Mesh :: GetParentEdges (int enr) const { return mesh->GetTopology().GetParentEdges(enr); } inline tuple> Ngx_Mesh :: GetParentFaces (int fnr) const { return mesh->GetTopology().GetParentFaces(fnr); } inline auto Ngx_Mesh :: GetTimeStamp() const { return mesh->GetTimeStamp(); } ================================================ FILE: libsrc/include/ngsimd.hpp ================================================ #include <../general/ngsimd.hpp> ================================================ FILE: libsrc/include/occgeom.hpp ================================================ #include "../occ/occgeom.hpp" ================================================ FILE: libsrc/include/opti.hpp ================================================ #include "../linalg/opti.hpp" ================================================ FILE: libsrc/include/parallel.hpp ================================================ #include "../parallel/parallel.hpp" ================================================ FILE: libsrc/include/stlgeom.hpp ================================================ #include <../stlgeom/stlgeom.hpp> ================================================ FILE: libsrc/include/visual.hpp ================================================ #include "../visualization/visual.hpp" ================================================ FILE: libsrc/interface/CMakeLists.txt ================================================ target_sources(nglib PRIVATE writeuser.cpp 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 wuchemnitz.cpp writegmsh2.cpp writeOpenFOAM15x.cpp rw_cgns.cpp rw_medit.cpp ) install(FILES writeuser.hpp rw_medit.hpp DESTINATION ${NG_INSTALL_DIR_INCLUDE}/interface COMPONENT netgen_devel ) ================================================ FILE: libsrc/interface/nginterface.cpp ================================================ #include #include #include #include #ifdef SOCKETS #include "../sockets/sockets.hpp" #endif #include "../general/gzstream.h" #include "nginterface.h" // #include "../visualization/soldata.hpp" // #include namespace netgen { DLL_HEADER MeshingParameters mparam; /** Force linking of geom2d library (for SplineGeometryRegister)**/ SplineGeometry2d dummy_2dgeom; } static std::thread meshingthread; void RunParallel ( void * (*fun)(void *), void * in) { if (netgen::mparam.parthread) { meshingthread = std::thread(fun, in); meshingthread.detach(); } else fun (in); } #include "writeuser.hpp" namespace netgen { extern shared_ptr mesh; extern shared_ptr ng_geometry; extern Tcl_Interp * tcl_interp; #ifdef SOCKETS extern AutoPtr clientsocket; //extern NgArray< AutoPtr < ServerInfo > > servers; extern NgArray< ServerInfo* > servers; #endif } using namespace netgen; void Ng_LoadGeometry (const char * filename) { // he: if filename is empty, return // can be used to reset geometry if (!filename || strcmp(filename,"")==0) { ng_geometry.reset (new NetgenGeometry()); return; } for (auto loader : GeometryRegister()) { NetgenGeometry * hgeom = loader->Load (filename); if (hgeom) { ng_geometry.reset (hgeom); mesh.reset(); return; } } // if (id == 0) cerr << "cannot load geometry '" << filename << "'" << ", id = " << id << endl; } void Ng_LoadMeshFromStream ( istream & input ) { mesh.reset (new Mesh()); mesh -> Load(input); SetGlobalMesh (mesh); ng_geometry = GeometryRegister().LoadFromMeshFile (input); if (!ng_geometry) ng_geometry = make_shared(); mesh->SetGeometry (ng_geometry); } void Ng_LoadMesh (const char * filename, ngcore::NgMPI_Comm comm) { int id = comm.Rank(); int ntasks = comm.Size(); { ifstream infile(filename); if(!infile.good()) throw NgException(string("Error opening file ") + filename); } if ( string(filename).find(".vol") == string::npos ) { if(ntasks>1) throw NgException("Not sure what to do with this?? Does this work with MPI??"); mesh.reset (new Mesh()); mesh->SetCommunicator(comm); ReadFile(*mesh,filename); //mesh->SetGlobalH (mparam.maxh); //mesh->CalcLocalH(); return; } istream * infile; Array buf; // for distributing geometry! int strs; if( id == 0) { mesh.reset (new Mesh()); mesh->SetCommunicator(comm); string fn(filename); if (fn.length() > 8 && fn.substr (fn.length()-8, 8) == ".vol.bin") { mesh -> Load(fn); SetGlobalMesh (mesh); } else { if (fn.substr (fn.length()-3, 3) == ".gz") infile = new igzstream (filename); else infile = new ifstream (filename); mesh -> Load(*infile); SetGlobalMesh (mesh); // make string from rest of file (for geometry info!) // (this might be empty, in which case we take the global ng_geometry) stringstream geom_part; geom_part << infile->rdbuf(); string geom_part_string = geom_part.str(); strs = geom_part_string.size(); // buf = new char[strs]; buf.SetSize(strs); memcpy(buf.Data(), geom_part_string.c_str(), strs*sizeof(char)); delete infile; } if (ntasks > 1) { char * weightsfilename = new char [strlen(filename)+1]; strcpy (weightsfilename, filename); weightsfilename[strlen (weightsfilename)-3] = 'w'; weightsfilename[strlen (weightsfilename)-2] = 'e'; weightsfilename[strlen (weightsfilename)-1] = 'i'; ifstream weightsfile(weightsfilename); delete [] weightsfilename; if (!(weightsfile.good())) { // cout << "regular distribute" << endl; mesh -> Distribute(); } else { char str[20]; bool endfile = false; int n, dummy; NgArray segment_weights; NgArray surface_weights; NgArray volume_weights; while (weightsfile.good() && !endfile) { weightsfile >> str; if (strcmp (str, "edgeweights") == 0) { weightsfile >> n; segment_weights.SetSize(n); for (int i = 0; i < n; i++) weightsfile >> dummy >> segment_weights[i]; } if (strcmp (str, "surfaceweights") == 0) { weightsfile >> n; surface_weights.SetSize(n); for (int i=0; i> dummy >> surface_weights[i]; } if (strcmp (str, "volumeweights") == 0) { weightsfile >> n; volume_weights.SetSize(n); for (int i=0; i> dummy >> volume_weights[i]; } if (strcmp (str, "endfile") == 0) endfile = true; } mesh -> Distribute(volume_weights, surface_weights, segment_weights); } } // ntasks>1 end } // id==0 end else { mesh.reset (new Mesh()); mesh->SetCommunicator(comm); SetGlobalMesh (mesh); mesh->SendRecvMesh(); } /* if(ntasks>1) { #ifdef PARALLEL // Scatter the geometry-string (no dummy-implementation in mpi_interface) int strs = buf.Size(); MyMPI_Bcast(strs, comm); if(strs>0) MyMPI_Bcast(buf, comm); #endif } */ comm.Bcast(buf); shared_ptr geo; if(buf.Size()) { // if we had geom-info in the file, take it istringstream geom_infile(string((const char*)&buf[0], buf.Size())); geo = GeometryRegister().LoadFromMeshFile(geom_infile); } if(geo!=nullptr) { ng_geometry = geo; mesh->SetGeometry(geo); } else if(ng_geometry!=nullptr) mesh->SetGeometry(ng_geometry); } 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 { const Element2d & el = mesh->SurfaceElement (ei); for (int i = 0; i < el.GetNP(); i++) epi[i] = el.PNum(i+1); if (np) *np = el.GetNP(); return NG_ELEMENT_TYPE (el.GetType()); } // 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); } const char * Ng_GetElementMaterial (int ei) { static char empty[] = ""; if (mesh->GetDimension() == 3) { int ind = mesh->VolumeElement(ei).GetIndex(); // cout << "ind = " << ind << endl; const string * mat = mesh->GetMaterialPtr (ind); if (mat) // return const_cast (mat); return mat->c_str(); else return empty; } // add astrid else { int ind = mesh->SurfaceElement(ei).GetIndex(); ind = mesh->GetFaceDescriptor(ind).BCProperty(); const string * mat = mesh->GetMaterialPtr ( ind ); if (mat) return mat->c_str(); else return empty; } return 0; } const char * Ng_GetDomainMaterial (int dom) { static char empty[] = ""; // astrid if ( 1 ) // mesh->GetDimension() == 3) { const string * mat = mesh->GetMaterialPtr(dom); if (mat) return mat->c_str(); else return empty; } return 0; } int Ng_GetUserDataSize (char * id) { NgArray da; mesh->GetUserData (id, da); return da.Size(); } void Ng_GetUserData (char * id, double * data) { NgArray 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].IsValid()) { 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(mesh->GetFaceDescriptor(mesh->SurfaceElement(ei).GetIndex()).GetBCName().c_str()); else return const_cast(mesh->GetBCName(mesh->LineSegment(ei).si).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(mesh->GetBCName(bcnr).c_str()); } char * Ng_GetCD2NumCD2Name (int cd2nr) { return const_cast(mesh->GetCD2Name(cd2nr).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 (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 (ng_geometry.get()); 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) { NgArray * dummy(NULL); int ind = -1; if(indices != NULL) { dummy = new NgArray(numind); for(int i=0; iGetDimension() == 3) { Point3d p3d(p[0], p[1], p[2]); ind = mesh->GetElementOfPoint(p3d, lami, dummy, build_searchtree != 0) + 1; } else { double lam3[3]; Point3d p2d(p[0], p[1], 0); ind = mesh->GetSurfaceElementOfPoint(p2d, lam3, dummy, build_searchtree != 0) + 1; 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) { NgArray * dummy(NULL); int ind = -1; if(indices != NULL) { dummy = new NgArray(numind); for(int i=0; iGetDimension() == 3) { Point3d p3d(p[0], p[1], p[2]); ind = mesh->GetSurfaceElementOfPoint(p3d, lami, dummy, build_searchtree != 0) + 1; } 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) { switch (mesh->GetDimension()) { case 1: return mesh->GetCurvedElements().IsSegmentCurved (ei-1); case 2: return mesh->GetCurvedElements().IsSurfaceElementCurved (ei-1); case 3: return mesh->GetCurvedElements().IsElementCurved (ei-1); } return 0; /* 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); } } } } 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].IsValid()) { 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 // gibt anzahl an distant pnums zurueck // * pnums entspricht ARRAY [[deprecated("Use GetDistantNodeNums(locnum) -> FlatArray instead!")]] int NgPar_GetDistantNodeNums ( int nodetype, int locnum, int * distnums ) { int size = NgPar_GetNDistantNodeNums (nodetype, locnum); locnum++; switch ( nodetype ) { case 0: mesh->GetParallelTopology().GetDistantPNums( locnum, distnums ); break; case 1: mesh->GetParallelTopology().GetDistantEdgeNums( locnum, distnums ); break; case 2: mesh->GetParallelTopology().GetDistantFaceNums( locnum, distnums ); break; case 3: // mesh->GetParallelTopology().GetDistantElNums( locnum, distnums ); break; default: cerr << "NgPar_GetDistantNodeNums() Unknown nodetype " << nodetype << endl; size = -1; } return size; } [[deprecated("Use GetDistantNodeNums(locnum) -> FlatArray instead!")]] int NgPar_GetNDistantNodeNums ( int nodetype, int locnum ) { locnum++; switch ( nodetype ) { case 0: return mesh->GetParallelTopology().GetNDistantPNums (locnum); case 1: return mesh->GetParallelTopology().GetNDistantEdgeNums (locnum); case 2: return mesh->GetParallelTopology().GetNDistantFaceNums(locnum ); case 3: return 0; } return -1; } [[deprecated("Use GetDistantNodeNums(locnum) -> FlatArray instead!")]] int NgPar_GetGlobalNodeNum (int nodetype, int locnum) { locnum++; switch (nodetype) { case 0: return mesh->GetParallelTopology().GetGlobalPNum (locnum)-1; case 1: return mesh->GetParallelTopology().GetGlobalEdgeNum (locnum)-1; case 2: return mesh->GetParallelTopology().GetGlobalFaceNum (locnum)-1; case 3: return mesh->GetParallelTopology().GetGlobalElNum (locnum)-1; } return -1; } #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 = mesh->GetGeometry()->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 (mesh->GetGeometry()->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 (mesh->GetGeometry()->GetRefinement()); HPRefinement (*mesh, &ref, SPLIT_HP, levels, parameter, setorders, ref_level); /* 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); /* mesh -> GetCurvedElements().BuildCurvedElements (&const_cast (ng_geometry -> GetRefinement()), order, rational); */ /* if (!mesh->GetGeometry()) throw NgException ("don't have a geometry for mesh curving"); mesh->BuildCurvedElements (&const_cast (mesh->GetGeometry()->GetRefinement()), order, rational); mesh -> SetNextMajorTimeStamp(); */ mesh->BuildCurvedElements(order); } 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.get(); mesh.reset((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(); NgArray 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) { SurfaceElementIndex sei = selnr-1; const MeshTopology & topology = mesh->GetTopology(); if (orient) *orient = topology.GetSurfaceElementFaceOrientation (selnr); return topology.GetFace(sei); } return -1; } int Ng_GetFace_Vertices (int fnr, int * vert) { const MeshTopology & topology = mesh->GetTopology(); NgArrayMem 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(); NgArrayMem 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]); // tie(vert[0], vert[1]) = topology.GetEdgeVertices(ednr-1); auto [v1,v2] = topology.GetEdgeVertices(ednr-1); vert[0] = v1-IndexBASE()+1; vert[1] = v2-IndexBASE()+1; } int Ng_GetNVertexElements (int vnr) { switch (mesh->GetDimension()) { case 3: return mesh->GetTopology().GetVertexElements(vnr).Size(); case 2: return mesh->GetTopology().GetVertexSurfaceElements(vnr).Size(); case 1: return mesh->GetTopology().GetVertexSegments(vnr).Size(); /* { int cnt = 0; for (SegmentIndex i = 0; i < mesh->GetNSeg(); i++) if ( ((*mesh)[i][0] == vnr) || ((*mesh)[i][1] == vnr) ) cnt++; return cnt; } */ default: cerr << "error: mesh->GetDimension() gives " << mesh->GetDimension() << endl; return 0; } } void Ng_GetVertexElements (int vnr, int * els) { switch (mesh->GetDimension()) { case 3: { auto ia = mesh->GetTopology().GetVertexElements(vnr); for (int i = 0; i < ia.Size(); i++) els[i] = ia[i]+1; break; } case 2: { auto ia = mesh->GetTopology().GetVertexSurfaceElements(vnr); for (int i = 0; i < ia.Size(); i++) els[i] = ia[i]+1; break; } case 1: { auto ia = mesh->GetTopology().GetVertexSegments(vnr); for (int i = 0; i < ia.Size(); i++) els[i] = ia[i]+1; break; /* int cnt = 0; for (SegmentIndex i = 0; i < mesh->GetNSeg(); i++) if ( ((*mesh)[i][0] == vnr) || ((*mesh)[i][1] == vnr) ) els[cnt++] = i+1; break; */ } } } 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 () { if (!mesh) return 0; return max(size_t(1), mesh -> level_nv.Size()); // return (mesh) ? mesh->mglevels : 0; } void Ng_GetParentNodes (int ni, int * parents) { if (ni <= mesh->mlbetweennodes.Size()) { parents[0] = mesh->mlbetweennodes[ni].I1(); parents[1] = mesh->mlbetweennodes[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[ei-1]+1; } else { if (ei <= mesh->mlparentsurfaceelement.Size()) return mesh->mlparentsurfaceelement[ei-1]+1; } return 0; } int Ng_GetParentSElement (int ei) { if (mesh->GetDimension() == 3) { if (ei <= mesh->mlparentsurfaceelement.Size()) return mesh->mlparentsurfaceelement[ei-1]+1; } 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) { NgArray 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) { NgArray 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) { idmap_type 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 = PointIndex (map[(*mesh)[si][0]]); PointIndex other2 = PointIndex (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) { idmap_type 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 = PointIndex (map[(*mesh)[si][0]]); PointIndex other2 = PointIndex (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); pairs[cnt++] = top.GetEdge (si)+1; pairs[cnt++] = top.GetEdge (otherseg)+1; } } } } void Ng_PushStatus (const std::string& str) { PushStatus (str); } void Ng_PopStatus () { PopStatus (); } void Ng_SetThreadPercentage (double percent) { SetThreadPercent (percent); } void Ng_GetStatus (std::string & str, double & percent) { /* MyStr s; GetStatus(s,percent); *str = new char[s.Length()+1]; strcpy(*str,s.c_str()); */ GetStatus (str, percent); } 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 indexArray; // topology.GetVertexElements( vnr, indexArray ); auto indexArray = topology.GetVertexElements( vnr ); for( int i=0; i()-1; switch (mesh->GetDimension()) { case 3: { const MeshTopology& topology = mesh->GetTopology(); // ArrayMem indexArray; // topology.GetVertexSurfaceElements( vnr, indexArray ); auto indexArray = topology.GetVertexSurfaceElements( vnr ); for( int i=0; iGetNSeg(); i++) if ( ((*mesh)[i][0] == vnr) || ((*mesh)[i][1] == vnr) ) elems[cnt++] = i+1; return cnt; } case 1: { int cnt = 0; for (int i = 0; i < mesh->pointelements.Size(); i++) if (mesh->pointelements[i].pnum == vnr) elems[cnt++] = i+1; return cnt; } } return 0; } ///// Added by Roman Stainko .... int Ng_GetVertex_NElements( int vnr ) { const MeshTopology& topology = mesh->GetTopology(); /* ArrayMem indexArray; topology.GetVertexElements( vnr, indexArray ); return indexArray.Size(); */ return topology.GetVertexElements(vnr).Size(); } ///// Added by Roman Stainko .... int Ng_GetVertex_NSurfaceElements( int vnr_ ) { PointIndex vnr = vnr_ + IndexBASE()-1; switch (mesh->GetDimension()) { case 3: { const MeshTopology& topology = mesh->GetTopology(); // ArrayMem indexArray; // topology.GetVertexSurfaceElements( vnr, indexArray ); auto indexArray = topology.GetVertexSurfaceElements( vnr ); return indexArray.Size(); } case 2: { int cnt = 0; for (SegmentIndex i = 0; i < mesh->GetNSeg(); i++) if ( ((*mesh)[i][0] == vnr) || ((*mesh)[i][1] == vnr) ) cnt++; return cnt; } } return 0; } #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 (&mesh->GetGeometry()->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); /* // joachim, oct 2014 CSGeometry * geometry = dynamic_cast (ng_geometry.get()); if (geometry) { opt = new MeshOptimize2dSurfaces(*geometry); ref->Set2dOptimizer(opt); } */ } if(!mesh->LocalHFunctionGenerated()) mesh->CalcLocalH(mparam.grading); mesh->LocalHFunction().SetGrading (mparam.grading); NgArray * qualityloss_arr = NULL; if(qualityloss != NULL) qualityloss_arr = new NgArray; ref -> Bisect (*mesh, biopt, qualityloss_arr); int retval = 0; if(qualityloss != NULL) { *qualityloss = new double[qualityloss_arr->Size()+1]; for(int i = 0; iSize(); 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] - IndexBASE(); } } if (nodeset & 2) // Edges { auto edges = mesh->GetTopology().GetEdges (ElementIndex(nodenr)); for (int i = 0; i < edges.Size(); 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] - IndexBASE(); } } 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().GetFace (SurfaceElementIndex(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; } void Ng_GetArgs (int & argc, char ** &argv) { argc = h_argc; argv = h_argv; } void Ng_TclCmd(string cmd) { lock_guard guard(tcl_todo_mutex); *(multithread.tcl_todo) += cmd; } ================================================ FILE: libsrc/interface/nginterface_v2.cpp ================================================ #include #ifdef SOCKETS #include "../sockets/sockets.hpp" #endif #include "nginterface.h" #include "nginterface_v2.hpp" // #include #include "writeuser.hpp" namespace netgen { extern shared_ptr mesh; } namespace netgen { #define NGX_INLINE #include "nginterface_v2_impl.hpp" shared_ptr Ngx_Mesh :: SelectMesh () const { shared_ptr hmesh = netgen::mesh; netgen::mesh = mesh; SetGlobalMesh (mesh); return hmesh; } Ngx_Mesh :: Ngx_Mesh (shared_ptr amesh) { mesh = amesh ? amesh : netgen::mesh; } Ngx_Mesh :: Ngx_Mesh (string filename, NgMPI_Comm acomm) { LoadMesh(filename, acomm); } Ngx_Mesh * LoadMesh (const string & filename, NgMPI_Comm comm) { netgen::mesh.reset(); Ng_LoadMesh (filename.c_str(), comm); return new Ngx_Mesh (netgen::mesh); } void Ngx_Mesh :: LoadMesh (const string & filename, NgMPI_Comm comm) { netgen::mesh.reset(); Ng_LoadMesh (filename.c_str(), comm); // mesh = move(netgen::mesh); mesh = netgen::mesh; } void Ngx_Mesh :: LoadMesh (istream & ist, NgMPI_Comm comm) { netgen::mesh = make_shared(); netgen::mesh->SetCommunicator(comm); netgen::mesh -> Load (ist); // mesh = move(netgen::mesh); mesh = netgen::mesh; SetGlobalMesh (mesh); } const NgMPI_Comm & Ngx_Mesh :: GetCommunicator() const { // return Valid() ? mesh->GetCommunicator() : NgMPI_Comm{}; if (!Valid()) throw Exception("Ngx_mesh::GetCommunicator: don't have a valid mesh"); return mesh->GetCommunicator(); } void Ngx_Mesh :: SaveMesh (ostream & ost) const { mesh -> Save (ost); } void Ngx_Mesh :: DoArchive (Archive & archive) { #ifdef PARALLEL if (archive.Input()) { mesh = make_shared(); mesh->SetCommunicator(GetCommunicator()); } #endif mesh->DoArchive(archive); if (archive.Input()) { netgen::mesh = mesh; SetGlobalMesh (mesh); } /* if (archive.Output()) { stringstream str; SaveMesh (str); string st = str.str(); archive & st; } else { string st; archive & st; stringstream str(st); LoadMesh (str); } */ } void Ngx_Mesh :: UpdateTopology () { if (mesh) mesh -> UpdateTopology(); } /* Ngx_Mesh :: Ngx_Mesh (Mesh * amesh) : mesh(amesh) { ; } */ Ngx_Mesh :: ~Ngx_Mesh () { // causes crashes when global variable netgen::mesh is destructed // before visualization data if (mesh == netgen::mesh) netgen::mesh = nullptr; } int Ngx_Mesh :: GetDimension() const { return mesh -> GetDimension(); } int Ngx_Mesh :: GetNLevels() const { return max(size_t(1), mesh -> level_nv.Size()); } size_t Ngx_Mesh :: GetNVLevel(int level) const { if (level >= mesh->level_nv.Size()) return mesh->GetNV(); else return mesh->level_nv[level]; } int Ngx_Mesh :: GetNElements (int dim) const { switch (dim) { case 0: return mesh -> pointelements.Size(); case 1: return mesh -> GetNSeg(); case 2: return mesh -> GetNSE(); case 3: return mesh -> GetNE(); } return -1; } int Ngx_Mesh :: GetNNodes (int nt) const { 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; } /* Ng_Point Ngx_Mesh :: GetPoint (int nr) const { return Ng_Point (&mesh->Point(nr + PointIndex::BASE)(0)); } */ /* template <> DLL_HEADER Ng_Element Ngx_Mesh :: GetElement<0> (int nr) const { const Element0d & el = mesh->pointelements[nr]; Ng_Element ret; ret.type = NG_PNT; ret.index = el.index; ret.points.num = 1; ret.points.ptr = (int*)&el.pnum; ret.vertices.num = 1; ret.vertices.ptr = (int*)&el.pnum; ret.edges.num = 0; ret.edges.ptr = NULL; ret.faces.num = 0; ret.faces.ptr = NULL; return ret; } */ /* template <> DLL_HEADER Ng_Element Ngx_Mesh :: GetElement<1> (int nr) const { 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 Ngx_Mesh :: GetElement<2> (int nr) const { 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 Ngx_Mesh :: GetElement<3> (int nr) const { 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; } */ /* template <> DLL_HEADER int Ngx_Mesh :: GetElementIndex<0> (int nr) const { return 0; } template <> DLL_HEADER int Ngx_Mesh :: GetElementIndex<1> (int nr) const { return (*mesh)[SegmentIndex(nr)].si; } template <> DLL_HEADER int Ngx_Mesh :: GetElementIndex<2> (int nr) const { int ind = (*mesh)[SurfaceElementIndex(nr)].GetIndex(); return mesh->GetFaceDescriptor(ind).BCProperty(); } template <> DLL_HEADER int Ngx_Mesh :: GetElementIndex<3> (int nr) const { return (*mesh)[ElementIndex(nr)].GetIndex(); } */ /* 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 <> int DLL_HEADER Ng_GetNElements<0> () { return 0; } 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<0> (int nr) { cout << "Netgen does not support 0-D elements" << endl; Ng_Element ret; return ret; } 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; } */ template <> DLL_HEADER void Ngx_Mesh :: ElementTransformation<3,3> (int elnr, const double * xi, double * x, double * dxdxi) const { Point<3> xl(xi[0], xi[1], xi[2]); Point<3> xg; Mat<3,3> dx; mesh->GetCurvedElements().CalcElementTransformation (xl, elnr, 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); } } template <> DLL_HEADER void Ngx_Mesh :: ElementTransformation<2,3> (int elnr, const double * xi, double * x, double * dxdxi) const { Point<2> xl(xi[0], xi[1]); Point<3> xg; Mat<3,2> dx; mesh->GetCurvedElements().CalcSurfaceTransformation (xl, elnr, 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[2*i] = dx(i,0); dxdxi[2*i+1] = dx(i,1); } } template <> DLL_HEADER void Ngx_Mesh :: ElementTransformation<1,3> (int elnr, const double * xi, double * x, double * dxdxi) const { Point<3> xg; Vec<3> dx; mesh->GetCurvedElements().CalcSegmentTransformation(xi[0],elnr,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[i] = dx(i); } template <> DLL_HEADER void Ngx_Mesh :: ElementTransformation<0,3> (int elnr, const double * xi, double * x, double * dxdxi) const { PointIndex pi = mesh->pointelements[elnr].pnum; Point<3> xg = mesh->Point(pi); if (x) for(int i=0;i<3;i++) x[i] = xg(i); } template <> DLL_HEADER void Ngx_Mesh :: ElementTransformation<2,2> (int elnr, const double * xi, double * x, double * dxdxi) const { Point<2> xl(xi[0], xi[1]); Point<3> xg; Mat<3,2> dx; mesh->GetCurvedElements().CalcSurfaceTransformation (xl, elnr, 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); } } template <> DLL_HEADER void Ngx_Mesh :: ElementTransformation<1,2> (int elnr, const double * xi, double * x, double * dxdxi) const { Point<3> xg; Vec<3> dx; mesh->GetCurvedElements().CalcSegmentTransformation (xi[0], elnr, 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); } template <> DLL_HEADER void Ngx_Mesh :: ElementTransformation<1,1> (int elnr, const double * xi, double * x, double * dxdxi) const { Point<3> xg; Vec<3> dx; mesh->GetCurvedElements().CalcSegmentTransformation (xi[0], elnr, xg, dx); if (x) x[0] = xg(0); if (dxdxi) dxdxi[0] = dx(0); } template <> DLL_HEADER void Ngx_Mesh :: ElementTransformation<0,2> (int elnr, const double *xi, double * x, double * dxdxi) const { PointIndex pnum = mesh->pointelements[elnr].pnum; if (x) for (int i = 0; i< 2; i++) x[i] = (*mesh)[pnum](i); } template <> DLL_HEADER void Ngx_Mesh :: ElementTransformation<0,1> (int elnr, const double * xi, double * x, double * dxdxi) const { PointIndex pnum = mesh->pointelements[elnr].pnum; if (x) x[0] = (*mesh)[pnum](0); // if (dxdxi) dxdxi[0] = 0; // Jacobi-matrix is 1 x 0 !!! } template <> DLL_HEADER void Ngx_Mesh :: MultiElementTransformation<3,3> (int elnr, int npts, const double * xi, size_t sxi, double * x, size_t sx, double * dxdxi, size_t sdxdxi) const { mesh->GetCurvedElements().CalcMultiPointElementTransformation (elnr, npts, xi, sxi, x, sx, dxdxi, sdxdxi); } template <> DLL_HEADER void Ngx_Mesh :: MultiElementTransformation<2,2> (int elnr, int npts, const double * xi, size_t sxi, double * x, size_t sx, double * dxdxi, size_t sdxdxi) const { mesh->GetCurvedElements().CalcMultiPointSurfaceTransformation<2> (elnr, npts, xi, sxi, x, sx, dxdxi, sdxdxi); } template <> DLL_HEADER void Ngx_Mesh :: MultiElementTransformation<2,3> (int elnr, int npts, const double * xi, size_t sxi, double * x, size_t sx, double * dxdxi, size_t sdxdxi) const { mesh->GetCurvedElements().CalcMultiPointSurfaceTransformation<3> (elnr, npts, xi, sxi, x, sx, dxdxi, sdxdxi); } template <> DLL_HEADER void Ngx_Mesh :: MultiElementTransformation<1,3> (int elnr, int npts, const double * xi, size_t sxi, double * x, size_t sx, double * dxdxi, size_t sdxdxi) const { mesh->GetCurvedElements().CalcMultiPointSegmentTransformation<3> (elnr, npts, xi, sxi, x, sx, dxdxi, sdxdxi); } template <> DLL_HEADER void Ngx_Mesh :: MultiElementTransformation<0,3> (int elnr, int npts, const double * xi, size_t sxi, double * x, size_t sx, double * dxdxi, size_t sdxdxi) const { for (int i = 0; i < npts; i++) ElementTransformation<0,3> (elnr, xi+i*sxi, x+i*sx, dxdxi+i*sdxdxi); } template <> DLL_HEADER void Ngx_Mesh :: MultiElementTransformation<1,2> (int elnr, int npts, const double * xi, size_t sxi, double * x, size_t sx, double * dxdxi, size_t sdxdxi) const { mesh->GetCurvedElements().CalcMultiPointSegmentTransformation<2> (elnr, npts, xi, sxi, x, sx, dxdxi, sdxdxi); } template <> DLL_HEADER void Ngx_Mesh :: MultiElementTransformation<1,1> (int elnr, int npts, const double * xi, size_t sxi, double * x, size_t sx, double * dxdxi, size_t sdxdxi) const { for (int i = 0; i < npts; i++) ElementTransformation<1,1> (elnr, xi + i*sxi, x+i*sx, dxdxi+i*sdxdxi); } template <> DLL_HEADER void Ngx_Mesh :: MultiElementTransformation<0,2> (int elnr, int npts, const double * xi, size_t sxi, double * x, size_t sx, double * dxdxi, size_t sdxdxi) const { for (int i = 0; i < npts; i++) ElementTransformation<0,2> (elnr, xi + i*sxi, x+i*sx, dxdxi+i*sdxdxi); } template <> DLL_HEADER void Ngx_Mesh :: MultiElementTransformation<0,1> (int elnr, int npts, const double * xi, size_t sxi, double * x, size_t sx, double * dxdxi, size_t sdxdxi) const { for (int i = 0; i < npts; i++) ElementTransformation<0,1> (elnr, xi + i*sxi, x+i*sx, dxdxi+i*sdxdxi); } int Ngx_Mesh :: GetHPElementLevel (int ei, int dir) const { ei++; int level = -1; if (mesh->hpelements) { int hpelnr = -1; if (mesh->GetDimension() == 2) hpelnr = mesh->SurfaceElement(ei).GetHpElnr(); else hpelnr = mesh->VolumeElement(ei).GetHpElnr(); if (hpelnr < 0) throw NgException("Ngx_Mesh::GetHPElementLevel: Wrong hp-element number!"); if (dir == 1) level = (*mesh->hpelements)[hpelnr].levelx; else if (dir == 2) level = (*mesh->hpelements)[hpelnr].levely; else if (dir == 3) level = (*mesh->hpelements)[hpelnr].levelz; else throw NgException("Ngx_Mesh::GetHPElementLevel: dir has to be 1, 2 or 3!"); } //else // throw NgException("Ngx_Mesh::GetHPElementLevel only for HPRefinement implemented!"); return level; } int Ngx_Mesh :: GetParentElement (int ei) const { if (mesh->GetDimension() == 3) { if (ei < mesh->mlparentelement.Size()) return mesh->mlparentelement[ei]; } else { if (ei < mesh->mlparentsurfaceelement.Size()) return mesh->mlparentsurfaceelement[ei]; } return -1; } int Ngx_Mesh :: GetParentSElement (int ei) const { if (mesh->GetDimension() == 3) { if (ei < mesh->mlparentsurfaceelement.Size()) return mesh->mlparentsurfaceelement[ei]; } else { return -1; } return -1; } int Ngx_Mesh :: GetNIdentifications () const { return mesh->GetIdentifications().GetMaxNr(); } int Ngx_Mesh :: GetIdentificationType(int idnr) const { return mesh->GetIdentifications().GetType(idnr+1); } Ng_BufferMS Ngx_Mesh::GetFaceEdges (int fnr) const { const MeshTopology & topology = mesh->GetTopology(); NgArrayMem ia; topology.GetFaceEdges (fnr+1, ia); Ng_BufferMS res(ia.Size()); for (size_t i = 0; i < ia.Size(); i++) res[i] = ia[i]-1; return res; } template<> DLL_HEADER void Ngx_Mesh :: MultiElementTransformation<1,1> (int elnr, int npts, const SIMD * xi, size_t sxi, SIMD * x, size_t sx, SIMD * dxdxi, size_t sdxdxi) const { cout << "multi-eltrafo simd called, 1,1,simd" << endl; } template<> DLL_HEADER void Ngx_Mesh :: MultiElementTransformation<2,2> (int elnr, int npts, const SIMD * xi, size_t sxi, SIMD * x, size_t sx, SIMD * dxdxi, size_t sdxdxi) const { mesh->GetCurvedElements().CalcMultiPointSurfaceTransformation<2> (elnr, npts, xi, sxi, x, sx, dxdxi, sdxdxi); /* for (int i = 0; i < npts; i++) { double hxi[4][2]; double hx[4][2]; double hdxdxi[4][4]; for (int j = 0; j < 4; j++) for (int k = 0; k < 2; k++) hxi[j][k] = ((double*)&(xi[k]))[j]; MultiElementTransformation<2,2> (elnr, 4, &hxi[0][0], 2, &hx[0][0], 2, &hdxdxi[0][0], 4); for (int j = 0; j < 4; j++) for (int k = 0; k < 2; k++) ((double*)&(x[k]))[j] = hx[j][k]; for (int j = 0; j < 4; j++) for (int k = 0; k < 4; k++) ((double*)&(dxdxi[k]))[j] = hdxdxi[j][k]; xi += sxi; x += sx; dxdxi += sdxdxi; } */ } template<> DLL_HEADER void Ngx_Mesh :: MultiElementTransformation<3,3> (int elnr, int npts, const SIMD * xi, size_t sxi, SIMD * x, size_t sx, SIMD * dxdxi, size_t sdxdxi) const { mesh->GetCurvedElements().CalcMultiPointElementTransformation (elnr, npts, xi, sxi, x, sx, dxdxi, sdxdxi); /* for (int i = 0; i < npts; i++) { double hxi[4][3]; double hx[4][3]; double hdxdxi[4][9]; for (int j = 0; j < 4; j++) for (int k = 0; k < 3; k++) hxi[j][k] = ((double*)&(xi[k]))[j]; MultiElementTransformation<3,3> (elnr, 4, &hxi[0][0], 3, &hx[0][0], 3, &hdxdxi[0][0], 9); for (int j = 0; j < 4; j++) for (int k = 0; k < 3; k++) ((double*)&(x[k]))[j] = hx[j][k]; for (int j = 0; j < 4; j++) for (int k = 0; k < 9; k++) ((double*)&(dxdxi[k]))[j] = hdxdxi[j][k]; xi += sxi; x += sx; dxdxi += sdxdxi; } */ } template<> DLL_HEADER void Ngx_Mesh :: MultiElementTransformation<0,2> (int elnr, int npts, const SIMD *xi, size_t sxi, SIMD * x, size_t sx, SIMD * dxdxi, size_t sdxdxi) const { //cout << "MultiElementtransformation<0,2> simd not implemented" << endl; PointIndex pi = mesh->pointelements[elnr].pnum; Point<3> xg = mesh->Point(pi); if (x) for (int j = 0; j < npts; j++) for (int i = 0; i < 2; i++) x[j*sx+i] = xg(i); } template<> DLL_HEADER void Ngx_Mesh :: MultiElementTransformation<0,1> (int elnr, int npts, const SIMD * xi, size_t sxi, SIMD * x, size_t sx, SIMD * dxdxi, size_t sdxdxi) const { //cout << "multi-eltrafo simd called, 0,1,simd" << endl; PointIndex pi = mesh->pointelements[elnr].pnum; Point<3> xg = mesh->Point(pi); if (x) for (int j = 0; j < npts; j++) for (int i = 0; i < 1; i++) x[j*sx+i] = xg(i); } template<> DLL_HEADER void Ngx_Mesh :: MultiElementTransformation<1,3> (int elnr, int npts, const SIMD * xi, size_t sxi, SIMD * x, size_t sx, SIMD * dxdxi, size_t sdxdxi) const { mesh->GetCurvedElements().CalcMultiPointSegmentTransformation<3> (elnr, npts, xi, sxi, x, sx, dxdxi, sdxdxi); /* double hxi[4][1]; double hx[4][3]; double hdxdxi[4][3]; for (int j = 0; j<4;j++) hxi[j][0] = ((double*)&(xi[0]))[j]; MultiElementTransformation<1,3> (elnr, 4, &hxi[0][0], 1, &hx[0][0], 3, &hdxdxi[0][0],3); for(int j=0; j<4; j++) for(int k=0; k<3; k++) ((double*)&(x[k]))[j] = hx[j][k]; for(int j=0; j< 4; j++) for (int k = 0; k<3; k++) ((double*) & (dxdxi[k]))[j] = hdxdxi[j][k]; xi += sxi; x += sx; dxdxi += sdxdxi; */ } template<> DLL_HEADER void Ngx_Mesh :: MultiElementTransformation<1,2> (int elnr, int npts, const SIMD * xi, size_t sxi, SIMD * x, size_t sx, SIMD * dxdxi, size_t sdxdxi) const { mesh->GetCurvedElements().CalcMultiPointSegmentTransformation<2> (elnr, npts, xi, sxi, x, sx, dxdxi, sdxdxi); /* for (int i = 0; i < npts; i++) { double hxi[4][1]; double hx[4][2]; double hdxdxi[4][2]; for (int j = 0; j < 4; j++) for (int k = 0; k < 1; k++) hxi[j][k] = ((double*)&(xi[k]))[j]; MultiElementTransformation<1,2> (elnr, 4, &hxi[0][0], 1, &hx[0][0], 2, &hdxdxi[0][0], 2); for (int j = 0; j < 4; j++) for (int k = 0; k < 2; k++) ((double*)&(x[k]))[j] = hx[j][k]; for (int j = 0; j < 4; j++) for (int k = 0; k < 2; k++) ((double*)&(dxdxi[k]))[j] = hdxdxi[j][k]; xi += sxi; x += sx; dxdxi += sdxdxi; } */ } template<> DLL_HEADER void Ngx_Mesh :: MultiElementTransformation<2,3> (int elnr, int npts, const SIMD * xi, size_t sxi, SIMD * x, size_t sx, SIMD * dxdxi, size_t sdxdxi) const { mesh->GetCurvedElements().CalcMultiPointSurfaceTransformation<3> (elnr, npts, xi, sxi, x, sx, dxdxi, sdxdxi); /* for (int i = 0; i < npts; i++) { double hxi[4][2]; double hx[4][3]; double hdxdxi[4][6]; for (int j = 0; j < 4; j++) for (int k = 0; k < 2; k++) hxi[j][k] = ((double*)&(xi[k]))[j]; MultiElementTransformation<2,3> (elnr, 4, &hxi[0][0], 2, &hx[0][0], 3, &hdxdxi[0][0], 6); for (int j = 0; j < 4; j++) for (int k = 0; k < 3; k++) ((double*)&(x[k]))[j] = hx[j][k]; for (int j = 0; j < 4; j++) for (int k = 0; k < 6; k++) ((double*)&(dxdxi[k]))[j] = hdxdxi[j][k]; xi += sxi; x += sx; dxdxi += sdxdxi; } */ } template<> DLL_HEADER void Ngx_Mesh :: MultiElementTransformation<0,3> (int elnr, int npts, const SIMD * xi, size_t sxi, SIMD * x, size_t sx, SIMD * dxdxi, size_t sdxdxi) const { for (int i = 0; i < npts; i++) { double hxi[4][1]; double hx[4][3]; for (int j = 0; j < 4; j++) for (int k = 0; k < 1; k++) hxi[j][k] = ((double*)&(xi[k]))[j]; MultiElementTransformation<0,3> (elnr, 4, &hxi[0][0], 2, &hx[0][0], 3, (double*)nullptr, 0); for (int j = 0; j < 4; j++) for (int k = 0; k < 3; k++) ((double*)&(x[k]))[j] = hx[j][k]; xi += sxi; x += sx; dxdxi += sdxdxi; } } template <> DLL_HEADER int Ngx_Mesh :: FindElementOfPoint <1> (double * hp, double * lami, bool build_searchtree, int * const indices, int numind, double tol) const { Point<3> p(hp[0], 0., 0.); if(mesh->GetDimension() > 1) p[1] = hp[1]; if(mesh->GetDimension() == 3) p[2] = hp[2]; for (SegmentIndex si = 0; si < mesh->GetNSeg(); si++) { auto & seg = (*mesh)[si]; Point<3> p1 = (*mesh)[seg[0]]; Point<3> p2 = (*mesh)[seg[1]]; Vec<3> v1 = p2-p1; Vec<3> v2 = p-p1; double lam = v1*v2 / v1.Length2(); double lam2 = (v2 - lam * v1).Length() / v1.Length(); if (lam >= -1e-10 && lam <= 1+1e-10 && lam2 < 1e-10) { lami[0] = 1-lam; return si; } } return -1; } template <> DLL_HEADER int Ngx_Mesh :: FindElementOfPoint <2> (double * p, double * lami, bool build_searchtree, int * const indices, int numind, double tol) const { Point<3> pp(p[0], p[1], 0.); if(mesh->GetDimension() == 3) pp[2] = p[2]; FlatArray ind(numind, indices); double lam3[3]; auto elnr = mesh->GetSurfaceElementOfPoint(pp, lam3, ind, build_searchtree); if(elnr.IsValid()) { if((*mesh)[elnr].GetType() == QUAD || (*mesh)[elnr].GetType() == TRIG6) { lami[0] = lam3[0]; lami[1] = lam3[1]; } else { lami[0] = 1-lam3[0]-lam3[1]; lami[1] = lam3[0]; } } return elnr; } template <> DLL_HEADER int Ngx_Mesh :: FindElementOfPoint <3> (double * p, double * lami, bool build_searchtree, int * const indices, int numind, double tol) const { Point<3> pp(p[0], p[1], p[2]); FlatArray ind(numind, indices); return mesh->GetElementOfPoint(pp, lami, ind, build_searchtree, true, tol); } void Ngx_Mesh :: Curve (int order) { NgLock meshlock (mesh->MajorMutex(), true); mesh->BuildCurvedElements(order); } int Ngx_Mesh :: GetCurveOrder () { return mesh->GetCurvedElements().GetOrder(); } void Ngx_Mesh :: EnableTable (string name, bool set) { mesh->GetTopology().EnableTable (name, set); mesh->SetNextTimeStamp(); // update topology will do work } template <> DLL_HEADER void Ngx_Mesh :: SetRefinementFlag<2> (size_t elnr, bool flag) { mesh->SurfaceElement(elnr+1).SetRefinementFlag(flag); } template <> DLL_HEADER void Ngx_Mesh :: SetRefinementFlag<3> (size_t elnr, bool flag) { mesh->VolumeElement(elnr+1).SetRefinementFlag(flag); } void Ngx_Mesh :: Refine (NG_REFINEMENT_TYPE reftype, bool onlyonce, void (*task_manager)(function), NgTracer tracer) { NgLock meshlock (mesh->MajorMutex(), 1); BisectionOptions biopt; biopt.usemarkedelements = 1; biopt.refine_p = 0; biopt.refine_hp = 0; biopt.onlyonce = onlyonce; if (reftype == NG_REFINE_P) biopt.refine_p = 1; if (reftype == NG_REFINE_HP) biopt.refine_hp = 1; biopt.task_manager = task_manager; biopt.tracer = tracer; mesh->GetGeometry()->GetRefinement().Bisect (*mesh, biopt); (*tracer)("call updatetop", false); mesh -> UpdateTopology(task_manager, tracer); (*tracer)("call updatetop", true); if(mesh->GetCurvedElements().IsHighOrder()) mesh->GetCurvedElements() .BuildCurvedElements(&mesh->GetGeometry()->GetRefinement(), mesh->GetCurvedElements().GetOrder()); } // just copied with redesign size_t Ngx_Mesh::GetNP() const { return mesh->GetNP(); } int Ngx_Mesh::GetSurfaceElementSurfaceNumber (size_t ei) const { if (mesh->GetDimension() == 3) return mesh->GetFaceDescriptor(mesh->SurfaceElement(ei).GetIndex()).SurfNr(); else return mesh->LineSegment(ei).si; } int Ngx_Mesh::GetSurfaceElementFDNumber (size_t ei) const { if (mesh->GetDimension() == 3) return mesh->SurfaceElement(ei).GetIndex(); else return -1; } void Ngx_Mesh::HPRefinement (int levels, double parameter, bool setorders, bool ref_level) { NgLock meshlock (mesh->MajorMutex(), true); Refinement & ref = const_cast (mesh->GetGeometry()->GetRefinement()); ::netgen::HPRefinement (*mesh, &ref, SPLIT_HP, levels, parameter, setorders, ref_level); } void Ngx_Mesh::SplitAlfeld () { NgLock meshlock (mesh->MajorMutex(), true); Refinement & ref = const_cast (mesh->GetGeometry()->GetRefinement()); ::netgen::HPRefinement (*mesh, &ref, SPLIT_ALFELD, 1, 1.0 / (mesh->GetDimension()+1), true, true); } int Ngx_Mesh::GetElementOrder (int enr) const { if (mesh->GetDimension() == 3) return mesh->VolumeElement(enr).GetOrder(); else return mesh->SurfaceElement(enr).GetOrder(); } void Ngx_Mesh::GetElementOrders (int enr, int * ox, int * oy, int * oz) const { if (mesh->GetDimension() == 3) { ElementIndex ei = IndexBASE() + enr-1; mesh->VolumeElement(ei).GetOrder(*ox, *oy, *oz); } else { SurfaceElementIndex sei = IndexBASE() + enr-1; mesh->SurfaceElement(sei).GetOrder(*ox, *oy, *oz); } } void Ngx_Mesh::SetElementOrder (int enr, int order) { if (mesh->GetDimension() == 3) return mesh->VolumeElement(enr).SetOrder(order); else return mesh->SurfaceElement(enr).SetOrder(order); } void Ngx_Mesh::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 Ngx_Mesh::GetSurfaceElementOrder (int enr) const { return mesh->SurfaceElement(enr).GetOrder(); } int Ngx_Mesh::GetClusterRepVertex (int pi) const { return mesh->GetClusters().GetVertexRepresentant(pi); } int Ngx_Mesh::GetClusterRepEdge (int pi) const { return mesh->GetClusters().GetEdgeRepresentant(pi); } int Ngx_Mesh::GetClusterRepFace (int pi) const { return mesh->GetClusters().GetFaceRepresentant(pi); } int Ngx_Mesh::GetClusterRepElement (int pi) const { return mesh->GetClusters().GetElementRepresentant(pi); } int Ngx_Mesh::GetElement_Faces (int elnr, int * faces, int * orient) const { const MeshTopology & topology = mesh->GetTopology(); if (mesh->GetDimension() == 3) { int num = topology.GetElementFaces (elnr+1, faces, orient); for (int i = 0; i < num; i++) faces[i]--; return num; } else { faces[0] = elnr; if (orient) orient[0] = 0; return 1; } } int Ngx_Mesh::GetSurfaceElement_Face (int selnr, int * orient) const { if (mesh->GetDimension() == 3) { const MeshTopology & topology = mesh->GetTopology(); if (orient) *orient = topology.GetSurfaceElementFaceOrientation (selnr+1); return topology.GetFace (SurfaceElementIndex(selnr)); } return -1; } //HERBERT: falsche Anzahl von Argumenten //void Ngx_Mesh::GetSurfaceElementOrders (int enr, int * ox, int * oy, int * oz) void Ngx_Mesh::GetSurfaceElementOrders (int enr, int * ox, int * oy) const { int d; mesh->SurfaceElement(enr).GetOrder(*ox, *oy, d); } void Ngx_Mesh::SetSurfaceElementOrder (int enr, int order) { return mesh->SurfaceElement(enr).SetOrder(order); } void Ngx_Mesh::SetSurfaceElementOrders (int enr, int ox, int oy) { mesh->SurfaceElement(enr).SetOrder(ox, oy); } size_t Ngx_Mesh :: GetGlobalVertexNum (int locnum) const { #ifdef PARALLEL return mesh->GetParallelTopology().GetGlobalPNum (locnum+1)-1; #else return locnum; #endif } FlatArray Ngx_Mesh :: GetDistantProcs (int nodetype, int locnum) const { #ifdef PARALLEL if (mesh->GetCommunicator().Size() == 1) return FlatArray(0,nullptr); switch (nodetype) { case 0: // return mesh->GetParallelTopology().GetDistantPNums(locnum); return mesh->GetParallelTopology().GetDistantProcs(locnum+PointIndex::BASE); case 1: // return mesh->GetParallelTopology().GetDistantEdgeNums(locnum); return mesh->GetParallelTopology().GetDistantEdgeProcs(locnum); case 2: // return mesh->GetParallelTopology().GetDistantFaceNums(locnum); return mesh->GetParallelTopology().GetDistantFaceProcs(locnum); default: return FlatArray(0, nullptr); } #else return FlatArray(0,nullptr); #endif } } int link_it_nginterface_v2; ================================================ FILE: libsrc/interface/read_fnf_mesh.cpp ================================================ // // Read Pro/ENGINEER neutral format // #include #include #include #include #include #include #include "writeuser.hpp" namespace netgen { 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; NgArray places; }; void ReadFNFFormat (Mesh & mesh, const filesystem::path & filename) { ifstream fin (filename); 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; PrintMessage(3, "Title: ", name); } else if (token == "%STATISTICS") { ; } else if (token == "%END_SECT") { break; } else { PrintMessage(1, "SECTION HEADER, unknown field: ",buf); } } } 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 { PrintMessage(1, "SECTION ELEM_TYPE, unknown field: ", buf); } } } 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 == "ANALYSIS") { // ignore this section while (1) { ReadLine (fin, buf); stringstream sbuf(buf); string token; sbuf >> token; if (token == "%END_SECT") { break; } } } else if (token == "MATERIALS") { *testout << "parse materials" << endl; NgArray 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") { string name; sbuf >> name; mesh.SetMaterial(nr, name); } 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 { PrintMessage(1, "SECTION MATERIALS, unknown field: ", buf); } } } 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; NgArray 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 { PrintMessage(1, "SECTION MESH, unknown: ", buf); } } } 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") { NgArray 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") { NgArray 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); if(j == 0) mesh.GetFaceDescriptor(nr).SetDomainIn(el.GetIndex()); Element2d el2d; el.GetFace (fnr, el2d); el2d.SetIndex (nr); mesh.AddSurfaceElement (el2d); } } } else if (token == "%END_SECT") { break; } else { PrintMessage(1, "SECTION MESH, unknown: ", buf); } } } else if (token == "LOADS") { NgArray 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") PrintMessage(3, "loadtype DISPLACEMENT found"); if (lt->placement != "FACE" && lt->placement != "EDGE" && lt->placement != "NODE") PrintMessage(1, "unsupported placement ", lt->placement); 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 == "%CON_CASE") { ; } else if (token == "%END_SECT") { for (int i = 0; i < loadtypes.Size(); i++) { stringstream str; str << loadtypes[i]->places; if (loadtypes[i]->placement == "FACE" && loadtypes[i]->name == "DISPLACEMENT") { mesh.SetUserData ("CONSTRAINT_DISP_FACE", loadtypes[i]->places); PrintMessage(3, "constrained faces: ", str.str()); } if (loadtypes[i]->placement == "EDGE" && loadtypes[i]->name == "DISPLACEMENT") { mesh.SetUserData ("CONSTRAINT_DISP_EDGE", loadtypes[i]->places); PrintMessage(3,"constrained edges: ", str.str()); } if (loadtypes[i]->placement == "NODE" && loadtypes[i]->name == "DISPLACEMENT") { mesh.SetUserData ("CONSTRAINT_DISP_NODE", loadtypes[i]->places); PrintMessage(3, "constrained nodes: ", str.str()); } } break; } else { PrintMessage(1, "SECTION LOADS, unknown field: ", buf); } } } else { PrintMessage(1, "unknown section ", token); } } else PrintMessage(3, "parse line: (", buf, ")"); } mesh.ComputeNVertices(); } static RegisterUserFormat reg_fnf ("Pro/ENGINEER Format", {".fnf"}, ReadFNFFormat, nullopt); } ================================================ FILE: libsrc/interface/readtetmesh.cpp ================================================ // // Read CST file format // #include #include #include #include #include #include namespace netgen { #include "writeuser.hpp" void ReadTETFormat (Mesh & mesh, const filesystem::path & filename) { 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; NgArray eldom; int minId3D = -1, minId2D = -1; int maxId3D(-1), maxId2D(-1), maxId1D(-1), maxId0D(-1); NgArray *> segmentdata; NgArray tris; NgArray userdata_int; // just save data for 1:1 output NgArray userdata_double; NgArray point_pids; NgArray tetfacedata; NgArray 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=PMinion 3=CPMaster 4=CPMinion), PID: { cout << "read nodes" << endl; for(int i=0; i> 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, MinionNodeID, TranslCode (1=dS1 2=dS2 3=dS1+dS2) for(int i=0; i> dummyint; in >> dummyint; } break; case 10: // Number of Corner Periodic Master Nodes in >> ncornerperiodicmasternodes; break; case 11: // MasterNodeID, 3-MinionNodeID's, 3-TranslCodes (1=dS1 2=dS2 3=dS1+dS2) for(int i=0; i> 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-MinionNodeID's, TranslCodes for(int i=0; i> dummyint; for(int j=0; j<7; j++) in >> dummyint; } break; case 14: // EdgeID, NodeID0, NodeID1, Type (0=Reg 1=PMaster 2=PMinion 3=CPMaster 4=CPMinion), PID cout << "read edges" << endl; // nullstarted = false; segmentdata.SetSize(nedges); for(int i=0; i(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, MinionEdgeID, TranslCode (1=dS1 2=dS2 3=dS1+dS2) for(int i=0; i> dummyint >> dummyint >> dummyint; break; case 17: // Number of Corner Periodic Master Edges in >> ncornerperiodicmasteredges; break; case 18: // MasterEdgeID, 3 MinionEdgeID's, 3 TranslCode (1=dS1 2=dS2 3=dS1+dS2) for(int i=0; i> 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=PMinion), PID { //Segment seg; int segnum_ng[3]; bool neg[3]; cout << "read faces" << endl; // nullstarted = false; for(int i=0; i> 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"<> nperiodicmasterfaces; break; case 21: // MasterFaceID, MinionFaceID, TranslCode (1=dS1 2=dS2) { Vec<3> randomvec(-1.32834,3.82399,0.5429151); int maxtransl = -1; for(int i=0; i nodes1(3),nodes2(3); NgArray 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> 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; // NgArray indextodescriptor(maxId2D+1); // for(int i=1; i<=mesh.GetNFD(); i++) // indextodescriptor[mesh.GetFaceDescriptor(i).SurfNr()] = i; // for(SurfaceElementIndex i=0; i> 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 ElemID List { uid_to_group_3D.SetSize(maxId3D+1); uid_to_group_3D = -1; for(int i=0; i> groupid; (*testout) << "3d groupid " << groupid << endl; //userdata_int.Append(groupid); int nelems; in >> nelems; //userdata_int.Append(nelems); for(int j=0; j> 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 FaceID List { NgArray ports; //int totnum = 0; uid_to_group_2D.SetSize(maxId2D+1); uid_to_group_2D = -1; for(int i=0; i> groupid; (*testout) << "2d groupid " << groupid << endl; //userdata_int.Append(groupid); int nelems; in >> nelems; //userdata_int.Append(nelems); for(int j=0; j> 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 EdgeID List { uid_to_group_1D.SetSize(maxId1D+1); uid_to_group_1D = -1; for(int i=0; i> groupid; //userdata_int.Append(groupid); int nelems; in >> nelems; //userdata_int.Append(nelems); for(int j=0; j> 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 NodeID List { uid_to_group_0D.SetSize(maxId0D+1); uid_to_group_0D = -1; for(int i=0; i> groupid; //userdata_int.Append(groupid); int nelems; in >> nelems; //userdata_int.Append(nelems); for(int j=0; j> 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); NgArray surfindices(tris.Size()); surfindices = -1; for(int i=0; iGetIndex() > 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 indextodescriptor(maxId2D+1); // for(int i=1; i<=mesh.GetNFD(); i++) // indextodescriptor[mesh.GetFaceDescriptor(i).SurfNr()] = i; // for(SurfaceElementIndex i=0; i 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(); } } ================================================ FILE: libsrc/interface/readuser.cpp ================================================ // // Read user dependent output file // #include #include #include #include #include #include #include #include "writeuser.hpp" namespace netgen { extern void ReadTETFormat (Mesh & mesh, const filesystem::path & filename); extern void ReadFNFFormat (Mesh & mesh, const filesystem::path & filename); #ifdef NG_CGNS extern void ReadCGNSMesh (Mesh & mesh, const filesystem::path & filename); #endif // NG_CGNS void ReadFile (Mesh & mesh, const filesystem::path & filename) { PrintMessage(3, "Read User File"); auto ext = filename.extension(); char reco[100]; int np, nbe; if ( ext == ".surf" ) { cout << IM(3) << "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(); mesh.AddPoint (p); } mesh.ClearFaceDescriptors(); mesh.AddFaceDescriptor (FaceDescriptor(1,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 << IM(3) << "points: " << np << " faces: " << nbe << endl; } if ( ext == ".unv" ) { char reco[100]; // int invert; // read files that are stored with D instead of E as exponent prefix // such files are for example exported by GMSH bool Dnotation; bool DnotationSet = false; ifstream in(filename); mesh.ClearFaceDescriptors(); mesh.AddFaceDescriptor (FaceDescriptor(0,1,0,0)); mesh.GetFaceDescriptor(1).SetBCProperty (1); // map from unv element nr to our element number + an index if it is vol (0), bnd(1), ... std::map> element_map; int dim = 3; int bccounter = 0; NgArray tmp_segments; while (in.good()) { in >> reco; if (strcmp(reco, "-1") == 0) continue; else if (strcmp (reco, "2411") == 0) { cout << IM(3) << "nodes found" << endl; while (1) { int pi, hi; Point<3> p; string p1tmp, p2tmp, p3tmp; in >> pi; if (pi == -1) break; in >> hi >> hi >> hi; // check if D in first line if (DnotationSet == false) { in >> p1tmp >> p2tmp >> p3tmp; if (p1tmp.find("D") != std::string::npos){ Dnotation = true; cout << IM(3) << "Attention: in your UNV file, D is used as an exponent prefix instead of E" << endl; std::replace(p1tmp.begin(), p1tmp.end(), 'D', 'E'); std::replace(p2tmp.begin(), p2tmp.end(), 'D', 'E'); std::replace(p3tmp.begin(), p3tmp.end(), 'D', 'E'); } p(0) = std::stod(p1tmp); p(1) = std::stod(p2tmp); p(2) = std::stod(p3tmp); mesh.AddPoint(p); DnotationSet = true; continue; } if (Dnotation == true) { in >> p1tmp >> p2tmp >> p3tmp; std::replace(p1tmp.begin(), p1tmp.end(), 'D', 'E'); std::replace(p2tmp.begin(), p2tmp.end(), 'D', 'E'); std::replace(p3tmp.begin(), p3tmp.end(), 'D', 'E'); p(0) = std::stod(p1tmp); p(1) = std::stod(p2tmp); p(2) = std::stod(p3tmp); } else{ in >> p(0) >> p(1) >> p(2); } mesh.AddPoint(p); } cout << IM(3) << "read " << mesh.GetNP() << " points" << endl; Point3d pmin, pmax; cout << IM(5) << "Get Box" << endl; mesh.GetBox (pmin, pmax); cout << IM(5) << "Pmin: " << pmin << " Pmax: " << pmax << endl; if(fabs(pmin.Z() - pmax.Z()) < 1e-10 * Dist(pmin, pmax)) { cout << IM(5) << "Set Dimension to 2." << endl; mesh.SetDimension(2); dim = 2 ; } } else if (strcmp (reco, "2412") == 0) { cout << IM(3) << "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; 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 11: // (Rod) SEGM { Segment el; el[0] = nodes[0]; el[1] = nodes[1]; el[2] = -1; if(dim == 3){ auto nr = tmp_segments.Size(); tmp_segments.Append(el); element_map[label] = std::make_tuple(nr+1, 2); } else if(dim == 2){ el.si = -1; // add label to segment, will be changed later when BC's are assigned auto nr = mesh.AddSegment(el); element_map[label] = std::make_tuple(nr+1, 2); } break; } case 22: // (Tapered beam) SEGM { Segment el; el[0] = nodes[0]; el[1] = nodes[2]; el[2] = nodes[1]; if(dim == 3){ auto nr = tmp_segments.Size(); tmp_segments.Append(el); element_map[label] = std::make_tuple(nr+1, 2); } else if(dim == 2){ el.si = -1; // add label to segment, will be changed later when BC's are assigned auto nr = mesh.AddSegment(el); element_map[label] = std::make_tuple(nr+1, 2); } break; } case 41: // TRIG { Element2d el (TRIG); el.SetIndex (1); for (int j = 0; j < nnodes; j++) el[j] = nodes[j]; auto nr = mesh.AddSurfaceElement (el); element_map[label] = std::make_tuple(nr+1, 1); break; } case 42: // TRIG6 { Element2d el(TRIG6); el.SetIndex(1); int jj = 0; for(auto j : {0,2,4,3,5,1}) el[jj++] = nodes[j]; auto nr = mesh.AddSurfaceElement(el); element_map[label] = std::make_tuple(nr+1, 1); break; } case 111: // TET { Element el (TET); el.SetIndex (1); for (int j = 0; j < nnodes; j++) el[j] = nodes[j]; auto nr = mesh.AddVolumeElement (el); element_map[label] = std::make_tuple(nr+1, 0); break; } case 118: // TET10 { Element el(TET10); el.SetIndex(1); int jj = 0; for(auto j : {0,2,4,9,1,5,6,3,7,8}) el[jj++] = nodes[j]; auto nr = mesh.AddVolumeElement(el); element_map[label] = std::make_tuple(nr+1, 0); break; } default: cout << IM(3) << "Do not know fe_id = " << fe_id << ", skipping it." << endl; break; } } cout << IM(3) << mesh.GetNE() << " elements found" << endl; cout << IM(3) << mesh.GetNSE() << " surface elements found" << endl; } else if(strcmp (reco, "2467") == 0) { int matnr = 1; cout << IM(3) << "Groups found" << endl; while(in.good()) { int len; string name; in >> len; if(len == -1) break; for(int i=0; i < 7; i++) in >> len; in >> name; cout << IM(3) << len << " element are in group " << name << endl; int hi, index; int fdnr=-1, ednr=-1; in >> hi >> index >> hi >> hi; int codim = get<1>(element_map[index]); // use first element to determine if boundary or volume switch (codim) { case 0: { mesh.SetMaterial(++matnr, name); mesh.VolumeElement(get<0>(element_map[index])).SetIndex(matnr); break; } case 1: { if(dim == 3) { int bcpr = mesh.GetNFD(); fdnr = mesh.AddFaceDescriptor(FaceDescriptor(bcpr, 0,0,0)); mesh.GetFaceDescriptor(fdnr).SetBCProperty(bcpr+1); mesh.SetBCName(bcpr, name); mesh.SurfaceElement(get<0>(element_map[index])).SetIndex(fdnr); bccounter++; } else if(dim == 2) { mesh.SetMaterial(matnr, name); fdnr = mesh.AddFaceDescriptor(FaceDescriptor(matnr, 0,0,0)); mesh.SurfaceElement(get<0>(element_map[index])).SetIndex(matnr); mesh.GetFaceDescriptor(fdnr).SetBCProperty(matnr); matnr++; } break; } case 2: { if(dim == 3) { int bcpr = mesh.GetNCD2Names()+1; auto ed = EdgeDescriptor(); ed.SetSurfNr(0,bcpr);//? ednr = mesh.AddEdgeDescriptor(ed); mesh.SetCD2Name(bcpr, name); auto nr = mesh.AddSegment(tmp_segments[get<0>(element_map[index])-1]); mesh[nr].edgenr = ednr+1; } else if(dim == 2) { Segment & seg = mesh.LineSegment(get<0>(element_map[index])); seg.si = bccounter + 1; mesh.SetBCName(bccounter, name); bccounter++; } break; } default: { cout << IM(3) << "Codim " << codim << " not implemented yet!" << endl; } } for(int i=0; i> hi >> index >> hi >> hi; switch (codim) { case 0: mesh.VolumeElement(get<0>(element_map[index])).SetIndex(matnr); break; case 1: if(dim == 3) mesh.SurfaceElement(get<0>(element_map[index])).SetIndex(fdnr); else if (dim == 2){ mesh.SurfaceElement(get<0>(element_map[index])).SetIndex(matnr-1); mesh.GetFaceDescriptor(fdnr).SetBCProperty(matnr); } break; case 2: if(dim == 3) { auto nr = mesh.AddSegment(tmp_segments[get<0>(element_map[index])-1]); mesh[nr].edgenr = ednr+1; } else if(dim == 2) { Segment & seg = mesh.LineSegment(get<0>(element_map[index])); seg.si = bccounter; } break; default: break; } } } } else { cout << IM(3) << "Do not know data field type " << reco << ", skipping it" << endl; while(in.good()) { in >> reco; if(strcmp(reco, "-1") == 0) break; } } } if(dim == 2){ // loop through segments to assign default BC to unmarked edges int bccounter_tmp = bccounter; for(int index=1; index <= mesh.GetNSeg(); index++){ Segment & seg = mesh.LineSegment(index); if(seg.si == -1){ seg.si = bccounter + 1; if(bccounter_tmp == bccounter) mesh.SetBCName(bccounter, "default"); // could be more efficient bccounter_tmp++; } } if(bccounter_tmp > bccounter) bccounter++; } cout << IM(5) << "Finalize mesh" << endl; Point3d pmin, pmax; cout << IM(5) << "ComputeNVertices" << endl; mesh.ComputeNVertices(); cout << IM(5) << "RebuildSurfaceElementLists" << endl; mesh.RebuildSurfaceElementLists(); cout << IM(5) << "GetBox" << endl; mesh.GetBox (pmin, pmax); cout << IM(5) << "UpdateTopology" << endl; mesh.UpdateTopology(); cout << IM(5) << "increment bccounter" << endl; if(dim == 3) bccounter++; cout << IM(5) << "bounding-box = " << pmin << "-" << pmax << endl; cout << IM(5) << "Created " << bccounter << " boundaries." << endl; for(int i=0; i> 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 ( ext == ".mesh" ) { cout << IM(3) << "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)); int nfd = 1; in >> nse; for (i = 1; i <= nse; i++) { int mat; // , nelp; in >> mat; Element2d el (TRIG); el.SetIndex (mat); while(nfd> el.PNum(j); mesh.AddSurfaceElement (el); } } else { char buf[100]; in.clear(); do { in >> buf; cout << IM(5) << "buf = " << buf << endl; if (strcmp (buf, "points") == 0) { in >> np; cout << IM(5) << "np = " << np << endl; } } while (in.good()); } } if ( ext == ".emt" ) { ifstream inemt (filename); auto pktfile = filename; pktfile.replace_extension("pkt"); cout << IM(3) << "pktfile = " << pktfile << endl; int np, nse, i; int bcprop; ifstream inpkt (pktfile); inpkt >> np; NgArray 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 << IM(3) << "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 << IM(3) << "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 << IM(3) << "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 ( ext == ".tet" ) ReadTETFormat (mesh, filename); // .fnf mesh (FNF - PE neutral format) if ( ext == ".fnf" ) ReadFNFFormat (mesh, filename); #ifdef NG_CGNS // .cgns file - CFD General Notation System if ( ext == ".cgns" ) ReadCGNSMesh (mesh, filename); #endif // NG_CGNS if ( ext == ".stl" || ext == ".stlb" ) { ifstream ist{filename}; auto geom = shared_ptr(STLGeometry::Load(ist)); mesh.SetDimension (3); auto & points = geom->GetPoints(); for (auto & p : points) mesh.AddPoint(MeshPoint(p)); mesh.AddFaceDescriptor (FaceDescriptor (1, 1, 0, 1)); for (auto ti : IntRange(geom->GetNT())) { Element2d el(TRIG); for (auto i : IntRange(3)) el[i] = int((*geom)[STLTrigId(ti+IndexBASE())][i]); el.SetIndex(1); mesh.AddSurfaceElement(el); } } } void ReadUserFormat(Mesh & mesh, const filesystem::path & filename, const string & format) { if(format == "") return ReadFile(mesh, filename); if(!UserFormatRegister::HaveFormat(format)) throw Exception("Unknown format: " + format); const auto entry = UserFormatRegister::Get(format); if(!entry.read) throw Exception("Reading format " + format + " is not implemented"); (*entry.read)(mesh, filename); } static RegisterUserFormat reg_uni ("Universial Format", {".unv"}, ReadFile, nullopt); static RegisterUserFormat reg_olaf ("Olaf Format", {".emt"}, ReadFile, nullopt); } ================================================ FILE: libsrc/interface/rw_cgns.cpp ================================================ #include #include "writeuser.hpp" #ifdef NG_CGNS #include #include namespace netgen::cg { typedef ngcore::ClosedHashTable, size_t> PointTable; int getDim(ElementType_t type) { switch(type) { case BAR_2: case BAR_3: return 1; case TRI_3: case TRI_6: case QUAD_4: case QUAD_8: return 2; case TETRA_4: case TETRA_10: case PYRA_5: case PYRA_13: case HEXA_8: case HEXA_20: case PENTA_6: case PENTA_15: return 3; default: throw Exception("Read CGNS: unknown element type " + string(cg_ElementTypeName(type))); } } Segment ReadCGNSElement1D( ElementType_t type, FlatArray verts ) { int np; cg_npe(type, &np); Segment s; for (auto i : Range(np)) s[i] = verts[i]; return s; } Element2d ReadCGNSElement2D( ElementType_t type, FlatArray verts ) { // static constexpr int map_tri3[] = {0,2,1}; static constexpr int map_tri6[] = {0,2,1,3,5,4}; // untested // static constexpr int map_quad4[] = {0,3,2,1}; static constexpr int map_quad8[] = {0,3,2,1,4,7,6,5}; // untested const int * map = nullptr; switch(type) { case TRI_3: // map = map_tri3; break; case QUAD_4: // map = map_quad4; break; case TRI_6: map = map_tri6; break; case QUAD_8: map = map_quad8; break; default: throw Exception("Read CGNS: unknown element type " + string(cg_ElementTypeName(type))); } int np; cg_npe(type, &np); Element2d el(np); for (auto i : Range(np)) el[i] = verts[i]; return el; } Element ReadCGNSElement3D( ElementType_t type, FlatArray verts ) { static constexpr int map_tet4[] = {0,2,1,3}; static constexpr int map_prism6[] = {0,2,1,3,5,4}; static constexpr int map_pyra5[] = {0,3,2,1,4}; static constexpr int map_hexa8[] = {0,3,2,1,4,7,6,5}; int np; cg_npe(type, &np); const int * map = nullptr; switch(type) { case TETRA_4: map = map_tet4; break; case PYRA_5: map = map_pyra5; break; case PENTA_6: map = map_prism6; break; case HEXA_8: map = map_hexa8; break; // TODO: Second order elements case TETRA_10: case PYRA_13: case HEXA_20: case PENTA_15: default: throw Exception("Read CGNS: unknown element type " + string(cg_ElementTypeName(type))); } Element el(np); for (auto i : Range(np)) el[i] = verts[map[i]]; return el; } void WriteCGNSElement( const Segment & el, Array & verts ) { verts.Append(BAR_2); verts.Append(el[0]); verts.Append(el[1]); } void WriteCGNSElement( const Element2d & el, Array & verts ) { static constexpr int map_tri6[] = {0,2,1,3,5,4}; // untested static constexpr int map_quad8[] = {0,3,2,1,4,7,6,5}; // untested ElementType_t type; const int * map = nullptr; switch(el.GetType()) { case TRIG: type = TRI_3; break; case QUAD: type = QUAD_4; break; case TRIG6: type = TRI_6; map = map_tri6; break; case QUAD8: type = QUAD_8; map = map_quad8; break; // TODO: Second order elements default: throw Exception("Write CGNS: unknown element type " + ToString(el.GetType())); } verts.Append(type); for (auto i : Range(el.GetNP())) verts.Append(el[i]); } void WriteCGNSElement( const Element & el, Array & verts ) { static constexpr int map_tet4[] = {0,2,1,3}; static constexpr int map_prism6[] = {0,2,1,3,5,4}; static constexpr int map_pyra5[] = {0,3,2,1,4}; static constexpr int map_hexa8[] = {0,3,2,1,4,7,6,5}; ElementType_t type; const int * map = nullptr; switch(el.GetType()) { case TET: map = map_tet4; type = TETRA_4; break; case PYRAMID: type = PYRA_5; map = map_pyra5; break; case PRISM: type = PENTA_6; map = map_prism6; break; case HEX: type = HEXA_8; map = map_hexa8; break; // TODO: Second order elements default: throw Exception("Write CGNS: unknown element type " + ToString(el.GetType())); } verts.Append(type); for (auto i : Range(el.GetNP())) verts.Append(el[map[i]]); } int WriteCGNSRegion( const Mesh & mesh, int dim, int index, int fn, int base, int zone, int ne_before ) { int meshdim = mesh.GetDimension(); int codim = meshdim-dim; if(codim < 0 || codim > 2) return 0; // make sure that each material/boundary name is unique string prefix[] = { "dom_", "bnd_", "bbnd_" }; string name = prefix[meshdim-dim] + ToString(index) + "_"; if(codim==0) name += mesh.GetMaterial(index+1); if(codim==1) name += *mesh.GetBCNamePtr(index); if(codim==2) name += mesh.GetCD2Name(index); int ne = 0; Array data; if(dim==3) for(const auto el : mesh.VolumeElements()) if(el.GetIndex()==index) { ne++; WriteCGNSElement(el, data); } if(dim==2) for(const auto el : mesh.SurfaceElements()) if(el.GetIndex()==index) { ne++; WriteCGNSElement(el, data); } if(dim==1) for(const auto el : mesh.LineSegments()) if(el.si==index) { ne++; WriteCGNSElement(el, data); } if(ne==0) return 0; int section; // int start = 1; // int end = ne; #if CGNS_VERSION < 3400 cg_section_write(fn,base,zone, name.c_str(), MIXED, ne_before+1, ne_before+ne, 0, &data[0], §ion); #else cg_poly_section_write(fn,base,zone, name.c_str(), MIXED, ne_before+1, ne_before+ne, 0, &data[0], nullptr, §ion); #endif return ne; } // maps cgns node type to ngsolve node type // enum NODE_TYPE { NT_VERTEX = 0, NT_EDGE = 1, NT_FACE = 2, NT_CELL = 3, NT_ELEMENT = 4, NT_FACET = 5 }; int getNodeType( GridLocation_t location ) { switch(location) { case Vertex: return 0; case CellCenter: return 3; case FaceCenter: return 2; case EdgeCenter: return 1; default: throw Exception("Read CGNS: unknown grid location " + string(cg_GridLocationName(location))); } } GridLocation_t getCGNodeType( int node_type ) { switch(node_type) { case 0: return Vertex; case 1: return EdgeCenter; case 2: return FaceCenter; case 3: return CellCenter; default: throw Exception("Write CGNS: unknown node type " + ToString(node_type)); } } struct Solution { int fn, base, zone, solution; string name; GridLocation_t location; // solution is defined on either cells, faces, edges or vertices PointSetType_t point_type; cgsize_t n_points; Array field_names; Array field_datatypes; Solution() = default; Solution(int fn_, int base_, int zone_, int solution_) : fn(fn_), base(base_), zone(zone_), solution(solution_) { char solname[100]; cg_sol_info(fn, base, zone, solution, solname, &location); name = solname; cg_sol_ptset_info(fn, base, zone, solution, &point_type, &n_points); int n_fields = 0; cg_nfields(fn, base, zone, solution, &n_fields); field_names.SetSize(n_fields); field_datatypes.SetSize(n_fields); for(auto fi : Range(n_fields)) { char buf[100]; cg_field_info(fn, base, zone, solution, fi+1, &field_datatypes[fi], buf); field_names[fi] = buf; } } }; struct Zone { ZoneType_t zone_type; int fn, base, zone; int first_index_1d, first_index_2d, first_index_3d; int nv=0, ne_1d=0, ne_2d=0, ne_3d=0; Array names_1d, names_2d, names_3d; string name; cgsize_t size[3]; Array solutions; Zone(int fn_, int base_, int zone_) : fn(fn_), base(base_), zone(zone_) { cg_zone_type(fn, base, zone, &zone_type); char zone_name[100]; cg_zone_read(fn,base,zone, zone_name, size); nv = size[0]; int n_solutions; cg_nsols(fn, base, zone, &n_solutions); solutions.SetSize(n_solutions); for(auto si : Range(n_solutions)) solutions[si] = Solution{fn, base, zone, si+1}; } void ReadSolutions( int meshdim, std::vector & sol_names, std::vector> & sol_values, std::vector & sol_locations ) { static Timer tall("CGNS::ReadSolutions"); RegionTimer rtall(tall); for (auto & sol : solutions) { for (auto fi : Range(sol.field_names.Size())) { cgsize_t size = sol.n_points; size=0; // TODO: check if sol.point_type is a list or range, and handle appropriately if(size==0) { switch(sol.location) { case Vertex: size = nv; break; case CellCenter: size = (meshdim == 3 ? ne_3d : ne_2d); break; case FaceCenter: case IFaceCenter: case JFaceCenter: case KFaceCenter: case EdgeCenter: default: throw Exception("Read CGNS: unknown grid location " + string(cg_GridLocationName(sol.location))); } } auto values = Array(size); cgsize_t imin = 1UL; cg_field_read(fn, base, zone, sol.solution, sol.field_names[fi].c_str(), RealDouble, &imin, &size, &values[0]); sol_names.push_back(sol.field_names[fi]); sol_values.emplace_back(std::move(values)); sol_locations.push_back(getNodeType(sol.location)); } } } void ReadMesh( Mesh & mesh, PointTable & point_table ) { static Timer tall("CGNS::ReadMesh-Zone"); RegionTimer rtall(tall); static Timer tsection("CGNS::ReadMesh-Section"); first_index_1d = mesh.GetRegionNamesCD(2).Size(); first_index_2d = mesh.GetRegionNamesCD(1).Size(); first_index_3d = mesh.GetRegionNamesCD(0).Size(); Array x(nv), y(nv), z(nv); cgsize_t imin=1; cg_coord_read(fn,base,zone, "CoordinateX", RealDouble, &imin, &nv, &x[0]); cg_coord_read(fn,base,zone, "CoordinateY", RealDouble, &imin, &nv, &y[0]); cg_coord_read(fn,base,zone, "CoordinateZ", RealDouble, &imin, &nv, &z[0]); Array point_map(nv); for(auto i : Range(nv)) { ngcore::IVec<3,size_t> hash = {*reinterpret_cast(&x[i]), *reinterpret_cast(&y[i]), *reinterpret_cast(&z[i])}; size_t pi_ng; size_t pos; // check if this point is new if( point_table.PositionCreate (hash, pos) ) { pi_ng = mesh.AddPoint( {x[i], y[i], z[i]} ); point_table.SetData(pos, pi_ng); } else point_table.GetData(pos, pi_ng); point_map[i] = pi_ng; } int nsections; cg_nsections(fn, base, zone, &nsections); int index_1d = first_index_1d; int index_2d = first_index_2d; int index_3d = first_index_3d; for (auto section : Range(1,nsections+1)) { RegionTimer rtsection(tsection); char sec_name[100]; ElementType_t type; cgsize_t start, end; int nbndry, parent_flag; cg_section_read(fn, base, zone, section, sec_name, &type, &start, &end, &nbndry, &parent_flag); PrintMessage(4, "Read section ", section, " with name ", sec_name, " and element type ", cg_ElementTypeName(type)); string ngname{sec_name}; for (char & c : ngname) if(c==' ') c = '_'; if(type==MIXED) { bool have_1d_elements = false; bool have_2d_elements = false; bool have_3d_elements = false; cgsize_t nv; cg_ElementDataSize(fn, base, zone, section, &nv); Array vertices(nv); #if CGNS_VERSION < 3400 cg_elements_read(fn, base, zone, section, &vertices[0], nullptr); #else cg_poly_elements_read(fn, base, zone, section, &vertices[0], nullptr, nullptr); #endif size_t vi = 0; while(vi(vertices[vi++]); int dim = getDim(type); int np; cg_npe(type, &np); for (auto & v : vertices.Range(vi, vi+np)) v = point_map[v-1]; if(dim==1) { if(!have_1d_elements) { index_1d++; have_1d_elements = true; mesh.AddEdgeDescriptor(EdgeDescriptor{}); names_1d.Append(ngname); } auto el = ReadCGNSElement1D(type, vertices.Range(vi, vertices.Size())); el.si = index_1d; mesh.AddSegment(el); vi += el.GetNP(); ne_1d++; } if(dim==2) { if(!have_2d_elements) { index_2d++; have_2d_elements = true; mesh.AddFaceDescriptor(FaceDescriptor(index_2d, 1, 0, 1)); names_2d.Append(ngname); } auto el = ReadCGNSElement2D(type, vertices.Range(vi, vertices.Size())); el.SetIndex(index_2d); mesh.AddSurfaceElement(el); vi += el.GetNP(); ne_2d++; } if(dim==3) { if(!have_3d_elements) { index_3d++; have_3d_elements = true; names_3d.Append(ngname); } auto el = ReadCGNSElement3D(type, vertices.Range(vi, vertices.Size())); el.SetIndex(index_3d); mesh.AddVolumeElement(el); vi += el.GetNP(); ne_3d++; } } } else { int dim = getDim(type); cgsize_t nv; cg_ElementDataSize(fn, base, zone, section, &nv); int np=0; cg_npe(type, &np); Array vertices(nv); cg_elements_read(fn, base, zone, section, &vertices[0], nullptr); for (auto & v : vertices) v = point_map[v-1]; int ne_section = nv/np; if(dim==1) { index_1d++; mesh.AddEdgeDescriptor(EdgeDescriptor{}); names_1d.Append(ngname); for(auto i : Range(ne_section)) { auto el = ReadCGNSElement1D(type, vertices.Range(np*i, np*(i+1))); el.si = index_1d; mesh.AddSegment(el); } ne_1d += ne_section; } if(dim==2) { index_2d++; mesh.AddFaceDescriptor(FaceDescriptor(index_2d, 1, 0, 1)); names_2d.Append(ngname); for(auto i : Range(ne_section)) { auto el = ReadCGNSElement2D(type, vertices.Range(np*i, np*(i+1))); el.SetIndex(index_2d); mesh.AddSurfaceElement(el); } ne_2d += ne_section; } if(dim==3) { index_3d++; names_3d.Append(ngname); for(auto i : Range(ne_section)) { auto el = ReadCGNSElement3D(type, vertices.Range(np*i, np*(i+1))); el.SetIndex(index_3d); mesh.AddVolumeElement(el); } ne_3d += ne_section; } } } mesh.GetRegionNamesCD(2).SetSize(index_1d); mesh.GetRegionNamesCD(1).SetSize(index_2d); mesh.GetRegionNamesCD(0).SetSize(index_3d); mesh.GetRegionNamesCD(2) = nullptr; mesh.GetRegionNamesCD(1) = nullptr; mesh.GetRegionNamesCD(0) = nullptr; } void SetNames( Mesh & mesh ) { if(mesh.GetDimension() == 2) { for (auto i : Range(names_1d.Size())) mesh.SetBCName(first_index_1d + i, names_1d[i]); for (auto i : Range(names_2d.Size())) mesh.SetMaterial(first_index_2d + i +1, names_2d[i]); } else { for (auto i : Range(names_1d.Size())) mesh.SetCD2Name(first_index_1d + i +1, names_1d[i]); for (auto i : Range(names_2d.Size())) { mesh.SetBCName(first_index_2d + i, names_2d[i]); mesh.GetFaceDescriptor(first_index_2d + i +1).SetDomainIn(first_index_3d+1); } for (auto i : Range(names_3d.Size())) mesh.SetMaterial(first_index_3d + i +1, names_3d[i]); } } }; } namespace netgen { int ReadCGNSMesh (Mesh & mesh, const filesystem::path & filename, Array> & zones) { mesh.SetDimension(3); static Timer tall("CGNS::ReadMesh"); RegionTimer rtall(tall); int fn; cg_open(filename.string().c_str(),CG_MODE_READ,&fn); int base = 1; int nzones; cg_nzones(fn, base, &nzones); int n_vertices = 0; for (auto zi : Range(1, nzones+1)) { int size[3]; char name[100]; cg_zone_read(fn,base,zi, name, size); n_vertices += size[0]; } cg::PointTable points(2*n_vertices); for (auto zi : Range(1, nzones+1)) { ZoneType_t zone_type; cg_zone_type(fn, base, zi, &zone_type); if(zone_type != Unstructured ) { PrintMessage(2, "skipping zone with type ", cg_ZoneTypeName(zone_type) ); continue; } auto zone = make_unique(fn, base, zi); zone->ReadMesh( mesh, points ); zones.Append(std::move(zone)); } if(mesh.GetNE() == 0) mesh.SetDimension(2); for (auto & zone : zones) zone->SetNames(mesh); mesh.UpdateTopology(); const auto & topo = mesh.GetTopology(); for (auto sei : Range(mesh.SurfaceElements())) { int ei0, ei1; topo.GetSurface2VolumeElement (sei+1, ei0, ei1); auto si = mesh.SurfaceElement(sei).GetIndex(); auto & fd = mesh.GetFaceDescriptor(si); if(ei0>0) { int i0 = mesh.VolumeElement(ei0).GetIndex(); if(fd.DomainIn()!=i0) fd.SetDomainOut(i0); } if(ei1>0) { int i1 = mesh.VolumeElement(ei1).GetIndex(); if(fd.DomainIn()!=i1) fd.SetDomainOut(i1); } } return fn; } void ReadCGNSMesh (Mesh & mesh, const filesystem::path & filename) { Array> zones; int fn = ReadCGNSMesh(mesh, filename, zones); cg_close(fn); } // Reads mesh and solutions of .csns file tuple, vector, vector>, vector> ReadCGNSFile(const filesystem::path & filename, int base) { static Timer tall("CGNS::ReadFile"); RegionTimer rtall(tall); auto mesh = make_shared(); Array> zones; int fn = ReadCGNSMesh(*mesh, filename, zones); std::vector names; std::vector> values; std::vector locations; for (auto & zone : zones) zone->ReadSolutions( mesh->GetDimension(), names, values, locations ); cg_close(fn); return std::make_tuple(mesh, names, values, locations); } void WriteCGNSMesh (const Mesh & mesh, int fn, int & base, int & zone) { int dim = mesh.GetDimension(); cg_base_write(fn, "mesh", dim, dim, &base); int nv = static_cast(mesh.GetNV()); int ne = mesh.GetNE(); Array x, y, z; for(auto & p : mesh.Points()) { x.Append(p[0]); y.Append(p[1]); z.Append(p[2]); } cgsize_t isize[3] = { nv, ne, 0 }; cg_zone_write(fn,base, "mesh", isize, Unstructured, &zone); int coord; cg_coord_write(fn,base,zone, RealDouble, "CoordinateX", &x[0], &coord); cg_coord_write(fn,base,zone, RealDouble, "CoordinateY", &y[0], &coord); cg_coord_write(fn,base,zone, RealDouble, "CoordinateZ", &z[0], &coord); int imax3 = 0; for(const auto & el : mesh.VolumeElements()) imax3 = max(imax3, el.GetIndex()); int imax2 = 0; for(const auto & el : mesh.SurfaceElements()) imax2 = max(imax2, el.GetIndex()); int imax1 = 0; for(const auto & el : mesh.LineSegments()) imax1 = max(imax1, el.si); int ne_written = 0; // int meshdim = mesh.GetDimension(); for(const auto i : IntRange(imax3)) ne_written += cg::WriteCGNSRegion(mesh, 3, i+1, fn, base, zone, ne_written); for(const auto i : IntRange(imax2)) ne_written += cg::WriteCGNSRegion(mesh, 2, i+1, fn, base, zone, ne_written); for(const auto i : IntRange(imax1)) ne_written += cg::WriteCGNSRegion(mesh, 1, i+1, fn, base, zone, ne_written); } void WriteCGNSMesh (const Mesh & mesh, const filesystem::path & filename) { static Timer tall("CGNS::WriteMesh"); RegionTimer rtall(tall); int fn, base, zone; cg_open(filename.string().c_str(),CG_MODE_WRITE,&fn); WriteCGNSMesh(mesh, fn, base, zone); cg_close(fn); } void WriteCGNSFile(shared_ptr mesh, const filesystem::path & filename, vector fields, vector> values, vector locations) { static Timer tall("CGNS::WriteFile"); RegionTimer rtall(tall); int fn, base, zone; cg_open(filename.string().c_str(),CG_MODE_WRITE,&fn); WriteCGNSMesh(*mesh, fn, base, zone); for(auto i : IntRange(fields.size())) { int section, field; string name = "solution_" + ToString(i); cg_sol_write(fn, base, zone, name.c_str(), cg::getCGNodeType(locations[i]), §ion); cg_field_write(fn, base, zone, section, RealDouble, fields[i].c_str(), &values[i][0], &field); } cg_close(fn); } static RegisterUserFormat reg_cgns ("CGNS Format", {".cgns"}, static_cast(&ReadCGNSMesh), static_cast(&WriteCGNSMesh)); } #endif // NG_CGNS ================================================ FILE: libsrc/interface/rw_medit.cpp ================================================ #include #include #include "rw_medit.hpp" namespace netgen { void ReadMeditFormat (Mesh & mesh, const filesystem::path & filename, map, int> & index_map) { static Timer tall("ReadMeditMesh"); RegionTimer rtall(tall); if(!filesystem::exists(filename)) throw Exception("File does not exist: " + filename.string()); auto fin = ifstream(filename); string token; int version, dim; mesh.ClearFaceDescriptors(); int index_cnt[4] = {0,0,0,0}; auto getIndex = [&](int eldim, int index) { if(index_map.count({eldim,index})==0) { auto n = ++index_cnt[eldim]; index_map[{eldim, index}] = n; if(eldim==2) { auto fd = FaceDescriptor(n-1,1,0,0); fd.SetBCProperty(n); mesh.AddFaceDescriptor (fd); } } return index_map[{eldim, index}]; }; while(true) { fin >> token; int index; // cout << "token: " << token << endl; if(token == "End") { break; } else if(token == "" || std::regex_match(token, std::regex("^[\\s]*$"))) { continue; } else if(token == "MeshVersionFormatted") { fin >> version; } else if(token == "Dimension") { fin >> dim; mesh.SetDimension(dim); } else if(token == "Vertices") { int nvert; fin >> nvert; Point<3> p{0.,0.,0.}; for([[maybe_unused]] auto k : Range(nvert)) { for(auto i : Range(dim)) fin >> p[i]; fin >> index; mesh.AddPoint(p); } } else if(token == "Edges") { int nedge; fin >> nedge; Segment seg; for([[maybe_unused]] auto k : Range(nedge)) { for(auto i : Range(2)) fin >> seg[i]; fin >> seg.edgenr; seg.edgenr = getIndex(1, seg.edgenr); seg.si = seg.edgenr; mesh.AddSegment(seg); } } else if(token == "Triangles") { int ntrig, index; fin >> ntrig; Element2d sel; for([[maybe_unused]] auto k : Range(ntrig)) { for(auto i : Range(3)) fin >> sel[i]; fin >> index; sel.SetIndex(getIndex(2, index)); mesh.AddSurfaceElement(sel); } } else if(token == "Tetrahedra") { int ntet; fin >> ntet; Element el(4); for([[maybe_unused]] auto k : Range(ntet)) { for(auto i : Range(4)) fin >> el[i]; fin >> index; el.SetIndex(getIndex(3, index)); el.Invert(); mesh.AddVolumeElement(el); } } else if(token == "Corners") { int ncorners; fin >> ncorners; Element0d el; for([[maybe_unused]] auto k : Range(ncorners)) { fin >> el.pnum; } } else if(token == "RequiredVertices") { int nverts; fin >> nverts; int vert; for([[maybe_unused]] auto k : Range(nverts)) { fin >> vert; } } else if(token == "Normals") { int nnormals; fin >> nnormals; Vec<3> normal; for([[maybe_unused]] auto k : Range(nnormals)) { fin >> normal[0]; fin >> normal[1]; fin >> normal[2]; } } else if(token == "NormalAtVertices") { int nnormals; fin >> nnormals; int vert; int normal; for([[maybe_unused]] auto k : Range(nnormals)) { fin >> normal; fin >> vert; } } else if(token == "Tangents") { int ntangents; fin >> ntangents; Vec<3> tangent; for([[maybe_unused]] auto k : Range(ntangents)) { fin >> tangent[0]; fin >> tangent[1]; fin >> tangent[2]; } } else if(token == "TangentAtVertices") { int ntangents; fin >> ntangents; int vert; int tangent; for([[maybe_unused]] auto k : Range(ntangents)) { fin >> tangent; fin >> vert; } } else if(token == "Ridges") { int nridges; fin >> nridges; int ridge; for([[maybe_unused]] auto k : Range(nridges)) { fin >> ridge; } } else { cout << "unknown token " << token << endl; int nitems; fin >> nitems; string s; for([[maybe_unused]] auto i : Range(nitems)) fin >> s; // read one line } } } void ReadMeditFormat (Mesh & mesh, const filesystem::path & filename) { map, int> index_map; ReadMeditFormat(mesh, filename, index_map); } void WriteMeditFormat (const Mesh & mesh, const filesystem::path & filename, map, int> & index_map) { static Timer tall("WriteMeditFormat"); RegionTimer rtall(tall); auto fout = ofstream(filename); fout << "MeshVersionFormatted 2\n"; fout << "Dimension\n" << mesh.GetDimension() << endl; fout << "Vertices\n" << mesh.GetNP() << endl; int base_index = 0; int max_index = 0; auto getIndex = [&](int i, int dim) { max_index = max(max_index, i+base_index); auto index = base_index+i; index_map[{dim,i}] = index; return index; }; fout << setprecision(16); for(const auto & p : mesh.Points()) { for(auto i : Range(mesh.GetDimension())) fout << p[i] << ' '; fout << getIndex(1, 0) << endl; } base_index = max_index; fout << "Edges\n" << mesh.GetNSeg() << endl; for(const auto & seg : mesh.LineSegments()) fout << seg[0] << ' ' << seg[1] << ' ' << getIndex(seg.edgenr, 1) << endl; base_index = max_index; fout << "Triangles\n" << mesh.GetNSE() << endl; for(const auto & sel : mesh.SurfaceElements()) fout << sel[0] << ' ' << sel[1] << ' ' << sel[2] << ' ' << getIndex(sel.GetIndex(), 2) << endl; base_index = max_index; fout << "Tetrahedra\n" << mesh.GetNE() << endl; for(const auto & el : mesh.VolumeElements()) fout << el[0] << ' ' << el[1] << ' ' << el[2] << ' ' << el[3] << '\t' << getIndex(el.GetIndex(), 3) << endl; fout << "End" << endl; } void WriteMeditFormat (const Mesh & mesh, const filesystem::path & filename) { map, int> index_map; WriteMeditFormat(mesh, filename, index_map); } static RegisterUserFormat reg_medit ("Medit Format", {".mesh"}, static_cast(ReadMeditFormat), static_cast(WriteMeditFormat)); } // namespace netgen ================================================ FILE: libsrc/interface/rw_medit.hpp ================================================ #include #include "writeuser.hpp" namespace netgen { DLL_HEADER void ReadMeditFormat (Mesh & mesh, const filesystem::path & filename, map, int> & index_map); DLL_HEADER void ReadMeditFormat (Mesh & mesh, const filesystem::path & filename); DLL_HEADER void WriteMeditFormat (const Mesh & mesh, const filesystem::path & filename, map, int> & index_map); DLL_HEADER void WriteMeditFormat (const Mesh & mesh, const filesystem::path & filename); } // namespace netgen ================================================ FILE: libsrc/interface/writeOpenFOAM15x.cpp ================================================ /*! \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 (pnt_ind1 pnt_ind2 .... pnt_ind) * 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 #include #include #include #include #include #include "../general/gzstream.h" #include "writeuser.hpp" namespace netgen { extern MeshingParameters mparam; // Global arrays used to maintain the owner, neighbour and face lists // so that they are accessible across functions static NgArray owner_facelist; static NgArray owner_celllist; static NgArray neighbour_celllist; static NgArray surfelem_bclist; static NgArray surfelem_lists; static void WriteOpenFOAM15xBanner(ostream * 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(ostream * outfile) { *outfile << "// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //\n"; } static void WriteOpenFOAM15xDividerEnd(ostream * 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 (meshtopo).SetBuildEdges(true); const_cast (meshtopo).SetBuildFaces(true); const_cast (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; // NgArray 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 NgArray ownerfaces(totfaces); ownerfaces = 0; // NgArray 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 NgArray 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 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.GetFace2SurfaceElement1(absfacenr); int surfelem = meshtopo.GetFace2SurfaceElement(absfacenr-1)+1; 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 (ostream * 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 (ostream * 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 (ostream * 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"; // NgArray to hold the indices of the points of each face to // flip if required NgArray 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 (ostream * 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 (ostream * 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"; NgArray 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 filesystem::path & dirname, const bool compressed) { bool error = false; // char casefiles[256]; // Make sure that the mesh data has been updated const_cast (mesh).Compress(); const_cast (mesh).CalcSurfacesOfNode(); const_cast (mesh).RebuildSurfaceElementLists(); const_cast (mesh).BuildElementSearchTree(3); 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: " << dirname.string() << "\n"; // Create the case directory if it does not already exist // NOTE: This needs to be improved for the Linux variant....!!! auto mesh_dir = filesystem::path(dirname).append("constant").append("polyMesh"); filesystem::create_directories(mesh_dir); // Open handles to the five required mesh files // points // faces // owner // neighbour // boundary auto get_name = [compressed, &mesh_dir]( string s ) { auto p = filesystem::path(mesh_dir).append(s); if(compressed) p.concat(".gz"); return p; }; auto outfile_pnts = make_unique(get_name("points")); auto outfile_faces = make_unique(get_name("faces")); auto outfile_own = make_unique(get_name("owner")); auto outfile_nei = make_unique(get_name("neighbor")); // Note... the boundary file is not compressed auto outfile_bnd = make_unique(mesh_dir.append("boundary")); 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.get()); 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.get()); 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.get(), mesh); 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.get(),mesh); 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.get()); 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"; } } void WriteOpenFOAM15xFormatCompressed (const Mesh & mesh, const filesystem::path & dirname) { WriteOpenFOAM15xFormat(mesh, dirname, true); } void WriteOpenFOAM15xFormatUncompressed (const Mesh & mesh, const filesystem::path & dirname) { WriteOpenFOAM15xFormat(mesh, dirname, false); } static RegisterUserFormat reg_openfoam ("OpenFOAM 1.5+ Format", {"*"}, nullopt, WriteOpenFOAM15xFormatUncompressed); static RegisterUserFormat reg_openfoam_compressed ("OpenFOAM 1.5+ Compressed", {"*"}, nullopt, WriteOpenFOAM15xFormatCompressed); } ================================================ FILE: libsrc/interface/writeabaqus.cpp ================================================ // // Write Abaqus file // // #include #include #include #include #include #include "writeuser.hpp" namespace netgen { using std::vector; struct AbaqusElementType { const char * name; const vector permutation; AbaqusElementType(const char * name, const vector & permutation) : name(name), permutation(permutation) {} }; static inline const AbaqusElementType & GetAbaqusType(int dim, int num_nodes) { // maps num_nodes to AbaqusElementType for each dimension typedef std::map AbaqusElementTypes; static const std::map abaqus_eltypes[3] = { // 1D AbaqusElementTypes{ {2, AbaqusElementType{"T2D2", vector{0,1}}}, }, // 2D AbaqusElementTypes{ {3, AbaqusElementType{"CPS3", vector{0,1,2}}}, {6, AbaqusElementType{"CPS6", vector{0,1,2,5,6,4}}}, }, // 3D AbaqusElementTypes{ {4, AbaqusElementType{"C3D4", vector{0,1,3,2}}}, {10, AbaqusElementType{"C3D10", vector{0,1,3,2,4,8,6,5,7,9}}}, } }; const auto & eltypes = abaqus_eltypes[dim-1]; if (eltypes.count(num_nodes) > 0) return eltypes.at(num_nodes); else throw Exception("unsupported " + ToString(dim)+"d Element type with " + ToString(num_nodes) + " nodes"); } static void WritePoints ( const Mesh & mesh, ostream & out ) { out << "*Node" << endl; for(auto pi : mesh.Points().Range() ) { out << pi+1-IndexBASE() << ", "; auto p = mesh[pi]; out << p[0] << ", " << p[1] << ", " << p[2] << '\n'; } } template static void WriteElement(ostream & out, const Mesh& mesh, ElIndex ei, const vector & permutation, int & el_counter) { el_counter++; auto el = mesh[ei]; out << el_counter; for(auto i : Range(el.PNums())) out << ", " << el[permutation[i]]+1-IndexBASE(); out << '\n'; } template static void WriteElements ( ostream & out, const Mesh & mesh, int dim, const Elements & el_range, int & el_counter) { // map index, num_nodes to elements std::map, Array> elset_map; for(auto ei : el_range) { const auto & el = mesh[ei]; int index = 0; if constexpr(std::is_same_v) index = el.edgenr; else index = el.GetIndex(); elset_map[{index, el.GetNP()}].Append(ei); } for(auto & [key, elems] : elset_map) { auto [index, num_nodes] = key; auto name = mesh.GetRegionName(elems[0]); if (name == "") name = "default"; PrintMessage (5, index, ": ", name); const auto & eltype = GetAbaqusType(dim, num_nodes) ; out << "*Element, type=" << eltype.name << ", ELSET=" << name << endl; for(auto ei : elems) WriteElement(out, mesh, ei, eltype.permutation, el_counter); } } void WriteAbaqusFormat (const Mesh & mesh, const filesystem::path & filename) { PrintMessage (1, "Write Abaqus Mesh"); ofstream outfile (filename); outfile << "*Heading" << endl; outfile << " " << filename << endl; outfile.precision(8); int element_counter = 0; WritePoints(mesh, outfile); if(mesh.GetDimension() < 3) WriteElements(outfile, mesh, 1, mesh.LineSegments().Range(), element_counter); WriteElements(outfile, mesh, 2, mesh.SurfaceElements().Range(), element_counter); WriteElements(outfile, mesh, 3, mesh.VolumeElements().Range(), element_counter); // Write identifications (untested!) if (mesh.GetIdentifications().GetMaxNr()) { const auto np = mesh.GetNP(); // periodic identification, implementation for // Helmut J. Boehm, TU Vienna auto mpcfilename = filename; if (filename.extension() == ".inp") mpcfilename.replace_extension(".mpc"); else mpcfilename.concat(".mpc"); ofstream mpc (mpcfilename); int masternode(0); NgArray pairs; NgBitArray master(np), help(np); master.Set(); for (int i = 1; i <= 3; i++) { mesh.GetIdentifications().GetPairs (i, pairs); help.Clear(); for (int j = 1; j <= pairs.Size(); j++) { help.Set (pairs.Get(j).I1()); } master.And (help); } for (int i = 1; i <= np; i++) if (master.Test(i)) masternode = i; cout << "masternode = " << masternode << " = " << mesh.Point(masternode) << endl; NgArray minions(3); for (int i = 1; i <= 3; i++) { mesh.GetIdentifications().GetPairs (i, pairs); for (int j = 1; j <= pairs.Size(); j++) { if (pairs.Get(j).I1() == masternode) minions.Elem(i) = pairs.Get(j).I2(); } cout << "minion(" << i << ") = " << minions.Get(i) << " = " << mesh.Point(minions.Get(i)) << endl; } outfile << "**\n" << "*NSET,NSET=CTENODS\n" << minions.Get(1) << ", " << minions.Get(2) << ", " << minions.Get(3) << endl; outfile << "**\n" << "**POINT_fixed\n" << "**\n" << "*BOUNDARY, OP=NEW\n"; for (int j = 1; j <= 3; j++) outfile << masternode << ", " << j << ",, 0.\n"; outfile << "**\n" << "*BOUNDARY, OP=NEW\n"; for (int j = 1; j <= 3; j++) { Vec3d v(mesh.Point(masternode), mesh.Point(minions.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 << minions.Get(j) << ", " << dir << ",, 0.\n"; } outfile << "**\n" << "*EQUATION, INPUT=" << mpcfilename << endl; NgBitArray eliminated(np); eliminated.Clear(); for (int i = 1; i <= mesh.GetIdentifications().GetMaxNr(); i++) { mesh.GetIdentifications().GetPairs (i, pairs); if (!pairs.Size()) continue; for (int 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 (int 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 << minions.Get(i) << "," << k << ", 1.0, "; mpc << masternode << "," << k << ", -1.0 \n"; } } } } PrintMessage(1, "done"); } static RegisterUserFormat reg_abaqus ("Abaqus Format", {".mesh"}, nullopt, WriteAbaqusFormat); } ================================================ FILE: libsrc/interface/writediffpack.cpp ================================================ // // Write diffpack file // // by // Bartosz Sawicki // extended by // Jacques Lechelle // #include #include #include #include #include #include "writeuser.hpp" namespace netgen { void WriteDiffPackFormat (const Mesh & mesh, const filesystem::path & filename) { // double scale = globflags.GetNumFlag ("scale", 1); double scale = 1; ofstream outfile(filename); outfile.precision(14); if (mesh.GetDimension() == 3) { // Output compatible to Diffpack grid format // Bartosz Sawicki int np = mesh.GetNP(); int ne = mesh.GetNE(); int nse = mesh.GetNSE(); NgArray BIname; NgArray 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 (int i = 1; i <= nse; i++) { int BI=mesh.GetFaceDescriptor(mesh.SurfaceElement(i).GetIndex()).BCProperty(); int nbi=BIname.Size(); int found=0; for (int j = 1; j <= nbi; j++) if(BI == BIname.Get(j)) found = 1; if( ! found ) BIname.Append(BI); } outfile << " " << BIname.Size() << " Boundary indicators: "; for (int 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"; // setup point-to-surfaceelement table TABLE point2sel(np); for (SurfaceElementIndex sei = 0; sei < nse; sei++) { const Element2d & el = mesh[sei]; for (int j = 0; j < el.GetNP(); j++) point2sel.Add (el[j], sei); } // for (int i = 1; i <= np; i++) for (PointIndex i : mesh.Points().Range()) { const Point3d & p = mesh.Point(i); outfile.width(12); outfile << i << " ("; outfile.width(16); outfile << p.X()/scale << ", "; outfile.width(16); outfile << p.Y()/scale << ", "; outfile.width(16); outfile << p.Z()/scale << ") "; if(mesh[PointIndex(i)].Type() != INNERPOINT) { BCsinpoint.DeleteAll(); /* for (j = 1; j <= nse; j++) */ NgFlatArray sels = point2sel[i]; for (int jj = 0; jj < sels.Size(); jj++) { for (int k = 1; k <= mesh[sels[jj]].GetNP(); k++) { if(mesh[sels[jj]].PNum(k)==i) { int BC=mesh.GetFaceDescriptor(mesh[sels[jj]].GetIndex()).BCProperty(); int nbcsp=BCsinpoint.Size(); int found = 0; for (int l = 1; l <= nbcsp; l++) if(BC == BCsinpoint.Get(l)) found = 1; if( ! found ) BCsinpoint.Append(BC); } } } int nbcsp = BCsinpoint.Size(); outfile << "[" << nbcsp << "] "; for (int 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 (int 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(); NgArray BIname; NgArray BCsinpoint; int i, j, k, l; outfile.precision(6); outfile.setf (ios::fixed, ios::floatfield); outfile.setf (ios::showpoint); const Element2d & eldummy = mesh.SurfaceElement((int)1); 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: "< #include #include #include #include #include namespace netgen { #include "writeuser.hpp" void WriteDolfinFormat (const Mesh & mesh, const filesystem::path & 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); // char str[100]; outfile.precision(8); outfile.setf (ios::fixed, ios::floatfield); outfile.setf (ios::showpoint); if ( nsd == 3) { outfile << "" <"<" <"<"<"<"<"<"<"<"< #include #include #include #include #include #include "writeuser.hpp" namespace netgen { extern MeshingParameters mparam; void WriteElmerFormat (const Mesh &mesh, const filesystem::path &dirname) { cout << "write elmer mesh files" << endl; std::map tmap; tmap[TRIG] = 303; tmap[TRIG6] = 306; tmap[QUAD] = 404; tmap[QUAD8] = 408; tmap[TET] = 504; tmap[TET10] = 510; tmap[PYRAMID] = 605; tmap[PYRAMID13] = 613; tmap[PRISM] = 706; tmap[PRISM15] = 715; tmap[HEX] = 808; tmap[HEX20] = 820; std::map> pmap; pmap[TRIG] = {1,2,3}; pmap[TRIG6] = {1,2,3, 6,4,5}; pmap[QUAD] = {1,2,3,4}; pmap[QUAD8] = {1,2,3,4, 5,8,6,7}; pmap[TET] = {1,2,3,4}; pmap[TET10] = {1,2,3,4, 5,8,6,7,9,10}; pmap[PYRAMID]={1,2,3,4,5}; pmap[PYRAMID13]= {1,2,3,4,5,6,7,8,9,10,11,12,13}; pmap[PRISM] = {1,2,3,4,5,6}; pmap[PRISM15] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; pmap[HEX] = {1,2,3,4,5,6,7,8}; pmap[HEX20] = {1,2,3,4,5,8,6,7,8, 9,12,10,11, 17,20,19,18, 13,16,14,15}; 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; filesystem::create_directories(dirname); auto get_name = [&dirname]( string s ) { return filesystem::path(dirname).append(s); }; ofstream outfile_h(get_name("mesh.header")); ofstream outfile_n(get_name("mesh.nodes")); ofstream outfile_e(get_name("mesh.elements")); ofstream outfile_b(get_name("mesh.boundary")); ofstream outfile_names(get_name("mesh.names")); for( auto codim : IntRange(0, mesh.GetDimension()-1) ) { auto & names = const_cast(mesh).GetRegionNamesCD(codim); for (auto i0 : Range(names) ) { if(names[i0] == nullptr) continue; string name = *names[i0]; if(name == "" || name == "default") continue; outfile_names << "$" << name << "=" << i0+1 << "\n"; } } auto get3FacePoints = [](const Element2d & el) { INDEX_3 i3; INDEX_4 i4; auto eltype = el.GetType(); switch (eltype) { case TRIG: case TRIG6: i3 = {el[0], el[1], el[2]}; i3.Sort(); break; case QUAD: case QUAD8: i4 = {el[0], el[1], el[2], el[3]}; i4.Sort(); i3 = {i4[0], i4[1], i4[2]}; break; default: throw Exception("Got invalid type (no face)"); } return i3; }; // fill hashtable // use lowest three point numbers of lowest-order face to index faces INDEX_3_HASHTABLE face2volelement(ne); for (int i = 1; i <= ne; i++) { const Element & el = mesh.VolumeElement(i); // getface not working for second order elements -> reconstruct linear element here Element linear_el = el; linear_el.SetNP(el.GetNV()); // GetNV returns 8 for HEX20 for instance for (auto j : Range(1,el.GetNFaces()+1)) { Element2d face; linear_el.GetFace(j, face); face2volelement.Set (get3FacePoints(face), i); cout << "set " << get3FacePoints(face) << "\tto " << i << endl; } } // outfile.precision(6); // outfile.setf (ios::fixed, ios::floatfield); // outfile.setf (ios::showpoint); std::map elcount; 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(); auto eltype = el.GetType(); elcount[eltype]++; outfile_e << i << " " << el.GetIndex() << " " << tmap[eltype] << " "; auto & map = pmap[eltype]; for (j = 1; j <= el.GetNP(); j++) { outfile_e << " "; outfile_e << el.PNum(map[j-1]); } outfile_e << "\n"; } for (i = 1; i <= nse; i++) { Element2d el = mesh.SurfaceElement(i); if (invertsurf) el.Invert(); auto eltype = el.GetType(); elcount[eltype]++; int elind = face2volelement.Get(get3FacePoints(el)); cout << "get " << get3FacePoints(el) << "\t " << elind << endl; outfile_b << i << " " << mesh.GetFaceDescriptor(el.GetIndex()).BCProperty() << " " << elind << " 0 " << tmap[eltype] << " "; auto & map = pmap[el.GetType()]; for (j = 1; j <= el.GetNP(); j++) { outfile_b << " "; outfile_b << el.PNum(map[j-1]); } outfile_b << "\n"; } outfile_h << np << " " << ne << " " << nse << "\n"; outfile_h << "2" << "\n"; for( auto & [eltype,count] : elcount ) outfile_h << tmap[eltype] << " " << count << "\n"; } static RegisterUserFormat reg_elmer ("Elmer Format", {"*"}, nullopt, WriteElmerFormat); } ================================================ FILE: libsrc/interface/writefeap.cpp ================================================ // // Write FEAP file // FEAP by Bob Taylor, Berkely // // contact Peter Wriggers or Albrecht Rieger, Hannover // rieger@ibnm.uni-hannover.de // #include #include #include #include #include #include "writeuser.hpp" namespace netgen { extern MeshingParameters mparam; void WriteFEAPFormat (const Mesh & mesh, const filesystem::path & 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); 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, minionindex; cout << "Master Surface index = "; cin >> masterindex; cout << "Minion Surface index = "; cin >> minionindex; // 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() == minionindex) { 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; } static RegisterUserFormat reg_feap ("FEAP Format", {".mesh"}, nullopt, WriteFEAPFormat); } ================================================ FILE: libsrc/interface/writefluent.cpp ================================================ // // Write Fluent file // Johannes Gerstmayr, University Linz // #include #include #include #include #include #include "writeuser.hpp" namespace netgen { void WriteFluentFormat (const Mesh & mesh, const filesystem::path & 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); 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: snprintf (str, size(str), "(10 (0 1 %x 1))",np); //hexadecimal!!! outfile << str << endl; //nodes of zone 1: snprintf (str, size(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; NgArray surfaceelp; NgArray surfaceeli; Array locels; //no cells=no tets //no faces=2*tets int noverbface = 2*ne-nse/2; snprintf (str, size(str), "(13 (0 1 %x 0))",(noverbface+nse)); //hexadecimal!!! outfile << str << endl; snprintf (str, size(str), "(13 (4 1 %x 2 3)(",noverbface); //hexadecimal!!! outfile << str << endl; const_cast (mesh).BuildElementSearchTree(3); 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 (auto locind : locels) { Element el2 = mesh[locind]; //if (inverttets) // el2.Invert(); for (j2 = 1; j2 <= el2.GetNFaces(); j2++) { el2.GetFace(j2, face2); if (face2.HasFace(face)) {eli2 = locind+1; stopsig = 1; break;} } if (stopsig) break; } if (eli2==i) cout << "error in WRITE_FLUENT!!!" << endl; if (eli2 > i) //don't 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; snprintf (str, size(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; snprintf (str, size(str), "(12 (0 1 %x 0))",ne); //hexadecimal!!! outfile << str << endl; snprintf (str, size(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; } static RegisterUserFormat reg_fluent ("Fluent Format", {".mesh"}, nullopt, WriteFluentFormat); } ================================================ FILE: libsrc/interface/writegmsh.cpp ================================================ /************************************* * 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 #include #include #include #include #include "writeuser.hpp" namespace netgen { extern MeshingParameters mparam; /* * GMSH mesh format * points, elements, surface elements and physical entities */ void WriteGmshFormat (const Mesh & mesh, const filesystem::path & filename) { ofstream outfile (filename); 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 << " Invalid element type for Gmsh volume Format !\n"; } } static RegisterUserFormat reg_gmsh ("Gmsh Format", {".gmsh"}, nullopt, WriteGmshFormat); } ================================================ FILE: libsrc/interface/writegmsh2.cpp ================================================ /*! \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 #include #include #include #include #include "writeuser.hpp" namespace netgen { extern MeshingParameters mparam; // 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 filesystem::path & filename) { ofstream outfile (filename); 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.VolumeElements().First().GetNP() <= 10) && (mesh.SurfaceElements().First().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 (int 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 (auto sei : Range(mesh.SurfaceElements())) { int elType = 0; Element2d el = mesh[sei]; // .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 << sei-IndexBASE(sei)+1; 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 (int j = 1; j <= el.GetNP(); j++) { outfile << " "; outfile << el.PNum(triGmsh[j]); } outfile << "\n"; } for (ElementIndex ei : Range(mesh.VolumeElements())) { int i = ei-IndexBASE(ei)+1; int elType = 0; Element el = mesh[ei]; 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 (int 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 (int 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 (int 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 (int 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 static RegisterUserFormat reg_gmsh2 ("Gmsh2 Format", {".gmsh2"}, nullopt, WriteGmsh2Format); } // End: namespace netgen ================================================ FILE: libsrc/interface/writejcm.cpp ================================================ // // Write JCMwave file // 07.07.2005, Sven Burger, ZIB Berlin // #include #include #include #include #include #include #include "writeuser.hpp" namespace netgen { void WriteJCMFormat (const Mesh & mesh, const filesystem::path & filename) { if (mesh.GetDimension() != 3) { cout <<"\n Error: Dimension 3 only supported by this output format!"< 0) cout << " Please note: Boundaries at infinity have to carry the bc-attribute '-bc=" << bc_at_infinity <<"'."< 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(int (el.PNum(j)),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); outfile.precision(6); outfile.setf (ios::fixed, ios::floatfield); outfile.setf (ios::showpoint); outfile << "/* \n"; outfile << "__BLOBTYPE__=Grid\n"; outfile << "__OWNER__=JCMwave\n"; outfile << "SpaceDim=3\n"; outfile << "ManifoldDim=3\n"; outfile << "NRefinementSteps=0\n"; outfile << "NPoints="<NTetrahedra="<NPrisms="<NBoundaryTriangles="<NBoundaryQuadrilaterals="< & 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"< 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"<= 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)!"<= 5 ) jj = jj - 4; outfile << identmap1[el.PNum(jj)]<<"\n"; } outfile << "\n"; } else if ( identmap2[el.PNum(1)].IsValid() && identmap2[el.PNum(2)].IsValid() && identmap2[el.PNum(3)].IsValid() && identmap2[el.PNum(4)].IsValid() ) { outfile << "-1\n"; for (j = 1; j <= 4; j++) { jj = j + ct; if ( jj >= 5 ) jj = jj - 4; outfile << identmap2[el.PNum(jj)] <<"\n"; } outfile << "\n"; } else if ( identmap3[el.PNum(1)].IsValid() && identmap3[el.PNum(2)].IsValid() && identmap3[el.PNum(3)].IsValid() && identmap3[el.PNum(4)].IsValid() ) { outfile << "-1\n"; for (j = 1; j <= 4; j++) { jj = j + ct; if ( jj >= 5 ) jj = jj - 4; outfile << identmap3[el.PNum(jj)]<<"\n"; } outfile << "\n"; } else outfile << "1\n\n"; } } cout << " JCMwave grid file written." << endl; } static RegisterUserFormat reg_jcmwave ("JCMwave Format", {".jcm"}, nullopt, WriteJCMFormat); } ================================================ FILE: libsrc/interface/writepermas.cpp ================================================ // // Write Permas file // for Intes GmbH, Stuttgart // #include #include #include #include #include #include #include "writeuser.hpp" using namespace std; namespace netgen { // Forward declarations (don't know, where to define them, sorry) int addComponent(string &strComp, string &strSitu, ofstream &out); void WritePermasFormat (const Mesh &mesh, const filesystem::path &filename); // This should be the new function to export a PERMAS file void WritePermasFormat (const Mesh &mesh, const filesystem::path &filename, string &strComp, string &strSitu) { ofstream outfile (filename); addComponent(strComp, strSitu, outfile); WritePermasFormat ( mesh, filename); } void WritePermasFormat (const Mesh &mesh, const filesystem::path &filename) { string strComp, strSitu; ofstream outfile (filename); 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(4) << " " << el.PNum(3) << 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; } static RegisterUserFormat reg_permas ("Permas Format", {".mesh"}, nullopt, static_cast(&WritePermasFormat)); } ================================================ FILE: libsrc/interface/writetecplot.cpp ================================================ // // // TECPLOT file by Jawor Georgiew // #include #include #include #include #include #include "writeuser.hpp" namespace netgen { void WriteTecPlotFormat (const Mesh & mesh, const filesystem::path & filename) { auto geom = dynamic_pointer_cast(mesh.GetGeometry()); if(geom == nullptr) throw Exception("TecPlot format requires a CSGeometry"); INDEX i; int j, k, e, z; Vec<3> n; INDEX np = mesh.GetNP(); INDEX ne = mesh.GetNE(); INDEX nse = mesh.GetNSE(); NgArray sn(np); ofstream outfile(filename); outfile << "TITLE=\" " << filename.string() << "\"" << endl; // fill hashtable INDEX_3_HASHTABLE 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); } } } } static RegisterUserFormat reg_tecplot ("TecPlot Format", {".mesh"}, nullopt, WriteTecPlotFormat); } ================================================ FILE: libsrc/interface/writetet.cpp ================================================ #include #include #include #include #include #include #include "writeuser.hpp" namespace netgen { extern void ReadTETFormat (Mesh & mesh, const filesystem::path & filename); void WriteTETFormat (const Mesh & mesh, const filesystem::path & 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.string() << endl; NgArray point_ids,edge_ids,face_ids; NgArray elnum(mesh.GetNE()); elnum = -1; NgArray userdata_int; NgArray userdata_double; NgArray ports; NgArray 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 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 edgenumbers(6*mesh.GetNE()+3*mesh.GetNSE());; INDEX_3_CLOSED_HASHTABLE facenumbers(4*mesh.GetNE()+mesh.GetNSE()); NgArray edge2node; NgArray face2edge; NgArray 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); 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(); NgArray nodenum(point_ids.Size()+1); nodenum = -1; numnodes = 0; for(int i=0; i idmaps; for(int i=1; i<=mesh.GetIdentifications().GetMaxNr(); i++) { if(mesh.GetIdentifications().GetType(i) == Identifications::PERIODIC) { idmaps.Append(new idmap_type); mesh.GetIdentifications().GetMap(i,*idmaps.Last(),true); } } NgArray id_num,id_type; NgArray< NgArray *> 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=PMinion 3=CPMaster 4=CPMinion), "<< 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 group; group.Append(i); for(int j=0; j 1) { id_groups.Append(new NgArray(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() < 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, MinionNodeID, TranslCode (1=dS1 2=dS2 3=dS1+dS2):\n" \ << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n"; for(int i=0; iSize() != 2) continue; for(int j=0; jSize(); j++) outfile << nodenum[(*id_groups[i])[j]] << " "; for(int j=1; jSize(); 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-MinionNodeID's, 3-TranslCodes (1=dS1 2=dS2 3=dS1+dS2):\n" \ << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n"; for(int i=0; iSize() != 4) continue; for(int j=0; jSize(); j++) outfile << nodenum[(*id_groups[i])[j]] << " "; for(int j=1; jSize(); 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-MinionNodeID's, TranslCodes:\n" \ << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n"; for(int i=0; iSize() != 8) continue; for(int j=0; jSize(); j++) outfile << nodenum[(*id_groups[i])[j]] << " "; for(int j=1; jSize(); 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=PMinion 3=CPMaster 4=CPMinion), "<* > vertex_to_edge(mesh.GetNP()+1); for(int i=0; i<=mesh.GetNP(); i++) vertex_to_edge[i] = new NgArray; NgArray< NgArray* > idmaps_edge(idmaps.Size()); for(int i=0; i(numedges); (*idmaps_edge[i]) = 0; } NgArray possible; for(int i=0; i 0) { cerr << "ERROR: too many possible edge identifications" << endl; (*testout) << "ERROR: too many possible edge identifications" << endl << "*vertex_to_edge["<Append(i+1); vertex_to_edge[v[1]]->Append(i+1); } for(int i=0; i group; group.Append(i); for(int j=0; j 1) { id_num[i] = 1; id_groups.Append(new NgArray(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; group.Append(i); for(int j=0; j 1) { id_num[i] = 1; id_groups.Append(new NgArray(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; jSize() != 2) continue; for(int j=0; jSize(); j++) outfile << (*id_groups[i])[j] << " "; for(int j=1; jSize(); 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 MinionEdgeID's, 3 TranslCode (1=dS1 2=dS2 3=dS1+dS2):\n"\ << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n"; for(int i=0; iSize() != 4) continue; for(int j=0; jSize(); j++) outfile << (*id_groups[i])[j] << " "; for(int j=1; jSize(); 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=PMinion), "<* > edge_to_face(numedges+1); for(int i=0; i; for(int i=0; iSetSize(numfaces); (*idmaps[i]) = 0; } for(int i=0; i 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 group; group.Append(i); for(int j=0; j 1) { id_num[i] = -1; id_groups.Append(new NgArray(group)); if(group.Size() == 2) n2++; else cerr << "ERROR: face identification group size = " << group.Size() << endl; } } for(int i=0; iSize() != 2) continue; for(int j=0; jSize(); j++) outfile << (*id_groups[i])[j] << " "; for(int j=1; jSize(); j++) outfile << id_num[(*id_groups[i])[j]] << " "; outfile << "\n"; delete id_groups[i]; } outfile << endl; outfile << "// ElemID, FaceID0, FaceID1, FaceID2, FaceID3, "<= 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= 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; NgArray< NgArray * > groups; int maxg = -1; for(int i = 0; i maxg) maxg = uid_to_group_3D[i]; for(int i = 0; i maxg) maxg = uid_to_group_2D[i]; for(int i = 0; i maxg) maxg = uid_to_group_1D[i]; for(int i = 0; i maxg) maxg = uid_to_group_0D[i]; groups.SetSize(maxg+1); for(int i=0; i; for(ElementIndex i=0; i= 0) groups[uid_to_group_3D[mesh[i].GetIndex()]]->Append(i+1); outfile << "// Object3D GroupID, #Elems ElemID List:\n" \ << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n"; for(int i=0; iSize() << "\n"; for(int j=0; jSize(); j++) outfile << (*groups[i])[j] << "\n"; } for(int i=0; iSetSize(0); for(int i=0; i= 0) groups[uid_to_group_2D[face_ids[i]]]->Append(i+1); outfile << "// Object2D GroupID, #Faces FaceID List:\n" \ << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n"; for(int i=0; iSize() << "\n"; for(int j=0; jSize(); j++) { outfile << (*groups[i])[j]; if(ports.Contains(face_ids[(*groups[i])[j]-1])) outfile << " P"; outfile << "\n"; } } outfile << endl; for(int i=0; iSetSize(0); for(int i=0; i= 0) groups[uid_to_group_1D[edge_ids[i]]]->Append(i+1); outfile << "// Object1D GroupID, #Edges EdgeID List:\n" \ << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n"; for(int i=0; iSize() << "\n"; for(int j=0; jSize(); j++) outfile << (*groups[i])[j] << "\n"; } outfile << endl; for(int i=0; iSetSize(0); // for(PointIndex i = mesh.Points().Begin(); i < mesh.Points().End(); i++) for(PointIndex i : mesh.Points().Range()) { if(i-IndexBASE() < point_ids.Size()) { if(uid_to_group_0D[point_ids[i]] >= 0) groups[uid_to_group_0D[point_ids[i]]]->Append(i+1-IndexBASE()); } else groups[uid_to_group_0D[0]]->Append(i+1-IndexBASE()); } outfile << "// Object0D GroupID, #Nodes NodeID List:\n" \ << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n"; for(int i=0; iSize() << "\n"; for(int j=0; jSize(); j++) outfile << (*groups[i])[j] << "\n"; } outfile << endl; for(int i=0; i #include #include #include #include #include "writeuser.hpp" namespace netgen { void WriteTochnogFormat (const Mesh & mesh, const filesystem::path & filename) { cout << "\nWrite Tochnog Volume Mesh" << endl; ofstream outfile (filename); 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; } static RegisterUserFormat reg_tochnog ("Tochnog Format", {".mesh"}, nullopt, WriteTochnogFormat); } ================================================ FILE: libsrc/interface/writeuser.cpp ================================================ // // Write user dependent output file // #include #include #include #include #include #include #include "writeuser.hpp" #include "../general/gzstream.h" namespace netgen { std::map& UserFormatRegister::getFormats() { static std::map formats = {}; return formats; } void UserFormatRegister::Register(UserFormatRegister::UserFormatEntry && entry) { getFormats()[entry.format] = std::move(entry); } const bool UserFormatRegister::HaveFormat(string format) { const auto formats = getFormats(); return formats.find(format) != formats.end(); } const UserFormatRegister::UserFormatEntry & UserFormatRegister::Get(string format) { return getFormats()[format]; } extern MeshingParameters mparam; void RegisterUserFormats (NgArray & names, NgArray & extensions) { for (const auto & entry : UserFormatRegister::getFormats()) { names.Append (entry.second.format.c_str()); extensions.Append (entry.second.extensions[0].c_str()); } } bool WriteUserFormat (const string & format, const Mesh & mesh, const filesystem::path & filename) { if(!UserFormatRegister::HaveFormat(format)) return true; const auto entry = UserFormatRegister::Get(format); if(!entry.write) return true; (*entry.write)(mesh, filename); return false; } /* * Neutral mesh format * points, elements, surface elements */ void WriteNeutralFormat (const Mesh & mesh, const filesystem::path & 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); outfile.precision(6); outfile.setf (ios::fixed, ios::floatfield); outfile.setf (ios::showpoint); outfile << np << "\n"; for (int 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 (int i = 1; i <= ne; i++) { Element el = mesh.VolumeElement(i); */ for (Element el : mesh.VolumeElements()) { if (inverttets) el.Invert(); outfile.width(4); outfile << el.GetIndex() << " "; for (int j = 1; j <= el.GetNP(); j++) { outfile << " "; outfile.width(8); outfile << el.PNum(j); } outfile << "\n"; } } outfile << nse << "\n"; /* for (int i = 1; i <= nse; i++) { Element2d el = mesh.SurfaceElement(i); */ for (Element2d el : mesh.SurfaceElements()) { if (invertsurf) el.Invert(); outfile.width(4); outfile << mesh.GetFaceDescriptor (el.GetIndex()).BCProperty() << " "; for (int j = 1; j <= el.GetNP(); j++) { outfile << " "; outfile.width(8); outfile << el.PNum(j); } outfile << "\n"; } if (mesh.GetDimension() == 2) { outfile << nseg << "\n"; for (int i = 1; i <= nseg; i++) { const Segment & seg = mesh.LineSegment(i); outfile.width(4); outfile << seg.si << " "; for (int j = 0; j < seg.GetNP(); j++) { outfile << " "; outfile.width(8); outfile << seg[j]; } /* outfile << " "; outfile.width(8); outfile << seg[0]; outfile << " "; outfile.width(8); outfile << seg[1]; if (seg[2] != -1) { outfile.width(8); outfile << seg[2]; } */ outfile << "\n"; } } } void WriteSurfaceFormat (const Mesh & mesh, const filesystem::path & filename) { // surface mesh int i, j; cout << "Write Surface Mesh" << endl; ofstream outfile (filename); 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 filesystem::path & filename) { cout << "\nWrite STL Surface Mesh" << endl; auto ext = filename.extension(); ostream *outfile; if(ext == ".gz") outfile = new ogzstream(filename); else outfile = new ofstream(filename); 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 filesystem::path & filename) { cout << "\nWrite STL Surface Mesh (with separated boundary faces)" << endl; auto ext = filename.extension(); ostream *outfile; if(ext == ".gz") outfile = new ogzstream(filename); else outfile = new ofstream(filename); outfile->precision(10); int numBCs = 0; NgArray faceBCs; TABLE 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 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[faceSei[i]].PNum(1)); const Point3d& p2 = mesh.Point(mesh[faceSei[i]].PNum(2)); const Point3d& p3 = mesh.Point(mesh[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 filesystem::path & filename) { if (faces) { // Output in VRML, IndexedFaceSet is used // Bartosz Sawicki int np = mesh.GetNP(); int nse = mesh.GetNSE(); int i, j; ofstream outfile (filename); 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 int np = mesh.GetNP(); int nse = mesh.GetNSE(); int i, j; ofstream outfile (filename); 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"; } } void WriteVRMLFormatLineset (const Mesh & mesh, const filesystem::path & filename) { WriteVRMLFormat(mesh, false, filename); } void WriteVRMLFormatFaceset (const Mesh & mesh, const filesystem::path & filename) { WriteVRMLFormat(mesh, true, filename); } /* * FEPP .. a finite element package developed at University Linz, Austria */ void WriteFEPPFormat (const Mesh & mesh, const filesystem::path & filename) { ofstream outfile (filename); 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); */ for (const Element & el : mesh.VolumeElements()) { 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 filesystem::path & 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 inverttets = mparam.inverttets; int invertsurf = mparam.inverttrigs; NgArray edges; ofstream outfile (filename); outfile.precision(6); outfile.setf (ios::fixed, ios::floatfield); outfile.setf (ios::showpoint); // vertices with coordinates outfile << npoints << "\n"; for (int 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); */ for (ElementIndex ei : Range(mesh.VolumeElements())) { int i = ei-IndexBASE(ei)+1; Element el = mesh.VolumeElement(ei); if (inverttets) el.Invert(); outfile.width(4); outfile << el.GetIndex() << " "; outfile.width(8); outfile << el.GetNP(); for (int j = 1; j <= el.GetNP(); j++) { outfile << " "; outfile.width(8); outfile << el.PNum(j); } // top->GetElementEdges(i,edges); auto eledges = top->GetEdges(ei); outfile << endl << " "; outfile.width(8); outfile << eledges.Size(); for (int j=1; j <= eledges.Size(); j++) { outfile << " "; outfile.width(8); outfile << eledges[j-1]+1; } outfile << "\n"; // orientation: top->GetElementEdgeOrientations(i,edges); outfile << " "; for (int 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 (int i = 1; i <= nsurfelem; i++) { SurfaceElementIndex sei(i-1); Element2d el = mesh[sei]; if (invertsurf) el.Invert(); outfile.width(4); outfile << mesh.GetFaceDescriptor (el.GetIndex()).BCProperty() << " "; outfile.width(8); outfile << el.GetNP(); for (int j = 1; j <= el.GetNP(); j++) { outfile << " "; outfile.width(8); outfile << el.PNum(j); } // top->GetSurfaceElementEdges(i,edges); auto edges = top->GetEdges(sei); outfile << endl << " "; outfile.width(8); outfile << edges.Size(); for (int j=0; j < edges.Size(); j++) { outfile << " "; outfile.width(8); outfile << edges[j]+1; } outfile << "\n"; } // int v1, v2; // edge - vertex - list outfile << nedges << "\n"; for (int i=1; i <= nedges; i++) { // top->GetEdgeVertices(i,v1,v2); auto [v1,v2] = top->GetEdgeVertices(i-1); outfile.width(4); outfile << v1; outfile << " "; outfile.width(8); outfile << v2 << endl; } } static RegisterUserFormat reg_neutral("Neutral Format", {".mesh"}, ReadFile, WriteNeutralFormat); static RegisterUserFormat reg_surface("Surface Mesh Format", {".mesh", ".surf"} ,ReadFile, WriteSurfaceFormat); static RegisterUserFormat reg_stl ("STL Format", {".stl", ".stlb"}, ReadFile, WriteSTLFormat); static RegisterUserFormat reg_stlx ("STL Extended Format", {".stl", ".stlb"}, nullopt, WriteSTLExtFormat); static RegisterUserFormat reg_vrml ("VRML Format", {".*"}, nullopt, WriteVRMLFormatLineset); static RegisterUserFormat reg_vrml_faces ("VRML Format Faces", {".*"}, nullopt, WriteVRMLFormatFaceset); static RegisterUserFormat reg_fepp ("Fepp Format", {"*"}, nullopt, WriteFEPPFormat); static RegisterUserFormat reg_edgeelement ("EdgeElement Format", {"*"}, nullopt, WriteEdgeElementFormat); } ================================================ FILE: libsrc/interface/writeuser.hpp ================================================ #ifndef WRITEUSER #define WRITEUSER /**************************************************************************/ /* File: writeuser.hh */ /* Authors: many */ /* Date: 10. Dec. 97 */ /**************************************************************************/ #include #include #include #include namespace netgen { using namespace std::filesystem; typedef std::function FWrite; typedef std::function FRead; typedef std::function FTest; struct UserFormatRegister { struct UserFormatEntry { string format; Array extensions; optional read; optional write; }; static void Register(UserFormatEntry && entry); static const bool HaveFormat(string format); DLL_HEADER static const UserFormatEntry & Get(string format); template static void IterateFormats(TFunc func, bool need_read=false, bool need_write=false) { Array import_formats; for(const auto & e: getFormats()) if((!need_read || e.second.read) && (!need_write || e.second.write)) import_formats.Append(e.second.format); QuickSort(import_formats); for(auto format : import_formats) func(Get(format)); } DLL_HEADER static std::map& getFormats(); }; struct RegisterUserFormat { RegisterUserFormat(string format, Array extensions, optional read, optional write, FTest ftest = [](const filesystem::path & ){return true;}) { UserFormatRegister::Register({format, std::move(extensions), std::move(read), std::move(write)}); } }; DLL_HEADER void ReadFile(Mesh & mesh, const filesystem::path & filename); DLL_HEADER void ReadUserFormat(Mesh & mesh, const filesystem::path & filename, const string & format = ""); extern bool DLL_HEADER WriteUserFormat (const string & format, const Mesh & mesh, const filesystem::path & filename); extern void DLL_HEADER RegisterUserFormats (NgArray & names, NgArray & extensions); } #endif ================================================ FILE: libsrc/interface/wuchemnitz.cpp ================================================ // Write Chemnitz file format #include #include #include #include #include #include "writeuser.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 NgArray points; static NgArray volelements; static NgArray surfelements; static NgArray faces; static NgArray 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 faceindex(volelements.Size()/5 + 1); INDEX_2_HASHTABLE 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(); faces.Append (fa); facei = faces.Size(); 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(); edges.Append (ed); edgei = edges.Size(); 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 filesystem::path & filename) { ofstream outfile (filename); ReadFileMesh (mesh); Convert (); WriteFile (outfile); cout << "Wrote Chemnitz standard file" << endl; } static RegisterUserFormat reg_chemnitz ("Chemnitz Format", {"*"}, nullopt, WriteUserChemnitz ); } ================================================ FILE: libsrc/linalg/CMakeLists.txt ================================================ target_sources(nglib PRIVATE bfgs.cpp densemat.cpp linopt.cpp linsearch.cpp polynomial.cpp ) install(FILES densemat.hpp linalg.hpp opti.hpp polynomial.hpp vector.hpp DESTINATION ${NG_INSTALL_DIR_INCLUDE}/linalg COMPONENT netgen_devel ) ================================================ FILE: libsrc/linalg/bfgs.cpp ================================================ /***************************************************************************/ /* */ /* Vorlesung Optimierung I, Gfrerer, WS94/95 */ /* BFGS-Verfahren zur Lösung freier nichtlinearer Optimierungsprobleme */ /* */ /* Programmautor: Joachim Schöberl */ /* Matrikelnummer: 9155284 */ /* */ /***************************************************************************/ #include #include #include #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 // cout << "it " << it << "f = " << f << endl; 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; } // cout << endl; // (*testout) << "x = " << x << ", x0 = " << x0 << endl; return f; } } ================================================ FILE: libsrc/linalg/densemat.cpp ================================================ #include #include namespace netgen { DenseMatrix :: DenseMatrix () { data = NULL; height = 0; width = 0; } DenseMatrix :: DenseMatrix (int h, int w) { if (!w) w = h; width = w; height = h; int hw = h*w; if (hw) data = new double[hw]; else data = 0; for (int i = 0 ; i < (hw); 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()); if (Height() && 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; NgArray 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 NgArray & 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 NgArray & 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; } } ================================================ FILE: libsrc/linalg/densemat.hpp ================================================ #ifndef FILE_DENSEMAT #define FILE_DENSEMAT /**************************************************************************/ /* File: densemat.hpp */ /* Author: Joachim Schoeberl */ /* Date: 01. Oct. 94 */ /**************************************************************************/ /** Data type dense matrix */ #include #include "vector.hpp" namespace netgen { 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 class MatrixFixWidth { protected: int height; T * __restrict data; bool ownmem; public: /// MatrixFixWidth () { height = 0; data = 0; ownmem = false; } /// MatrixFixWidth (int h) { height = h; data = new T[WIDTH*height]; ownmem = true; } /// MatrixFixWidth (int h, T * adata) { height = h; data = adata; ownmem = false; } /// MatrixFixWidth (const MatrixFixWidth & m2) : height(m2.height), ownmem(true) { data = new T[height*WIDTH]; for (int i = 0; i < WIDTH*height; i++) data[i] = m2.data[i]; } // : height(m2.height), data(m2.data), ownmem(false) //{ ; } /// ~MatrixFixWidth () { if (ownmem) delete [] data; } void SetSize (int h) { if (h != height) { if (ownmem) delete data; height = h; data = new T[WIDTH*height]; ownmem = true; } } /// int Height() const { return height; } /// int Width() const { return WIDTH; } MatrixFixWidth & operator= (const MatrixFixWidth & m2) { for (int i = 0; i < height*WIDTH; i++) data[i] = m2.data[i]; } /// MatrixFixWidth & operator= (T v) { for (int i = 0; i < height*WIDTH; i++) data[i] = v; return *this; } /* /// void Mult (const FlatVector & v, FlatVector & prod) const { T sum; const T * mp, * sp; T * dp; 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++; } } */ T & operator() (int i, int j) { return data[i*WIDTH+j]; } const T & operator() (int i, int j) const { return data[i*WIDTH+j]; } MatrixFixWidth & operator*= (T v) { if (data) for (int i = 0; i < height*WIDTH; i++) data[i] *= v; return *this; } const T & Get(int i, int j) const { return data[(i-1)*WIDTH+j-1]; } /// const T & Get(int i) const { return data[i-1]; } /// void Set(int i, int j, T v) { data[(i-1)*WIDTH+j-1] = v; } /// T & Elem(int i, int j) { return data[(i-1)*WIDTH+j-1]; } /// const T & ConstElem(int i, int j) const { return data[(i-1)*WIDTH+j-1]; } }; template class MatrixFixWidth { protected: int height; double * data; bool ownmem; public: /// MatrixFixWidth () { height = 0; data = 0; ownmem = false; } /// MatrixFixWidth (int h) { height = h; data = new double[WIDTH*height]; ownmem = true; } MatrixFixWidth (const MatrixFixWidth & m2) : height(m2.height), ownmem(true) { data = new double[height*WIDTH]; for (int i = 0; i < WIDTH*height; i++) data[i] = m2.data[i]; } /// MatrixFixWidth (int h, double * adata) { height = h; data = adata; ownmem = false; } /// ~MatrixFixWidth () { if (ownmem) delete [] data; } void SetSize (int h) { if (h != height) { if (ownmem) delete data; height = h; data = new double[WIDTH*height]; ownmem = true; } } /// 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 extern ostream & operator<< (ostream & ost, const MatrixFixWidth & 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); } // namespace netgen #endif ================================================ FILE: libsrc/linalg/linalg.hpp ================================================ #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" #include "vector.hpp" #include "densemat.hpp" #include "polynomial.hpp" #endif ================================================ FILE: libsrc/linalg/linopt.cpp ================================================ #include #include #include #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; } } } } ================================================ FILE: libsrc/linalg/linsearch.cpp ================================================ /***************************************************************************/ /* */ /* Problem: Liniensuche */ /* */ /* Programmautor: Joachim Schöberl */ /* Matrikelnummer: 9155284 */ /* */ /* Algorithmus nach: */ /* */ /* Optimierung I, Gfrerer, WS94/95 */ /* Algorithmus 2.1: Liniensuche Problem (ii) */ /* */ /***************************************************************************/ #include #include // min, max, sqr #include #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; // cout << "lin: "; while (it++ <= par.maxit_linsearch) { // cout << "i = " << it << " f = " << f << " "; 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; // cout << 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; } } ================================================ FILE: libsrc/linalg/opti.hpp ================================================ #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 fr alpha_hat // o: Loesung falls ifail = 0 double fmin, // i: untere Schranke fr 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 Grnden /** 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 ================================================ FILE: libsrc/linalg/polynomial.cpp ================================================ #include #include 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; } } ================================================ FILE: libsrc/linalg/polynomial.hpp ================================================ #ifndef FILE_POLYNOMIAL #define FILE_POLYNOMIAL /* *************************************************************************/ /* File: polynomial.hh */ /* Author: Joachim Schoeberl */ /* Date: 25. Nov. 99 */ /* *************************************************************************/ namespace netgen { 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 (); }; } // namespace netgen #endif ================================================ FILE: libsrc/linalg/vector.hpp ================================================ #ifndef FILE_VECTOR #define FILE_VECTOR /* *************************************************************************/ /* File: vector.hpp */ /* Author: Joachim Schoeberl */ /* Date: 01. Oct. 94 */ /* *************************************************************************/ namespace netgen { template class TFlatVector { protected: int s; T * data; public: TFlatVector () { ; } TFlatVector (int as, T * adata) { s = as; data = adata; } int Size () const { return s; } TFlatVector & operator= (const TFlatVector & v) { memcpy (data, v.data, s*sizeof(T)); return *this; } TFlatVector & operator= (T scal) { for (int i = 0; i < s; i++) data[i] = scal; return *this; } T & operator[] (int i) { return data[i]; } const T & operator[] (int i) const { return data[i]; } T & operator() (int i) { return data[i]; } const T & 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; } TFlatVector & operator*= (T scal) { for (int i = 0; i < s; i++) data[i] *= scal; return *this; } }; 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); } operator TFlatVector () const { return TFlatVector (s, data); } 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; } template void DoArchive(ARCHIVE& ar) { auto size = s; ar & ownmem & size; if(!ar.Output()) SetSize(size); ar.Do(data, size); } 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; } } operator TFlatVector () const { return TFlatVector (s, data); } }; template 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; } } //namespace netgen #endif ================================================ FILE: libsrc/meshing/CMakeLists.txt ================================================ target_sources(nglib PRIVATE 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 refine.cpp ruler2.cpp ruler3.cpp secondorder.cpp smoothing2.5.cpp smoothing2.cpp smoothing3.cpp specials.cpp topology.cpp validate.cpp bcfunctions.cpp parallelmesh.cpp paralleltop.cpp basegeom.cpp python_mesh.cpp surfacegeom.cpp debugging.cpp fieldlines.cpp visual_interface.cpp boundarylayer2d.cpp boundarylayer_interpolate.cpp ) target_link_libraries( nglib PRIVATE $ $ ) install(FILES adfront2.hpp adfront3.hpp basegeom.hpp bcfunctions.hpp bisect.hpp boundarylayer.hpp classifyhpel.hpp clusters.hpp curvedelems.hpp findip2.hpp findip.hpp geomsearch.hpp global.hpp hpref_hex.hpp hprefinement.hpp hpref_prism.hpp hpref_pyramid.hpp hpref_quad.hpp hpref_segm.hpp hpref_tet.hpp hpref_trig.hpp improve2.hpp improve3.hpp localh.hpp meshclass.hpp meshfunc.hpp meshing2.hpp meshing3.hpp meshing.hpp meshtool.hpp meshtype.hpp msghandler.hpp paralleltop.hpp ruler2.hpp ruler3.hpp specials.hpp topology.hpp validate.hpp python_mesh.hpp surfacegeom.hpp delaunay2d.hpp fieldlines.hpp soldata.hpp visual_interface.hpp DESTINATION ${NG_INSTALL_DIR_INCLUDE}/meshing COMPONENT netgen_devel ) ================================================ FILE: libsrc/meshing/adfront2.cpp ================================================ /* Advancing front class for surfaces */ #include #include #include #include "adfront2.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 << "WARNING: 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(); starti = *lines.Range().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++) for (int i : lines.Range()) if (lines[i].Valid()) ost << i << ": " << GetGlobalIndex (lines[i].L().I1()) << "-" << GetGlobalIndex (lines[i].L().I2()) << endl; } } /* void AdFront2 :: GetPoints (NgArray > & 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 { points.Append (FrontPoint2 (p, globind, mgi, pointonsurface)); pi = points.Size()-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 { lines.Append(FrontLine (INDEX_2(pi1, pi2))); li = lines.Size()-1; } if (!gi1.trignum || !gi2.trignum) { cout << "WARNING: 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 (PointIndices<2>(GetGlobalIndex (pi1), GetGlobalIndex (pi2)))) { cerr << "ERROR Adfront2::AddLine: line exists" << endl; (*testout) << "ERROR Adfront2::AddLine: line exists" << endl; } allflines->Set (PointIndices<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 (PointIndices<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; } 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++) for (int i = starti; i < *lines.Range().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++) for (int i : lines.Range()) 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, NgArray> & locpoints, NgArray & pgeominfo, NgArray & loclines, // local index NgArray & pindex, NgArray & lindex, double xh) { // static Timer timer("adfront2::GetLocals"); 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 nearlines(0); NgArrayMem nearpoints(0); // dominating costs !! linesearchtree.GetIntersecting (p0 - Vec3d(xh, xh, xh), p0 + Vec3d(xh, xh, xh), nearlines); // only special points that are not in adfront, // other points are from linesearchtree cpointsearchtree.GetIntersecting(p0 - Vec3d(xh, xh, xh), p0 + Vec3d(xh, xh, xh), nearpoints); for(auto i : nearlines) { if (lines[i].Valid() && i != baselineindex) { loclines.Append(lines[i].L()); lindex.Append(i); } } // static NgArray invpindex; invpindex.SetSize (points.Size()); // invpindex = -1; for(auto pi : nearpoints) invpindex[pi] = -1; for(const auto& li : loclines) { invpindex[li.I1()] = 0; invpindex[li.I2()] = 0; } for(auto& line : loclines) { for(auto i : Range(2)) { auto& pi = line[i]; if (invpindex[pi] == 0) { pindex.Append (pi); invpindex[pi] = pindex.Size(); locpoints.Append (points[pi].P()); pi = locpoints.Size(); } else pi = invpindex[pi]; } } // double xh2 = xh*xh; for(auto i : nearpoints) { if (points[i].Valid() && points[i].OnSurface() && // Dist2 (points.Get(i).P(), p0) <= xh2 && invpindex[i] <= 0) { locpoints.Append (points[i].P()); invpindex[i] = locpoints.Size(); 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 << IM(5) << "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++) for (int i : lines.Range()) 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++) for (int i : points.Range()) if (points[i].Valid()) ost << i << " " << points[i].P() << endl; ost << nfl << " Lines: " << endl; // for (int i = lines.Begin(); i < lines.End(); i++) for (int i : lines.Range()) 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); // quasi-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); } bool AdFront2 :: SameSide (const Point<2> & lp1, const Point<2> & lp2, const FlatArray * testfaces) const { int cnt = 0; if (testfaces) { for (int ii = 0; ii < testfaces->Size(); ii++) if (lines[(*testfaces)[ii]].Valid()) { int i = (*testfaces)[ii]; const Point<3> & p13d = points[lines[i].L().I1()].P(); const Point<3> & p23d = points[lines[i].L().I2()].P(); Point<2> p1(p13d(0), p13d(1)); Point<2> p2(p23d(0), p23d(1)); // p1 + alpha v = lp1 + beta vl Vec<2> v = p2-p1; Vec<2> vl = lp2 - lp1; Mat<2,2> mat, inv; Vec<2> rhs, sol; mat(0,0) = v(0); mat(1,0) = v(1); mat(0,1) = -vl(0); mat(1,1) = -vl(1); rhs = lp1-p1; if (Det(mat) == 0) continue; CalcInverse (mat, inv); sol = inv * rhs; if ( (sol(0) >= 0) && (sol(0) <= 1) && (sol(1) >= 0) && (sol(1) <= 1)) { cnt++; } } } else { for (int i = 0; i < lines.Size(); i++) if (lines[i].Valid()) { const Point<3> & p13d = points[lines[i].L().I1()].P(); const Point<3> & p23d = points[lines[i].L().I2()].P(); Point<2> p1(p13d(0), p13d(1)); Point<2> p2(p23d(0), p23d(1)); // p1 + alpha v = lp1 + beta vl Vec<2> v = p2-p1; Vec<2> vl = lp2 - lp1; Mat<2,2> mat, inv; Vec<2> rhs, sol; mat(0,0) = v(0); mat(1,0) = v(1); mat(0,1) = -vl(0); mat(1,1) = -vl(1); rhs = lp1-p1; if (Det(mat) == 0) continue; CalcInverse (mat, inv); sol = inv * rhs; if ((sol(0) >= 0) && (sol(0) <= 1) && (sol(1) >= 0) && (sol(1) <= 1)) { cnt++; } } } return ((cnt % 2) == 0); } } ================================================ FILE: libsrc/meshing/adfront2.hpp ================================================ #ifndef NETGEN_ADFRONT2_HPP #define NETGEN_ADFRONT2_HPP /**************************************************************************/ /* File: adfront2.hpp */ /* Author: Joachim Schoeberl */ /* Date: 01. Okt. 95 */ /**************************************************************************/ /** Advancing front class for surfaces */ #include #include #include "meshtype.hpp" namespace netgen { /// 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.Invalidate(); // = -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; // want to replace by std::array 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 auto & L () const { return l; } /// int LineClass() const { return lineclass; } /// void IncrementClass () { lineclass++; } /// void ResetClass () { lineclass = 1; } /// bool Valid () const { return l[0] != -1; } /// void Invalidate () { l[0] = -1; l[1] = -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 points; /// front points Array lines; /// front lines Box3d boundingbox; BoxTree<3> linesearchtree; /// search tree for lines Point3dTree pointsearchtree; /// search tree for points Point3dTree cpointsearchtree; /// search tree for cone points (not used ???) Array delpointl; /// list of deleted front points Array dellinel; /// list of deleted front lines int nfl; /// number of front lines; INDEX_2_HASHTABLE * allflines; /// all front lines ever have been Array invpindex; int minval; int starti; public: /// // AdFront2 (); AdFront2 (const Box3d & aboundingbox); /// ~AdFront2 (); /// // void GetPoints (NgArray > & apoints) const; /// void Print (ostream & ost) const; /// bool Empty () const { return nfl == 0; } /// int GetNFL () const { return nfl; } const FrontLine & GetLine (int nr) const { return lines[nr]; } const FrontPoint2 & GetPoint (int nr) const { return points[nr]; } const auto & GetLines () const { return lines; } /// int SelectBaseLine (Point<3> & p1, Point<3> & p2, const PointGeomInfo *& geominfo1, const PointGeomInfo *& geominfo2, int & qualclass); /// int GetLocals (int baseline, NgArray> & locpoints, NgArray & pgeominfo, NgArray & loclines, // local index NgArray & pindex, NgArray & 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 FlatArray * /* testfaces */ = NULL) const; /* { return Inside (lp1) == Inside (lp2); } */ /// void SetStartFront (); /// void PrintOpenSegments (ostream & ost) const; }; } // namespace netgen #endif // NETGEN_ADFRONT2_HPP ================================================ FILE: libsrc/meshing/adfront3.cpp ================================================ #include #include #include "adfront3.hpp" /* ********************** FrontPoint ********************** */ namespace netgen { FrontPoint3 :: FrontPoint3 () { globalindex.Invalidate(); // = -1; nfacetopoint = 0; frontnr = 1000; cluster = PointIndex::INVALID; } FrontPoint3 :: FrontPoint3 (const Point<3> & ap, PointIndex agi) { p = ap; globalindex = agi; nfacetopoint = 0; frontnr = 1000; cluster = PointIndex::INVALID; } /* ********************** FrontFace ********************** */ FrontFace :: FrontFace () { qualclass = 1; oldfront = 0; hashvalue = 0; cluster = PointIndex::INVALID; } 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 (NgArray > & apoints) const { /* for (PointIndex pi = points.Begin(); pi < points.End(); pi++) apoints.Append (points[pi].P()); */ for (auto & p : points) apoints.Append(p.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.End(); return *points.Range().end()-1; // 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; } PointIndex cluster = PointIndex::INVALID; for (i = 1; i <= aface.GetNP(); i++) { if (points[aface.PNum(i)].cluster.IsValid()) 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); faces.Append(FrontFace (aface)); int nfn = faces.Size(); 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); */ for (PointIndex pi : faces.Get(fi).Face().PNums()) { 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 (PointIndices<2> apair) { if (!connectedpairs) connectedpairs = make_unique> (GetNP()); connectedpairs->Add (apair[0], apair[1]); connectedpairs->Add (apair[1], apair[0]); return 0; } void AdFront3 :: CreateTrees () { int i, j; PointIndex pi; Point3d pmin, pmax; for (pi = IndexBASE(); pi < GetNP()+IndexBASE(); pi++) { const Point<3> & p = GetPoint(pi); if (pi == IndexBASE()) { 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 BoxTree<3> (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, NgArray & 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 (PointIndex pi = points.Begin(); pi < points.End(); pi++) for (PointIndex pi : points.Range()) points[pi].cluster = pi; 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(); PointIndex mini = points[el.PNum(1)].cluster; PointIndex maxi = mini; for (int j = 2; j <= 3; j++) { PointIndex 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); Array usecl(np); usecl = false; for (int i = 1; i <= faces.Size(); i++) { usecl[points[faces.Get(i).Face().PNum(1)].cluster] = true; 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[i]) cntcl++; */ Array 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); bool negvol = false; for (auto i : clvol.Range()) if (clvol[i] < 0) negvol = true; if (negvol) { for (int i = 1; i <= faces.Size(); i++) faces.Elem(i).cluster = IndexBASE(); // for (PointIndex pi = points.Begin(); pi < points.End(); pi++) for (PointIndex pi : points.Range()) points[pi].cluster = IndexBASE(); } if (hashon) hashtable.Create(); NgProfiler::StopTimer (timer_d); } int AdFront3 :: SelectBaseElement () { /* 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; } */ int fstind = 0; for (int i = lasti+1; i <= faces.Size() && !fstind; i++) if (faces.Elem(i).Valid()) { int 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 (int i = 1; i <= faces.Size(); i++) if (faces.Elem(i).Valid()) { int 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 & locpoints, Array & locfaces, // local index Array & pindex, Array & findex, INDEX_2_HASHTABLE & 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; PointIndex pstind; Point3d midp, p0; // static NgArray invpindex; NgArray locfaces2; //all local faces in radius xh NgArray locfaces3; // all faces in outer radius relh NgArray findex2; locfaces2.SetSize(0); locfaces3.SetSize(0); findex2.SetSize(0); PointIndex 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++) { PointIndex pi = locfaces.Get(i).PNum(j); invpindex[pi] = PointIndex::INVALID; } */ for (auto & f : locfaces) for (int j = 1; j <= f.GetNP(); j++) { PointIndex pi = f.PNum(j); invpindex[pi] = PointIndex::INVALID; } // for (i = 1; i <= locfaces.Size(); i++) for (auto & f : locfaces) { // for (j = 1; j <= locfaces.Get(i).GetNP(); j++) for (int j = 1; j <= f.GetNP(); j++) { // PointIndex pi = locfaces.Get(i).PNum(j); PointIndex pi = f.PNum(j); if (!invpindex[pi].IsValid()) { pindex.Append (pi); locpoints.Append (points[pi].P()); invpindex[pi] = pindex.Size()-1+IndexBASE(); } // locfaces.Elem(i).PNum(j) = invpindex[pi]; f.PNum(j) = invpindex[pi]; } } if (connectedpairs) { // for (i = 1; i <= locpoints.Size(); i++) for (auto i : locpoints.Range()) { PointIndex pind = pindex[i]; // .Get(i); // if (pind.IsValid() && pind <= connectedpairs->Size ()) if (connectedpairs->Range().Contains(pind)) { // for (int j = 1; j <= connectedpairs->EntrySize(pind); j++) for (auto j : (*connectedpairs)[pind].Range()) { //PointIndex oi = connectedpairs->Get(pind, j); PointIndex oi = (*connectedpairs)[pind][j]; PointIndex other = invpindex[oi]; // if (other >= 1 && other <= pindex.Size() && if (pindex.Range().Contains(other) && pindex[other] == oi) { // INDEX_2 coned(i, other); // coned.Sort(); // (*testout) << "connected: " << locpoints.Get(i) << "-" << locpoints.Get(other) << endl; getconnectedpairs.Set (PointIndices<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 & grouppoints, Array & groupelements, Array & pindex, Array & findex) { // static NgArray pingroup; int changed; pingroup.SetSize(points.Size()); pingroup = 0; for (int j = 1; j <= 3; j++) pingroup[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; } } */ for (auto & f : faces) if (f.Valid()) { const MiniElement2d & face = f.Face(); int fused = 0; for (int j = 1; j <= 3; j++) if (pingroup[face.PNum(j)]) fused++; if (fused >= 2) for (int j = 1; j <= 3; j++) if (!pingroup[face.PNum(j)]) { pingroup[face.PNum(j)] = 1; changed = 1; } } } while (changed); invpindex.SetSize (points.Size()); // for (PointIndex pi = points.Begin(); pi < points.End(); pi++) for (PointIndex pi : points.Range()) if (points[pi].Valid()) { grouppoints.Append (points[pi].P()); pindex.Append (pi); // invpindex[pi] = pindex.Size(); invpindex[pi] = pindex.Size()-1 + IndexBASE(); } for (int i = 1; i <= faces.Size(); i++) if (faces.Get(i).Valid()) { int fused = 0; for (int j = 1; j <= 3; j++) if (pingroup[faces.Get(i).Face().PNum(j)]) fused++; if (fused >= 2) { groupelements.Append (faces.Get(i).Face()); findex.Append (i); } } /* for (int i = 1; i <= groupelements.Size(); i++) for (int j = 1; j <= 3; j++) { groupelements.Elem(i).PNum(j) = invpindex.Get(groupelements.Elem(i).PNum(j)); } */ for (auto & e : groupelements) for (int j = 1; j <= 3; j++) e.PNum(j) = invpindex[e.PNum(j)]; } void AdFront3 :: SetStartFront (int /* baseelnp */) { for (INDEX i = 1; i <= faces.Size(); i++) if (faces.Get(i).Valid()) { const MiniElement2d & face = faces.Get(i).Face(); for (int 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 :: PointInsideGroup(const Array &grouppindex, const Array &groupfaces) const { for(auto pi : Range(points)) { const auto& p = points[pi].P(); bool found = false; for(const auto& f : groupfaces) { for(auto i : Range(3)) if(grouppindex[f.PNum(i+1)] == pi) { found = true; break; } } if(found) continue; // "random" direction Vec<3> dir = { 0.123871, 0.15432,-0.43989 }; DenseMatrix a(3), ainv(3); Vector b(3), u(3); int count = 0; for(const auto& f : groupfaces) { const auto& p1 = points[grouppindex[f.PNum(1)]].P(); auto v1 = points[grouppindex[f.PNum(2)]].P() - p1; auto v2 = points[grouppindex[f.PNum(3)]].P() - p1; for(auto i : Range(3)) { a(i,0) = v1[i]; a(i,1) = v2[i]; a(i,2) = -dir[i]; b(i) = p[i] - p1[i]; } CalcInverse (a, ainv); ainv.Mult (b, u); if (u(0) >= 0 && u(1) >= 0 && u(0)+u(1) <= 1 && u(2) > 0) count++; } if (count % 2 == 1) return true; } return false; } bool AdFront3 :: Inside (const Point<3> & p) const { static Timer timer("AdFront3::Inside"); RegionTimer rt(timer); 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 NgArray * 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); NgArrayMem 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); } } ================================================ FILE: libsrc/meshing/adfront3.hpp ================================================ #ifndef FILE_ADFRONT3 #define FILE_ADFRONT3 /**************************************************************************/ /* File: adfront3.hh */ /* Author: Joachim Schoeberl */ /* Date: 01. Okt. 95 */ /**************************************************************************/ /* Advancing front class for volume meshing */ #include #include #include "meshtype.hpp" #include "geomsearch.hpp" namespace netgen { /// 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; /// PointIndex 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++; } /// if last face is removed, then point is invalidated void RemoveFace() { nfacetopoint--; if (nfacetopoint == 0) nfacetopoint = -1; } /// bool 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]; // can be global or local nums 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]; } auto PNums() { return FlatArray (np, &pnum[0]); } auto PNums() const { return FlatArray (np, &pnum[0]); } void Delete () { deleted = true; for (PointIndex & p : pnum) p.Invalidate(); } 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; /// PointIndex 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; PointIndex Cluster () const { return cluster; } }; /// Advancing front, 3D. class AdFront3 { /// // NgArray points; Array points ; /// NgArray faces; /// Array delpointl; /// which points are connected to pi ? // TABLE * connectedpairs; unique_ptr> 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 invpindex; Array pingroup; /// class BoxTree<3> * facetree; public: /// AdFront3 (); /// ~AdFront3 (); /// void GetPoints (NgArray > & apoints) const; /// int GetNP() const { return points.Size(); } /// const Point<3> & GetPoint (PointIndex pi) const { return points[pi].P(); } /// int GetNF() const { return nff; } /// 1-based const MiniElement2d & GetFace (int i) const { return faces[i-1].Face(); } const auto & Faces() const { return faces; } /// 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, NgArray & ifaces) const; bool PointInsideGroup(const Array &grouppindex, const Array& groupfaces) const; /// void GetFaceBoundingBox (int i, Box3d & box) const; /// int GetLocals (int baseelement, Array & locpoints, Array & locfaces, // local index Array & pindex, Array & findex, INDEX_2_HASHTABLE & connectedpairs, float xh, float relh, INDEX& facesplit); /// void GetGroup (int fi, Array & grouppoints, Array & groupelements, Array & pindex, Array & findex); /// void DeleteFace (INDEX fi); /// PointIndex AddPoint (const Point<3> & p, PointIndex globind); /// INDEX AddFace (const MiniElement2d & e); /// INDEX AddConnectedPair (PointIndices<2> pair); /// void IncrementClass (INDEX fi) { faces[fi-1].IncrementQualClass(); } /// void ResetClass (INDEX fi) { faces[fi-1].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 NgArray * testfaces = NULL) const; /// PointIndex GetGlobalIndex (PointIndex pi) const { return points[pi].GlobalIndex(); } /// double Volume () const { return vol; } private: void RebuildInternalTables(); }; } // namespace netgen #endif ================================================ FILE: libsrc/meshing/basegeom.cpp ================================================ #include #include #include "meshing.hpp" #include namespace netgen { struct PointTree { std::map> tree; Box<3> bounding_box; PointTree( Box<3> bb ) : bounding_box(bb) {} void Insert(Point<3> p, PointIndex n, int index) { if(tree.count(index) == 0) tree.emplace(index, bounding_box); tree.at(index).Insert(p, p, n); } PointIndex Find(Point<3> p, int index) const { ArrayMem points; tree.at(index).GetIntersecting(p, p, points); if(points.Size()==0) throw Exception("cannot find mapped point " + ToString(p)); return points[0]; } }; void ShapeProperties :: DoArchive( Archive & ar ) { ar & name & col & maxh & hpref & layer; if(ar.GetVersion("netgen") > "v6.2.2506-14") ar & partition & quad_dominated; } GeometryRegisterArray& GeometryRegister() { static GeometryRegisterArray geometryregister; return geometryregister; } GeometryRegister :: ~GeometryRegister() { ; } bool GeometryShape :: IsMappedShape( const GeometryShape & other_, const Transformation<3> & trafo, double tol ) const { throw Exception("GeometryShape::IsMappedShape not implemented for class " + Demangle(typeid(this).name())); } bool GeometryVertex :: IsMappedShape( const GeometryShape & other_, const Transformation<3> & trafo, double tol ) const { const auto other_ptr = dynamic_cast(&other_); if(!other_ptr) return false; return Dist(trafo(GetPoint()), other_ptr->GetPoint()) < tol; } bool GeometryEdge :: IsMappedShape( const GeometryShape & other_, const Transformation<3> & trafo, double tol ) const { const auto other_ptr = dynamic_cast(&other_); if(!other_ptr) return false; auto & e = *other_ptr; if (IsDegenerated(tol) || e.IsDegenerated(tol)) return false; if(tol < Dist(trafo(GetCenter()), e.GetCenter())) return false; auto v0 = trafo(GetStartVertex().GetPoint()); auto v1 = trafo(GetEndVertex().GetPoint()); auto w0 = e.GetStartVertex().GetPoint(); auto w1 = e.GetEndVertex().GetPoint(); // have two closed edges, use midpoints to compare if(Dist(v0,v1) < tol && Dist(w0,w1) < tol) { v1 = trafo(GetPoint(0.5)); w1 = other_ptr->GetPoint(0.5); } return( (Dist(v0, w0) < tol && Dist(v1, w1) < tol) || (Dist(v0, w1) < tol && Dist(v1, w0) < tol) ); } bool GeometryFace :: IsMappedShape( const GeometryShape & other_, const Transformation<3> & trafo, double tol ) const { const auto other_ptr = dynamic_cast(&other_); if(!other_ptr) return false; auto & f = *other_ptr; if(tol < Dist(GetCenter(), f.GetCenter())) return false; // simple check: check if there is a bijective mapping of mapped edges auto & other_edges = f.edges; if(edges.Size() != other_edges.Size()) return false; auto nedges = edges.Size(); Array is_mapped(nedges); is_mapped = false; for(auto e : edges) { int found_mapping = 0; for(auto other_e : other_edges) if(e->IsMappedShape(*other_e, trafo, tol)) found_mapping++; if(found_mapping != 1) return false; } return true; } bool GeometryFace :: IsConnectingCloseSurfaces() const { std::map verts; for(const auto& edge : edges) { verts[&edge->GetStartVertex()] = false; verts[&edge->GetEndVertex()] = false; } for(const auto& [v, is_mapped] : verts) { if(is_mapped) continue; for(const auto& v_ident : v->identifications) { const auto& other = v_ident.to == v ? v_ident.from : v_ident.to; if(v_ident.type == Identifications::CLOSESURFACES && verts.count(other)) { verts[v] = true; verts[other] = true; } } } for(auto& [v, is_mapped] : verts) if(!is_mapped) return false; return true; } void GeometryFace :: RestrictHTrig(Mesh& mesh, const PointGeomInfo& gi0, const PointGeomInfo& gi1, const PointGeomInfo& gi2, const MeshingParameters& mparam, int depth, double h) const { auto p0 = GetPoint(gi0); auto p1 = GetPoint(gi1); auto p2 = GetPoint(gi2); auto longest = (p0-p1).Length(); int cutedge = 2; if(auto len = (p0-p2).Length(); len > longest) { longest = len; cutedge = 1; } if(auto len = (p1-p2).Length(); len > longest) { longest = len; cutedge = 0; } PointGeomInfo gi_mid; gi_mid.u = (gi0.u + gi1.u + gi2.u)/3; gi_mid.v = (gi0.v + gi1.v + gi2.v)/3; if(depth % 3 == 0) { double curvature = 0.; curvature = max({curvature, GetCurvature(gi_mid), GetCurvature(gi0), GetCurvature(gi1), GetCurvature(gi2)}); if(curvature < 1e-3) return; double kappa = curvature * mparam.curvaturesafety; h = mparam.maxh * kappa < 1 ? mparam.maxh : 1./kappa; if(h < 1e-4 * longest) return; } if(h < longest && depth < 10) { if(cutedge == 0) { PointGeomInfo gi_m; gi_m.u = 0.5 * (gi1.u + gi2.u); gi_m.v = 0.5 * (gi1.v + gi2.v); RestrictHTrig(mesh, gi_m, gi2, gi0, mparam, depth+1, h); RestrictHTrig(mesh, gi_m, gi0, gi1, mparam, depth+1, h); } else if(cutedge == 1) { PointGeomInfo gi_m; gi_m.u = 0.5 * (gi0.u + gi2.u); gi_m.v = 0.5 * (gi0.v + gi2.v); RestrictHTrig(mesh, gi_m, gi1, gi2, mparam, depth+1, h); RestrictHTrig(mesh, gi_m, gi0, gi1, mparam, depth+1, h); } else if(cutedge == 2) { PointGeomInfo gi_m; gi_m.u = 0.5 * (gi0.u + gi1.u); gi_m.v = 0.5 * (gi0.v + gi1.v); RestrictHTrig(mesh, gi_m, gi1, gi2, mparam, depth+1, h); RestrictHTrig(mesh, gi_m, gi2, gi0, mparam, depth+1, h); } } else { auto pmid = GetPoint(gi_mid); for(const auto& p : {p0, p1, p2, pmid}) mesh.RestrictLocalH(p, h); } } namespace { struct Line { Point<3> p0, p1; inline double Length() const { return (p1-p0).Length(); } inline double Dist(const Line& other) const { Vec<3> n = p1-p0; Vec<3> q = other.p1-other.p0; double nq = n*q; Point<3> p = p0 + 0.5*n; double lambda = (p-other.p0)*n / (nq + 1e-10); if (lambda >= 0 && lambda <= 1) return (p-other.p0-lambda*q).Length(); return 1e99; } }; } void NetgenGeometry :: Clear() { vertices.SetSize0(); edges.SetSize0(); faces.SetSize0(); solids.SetSize0(); } void NetgenGeometry :: ProcessIdentifications() { for(auto i : Range(vertices)) vertices[i]->nr = i; for(auto i : Range(edges)) edges[i]->nr = i; for(auto i : Range(faces)) faces[i]->nr = i; for(auto i : Range(solids)) solids[i]->nr = i; auto mirror_identifications = [&] ( auto & shapes ) { for(auto i : Range(shapes)) { auto &s = shapes[i]; s->nr = i; for(auto & ident : s->identifications) if(s.get() == ident.from && s.get() != ident.to) ident.to->identifications.Append(ident); } }; auto tol = 1e-8 * bounding_box.Diam(); for(auto & f : faces) for(auto & ident: f->identifications) for(auto e : static_cast(ident.from)->edges) for(auto e_other : static_cast(ident.to)->edges) if(ident.trafo && e->IsMappedShape(*e_other, *ident.trafo, tol)) e->identifications.Append( {e, e_other, ident.trafo, ident.type, ident.name} ); for(auto & e : edges) for(auto & ident: e->identifications) { auto & from = static_cast(*ident.from); auto & to = static_cast(*ident.to); GeometryVertex * pfrom[] = { &from.GetStartVertex(), &from.GetEndVertex() }; GeometryVertex * pto[] = { &to.GetStartVertex(), &to.GetEndVertex() }; if(!ident.trafo) continue; // swap points of other edge if necessary Point<3> p_from0 = (*ident.trafo)(from.GetStartVertex().GetPoint()); Point<3> p_from1 = (*ident.trafo)(from.GetEndVertex().GetPoint()); Point<3> p_to0 = to.GetStartVertex().GetPoint(); if(Dist(p_from1, p_to0) < Dist(p_from0, p_to0)) swap(pto[0], pto[1]); for(auto i : Range(2)) pfrom[i]->identifications.Append( {pfrom[i], pto[i], ident.trafo, ident.type, ident.name} ); } mirror_identifications(vertices); mirror_identifications(edges); mirror_identifications(faces); auto find_primary = [&] (auto & shapes) { for(auto &s : shapes) s->primary = s.get(); bool changed = true; while(changed) { changed = false; for(auto &s : shapes) { for(auto & ident : s->identifications) { bool need_inverse = ident.from == s.get(); auto other = need_inverse ? ident.to : ident.from; if(other->primary->nr < s->primary->nr) { s->primary = other->primary; if(ident.trafo) { auto trafo = *ident.trafo; if(need_inverse) trafo = trafo.CalcInverse(); if(!s->primary_to_me) s->primary_to_me = Transformation<3>( Vec<3>{0., 0., 0.} ); if(!other->primary_to_me) other->primary_to_me = Transformation<3>( Vec<3>{0., 0., 0.} ); s->primary_to_me->Combine(trafo, *other->primary_to_me); changed = true; } } } } } }; find_primary(vertices); find_primary(edges); find_primary(faces); } void NetgenGeometry :: Analyse(Mesh& mesh, const MeshingParameters& mparam) const { static Timer t1("SetLocalMeshsize"); RegionTimer regt(t1); mesh.SetGlobalH(mparam.maxh); mesh.SetMinimalH(mparam.minh); mesh.SetLocalH(bounding_box.PMin(), bounding_box.PMax(), mparam.grading); // only set meshsize for edges longer than this double mincurvelength = 1e-3 * bounding_box.Diam(); if(mparam.uselocalh) { double eps = 1e-10 * bounding_box.Diam(); const char* savetask = multithread.task; multithread.task = "Analyse Edges"; // restrict meshsize on edges for(auto i : Range(edges)) { multithread.percent = 100. * i/edges.Size(); const auto & edge = edges[i]; auto length = edge->GetLength(); // skip very short edges if(length < mincurvelength) continue; static constexpr int npts = 20; // restrict mesh size based on edge length for(auto i : Range(npts+1)) mesh.RestrictLocalH(edge->GetPoint(double(i)/npts), length/mparam.segmentsperedge); // restrict mesh size based on edge curvature double t = 0.; auto p_old = edge->GetPoint(t); while(t < 1.-eps) { t += edge->CalcStep(t, 1./mparam.curvaturesafety); if(t < 1.) { auto p = edge->GetPoint(t); auto dist = (p-p_old).Length(); mesh.RestrictLocalH(p, dist); p_old = p; } } } multithread.task = "Analyse Faces"; // restrict meshsize on faces for(auto i : Range(faces)) { multithread.percent = 100. * i/faces.Size(); const auto& face = faces[i]; face->RestrictH(mesh, mparam); } if(mparam.closeedgefac.has_value()) { multithread.task = "Analyse close edges"; constexpr int sections = 100; Array lines; lines.SetAllocSize(sections*edges.Size()); BoxTree<3> searchtree(bounding_box.PMin(), bounding_box.PMax()); for(const auto& edge : edges) { if(edge->GetLength() < eps) continue; double t = 0.; auto p_old = edge->GetPoint(t); auto t_old = edge->GetTangent(t); t_old.Normalize(); for(auto i : IntRange(1, sections+1)) { t = double(i)/sections; auto p_new = edge->GetPoint(t); auto t_new = edge->GetTangent(t); t_new.Normalize(); auto cosalpha = fabs(t_old * t_new); if((i == sections) || (cosalpha < cos(10./180 * M_PI))) { auto index = lines.Append({p_old, p_new}); searchtree.Insert(p_old, p_new, index); p_old = p_new; t_old = t_new; } } } Array linenums; for(auto i : Range(lines)) { const auto& line = lines[i]; if(line.Length() < eps) continue; multithread.percent = 100.*i/lines.Size(); Box<3> box; box.Set(line.p0); box.Add(line.p1); // box.Increase(max2(mesh.GetH(line.p0), mesh.GetH(line.p1))); box.Increase(line.Length()); double mindist = 1e99; linenums.SetSize0(); searchtree.GetIntersecting(box.PMin(), box.PMax(), linenums); for(auto num : linenums) { if(i == num) continue; const auto & other = lines[num]; if((line.p0 - other.p0).Length2() < eps || (line.p0 - other.p1).Length2() < eps || (line.p1 - other.p0).Length2() < eps || (line.p1 - other.p1).Length2() < eps) continue; mindist = min2(mindist, line.Dist(other)); } if(mindist == 1e99) continue; mindist /= *mparam.closeedgefac + 1e-10; if(mindist < 1e-3 * bounding_box.Diam()) { (*testout) << "extremely small local h: " << mindist << " --> setting to " << 1e-3 * bounding_box.Diam() << endl; (*testout) << "somewhere near " << line.p0 << " - " << line.p1 << endl ; mindist = 1e-3 * bounding_box.Diam(); } mesh.RestrictLocalHLine(line.p0, line.p1, mindist); } } multithread.task = savetask; } for(const auto& mspnt : mparam.meshsize_points) mesh.RestrictLocalH(mspnt.pnt, mspnt.h, mspnt.layer); mesh.LoadLocalMeshSize(mparam.meshsizefilename); } void GeometryEdge :: Divide(const MeshingParameters & mparam, const Mesh & mesh, Array> & points, Array & params) { static Timer tdivedgesections("Divide edge sections"); static Timer tdivide("Divide Edges"); RegionTimer rt(tdivide); // -------------------- DivideEdge ----------------- if(properties.partition) { points.SetSize(properties.partition->Size()); params.SetSize(properties.partition->Size()+2); params[0] = 0.0; params.Last() = 1.0; for(auto i : Range(properties.partition->Size())) { params[i+1] = (*properties.partition)[i]; points[i] = GetPoint(params[i+1]); } return; } tdivedgesections.Start(); auto layer = properties.layer; double safety = 0.5*(1.-mparam.grading); double lam = 0.0; Point<3> p = GetPoint(0.0); auto old_p = p; Array hvalue, fine_params; hvalue.Append(.0); while (lam<1. && hvalue.Size() < 20000) { fine_params.Append(lam); auto h = mesh.GetH(old_p, layer); auto step = safety * h/GetTangent(lam).Length(); lam += step; lam = min2(lam, 1.0); p = GetPoint(lam); hvalue.Append((hvalue.Size()==0 ? 0.0 : hvalue.Last()) + 1./h * (p-old_p).Length()); old_p = p; } fine_params.Append(1.0); if(hvalue.Size()==20000 && lam<1.0) cout << "Warning: Could not divide Edge" << endl; tdivedgesections.Stop(); // auto n = hvalue.Size()-1; int nsubedges = max2(1, int(floor(hvalue.Last()+0.5))); points.SetSize(nsubedges-1); params.SetSize(nsubedges+1); int i1 = 0; for(auto i : Range(1,nsubedges)) { auto h_target = i*hvalue.Last()/nsubedges; while(hvalue[i1] vert2meshpt(vertices.Size()); vert2meshpt = PointIndex::INVALID; for(auto & vert : vertices) { auto pi = mesh.AddPoint(vert->GetPoint(), vert->properties.layer); vert2meshpt[vert->nr] = pi; mesh[pi].Singularity(vert->properties.hpref); mesh[pi].SetType(FIXEDPOINT); Element0d el(pi, pi-IndexBASE()+1); el.name = vert->properties.GetName(); mesh.SetCD3Name(pi-IndexBASE()+1, el.name); mesh.pointelements.Append (el); } for(auto & vert : vertices) for(auto & ident : vert->identifications) identifications.Add(vert2meshpt[ident.from->nr], vert2meshpt[ident.to->nr], ident.name, ident.type); // size_t segnr = 0; auto nedges = edges.Size(); Array> all_pnums(nedges); Array> all_params(nedges); for (auto edgenr : Range(edges)) { auto edge = edges[edgenr].get(); PointIndex startp, endp; // throws if points are not found startp = vert2meshpt[edge->GetStartVertex().nr]; endp = vert2meshpt[edge->GetEndVertex().nr]; // ignore collapsed edges if(edge->IsDegenerated()) continue; // ----------- Add Points to mesh and create segments ----- auto & pnums = all_pnums[edgenr]; auto & params = all_params[edgenr]; Array> edge_points; Array edge_params; if(edge->primary == edge) { // check if start and end vertex are identified (if so, we only insert one segment and do z-refinement later) bool is_identified_edge = false; auto v0 = vertices[edge->GetStartVertex().nr].get(); auto v1 = vertices[edge->GetEndVertex().nr].get(); for(auto & ident : v0->identifications) { auto other = ident.from == v0 ? ident.to : ident.from; if(other->nr == v1->nr && ident.type == Identifications::CLOSESURFACES) { is_identified_edge = true; break; } } if(is_identified_edge) { params.SetSize(2); params[0] = 0.; params[1] = 1.; } else { edge->Divide(mparam, mesh, edge_points, params); } } else { auto nr_primary = edge->primary->nr; auto & pnums_primary = all_pnums[nr_primary]; // auto & params_primary = all_params[nr_primary]; auto trafo = edge->primary_to_me; auto np = pnums_primary.Size(); edge_points.SetSize(np-2); edge_params.SetSize(np-2); for(auto i : Range(np-2)) { edge_points[i] = mesh[pnums_primary[i+1]]; if(trafo) edge_points[i] = (*trafo)(edge_points[i]); EdgePointGeomInfo gi; edge->ProjectPoint(edge_points[i], &gi); edge_params[i] = gi.dist; } params.SetSize(edge_params.Size()+2); for(auto i : Range(edge_params)) params[i+1] = edge_params[i]; if(edge_params.Size()>1) { // Just projecting (code below) does not work for closed edges (startp == endp) // In this case, there are at least 2 inner points which we use to check edge orientation bool reversed = edge_params[1] < edge_params[0]; if(reversed) { params[0] = 1.0; params.Last() = 0.0; } else { params.Last() = 1.0; params[0] = 0.0; } } else { for(size_t i : std::vector{0UL, pnums_primary.Size()-1}) { auto p_mapped = mesh[pnums_primary[i]]; if(trafo) p_mapped = (*trafo)(p_mapped); EdgePointGeomInfo gi; edge->ProjectPoint(p_mapped, &gi); params[i] = gi.dist; } } } pnums.SetSize(edge_points.Size() + 2); bool is_reversed = params.Last() < params[0]; pnums[0] = is_reversed ? endp : startp; pnums.Last() = is_reversed ? startp : endp; for(auto i : Range(edge_points)) { auto pi = mesh.AddPoint(edge_points[i], edge->properties.layer); if(edge->identifications.Size()) tree.Insert(mesh[pi], pi, edge->nr); pnums[i+1] = pi; } for(auto i : Range(pnums.Size()-1)) { // segnr++; Segment seg; seg[0] = pnums[i]; seg[1] = pnums[i+1]; seg.edgenr = edgenr+1; seg.index = edgenr+1; seg.si = edgenr+1; seg.epgeominfo[0].dist = params[i]; seg.epgeominfo[1].dist = params[i+1]; seg.epgeominfo[0].edgenr = edgenr; seg.epgeominfo[1].edgenr = edgenr; seg.singedge_left = edge->properties.hpref; seg.singedge_right = edge->properties.hpref; seg.domin = edge->domin+1; seg.domout = edge->domout+1; mesh.AddSegment(seg); } mesh.SetCD2Name(edgenr+1, edge->properties.GetName()); } for (auto & edge : edges) { // identify points on edge for(auto & ident : edge->identifications) if(ident.from == edge.get()) { auto & pnums = all_pnums[edge->nr]; if(pnums.Size() < 2) continue; // degenerated edge // start and end vertex are already identified for(auto pi : pnums.Range(1, pnums.Size()-1)) { Point<3> p_other = mesh[pi]; if(ident.trafo) p_other = (*ident.trafo)(mesh[pi]); else static_cast(ident.to)->ProjectPoint(p_other, nullptr); auto pi_other = tree.Find(p_other, ident.to->nr); identifications.Add(pi, pi_other, ident.name, ident.type); } } } mesh.CalcSurfacesOfNode(); multithread.task = savetask; } bool NetgenGeometry :: MeshFace(Mesh& mesh, const MeshingParameters& mparam, int k, FlatArray glob2loc) const { multithread.percent = 100. * k/faces.Size(); const auto& face = *faces[k]; auto bb = face.GetBoundingBox(); bb.Increase(bb.Diam()/10); Meshing2 meshing(*this, mparam, bb); glob2loc = 0; int cntp = 0; auto segments = face.GetBoundary(mesh); for(auto& seg : segments) { for(auto j : Range(2)) { auto pi = seg[j]; if(glob2loc[pi] == 0) { meshing.AddPoint(mesh[pi], pi); cntp++; glob2loc[pi] = cntp; } } } for(const auto& vert : GetFaceVertices(face)) { PointIndex pi = vert->nr + 1; if(glob2loc[pi] == 0) { auto gi = face.Project(mesh[pi]); MultiPointGeomInfo mgi; mgi.AddPointGeomInfo(gi); meshing.AddPoint(mesh[pi], pi, &mgi); cntp++; glob2loc[pi] = cntp; } } for(auto & seg : segments) { PointGeomInfo gi0, gi1; gi0.trignum = gi1.trignum = k+1; 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[seg[0]], glob2loc[seg[1]], gi0, gi1); } // TODO Set max area 2* area of face auto noldsurfels = mesh.GetNSE(); static Timer t("GenerateMesh"); RegionTimer reg(t); MESHING2_RESULT res = meshing.GenerateMesh(mesh, mparam, mparam.maxh, k+1, face.properties.layer); for(auto i : Range(noldsurfels, mesh.GetNSE())) { mesh.SurfaceElements()[i].SetIndex(k+1); } return res != MESHING2_OK; } void NetgenGeometry :: MeshSurface(Mesh& mesh, const MeshingParameters& mparam) const { static Timer t1("Surface Meshing"); RegionTimer regt(t1); const char* savetask = multithread.task; multithread.task = "Mesh Surface"; mesh.ClearFaceDescriptors(); size_t n_failed_faces = 0; Array glob2loc(mesh.GetNP()); for(auto k : Range(faces)) { auto & face = *faces[k]; FaceDescriptor fd(k+1, face.domin+1, face.domout+1, k+1); if(face.properties.col) fd.SetSurfColour(*face.properties.col); mesh.AddFaceDescriptor(fd); mesh.SetBCName(k, face.properties.GetName()); if(face.primary == &face) { // check if this face connects two identified closesurfaces // auto & idents = mesh.GetIdentifications(); std::set relevant_edges; auto segments = face.GetBoundary(mesh); for(const auto &s : segments) relevant_edges.insert(s.edgenr-1); Array is_point_in_tree(mesh.Points().Size()); is_point_in_tree = false; PointTree tree( bounding_box ); for(const auto &s : segments) for(auto pi : s.PNums()) if(!is_point_in_tree[pi]) { tree.Insert(mesh[pi], pi, -1); is_point_in_tree[pi] = true; } Array mapped_edges(edges.Size()); constexpr int UNINITIALIZED = -2; constexpr int NOT_MAPPED = -1; mapped_edges = UNINITIALIZED; optional> trafo; if(face.IsConnectingCloseSurfaces()) { Array, PointIndex> p2seg(mesh.Points().Size()); for(int si : Range(segments)) { const auto & s = segments[si]; p2seg[s[0]].Append(si); p2seg[s[1]].Append(si); } for(const auto & s : segments) { auto edgenr = s.edgenr-1; auto & edge = *edges[edgenr]; // ShapeIdentification *edge_mapping; // have edgenr first time, search for closesurface identification if(mapped_edges[edgenr] == UNINITIALIZED) { mapped_edges[edgenr] = NOT_MAPPED; for(auto & edge_ident : edge.identifications) { if(edge_ident.type == Identifications::CLOSESURFACES && edge_ident.from->nr == edgenr && relevant_edges.count(edge_ident.to->nr) > 0 ) { trafo = edge_ident.trafo; mapped_edges[edgenr] = edge_ident.to->nr; break; } } } // this edge has a closesurface mapping to another -> make connecting quad if(mapped_edges[edgenr] != NOT_MAPPED) { Element2d sel(4); sel[0] = s[0]; sel[1] = s[1]; auto gis = sel.GeomInfo(); for(auto i : Range(2)) { gis[i].u = s.epgeominfo[i].u; gis[i].v = s.epgeominfo[i].v; } Point<3> p2 = mesh[s[1]]; Point<3> p3 = mesh[s[0]]; if(trafo) { p2 = (*trafo)(p2); p3 = (*trafo)(p3); } else { edges[mapped_edges[edgenr]]->ProjectPoint(p2, nullptr); edges[mapped_edges[edgenr]]->ProjectPoint(p3, nullptr); } sel[2] = tree.Find(p2, -1); sel[3] = tree.Find(p3, -1); // find mapped segment to set PointGeomInfo correctly Segment s_other; for(auto si_other : p2seg[sel[2]]) { s_other = segments[si_other]; if(s_other[0] == sel[2] && s_other[1] == sel[3]) break; if(s_other[0] == sel[3] && s_other[1] == sel[2]) break; } for(auto i : Range(2)) { auto i_other = sel[i+2] == s_other[i] ? i : 1-i; gis[i+2].u = s_other.epgeominfo[i_other].u; gis[i+2].v = s_other.epgeominfo[i_other].v; } sel.SetIndex(face.nr+1); mesh.AddSurfaceElement(sel); } } } else if(MeshFace(mesh, mparam, k, glob2loc)) n_failed_faces++; } } if(n_failed_faces) { cout << "WARNING! NOT ALL FACES HAVE BEEN MESHED" << endl; cout << "SURFACE MESHING ERROR OCCURRED IN " << n_failed_faces << " FACES:" << endl; return; } if (mparam.perfstepsend >= MESHCONST_OPTSURFACE) { mesh.CalcSurfacesOfNode(); OptimizeSurface(mesh, mparam); } bool have_identifications = false; std::map, PointIndex> mapto; for(auto & face : faces) if(face->primary != face.get()) { have_identifications = true; MapSurfaceMesh(mesh, *face, mapto); } // identify points on faces if(have_identifications) { mesh.CalcSurfacesOfNode(); BitArray is_identified_face(faces.Size()); is_identified_face = false; for(auto & face : faces) for(auto & ident : face->identifications) { is_identified_face.SetBit(ident.from->nr); is_identified_face.SetBit(ident.to->nr); } PointTree tree( bounding_box ); Array pi_to_face(mesh.GetNP()); pi_to_face = -1; Array si_of_face; Array> pi_of_face(faces.Size()); for(auto & face : faces) if(is_identified_face[face->nr]) { mesh.GetSurfaceElementsOfFace(face->nr+1, si_of_face); for(auto si : si_of_face) for(auto pi : mesh[si].PNums()) { if(mesh[pi].Type() == SURFACEPOINT && pi_to_face[pi]==-1) { pi_to_face[pi] = face->nr; tree.Insert(mesh[pi], pi, -1); pi_of_face[face->nr].Append(pi); } } } auto & mesh_ident = mesh.GetIdentifications(); for(auto & face : faces) for(auto & ident : face->identifications) { if(ident.from == face.get()) for(auto pi : pi_of_face[face->nr]) { auto pi_primary = ident.from->primary->nr == ident.from->nr ? pi : mapto[{pi, ident.to->primary->nr}]; auto pi_other = ident.to->primary->nr == ident.to->nr ? pi_primary : mapto[{pi_primary, ident.to->nr}]; mesh_ident.Add(pi, pi_other, ident.name, ident.type); } } } mesh.CalcSurfacesOfNode(); multithread.task = savetask; } void NetgenGeometry :: MapSurfaceMesh( Mesh & mesh, const GeometryFace & dst, std::map, PointIndex> & mapto ) const { static Timer timer("MapSurfaceMesh"); RegionTimer rt(timer); const auto & src = dynamic_cast(*dst.primary); auto trafo = dst.primary_to_me; PrintMessage(2, "Map face ", src.nr+1, " -> ", dst.nr+1); // point map from src to dst auto np = mesh.Points().Size(); Array pmap(np); pmap = PointIndex::INVALID; BitArray is_double_edge_point(np); is_double_edge_point.Clear(); // first map points on edges (mapped points already in mesh, use search tree) Array is_point_in_tree(mesh.Points().Size()); is_point_in_tree = false; PointTree tree( bounding_box ); for (Segment & seg : src.GetBoundary(mesh)) for(auto i : Range(2)) { auto pi = seg[i]; if(!is_point_in_tree[pi]) { auto p = mesh[pi]; if(trafo) p = (*trafo)(p); else for(auto& edge: dst.edges) if (edge->primary->nr == seg.edgenr-1) { if (mesh[pi].Type() == FIXEDPOINT) { if((edge->GetStartVertex().GetPoint() - p).Length2() >\ (edge->GetEndVertex().GetPoint() - p).Length2()) p = edge->GetEndVertex().GetPoint(); else p = edge->GetStartVertex().GetPoint(); } else edge->ProjectPoint(p, nullptr); } tree.Insert(p, pi, -1); is_point_in_tree[pi] = true; } } Array, 2>, PointIndex> uv_values(np); for (Segment & seg : dst.GetBoundary(mesh)) { for(auto i : Range(2)) { auto pi = seg[i]; if(!pmap[pi].IsValid()) pmap[tree.Find(mesh[pi], -1)] = pi; // store uv values (might be different values for same point in case of internal edges) double u = seg.epgeominfo[i].u; double v = seg.epgeominfo[i].v; auto & vals = uv_values[pi]; bool found = false; for(const auto & [u1,v1] : vals) if((u-u1)*(u-u1)+(v-v1)*(v-v1) < 1e-7) found = true; if(!found) vals.Append({u,v}); } } xbool do_invert = maybe; if(!trafo) do_invert = true; // now insert mapped surface elements for(auto sei : mesh.SurfaceElements().Range()) { auto sel = mesh[sei]; if(sel.GetIndex() != src.nr+1) continue; auto sel_new = sel; sel_new.SetIndex(dst.nr+1); for(auto i : Range(sel.PNums())) { auto pi = sel[i]; if(!pmap[pi].IsValid()) { auto p = mesh[pi]; if(trafo) p = (*trafo)(p); else dst.Project(p); pmap[pi] = mesh.AddPoint(p, 1, SURFACEPOINT); } sel_new[i] = pmap[pi]; mapto[{pi, dst.nr}] = pmap[pi]; mapto[{pmap[pi], src.nr}] = pi; } if(do_invert.IsMaybe()) { auto n_src = src.GetNormal(mesh[sel[0]]); auto n_dist = dst.GetNormal(mesh[sel_new[0]]); Mat<3> normal_matrix; CalcInverse(Trans(trafo->GetMatrix()), normal_matrix); do_invert = (normal_matrix * n_src) * n_dist < 0.0; } if(do_invert.IsTrue()) sel_new.Invert(); for(auto i : Range(sel.PNums())) { auto pi = sel_new[i]; if(uv_values.Range().Next() <= pi) { // new point (inner surface point) PointGeomInfo gi; dst.CalcPointGeomInfo(mesh[sel_new[i]], gi); sel_new.GeomInfo()[i] = gi; continue; } const auto & uvs = uv_values[pi]; if(uvs.Size() == 1) { // appears only once -> take uv values from edgepointgeominfo const auto & [u,v] = uvs[0]; PointGeomInfo gi; gi.u = u; gi.v = v; sel_new.GeomInfo()[i] = gi; } else if(uvs.Size() > 1) { // multiple uv pairs -> project to close point and select closest uv pair double eps = 1e-3; auto p = Point<3>((1.0-eps)*Vec<3>(mesh[sel_new.PNumMod(i+1)]) + eps/2*Vec<3>(mesh[sel_new.PNumMod(i+2)]) + eps/2*Vec<3>(mesh[sel_new.PNumMod(i+3)])); PointGeomInfo gi_p, gi; dst.CalcPointGeomInfo(p, gi_p); gi.trignum = gi_p.trignum; double min_dist = numeric_limits::max(); for(const auto & [u,v] : uvs) { double dist = (gi_p.u-u)*(gi_p.u-u) + (gi_p.v-v)*(gi_p.v-v); if(dist < min_dist) { min_dist = dist; gi.u = u; gi.v = v; } } sel_new.GeomInfo()[i] = gi; } else throw Exception(string(__FILE__) + ":"+ToString(__LINE__) + " shouldn't come here"); } mesh.AddSurfaceElement(sel_new); } } void NetgenGeometry :: OptimizeSurface(Mesh& mesh, const MeshingParameters& mparam) const { const auto savetask = multithread.task; multithread.task = "Optimizing surface"; static Timer timer_opt2d("Optimization 2D"); RegionTimer reg(timer_opt2d); auto meshopt = MeshOptimize2d(mesh); for(auto i : Range(mparam.optsteps2d)) for(auto k : Range(mesh.GetNFD())) { PrintMessage(3, "Optimization step ", i); meshopt.SetFaceIndex(k+1); meshopt.SetMetricWeight (mparam.elsizeweight); int innerstep = 0; for(auto optstep : mparam.optimize2d) { multithread.percent = 100. * (double(innerstep++)/mparam.optimize2d.size() + i)/mparam.optsteps2d; switch(optstep) { case 's': meshopt.EdgeSwapping(0); break; case 'S': meshopt.EdgeSwapping(1); break; case 'm': meshopt.ImproveMesh(mparam); break; case 'c': meshopt.CombineImprove(); break; } } } mesh.CalcSurfacesOfNode(); mesh.Compress(); multithread.task = savetask; } void NetgenGeometry :: FinalizeMesh(Mesh& mesh) const { for (int i = 0; i < std::min(solids.Size(), (size_t)mesh.GetNDomains()); i++) if (auto name = solids[i]->properties.name) mesh.SetMaterial (i+1, *name); mesh.OrderElements(); } shared_ptr GeometryRegisterArray :: LoadFromMeshFile (istream & ist) const { if (!ist.good()) return nullptr; string token; ist >> token; if(token == "TextOutArchive") { NetgenGeometry *geo = nullptr; size_t string_length; ist >> string_length; string buffer(string_length+1, '\0'); ist.read(&buffer[0], string_length); auto ss = make_shared(buffer); TextInArchive in(ss); in & geo; return shared_ptr(geo); } for (int i = 0; i < Size(); i++) { NetgenGeometry * hgeom = (*this)[i]->LoadFromMeshFile (ist, token); if (hgeom) return shared_ptr(hgeom); } return nullptr; } int NetgenGeometry :: GenerateMesh (shared_ptr & mesh, MeshingParameters & mp) { multithread.percent = 0; // copy so that we don't change them outside MeshingParameters mparam = mp; if(restricted_h.Size()) for(const auto& [pnt, maxh] : restricted_h) mparam.meshsize_points.Append({pnt, maxh}); if(mparam.perfstepsstart <= MESHCONST_ANALYSE) { if(!mesh) mesh = make_shared(); mesh->geomtype = GetGeomType(); Analyse(*mesh, mparam); } if(multithread.terminate || mparam.perfstepsend <= MESHCONST_ANALYSE) return 0; if(mparam.perfstepsstart <= MESHCONST_MESHEDGES) FindEdges(*mesh, mparam); if(multithread.terminate || mparam.perfstepsend <= MESHCONST_MESHEDGES) return 0; if(dimension == 1) { FinalizeMesh(*mesh); mesh->SetDimension(1); return 0; } if (mparam.perfstepsstart <= MESHCONST_MESHSURFACE) { MeshSurface(*mesh, mparam); } if (multithread.terminate || mparam.perfstepsend <= MESHCONST_OPTSURFACE) return 0; if(dimension == 2) { FinalizeMesh(*mesh); mesh->SetDimension(2); return 0; } if(mparam.perfstepsstart <= MESHCONST_MESHVOLUME) { multithread.task = "Volume meshing"; MESHING3_RESULT res = MeshVolume (mparam, *mesh); if (res != MESHING3_OK) return 1; if (multithread.terminate) return 0; MeshQuality3d (*mesh); } if (multithread.terminate || mparam.perfstepsend <= MESHCONST_MESHVOLUME) return 0; if (mparam.perfstepsstart <= MESHCONST_OPTVOLUME) { multithread.task = "Volume optimization"; OptimizeVolume (mparam, *mesh); if (multithread.terminate) return 0; } FinalizeMesh(*mesh); return 0; } void NetgenGeometry :: Save (const filesystem::path & filename) const { throw NgException("Cannot save geometry - no geometry available"); } static RegisterClassForArchive regnggeo; } ================================================ FILE: libsrc/meshing/basegeom.hpp ================================================ #ifndef FILE_BASEGEOM #define FILE_BASEGEOM /**************************************************************************/ /* File: basegeom.hpp */ /* Author: Joachim Schoeberl */ /* Date: 23. Aug. 09 */ /**************************************************************************/ #include #include #include "meshtype.hpp" #include "meshclass.hpp" struct Tcl_Interp; namespace netgen { class Refinement; struct ShapeProperties { optional name; optional> col; double maxh = 1e99; double hpref = 0; // number of hp refinement levels (will be multiplied by factor later) int layer = 1; optional quad_dominated; optional> partition; void Merge(const ShapeProperties & prop2) { if (!name && prop2.name) name = prop2.name; if (!col && prop2.col) col = prop2.col; if (!partition && prop2.partition) partition = prop2.partition; maxh = min2(maxh, prop2.maxh); hpref = max2(hpref, prop2.hpref); if(!quad_dominated.has_value()) quad_dominated = prop2.quad_dominated; layer = max(layer, prop2.layer); } string GetName() const { return name ? *name : "default"; } Vec<4> GetColor() { return col ? *col : Vec<4>{0., 1., 0., 1.}; } void DoArchive(Archive& ar); }; class GeometryShape; struct ShapeIdentification { GeometryShape * from; GeometryShape * to; optional> trafo; Identifications::ID_TYPE type; string name = ""; }; class DLL_HEADER GeometryShape { public: int nr = -1; int layer = 1; ShapeProperties properties; Array identifications; GeometryShape * primary; optional> primary_to_me = nullopt; virtual ~GeometryShape() {} virtual bool IsMappedShape( const GeometryShape & other, const Transformation<3> & trafo, double tolerance ) const; }; class DLL_HEADER GeometryVertex : public GeometryShape { public: virtual Point<3> GetPoint() const = 0; virtual bool IsMappedShape( const GeometryShape & other, const Transformation<3> & trafo, double tolerance ) const override; }; class DLL_HEADER GeometryEdge : public GeometryShape { protected: GeometryVertex *start, *end; public: // Neighboring domains in 2d // In 3d unused, EXCEPT for free floating edges in a domain, // then both are pointing to the containing domain int domin=-1, domout=-1; GeometryEdge( GeometryVertex &start_, GeometryVertex &end_ ) : start(&start_), end(&end_) {} virtual const GeometryVertex& GetStartVertex() const { return *start; } virtual const GeometryVertex& GetEndVertex() const { return *end; } virtual GeometryVertex& GetStartVertex() { return *start; } virtual GeometryVertex& GetEndVertex() { return *end; } virtual double GetLength() const = 0; virtual Point<3> GetCenter() const = 0; virtual Point<3> GetPoint(double t) const = 0; // Calculate parameter step respecting edges sag value virtual double CalcStep(double t, double sag) const = 0; virtual bool IsDegenerated(double tol = 1e-10) const { return GetLength() < tol; } virtual void ProjectPoint(Point<3>& p, EdgePointGeomInfo* gi) const = 0; virtual void PointBetween(const Point<3>& p1, const Point<3>& p2, double secpoint, const EdgePointGeomInfo& gi1, const EdgePointGeomInfo& gi2, Point<3>& newp, EdgePointGeomInfo& newgi) const { newp = p1 + secpoint * (p2-p1); newgi = gi1; ProjectPoint(newp, &newgi); } virtual Vec<3> GetTangent(double t) const = 0; virtual bool IsMappedShape( const GeometryShape & other, const Transformation<3> & trafo, double tolerance ) const override; virtual void Divide(const MeshingParameters & mparam, const Mesh & mesh, Array> & points, Array & params); }; class DLL_HEADER GeometryFace : public GeometryShape { public: Array edges; int domin=-1, domout=-1; virtual Point<3> GetCenter() const = 0; virtual size_t GetNBoundaries() const = 0; virtual Array GetBoundary(const Mesh& mesh) const = 0; virtual PointGeomInfo Project(Point<3>& p) const = 0; // Project point using geo info. Fast if point is close to // parametrization in geo info. virtual bool ProjectPointGI(Point<3>& p, PointGeomInfo& gi) const =0; virtual bool CalcPointGeomInfo(const Point<3>& p, PointGeomInfo& gi) const { auto pnew = p; gi = Project(pnew); return (p-pnew).Length() < 1e-10 * GetBoundingBox().Diam() ; } virtual Point<3> GetPoint(const PointGeomInfo& gi) const = 0; virtual void CalcEdgePointGI(const GeometryEdge& edge, double t, EdgePointGeomInfo& egi) const = 0; virtual Box<3> GetBoundingBox() const = 0; // Get curvature in point from local coordinates in PointGeomInfo virtual double GetCurvature(const PointGeomInfo& gi) const = 0; virtual void RestrictH(Mesh& mesh, const MeshingParameters& mparam) const = 0; virtual Vec<3> GetNormal(const Point<3>& p, const PointGeomInfo* gi = nullptr) const = 0; virtual void PointBetween(const Point<3>& p1, const Point<3>& p2, double secpoint, const PointGeomInfo& gi1, const PointGeomInfo& gi2, Point<3>& newp, PointGeomInfo& newgi) const { newp = p1 + secpoint * (p2-p1); newgi.trignum = gi1.trignum; /* newgi.u = 0.5 * (gi1.u + gi1.u); newgi.v = 0.5 * (gi1.v + gi2.v); */ newgi.u = gi1.u + secpoint*(gi2.u - gi1.u); newgi.v = gi1.v + secpoint*(gi2.v - gi1.v); if(!ProjectPointGI(newp, newgi)) newgi = Project(newp); } virtual bool IsMappedShape( const GeometryShape & other, const Transformation<3> & trafo, double tolerance ) const override; virtual bool IsConnectingCloseSurfaces() const; protected: void RestrictHTrig(Mesh& mesh, const PointGeomInfo& gi0, const PointGeomInfo& gi1, const PointGeomInfo& gi2, const MeshingParameters& mparam, int depth = 0, double h = 0.) const; }; class DLL_HEADER GeometrySolid : public GeometryShape { public: Array free_edges; // edges with no adjacent face }; class DLL_HEADER NetgenGeometry { unique_ptr ref; protected: Array> vertices; Array> edges; Array> faces; Array> solids; Array, double>> restricted_h; Box<3> bounding_box; int dimension = 3; public: NetgenGeometry() { ref = make_unique(*this); } virtual ~NetgenGeometry () { ; } size_t GetNVertices() const { return vertices.Size(); } size_t GetNEdges() const { return edges.Size(); } size_t GetNFaces() const { return faces.Size(); } size_t GetNSolids() const { return solids.Size(); } const GeometrySolid & GetSolid(int i) const { return *solids[i]; } const GeometryFace & GetFace(int i) const { return *faces[i]; } const GeometryEdge & GetEdge(int i) const { return *edges[i]; } const GeometryVertex & GetVertex(int i) const { return *vertices[i]; } auto Solids() const { return FlatArray{solids}; } auto Faces() const { return FlatArray{faces}; } auto Edges() const { return FlatArray{edges}; } auto Vertices() const { return FlatArray{vertices}; } virtual Array GetFaceVertices(const GeometryFace& face) const { return Array{}; } void Clear(); virtual int GenerateMesh (shared_ptr & mesh, MeshingParameters & mparam); void RestrictH(const Point<3>& pnt, double maxh) { restricted_h.Append({pnt, maxh}); } virtual const Refinement & GetRefinement () const { return *ref; } virtual void DoArchive(Archive&) { throw NgException("DoArchive not implemented for " + Demangle(typeid(*this).name())); } virtual Mesh::GEOM_TYPE GetGeomType() const { return Mesh::NO_GEOM; } virtual void ProcessIdentifications(); virtual void Analyse(Mesh& mesh, const MeshingParameters& mparam) const; virtual void FindEdges(Mesh& mesh, const MeshingParameters& mparam) const; virtual void MeshSurface(Mesh& mesh, const MeshingParameters& mparam) const; virtual bool MeshFace(Mesh& mesh, const MeshingParameters& mparam, int nr, FlatArray glob2loc) const; virtual void MapSurfaceMesh( Mesh & mesh, const GeometryFace & dst, std::map, PointIndex> & mapto) const; virtual void OptimizeSurface(Mesh& mesh, const MeshingParameters& mparam) const; virtual void FinalizeMesh(Mesh& mesh) const; virtual PointGeomInfo ProjectPoint (int surfind, Point<3> & p) const { if(surfind <= faces.Size() && surfind > 0) return faces[surfind-1]->Project(p); return PointGeomInfo(); } virtual void ProjectPointEdge (int surfind, int surfind2, Point<3> & p, EdgePointGeomInfo* gi = nullptr) const { if(gi && gi->edgenr < edges.Size() && gi->edgenr >= 0) edges[gi->edgenr]->ProjectPoint(p, gi); } virtual bool CalcPointGeomInfo(int surfind, PointGeomInfo& gi, const Point<3> & p3) const { return faces[surfind-1]->CalcPointGeomInfo(p3, gi); } virtual bool ProjectPointGI (int surfind, Point<3> & p, PointGeomInfo & gi) const { if(surfind > 0 && surfind <= faces.Size()) return faces[surfind-1]->ProjectPointGI(p, gi); return false; } virtual Vec<3> GetNormal(int surfind, const Point<3> & p, const PointGeomInfo* gi = nullptr) const { if(surfind > 0 && surfind <= faces.Size()) return faces[surfind-1]->GetNormal(p, gi); else return {0., 0., 0.}; } 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 { if(faces.Size() >= surfi && surfi > 0) { faces[surfi-1]->PointBetween(p1, p2, secpoint, gi1, gi2, newp, newgi); return; } newp = p1 + secpoint * (p2-p1); } virtual void PointBetweenEdge(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 { if(ap1.edgenr < edges.Size() && ap1.edgenr >= 0) { edges[ap1.edgenr]->PointBetween(p1, p2, secpoint, ap1, ap2, newp, newgi); return; } newp = p1+secpoint*(p2-p1); newgi.edgenr = ap1.edgenr; newgi.dist = ap1.dist + secpoint*(ap2.dist-ap1.dist); } virtual Vec<3> GetTangent(const Point<3> & p, int surfi1, int surfi2, const EdgePointGeomInfo & egi) const { throw Exception("Base geometry get tangent called"); } virtual void Save (const filesystem::path & filename) const; virtual void SaveToMeshFile (ostream & /* ost */) const { ; } }; class DLL_HEADER GeometryRegister { public: virtual ~GeometryRegister(); virtual NetgenGeometry * Load (const filesystem::path & filename) const = 0; virtual NetgenGeometry * LoadFromMeshFile (istream & /* ist */, string) const { return NULL; } virtual class VisualScene * GetVisualScene (const NetgenGeometry * /* geom */) const { return NULL; } virtual void SetParameters (Tcl_Interp * /* interp */) { ; } }; class DLL_HEADER GeometryRegisterArray : public NgArray { public: virtual ~GeometryRegisterArray() { for (int i = 0; i < Size(); i++) delete (*this)[i]; } virtual shared_ptr LoadFromMeshFile (istream & ist) const; }; DLL_HEADER GeometryRegisterArray& GeometryRegister(); } #endif ================================================ FILE: libsrc/meshing/bcfunctions.cpp ================================================ #include #include #include "bcfunctions.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(Vec<4> col1, Vec<4> col2, double eps) { if(eps <= 0.0) eps = DEFAULT_EPS; bool colmatch = false; if((col1-col2).Length2() < 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, NgArray> & face_colours) { face_colours.SetSize(1); face_colours.Elem(1) = mesh.GetFaceDescriptor(1).SurfColour(); for(int i = 1; i <= mesh.GetNFD(); i++) { auto 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 NgArray> bc_colours(numentries); NgArray bc_num(numentries); NgArray 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)[0] >> bc_colours.Elem(i)[1] >> bc_colours.Elem(i)[2]; 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 for(auto i : Range(3)) bc_colours.Elem(bcnum)[i] = max2(min2(bc_colours.Elem(bcnum)[i], 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); NgArray> 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++) { // Get the colour of the face being currently processed auto face_colour = mesh.GetFaceDescriptor(face_index).SurfColour(); if(!ColourMatch(face_colour,Vec<4>(DEFAULT_R,DEFAULT_G,DEFAULT_B, 1.0))) { // 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 Vec<4> ref_colour(0.0,1.0,0.0,1.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 = ",Vec3d{ref_colour[0], ref_colour[1], ref_colour[2]},"","\n"); } else if(bc_used.Elem(bc_index)) { PrintMessage(3, "BC Property: ",bc_num.Elem(bc_index)); PrintMessage(3, " RGB Face Colour = ",Vec3d{ref_colour[0], ref_colour[1], ref_colour[2]},"","\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) { NgArray> all_colours; NgArray faces_sorted; NgArray 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),Vec<4>(DEFAULT_R,DEFAULT_G,DEFAULT_B,1.0))) { 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; // Index NgArray 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 se_face; mesh.GetSurfaceElementsOfFace(face_index, se_face); auto face_colour = mesh.GetFaceDescriptor(face_index).SurfColour(); if(!ColourMatch(face_colour,Vec<4>(DEFAULT_R,DEFAULT_G,DEFAULT_B,1.0))) { 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++) { auto face_colour = mesh.GetFaceDescriptor(face_index).SurfColour(); if(!ColourMatch(face_colour,Vec<4>(DEFAULT_R,DEFAULT_G,DEFAULT_B, 1.0))) { for(int i = 0; i < colours_sorted.Size(); i++) { Vec<4> 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 Vec<4> ref_colour(0.0,1.0,0.0,1.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 = ",Vec3d{ref_colour[0], ref_colour[1], ref_colour[2]},"","\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(); } } } } } ================================================ FILE: libsrc/meshing/bcfunctions.hpp ================================================ #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 index - 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 DLL_HEADER void AutoColourBcProps(Mesh & mesh, const char *bccolourfile); extern DLL_HEADER void GetFaceColours(Mesh & mesh, NgArray> & face_colours); extern DLL_HEADER bool ColourMatch(Vec<4> col1, Vec<4> col2, double eps = 2.5e-05); } #endif ================================================ FILE: libsrc/meshing/bisect.cpp ================================================ #include #include #include "meshclass.hpp" #include "bisect.hpp" #include "validate.hpp" #include "paralleltop.hpp" // #include "meshing.hpp" // quickfix for parallel #define noDEBUG namespace netgen { 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; int8_t newest_vertex; MarkedTet() = default; /* { for (int i = 0; i < 4; i++) { faceedges[i] = 127; } } */ MarkedTet (const MarkedTet&) = default; MarkedTet (MarkedTet &&) = default; MarkedTet & operator= (const MarkedTet&) = default; MarkedTet & operator= (MarkedTet&&) = default; }; 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) - or edge (in 2d) int np; /// 6 or 8 point numbers - or 4 in 2d 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: MarkedTri () = default; MarkedTri (const MarkedTri&) = default; MarkedTri (MarkedTri &&) = default; MarkedTri & operator= (const MarkedTri&) = default; MarkedTri & operator= (MarkedTri&&) = default; /// 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; int8_t newest_vertex; }; 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; } template int BTSortEdges (const Mesh & mesh, const NgArray & idmaps, HASHTABLE_EDGENUMBER & edgenumber) { PrintMessage(4,"sorting ... "); // if (mesh.PureTetMesh()) if (true) { // new, fast version Array> edges; // int i, j, k; int cntedges = 0; bool go_on; int ned(0); // enumerate edges: for (const Element & el : mesh.VolumeElements()) { 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 (int j = 0; j < ned; j++) { PointIndices<2> i2(el.PNum(tip[j][0]), el.PNum(tip[j][1])); i2.Sort(); if (!edgenumber.Used(i2)) { cntedges++; edges.Append (i2); edgenumber.Set(i2, cntedges); } } } // additional surface edges: for (const Element2d & el : mesh.SurfaceElements()) { 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 (int j = 0; j < ned; j++) { PointIndices<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); } } } NgArray eclasses(cntedges); for (int i = 1; i <= cntedges; i++) eclasses.Elem(i) = i; // identify edges in element stack do { go_on = false; for (auto ei : mesh.VolumeElements().Range()) { const Element & el = mesh[ei]; 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 (int j = 0; j < 3; j++) { PointIndices<2> e1 (el.PNum(pairs[j][0]), el.PNum(pairs[j][1])); PointIndices<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 = true; } else if (eclasses.Get(eclass2) > eclasses.Get(eclass1)) { eclasses.Elem(eclass2) = eclasses.Get(eclass1); go_on = true; } } } for (const Element2d & el2d : mesh.SurfaceElements()) { for(int i = 0; i < el2d.GetNP(); i++) { PointIndices<2> e1(el2d[i], el2d[(i+1) % el2d.GetNP()]); e1.Sort(); PointIndices<2> e2; for(int k = 0; k < idmaps.Size(); k++) { e2[0] = (*idmaps[k])[e1[0]]; e2[1] = (*idmaps[k])[e1[1]]; if(!e2.I1().IsValid() || !e2.I2().IsValid() || 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 = true; } else if (eclasses.Get(eclass2) > eclasses.Get(eclass1)) { eclasses.Elem(eclass2) = eclasses.Get(eclass1); go_on = true; } } } } } 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: NgArray edgelength(cntedges); /* for (i = 1; i <= cntedges; i++) edgelength.Elem(i) = 1e20; */ for (int i = 0; i < cntedges; i++) edgelength[i] = Dist (mesh[edges[i][0]], mesh[edges[i][1]]); /* 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 (int 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 eclasstab(cntedges); for (int i = 1; i <= cntedges; i++) eclasstab.Add1 (eclasses.Get(i), i-1); // sort edges: NgArray sorted(cntedges); QuickSort (edgelength, sorted); int cnt = 0; for (int i = 1; i <= cntedges; i++) { int ii = sorted.Get(i); for (int j = 1; j <= eclasstab.EntrySize(ii); j++) edgenumber.Set (edges[eclasstab.Get(ii, j)], ++cnt); } return cnt; } else { // old version // int i, j; int cnt = 0; bool found; double len2, maxlen2; INDEX_2 ep; // sort edges by length, parallel edges (on prisms) // are added in blocks do { found = false; maxlen2 = 1e30; // for (int i = 1; i <= mesh.GetNE(); i++) for (auto ei : mesh.VolumeElements().Range()) { const Element & el = mesh[ei]; // .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 (int j = 0; j < ned; j++) { PointIndices<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 = true; } } } } if (found) { cnt++; edgenumber.Set (ep, cnt); // find connected edges: bool go_on = false; do { go_on = false; //for (int i = 1; i <= mesh.GetNE(); i++) for (auto ei : mesh.VolumeElements().Range()) { const Element & el = mesh[ei]; // .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 (int j = 0; j < 3; j++) { PointIndices<2> e1 (el.PNum(pairs[j][0]), el.PNum(pairs[j][1])); PointIndices<2> e2 (el.PNum(pairs[j][2]), el.PNum(pairs[j][3])); e1.Sort(); e2.Sort(); bool used1 = edgenumber.Used (e1); bool used2 = edgenumber.Used (e2); if (used1 && !used2) { cnt++; edgenumber.Set (e2, cnt); go_on = true; } if (used2 && !used1) { cnt++; edgenumber.Set (e1, cnt); go_on = true; } } } } while (go_on); } } while (found); return cnt; } } template void BTDefineMarkedTet (const Element & el, T_EDGENUMBER & edgenumber, MarkedTet & mt) { for (int 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 (int i = 0; i < 3; i++) for (int j = i+1; j < 4; j++) { PointIndices<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 (int k = 0; k < 4; k++) { val = 0; for (int i = 0; i < 3; i++) for (int j = i+1; j < 4; j++) if (i != k && j != k) { /* PointIndices<2> i2(mt.pnums[i], mt.pnums[j]); i2.Sort(); int hval = edgenumber.Get(i2); */ int hval = edgenumber[ { mt.pnums[i], mt.pnums[j] } ]; if (hval > val) { val = hval; int hi = 6 - k - i - j; mt.faceedges[k] = char(hi); } } } } template void BTDefineMarkedPrism (const Element & el, T_EDGENUMBER & edgenumber, MarkedPrism & mp) { if (el.GetType() == PRISM || el.GetType() == PRISM12) { for (int 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 (int 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 (int 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 (int i = 0; i < 2; i++) for (int j = i+1; j < 3; j++) { PointIndices<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; } } } template bool BTDefineMarkedId(const Element2d & el, T_EDGENUMBER & edgenumber, const idmap_type & idmap, MarkedIdentification & mi) { bool identified = true; mi.np = el.GetNP(); // int min1(0),min2(0); PointIndex min1(PointIndex::INVALID), min2(PointIndex::INVALID); 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].IsValid() && 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++) { PointIndices<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; } template void BTDefineMarkedTri (const Element2d & el, T_EDGENUMBER & edgenumber, MarkedTri & mt) { for (int 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 = -1; for (int i = 0; i < 2; i++) for (int j = i+1; j < 3; j++) { /* PointIndices<2> i2(mt.pnums[i], mt.pnums[j]); i2.Sort(); int hval = edgenumber.Get(i2); */ int hval = edgenumber[ SortedPointIndices<2>(mt.pnums[i], mt.pnums[j]) ]; // int hval = edgenumber[ { mt.pnums[i], mt.pnums[j] }]; 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; } template void BTDefineMarkedQuad (const Element2d & el, T_EDGENUMBER & edgenumber, MarkedQuad & mq) { for (int i = 0; i < 4; i++) { mq.pnums[i] = el[i]; mq.pgeominfo[i] = el.GeomInfoPi (i+1); } Swap (mq.pnums[2], mq.pnums[3]); Swap (mq.pgeominfo[2], mq.pgeominfo[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++) for (ElementIndex ei : mtets.Range()) { 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[ei].pnums[j]); const Point<3> & p2 = mesh.Point (mtets[ei].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[ei].pnums[j]-IndexBASE()); if (hi < hshould) hshould = hi; } if (step == 1) { if (h / hshould > hfac) hfac = h / hshould; } else { if (h > hshould * hfac) { mtets[ei].marked = 1; marked = 1; } else mtets[ei].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]-IndexBASE()); 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, PointIndex newp, MarkedTet & newtet1, MarkedTet & newtet2) { #ifdef DEBUG *testout << "bisect tet " << oldtet << endl; #endif // 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 (int i = 0; i < 4; i++) { int cnt = 0; for (int j = 0; j < 4; j++) if (oldtet.faceedges[j] == i) cnt++; if (cnt == 3) istypep = 1; } for (int 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; newtet1.newest_vertex = oldtet.newest_vertex; #ifdef DEBUG *testout << "newtet1,before = " << newtet1 << endl; *testout << "newtet2,before = " << newtet2 << endl; #endif for (int i = 0; i < 4; i++) { if (i == oldtet.tetedge1) { newtet2.newest_vertex = i; newtet2.pnums[i] = newp; newtet2.faceedges[i] = oldtet.faceedges[i]; // inherited face newtet2.faceedges[vis1] = i; // cut faces newtet2.faceedges[vis2] = i; int j = 0; while (j == i || j == oldtet.faceedges[i]) j++; int 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; int j = 0; while (j == i || j == oldtet.faceedges[i]) j++; int 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, PointIndex newp1, PointIndex newp2, MarkedPrism & newprism1, MarkedPrism & newprism2) { for (int i = 0; i < 6; i++) { newprism1.pnums[i] = oldprism.pnums[i]; newprism2.pnums[i] = oldprism.pnums[i]; } int pe1 = 0; if (pe1 == oldprism.markededge) pe1++; int 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 & 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 == 2) { newid1.pnums[1] = newp[0]; newid2.pnums[0] = newp[0]; newid1.pnums[3] = newp[1]; newid2.pnums[2] = newp[1]; newid1.markededge = 0; newid2.markededge = 0; } 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, PointIndex newp, const PointGeomInfo & newpgi, MarkedTri & newtri1, MarkedTri & newtri2) { for (int 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 = 0; if (pe1 == oldtri.markededge) pe1++; int pe2 = 3 - oldtri.markededge - pe1; newtri1.pnums[pe2] = newp; newtri1.pgeominfo[pe2] = newpgi; newtri1.markededge = pe2; newtri1.newest_vertex = oldtri.newest_vertex; newtri2.pnums[pe1] = newp; newtri2.pgeominfo[pe1] = newpgi; newtri2.markededge = pe1; newtri2.newest_vertex = 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, PointIndex newp1, const PointGeomInfo & npgi1, PointIndex newp2, const PointGeomInfo & npgi2, MarkedQuad & newquad1, MarkedQuad & newquad2) { for (int 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; } } template int MarkHangingIdentifications(T_MIDS & mids, const HASHTABLE_CUTEDGES & cutedges) { int hanging = 0; for (int i = 1; i <= mids.Size(); i++) { if (mids.Elem(i).marked) { hanging = 1; continue; } const int np = mids.Get(i).np; for(int j = 0; j < np; j++) { PointIndices<2> edge1(mids.Get(i).pnums[j], mids.Get(i).pnums[(j+1) % np]); PointIndices<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 & cutedges) { int i,j,k; NgArray< NgArray* > idmaps; for(i=1; i<=mesh.GetIdentifications().GetMaxNr(); i++) { idmaps.Append(new NgArray); 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 int MarkHangingTets (T_MTETS & mtets, const HASHTABLE_CUTEDGES & cutedges, NgTaskManager tm) { static int timer = NgProfiler::CreateTimer ("MarkHangingTets"); NgProfiler::RegionTimer reg (timer); int hanging = 0; // for (int i = 1; i <= mtets.Size(); i++) ngcore::ParallelForRange // (tm, mtets.Size(), [&] (size_t begin, size_t end) (mtets.Range(), [&] (auto myrange) { bool my_hanging = false; // for (size_t i = begin; i < end; i++) for (auto ei : myrange) { MarkedTet & teti = mtets[ei]; if (teti.marked) { my_hanging = true; continue; } for (int j = 0; j < 3; j++) for (int k = j+1; k < 4; k++) { PointIndices<2> edge(teti.pnums[j], teti.pnums[k]); edge.Sort(); if (cutedges.Used (edge)) { teti.marked = 1; my_hanging = true; } } } if (my_hanging) hanging = true; }); return hanging; } template int MarkHangingPrisms (T_MPRISMS & mprisms, const HASHTABLE_CUTEDGES & cutedges) { int hanging = 0; for (int i = 1; i <= mprisms.Size(); i++) { if (mprisms.Elem(i).marked) { hanging = 1; continue; } for (int j = 0; j < 2; j++) for (int k = j+1; k < 3; k++) { PointIndices<2> edge1(mprisms.Get(i).pnums[j], mprisms.Get(i).pnums[k]); PointIndices<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; } template bool MarkHangingTris (T_MTRIS & mtris, const HASHTABLE_CUTEDGES & cutedges, NgTaskManager tm) { bool hanging = false; // for (int i = 1; i <= mtris.Size(); i++) // for (auto & tri : mtris) ParallelForRange (tm, mtris.Size(), [&] (size_t begin, size_t end) { bool my_hanging = false; for (size_t i = begin; i < end; i++) { auto & tri = mtris[i]; if (tri.marked) { my_hanging = true; continue; } for (int j = 0; j < 2; j++) for (int k = j+1; k < 3; k++) { /* PointIndices<2> edge(tri.pnums[j], tri.pnums[k]); edge.Sort(); if (cutedges.Used (edge)) */ if (cutedges.Used( { tri.pnums[j], tri.pnums[k] } )) { tri.marked = 1; my_hanging = true; } } } if (my_hanging) hanging = true; }); return hanging; } template int MarkHangingQuads (T_MQUADS & mquads, const HASHTABLE_CUTEDGES & cutedges) { int hanging = 0; for (int i = 1; i <= mquads.Size(); i++) { if (mquads.Elem(i).marked) { hanging = 1; continue; } PointIndices<2> edge1(mquads.Get(i).pnums[0], mquads.Get(i).pnums[1]); PointIndices<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 PointIndices<2> edge3(mquads.Get(i).pnums[1], mquads.Get(i).pnums[3]); PointIndices<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 & conto, NgArray & connecttonode) { // (*testout) << "connect " << node << " to " << tonode << endl; for (int i = 1; i <= conto.EntrySize(node); i++) { int n2 = conto.Get(node, i); if (!connecttonode.Get(n2)) { connecttonode.Elem(n2) = tonode; ConnectToNodeRec (n2, tonode, conto, connecttonode); } } } BisectionInfo::BisectionInfo() { mtets = make_unique(); mprisms = make_unique(); mids = make_unique(); mtris = make_unique(); mquads = make_unique(); } BisectionInfo::~BisectionInfo() {} void WriteMarkedElements(const Mesh& mesh, ostream & ost) { ost << "Marked Elements\n"; const auto& mtets = *mesh.bisectioninfo.mtets; const auto& mprisms = *mesh.bisectioninfo.mprisms; const auto& mids = *mesh.bisectioninfo.mids; const auto& mtris = *mesh.bisectioninfo.mtris; const auto& mquads = *mesh.bisectioninfo.mquads; ost << mtets.Size() << "\n"; for(auto ei : mtets.Range()) ost << mtets[ei]; ost << mprisms.Size() << "\n"; for(int i=0; i> auxstring; if(auxstring != "Marked") return false; if(ist) ist >> auxstring; if(auxstring != "Elements") return false; int size; ist >> size; mtets.SetSize(size); constexpr auto PI0 = IndexBASE(); // for(int i=0; i(size) ) { ist >> mtets[ei]; if(mtets[ei].pnums[0] >= PI0+mesh.GetNV() || mtets[ei].pnums[1] >= PI0+mesh.GetNV() || mtets[ei].pnums[2] >= PI0+mesh.GetNV() || mtets[ei].pnums[3] >= PI0+mesh.GetNV()) return false; } ist >> size; mprisms.SetSize(size); for(int i=0; i> mprisms[i]; ist >> size; mids.SetSize(size); for(int i=0; i> mids[i]; ist >> size; mtris.SetSize(size); for(int i=0; i> mtris[i]; ist >> size; mquads.SetSize(size); for(int i=0; i> mquads[i]; return true; } void BisectTetsCopyMesh (Mesh & mesh, const NetgenGeometry *, BisectionOptions & opt, const NgArray & idmaps, const string & refinfofile) { auto& mtets = *mesh.bisectioninfo.mtets; auto& mprisms = *mesh.bisectioninfo.mprisms; auto& mids = *mesh.bisectioninfo.mids; auto& mtris = *mesh.bisectioninfo.mtris; auto& mquads = *mesh.bisectioninfo.mquads; if (mesh.GetDimension() < 2) throw Exception ("Mesh bisection is available in 2D and 3D"); // mtets.SetName ("bisection, tets"); // mprisms.SetName ("bisection, prisms"); // mtris.SetName ("bisection, trigs"); // nmquads.SetName ("bisection, quads"); // mids.SetName ("bisection, identifications"); //int np = mesh.GetNP(); int ne = mesh.GetNE(); int nse = mesh.GetNSE(); /* 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 shortedges(100); // for (int i = 1; i <= ne; i++) for (auto ei : mesh.VolumeElements().Range()) { const Element & el = mesh[ei]; if (el.GetType() == PRISM || el.GetType() == PRISM12) { for (int j = 1; j <= 3; j++) { PointIndices<2> se(el.PNum(j), el.PNum(j+3)); se.Sort(); shortedges.Set (se, 1); } } } // INDEX_2_HASHTABLE edgenumber(np); // INDEX_2_CLOSED_HASHTABLE edgenumber(9*ne+4*nse); // ClosedHashTable edgenumber(9*ne+4*nse); ClosedHashTable, int> edgenumber(9*ne+4*nse); BTSortEdges (mesh, idmaps, edgenumber); // for (int i = 1; i <= ne; i++) for (auto ei : mesh.VolumeElements().Range()) { const Element & el = mesh[ei]; switch (el.GetType()) { case TET: case TET10: { // if tet has short edge, it is handled as degenerated prism int foundse = 0; for (int j = 1; j <= 3; j++) for (int k = j+1; k <= 4; k++) { PointIndices<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 (int l = 1; l <= 4; l++) for (int 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; PointIndices<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 (int i = 1; i <= nse; i++) /* for (SurfaceElementIndex sei = 0; sei < nse; sei++) { const Element2d & el = mesh[sei]; */ for (const Element2d & el : mesh.SurfaceElements()) { 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); } if(mesh.GetDimension() == 3) { MarkedIdentification mi; for(int j=0; j min2) continue; mi.marked = 0; mi.markededge = 0; mi.incorder = 0; mids.Append(mi); } } } } } mesh.mlparentelement.SetSize(ne); // for (int i = 1; i <= ne; i++) // mesh.mlparentelement.Elem(i) = 0; mesh.mlparentelement = ElementIndex::INVALID; mesh.mlparentsurfaceelement.SetSize(nse); // for (int i = 1; i <= nse; i++) // mesh.mlparentsurfaceelement.Elem(i) = 0; mesh.mlparentsurfaceelement = SurfaceElementIndex::INVALID; 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 NgArray< NgArray* > & idmaps) { NgArray< NgArray*,PointIndex::BASE > mtets_old(mesh.GetNP()); NgArray< NgArray*,PointIndex::BASE > mprisms_old(mesh.GetNP()); NgArray< NgArray*,PointIndex::BASE > mids_old(mesh.GetNP()); NgArray< NgArray*,PointIndex::BASE > mtris_old(mesh.GetNP()); NgArray< NgArray*,PointIndex::BASE > mquads_old(mesh.GetNP()); for(int i=PointIndex::BASE; i; for(int i=PointIndex::BASE; i; for(int i=PointIndex::BASE; i; for(int i=PointIndex::BASE; i; for(int i=PointIndex::BASE; i; for(int i=0; iAppend(mtets[i]); for(int i=0; iAppend(mprisms[i]); for(int i=0; iAppend(mids[i]); for(int i=0; iAppend(mtris[i]); } for(int i=0; iAppend(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 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 edgenumber(np); INDEX_2_CLOSED_HASHTABLE 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 && lSize(); 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; jSize(); 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 & idmaps) //const NgArray < NgArray* > & elements_before, //const NgArray < NgArray* > & markedelts_num, // const NgArray < NgArray* > & surfelements_before, // const NgArray < NgArray* > & 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); */ auto& mtets = *mesh.bisectioninfo.mtets; auto& mprisms = *mesh.bisectioninfo.mprisms; auto& mids = *mesh.bisectioninfo.mids; auto& mtris = *mesh.bisectioninfo.mtris; auto& mquads = *mesh.bisectioninfo.mquads; T_MTETS mtets_old (mtets); T_MPRISMS mprisms_old (mprisms); T_MIDS mids_old (mids); T_MTRIS mtris_old (mtris); T_MQUADS mquads_old (mquads); mtets.SetSize(0); mprisms.SetSize(0); mids.SetSize(0); mtris.SetSize(0); mquads.SetSize(0); //int nv = mesh.GetNV(); // INDEX_2_CLOSED_HASHTABLE edgenumber(9*mesh.GetNE()+4*mesh.GetNSE()); ClosedHashTable, int> edgenumber; int maxnum = BTSortEdges (mesh, idmaps, edgenumber); // for(int m = 0; m < mtets_old.Size(); m++) for (auto mi : mtets_old.Range()) { MarkedTet & mt = mtets_old[mi]; //(*testout) << "old mt " << mt; PointIndices<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 (auto ei : mesh.VolumeElements().Range()) { const Element & el = mesh[ei]; */ for (const Element & el : mesh.VolumeElements()) { //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 (const Element2d & el : mesh.SurfaceElements()) { /* 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; jPos(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 * quality_loss) const { PrintMessage(1,"Mesh bisection"); PushStatus("Mesh bisection"); auto& mtets = *mesh.bisectioninfo.mtets; auto& mprisms = *mesh.bisectioninfo.mprisms; auto& mids = *mesh.bisectioninfo.mids; auto& mtris = *mesh.bisectioninfo.mtris; auto& mquads = *mesh.bisectioninfo.mquads; static int timer = NgProfiler::CreateTimer ("Bisect"); static int timer1 = NgProfiler::CreateTimer ("Bisect 1"); static int timer1a = NgProfiler::CreateTimer ("Bisect 1a"); static int timer1b = NgProfiler::CreateTimer ("Bisect 1b"); static int timer2 = NgProfiler::CreateTimer ("Bisect 2"); static int timer2a = NgProfiler::CreateTimer ("Bisect 2a"); static int timer2b = NgProfiler::CreateTimer ("Bisect 2b"); // static int timer2c = NgProfiler::CreateTimer ("Bisect 2c"); static int timer3 = NgProfiler::CreateTimer ("Bisect 3"); static int timer3a = NgProfiler::CreateTimer ("Bisect 3a"); static int timer3b = NgProfiler::CreateTimer ("Bisect 3b"); static int timer_bisecttet = NgProfiler::CreateTimer ("Bisect tets"); static int timer_bisecttrig = NgProfiler::CreateTimer ("Bisect trigs"); static int timer_bisectsegms = NgProfiler::CreateTimer ("Bisect segms"); NgProfiler::RegionTimer reg1 (timer); (*opt.tracer)("Bisect", false); NgProfiler::StartTimer (timer1); NgProfiler::StartTimer (timer1a); static int localizetimer = NgProfiler::CreateTimer("localize edgepoints"); NgProfiler::RegionTimer * loct = new NgProfiler::RegionTimer(localizetimer); LocalizeEdgePoints(mesh); delete loct; NgArray< idmap_type* > idmaps; for(int i=1; i<=mesh.GetIdentifications().GetMaxNr(); i++) { if(mesh.GetIdentifications().GetType(i) == Identifications::PERIODIC) { idmaps.Append(new idmap_type); 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(); } mesh.ComputeNVertices(); // if (mesh.mglevels == 1 || idmaps.Size() > 0) if (mesh.level_nv.Size() == 0) // || idmaps.Size() ???? { BisectTetsCopyMesh(mesh, NULL, opt, idmaps, refelementinfofileread); mesh.level_nv.Append (mesh.GetNV()); } int np = mesh.GetNV(); mesh.SetNP(np); #ifdef PARALLEL if (mesh.GetCommunicator().Size() > 1) { mesh.GetParallelTopology().IdentifyVerticesAfterRefinement(); mesh.GetCommunicator().Barrier(); mesh.GetParallelTopology().EnumeratePointsGlobally(); } #endif // 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++) for (auto ei : mesh.VolumeElements().Range()) 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 // NgArray v_order (mesh.GetNP()); Array v_order (mesh.GetNP()); v_order = 0; // for (ElementIndex ei = 0; ei < ne; ei++) for (auto ei : mesh.VolumeElements().Range()) for (int 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 (int 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 (auto ei : mesh.VolumeElements().Range()) for (int 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 (int 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 cutedges(10 + 5 * (mtets.Size()+mprisms.Size()+mtris.Size()+mquads.Size())); // INDEX_2_CLOSED_HASHTABLE cutedges(10 + 9 * (mtets.Size()+mprisms.Size()+mtris.Size()+mquads.Size())); // ClosedHashTable cutedges(10 + 9 * (mtets.Size()+mprisms.Size()+mtris.Size()+mquads.Size())); ClosedHashTable, PointIndex> cutedges(10 + 9 * (mtets.Size()+mprisms.Size()+mtris.Size()+mquads.Size())); bool noprojection = false; NgProfiler::StopTimer (timer1a); for (int 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(int i=1; i<=mtets.Size(); i++) mtets[i-1].marked = 0; */ for(auto ei : mtets.Range()) mtets[ei].marked = 0; for(int i=1; i<=mprisms.Size(); i++) mprisms.Elem(i).marked = 0; for(int i=1; i<=mtris.Size(); i++) mtris.Elem(i).marked = 0; for(int i=1; i<=mquads.Size(); i++) mquads.Elem(i).marked = 0; for(int 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()+(atoi(st.c_str())-1)].marked = 3; marked = 1; inf >> st; isint = true; for(string::size_type ii=0; isint && ii> bounds[i]; int cnt = 0; // for(ElementIndex ei = 0; ei < mesh.GetNE(); ei++) for (auto ei : mesh.VolumeElements().Range()) { const Element & el = mesh[ei]; // Point<3> center(0,0,0); for(int i=0; i 0) marked = 1; inf >> st; } else { throw NgException("something wrong with refinementinfo file"); } } } } else { inf.close(); inf.open(opt.refinementfilename); char ch; // for (int i = 1; i <= mtets.Size(); i++) for (auto ei : mtets.Range()) { inf >> ch; if(!inf) throw NgException("something wrong with refinementinfo file (old format)"); mtets[ei].marked = (ch == '1'); } marked = 1; } inf.close(); } else if (opt.usemarkedelements) { int cntm = 0; // all in one ! if (mprisms.Size()) { ElementIndex cnttet = IndexBASE(); int cntprism = 0; // for (int i = 1; i <= mesh.GetNE(); i++) for (auto ei : mesh.VolumeElements().Range()) { if (mesh.VolumeElement(ei).GetType() == TET || mesh.VolumeElement(ei).GetType() == TET10) { mtets[cnttet].marked = (opt.onlyonce ? 3 : 1) * mesh.VolumeElement(ei).TestRefinementFlag(); if (mtets[cnttet].marked) cntm++; cnttet++; } else { cntprism++; mprisms.Elem(cntprism).marked = 2 * mesh.VolumeElement(ei).TestRefinementFlag(); if (mprisms.Elem(cntprism).marked) cntm++; } } } else // for (int i = 1; i <= mtets.Size(); i++) for (auto ei : mtets.Range()) { mtets[ei].marked = (opt.onlyonce ? 1 : 3) * mesh.VolumeElement(ei).TestRefinementFlag(); if (mtets[ei].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 (int i = 1; i <= mesh.GetNSE(); i++) for (SurfaceElementIndex sei = 0; sei < mesh.GetNSE(); sei++) { if (mesh[sei].GetType() == TRIG || mesh[sei].GetType() == TRIG6) { cnttrig++; mtris.Elem(cnttrig).marked = mesh[sei].TestRefinementFlag() ? (opt.onlyonce ? 1 : 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[sei].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 (auto ei : mtets.Range()) mtets[ei].incorder = mtets[ei].marked ? 1 : 0; for (auto ei : mtets.Range()) if (mtets[ei].incorder) mtets[ei].marked = 0; for (int i = 1; i <= mprisms.Size(); i++) mprisms.Elem(i).incorder = mprisms.Elem(i).marked ? 1 : 0; for (int i = 1; i <= mprisms.Size(); i++) if (mprisms.Elem(i).incorder) mprisms.Elem(i).marked = 0; for (int i = 1; i <= mtris.Size(); i++) mtris.Elem(i).incorder = mtris.Elem(i).marked ? 1 : 0; for (int i = 1; i <= mtris.Size(); i++) { if (mtris.Elem(i).incorder) mtris.Elem(i).marked = 0; } } if (opt.refine_hp) { PrintMessage(3,"refine hp"); TBitArray singv(np); singv.Clear(); if (mesh.GetDimension() == 3) { for (int i = 1; i <= mesh.GetNSeg(); i++) { const Segment & seg = mesh.LineSegment(i); singv.SetBit (seg[0]); singv.SetBit (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 bndind(np); bndind = 0; for (int i = 1; i <= mesh.GetNSeg(); i++) { const Segment & seg = mesh.LineSegment(i); for (int j = 0; j < 2; j++) { PointIndex pi = (j == 0) ? seg[0] : seg[1]; if (bndind[pi] == 0) bndind[pi] = seg.edgenr; else if (bndind[pi] != seg.edgenr) singv.SetBit (pi); } } } // for (int i = 1; i <= mtets.Size(); i++) for (auto ei : mtets.Range()) mtets[ei].incorder = 1; // for (int i = 1; i <= mtets.Size(); i++) for (auto ei : mtets.Range()) { if (!mtets[ei].marked) mtets[ei].incorder = 0; for (int j = 0; j < 4; j++) if (singv.Test (mtets[ei].pnums[j])) mtets[ei].incorder = 0; } // for (int i = 1; i <= mtets.Size(); i++) for (auto ei : mtets.Range()) if (mtets[ei].incorder) mtets[ei].marked = 0; for (int i = 1; i <= mprisms.Size(); i++) mprisms.Elem(i).incorder = 1; for (int i = 1; i <= mprisms.Size(); i++) { if (!mprisms.Elem(i).marked) mprisms.Elem(i).incorder = 0; for (int j = 0; j < 6; j++) if (singv.Test (mprisms.Elem(i).pnums[j])) mprisms.Elem(i).incorder = 0; } for (int i = 1; i <= mprisms.Size(); i++) if (mprisms.Elem(i).incorder) mprisms.Elem(i).marked = 0; for (int i = 1; i <= mtris.Size(); i++) mtris.Elem(i).incorder = 1; for (int i = 1; i <= mtris.Size(); i++) { if (!mtris.Elem(i).marked) mtris.Elem(i).incorder = 0; for (int j = 0; j < 3; j++) if (singv.Test (mtris.Elem(i).pnums[j])) mtris.Elem(i).incorder = 0; } for (int 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 NgProfiler::StartTimer (timer_bisecttet); (*opt.tracer)("bisecttet", false); size_t nel = mtets.Size(); // for (size_t i = 0; i < nel; i++) for (auto ei : ngcore::T_Range(nel)) if (mtets[ei].marked) { MarkedTet oldtet = mtets[ei]; SortedPointIndices<2> edge(oldtet.pnums[oldtet.tetedge1], oldtet.pnums[oldtet.tetedge2]); PointIndex newp; if (auto optnewp = cutedges.GetIfUsed(edge)) { newp = *optnewp; } else { Point<3> npt = Center (mesh[edge[0]], mesh[edge[1]]); newp = mesh.AddPoint (npt); cutedges.Set (edge, newp); } MarkedTet newtet1, newtet2; BTBisectTet (oldtet, newp, newtet1, newtet2); mtets[ei] = newtet1; mtets.Append (newtet2); mesh.mlparentelement.Append (ei); } NgProfiler::StopTimer (timer_bisecttet); (*opt.tracer)("bisecttet", true); int npr = mprisms.Size(); for (int i = 1; i <= npr; i++) if (mprisms.Elem(i).marked) { MarkedPrism oldprism; MarkedPrism newprism1, newprism2; PointIndex newp1, newp2; oldprism = mprisms.Get(i); int pi1 = 0; if (pi1 == oldprism.markededge) pi1++; int pi2 = 3-pi1-oldprism.markededge; SortedPointIndices<2> edge1(oldprism.pnums[pi1], oldprism.pnums[pi2]); SortedPointIndices<2> edge2(oldprism.pnums[pi1+3], oldprism.pnums[pi2+3]); if (cutedges.Used (edge1)) newp1 = cutedges.Get(edge1); else { Point<3> npt = Center (mesh[edge1[0]], mesh[edge1[1]]); newp1 = mesh.AddPoint (npt); cutedges.Set (edge1, newp1); } if (cutedges.Used (edge2)) newp2 = cutedges.Get(edge2); else { Point<3> npt = Center (mesh[edge2[0]], mesh[edge2[1]]); 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 (int i = 1; i <= nid; i++) if (mids.Elem(i).marked) { MarkedIdentification oldid,newid1,newid2; Array newp; oldid = mids.Get(i); NgArray> edges; edges.Append( { oldid.pnums[oldid.markededge], oldid.pnums[(oldid.markededge+1)%oldid.np] } ); edges.Append( { oldid.pnums[oldid.markededge + oldid.np], oldid.pnums[(oldid.markededge+1)%oldid.np + oldid.np] } ); if(oldid.np == 4) { edges.Append( { oldid.pnums[(oldid.markededge+2)%oldid.np], oldid.pnums[(oldid.markededge+3)%oldid.np]} ); edges.Append( { oldid.pnums[(oldid.markededge+2)%oldid.np + oldid.np], oldid.pnums[(oldid.markededge+3)%oldid.np + oldid.np] } ); } for (int 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); (*opt.tracer)("mark elements", false); hangingvol = MarkHangingTets (mtets, cutedges, opt.task_manager) + MarkHangingPrisms (mprisms, cutedges) + MarkHangingIdentifications (mids, cutedges); (*opt.tracer)("mark elements", true); size_t nsel = mtris.Size(); NgProfiler::StartTimer (timer_bisecttrig); (*opt.tracer)("Bisect trigs", false); for (size_t i = 0; i < nsel; i++) if (mtris[i].marked) { MarkedTri newtri1, newtri2; PointIndex newp; MarkedTri oldtri = mtris[i]; PointIndex oldpi1 = oldtri.pnums[(oldtri.markededge+1)%3]; PointIndex oldpi2 = oldtri.pnums[(oldtri.markededge+2)%3]; PointIndices<2> edge(oldpi1, oldpi2); edge.Sort(); int si = mesh.GetFaceDescriptor (oldtri.surfid).SurfNr(); PointGeomInfo npgi; PointGeomInfo gi1 = oldtri.pgeominfo[(oldtri.markededge+1)%3]; PointGeomInfo gi2 = oldtri.pgeominfo[(oldtri.markededge+2)%3]; if (cutedges.Used (edge)) { newp = cutedges.Get(edge); npgi.u = 0.5*(gi1.u + gi2.u); npgi.v = 0.5*(gi1.v + gi2.v); geo.ProjectPointGI (si, mesh[newp], npgi); } else { Point<3> npt = Center (mesh.Point (edge[0]), mesh.Point (edge[1])); newp = mesh.AddPoint (npt); cutedges.Set (edge, newp); geo.PointBetween (mesh.Point (oldpi1), mesh.Point (oldpi2), 0.5, si, gi1, gi2, mesh.Point (newp), npgi); } BTBisectTri (oldtri, newp, npgi, newtri1, newtri2); mtris[i] = newtri1; mtris.Append (newtri2); mesh.mlparentsurfaceelement.Append (i); } NgProfiler::StopTimer (timer_bisecttrig); (*opt.tracer)("Bisect trigs", true); int nquad = mquads.Size(); for (int i = 1; i <= nquad; i++) if (mquads.Elem(i).marked) { MarkedQuad oldquad; MarkedQuad newquad1, newquad2; PointIndex newp1, newp2; oldquad = mquads.Get(i); /* INDEX_2 edge1(oldquad.pnums[0], oldquad.pnums[1]); INDEX_2 edge2(oldquad.pnums[2], oldquad.pnums[3]); */ PointIndices<2> edge1, edge2; PointGeomInfo pgi11, pgi12, pgi21, pgi22; if (oldquad.markededge==0 || oldquad.markededge==2) { edge1[0] = oldquad.pnums[0]; pgi11=oldquad.pgeominfo[0]; edge1[1] = oldquad.pnums[1]; pgi12=oldquad.pgeominfo[1]; edge2[0] = oldquad.pnums[2]; pgi21=oldquad.pgeominfo[2]; edge2[1] = oldquad.pnums[3]; pgi22=oldquad.pgeominfo[3]; } else // 3 || 1 { edge1[0] = oldquad.pnums[0]; pgi11=oldquad.pgeominfo[0]; edge1[1] = oldquad.pnums[2]; pgi12=oldquad.pgeominfo[2]; edge2[0] = oldquad.pnums[1]; pgi21=oldquad.pgeominfo[1]; edge2[1] = 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[0]), mesh.Point (edge1[1])); newp1 = mesh.AddPoint (np1); cutedges.Set (edge1, newp1); } if (cutedges.Used (edge2)) { newp2 = cutedges.Get(edge2); } else { Point<3> np2 = Center (mesh.Point (edge2[0]), mesh.Point (edge2[1])); newp2 = mesh.AddPoint (np2); cutedges.Set (edge2, newp2); } PointGeomInfo npgi1, npgi2; int si = mesh.GetFaceDescriptor (oldquad.surfid).SurfNr(); geo.PointBetween(mesh.Point (edge1.I1()), mesh.Point (edge1.I2()), 0.5, si, pgi11, pgi12, mesh.Point (newp1), npgi1); geo.PointBetween (mesh.Point (edge2.I1()), mesh.Point (edge2.I2()), 0.5, si, pgi21, pgi22, mesh.Point (newp2), npgi2); BTBisectQuad (oldquad, newp1, npgi1, newp2, npgi2, newquad1, newquad2); mquads.Elem(i) = newquad1; mquads.Append (newquad2); } NgProfiler::StartTimer (timer1b); hangingsurf = MarkHangingTris (mtris, cutedges, opt.task_manager) + MarkHangingQuads (mquads, cutedges); hangingedge = mesh.GetDimension() == 3 ? 0 : MarkHangingIdentifications(mids, cutedges); NgProfiler::StopTimer (timer1b); NgProfiler::StartTimer (timer_bisectsegms); int nseg = mesh.GetNSeg (); for (int i = 1; i <= nseg; i++) { Segment & seg = mesh.LineSegment (i); PointIndices<2> edge(seg[0], seg[1]); edge.Sort(); if (cutedges.Used (edge)) { hangingedge = 1; Segment nseg1 = seg; Segment nseg2 = seg; PointIndex newpi = cutedges.Get(edge); nseg1[1] = newpi; nseg2[0] = newpi; EdgePointGeomInfo newepgi; geo.PointBetweenEdge(mesh.Point (seg[0]), mesh.Point (seg[1]), 0.5, seg.surfnr1, seg.surfnr2, seg.epgeominfo[0], seg.epgeominfo[1], mesh.Point (newpi), newepgi); nseg1.epgeominfo[1] = newepgi; nseg2.epgeominfo[0] = newepgi; mesh.LineSegment (i) = nseg1; mesh.AddSegment (nseg2); } } NgProfiler::StopTimer (timer_bisectsegms); } 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"); } NgProfiler::StopTimer (timer1); // (*testout) << "mtets = " << mtets << endl; if (opt.refine_hp) { // Array v_order (mesh.GetNP()); v_order = 0; if (mesh.GetDimension() == 3) { // for (int i = 1; i <= mtets.Size(); i++) for (auto ei : mtets.Range()) if (mtets[ei].incorder) mtets[ei].order++; // for (int i = 0; i < mtets.Size(); i++) for (auto ei : mtets.Range()) for (int j = 0; j < 4; j++) if (int(mtets[ei].order) > v_order[mtets[ei].pnums[j]]) v_order[mtets[ei].pnums[j]] = mtets[ei].order; // for (int i = 0; i < mtets.Size(); i++) for (auto ei : mtets.Range()) for (int j = 0; j < 4; j++) if (int(mtets[ei].order) < v_order[mtets[ei].pnums[j]]-1) mtets[ei].order = v_order[mtets[ei].pnums[j]]-1; } else { for (int i = 1; i <= mtris.Size(); i++) if (mtris.Elem(i).incorder) { mtris.Elem(i).order++; } for (int i = 0; i < mtris.Size(); i++) for (int j = 0; j < 3; j++) if (int(mtris[i].order) > v_order[mtris[i].pnums[j]]) v_order[mtris[i].pnums[j]] = mtris[i].order; for (int i = 0; i < mtris.Size(); i++) { for (int j = 0; j < 3; j++) if (int(mtris[i].order) < v_order[mtris[i].pnums[j]]-1) mtris[i].order = v_order[mtris[i].pnums[j]]-1; } } } NgProfiler::StartTimer (timer2); NgProfiler::StartTimer (timer2a); mtets.SetAllocSize (mtets.Size()); mprisms.SetAllocSize (mprisms.Size()); mids.SetAllocSize (mids.Size()); mtris.SetAllocSize (mtris.Size()); mquads.SetAllocSize (mquads.Size()); (*opt.tracer)("copy tets", false); mesh.ClearVolumeElements(); mesh.VolumeElements().SetAllocSize (mtets.Size()+mprisms.Size()); mesh.VolumeElements().SetSize(mtets.Size()); /* for (int i = 1; i <= mtets.Size(); i++) { Element el(TET); el.SetIndex (mtets.Get(i).matindex); for (int j = 1; j <= 4; j++) el.PNum(j) = mtets.Get(i).pnums[j-1]; el.SetOrder (mtets.Get(i).order); mesh.AddVolumeElement (el); } */ ngcore::ParallelForRange (mtets.Range(), [&] (auto myrange) { for (auto ei : myrange) { Element el(TET); auto & tet = mtets[ei]; el.SetIndex (tet.matindex); el.SetOrder (tet.order); for (int j = 0; j < 4; j++) el[j] = tet.pnums[j]; el.NewestVertex() = tet.newest_vertex; mesh.SetVolumeElement (ei, el); } }); (*opt.tracer)("copy tets", true); for (int i = 1; i <= mprisms.Size(); i++) { Element el(PRISM); el.SetIndex (mprisms.Get(i).matindex); for (int 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 (int 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 (int 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(); mesh.SurfaceElements().SetAllocSize (mtris.Size()+mquads.Size()); NgProfiler::StopTimer (timer2a); NgProfiler::StartTimer (timer2b); /* for (auto & trig : mtris) { Element2d el(TRIG); el.SetIndex (trig.surfid); el.SetOrder (trig.order); for (int j = 0; j < 3; j++) { el[j] = trig.pnums[j]; el.GeomInfoPi(j+1) = trig.pgeominfo[j]; } mesh.AddSurfaceElement (el); } */ mesh.SurfaceElements().SetSize(mtris.Size()); // for (size_t i = 0; i < mtris.Size(); i++) ParallelForRange (opt.task_manager, mtris.Size(), [&] (size_t begin, size_t end) { for (size_t i = begin; i < end; i++) { Element2d el(TRIG); auto & trig = mtris[i]; el.SetIndex (trig.surfid); el.SetOrder (trig.order); for (int j = 0; j < 3; j++) { el[j] = trig.pnums[j]; el.GeomInfoPi(j+1) = trig.pgeominfo[j]; } el.NewestVertex() = trig.newest_vertex; mesh.SetSurfaceElement (SurfaceElementIndex(i), el); } }); mesh.RebuildSurfaceElementLists(); for (int i = 1; i <= mquads.Size(); i++) { Element2d el(QUAD); el.SetIndex (mquads.Get(i).surfid); for (int j = 1; j <= 4; j++) el.PNum(j) = mquads.Get(i).pnums[j-1]; Swap (el.PNum(3), el.PNum(4)); mesh.AddSurfaceElement (el); } NgProfiler::StopTimer (timer2b); // write multilevel hierarchy to mesh: np = mesh.GetNP(); mesh.mlbetweennodes.SetSize(np); // if (mesh.mglevels <= 2) if (mesh.level_nv.Size() <= 1) { PrintMessage(4,"RESETTING mlbetweennodes"); /* for (int i = 1; i <= np; i++) { mesh.mlbetweennodes.Elem(i).I1() = 0; mesh.mlbetweennodes.Elem(i).I2() = 0; } */ for (auto i : mesh.mlbetweennodes.Range()) mesh.mlbetweennodes[i] = { PointIndex::INVALID, PointIndex::INVALID }; } mesh.level_nv.Append (np); /* 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; } */ TBitArray isnewpoint(np); isnewpoint.Clear(); { static Timer t("update mlbetween"); RegionTimer reg(t); /* for (int i = 0; i < cutedges.Size(); i++) if (cutedges.UsedPos0(i)) { INDEX_2 edge; PointIndex newpi; cutedges.GetData0 (i, edge, newpi); isnewpoint.SetBit(newpi); mesh.mlbetweennodes[newpi] = edge; } */ for (auto [edge,newpi] : cutedges) { isnewpoint.SetBit(newpi); mesh.mlbetweennodes[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 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(); { static Timer t("ComputeNV"); RegionTimer reg(t); mesh.ComputeNVertices(); } (*opt.tracer)("call RebuildSurfElList", false); mesh.RebuildSurfaceElementLists(); (*opt.tracer)("call RebuildSurfElList", true); // update identification tables for (int i = 1; i <= mesh.GetIdentifications().GetMaxNr(); i++) { idmap_type 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 (int j = 0; j < cutedges.Size(); j++) if (cutedges.UsedPos0(j)) { PointIndices<2> i2; PointIndex newpi; cutedges.GetData0 (j, i2, newpi); PointIndices<2> oi2(identmap[i2[0]], identmap[i2[1]]); oi2.Sort(); if (cutedges.Used (oi2)) { PointIndex onewpi = cutedges.Get(oi2); mesh.GetIdentifications().Add (newpi, onewpi, i); } } */ for (auto [i2, newpi] : cutedges) { PointIndices<2> oi2(identmap[i2[0]], identmap[i2[1]]); if((!oi2[0].IsValid()) || (!oi2[1].IsValid())) continue; oi2.Sort(); if (cutedges.Used (oi2)) { PointIndex onewpi = cutedges.Get(oi2); mesh.GetIdentifications().Add (newpi, onewpi, i); } } } (*opt.tracer)("Bisect", true); // 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++) for (auto ii : mesh.Points().Range()) { if(isnewpoint.Test(ii) && mesh.mlbetweennodes[ii][0].IsValid()) { 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) if(mesh.level_nv.Size() == 1) repaired_once = false; //mesh.Save("before.vol"); static int reptimer = NgProfiler::CreateTimer("check/repair"); NgProfiler::RegionTimer * regt(NULL); regt = new NgProfiler::RegionTimer(reptimer); NgArray bad_elts; NgArray 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 0) { clock_t t1(clock()); // update id-maps int j=0; for(int 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(int i=0; i #include #include "basegeom.hpp" #include "meshclass.hpp" namespace netgen { class BisectionOptions { public: const char * outfilename; const char * mlfilename; const char * refinementfilename; const char * femcode; int maxlevel; int usemarkedelements; bool refine_hp = false; bool refine_p = false; bool onlyonce = false; NgTaskManager task_manager = &DummyTaskManager; NgTracer tracer = &DummyTracer; DLL_HEADER BisectionOptions (); }; class ZRefinementOptions { public: int minref; DLL_HEADER ZRefinementOptions(); }; DLL_HEADER extern void BisectTetsCopyMesh (Mesh &, const NetgenGeometry *, BisectionOptions & opt); DLL_HEADER extern void ZRefinement (Mesh &, const class NetgenGeometry *, ZRefinementOptions & opt); class DLL_HEADER Refinement { const NetgenGeometry& geo; public: Refinement (const NetgenGeometry& ageo) : geo(ageo) {} virtual ~Refinement () {} void Refine (Mesh & mesh) const; void Refine (Mesh & mesh); void Bisect (Mesh & mesh, class BisectionOptions & opt, NgArray * quality_loss = NULL) const; void MakeSecondOrder (Mesh & mesh) const; void MakeSecondOrder (Mesh & mesh); void ValidateSecondOrder (Mesh & mesh); void ValidateRefinedMesh (Mesh & mesh, NgArray & parents); virtual void LocalizeEdgePoints(Mesh & /* mesh */) const {;} }; } // namespace netgen #endif // NETGEN_BISECT_HPP ================================================ FILE: libsrc/meshing/boundarylayer.cpp ================================================ #include "boundarylayer.hpp" #include "boundarylayer_limiter.hpp" #include #include #include #include "debugging.hpp" #include "global.hpp" #include "meshfunc.hpp" namespace netgen { struct SpecialPointException : public Exception { SpecialPointException () : Exception("") {} }; std::tuple FindCloseVectors (FlatArray> ns, bool find_max = true) { int maxpos1 = 0; int maxpos2 = 0; double val = find_max ? -1e99 : 1e99; for (auto i : Range(ns)) for (auto j : Range(i + 1, ns.Size())) { double ip = ns[i] * ns[j]; if ((find_max && (ip > val)) || (!find_max && (ip < val))) { val = ip; maxpos1 = i; maxpos2 = j; } } return {maxpos1, maxpos2}; } Vec<3> CalcGrowthVector (FlatArray> ns) { if (ns.Size() == 0) return {0, 0, 0}; if (ns.Size() == 1) return ns[0]; if (ns.Size() == 2) { auto gw = ns[0]; auto n = ns[1]; auto npn = gw * n; auto npnp = gw * gw; auto nn = n * n; if (fabs(nn - npn * npn / npnp) < 1e-6) return n; gw += (nn - npn) / (nn - npn * npn / npnp) * (n - npn / npnp * gw); return gw; } if (ns.Size() == 3) { DenseMatrix mat(3, 3); for (auto i : Range(3)) for (auto j : Range(3)) mat(i, j) = ns[i][j]; if (fabs(mat.Det()) > 1e-2) { DenseMatrix mat(3, 3); for (auto i : Range(3)) for (auto j : Range(3)) mat(i, j) = ns[i] * ns[j]; if (fabs(mat.Det()) > 1e-2) { Vector rhs(3); rhs = 1.; Vector res(3); DenseMatrix inv(3, ns.Size()); CalcInverse(mat, inv); inv.Mult(rhs, res); Vec<3> growth = 0.; for (auto i : Range(ns)) growth += res[i] * ns[i]; return growth; } } } auto [maxpos1, maxpos2] = FindCloseVectors(ns); Array> new_normals; new_normals = ns; // const auto dot = ns[maxpos1] * ns[maxpos2]; auto average = 0.5 * (ns[maxpos1] + ns[maxpos2]); average.Normalize(); new_normals[maxpos1] = average; new_normals.DeleteElement(maxpos2); auto gw = CalcGrowthVector(new_normals); for (auto n : ns) if (n * gw < 0) throw SpecialPointException(); return gw; } SpecialBoundaryPoint ::GrowthGroup ::GrowthGroup (FlatArray faces_, FlatArray> normals) { faces = faces_; growth_vector = CalcGrowthVector(normals); } SpecialBoundaryPoint ::SpecialBoundaryPoint ( const std::map>& normals) { // find opposing face normals Array> ns; Array faces; for (auto [face, normal] : normals) { ns.Append(normal); faces.Append(face); } auto [minface1, minface2] = FindCloseVectors(ns, false); minface1 = faces[minface1]; minface2 = faces[minface2]; Array g1_faces; g1_faces.Append(minface1); Array g2_faces; g2_faces.Append(minface2); auto n1 = normals.at(minface1); auto n2 = normals.at(minface2); separating_direction = 0.5 * (n2 - n1); Array> normals1, normals2; for (auto [facei, normali] : normals) if (facei != minface1 && facei != minface2) { g1_faces.Append(facei); g2_faces.Append(facei); } for (auto fi : g1_faces) normals1.Append(normals.at(fi)); for (auto fi : g2_faces) normals2.Append(normals.at(fi)); growth_groups.Append(GrowthGroup(g1_faces, normals1)); growth_groups.Append(GrowthGroup(g2_faces, normals2)); } Vec<3> BoundaryLayerTool ::getEdgeTangent (PointIndex pi, int index, FlatArray segs) { Vec<3> tangent = 0.0; ArrayMem pts; for (auto* p_seg : segs) { auto& seg = *p_seg; if (seg.index != index) continue; PointIndex other = seg[0] - pi + seg[1]; if (!pts.Contains(other)) pts.Append(other); } if (pts.Size() != 2) { cout << "getEdgeTangent pi = " << pi << ", index = " << index << endl; cout << pts << endl; for (auto* p_seg : segs) cout << *p_seg << endl; throw NG_EXCEPTION("Something went wrong in getEdgeTangent!"); } tangent = mesh[pts[1]] - mesh[pts[0]]; return tangent.Normalize(); } void BoundaryLayerTool ::LimitGrowthVectorLengths () { static Timer tall("BoundaryLayerTool::LimitGrowthVectorLengths"); RegionTimer rtall(tall); GrowthVectorLimiter limiter(*this); limiter.Perform(); } // depending on the geometry type, the mesh contains segments multiple times // (once for each face) bool HaveSingleSegments (const Mesh& mesh) { auto& topo = mesh.GetTopology(); NgArray surf_els; for (auto segi : Range(mesh.LineSegments())) { mesh.GetTopology().GetSegmentSurfaceElements(segi + 1, surf_els); if (surf_els.Size() < 2) continue; auto seg = mesh[segi]; auto pi0 = min(seg[0], seg[1]); auto pi1 = max(seg[0], seg[1]); auto p0_segs = topo.GetVertexSegments(seg[0]); for (auto segi_other : p0_segs) { if (segi_other == segi) continue; auto seg_other = mesh[segi_other]; auto pi0_other = min(seg_other[0], seg_other[1]); auto pi1_other = max(seg_other[0], seg_other[1]); if (pi0_other == pi0 && pi1_other == pi1) return false; } // found segment with multiple adjacent surface elements but no other // segments with same points -> have single segments return true; } return true; } // duplicates segments (and sets seg.si accordingly) to have a unified data // structure for all geometry types void BuildSegments (Mesh& mesh, bool have_single_segments, Array& segments, Array& free_segments) { // auto& topo = mesh.GetTopology(); NgArray surf_els; for (auto segi : Range(mesh.LineSegments())) { auto seg = mesh[segi]; if (seg.domin == seg.domout && seg.domin > 0) { free_segments.Append(seg); continue; } if (!have_single_segments) { segments.Append(seg); continue; } mesh.GetTopology().GetSegmentSurfaceElements(segi + 1, surf_els); for (auto seli : surf_els) { const auto& sel = mesh[seli]; seg.si = sel.GetIndex(); auto np = sel.GetNP(); for (auto i : Range(np)) { if (sel[i] == seg[0]) { if (sel[(i + 1) % np] != seg[1]) swap(seg[0], seg[1]); break; } } segments.Append(seg); } } } void MergeAndAddSegments (Mesh& mesh, FlatArray segments, FlatArray new_segments) { INDEX_2_HASHTABLE already_added(segments.Size() + 2 * new_segments.Size()); mesh.LineSegments().SetSize0(); auto addSegment = [&] (auto seg) { SortedPointIndices<2> i2(seg[0], seg[1]); if (!already_added.Used(i2)) { seg.si = seg.index + 1; mesh.AddSegment(seg); already_added.Set(i2, true); } }; for (const auto& seg : segments) addSegment(seg); for (const auto& seg : new_segments) addSegment(seg); } BoundaryLayerTool::BoundaryLayerTool (Mesh& mesh_, const BoundaryLayerParameters& params_) : mesh(mesh_), topo(mesh_.GetTopology()), params(params_) { static Timer timer("BoundaryLayerTool::ctor"); RegionTimer regt(timer); ProcessParameters(); if (domains.NumSet() == 0) return; topo.SetBuildVertex2Element(true); mesh.UpdateTopology(); old_segments = mesh.LineSegments(); have_single_segments = HaveSingleSegments(mesh); BuildSegments(mesh, have_single_segments, segments, free_segments); np = mesh.GetNP(); first_new_pi = IndexBASE() + np; ne = mesh.GetNE(); nse = mesh.GetNSE(); nseg = segments.Size(); p2sel = mesh.CreatePoint2SurfaceElementTable(); nfd_old = mesh.GetNFD(); moved_surfaces.SetSize(nfd_old + 1); moved_surfaces.Clear(); si_map.SetSize(nfd_old + 1); for (auto i : Range(nfd_old + 1)) si_map[i] = i; } void BoundaryLayerTool ::CreateNewFaceDescriptors () { surfacefacs.SetSize(nfd_old + 1); surfacefacs = 0.0; // create new FaceDescriptors for (auto i : Range(1, nfd_old + 1)) { const auto& fd = mesh.GetFaceDescriptor(i); string name = fd.GetBCName(); if (par_surfid.Contains(i)) { if (auto isIn = domains.Test(fd.DomainIn()); isIn != domains.Test(fd.DomainOut())) { int new_si = mesh.GetNFD() + 1; surfacefacs[i] = isIn ? 1. : -1.; moved_surfaces.SetBit(i); if (!insert_only_volume_elements) { // -1 surf nr is so that curving does not do anything FaceDescriptor new_fd(-1, isIn ? new_mat_nrs[i] : fd.DomainIn(), isIn ? fd.DomainOut() : new_mat_nrs[i], -1); new_fd.SetBCProperty(new_si); new_fd.SetSurfColour(fd.SurfColour()); mesh.AddFaceDescriptor(new_fd); si_map[i] = new_si; mesh.SetBCName(new_si - 1, "mapped_" + name); } } // curving of surfaces with boundary layers will often // result in pushed through elements, since we do not (yet) // curvature through layers. // Therefore we disable curving for these surfaces. if (params.disable_curving) mesh.GetFaceDescriptor(i).SetSurfNr(-1); } } for (auto si : par_surfid) if (surfacefacs[si] == 0.0) throw Exception("Surface " + to_string(si) + " is not a boundary of the domain to be grown into!"); } void BoundaryLayerTool ::CreateFaceDescriptorsSides () { if (insert_only_volume_elements) return; BitArray face_done(mesh.GetNFD() + 1); face_done.Clear(); for (const auto& sel : mesh.SurfaceElements()) { auto facei = sel.GetIndex(); if (face_done.Test(facei)) continue; bool point_moved = false; // bool point_fixed = false; for (auto pi : sel.PNums()) { if (growthvectors[pi].Length() > 0) point_moved = true; /* else point_fixed = true; */ } if (point_moved && !moved_surfaces.Test(facei)) { int new_si = mesh.GetNFD() + 1; const auto& fd = mesh.GetFaceDescriptor(facei); // auto isIn = domains.Test(fd.DomainIn()); // auto isOut = domains.Test(fd.DomainOut()); int si = params.sides_keep_surfaceindex ? facei : -1; // domin and domout can only be set later FaceDescriptor new_fd(si, -1, -1, si); new_fd.SetBCProperty(new_si); mesh.AddFaceDescriptor(new_fd); si_map[facei] = new_si; mesh.SetBCName(new_si - 1, fd.GetBCName()); face_done.SetBit(facei); } } } void BoundaryLayerTool ::CalculateGrowthVectors () { growthvectors.SetSize(np); growthvectors = 0.; for (auto pi : mesh.Points().Range()) { const auto& p = mesh[pi]; if (p.Type() == INNERPOINT) continue; std::map> normals; // calculate one normal vector per face (average with angles as weights for // multiple surface elements within a face) for (auto sei : p2sel[pi]) { const auto& sel = mesh[sei]; auto facei = sel.GetIndex(); if (!par_surfid.Contains(facei)) continue; auto n = surfacefacs[sel.GetIndex()] * getNormal(sel); int itrig = sel.PNums().Pos(pi); itrig += sel.GetNP(); auto v0 = (mesh[sel.PNumMod(itrig + 1)] - mesh[pi]).Normalize(); auto v1 = (mesh[sel.PNumMod(itrig - 1)] - mesh[pi]).Normalize(); if (normals.count(facei) == 0) normals[facei] = {0., 0., 0.}; normals[facei] += acos(v0 * v1) * n; } for (auto& [facei, n] : normals) n *= 1.0 / n.Length(); // combine normal vectors for each face to keep uniform distances ArrayMem, 5> ns; for (auto& [facei, n] : normals) { ns.Append(n); } try { growthvectors[pi] = CalcGrowthVector(ns); } catch (const SpecialPointException& e) { special_boundary_points.emplace(pi, normals); growthvectors[pi] = special_boundary_points[pi].growth_groups[0].growth_vector; } } } Array>, SegmentIndex> BoundaryLayerTool ::BuildSegMap () { // Bit array to keep track of segments already processed BitArray segs_done(nseg + 1); segs_done.Clear(); // map for all segments with same points // points to pair of SegmentIndex, int // int is type of other segment, either: // 0 == adjacent surface grows layer // 1 == adjacent surface doesn't grow layer, but layer ends on it // 2 == adjacent surface is interior surface that ends on layer // 3 == adjacent surface is exterior surface that ends on layer (not allowed // yet) Array>, SegmentIndex> segmap(segments.Size()); // moved segments is_edge_moved.SetSize(max_edge_nr + 1); is_edge_moved = false; // boundaries to project endings to is_boundary_projected.SetSize(nfd_old + 1); is_boundary_projected.Clear(); is_boundary_moved.SetSize(nfd_old + 1); is_boundary_moved.Clear(); for (auto si : Range(segments)) { if (segs_done[si]) continue; const auto& segi = segments[si]; if (!moved_surfaces.Test(segi.si)) continue; segs_done.SetBit(si); segmap[si].Append(make_pair(si, 0)); moved_segs.Append(si); is_edge_moved.SetBit(segi.index); for (auto sj : Range(segments)) { if (segs_done.Test(sj)) continue; const auto& segj = segments[sj]; if ((segi[0] == segj[0] && segi[1] == segj[1]) || (segi[0] == segj[1] && segi[1] == segj[0])) { segs_done.SetBit(sj); int type; if (moved_surfaces.Test(segj.si)) { type = 0; moved_segs.Append(sj); } else if (const auto& fd = mesh.GetFaceDescriptor(segj.si); domains.Test(fd.DomainIn()) && domains.Test(fd.DomainOut())) { type = 2; if (fd.DomainIn() == 0 || fd.DomainOut() == 0) is_boundary_projected.SetBit(segj.si); } else if (const auto& fd = mesh.GetFaceDescriptor(segj.si); !domains.Test(fd.DomainIn()) && !domains.Test(fd.DomainOut())) { type = 3; // cout << "set is_moved boundary to type 3 for " << segj.si << endl; is_boundary_moved.SetBit(segj.si); } else { type = 1; // in case 1 we project the growthvector onto the surface is_boundary_projected.SetBit(segj.si); } segmap[si].Append(make_pair(sj, type)); } } } return segmap; } BitArray BoundaryLayerTool ::ProjectGrowthVectorsOnSurface () { BitArray in_surface_direction(nfd_old + 1); in_surface_direction.Clear(); // project growthvector on surface for inner angles if (params.grow_edges) { for (const auto& sel : mesh.SurfaceElements()) if (is_boundary_projected.Test(sel.GetIndex())) { auto n = getNormal(sel); for (auto i : Range(sel.PNums())) { auto pi = sel.PNums()[i]; if (growthvectors[pi].Length2() == 0.) continue; auto next = sel.PNums()[(i + 1) % sel.GetNV()]; auto prev = sel.PNums()[i == 0 ? sel.GetNV() - 1 : i - 1]; auto v1 = (mesh[next] - mesh[pi]).Normalize(); auto v2 = (mesh[prev] - mesh[pi]).Normalize(); auto v3 = growthvectors[pi]; v3.Normalize(); auto tol = v1.Length() * 1e-12; if ((v1 * v3 > -tol) && (v2 * v3 > -tol)) in_surface_direction.SetBit(sel.GetIndex()); else continue; if (!par_project_boundaries.Contains(sel.GetIndex())) continue; auto& g = growthvectors[pi]; auto ng = n * g; auto gg = g * g; auto nn = n * n; // if(fabs(ng*ng-nn*gg) < 1e-12 || fabs(ng) < 1e-12) continue; auto a = -ng * ng / (ng * ng - nn * gg); auto b = ng * gg / (ng * ng - nn * gg); g += a * g + b * n; } } } else { for (const auto& seg : segments) { int count = 0; for (const auto& seg2 : segments) if (((seg[0] == seg2[0] && seg[1] == seg2[1]) || (seg[0] == seg2[1] && seg[1] == seg2[0])) && par_surfid.Contains(seg2.si)) count++; if (count == 1) { growthvectors[seg[0]] = {0., 0., 0.}; growthvectors[seg[1]] = {0., 0., 0.}; } } } return in_surface_direction; } void BoundaryLayerTool ::InsertNewElements ( FlatArray>, SegmentIndex> segmap, const BitArray& in_surface_direction) { static Timer timer("BoundaryLayerTool::InsertNewElements"); RegionTimer rt(timer); mapto.SetSize(0); mapto.SetSize(np); mapfrom.SetSize(mesh.GetNP()); mapfrom = PointIndex::INVALID; auto changed_domains = domains; if (!params.outside) changed_domains.Invert(); auto& identifications = mesh.GetIdentifications(); const int identnr = identifications.GetNr("boundarylayer"); auto add_points = [&] (PointIndex pi, Vec<3>& growth_vector, Array& new_points) { Point<3> p = mesh[pi]; PointIndex pi_last = pi; double height = 0.0; for (auto i : Range(par_heights)) { height += par_heights[i]; auto pi_new = mesh.AddPoint(p); // mesh.AddLockedPoint(pi_new); mapfrom.Append(pi); new_points.Append(pi_new); growth_vector_map[pi_new] = {&growth_vector, height}; // if (special_boundary_points.count(pi) > 0) // mesh.AddLockedPoint(pi_new); pi_last = pi_new; } }; // insert new points // for (PointIndex pi = 1; pi <= np; pi++) for (PointIndex pi = IndexBASE(); pi < IndexBASE() + np; pi++) { if (growthvectors[pi].Length2() != 0) { if (special_boundary_points.count(pi)) { for (auto& group : special_boundary_points[pi].growth_groups) add_points(pi, group.growth_vector, group.new_points); } else add_points(pi, growthvectors[pi], mapto[pi]); } } // get point from mapto (or the group if point is mapped to multiple new // points) layer = -1 means last point (top of boundary layer) auto newPoint = [&] (PointIndex pi, int layer = -1, int group = 0) { if (layer == -1) layer = par_heights.Size() - 1; if (special_boundary_points.count(pi)) return special_boundary_points[pi].growth_groups[group].new_points[layer]; else return mapto[pi][layer]; }; auto hasMoved = [&] (PointIndex pi) { return mapto[pi].Size() > 0 || special_boundary_points.count(pi); }; auto numGroups = [&] (PointIndex pi) -> size_t { if (special_boundary_points.count(pi)) return special_boundary_points[pi].growth_groups.Size(); else return 1; }; auto getGroups = [&] (PointIndex pi, int face_index) -> Array { auto n = numGroups(pi); Array groups; if (n == 1) { groups.Append(0); return groups; } const auto& all_groups = special_boundary_points[pi].growth_groups; for (auto i : Range(n)) if (all_groups[i].faces.Contains(face_index)) groups.Append(i); // cout << "groups " << pi << ", " << face_index << endl << groups; return groups; }; // add 2d quads on required surfaces map, int> seg2edge; map edge_map; int edge_nr = max_edge_nr; auto getIndex = [&] (int ei) { if (edge_map.count(ei) == 0) edge_map[ei] = ++edge_nr; return edge_map[ei]; }; if (params.grow_edges) { for (auto sei : moved_segs) { // copy here since we will add segments and this would // invalidate a reference! // auto segi = segments[sei]; for (auto [sej, type] : segmap[sei]) { auto segj = segments[sej]; if (type == 0) { auto addSegment = [&] (PointIndex p0, PointIndex p1, bool extra_edge_nr = false) { Segment s; s[0] = p0; s[1] = p1; s[2] = PointIndex::INVALID; [[maybe_unused]] auto pair = s[0] < s[1] ? make_pair(s[0], s[1]) : make_pair(s[1], s[0]); if (extra_edge_nr) s.index = ++edge_nr; else s.index = getIndex(segj.index); s.si = si_map[segj.si]; new_segments.Append(s); // cout << __LINE__ <<"\t" << s << endl; return s; }; auto p0 = segj[0], p1 = segj[1]; auto g0 = getGroups(p0, segj.si); auto g1 = getGroups(p1, segj.si); if (g0.Size() == 1 && g1.Size() == 1) { auto p0_new = newPoint(p0, -1, g0[0]); auto p1_new = newPoint(p1, -1, g1[0]); addSegment(p0_new, p1_new); } else { if (g0.Size() == 2) addSegment(newPoint(p0, -1, g0[0]), newPoint(p0, -1, g0[1])); if (g1.Size() == 2) addSegment(newPoint(p1, -1, g1[0]), newPoint(p1, -1, g1[1])); } } // here we need to grow the quad elements else if (type == 1) { PointIndex pp1 = segj[1]; PointIndex pp2 = segj[0]; if (in_surface_direction.Test(segj.si)) { Swap(pp1, pp2); is_boundary_moved.SetBit(segj.si); } PointIndex p1 = pp1; PointIndex p2 = pp2; PointIndex p3, p4; Segment s0; s0[0] = p1; s0[1] = p2; s0[2] = PointIndex::INVALID; s0.index = segj.index; s0.si = segj.si; new_segments.Append(s0); if (type == 3) new_segments_on_moved_bnd.Append(s0); for (auto i : Range(par_heights)) { Element2d sel(QUAD); p3 = newPoint(pp2, i); p4 = newPoint(pp1, i); sel[0] = p1; sel[1] = p2; sel[2] = p3; sel[3] = p4; for (auto i : Range(4)) { sel.GeomInfo()[i].u = 0.0; sel.GeomInfo()[i].v = 0.0; } identifications.Add(p1, p4, identnr); identifications.Add(p2, p3, identnr); sel.SetIndex(si_map[segj.si]); new_sels.Append(sel); new_sels_on_moved_bnd.Append(sel); // TODO: Too many, would be enough to only add outermost ones Segment s1; s1[0] = p2; s1[1] = p3; s1[2] = PointIndex::INVALID; auto pair = make_pair(p2, p3); s1.index = getIndex(segj.index); s1.si = segj.si; // new_segments.Append(s1); Segment s2; s2[0] = p4; s2[1] = p1; s2[2] = PointIndex::INVALID; pair = make_pair(p1, p4); s2.index = getIndex(segj.index); s2.si = segj.si; // new_segments.Append(s2); p1 = p4; p2 = p3; } Segment s3; s3[0] = p3; s3[1] = p4; s3[2] = PointIndex::INVALID; // auto pair = p3 < p4 ? make_pair(p3, p4) : make_pair(p4, p3); s3.index = getIndex(segj.index); s3.si = segj.si; new_segments.Append(s3); if (type == 3) new_segments_on_moved_bnd.Append(s0); } else if (type == 3) { PointIndex pp1 = segj[1]; PointIndex pp2 = segj[0]; if (!in_surface_direction.Test(segj.si)) { Swap(pp1, pp2); } PointIndex p1 = pp1; PointIndex p2 = pp2; PointIndex p3, p4; for (auto i : Range(par_heights)) { Element2d sel(QUAD); p3 = newPoint(pp2, i); p4 = newPoint(pp1, i); sel[0] = p1; sel[1] = p2; sel[2] = p3; sel[3] = p4; for (auto i : Range(4)) { sel.GeomInfo()[i].u = 0.0; sel.GeomInfo()[i].v = 0.0; } identifications.Add(p1, p4, identnr); identifications.Add(p2, p3, identnr); sel.SetIndex(si_map[segj.si]); new_sels.Append(sel); new_sels_on_moved_bnd.Append(sel); p1 = p4; p2 = p3; } } } } } auto getClosestGroup = [&] (PointIndex pi, SurfaceElementIndex sei) { auto n = numGroups(pi); if (n == 1) return 0; const auto& sel = mesh[sei]; auto groups = getGroups(pi, sel.GetIndex()); if (groups.Size() == 1) return groups[0]; // auto& growth_groups = special_boundary_points[pi].growth_groups; auto vdir = Center(mesh[sel[0]], mesh[sel[1]], mesh[sel[2]]) - mesh[pi]; auto dot = vdir * special_boundary_points[pi].separating_direction; return dot > 0 ? 1 : 0; }; BitArray fixed_points(np + 1); fixed_points.Clear(); auto p2el = mesh.CreatePoint2ElementTable(); for (SurfaceElementIndex si = 0; si < nse; si++) { const auto sel = mesh[si]; const auto iface = sel.GetIndex(); if (moved_surfaces.Test(iface)) { const auto np = sel.GetNP(); ArrayMem points(sel.PNums()); if (surfacefacs[iface] > 0) Swap(points[0], points[2]); ArrayMem groups(points.Size()); for (auto i : Range(points)) groups[i] = getClosestGroup(points[i], si); bool add_volume_element = true; for (auto pi : points) if (numGroups(pi) > 1) add_volume_element = false; Element el(2 * np); el.PNums().Range(np, 2 * np) = points; auto new_index = new_mat_nrs[iface]; if (new_index == -1) throw Exception("Boundary " + ToString(iface) + " with name " + mesh.GetBCName(iface - 1) + " extruded, but no new material specified for it!"); el.SetIndex(new_index); for (auto j : Range(par_heights)) { el.PNums().Range(0, np) = el.PNums().Range(np, 2 * np); for (auto i : Range(np)) el[np + i] = newPoint(points[i], j, groups[i]); if (add_volume_element) mesh.AddVolumeElement(el); else { // Let the volume mesher fill the hole with pyramids/tets // To insert pyramids, we need close surface identifications on open quads for (auto i : Range(np)) if (numGroups(el[i]) == 1) { auto pi0 = el[i]; auto pi1 = el[np + i]; auto nr = identifications.Get(pi0, pi1); if (nr == 0) identifications.Add(pi0, pi1, identnr); } } } Element2d newel = sel; for (auto i : Range(np)) newel[i] = newPoint(points[i], -1, groups[i]); if (surfacefacs[iface] > 0) Swap(newel[0], newel[2]); // swap back newel.SetIndex(si_map[iface]); new_sels.Append(newel); } if (is_boundary_moved.Test(iface)) { auto& sel = mesh[si]; for (auto& p : sel.PNums()) if (hasMoved(p)) p = newPoint(p); } } for (SegmentIndex sei = 0; sei < nseg; sei++) { auto& seg = segments[sei]; if (is_boundary_moved.Test(seg.si)) { // cout << "moved setg " << seg << endl; for (auto& p : seg.PNums()) if (hasMoved(p)) { p = newPoint(p); if (params.disable_curving) seg.SetEdgeNr(-1); } } } // fill holes in surface mesh at special boundary points (i.e. points with >=4 // adjacent boundary faces) auto p2sel = ngcore::CreateSortedTable( new_sels.Range(), [&] (auto& table, SurfaceElementIndex ei) { for (PointIndex pi : new_sels[ei].PNums()) table.Add(pi, ei); }, mesh.GetNP()); for (auto& [special_pi, special_point] : special_boundary_points) { if (special_point.growth_groups.Size() != 2) throw Exception("special_point.growth_groups.Size() != 2"); // Special points are split into two new points, when mapping a surface // element, we choose the closer one to the center. Now, find points which // are mapped to both new points (for different surface elements they belong // to). At exactly these points we need to insert new surface elements to // fill the hole. std::map, 2>> close_group; for (auto sei : p2sel[special_pi]) { const auto& sel = mesh[sei]; for (auto p : sel.PNums()) if (p != special_pi) close_group[sel.GetIndex()][getClosestGroup(special_pi, sei)].insert( p); } for (auto [fi, groups] : close_group) { const auto mapped_fi = si_map[fi]; std::set common_points; for (auto pi : groups[0]) if (groups[1].count(pi) == 1) common_points.insert(pi); if (common_points.size() > 0) { auto pi_common = mapto[*common_points.begin()].Last(); auto new_special_pi0 = special_point.growth_groups[0].new_points.Last(); auto new_special_pi1 = special_point.growth_groups[1].new_points.Last(); for (auto sei : p2sel[pi_common]) { if (mesh[sei].GetIndex() == mapped_fi && mesh[sei].PNums().Contains(new_special_pi0)) { auto sel = mesh[sei]; sel.Invert(); for (auto& pi : sel.PNums()) if (pi != pi_common && pi != new_special_pi0) pi = new_special_pi1; new_sels.Append(sel); } } } } } for (auto& [pi, special_point] : special_boundary_points) { if (special_point.growth_groups.Size() != 2) throw Exception("special_point.growth_groups.Size() != 2"); for (auto igroup : Range(2)) { auto& group = special_point.growth_groups[igroup]; std::set faces; for (auto face : group.faces) faces.insert(si_map[face]); auto pi_new = group.new_points.Last(); auto pi_new_other = special_point.growth_groups[1 - igroup].new_points.Last(); for (auto sei : p2sel[pi_new]) faces.erase(mesh[sei].GetIndex()); for (auto face : faces) for (auto seg : new_segments) { if ( // seg.si == face (seg[0] == pi_new || seg[1] == pi_new) && (seg[0] != pi_new_other && seg[1] != pi_new_other)) { bool is_correct_face = false; auto pi_other = seg[0] == pi_new ? seg[1] : seg[0]; for (auto sei : p2sel[pi_other]) { if (mesh[sei].GetIndex() == face) { is_correct_face = true; break; } } if (is_correct_face) { Element2d sel; sel[0] = seg[1]; sel[1] = seg[0]; sel[2] = pi_new_other; sel.SetIndex(face); new_sels.Append(sel); } } } } } } void BoundaryLayerTool ::SetDomInOut () { if (insert_only_volume_elements) return; for (auto i : Range(1, nfd_old + 1)) if (moved_surfaces.Test(i)) { if (auto dom = mesh.GetFaceDescriptor(si_map[i]).DomainIn(); dom > ndom_old) mesh.GetFaceDescriptor(i).SetDomainOut(dom); else mesh.GetFaceDescriptor(i).SetDomainIn( mesh.GetFaceDescriptor(si_map[i]).DomainOut()); } } void BoundaryLayerTool ::SetDomInOutSides () { // Set the domin/domout entries for face descriptors on the "side" of new boundary layers if (insert_only_volume_elements) return; BitArray done(mesh.GetNFD() + 1); done.Clear(); std::map inv_si_map; for (auto i : Range(si_map.Size())) inv_si_map[si_map[i]] = i; for (auto sei : Range(mesh.SurfaceElements())) { auto& sel = mesh[sei]; auto index = sel.GetIndex(); if (done.Test(index)) continue; done.SetBit(index); if (index < nfd_old && moved_surfaces.Test(index)) continue; auto& fd = mesh.GetFaceDescriptor(index); if (fd.DomainIn() != -1) continue; // First check if there are adjacent volume elements, if so, use their domains int e1 = 0, e2 = 0; mesh.GetTopology().GetSurface2VolumeElement(sei + 1, e1, e2); int dom[2] = {-1, -1}; if (e1) dom[0] = mesh.VolumeElement(e1).GetIndex(); if (e2) dom[1] = mesh.VolumeElement(e2).GetIndex(); const auto& fd_old = mesh.GetFaceDescriptor(inv_si_map[index]); int dom_old[2] = {fd_old.DomainIn(), fd_old.DomainOut()}; for (auto i : Range(2)) { if (dom[i] != -1) continue; // adjacent volume element -> done if (dom_old[i] == 0) { // outer boundary -> keep 0 dom[i] = 0; continue; } // Check if the old domain adjacent to this face gets a new boundary layer domain, if so, use that number int dom_new = dom_old[i]; if (domains.Test(dom_old[i]) && new_mat_nrs[dom_old[i]] > 0) dom_new = new_mat_nrs[dom_old[i]]; // This case is tested by test_boundarylayer.py::test_pyramids[False] -> look at the generated mesh to understand the text below :) // Special case check here: when growing "outside" the new face could have the same domain on both sides (before adding blayer elements). // Thus we don't know in advance on which side the mapped domain will be. So check, if the other domain has already prisms (adjacent vol elements) with mapped domain. If so, use the original domain instead. if (dom[1 - i] != dom_new) { dom[i] = dom_new; } else { dom[i] = dom_old[i]; } } fd.SetDomainIn(dom[0]); fd.SetDomainOut(dom[1]); } } void BoundaryLayerTool ::AddSegments () { if (insert_only_volume_elements) { if (params.disable_curving) { auto is_mapped = [&] (PointIndex pi) { return pi >= mapto.Range().Next() || mapto[pi].Size() > 0; }; for (auto& seg : old_segments) if (is_mapped(seg[0]) || is_mapped(seg[1])) seg.SetEdgeNr(-1); } } auto& new_segs = insert_only_volume_elements ? new_segments_on_moved_bnd : new_segments; if (params.disable_curving) { auto is_mapped = [&] (PointIndex pi) { return pi >= mapto.Range().Next() || mapto[pi].Size() > 0; }; for (auto& seg : segments) if (is_mapped(seg[0]) || is_mapped(seg[1])) seg.SetEdgeNr(-1); for (auto& seg : segments) if (is_edge_moved[seg.index]) seg.SetEdgeNr(-1); for (auto& seg : new_segs) seg.SetEdgeNr(-1); } if (have_single_segments) MergeAndAddSegments(mesh, segments, new_segs); else { mesh.LineSegments() = segments; for (auto& seg : new_segs) mesh.AddSegment(seg); } for (auto& seg : free_segments) mesh.AddSegment(seg); } void BoundaryLayerTool ::AddSurfaceElements () { for (auto& sel : insert_only_volume_elements ? new_sels_on_moved_bnd : new_sels) mesh.AddSurfaceElement(sel); } void BoundaryLayerTool ::ProcessParameters () { if (int* bc = get_if(¶ms.boundary); bc) { for (int i = 1; i <= mesh.GetNFD(); i++) if (mesh.GetFaceDescriptor(i).BCProperty() == *bc) par_surfid.Append(i); } else if (string* s = get_if(¶ms.boundary); s) { regex pattern(*s); BitArray boundaries(mesh.GetNFD() + 1); boundaries.Clear(); for (int i = 1; i <= mesh.GetNFD(); i++) { auto& fd = mesh.GetFaceDescriptor(i); if (regex_match(fd.GetBCName(), pattern)) { boundaries.SetBit(i); auto dom_pattern = get_if(¶ms.domain); // only add if adjacent to domain if (dom_pattern) { regex pattern(*dom_pattern); bool mat1_match = fd.DomainIn() > 0 && regex_match(mesh.GetMaterial(fd.DomainIn()), pattern); bool mat2_match = fd.DomainOut() > 0 && regex_match(mesh.GetMaterial(fd.DomainOut()), pattern); // if boundary is inner or outer remove from list if (mat1_match == mat2_match) boundaries.Clear(i); // if((fd.DomainIn() > 0 && // regex_match(mesh.GetMaterial(fd.DomainIn()), pattern)) || // (fd.DomainOut() > 0 && // regex_match(self.GetMaterial(fd.DomainOut()), pattern))) // boundaries.Clear(i); // par_surfid.Append(i); } // else // par_surfid.Append(i); } } for (int i = 1; i <= mesh.GetNFD(); i++) if (boundaries.Test(i)) par_surfid.Append(i); } else { auto& surfids = *get_if>(¶ms.boundary); for (auto id : surfids) par_surfid.Append(id); } insert_only_volume_elements = !params.new_material.has_value(); if (params.new_material) { if (string* mat = get_if(&*params.new_material); mat) par_new_mat = {{".*", *mat}}; else { par_new_mat = *get_if>(&*params.new_material); have_material_map = true; } } if (params.project_boundaries.has_value()) { auto proj_bnd = *params.project_boundaries; if (string* s = get_if(&proj_bnd); s) { regex pattern(*s); for (int i = 1; i <= mesh.GetNFD(); i++) if (regex_match(mesh.GetFaceDescriptor(i).GetBCName(), pattern)) par_project_boundaries.Append(i); } else { for (auto id : *get_if>(&proj_bnd)) par_project_boundaries.Append(id); } } if (double* height = get_if(¶ms.thickness); height) { par_heights.Append(*height); } else { auto& heights = *get_if>(¶ms.thickness); for (auto val : heights) par_heights.Append(val); } int nr_domains = mesh.GetNDomains(); domains.SetSize(nr_domains + 1); // one based domains.Clear(); if (string* pdomain = get_if(¶ms.domain); pdomain) { regex pattern(*pdomain); for (auto i : Range(1, nr_domains + 1)) if (regex_match(mesh.GetMaterial(i), pattern)) domains.SetBit(i); } else if (int* idomain = get_if(¶ms.domain); idomain) { domains.SetBit(*idomain); } else { for (auto i : *get_if>(¶ms.domain)) domains.SetBit(i); } if (domains.NumSet() == 0) return; total_height = 0.0; for (auto h : par_heights) total_height += h; max_edge_nr = -1; for (const auto& seg : mesh.LineSegments()) if (seg.index > max_edge_nr) max_edge_nr = seg.index; int ndom = mesh.GetNDomains(); ndom_old = ndom; new_mat_nrs.SetSize(mesh.FaceDescriptors().Size() + 1); new_mat_nrs = -1; if (insert_only_volume_elements) { for (auto i : Range(1, mesh.GetNFD() + 1)) { auto& fd = mesh.GetFaceDescriptor(i); auto domin = fd.DomainIn(); auto domout = fd.DomainOut(); for (int dom : {domin, domout}) if (domains.Test(dom)) { if (params.outside) { dom = domin + domout - dom; if (dom == 0) throw NG_EXCEPTION("No new material specified for boundarylayer " "on the outside of domain"); } new_mat_nrs[i] = dom; } } } else { for (auto [bcname, matname] : par_new_mat) { mesh.SetMaterial(++ndom, matname); regex pattern(bcname); for (auto i : Range(1, mesh.GetNFD() + 1)) { auto& fd = mesh.GetFaceDescriptor(i); if (regex_match(fd.GetBCName(), pattern)) new_mat_nrs[i] = ndom; } } } if (!params.outside) domains.Invert(); } void BoundaryLayerTool ::Perform () { if (domains.NumSet() == 0) return; CreateNewFaceDescriptors(); CalculateGrowthVectors(); CreateFaceDescriptorsSides(); auto segmap = BuildSegMap(); auto in_surface_direction = ProjectGrowthVectorsOnSurface(); InsertNewElements(segmap, in_surface_direction); SetDomInOut(); AddSegments(); mesh.CalcSurfacesOfNode(); topo.SetBuildVertex2Element(true); mesh.UpdateTopology(); InterpolateGrowthVectors(); InterpolateSurfaceGrowthVectors(); AddSurfaceElements(); if (params.limit_growth_vectors) LimitGrowthVectorLengths(); FixSurfaceElements(); for (auto [pi, data] : growth_vector_map) { auto [gw, height] = data; mesh[pi] += height * (*gw); } auto& identifications = mesh.GetIdentifications(); NgArray pairs; for (auto nr : Range(0, identifications.GetMaxNr() + 1)) { identifications.GetPairs(nr, pairs); for (auto pair : pairs) { auto p0 = pair[0]; auto p1 = pair[1]; if (max(p0, p1) < first_new_pi && mapto[p0].Size() && mapto[p1].Size()) for (auto i : Range(mapto[p0].Size())) identifications.Add(mapto[p0][i], mapto[p1][i], nr); } } // there is still a bug with segment edge numbers in moved boundaries. // As a workaround, don't add them at all if only volume elements are inserted if (insert_only_volume_elements) mesh.LineSegments() = old_segments; mesh.CalcSurfacesOfNode(); mesh.GetTopology().ClearEdges(); mesh.SetNextMajorTimeStamp(); mesh.UpdateTopology(); SetDomInOutSides(); if (have_material_map) { AddFacesBetweenDomains(mesh); mesh.SplitFacesByAdjacentDomains(); } } void GenerateBoundaryLayer (Mesh& mesh, const BoundaryLayerParameters& blp) { static Timer timer("Create Boundarylayers"); RegionTimer regt(timer); BoundaryLayerTool tool(mesh, blp); tool.Perform(); } } // namespace netgen ================================================ FILE: libsrc/meshing/boundarylayer.hpp ================================================ #ifndef NETGEN_BOUNDARYLAYER_HPP #define NETGEN_BOUNDARYLAYER_HPP #include #include #include namespace netgen { /// DLL_HEADER extern void InsertVirtualBoundaryLayer (Mesh& mesh); /// Create a typical prismatic boundary layer on the given /// surfaces struct SpecialBoundaryPoint { struct GrowthGroup { Array faces; Vec<3> growth_vector; Array new_points; GrowthGroup (FlatArray faces_, FlatArray> normals); GrowthGroup (const GrowthGroup&) = default; GrowthGroup () = default; }; Array growth_groups; Vec<3> separating_direction; SpecialBoundaryPoint (const std::map>& normals); SpecialBoundaryPoint () = default; }; DLL_HEADER void GenerateBoundaryLayer (Mesh& mesh, const BoundaryLayerParameters& blp); DLL_HEADER int /* new_domain_number */ GenerateBoundaryLayer2 (Mesh& mesh, int domain, const Array& thicknesses, bool should_make_new_domain = true, const Array& boundaries = Array{}); class BoundaryLayerTool { public: BoundaryLayerTool (Mesh& mesh_, const BoundaryLayerParameters& params_); void ProcessParameters (); void Perform (); Mesh& mesh; MeshTopology& topo; BoundaryLayerParameters params; Array, PointIndex> growthvectors; std::map> non_bl_growth_vectors; Table p2sel; BitArray domains, is_edge_moved, is_boundary_projected, is_boundary_moved; Array moved_segs; int max_edge_nr, nfd_old, ndom_old; Array new_mat_nrs; BitArray moved_surfaces; int np, nseg, nse, ne; PointIndex first_new_pi; double total_height; Array point_types; // These parameters are derived from given BoundaryLayerParameters and the Mesh Array par_heights; Array par_surfid; bool insert_only_volume_elements; map par_new_mat; bool have_material_map = false; Array par_project_boundaries; bool have_single_segments; Array old_segments, free_segments, segments, new_segments, new_segments_on_moved_bnd; Array new_sels, new_sels_on_moved_bnd; Array, PointIndex> mapto; Array mapfrom; Array surfacefacs; Array si_map; std::map special_boundary_points; std::map*, double>> growth_vector_map; // major steps called in Perform() void CreateNewFaceDescriptors (); void CreateFaceDescriptorsSides (); void CalculateGrowthVectors (); Array>, SegmentIndex> BuildSegMap (); BitArray ProjectGrowthVectorsOnSurface (); void InterpolateSurfaceGrowthVectors (); void InterpolateGrowthVectors (); void LimitGrowthVectorLengths (); void FixSurfaceElements (); void InsertNewElements (FlatArray>, SegmentIndex> segmap, const BitArray& in_surface_direction); void SetDomInOut (); void SetDomInOutSides (); void AddSegments (); void AddSurfaceElements (); Vec<3> getNormal (const Element2d& el) { auto v0 = mesh[el[0]]; return Cross(mesh[el[1]] - v0, mesh[el[2]] - v0).Normalize(); } Vec<3> getEdgeTangent (PointIndex pi, int edgenr, FlatArray segs); }; } // namespace netgen #endif // NETGEN_BOUNDARYLAYER_HPP ================================================ FILE: libsrc/meshing/boundarylayer2d.cpp ================================================ #include #include "boundarylayer.hpp" #include "meshing2.hpp" #include "../geom2d/csg2d.hpp" namespace netgen { void InsertVirtualBoundaryLayer (Mesh & mesh) { cout << "Insert virt. b.l." << endl; int surfid; cout << "Boundary Nr:"; cin >> surfid; int i; int np = mesh.GetNP(); cout << "Old NP: " << mesh.GetNP() << endl; cout << "Trigs: " << mesh.GetNSE() << endl; NgBitArray bndnodes(np); NgArray 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 (int 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; } void AddDirection( Vec<3> & a, Vec<3> b ) { if(a.Length2()==0.) { a = b; return; } if(b.Length2()==0.) return; auto ab = a * b; if(fabs(ab)>1-1e-8) return; Mat<2> m; m(0,0) = a[0]; m(0,1) = a[1]; m(1,0) = b[0]; m(1,1) = b[1]; Vec<2> lam; Vec<2> rhs; rhs[0] = a[0]-b[0]; rhs[1] = a[1]-b[1]; const auto Dot = [](Vec<3> a, Vec<3> b) { return a[0]*b[0] + a[1]*b[1] + a[2]*b[2]; }; rhs[0] = Dot(a,a); rhs[1] = Dot(b,b); m.Solve(rhs, lam); a[0] = lam[0]; a[1] = lam[1]; a[2] = 0.0; return; } static void Generate2dMesh( Mesh & mesh, int domain ) { Box<3> box{Box<3>::EMPTY_BOX}; for(const auto & seg : mesh.LineSegments()) if (seg.domin == domain || seg.domout == domain) for (auto pi : {seg[0], seg[1]}) box.Add(mesh[pi]); MeshingParameters mp; Meshing2 meshing (*mesh.GetGeometry(), mp, box); Array compress(mesh.GetNP()); compress = PointIndex::INVALID; PointIndex cnt = PointIndex::BASE; auto p2sel = mesh.CreatePoint2SurfaceElementTable(); PointGeomInfo gi; gi.u = 0.0; gi.v = 0.0; gi.trignum = domain; for(auto seg : mesh.LineSegments()) { if(seg.domin == domain || seg.domout == domain) for (auto pi : {seg[0], seg[1]}) if (compress[pi]==PointIndex{PointIndex::INVALID}) { meshing.AddPoint(mesh[pi], pi); compress[pi] = cnt++; } if(seg.domin == domain) meshing.AddBoundaryElement (compress[seg[0]], compress[seg[1]], gi, gi); if(seg.domout == domain) meshing.AddBoundaryElement (compress[seg[1]], compress[seg[0]], gi, gi); } auto oldnf = mesh.GetNSE(); // auto res = meshing.GenerateMesh (mesh, mp, mp.maxh, domain); for (SurfaceElementIndex sei : Range(oldnf, mesh.GetNSE())) mesh[sei].SetIndex (domain); // int hsteps = mp.optsteps2d; const char * optstr = mp.optimize2d.c_str(); MeshOptimize2d meshopt(mesh); meshopt.SetFaceIndex(domain); meshopt.SetMetricWeight (mp.elsizeweight); for (size_t j = 1; j <= strlen(optstr); j++) { switch (optstr[j-1]) { case 's': { // topological swap meshopt.EdgeSwapping (0); break; } case 'S': { // metric swap meshopt.EdgeSwapping (1); break; } case 'm': { meshopt.ImproveMesh(mp); break; } case 'c': { meshopt.CombineImprove(); break; } default: cerr << "Optimization code " << optstr[j-1] << " not defined" << endl; } } mesh.Compress(); mesh.CalcSurfacesOfNode(); mesh.OrderElements(); mesh.SetNextMajorTimeStamp(); } int GenerateBoundaryLayer2 (Mesh & mesh, int domain, const Array & thicknesses, bool should_make_new_domain, const Array & boundaries) { mesh.GetTopology().SetBuildVertex2Element(true); mesh.UpdateTopology(); const auto & line_segments = mesh.LineSegments(); SegmentIndex first_new_seg = mesh.LineSegments().Range().Next(); int np = mesh.GetNP(); int nseg = line_segments.Size(); // int ne = mesh.GetNSE(); mesh.UpdateTopology(); double total_thickness = 0.0; for(auto thickness : thicknesses) total_thickness += thickness; Array, PointIndex> mapto(np); // Bit array to keep track of segments already processed BitArray segs_done(nseg); segs_done.Clear(); // moved segments Array moved_segs; Array, PointIndex> growthvectors(np); growthvectors = 0.; auto & meshtopo = mesh.GetTopology(); Array segments; // int fd_old = mesh.GetNFD(); int max_edge_nr = -1; int max_domain = -1; for(const auto& seg : line_segments) { if(seg.edgenr > max_edge_nr) max_edge_nr = seg.edgenr; if(seg.domin > max_domain) max_domain = seg.domin; if(seg.domout > max_domain) max_domain = seg.domout; } int new_domain = max_domain+1; int new_edge_nr = max_edge_nr+1; BitArray active_boundaries(max_edge_nr+1); BitArray active_segments(nseg); active_boundaries.Clear(); active_segments.Clear(); if(boundaries.Size() == 0) active_boundaries.Set(); else for(auto edgenr : boundaries) active_boundaries.SetBit(edgenr); for(auto segi : Range(line_segments)) { const auto seg = line_segments[segi]; if(active_boundaries.Test(seg.epgeominfo[0].edgenr) && (seg.domin==domain || seg.domout==domain)) active_segments.SetBit(segi); } { FaceDescriptor new_fd(0, 0, 0, -1); new_fd.SetBCProperty(new_domain); // int new_fd_index = mesh.AddFaceDescriptor(new_fd); if(should_make_new_domain) { mesh.SetMaterial(new_domain, "layer_" + mesh.GetMaterial(domain)); mesh.SetBCName(new_edge_nr - 1, "moved"); } } for(auto segi : Range(line_segments)) { if(segs_done[segi]) continue; segs_done.SetBit(segi); const auto& seg = line_segments[segi]; if(seg.domin != domain && seg.domout != domain) continue; if(!active_boundaries.Test(seg.epgeominfo[0].edgenr)) continue; moved_segs.Append(segi); } // calculate growth vectors (average normal vectors of adjacent segments at each point) for (auto si : moved_segs) { auto & seg = line_segments[si]; auto n = mesh[seg[1]] - mesh[seg[0]]; n = {-n[1], n[0], 0}; n.Normalize(); if(seg.domout == domain) n = -n; AddDirection(growthvectors[seg[0]], n); AddDirection(growthvectors[seg[1]], n); } ////////////////////////////////////////////////////////////////////////// // average growthvectors along straight lines to avoid overlaps in corners BitArray points_done(np+1); points_done.Clear(); for(auto si : moved_segs) { auto current_seg = line_segments[si]; auto current_si = si; auto first = current_seg[0]; PointIndex current(PointIndex::INVALID); auto next = current_seg[1]; if(points_done.Test(first)) continue; Array chain; chain.Append(first); // first find closed loops of segments while(next != current && next != first) { current = next; points_done.SetBit(current); chain.Append(current); for(auto sj : meshtopo.GetVertexSegments( current )) { if(!active_segments.Test(sj)) continue; if(sj!=current_si) { current_si = sj; current_seg = mesh[sj]; next = current_seg[0]-current + current_seg[1]; break; } } } auto ifirst = 0; auto n = chain.Size(); // angle of adjacent segments at points a[i-1], a[i], a[i+1] auto getAngle = [&mesh, &growthvectors] (FlatArray a, size_t i) { auto n = a.Size(); auto v0 = growthvectors[a[(i+n-1)%n]]; auto v1 = growthvectors[a[i]]; auto v2 = growthvectors[a[(i+1)%n]]; auto p0 = mesh[a[(i+n-1)%n]]; auto p1 = mesh[a[i]]; auto p2 = mesh[a[(i+1)%n]]; v0 = p1-p0; v1 = p2-p1; auto angle = abs(atan2(v1[0], v1[1]) - atan2(v0[0], v0[1])); if(angle>M_PI) angle = 2*M_PI-angle; return angle; }; // find first corner point while(getAngle(chain, ifirst) < 1e-5 ) ifirst = (ifirst+1)%n; // Copy points of closed loop in correct order, starting with a corner Array pis(n+1); pis.Range(0, n-ifirst) = chain.Range(ifirst, n); pis.Range(n-ifirst, n) = chain.Range(0, n-ifirst); pis[n] = pis[0]; Array lengths(n); for(auto i : Range(n)) lengths[i] = (mesh[pis[(i+1)%n]] - mesh[pis[i]]).Length(); auto averageGrowthVectors = [&] (size_t first, size_t last) { if(first+1 >= last) return; double total_len = 0.0; for(auto l : lengths.Range(first, last)) total_len += l; double len = lengths[first]; auto v0 = growthvectors[pis[first]]; auto v1 = growthvectors[pis[last]]; for(auto i : Range(first+1, last)) { auto pi = pis[i]; growthvectors[pi] = (len/total_len)*v1 + (1.0-len/total_len)*v0; len += lengths[i]; } }; auto icurrent = 0; while(icurrent average growth vectors between end points if(icurrent!=ilast) averageGrowthVectors(icurrent, ilast); icurrent = ilast; } } ////////////////////////////////////////////////////////////////////// // reduce growthvectors where necessary to avoid overlaps/slim regions const auto getSegmentBox = [&] (SegmentIndex segi) { PointIndex pi0=mesh[segi][0], pi1=mesh[segi][1]; Box<3> box( mesh[pi0], mesh[pi1] ); box.Add( mesh[pi0]+growthvectors[pi0] ); box.Add( mesh[pi1]+growthvectors[pi1] ); return box; }; Array growth(np); growth = 1.0; const auto Dot = [](auto a, auto b) { return a[0]*b[0] + a[1]*b[1] + a[2]*b[2]; }; const auto restrictGrowthVectors = [&] (SegmentIndex segi0, SegmentIndex segi1) { if(!active_segments.Test(segi0)) return; const auto & seg0 = mesh[segi0]; const auto & seg1 = mesh[segi1]; if( (seg0.domin != domain && seg0.domout != domain) || (seg1.domin != domain && seg1.domout != domain) ) return; if(segi0 == segi1) return; if(seg0[0]==seg1[0] || seg0[0]==seg1[1] || seg0[1]==seg1[0] || seg0[1] == seg1[1]) return; auto n = mesh[seg0[0]] - mesh[seg0[1]]; n = {-n[1], n[0], 0}; n.Normalize(); if(Dot(n, growthvectors[seg0[0]])<0) n = -n; if(Dot(n, growthvectors[seg0[1]])<0) n = -n; auto n1 = mesh[seg1[0]] - mesh[seg1[1]]; n1 = {-n1[1], n1[0], 0}; n1.Normalize(); if(Dot(n1, growthvectors[seg1[0]])<0) n1 = -n; if(Dot(n1, growthvectors[seg1[1]])<0) n1 = -n; auto p10 = mesh[seg1[0]]; auto p11 = mesh[seg1[1]]; for ( auto pi : {seg0[0], seg0[1]} ) { if(growthvectors[pi].Length2() == 0.0) continue; PointIndex pi1 = seg0[0] - pi + seg0[1]; auto p1 = mesh[pi1]; auto p = mesh[pi]; Point<3> points[] = { p10, p11, p10+total_thickness*growthvectors[seg1[0]], p11+total_thickness*growthvectors[seg1[1]], p1+total_thickness*growthvectors[pi1] }; Vec<3> gn{ growthvectors[pi][1], -growthvectors[pi][0], 0.0 }; if(Dot(gn, p1-p) < 0) gn = -gn; double d0 = Dot(gn, p); double d1 = Dot(gn, p1); if(d0>d1) Swap(d0,d1); bool all_left=true, all_right=true; for (auto i: Range(4)) { auto p_other = points[i]; auto dot = Dot(gn,p_other); if(dot>d0) all_left = false; if(dot points[] = { p10, p10+t*growthvectors[seg1[0]], p11, p11+t*growthvectors[seg1[1]] }; auto p0 = mesh[pi]; auto p1 = p0 + t*growthvectors[pi]; auto P2 = [](Point<3> p) { return Point<2>{p[0], p[1]}; }; ArrayMem, 4> intersections; double alpha, beta; auto checkIntersection = [] (Point<2> p0, Point<2> p1, Point<2> q0, Point<2> q1, double & alpha, double & beta) { auto intersection_type = intersect( p0, p1, q0, q1, alpha, beta ); return intersection_type == X_INTERSECTION || intersection_type == T_INTERSECTION_P || intersection_type == T_INTERSECTION_Q; }; if(checkIntersection( P2(p0), P2(p1), P2(points[0]), P2(points[2]), alpha, beta )) intersections.Append({alpha, 0.0}); if(checkIntersection( P2(p0), P2(p1), P2(points[1]), P2(points[3]), alpha, beta )) intersections.Append({alpha, 1.0}); if(checkIntersection( P2(p0), P2(p1), P2(points[0]), P2(points[1]), alpha, beta )) intersections.Append({alpha, beta}); if(checkIntersection( P2(p0), P2(p1), P2(points[2]), P2(points[3]), alpha, beta )) intersections.Append({alpha, beta}); QuickSort(intersections); for(auto [alpha,beta] : intersections) { if(!active_segments.Test(segi1)) growth[pi] = min(growth[pi], alpha); else { double mean = 0.5*(alpha+beta); growth[pi] = min(growth[pi], mean); growth[seg1[0]] = min(growth[seg1[0]], mean); growth[seg1[1]] = min(growth[seg1[1]], mean); } } } } }; Box<3> box(Box<3>::EMPTY_BOX); for (auto segi : Range(mesh.LineSegments())) { auto segbox = getSegmentBox( segi ); box.Add(segbox.PMin()); box.Add(segbox.PMax()); } BoxTree<3> segtree(box); for (auto segi : Range(mesh.LineSegments())) { auto p2 = [](Point<3> p) { return Point<2>{p[0], p[1]}; }; auto seg = line_segments[segi]; double alpha=0.0; double beta=0.0; if (intersect(p2(mesh[seg[0]]), p2(mesh[seg[0]] + total_thickness * growthvectors[seg[0]]), p2(mesh[seg[1]]), p2(mesh[seg[1]] + total_thickness * growthvectors[seg[1]]), alpha, beta)) { if (beta > 0 && alpha > 0 && alpha < 1.1) growth[seg[0]] = min(growth[seg[0]], 0.8 * alpha); if (alpha > 0 && beta > 0 && beta < 1.1) growth[seg[1]] = min(growth[seg[1]], 0.8 * beta); } for (auto segj : Range(mesh.LineSegments())) if(segi!=segj) restrictGrowthVectors(segi, segj); } for( auto pi : Range(growthvectors)) growthvectors[pi] *= growth[pi]; // insert new points for(PointIndex pi : Range(mesh.Points())) if(growthvectors[pi].Length2()!=0) { auto & pnew = mapto[pi]; auto dist = 0.0; for(auto t : thicknesses) { dist+=t; pnew.Append( mesh.AddPoint( mesh[pi] + dist*growthvectors[pi] ) ); mesh[pnew.Last()].SetType(FIXEDPOINT); } } // insert new elements ( and move old ones ) for(auto si : moved_segs) { auto seg = line_segments[si]; bool swap = false; auto & pm0 = mapto[seg[0]]; auto & pm1 = mapto[seg[1]]; Segment s = seg; s.geominfo[0] = {}; s.geominfo[1] = {}; s[0] = pm0.Last(); s[1] = pm1.Last(); s[2] = PointIndex::INVALID; // auto pair = s[0] < s[1] ? make_pair(s[0], s[1]) : make_pair(s[1], s[0]); s.edgenr = new_edge_nr; s.epgeominfo[0].edgenr = -1; s.epgeominfo[1].edgenr = -1; s.si = s.edgenr; mesh.AddSegment(s); for ( auto i : Range(thicknesses)) { PointIndex pi0, pi1, pi2, pi3; if(i==0) { pi0 = seg[0]; pi1 = seg[1]; } else { pi0 = pm0[i-1]; pi1 = pm1[i-1]; } pi2 = pm1[i]; pi3 = pm0[i]; if(i==0) { auto p0 = mesh[pi0]; auto p1 = mesh[pi1]; auto q0 = mesh[pi2]; // auto q1 = mesh[pi3]; Vec<2> n = {-p1[1]+p0[1], p1[0]-p0[0]}; Vec<2> v = { q0[0]-p0[0], q0[1]-p0[1]}; if(n[0]*v[0]+n[1]*v[1]<0) swap = true; } Element2d newel; newel.SetType(QUAD); newel[0] = pi0; newel[1] = pi1; newel[2] = pi2; newel[3] = pi3; newel.SetIndex(new_domain); newel.GeomInfo() = PointGeomInfo{}; if(swap) { Swap(newel[0], newel[1]); Swap(newel[2], newel[3]); } for(auto i : Range(4)) { newel.GeomInfo()[i].u = 0.0; newel.GeomInfo()[i].v = 0.0; } mesh.AddSurfaceElement(newel); } // segment now adjacent to new 2d-domain! if(line_segments[si].domin == domain) line_segments[si].domin = new_domain; if(line_segments[si].domout == domain) line_segments[si].domout = new_domain; } for(auto pi : Range(mapto)) { if(mapto[pi].Size() == 0) continue; auto pnew = mapto[pi].Last(); for(auto old_sei : meshtopo.GetVertexSurfaceElements( pi )) { if(mesh[old_sei].GetIndex() == domain) { auto & old_el = mesh[old_sei]; for(auto i : IntRange(old_el.GetNP())) if(old_el[i]==pi) old_el[i] = pnew; } } } for(auto & sel : mesh.SurfaceElements()) if(sel.GetIndex() == domain) sel.Delete(); mesh.Compress(); mesh.CalcSurfacesOfNode(); Generate2dMesh(mesh, domain); // even without new domain, we need temporarily a new domain to mesh the remaining area, without confusing the meshes with quads -> add segments temporarily and reset domain number and segments afterwards if(!should_make_new_domain) { // map new domain back to old one for(auto & sel : mesh.SurfaceElements()) if(sel.GetIndex()==new_domain) sel.SetIndex(domain); // remove (temporary) inner segments for(auto segi : Range(first_new_seg, mesh.LineSegments().Range().Next())) { mesh[segi][0].Invalidate(); mesh[segi][1].Invalidate(); } for(auto segi : moved_segs) { if(mesh[segi].domin == new_domain) mesh[segi].domin = domain; if(mesh[segi].domout == new_domain) mesh[segi].domout = domain; } mesh.Compress(); mesh.CalcSurfacesOfNode(); } return new_domain; } } // namespace netgen ================================================ FILE: libsrc/meshing/boundarylayer_interpolate.cpp ================================================ #include "boundarylayer.hpp" namespace netgen { namespace detail { struct Neighbor { PointIndex pi; SurfaceElementIndex sei; double weight; }; } // namespace detail Array> BuildNeighbors (FlatArray points, const Mesh& mesh) { auto p2sel = mesh.CreatePoint2SurfaceElementTable(); Array> neighbors(points.Size()); ArrayMem angles; ArrayMem inv_dists; for (auto i : points.Range()) { auto& p_neighbors = neighbors[i]; auto pi = points[i]; angles.SetSize(0); inv_dists.SetSize(0); for (auto sei : p2sel[pi]) { const auto& sel = mesh[sei]; for (auto pi1 : sel.PNums()) { if (pi1 == pi) continue; auto pi2 = pi1; for (auto pi_ : sel.PNums()) { if (pi_ != pi && pi_ != pi1) { pi2 = pi_; break; } } p_neighbors.Append({pi1, sei, 0.0}); inv_dists.Append(1.0 / (mesh[pi1] - mesh[pi]).Length()); auto dot = (mesh[pi1] - mesh[pi]).Normalize() * (mesh[pi2] - mesh[pi]).Normalize(); angles.Append(acos(dot)); } } double sum_inv_dist = 0.0; for (auto inv_dist : inv_dists) sum_inv_dist += inv_dist; double sum_angle = 0.0; for (auto angle : angles) sum_angle += angle; double sum_weight = 0.0; for (auto i : Range(inv_dists)) { p_neighbors[i].weight = inv_dists[i] * angles[i] / sum_inv_dist / sum_angle; sum_weight += p_neighbors[i].weight; } for (auto i : Range(inv_dists)) p_neighbors[i].weight /= sum_weight; } return neighbors; } void BoundaryLayerTool ::InterpolateGrowthVectors () { point_types.SetSize(mesh.GetNP()); for (auto p : mesh.Points().Range()) point_types[p] = mesh[p].Type(); int new_max_edge_nr = max_edge_nr; for (const auto& seg : segments) if (seg.edgenr > new_max_edge_nr) new_max_edge_nr = seg.edgenr; for (const auto& seg : new_segments) if (seg.edgenr > new_max_edge_nr) new_max_edge_nr = seg.edgenr; auto getGW = [&] (PointIndex pi) -> Vec<3> { if (growth_vector_map.count(pi) == 0) growth_vector_map[pi] = {&growthvectors[pi], total_height}; auto [gw, height] = growth_vector_map[pi]; return height * (*gw); }; auto addGW = [&] (PointIndex pi, Vec<3> vec) { if (growth_vector_map.count(pi) == 0) growth_vector_map[pi] = {&growthvectors[pi], total_height}; auto [gw, height] = growth_vector_map[pi]; *gw += 1.0 / height * vec; }; // interpolate tangential component of growth vector along edge if (max_edge_nr >= new_max_edge_nr) return; auto edgenr2seg = ngcore::CreateSortedTable( Range(segments.Size() + new_segments.Size()), [&] (auto& table, size_t segi) { auto& seg = segi < segments.Size() ? segments[segi] : new_segments[segi - segments.Size()]; table.Add(seg.edgenr, &seg); }, new_max_edge_nr + 1); auto point2seg = ngcore::CreateSortedTable( Range(segments.Size() + new_segments.Size()), [&] (auto& table, size_t segi) { auto& seg = segi < segments.Size() ? segments[segi] : new_segments[segi - segments.Size()]; table.Add(seg[0], &seg); table.Add(seg[1], &seg); }, mesh.GetNP()); for (auto edgenr : Range(1, new_max_edge_nr + 1)) { // "inner" edges between two flat faces are not treated as edges for interpolation bool no_angles = true; ArrayMem faces; for (auto* p_seg : edgenr2seg[edgenr]) { auto& seg = *p_seg; faces.SetSize(0); // if (seg[0] <= p2sel.Size()) if (seg[0] < IndexBASE() + p2sel.Size()) { for (auto sei : p2sel[seg[0]]) if (moved_surfaces.Test(mesh[sei].GetIndex()) && p2sel[seg[1]].Contains(sei)) faces.Append(sei); } if (faces.Size() == 2 && mesh[faces[0]].GetIndex() != mesh[faces[1]].GetIndex()) { auto n0 = getNormal(mesh[faces[0]]); auto n1 = getNormal(mesh[faces[1]]); if (n0 * n1 < 0.99) no_angles = false; } else { no_angles = false; } } if (no_angles && faces.Size() == 2 && have_material_map) if (par_new_mat[mesh.GetBCName(mesh[faces[0]].GetIndex() - 1)] != par_new_mat[mesh.GetBCName(mesh[faces[1]].GetIndex() - 1)]) no_angles = false; if (no_angles) { for (auto* p_seg : edgenr2seg[edgenr]) for (auto pi : p_seg->PNums()) { if (pi >= first_new_pi) continue; if (point_types[pi] == EDGEPOINT) point_types[pi] = SURFACEPOINT; else if (point_types[pi] == FIXEDPOINT) { // Check at edge corners if all adjacent surface elements have roughly the same normal. // If so, also treat this point as surface point for growth vector interpolation Vec<3> n = 0.0; for (auto si : p2sel[pi]) n += getNormal(mesh[si]); n.Normalize(); bool is_corner = false; for (auto si : p2sel[pi]) if (getNormal(mesh[si]) * n < 0.99) is_corner = true; if (!is_corner) point_types[pi] = SURFACEPOINT; } } continue; } } for (auto edgenr : Range(max_edge_nr + 1, new_max_edge_nr + 1)) { double edge_len = 0.; bool any_grows = false; auto is_end_point = [&] (PointIndex pi) { auto segs = point2seg[pi]; if (segs.Size() == 1) return true; auto first_edgenr = (*segs[0]).edgenr; for (auto* p_seg : segs) if (p_seg->edgenr != first_edgenr) return true; return false; }; Array points; for (auto* p_seg : edgenr2seg[edgenr]) { auto& seg = *p_seg; if (getGW(seg[0]).Length2() != 0 || getGW(seg[1]).Length2() != 0) any_grows = true; if (points.Size() == 0) for (auto i : Range(2)) if (is_end_point(seg[i])) { points.Append(seg[i]); points.Append(seg[1 - i]); edge_len += (mesh[seg[1]] - mesh[seg[0]]).Length(); break; } } if (!any_grows) { PrintMessage(1, "BLayer: skip interpolating growth vectors at edge ", edgenr + 1); continue; } if (!points.Size()) { if (debugparam.debugoutput) cerr << "Could not find startpoint for edge " << edgenr << endl; continue; } std::set points_set; points_set.insert(points[0]); points_set.insert(points[1]); bool point_found = true; while (point_found) { if (is_end_point(points.Last())) break; point_found = false; for (auto* p_seg : point2seg[points.Last()]) { const auto& seg = *p_seg; if (seg.edgenr != edgenr) continue; auto plast = points.Last(); if (plast != seg[0] && plast != seg[1]) continue; auto pnew = plast == seg[0] ? seg[1] : seg[0]; if (pnew == points[0] && points.Size() > 1) { } if (points_set.count(pnew) > 0 && (pnew != points[0] || points.Size() == 2)) continue; edge_len += (mesh[points.Last()] - mesh[pnew]).Length(); points.Append(pnew); points_set.insert(pnew); point_found = true; break; } } if (!point_found) { if (debugparam.debugoutput) { cerr << "Could not find connected list of line segments for edge " << edgenr << endl; cerr << "current points: " << endl << points << endl; } continue; } if (getGW(points[0]).Length2() == 0 && getGW(points.Last()).Length2() == 0) continue; // tangential part of growth vectors auto t1 = (mesh[points[1]] - mesh[points[0]]).Normalize(); auto gt1 = getGW(points[0]) * t1 * t1; auto t2 = (mesh[points.Last()] - mesh[points[points.Size() - 2]]).Normalize(); auto gt2 = getGW(points.Last()) * t2 * t2; double len = 0.; for (auto i : IntRange(1, points.Size() - 1)) { auto pi = points[i]; len += (mesh[pi] - mesh[points[i - 1]]).Length(); auto t = getEdgeTangent(pi, edgenr, point2seg[pi]); auto lam = len / edge_len; auto interpol = (1 - lam) * (gt1 * t) * t + lam * (gt2 * t) * t; addGW(pi, interpol); } } } void BoundaryLayerTool ::InterpolateSurfaceGrowthVectors () { static Timer tall("InterpolateSurfaceGrowthVectors"); RegionTimer rtall(tall); static Timer tsmooth("InterpolateSurfaceGrowthVectors-Smoothing"); auto np_old = this->np; [[maybe_unused]] auto np = mesh.GetNP(); auto hasMoved = [&] (PointIndex pi) { return (pi - IndexBASE() >= np_old) || mapto[pi].Size() > 0 || special_boundary_points.count(pi); }; std::set points_set; for (const auto& sel : mesh.SurfaceElements()) { for (auto pi : sel.PNums()) if (point_types[pi] == SURFACEPOINT && hasMoved(pi)) points_set.insert(pi); } Array points; for (auto pi : points_set) points.Append(pi); QuickSort(points); // smooth tangential part of growth vectors from edges to surface elements Array, PointIndex> corrections(mesh.GetNP()); corrections = 0.0; RegionTimer rtsmooth(tsmooth); auto neighbors = BuildNeighbors(points, mesh); Array, SurfaceElementIndex> surf_normals(mesh.GetNSE()); for (auto sei : mesh.SurfaceElements().Range()) surf_normals[sei] = getNormal(mesh[sei]); BitArray interpolate_tangent(mesh.GetNP() + 1); interpolate_tangent = false; for (auto pi : points) { for (auto sei : p2sel[pi]) if (is_boundary_moved[mesh[sei].GetIndex()]) interpolate_tangent.SetBit(pi); } constexpr int N_STEPS = 64; for ([[maybe_unused]] auto i : Range(N_STEPS)) { for (auto i : points.Range()) { auto pi = points[i]; auto& p_neighbors = neighbors[i]; ArrayMem, 20> g_vectors; double max_len = 0.0; double sum_len = 0.0; // average only tangent component on new bl points, average whole growth // vector otherwise bool do_average_tangent = true; for (const auto& s : p_neighbors) { auto gw_other = growthvectors[s.pi] + corrections[s.pi]; if (do_average_tangent) { auto n = surf_normals[s.sei]; gw_other = gw_other - (gw_other * n) * n; } auto v = gw_other; auto len = v.Length2(); sum_len += len; max_len = max(max_len, len); g_vectors.Append(v); } if (max_len == 0.0) continue; double lambda = 0; if (i > N_STEPS / 4.) lambda = 2.0 * (i - N_STEPS / 4.) / (N_STEPS / 2.); lambda = min(1.0, lambda); auto& correction = corrections[pi]; correction = 0.0; for (const auto i : p_neighbors.Range()) { auto v = g_vectors[i]; double weight = lambda * p_neighbors[i].weight + (1.0 - lambda) * v.Length2() / sum_len; correction += weight * v; } if (!do_average_tangent) correction -= growthvectors[pi]; } } for (auto pi : points) growthvectors[pi] += corrections[pi]; } void BoundaryLayerTool ::FixSurfaceElements () { static Timer tall("FixSurfaceElements"); RegionTimer rtall(tall); [[maybe_unused]] auto np_old = this->np; [[maybe_unused]] auto np = mesh.GetNP(); non_bl_growth_vectors.clear(); auto getGW = [&] (PointIndex pi) -> Vec<3> { // return growthvectors[pi]; if (growth_vector_map.count(pi) == 0) { non_bl_growth_vectors[pi] = .0; growth_vector_map[pi] = {&non_bl_growth_vectors[pi], 1.0}; } auto [gw, height] = growth_vector_map[pi]; return height * (*gw); }; auto addGW = [&] (PointIndex pi, Vec<3> vec) { if (growth_vector_map.count(pi) == 0) { non_bl_growth_vectors[pi] = .0; growth_vector_map[pi] = {&non_bl_growth_vectors[pi], 1.0}; } auto [gw, height] = growth_vector_map[pi]; *gw += 1.0 / height * vec; }; std::set points_set; // only smooth over old surface elements for (SurfaceElementIndex sei : Range(nse)) { const auto& sel = mesh[sei]; if (sel.GetNP() == 3 && is_boundary_moved[sel.GetIndex()]) for (auto pi : sel.PNums()) if (point_types[pi] == SURFACEPOINT) points_set.insert(pi); } Array points; for (auto pi : points_set) points.Append(pi); QuickSort(points); Array, PointIndex> corrections(mesh.GetNP()); corrections = 0.0; auto neighbors = BuildNeighbors(points, mesh); constexpr int N_STEPS = 32; for ([[maybe_unused]] auto i : Range(N_STEPS)) { for (auto i : points.Range()) { auto pi = points[i]; auto& p_neighbors = neighbors[i]; ArrayMem, 20> g_vectors; double max_len = 0.0; double sum_len = 0.0; for (const auto& s : p_neighbors) { auto v = getGW(s.pi) + corrections[s.pi]; auto len = v.Length2(); sum_len += len; max_len = max(max_len, len); g_vectors.Append(v); } if (max_len == 0.0) continue; double lambda = 0; if (i > N_STEPS / 4.) lambda = 2.0 * (i - N_STEPS / 4.) / (N_STEPS / 2.); lambda = min(1.0, lambda); auto& correction = corrections[pi]; correction = 0.0; for (const auto i : p_neighbors.Range()) { auto v = g_vectors[i]; double weight = lambda * p_neighbors[i].weight + (1.0 - lambda) * v.Length2() / sum_len; correction += weight * v; } } } for (auto pi : points) addGW(pi, corrections[pi]); } } // namespace netgen ================================================ FILE: libsrc/meshing/boundarylayer_limiter.hpp ================================================ #include "boundarylayer.hpp" #include namespace netgen { struct Intersection_ { bool is_intersecting = false; double lam0 = -1, lam1 = -1; Point<3> p; double bary[3]; operator bool() const { return is_intersecting; } }; struct GrowthVectorLimiter { typedef std::array, 2> Seg; typedef std::array, 3> Trig; BoundaryLayerTool& tool; const BoundaryLayerParameters& params; Mesh& mesh; double height; Array limits; FlatArray, PointIndex> growthvectors; BitArray changed_domains; unique_ptr> tree; Array map_from; Table p2sel; GrowthVectorLimiter (BoundaryLayerTool& tool_) : tool(tool_), params(tool_.params), mesh(tool_.mesh), height(tool_.total_height), growthvectors(tool_.growthvectors), map_from(mesh.Points().Size()) { changed_domains = tool.domains; if (!params.outside) changed_domains.Invert(); map_from = tool.mapfrom; p2sel = ngcore::CreateSortedTable( tool.new_sels.Range(), [&] (auto& table, SurfaceElementIndex ei) { for (PointIndex pi : tool.new_sels[ei].PNums()) table.Add(pi, ei); }, mesh.GetNP()); } auto SurfaceElementsRange () { return Range(tool.nse + tool.new_sels.Size()); } void WriteErrorMesh (string name) { if (!debugparam.write_mesh_on_error) return; Mesh out_mesh; out_mesh = mesh; for (auto [pi, data] : tool.growth_vector_map) { auto [gw, height] = data; out_mesh[pi] += limits[pi] * height * (*gw); } out_mesh.Save(name); } const auto& Get (SurfaceElementIndex sei) { if (sei < tool.nse) return mesh[sei]; return tool.new_sels[sei - tool.nse]; } std::pair GetMinMaxLimit (SurfaceElementIndex sei) { const auto& sel = Get(sei); double min_limit = GetLimit(sel[0]); double max_limit = min_limit; for (auto i : IntRange(1, sel.GetNP())) { auto limit = GetLimit(sel[i]); min_limit = min(min_limit, limit); max_limit = max(max_limit, limit); } return {min_limit, max_limit}; } double GetLimit (PointIndex pi) { if (pi < tool.first_new_pi) return limits[pi]; return limits[map_from[pi]]; } bool SetLimit (PointIndex pi, double new_limit) { double& limit = (pi < tool.first_new_pi) ? limits[pi] : limits[map_from[pi]]; if (limit <= new_limit) return false; limit = new_limit; return true; } bool ScaleLimit (PointIndex pi, double factor) { double& limit = (pi < tool.first_new_pi) ? limits[pi] : limits[map_from[pi]]; return SetLimit(pi, limit * factor); } Vec<3> GetVector (PointIndex pi_to, double shift = 1., bool apply_limit = false) { auto [gw, height] = tool.growth_vector_map[pi_to]; if (apply_limit) shift *= GetLimit(pi_to); return shift * height * (*gw); } Point<3> GetPoint (PointIndex pi_to, double shift = 1., bool apply_limit = false) { if (pi_to < tool.first_new_pi || tool.growth_vector_map.count(pi_to) == 0) return mesh[pi_to]; return mesh[pi_to] + GetVector(pi_to, shift, apply_limit); } Point<3> GetMappedPoint (PointIndex pi_from, double shift = 1., bool apply_limit = false) { auto pi_to = tool.mapto[pi_from].Last(); return GetPoint(pi_to, shift, apply_limit); } Seg GetMappedSeg (PointIndex pi_from, double shift = 1.) { return {mesh[pi_from], GetMappedPoint(pi_from, shift)}; } Seg GetSeg (PointIndex pi_to, double shift = 1., bool apply_limit = false) { return {GetPoint(pi_to, 0), GetPoint(pi_to, shift, apply_limit)}; } Trig GetTrig (SurfaceElementIndex sei, double shift = 0.0, bool apply_limit = false) { auto sel = Get(sei); Trig trig; for (auto i : Range(3)) trig[i] = GetPoint(sel[i], shift, apply_limit); return trig; } Trig GetMappedTrig (SurfaceElementIndex sei, double shift = 0.0) { auto sel = Get(sei); Trig trig; for (auto i : Range(3)) trig[i] = GetMappedPoint(sel[i], shift); return trig; } Trig GetSideTrig (SurfaceElementIndex sei, int index, double shift = 0.0, bool grow_first_vertex = true) { auto trig = GetMappedTrig(sei, 0.0); auto sel = Get(sei); auto index1 = (index + 1) % 3; if (!grow_first_vertex) index1 = (index + 2) % 3; trig[index] = GetMappedPoint(sel[index1], shift, true); return trig; } array GetSideTrigs (SurfaceElementIndex sei, int i0, double shift = 0.0) { auto trig = GetMappedTrig(sei, 0.0); array trigs{trig, trig, trig, trig}; auto sel = Get(sei); auto i1 = (i0 + 1) % 3; auto i2 = (i0 + 2) % 3; auto p1 = GetMappedPoint(sel[i1], shift, true); auto p2 = GetMappedPoint(sel[i2], shift, true); // create four trigs to span the quad from i1,i2 and their shifted points // i1, i2, shifted i1 trigs[0][i0] = p1; // i1, i2, shifted i2 trigs[1][i0] = p2; // i1, shifted i1, shifted i2 trigs[2][i0] = p1; trigs[2][i2] = p2; // i2, shifted i1, shifted i2 trigs[2][i0] = p2; trigs[2][i1] = p1; return trigs; } static constexpr double INTERSECTION_SAFETY = .9; bool LimitGrowthVector (PointIndex pi_to, SurfaceElementIndex sei, double trig_shift, double seg_shift, bool check_prism_sides = false) { auto pi_from = map_from[pi_to]; if (!pi_from.IsValid()) return false; for (auto pi : Get(sei).PNums()) { if (pi == pi_from) return false; if (map_from[pi] == pi_from) return false; } if (check_prism_sides || trig_shift > .0) { auto [trig_min_limit, trig_max_limit] = GetMinMaxLimit(sei); if (GetLimit(pi_to) < trig_min_limit) return false; auto getTrigs = [&] (double scaling = 1.0) -> ArrayMem { ArrayMem trigs; if (check_prism_sides) for (auto i : Range(3)) for (auto trig : GetSideTrigs(sei, i, scaling * trig_shift)) trigs.Append(trig); else trigs.Append(GetTrig(sei, scaling * trig_shift, true)); return trigs; }; if (!check_prism_sides) { // If the growth vectors of all points are pointing in the same direction, // an intersection means, we also have an intersection with a prism side face // this is an extra check and handled later auto seg = GetSeg(pi_to, 1.0, false); auto gw = seg[1] - seg[0]; bool have_same_growth_direction = true; for (auto pi : Get(sei).PNums()) { auto p_seg = GetSeg(pi, 1.0, false); auto p_gw = p_seg[1] - p_seg[0]; have_same_growth_direction &= (gw * p_gw) > 0; } if (have_same_growth_direction) return false; } double scaling = 1.0; while (true) { bool have_intersection = false; auto seg = GetSeg(pi_to, scaling * seg_shift, true); for (auto trig : getTrigs(scaling)) have_intersection |= isIntersectingTrig(seg, trig); if (!have_intersection) break; scaling *= 0.9; } if (scaling == 1.0) return false; double new_limit = scaling * max(GetLimit(pi_to), trig_max_limit); SetLimit(pi_to, new_limit); for (auto pi : Get(sei).PNums()) SetLimit(pi, new_limit); return true; } else { auto seg = GetSeg(pi_to, seg_shift, false); auto trig = GetTrig(sei, 0.0); auto intersection = isIntersectingTrig(seg, trig); // checking with original surface elements -> allow only half the distance auto new_seg_limit = 0.40 * intersection.lam0 * seg_shift; if (intersection && new_seg_limit < GetLimit(pi_from)) return SetLimit(pi_from, new_seg_limit); return false; } } void EqualizeLimits (double factor = .5) { static Timer t("GrowthVectorLimiter::EqualizeLimits"); PrintMessage(5, "GrowthVectorLimiter - equalize limits"); RegionTimer reg(t); if (factor == 0.0) return; // for (PointIndex pi : IntRange(tool.np, mesh.GetNP())) for (PointIndex pi : mesh.Points().Range().Modify(tool.np, 0)) { // auto pi_from = map_from[pi]; std::set pis; for (auto sei : p2sel[pi]) for (auto pi_ : tool.new_sels[sei].PNums()) pis.insert(pi_); ArrayMem limits; for (auto pi1 : pis) { auto limit = GetLimit(pi1); if (limit > 0.0) limits.Append(GetLimit(pi1)); } if (limits.Size() == 0) continue; double average = 0.0; for (auto l : limits) average += l; average /= limits.Size(); SetLimit(pi, factor * average + (1.0 - factor) * GetLimit(pi)); } } void LimitSelfIntersection (double safety = 1.4) { static Timer t("GrowthVectorLimiter::LimitSelfIntersection"); PrintMessage(5, "GrowthVectorLimiter - self intersection"); RegionTimer reg(t); // check for self-intersection within new elements (prisms/hexes) auto isIntersecting = [&] (SurfaceElementIndex sei, double shift) { // checks if surface element is self intersecting when growing with factor // shift // ignore new surface elements, side trigs are only built // from original surface elements if (sei >= tool.nse) return false; const auto sel = Get(sei); auto np = sel.GetNP(); for (auto i : Range(np)) { if (sel[i] >= tool.first_new_pi) return false; if (tool.mapto[sel[i]].Size() == 0) return false; } for (auto i : Range(np)) { auto seg = GetMappedSeg(sel[i], shift * limits[sel[i]]); for (auto fi : Range(np - 2)) { for (auto side : {true, false}) { auto trig = GetSideTrig(sei, i + fi, 1.0, side); if (isIntersectingPlane(seg, trig)) return true; } } } return false; }; for (SurfaceElementIndex sei : mesh.SurfaceElements().Range()) { auto sel = mesh[sei]; if (sei >= tool.nse) continue; if (!tool.moved_surfaces[sel.GetIndex()]) continue; if (sel.GetNP() == 4) continue; // const auto& fd = mesh.GetFaceDescriptor(sel.GetIndex()); auto np = sel.GetNP(); double shift = 1.0; const double step_factor = 0.9; while (isIntersecting(sei, shift * safety)) { shift *= step_factor; double max_limit = 0; for (auto i : Range(np)) max_limit = max(max_limit, limits[sel[i]]); for (auto i : Range(np)) if (max_limit == limits[sel[i]]) ScaleLimit(sel[i], step_factor); // if (max_limit < 0.01) break; } } } // checks if a segment is intersecting a plane, spanned by three points, lam // will be set s.t. p_intersect = seg[0] + lam * (seg[1]-seg[0]) Intersection_ isIntersectingPlane (const Seg& seg, const Trig& trig) { auto t1 = trig[1] - trig[0]; auto t2 = trig[2] - trig[0]; auto n = Cross(t1, t2); auto v0n = (seg[0] - trig[0]) * n; auto v1n = (seg[1] - trig[0]) * n; Intersection_ intersection; intersection.lam0 = -v0n / (v1n - v0n); intersection.p = seg[0] + intersection.lam0 * (seg[1] - seg[0]); intersection.is_intersecting = (v0n * v1n < 0) && (intersection.lam0 > -1e-8) && (intersection.lam0 < 1 + 1e-8); return intersection; } Intersection_ isIntersectingTrig (const Seg& seg, const Trig& trig) { auto intersection = isIntersectingPlane(seg, trig); if (!intersection) return intersection; auto p = seg[0] + intersection.lam0 * (seg[1] - seg[0]) - trig[0]; Vec3d col1 = trig[1] - trig[0]; Vec3d col2 = trig[2] - trig[0]; Vec3d col3 = Cross(col1, col2); Vec3d rhs = p; Vec3d bary; SolveLinearSystem(col1, col2, col3, rhs, bary); intersection.lam1 = 0; double eps = 1e-4; if (bary.X() >= -eps && bary.Y() >= -eps && bary.X() + bary.Y() <= 1 + eps) { intersection.bary[0] = bary.X(); intersection.bary[1] = bary.Y(); intersection.bary[2] = 1.0 - bary.X() - bary.Y(); } else intersection.is_intersecting = false; return intersection; } Intersection_ isIntersectingTrig (PointIndex pi_from, PointIndex pi_to, SurfaceElementIndex sei, double shift = 0.0) { // JS: where is that GetSeg function ? return isIntersectingTrig(GetSeg(pi_from, pi_to), GetTrig(sei, shift)); } void BuildSearchTree (double trig_shift) { static Timer t("BuildSearchTree"); RegionTimer rt(t); Box<3> bbox(Box<3>::EMPTY_BOX); for (PointIndex pi : mesh.Points().Range()) { bbox.Add(mesh[pi]); bbox.Add(GetPoint(pi, 1.1)); } tree = make_unique>(bbox); for (auto sei : SurfaceElementsRange()) { const auto& sel = Get(sei); // auto sel_index = sel.GetIndex(); Box<3> box(Box<3>::EMPTY_BOX); for (auto pi : sel.PNums()) { box.Add(GetPoint(pi, 0.)); box.Add(GetPoint(pi, trig_shift * GetLimit(pi))); } tree->Insert(box, sei); } } template void FindTreeIntersections (double trig_shift, double seg_shift, TFunc f, TBitArray* relevant_points = nullptr) { static Timer t("GrowthVectorLimiter::FindTreeIntersections"); RegionTimer rt(t); BuildSearchTree(trig_shift); auto np_new = mesh.Points().Size(); // int counter = 0; for (auto i : IntRange(tool.np, np_new)) { PointIndex pi_to = i + IndexBASE(); PointIndex pi_from = map_from[pi_to]; if (!pi_from.IsValid()) throw Exception("Point not mapped"); if (relevant_points && !relevant_points->Test(pi_to) && !relevant_points->Test(pi_from)) continue; Box<3> box(Box<3>::EMPTY_BOX); // auto seg = GetSeg(pi_to, seg_shift); box.Add(GetPoint(pi_to, 0)); box.Add(GetPoint(pi_to, GetLimit(pi_from))); tree->GetFirstIntersecting(box.PMin(), box.PMax(), [&] (SurfaceElementIndex sei) { const auto& sel = Get(sei); if (sel.PNums().Contains(pi_from)) return false; if (sel.PNums().Contains(pi_to)) return false; // counter++; f(pi_to, sei); return false; }); } } void FixIntersectingSurfaceTrigs () { static Timer t("GrowthVectorLimiter::FixIntersectingSurfaceTrigs"); RegionTimer reg(t); // check if surface trigs are intersecting each other bool changed = true; std::set special_points; if (tool.insert_only_volume_elements) for (auto [pi, special_point] : tool.special_boundary_points) { special_points.insert(pi); for (auto& group : special_point.growth_groups) special_points.insert(group.new_points.Last()); } auto skip_trig = [&] (const Element2d& tri) { if (!tool.insert_only_volume_elements) return false; for (auto pi : tri.PNums()) if (special_points.find(pi) != special_points.end()) return true; return false; }; while (changed) { changed = false; Point3d pmin, pmax; mesh.GetBox(pmin, pmax); BoxTree<3, SurfaceElementIndex> setree(pmin, pmax); for (auto sei : SurfaceElementsRange()) { const Element2d& tri = Get(sei); if (skip_trig(tri)) continue; Box<3> box(Box<3>::EMPTY_BOX); for (PointIndex pi : tri.PNums()) box.Add(GetPoint(pi, 1.0, true)); box.Increase(1e-3 * box.Diam()); setree.Insert(box, sei); } for (auto sei : SurfaceElementsRange()) { const Element2d& tri = Get(sei); if (skip_trig(tri)) continue; Box<3> box(Box<3>::EMPTY_BOX); for (PointIndex pi : tri.PNums()) box.Add(GetPoint(pi, 1.0, true)); setree.GetFirstIntersecting(box.PMin(), box.PMax(), [&] (size_t sej) { const Element2d& tri2 = Get(sej); if (mesh[tri[0]].GetLayer() != mesh[tri2[0]].GetLayer()) return false; netgen::Point<3> tri1_points[3], tri2_points[3]; const netgen::Point<3>*trip1[3], *trip2[3]; for (int k = 0; k < 3; k++) { trip1[k] = &tri1_points[k]; trip2[k] = &tri2_points[k]; } auto set_points = [&] () { for (int k = 0; k < 3; k++) { tri1_points[k] = GetPoint(tri[k], 1.0, true); tri2_points[k] = GetPoint(tri2[k], 1.0, true); } }; set_points(); int counter = 0; while (IntersectTriangleTriangle(&trip1[0], &trip2[0])) { changed = true; PointIndex pi_max_limit = PointIndex::INVALID; for (PointIndex pi : {tri[0], tri[1], tri[2], tri2[0], tri2[1], tri2[2]}) if (pi >= tool.first_new_pi && (!pi_max_limit.IsValid() || GetLimit(pi) > GetLimit(pi_max_limit))) pi_max_limit = map_from[pi]; if (!pi_max_limit.IsValid()) break; ScaleLimit(pi_max_limit, 0.9); set_points(); counter++; if (GetLimit(pi_max_limit) < 1e-10) { WriteErrorMesh("error_blayer_self_intersection_pi" + ToString(pi_max_limit) + ".vol.gz"); throw NgException("Stop meshing in boundary layer thickness limitation: overlapping regions detected at elements " + ToString(tri) + " and " + ToString(tri2)); } if (debugparam.debugoutput && counter > 20) { cerr << "Limit intersecting surface elements: too many " "limitation steps, sels: " << Get(sei) << '\t' << Get(sej) << endl; for (auto si : {sei, sej}) { auto sel = Get(si); cerr << "Limits: "; for (auto pi : sel.PNums()) cerr << GetLimit(pi) << ",\t"; cerr << endl; for (auto pi : sel.PNums()) cerr << GetPoint(pi, 1.0, true) << "\t"; cerr << endl; } cerr << "pi_max_limit " << pi_max_limit << endl; break; } } return false; }); } } } void LimitOriginalSurface (double safety) { static Timer t("GrowthVectorLimiter::LimitOriginalSurface"); RegionTimer reg(t); PrintMessage(5, "GrowthVectorLimiter - original surface"); // limit to not intersect with other (original) surface elements double trig_shift = 0; double seg_shift = safety; FindTreeIntersections( trig_shift, seg_shift, [&] (PointIndex pi_to, SurfaceElementIndex sei) { if (sei >= tool.nse) return; // ignore new surface elements in first pass LimitGrowthVector(pi_to, sei, trig_shift, seg_shift); }); } void LimitBoundaryLayer (double safety = 1.1) { static Timer t("GrowthVectorLimiter::LimitBoundaryLayer"); PrintMessage(5, "GrowthVectorLimiter - boundary layer"); // now limit again with shifted surface elements double trig_shift = safety; double seg_shift = safety; size_t limit_counter = 1; TBitArray relevant_points, relevant_points_next; relevant_points.SetSize(mesh.Points().Size() + 1); relevant_points_next.SetSize(mesh.Points().Size() + 1); relevant_points.Set(); while (limit_counter) { RegionTimer reg(t); size_t find_counter = 0; limit_counter = 0; relevant_points_next.Clear(); FindTreeIntersections( trig_shift, seg_shift, [&] (PointIndex pi_to, SurfaceElementIndex sei) { find_counter++; auto sel = Get(sei); if (LimitGrowthVector(pi_to, sei, trig_shift, seg_shift)) { limit_counter++; relevant_points_next.SetBit(pi_to); relevant_points_next.SetBit(map_from[pi_to]); for (auto pi : sel.PNums()) { relevant_points_next.SetBit(pi); if (pi >= tool.first_new_pi) relevant_points_next.SetBit(map_from[pi]); } } for (auto pi : sel.PNums()) { if (pi >= tool.first_new_pi) return; if (tool.mapto[pi].Size() == 0) return; } if (LimitGrowthVector(pi_to, sei, trig_shift, seg_shift, true)) limit_counter++; }, &relevant_points); relevant_points = relevant_points_next; } } void CheckLimits (int line) { auto check_point = [&] (PointIndex pi) { if (limits[pi] < 1e-8) { WriteErrorMesh("error_blayer_intersection_pi" + ToString(pi) + ".vol.gz"); throw NgException(__FILE__ + ToString(line) + ": Stop meshing in boundary layer thickness limitation: overlapping regions detected at point " + ToString(pi)); } }; for (auto pi : Range(growthvectors)) check_point(pi); if (!tool.insert_only_volume_elements) for (auto& [special_pi, special_point] : tool.special_boundary_points) check_point(special_pi); } void Perform () { limits.SetSize(mesh.Points().Size()); limits = 1.0; if (tool.special_boundary_points.size()) { auto point_to_sel = tool.mesh.CreatePoint2SurfaceElementTable(); for (auto& [pi, special_point] : tool.special_boundary_points) { auto maxh = mesh.GetH(mesh[pi]); auto new_limit = min(0.3 * maxh / tool.total_height, 1.0); if (new_limit < 1.0) { limits[pi] = new_limit; for (auto sei : point_to_sel[pi]) for (auto pi_ : Get(sei).PNums()) limits[pi_] = new_limit; } } } std::array safeties = {0.5, 1.1, 1.5, 1.5}; // No smoothing in the last pass, to avoid generating new intersections std::array smoothing_factors = {0.8, 0.7, 0.5, 0.0}; for (auto i_pass : Range(safeties.size())) { PrintMessage(4, "GrowthVectorLimiter pass ", i_pass); double safety = safeties[i_pass]; CheckLimits(__LINE__); // intersect segment with original surface elements LimitOriginalSurface(2.1); CheckLimits(__LINE__); // intersect prisms with themself LimitSelfIntersection(1.3 * safety); CheckLimits(__LINE__); // intesect segment with prism LimitBoundaryLayer(safety); CheckLimits(__LINE__); for ([[maybe_unused]] auto i : Range(10)) EqualizeLimits(smoothing_factors[i_pass]); CheckLimits(__LINE__); if (i_pass == safeties.size() - 1) FixIntersectingSurfaceTrigs(); CheckLimits(__LINE__); } for (auto i : Range(growthvectors)) growthvectors[i] *= limits[i]; for (auto& [special_pi, special_point] : tool.special_boundary_points) { for (auto& group : special_point.growth_groups) { group.growth_vector *= limits[special_pi]; } } } }; } // namespace netgen ================================================ FILE: libsrc/meshing/classifyhpel.hpp ================================================ // typename INDEX_2_HASHTABLE HT_EDGEPOINT_DOM; typedef ClosedHashTable, int> HT_EDGEPOINT_DOM; HPREF_ELEMENT_TYPE ClassifyTet(HPRefElement & el, INDEX_2_HASHTABLE & edges, HT_EDGEPOINT_DOM & edgepoint_dom, TBitArray & cornerpoint, TBitArray & edgepoint, INDEX_3_HASHTABLE & faces, INDEX_2_HASHTABLE & face_edges, INDEX_2_HASHTABLE & surf_edges, Array & 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; bool isface[4]; 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; */ // *testout << "new el" << endl; 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 (PointIndices<2>::Sort (el.pnums[j], el.pnums[k])); isedge2 = edges.Used (PointIndices<2>::Sort (el.pnums[j], el.pnums[pi3])); isedge3 = edges.Used (PointIndices<2>::Sort (el.pnums[j], el.pnums[pi4])); isedge4 = edges.Used (PointIndices<2>::Sort (el.pnums[k], el.pnums[pi3])); isedge5 = edges.Used (PointIndices<2>::Sort (el.pnums[k], el.pnums[pi4])); isedge6 = edges.Used (PointIndices<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; } for (int j = 0; j < 4; j++) isface[j] = false; for (int l = 0; l < 4; l++) { PointIndices<3> i3(PointIndex::INVALID, PointIndex::INVALID, PointIndex::INVALID); switch (l) { case 0: i3[0] = el.pnums[k]; i3[1] = el.pnums[pi3]; i3[2] = el.pnums[pi4]; break; case 1: i3[0] = el.pnums[j]; i3[1] = el.pnums[pi3]; i3[2] = el.pnums[pi4]; break; case 2: i3[0] = el.pnums[j]; i3[1] = el.pnums[k]; i3[2] = el.pnums[pi4]; break; case 3: i3[0] = el.pnums[j]; i3[1] = el.pnums[k]; i3[2] = el.pnums[pi3]; break; } i3.Sort(); if (faces.Used (i3)) { int domnr = faces.Get(i3); if (domnr == -1 || domnr == el.GetIndex()) isface[l] = true; } } /* 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++) { PointIndices<2> i2(PointIndex::INVALID, PointIndex::INVALID); switch (l) { case 0: i2[0] = el.pnums[j]; i2[1] = el[k]; break; case 1: i2[0] = el.pnums[j]; i2[1] = el.pnums[pi3]; break; case 2: i2[0] = el.pnums[j]; i2[1] = el.pnums[pi4]; break; case 3: i2[0] = el.pnums[k]; i2[1] = el.pnums[pi3]; break; case 4: i2[0] = el.pnums[k]; i2[1] = el.pnums[pi4]; break; case 5: i2[0] = el.pnums[pi3]; i2[1] = 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++) { PointIndex pti = PointIndex::INVALID; 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; } } } /* ep1 |= cp1; ep2 |= cp2; ep3 |= cp3; ep4 |= cp4; fp1 |= ep1; fp2 |= ep2; fp3 |= ep3; fp4 |= ep4; */ /* fp1 = facepoint[el.pnums[j]] != 0; fp2 = facepoint[el.pnums[k]] != 0; fp3 = facepoint[el.pnums[pi3]] != 0; fp4 = facepoint[el.pnums[pi4]] != 0; */ // cout << "marked faces: " // << isface[0] << isface[1] << isface[2] << isface[3] // << ", num = " << isface[0]+isface[1]+isface[2]+isface[3] << endl; bool sp1 = cp1 || (ep1 && !isedge1 && !isedge2 && !isedge3) || (fp1 && !isfedge1 && !isfedge2 && !isfedge3); bool sp2 = cp2 || (ep2 && !isedge1 && !isedge4 && !isedge5) || (fp2 && !isfedge1 && !isfedge4 && !isfedge5); bool sp3 = cp3 || (ep3 && !isedge2 && !isedge4 && !isedge6) || (fp3 && !isfedge2 && !isfedge4 && !isfedge6); bool sp4 = cp4 || (ep4 && !isedge3 && !isedge5 && !isedge6) || (fp4 && !isfedge3 && !isfedge5 && !isfedge6); bool se1 = isedge1 || (isfedge1 && !isface[2] && !isface[3]); bool se2 = isedge2 || (isfedge2 && !isface[1] && !isface[3]); bool se3 = isedge3 || (isfedge3 && !isface[1] && !isface[2]); bool se4 = isedge4 || (isfedge4 && !isface[0] && !isface[3]); bool se5 = isedge5 || (isfedge5 && !isface[0] && !isface[2]); bool se6 = isedge6 || (isfedge6 && !isface[0] && !isface[1]); // *testout << "sp = " << sp1 << sp2 << sp3 << sp4 << endl; // *testout << "se = " << se1 << se2 << se3 << se4 << se5 << se6 << endl; // *testout << "sf = " << isface[0] << isface[1] << isface[2] << isface[3] << endl; switch (isface[0]+isface[1]+isface[2]+isface[3]) { 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 (!sp1 && !sp2 && !sp3 && !sp4) type = HP_TET; if (sp1 && !sp2 && !sp3 && !sp4) type = HP_TET_0E_1V; if (sp1 && sp2 && !sp3 && !sp4) type = HP_TET_0E_2V; if (sp1 && sp2 && sp3 && !sp4) type = HP_TET_0E_3V; if (sp1 && sp2 && sp3 && sp4) type = HP_TET_0E_4V; break; } case 1: { if (!isedge1) break; if (!sp1 && !sp2 && !sp3 && !sp4) type = HP_TET_1E_0V; if (sp1 && !sp2 && !sp3 && !sp4) type = HP_TET_1E_1VA; if (!sp1 && !sp2 && !sp3 && sp4) type = HP_TET_1E_1VB; if (sp1 && sp2 && !sp3 && !sp4) type = HP_TET_1E_2VA; if (sp1 && !sp2 && sp3 && !sp4) type = HP_TET_1E_2VB; if (sp1 && !sp2 && !sp3 && sp4) type = HP_TET_1E_2VC; if (!sp1 && !sp2 && sp3 && sp4) type = HP_TET_1E_2VD; if (sp1 && sp2 && sp3 && !sp4) type = HP_TET_1E_3VA; if (sp1 && !sp2 && sp3 && sp4) type = HP_TET_1E_3VB; if (sp1 && sp2 && sp3 && sp4) type = HP_TET_1E_4V; break; } case 2: { if (isedge1 && isedge2) { if (!sp2 && !sp3 && !sp4) type = HP_TET_2EA_0V; if (sp2 && !sp3 && !sp4) type = HP_TET_2EA_1VA; if (!sp2 && sp3 && !sp4) type = HP_TET_2EA_1VB; if (!sp2 && !sp3 && sp4) type = HP_TET_2EA_1VC; if (sp2 && sp3 && !sp4) type = HP_TET_2EA_2VA; if (sp2 && !sp3 && sp4) type = HP_TET_2EA_2VB; if (!sp2 && sp3 && sp4) type = HP_TET_2EA_2VC; if (sp2 && sp3 && sp4) type = HP_TET_2EA_3V; } if (isedge1 && isedge6) { if (!sp1 && !sp2 && !sp3 && !sp4) type = HP_TET_2EB_0V; if (sp1 && !sp2 && !sp3 && !sp4) type = HP_TET_2EB_1V; if (sp1 && sp2 && !sp3 && !sp4) type = HP_TET_2EB_2VA; if (sp1 && !sp2 && sp3 && !sp4) type = HP_TET_2EB_2VB; if (sp1 && !sp2 && !sp3 && sp4) type = HP_TET_2EB_2VC; if (sp1 && sp2 && sp3 && !sp4) type = HP_TET_2EB_3V; if (sp1 && sp2 && sp3 && sp4) type = HP_TET_2EB_4V; } break; } case 3: { if (isedge1 && isedge2 && isedge3) { if (!sp2 && !sp3 && !sp4) type = HP_TET_3EA_0V; if (sp2 && !sp3 && !sp4) type = HP_TET_3EA_1V; if (sp2 && sp3 && !sp4) type = HP_TET_3EA_2V; if (sp2 && sp3 && sp4) type = HP_TET_3EA_3V; } if (isedge1 && isedge3 && isedge4) { if (!sp3 && !sp4) type = HP_TET_3EB_0V; if (sp3 && !sp4) type = HP_TET_3EB_1V; if (sp3 && sp4) type = HP_TET_3EB_2V; } if (isedge1 && isedge2 && isedge5) { if (!sp3 && !sp4) type = HP_TET_3EC_0V; if (sp3 && !sp4) type = HP_TET_3EC_1V; if (sp3 && sp4) type = HP_TET_3EC_2V; } if (isedge1 && isedge2 && isedge4) { if (!sp4) type = HP_TET_3ED_3V; // a loop } break; } } break; } case 1: // one singular face { if (!isface[0]) break; /* cout << "1F and 1E, isedge = " << isedge1 << isedge2 << isedge3 << isedge4 << isedge5 << isedge6 << endl; cout << "spoints = " << sp1 << sp2 << sp3 << sp4 << endl; cout << "cpoints = " << cp1 << cp2 << cp3 << cp4 << endl; cout << "epoints = " << ep1 << ep2 << ep3 << ep4 << endl; cout << "fpoints = " << fp1 << fp2 << fp3 << fp4 << endl; */ isedge1 |= isfedge1; isedge2 |= isfedge2; isedge3 |= isfedge3; // switch (isedge1+isedge2+isedge3+isedge4+isedge5+isedge6) switch (se1+se2+se3+se4+se5+se6) { 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; if (!fp1 && ep2 && ep3 & !ep4) type = HP_TET_1F_0E_2V; if (!sp1 && sp2 && sp3 && sp4) type = HP_TET_1F_0E_3V; break; } case 1: { if (se1) { if (!sp1 && !sp3 && !sp4) type = HP_TET_1F_1EA_0V; if (!sp1 && sp2 && sp3 && !sp4) type = HP_TET_1F_1E_2VA; if (!sp1 && sp2 && !sp3 && sp4) type = HP_TET_1F_1E_2VB; if (!sp1 && !sp2 && sp3 && sp4) type = HP_TET_1F_1E_2VC; if (!sp1 && sp2 && sp3 && sp4) type = HP_TET_1F_1EA_3V; } if (se4) // V2-V3 { if (!sp1 && !sp2 && !sp3 && !sp4) type = HP_TET_1F_1EB_0V; if (!sp1 && sp2 && !sp3 && !sp4) type = HP_TET_1F_1E_1VA; if (!sp1 && sp2 && sp3 && sp4) type = HP_TET_1F_1E_3V; } if (se5) // V2-V4 { if (!sp1 && sp2 && !sp3 && !sp4) type = HP_TET_1F_1E_1VB; } break; } case 2: { if (isedge1 && isedge2) { if (sp1 && sp2 && sp3 && !sp4) type = HP_TET_1F_2Eoo_3V; } if (isedge6 && isedge3) if (!cp1 && !cp2 && !cp3) type = HP_TET_1F_2E_0VA; if (isedge6 && isedge2) { if (!cp1 && !cp2 && !cp4) type = HP_TET_1F_2E_0VB; } if (se4 && se5) { // 2 edges in face if (!sp1 && sp2 && !sp3 && !sp4) type = HP_TET_1F_2E_1V; if (!sp1 && sp2 && sp3 && sp4) type = HP_TET_1F_2E_3V; } break; } default: ; } break; } case 2: // two singular faces { if (!isface[0] || !isface[1]) break; switch (isfedge1+isedge2+isedge3+isedge4+isedge5) { case 0: { if (!ep1 && !ep2 && !cp3 && !cp4) { type = HP_TET_2F_0E_0V; break; } if (!ep1 && !ep2 && !cp3 && cp4) { type = HP_TET_2F_0E_1V; break; } break; } case 1: { // *testout << "so far: 2F, 1E, sp = " << sp1 << sp2 << sp3 << sp4 << endl; if (isedge4) { if (!ep1 && !cp2 && !cp4) { type = HP_TET_2F_1E_0VA; break; } if (!sp1 && sp2 && sp3 && sp4) { type = HP_TET_2F_1E_3VA; break; } if (sp1 && sp2 && sp3 && sp4) { type = HP_TET_2F_1E_4VA; break; } } if (isedge5 && !ep1 && !cp2 && !cp3) { type = HP_TET_2F_1E_0VB; break; } break; } default: *testout << "2F, 2E or more not implemented so far" << endl; } break; } case 3: { if (!isface[3]) if (!cp1 && !cp2 && !cp3) { type = HP_TET_3F_0E_0V; break; } break; } case 4: { *testout << "4 singular faces" << endl; } } if (type != HP_NONE) { PointIndex 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) << "unclassified element " << el.pnums[0] << " " << el.pnums[1] << " " << el.pnums[2] << " " << el.pnums[3] << endl << "cp = " << cp1 << cp2 << cp3 << cp4 << endl << "ep = " << ep1 << ep2 << ep3 << ep4 << endl << "fp = " << fp1 << fp2 << fp3 << fp4 << endl << "isedge = " << isedge1 << isedge2 << isedge3 << isedge4 << isedge5 << isedge6 << endl << "isfedge = " << isfedge1 << isfedge2 << isfedge3 << isfedge4 << isfedge5 << isfedge6 << endl << "isface = " << isface[0] << isface[1] << isface[2] << isface[3] << endl; cout << "unclassified element !!! " << endl; } return(type); } HPREF_ELEMENT_TYPE ClassifyPrism(HPRefElement & el, INDEX_2_HASHTABLE & edges, HT_EDGEPOINT_DOM & edgepoint_dom, TBitArray & cornerpoint, TBitArray & edgepoint, INDEX_3_HASHTABLE & faces, INDEX_2_HASHTABLE & face_edges, INDEX_2_HASHTABLE & surf_edges, Array & 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++) { PointIndices<2> i2 = PointIndices<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++) { PointIndices<3> i3; if(k<2) i3 = PointIndices<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 { PointIndices<4> i4 (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 = PointIndices<3>(i4[0], i4[1], i4[2]); } 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) { PointIndex 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 & edges, HT_EDGEPOINT_DOM & edgepoint_dom, TBitArray & cornerpoint, TBitArray & edgepoint, INDEX_3_HASHTABLE & faces, INDEX_2_HASHTABLE & face_edges, INDEX_2_HASHTABLE & surf_edges, Array & facepoint, int dim, const FaceDescriptor & fd) { HPREF_ELEMENT_TYPE type = HP_NONE; PointIndex pnums[3]; int p[3]; PointIndices<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]; PointIndices<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]; PointIndices<2> i2 = PointIndices<2>::Sort(el.PNum(ep1),el.PNum(ep2)); if(edges.Used(i2)) { if(edgepoint_dom.Used( { fd.SurfNr(),pnums[ep1-1] } ) || edgepoint_dom.Used( { -1,pnums[ep1-1] } ) || edgepoint_dom.Used( { fd.SurfNr(), pnums[ep2-1]} ) || edgepoint_dom.Used( { -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]) && (dim==3 || edgepoint_dom.Used( { fd.SurfNr(),pnums[k] } ) || edgepoint_dom.Used( { -1,pnums[k] } ))) //edgepoint, but not member of sing_edge on trig -> cp { PointIndices<2> i2a = PointIndices<2>::Sort(el.PNum(p[k]), el.PNum(p[(k+1)%3])); PointIndices<2> i2b = PointIndices<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 & edges, INDEX_2_HASHTABLE & edgepoint_dom, NgBitArray & cornerpoint, NgBitArray & edgepoint, INDEX_3_HASHTABLE & faces, INDEX_2_HASHTABLE & face_edges, INDEX_2_HASHTABLE & surf_edges, NgArray & 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 & edges, HT_EDGEPOINT_DOM & edgepoint_dom, TBitArray & cornerpoint, TBitArray & edgepoint, INDEX_3_HASHTABLE & faces, INDEX_2_HASHTABLE & face_edges, INDEX_2_HASHTABLE & surf_edges, Array & 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 ( { el.GetIndex(), el.PNumMod(j) } ); ep2 = edgepoint_dom.Used ( { el.GetIndex(), el.PNumMod(j+1) } ); ep3 = edgepoint_dom.Used ( { el.GetIndex(), el.PNumMod(j+2) }); ep4 = edgepoint_dom.Used ( { 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; PointIndex 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) { PointIndices<2> i2 = PointIndices<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 & edges, HT_EDGEPOINT_DOM & edgepoint_dom, TBitArray & cornerpoint, TBitArray & edgepoint, INDEX_3_HASHTABLE & faces, INDEX_2_HASHTABLE & face_edges, INDEX_2_HASHTABLE & surf_edges, Array & 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 ClassifyHex7 (HPRefElement & el, INDEX_2_HASHTABLE & edges, HT_EDGEPOINT_DOM & edgepoint_dom, TBitArray & cornerpoint, TBitArray & edgepoint, INDEX_3_HASHTABLE & faces, INDEX_2_HASHTABLE & face_edges, INDEX_2_HASHTABLE & surf_edges, Array & facepoint) { // HPREF_ELEMENT_TYPE type = HP_NONE; // no singular // singular bottom // singular top // 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); INDEX_4 fbot4 = { el.pnums[0], el.pnums[1], el.pnums[2], el.pnums[3] }; INDEX_3 ftop = { el.pnums[4], el.pnums[5], el.pnums[6] }; fbot4.Sort(); INDEX_3 fbot = { fbot4[0], fbot4[1], fbot4[2] }; ftop.Sort(); bool singbot = faces.Used(fbot); bool singtop = faces.Used(ftop); if (singbot) el.type = HP_HEX7_1FA; else if (singtop) el.type = HP_HEX7_1FB; else el.type = HP_HEX7; return el.type; } HPREF_ELEMENT_TYPE ClassifySegm(HPRefElement & hpel, INDEX_2_HASHTABLE & edges, HT_EDGEPOINT_DOM & edgepoint_dom, TBitArray & cornerpoint, TBitArray & edgepoint, INDEX_3_HASHTABLE & faces, INDEX_2_HASHTABLE & face_edges, INDEX_2_HASHTABLE & surf_edges, Array & 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 & edges, HT_EDGEPOINT_DOM & edgepoint_dom, TBitArray & cornerpoint, TBitArray & edgepoint, INDEX_3_HASHTABLE & faces, INDEX_2_HASHTABLE & face_edges, INDEX_2_HASHTABLE & surf_edges, Array & facepoint) { // *testout << "classify pyramid, pnums = "; // for (int i = 0; i < 5; i++) *testout << el.pnums[i] << " "; // *testout << endl; 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++) { *testout << "m = " << m << endl; 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 (k < 4) { i3 = INDEX_3(el.pnums[p[elfaces[k][0]-1]], el.pnums[p[elfaces[k][1]-1]], el.pnums[p[elfaces[k][2]-1]]); i3.Sort(); } else { 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]; } *testout << "point_sing: "; for (int k = 0; k < 5; k++) *testout << point_sing[k] << " "; *testout << endl; *testout << "edge_sing: "; for (int k = 0; k < 4; k++) *testout << edge_sing[k] << " "; *testout << endl; *testout << "face_sing: "; for (int k = 0; k < 5; k++) *testout << face_sing[k] << " "; *testout << endl; 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) { if (point_sing[4] == 1) type = HP_PYRAMID_1FB_0E_0V; else 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); } ================================================ FILE: libsrc/meshing/clusters.cpp ================================================ #include #include "clusters.hpp" namespace netgen { AnisotropicClusters :: AnisotropicClusters (const Mesh & amesh) : mesh(amesh) { ; } AnisotropicClusters :: ~AnisotropicClusters () { ; } void AnisotropicClusters :: Update() { static Timer timer("clusters"); // static int timer1 = NgProfiler::CreateTimer ("clusters1"); // static int timer2 = NgProfiler::CreateTimer ("clusters2"); // static int timer3 = NgProfiler::CreateTimer ("clusters3"); RegionTimer reg (timer); constexpr auto PI0 = IndexBASE(); const MeshTopology & top = mesh.GetTopology(); auto id = this->mesh.GetCommunicator().Rank(); // auto ntasks = this->mesh.GetCommunicator().Size(); 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); cluster_reps = -1; NgArray llist (nv+ned+nfa+ne); llist = 0; NgArray nnums, ednums, fanums; int changed; // NgProfiler::StartTimer(timer1); /* for (int 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 (int j = 1; j <= elnv; j++) nnums.Elem(j) = el.PNum(j); for (int j = 1; j <= elned; j++) nnums.Elem(elnv+j) = nv+ednums.Elem(j); for (int 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 (int j = 0; j < nnums.Size(); j++) cluster_reps.Elem(nnums[j]) = nnums[j]; } */ ngcore::ParallelForRange (mesh.VolumeElements().Range(), [&] (auto myrange) { NgArray nnums; // , ednums, fanums; for (auto i_ : myrange) { int i = i_-IndexBASE()+1; const Element & el = mesh.VolumeElement(i_); ELEMENT_TYPE typ = el.GetType(); // top.GetElementEdges (i, ednums); // auto ednums = top.GetEdges (ElementIndex(i_)); auto ednums = top.GetEdges (i_); // top.GetElementFaces (i, fanums); // auto fanums = top.GetFaces (ElementIndex(i_)); auto fanums = top.GetFaces (i_); int elnv = top.GetNVertices (typ); int elned = ednums.Size(); int elnfa = fanums.Size(); nnums.SetSize(elnv+elned+elnfa+1); for (int j = 0; j < elnv; j++) nnums[j] = el[j]+1-PI0; for (int j = 0; j < elned; j++) nnums[elnv+j] = nv+ednums[j]+1; for (int j = 0; j < elnfa; j++) nnums[elnv+elned+j] = nv+ned+fanums[j]+1; nnums[elnv+elned+elnfa] = nv+ned+nfa+i; for (int j = 0; j < nnums.Size(); j++) cluster_reps.Elem(nnums[j]) = nnums[j]; } }, ngcore::TasksPerThread(4)); // NgProfiler::StopTimer(timer1); // NgProfiler::StartTimer(timer2); /* for (int 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 (int j = 1; j <= elnv; j++) nnums.Elem(j) = el.PNum(j)+1-PI0; for (int j = 1; j <= elned; j++) nnums.Elem(elnv+j) = nv+ednums.Elem(j); nnums.Elem(elnv+elned+1) = fanum; for (int j = 0; j < nnums.Size(); j++) cluster_reps.Elem(nnums[j]) = nnums[j]; } */ ngcore::ParallelForRange (mesh.SurfaceElements().Range(), [&] (auto myrange) { NgArrayMem nnums; // , ednums; for (SurfaceElementIndex i_ : myrange) { // int i = i_+1; const Element2d & el = mesh[i_]; // .SurfaceElement(i); ELEMENT_TYPE typ = el.GetType(); // top.GetSurfaceElementEdges (i, ednums); auto ednums = top.GetEdges (i_); // cout << "ednums = " << ednums << endl; int fanum = top.GetFace(i_)+1; int elnv = top.GetNVertices (typ); int elned = ednums.Size(); nnums.SetSize(elnv+elned+1); for (int j = 0; j < elnv; j++) nnums[j] = el[j]+1-PI0; for (int j = 0; j < elned; j++) nnums[elnv+j] = nv+ednums[j]+1; nnums[elnv+elned] = fanum; for (int j = 0; j < nnums.Size(); j++) cluster_reps.Elem(nnums[j]) = nnums[j]; } }, ngcore::TasksPerThread(4)); // NgProfiler::StopTimer(timer2); // NgProfiler::StartTimer(timer3); 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 { static Timer t("update cluster, identify"); RegionTimer rtr(t); // cnt++; changed = 0; for (int i = 1; i <= ne; i++) { ElementIndex ei(i-1); const Element & el = mesh[ei]; ELEMENT_TYPE typ = el.GetType(); 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)+1-PI0) == cluster_reps.Get(el.PNum(2)+1-PI0)) clustertab = tet_cluster12; else if (cluster_reps.Get(el.PNum(1)+1-PI0) == cluster_reps.Get(el.PNum(3)+1-PI0)) clustertab = tet_cluster13; else if (cluster_reps.Get(el.PNum(1)+1-PI0) == cluster_reps.Get(el.PNum(4)+1-PI0)) clustertab = tet_cluster14; else if (cluster_reps.Get(el.PNum(2)+1-PI0) == cluster_reps.Get(el.PNum(3)+1-PI0)) clustertab = tet_cluster23; else if (cluster_reps.Get(el.PNum(2)+1-PI0) == cluster_reps.Get(el.PNum(4)+1-PI0)) clustertab = tet_cluster24; else if (cluster_reps.Get(el.PNum(3)+1-PI0) == cluster_reps.Get(el.PNum(4)+1-PI0)) clustertab = tet_cluster34; else clustertab = NULL; break; default: clustertab = NULL; } if (clustertab) { // top.GetElementEdges (i, ednums); // top.GetElementFaces (i, fanums); auto ednums = top.GetEdges (ei); auto fanums = top.GetFaces (ei); int elnv = top.GetNVertices (typ); int elned = ednums.Size(); int elnfa = fanums.Size(); nnums.SetSize(elnv+elned+elnfa+1); for (int j = 0; j < elnv; j++) nnums[j] = el[j]+1-IndexBASE(); for (int j = 0; j < elned; j++) nnums[elnv+j] = nv+ednums[j]+1; for (int j = 0; j < elnfa; j++) nnums[elnv+elned+j] = nv+ned+fanums[j]+1; nnums[elnv+elned+elnfa] = nv+ned+nfa+i; for (int j = 0; j < nnums.Size(); j++) for (int k = 0; k < j; k++) if (clustertab[j] == clustertab[k]) { int jj = nnums[j]; int kk = nnums[k]; if (cluster_reps.Get(kk) < cluster_reps.Get(jj)) swap (jj,kk); if (cluster_reps.Get(jj) < cluster_reps.Get(kk)) { /* cluster_reps.Elem(kk) = cluster_reps.Get(jj); changed = 1; */ int rep = cluster_reps.Get(jj); int next = cluster_reps.Get(kk); do { int cur = next; next = llist.Elem(next); cluster_reps.Elem(cur) = rep; llist.Elem(cur) = llist.Elem(rep); llist.Elem(rep) = cur; } while (next); 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); // NgProfiler::StopTimer(timer3); /* (*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; } */ } } ================================================ FILE: libsrc/meshing/clusters.hpp ================================================ #ifndef NETGEN_CLUSTERS_HPP #define NETGEN_CLUSTERS_HPP /**************************************************************************/ /* File: clusers.hh */ /* Author: Joachim Schoeberl */ /* Date: 28. Apr. 01 */ /**************************************************************************/ /* Anisotropic clusters nodes, edges, faces, elements */ #include "meshclass.hpp" namespace netgen { class AnisotropicClusters { const Mesh & mesh; int nv, ned, nfa, ne; // connected nodes, nodes = vertices, edges, faces, elements NgArray 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); } }; } // namespace netgen #endif // NETGEN_CLUSTERS_HPP ================================================ FILE: libsrc/meshing/curvedelems.cpp ================================================ #include #include "curvedelems.hpp" #include "basegeom.hpp" #include "hprefinement.hpp" // #include "meshing.hpp" // #include "../general/autodiff.hpp" namespace netgen { using namespace std; // bool rational = true; static void ComputeGaussRule (int n, NgArray & xi, NgArray & 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) // integrated Legendre pols, starting with order 2 template static void CalcEdgeShape (int n, T x, T * shape) { T 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; } } template static void CalcEdgeShapeLambda (int n, T x, FUNC func) { T p1(x), p2(-1.0), p3(0.0); for (int j=2; j<=n; j++) { p3=p2; p2=p1; p1=( (2*j-3) * x * p2 - (j-3) * p3) / j; func(j-2, p1); } } template static void CalcEdgeDx (int n, T x, T * dshape) { T p1 = x, p2 = -1, p3 = 0; T 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; } } template static void CalcEdgeShapeDx (int n, T x, T * shape, T * dshape) { T p1 = x, p2 = -1, p3 = 0; T 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 template static void CalcScaledEdgeShape (int n, T x, T t, T * 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; } T p1 = x, p2 = -1, p3 = 0; T 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 static void CalcScaledEdgeShapeLambda (int n, T x, T t, FUNC func) { 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; } T p1(x), p2(-1.0), p3(0.0); T 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); func(j, p1); } } template static void CalcScaledEdgeShapeDxDt (int n, T x, T t, T * dshape) { T p1 = x, p2 = -1, p3 = 0; T p1dx = 1, p1dt = 0; T p2dx = 0, p2dt = 0; T 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 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 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; } } } class RecPol { protected: int maxorder; double *a, *b, *c; public: RecPol (int amaxorder) { maxorder = amaxorder; a = new double[maxorder+1]; b = new double[maxorder+1]; c = new double[maxorder+1]; } ~RecPol () { delete [] a; delete [] b; delete [] c; } template void Evaluate (int n, S x, T * values) { S p1(1.0), p2(0.0), p3; if (n >= 0) p2 = values[0] = 1.0; if (n >= 1) p1 = values[1] = a[0]+b[0]*x; for (int i = 1; i < n; i++) { p3 = p2; p2=p1; p1 = (a[i]+b[i]*x)*p2-c[i]*p3; values[i+1] = p1; } } template void EvaluateLambda (int n, S x, FUNC func) { S p1(1.0), p2(0.0), p3; if (n >= 0) { // p2 = values[0] = 1.0; p2 = 1.0; func(0,p2); } if (n >= 1) { // p1 = values[1] = a[0]+b[0]*x; p1 = a[0]+b[0]*x; func(1,p1); } for (int i = 1; i < n; i++) { p3 = p2; p2=p1; p1 = (a[i]+b[i]*x)*p2-c[i]*p3; // values[i+1] = p1; func(i+1, p1); } } template void EvaluateScaled (int n, S x, S y, T * values) { S p1(1.0), p2(0.0), p3; if (n >= 0) p2 = values[0] = 1.0; if (n >= 1) p1 = values[1] = a[0]*y+b[0]*x; for (int i = 1; i < n; i++) { p3 = p2; p2=p1; p1 = (a[i]*y+b[i]*x)*p2-c[i]*y*y*p3; values[i+1] = p1; } } template void EvaluateScaledLambda (int n, S x, S y, FUNC func) { S p1(1.0), p2(0.0), p3; if (n >= 0) { p2 = 1.0; func(0, p2); } if (n >= 1) { p1 = a[0]*y+b[0]*x; func(1, p1); } for (int i = 1; i < n; i++) { p3 = p2; p2=p1; p1 = (a[i]*y+b[i]*x)*p2-c[i]*y*y*p3; func(i+1, p1); } } }; class JacobiRecPol : public RecPol { public: JacobiRecPol (int amo, double al, double be) : RecPol (amo) { for (int i = 0; i <= maxorder; i++) { double den = 2*(i+1)*(i+al+be+1)*(2*i+al+be); a[i] = (2*i+al+be+1)*(al*al-be*be) / den; b[i] = (2*i+al+be)*(2*i+al+be+1)*(2*i+al+be+2) / den; c[i] = 2*(i+al)*(i+be)*(2*i+al+be+2) / den; } } }; /* template 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 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; } } */ // Jacobi polynomials alpah, beta=2 struct JacobiRecPols { static constexpr size_t N = 100; ArrayMem, N> jacpols; JacobiRecPols() { jacpols.SetSize (N); for (int i = 0; i < N; i++) jacpols[i] = make_unique(N, i, 2); } const unique_ptr & operator[] (int i) { return jacpols[i]; } }; static JacobiRecPols jacpols2; static JacobiRecPol jacpol00(100,0,0); static JacobiRecPol jacpol11(100,1,1); static JacobiRecPol jacpol22(100,2,2); // compute face bubbles up to order n, 0 < y, y-x < 1, x+y < 1 template static void CalcTrigShape (int n, Tx x, Ty y, Ts * shape) { // cout << "calc trig shape" << endl; if (n < 3) return; Tx hx[50], hy[50*50]; jacpols2[2] -> EvaluateScaled (n-3, x, 1-y, hx); for (int ix = 0; ix <= n-3; ix++) jacpols2[2*ix+5] -> Evaluate (n-3, 2*y-1, hy+50*ix); int ii = 0; Tx bub = (1+x-y)*y*(1-x-y); for (int ix = 0; ix <= n-3; ix++) hx[ix] *= bub; /* for (int iy = 0; iy <= n-3; iy++) for (int ix = 0; ix <= n-3-iy; ix++) shape[ii++] = hx[ix]*hy[iy+50*ix]; */ // change loops: for (int ix = 0; ix <= n-3; ix++) for (int iy = 0; iy <= n-3-ix; iy++) shape[ii++] = hx[ix]*hy[iy+50*ix]; } template static void CalcTrigShapeDxDy (int n, T x, T y, T * dshape) { if (n < 3) return; AutoDiff<2,T> adx(x, 0); AutoDiff<2,T> ady(y, 1); AutoDiff<2,T> 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); } } // compute face bubbles up to order n, 0 < y, y-x < 1, x+y < 1 template static void CalcScaledTrigShape (int n, Tx x, Ty y, Tt t, Tr * shape) { if (n < 3) return; /* Tx hx[50], hy[50]; ScaledJacobiPolynomial (n-3, x, t-y, 2, 2, hx); int ii = 0; Tx bub = (t+x-y)*y*(t-x-y); for (int ix = 0; ix <= n-3; ix++) { jacpols2[2*ix+5] -> EvaluateScaled (n-3, 2*y-1, t, hy); for (int iy = 0; iy <= n-3-ix; iy++) shape[ii++] = bub * hx[ix]*hy[iy]; } */ int ii = 0; Tx bub = (t+x-y)*y*(t-x-y); jacpols2[2]->EvaluateScaledLambda (n-3, x, t-y, [&](int ix, Tx valx) { jacpols2[2*ix+5] -> EvaluateScaledLambda (n-3-ix, 2*y-1, t, [&](int iy, Ty valy) { shape[ii++] = bub*valx*valy; }); }); } template static void CalcScaledTrigShapeLambda (int n, Tx x, Ty y, Tt t, FUNC func) { if (n < 3) return; int ii = 0; Tx bub = (t+x-y)*y*(t-x-y); jacpols2[2]->EvaluateScaledLambda (n-3, x, t-y, [&](int ix, Tx valx) { jacpols2[2*ix+5] -> EvaluateScaledLambda (n-3-ix, 2*y-1, t, [&](int iy, Ty valy) { func(ii++, bub*valx*valy); }); }); } // compute face bubbles up to order n, 0 < y, y-x < 1, x+y < 1 template static void CalcScaledTrigShapeDxDyDt (int n, T x, T y, T t, T * dshape) { /* if (n < 3) return; AutoDiff<3,T> adx(x, 0); AutoDiff<3,T> ady(y, 1); AutoDiff<3,T> adt(t, 2); AutoDiff<3,T> 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); } */ if (n < 3) return; AutoDiff<3,T> adx(x, 0); AutoDiff<3,T> ady(y, 1); AutoDiff<3,T> adt(t, 2); CalcScaledTrigShapeLambda (n, adx, ady, adt, [&] (int i, AutoDiff<3,T> shape) { dshape[3*i] = shape.DValue(0); dshape[3*i+1] = shape.DValue(1); dshape[3*i+2] = shape.DValue(2); }); } // tensor product of Jacobi(2,2) // x,y in (-1,1) template static void CalcQuadShapeLambda (int n, Tx x, Ty y, FUNC func) { if (n < 2) return; int ii = 0; Tx bub = (1-x*x)*(1-y*y); jacpol22.EvaluateLambda (n-2, x, [&](int ix, Tx valx) { jacpol22.EvaluateLambda (n-2, y, [&](int iy, Ty valy) { func(ii++, bub*valx*valy); }); }); } template static void CalcScaledQuadShapeLambda (int n, Tx x, Ty y, Tsx sx, Tsy sy, FUNC func) { if (n < 2) return; int ii = 0; Tx bub = (1-x*x)*(1-y*y); jacpol22.EvaluateScaledLambda (n-2, x, sx, [&](int ix, Tx valx) { jacpol22.EvaluateScaledLambda (n-2, y, sy, [&](int iy, Ty valy) { func(ii++, bub*valx*valy); }); }); } CurvedElements :: CurvedElements (const Mesh & amesh) : mesh(amesh) { order = 1; rational = 0; ishighorder = 0; } CurvedElements :: ~CurvedElements() { } void CurvedElements :: DoArchive(Archive& ar) { ar & edgeorder & faceorder & edgecoeffsindex & facecoeffsindex & edgecoeffs & facecoeffs & edgeweight & order & rational & ishighorder; } void CurvedElements :: BuildCurvedElements(const Refinement * ref, int aorder, bool arational) { auto & geo = *mesh.GetGeometry(); ishighorder = 0; order = 1; auto comm = mesh.GetCommunicator(); #ifdef PARALLEL enum { NG_MPI_TAG_CURVE = NG_MPI_TAG_MESH+20 }; const ParallelMeshTopology & partop = mesh.GetParallelTopology (); #endif int ntasks = comm.Size(); bool working = (ntasks == 1) || (comm.Rank() > 0); if (working) order = aorder; if (mesh.coarsemesh) { mesh.coarsemesh->GetCurvedElements().BuildCurvedElements (ref, aorder, arational); order = aorder; rational = arational; ishighorder = (order > 1); return; } PrintMessage (1, "Curve elements, order = ", aorder); if (rational) PrintMessage (1, "curved elements with rational splines"); // if (working) const_cast (mesh).UpdateTopology(); const MeshTopology & top = mesh.GetTopology(); rational = arational; NgArray edgenrs; int nedges = top.GetNEdges(); int nfaces = top.GetNFaces(); edgeorder.SetSize (nedges); faceorder.SetSize (nfaces); edgeorder = 1; faceorder = 1; if (rational) { edgeweight.SetSize (nedges); edgeweight = 1.0; } if (aorder <= 1) { for (ElementIndex ei : mesh.VolumeElements().Range()) if (mesh[ei].GetType() == TET10) ishighorder = 1; return; } if (rational) aorder = 2; if (working) { if (mesh.GetDimension() == 3) for (SurfaceElementIndex i = 0; i < mesh.GetNSE(); i++) { // top.GetEdges (i, edgenrs); auto edgenrs = top.GetEdges (i); for (int j = 0; j < edgenrs.Size(); j++) edgeorder[edgenrs[j]] = aorder; faceorder[top.GetFace (i)] = aorder; } for (SegmentIndex i = 0; i < mesh.GetNSeg(); i++) edgeorder[top.GetEdge (i)] = aorder; } if (rational) { edgeorder = 2; faceorder = 1; } #ifdef PARALLEL // TABLE send_orders(ntasks), recv_orders(ntasks); DynamicTable send_orders(ntasks), recv_orders(ntasks); if (ntasks > 1 && working) { for (int e = 0; e < edgeorder.Size(); e++) for (int proc : partop.GetDistantEdgeProcs(e)) send_orders.Add (proc, edgeorder[e]); for (int f = 0; f < faceorder.Size(); f++) for (int proc : partop.GetDistantFaceProcs(f)) send_orders.Add (proc, faceorder[f]); } if (ntasks > 1) // MyMPI_ExchangeTable (send_orders, recv_orders, NG_MPI_TAG_CURVE, comm); comm.ExchangeTable (send_orders, recv_orders, NG_MPI_TAG_CURVE); if (ntasks > 1 && working) { Array cnt(ntasks); cnt = 0; for (int e = 0; e < edgeorder.Size(); e++) for (auto proc : partop.GetDistantEdgeProcs(e)) edgeorder[e] = max(edgeorder[e], recv_orders[proc][cnt[proc]++]); for (int f = 0; f < faceorder.Size(); f++) for (auto proc : partop.GetDistantFaceProcs(f)) faceorder[f] = max(faceorder[f], recv_orders[proc][cnt[proc]++]); } #endif edgecoeffsindex.SetSize (nedges+1); int nd = 0; for (int i = 0; i < nedges; i++) { edgecoeffsindex[i] = nd; nd += max (0, edgeorder[i]-1); } edgecoeffsindex[nedges] = nd; edgecoeffs.SetSize (nd); edgecoeffs = Vec<3> (0,0,0); facecoeffsindex.SetSize (nfaces+1); nd = 0; for (int i = 0; i < nfaces; i++) { facecoeffsindex[i] = nd; if (top.GetFaceType0(i) == TRIG) nd += max2 (0, (faceorder[i]-1)*(faceorder[i]-2)/2); else nd += max2 (0, sqr(faceorder[i]-1)); } facecoeffsindex[nfaces] = nd; facecoeffs.SetSize (nd); facecoeffs = Vec<3> (0,0,0); if (!ref || aorder <= 1) { order = aorder; return; } NgArray xi, weight; ComputeGaussRule (aorder+4, xi, weight); // on (0,1) PrintMessage (3, "Curving edges"); if (mesh.GetDimension() == 3 || rational) { static Timer tce("curve edges"); RegionTimer reg(tce); NgArray surfnr(nedges); NgArray gi0(nedges); NgArray gi1(nedges); surfnr = -1; if (working) for (SurfaceElementIndex i = 0; i < mesh.GetNSE(); i++) { // top.GetEdges (i, edgenrs); auto edgenrs = top.GetEdges(i); const Element2d & el = mesh[i]; const ELEMENT_EDGE * edges = MeshTopology::GetEdges0 (el.GetType()); for (int i2 = 0; i2 < edgenrs.Size(); i2++) { auto enr = edgenrs[i2]; surfnr[enr] = mesh.GetFaceDescriptor(el.GetIndex()).SurfNr(); if (el[edges[i2][0]] < el[edges[i2][1]]) { gi0[enr] = el.GeomInfoPi(edges[i2][0]+1); gi1[enr] = el.GeomInfoPi(edges[i2][1]+1); } else { gi1[enr] = el.GeomInfoPi(edges[i2][0]+1); gi0[enr] = el.GeomInfoPi(edges[i2][1]+1); } } } #ifdef PARALLEL if (ntasks > 1) { // distribute it ... // TABLE senddata(ntasks), recvdata(ntasks); DynamicTable senddata(ntasks), recvdata(ntasks); if (working) for (int e = 0; e < nedges; e++) for (int proc : partop.GetDistantEdgeProcs(e)) { senddata.Add (proc, surfnr[e]); if (surfnr[e] != -1) { senddata.Add (proc, gi0[e].trignum); senddata.Add (proc, gi0[e].u); senddata.Add (proc, gi0[e].v); senddata.Add (proc, gi1[e].trignum); senddata.Add (proc, gi1[e].u); senddata.Add (proc, gi1[e].v); } } // MyMPI_ExchangeTable (senddata, recvdata, NG_MPI_TAG_CURVE, comm); comm.ExchangeTable (senddata, recvdata, NG_MPI_TAG_CURVE); NgArray cnt(ntasks); cnt = 0; if (working) for (int e = 0; e < nedges; e++) for (int proc : partop.GetDistantEdgeProcs(e)) { int surfnr1 = recvdata[proc][cnt[proc]++]; if (surfnr1 != -1) { surfnr[e] = surfnr1; gi0[e].trignum = int (recvdata[proc][cnt[proc]++]); gi0[e].u = recvdata[proc][cnt[proc]++]; gi0[e].v = recvdata[proc][cnt[proc]++]; gi1[e].trignum = int (recvdata[proc][cnt[proc]++]); gi1[e].u = recvdata[proc][cnt[proc]++]; gi1[e].v = recvdata[proc][cnt[proc]++]; } } } #endif if (working) for (int e = 0; e < surfnr.Size(); e++) { if (surfnr[e] == -1) continue; SetThreadPercent(double(e)/surfnr.Size()*100.); // PointIndex pi1, pi2; // top.GetEdgeVertices (e+1, pi1, pi2); auto [pi1,pi2] = top.GetEdgeVertices(e); bool swap = (pi1 > pi2); Point<3> p1 = mesh[pi1]; Point<3> p2 = mesh[pi2]; int order1 = edgeorder[e]; int ndof = max (0, order1-1); if (rational && order1 >= 2) { Point<3> pm = Center (p1, p2); Vec<3> n1 = geo.GetNormal (surfnr[e], p1, &gi0[e]); Vec<3> n2 = geo.GetNormal (surfnr[e], p2, &gi1[e]); // 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[e]] = 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); geo.ProjectPointGI(surfnr[e], pp05, gi0[e]); double d = Dist (pp05, p05); if (d < dold) { dold = d; wold = w; w += dw; } else { dw *= -0.7; w = wold + dw; } } edgeweight[e] = 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); geo.PointBetween (p1, p2, xi[j], surfnr[e], gi0[e], gi1[e], pp, ppgi); } else { p = p2 + xi[j] * (p1-p2); geo.PointBetween (p2, p1, xi[j], surfnr[e], gi1[e], gi0[e], 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[e]; for (int j = 0; j < ndof; j++) for (int k = 0; k < 3; k++) edgecoeffs[first+j](k) = sol(j,k); } } NgArray use_edge(nedges); NgArray edge_surfnr1(nedges); NgArray edge_surfnr2(nedges); NgArray swap_edge(nedges); NgArray edge_gi0(nedges); NgArray edge_gi1(nedges); use_edge = 0; if (working) for (SegmentIndex i = 0; i < mesh.GetNSeg(); i++) { const Segment & seg = mesh[i]; int edgenr = top.GetEdge (i); use_edge[edgenr] = 1; edge_surfnr1[edgenr] = seg.surfnr1; edge_surfnr2[edgenr] = seg.surfnr2; edge_gi0[edgenr] = seg.epgeominfo[0]; edge_gi1[edgenr] = seg.epgeominfo[1]; swap_edge[edgenr] = int (seg[0] > seg[1]); } #ifdef PARALLEL if (ntasks > 1) { // distribute it ... // TABLE senddata(ntasks), recvdata(ntasks); DynamicTable senddata(ntasks), recvdata(ntasks); if (working) for (int e = 0; e < nedges; e++) for (int proc : partop.GetDistantEdgeProcs(e)) { senddata.Add (proc, use_edge[e]); if (use_edge[e]) { senddata.Add (proc, edge_surfnr1[e]); senddata.Add (proc, edge_surfnr2[e]); senddata.Add (proc, edge_gi0[e].edgenr); senddata.Add (proc, edge_gi0[e].body); senddata.Add (proc, edge_gi0[e].dist); senddata.Add (proc, edge_gi0[e].u); senddata.Add (proc, edge_gi0[e].v); senddata.Add (proc, edge_gi1[e].edgenr); senddata.Add (proc, edge_gi1[e].body); senddata.Add (proc, edge_gi1[e].dist); senddata.Add (proc, edge_gi1[e].u); senddata.Add (proc, edge_gi1[e].v); senddata.Add (proc, swap_edge[e]); } } // MyMPI_ExchangeTable (senddata, recvdata, NG_MPI_TAG_CURVE, comm); comm.ExchangeTable (senddata, recvdata, NG_MPI_TAG_CURVE); NgArray cnt(ntasks); cnt = 0; if (working) for (int e = 0; e < edge_surfnr1.Size(); e++) for (int proc : partop.GetDistantEdgeProcs(e)) { int get_edge = int(recvdata[proc][cnt[proc]++]); if (get_edge) { use_edge[e] = 1; edge_surfnr1[e] = int (recvdata[proc][cnt[proc]++]); edge_surfnr2[e] = int (recvdata[proc][cnt[proc]++]); edge_gi0[e].edgenr = int (recvdata[proc][cnt[proc]++]); edge_gi0[e].body = int (recvdata[proc][cnt[proc]++]); edge_gi0[e].dist = recvdata[proc][cnt[proc]++]; edge_gi0[e].u = recvdata[proc][cnt[proc]++]; edge_gi0[e].v = recvdata[proc][cnt[proc]++]; edge_gi1[e].edgenr = int (recvdata[proc][cnt[proc]++]); edge_gi1[e].body = int (recvdata[proc][cnt[proc]++]); edge_gi1[e].dist = recvdata[proc][cnt[proc]++]; edge_gi1[e].u = recvdata[proc][cnt[proc]++]; edge_gi1[e].v = recvdata[proc][cnt[proc]++]; swap_edge[e] = recvdata[proc][cnt[proc]++]; } } } #endif if (working) for (int edgenr = 0; edgenr < use_edge.Size(); edgenr++) { int segnr = edgenr; if (!use_edge[edgenr]) continue; SetThreadPercent(double(edgenr)/edge_surfnr1.Size()*100.); // PointIndex pi1, pi2; // top.GetEdgeVertices (edgenr+1, pi1, pi2); auto [pi1,pi2] = top.GetEdgeVertices(edgenr); bool swap = swap_edge[edgenr]; // (pi1 > pi2); if (swap) Swap (pi1, pi2); Point<3> p1 = mesh[pi1]; Point<3> p2 = mesh[pi2]; int order1 = edgeorder[segnr]; int ndof = max (0, order1-1); if (rational) { Vec<3> tau1 = geo.GetTangent(p1, edge_surfnr2[edgenr], edge_surfnr1[edgenr], edge_gi0[edgenr]); Vec<3> tau2 = geo.GetTangent(p2, edge_surfnr2[edgenr], edge_surfnr1[edgenr], edge_gi1[edgenr]); // 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 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); geo.ProjectPointEdge(edge_surfnr1[edgenr], edge_surfnr2[edgenr], pp05, &edge_gi0[edgenr]); 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, pp; EdgePointGeomInfo ppgi; if (swap) { p = p1 + xi[j] * (p2-p1); geo.PointBetweenEdge(p1, p2, xi[j], edge_surfnr2[edgenr], edge_surfnr1[edgenr], edge_gi0[edgenr], edge_gi1[edgenr], pp, ppgi); } else { p = p2 + xi[j] * (p1-p2); geo.PointBetweenEdge(p2, p1, xi[j], edge_surfnr2[edgenr], edge_surfnr1[edgenr], edge_gi1[edgenr], edge_gi0[edgenr], 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"); NgArray surfnr(nfaces); surfnr = -1; if (working) for (SurfaceElementIndex i = 0; i < mesh.GetNSE(); i++) surfnr[top.GetFace(i)] = mesh.GetFaceDescriptor(mesh[i].GetIndex()).SurfNr(); #ifdef PARALLEL // TABLE send_surfnr(ntasks), recv_surfnr(ntasks); DynamicTable send_surfnr(ntasks), recv_surfnr(ntasks); if (ntasks > 1 && working) { for (int f = 0; f < nfaces; f++) for (int proc : partop.GetDistantFaceProcs(f)) send_surfnr.Add (proc, surfnr[f]); } if (ntasks > 1) // MyMPI_ExchangeTable (send_surfnr, recv_surfnr, NG_MPI_TAG_CURVE, comm); comm.ExchangeTable (send_surfnr, recv_surfnr, NG_MPI_TAG_CURVE); if (ntasks > 1 && working) { NgArray cnt(ntasks); cnt = 0; for (int f = 0; f < nfaces; f++) for (int proc : partop.GetDistantFaceProcs(f)) surfnr[f] = max(surfnr[f], recv_surfnr[proc][cnt[proc]++]); } #endif if (mesh.GetDimension() == 3 && working) { static Timer tcf("curve faces"); RegionTimer reg(tcf); for (int f = 0; f < nfaces; f++) { int facenr = f; if (surfnr[f] == -1) continue; auto face_type = top.GetFaceType0(facenr); bool has_inner = (face_type == TRIG && order >= 3) || (face_type == QUAD && order >= 2); if (has_inner) { auto verts = top.GetFaceVertices(facenr); int fnums[] = { 0, 1, 2, 4 }; if (face_type == TRIG) { if (verts[fnums[0]] > verts[fnums[1]]) swap (fnums[0], fnums[1]); if (verts[fnums[1]] > verts[fnums[2]]) swap (fnums[1], fnums[2]); if (verts[fnums[0]] > verts[fnums[1]]) swap (fnums[0], fnums[1]); } else { int fmin = 0; for (int j = 1; j < 4; j++) if (verts[j] < verts[fmin]) fmin = j; fnums[0] = fmin; fnums[1] = (fmin+1)%4; fnums[2] = (fmin+2)%4; fnums[3] = (fmin+3)%4; if (verts[fnums[3]] < verts[fnums[1]]) swap (fnums[1], fnums[3]); } int order1 = faceorder[facenr]; int ndof = max (0, (face_type==TRIG) ? (order1-1)*(order1-2)/2 : sqr(order1-1)); Vector shape(ndof), dmat(ndof); MatrixFixWidth<3> rhs(ndof), sol(ndof); rhs = 0.0; dmat = 0.0; int np = sqr(xi.Size()); NgArray > xia(np); NgArray > xa(np); if (face_type==TRIG) for (int jx = 0, jj = 0; jx < xi.Size(); jx++) for (int jy = 0; jy < xi.Size(); jy++, jj++) xia[jj] = Point<2> ((1-xi[jy])*xi[jx], xi[jy]); else for (int jx = 0, jj = 0; jx < xi.Size(); jx++) for (int jy = 0; jy < xi.Size(); jy++, jj++) xia[jj] = Point<2> (xi[jx], xi[jy]); // CalcMultiPointSurfaceTransformation (&xia, i, &xa, NULL); NgArray edgenrs; top.GetFaceEdges (facenr+1, edgenrs); for (int k = 0; k < edgenrs.Size(); k++) edgenrs[k]--; for (int jj = 0; jj < np; jj++) { Point<3> pp(0,0,0); double lami[4], mui[4]; if (face_type==TRIG) { lami[0] = xia[jj](0); lami[1] = xia[jj](1); lami[2] = 1-xia[jj](0)-xia[jj](1); lami[3] = 0.0; } else { lami[0] = (1-xia[jj](0))*(1-xia[jj](1)); lami[1] = ( xia[jj](0))*(1-xia[jj](1)); lami[2] = ( xia[jj](0))*( xia[jj](1)); lami[3] = (1-xia[jj](0))*( xia[jj](1)); mui[0] = (1-xia[jj](0))+(1-xia[jj](1)); mui[1] = ( xia[jj](0))+(1-xia[jj](1)); mui[2] = ( xia[jj](0))+( xia[jj](1)); mui[3] = (1-xia[jj](0))+( xia[jj](1)); } for (int k = 0; k < verts.Size(); k++) pp += lami[k] * Vec<3> (mesh.Point(verts[k])); for (int k = 0; k < edgenrs.Size(); k++) { int eorder = edgeorder[edgenrs[k]]; if (eorder < 2) continue; int first = edgecoeffsindex[edgenrs[k]]; Vector eshape(eorder-1); auto [vi1,vi2] = top.GetEdgeVertices(edgenrs[k]); if (vi1 > vi2) swap (vi1, vi2); int v1 = -1, v2 = -1; for (int j = 0; j < verts.Size(); j++) { if (verts[j] == vi1) v1 = j; if (verts[j] == vi2) v2 = j; } if (face_type==TRIG) CalcScaledEdgeShape (eorder, lami[v1]-lami[v2], lami[v1]+lami[v2], &eshape(0)); else { CalcEdgeShape (eorder, mui[v1]-mui[v2], &eshape(0)); eshape *= lami[v1]+lami[v2]; } for (int n = 0; n < eshape.Size(); n++) pp += eshape(n) * edgecoeffs[first+n]; } xa[jj] = pp; } // check JOACHIM if (face_type == TRIG) for (int jx = 0, jj = 0; jx < xi.Size(); jx++) for (int jy = 0; jy < xi.Size(); jy++, jj++) { 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<3> pp = xa[jj]; // ref -> ProjectToSurface (pp, mesh.GetFaceDescriptor(el.GetIndex()).SurfNr()); /** with MPI and an interior surface element between volume elements assigned to different procs, only one of them has the surf-el **/ SurfaceElementIndex sei = top.GetFace2SurfaceElement(f); if (sei != SurfaceElementIndex(-1)) { PointGeomInfo gi = mesh[sei].GeomInfoPi(1); // use improved initial guess gi.u = (lami[fnums[0]]*mesh[sei].GeomInfoPi(1).u+lami[fnums[1]]*mesh[sei].GeomInfoPi(2).u+lami[fnums[2]]*mesh[sei].GeomInfoPi(3).u); gi.v = (lami[fnums[0]]*mesh[sei].GeomInfoPi(1).v+lami[fnums[1]]*mesh[sei].GeomInfoPi(2).v+lami[fnums[2]]*mesh[sei].GeomInfoPi(3).v); geo.ProjectPointGI(surfnr[facenr], pp, gi); } else { geo.ProjectPoint(surfnr[facenr], pp); } Vec<3> dist = pp-xa[jj]; CalcTrigShape (order1, lami[fnums[1]]-lami[fnums[0]], 1-lami[fnums[1]]-lami[fnums[0]], &shape(0)); for (int k = 0; k < ndof; k++) dmat(k) += wi * shape(k) * shape(k); dist *= wi; for (int k = 0; k < ndof; k++) for (int l = 0; l < 3; l++) rhs(k,l) += shape(k) * dist(l); } else for (int jx = 0, jj = 0; jx < xi.Size(); jx++) for (int jy = 0; jy < xi.Size(); jy++, jj++) { double wi = weight[jx]*weight[jy]; double lami[4]; lami[0] = (1-xia[jj](0))*(1-xia[jj](1)); lami[1] = ( xia[jj](0))*(1-xia[jj](1)); lami[2] = ( xia[jj](0))*( xia[jj](1)); lami[3] = (1-xia[jj](0))*( xia[jj](1)); double mui[4]; mui[0] = (1-xia[jj](0))+(1-xia[jj](1)); mui[1] = ( xia[jj](0))+(1-xia[jj](1)); mui[2] = ( xia[jj](0))+( xia[jj](1)); mui[3] = (1-xia[jj](0))+( xia[jj](1)); Point<3> pp = xa[jj]; // ref -> ProjectToSurface (pp, mesh.GetFaceDescriptor(el.GetIndex()).SurfNr()); /** with MPI and an interior surface element between volume elements assigned to different procs, only one of them has the surf-el **/ SurfaceElementIndex sei = top.GetFace2SurfaceElement(f); if (sei != SurfaceElementIndex(-1)) { PointGeomInfo gi = mesh[sei].GeomInfoPi(1); // use improved initial guess TODO JOACHIM gi.u = 0; gi.v = 0; for (int k = 0; k < 4; k++) { gi.u += lami[k] * mesh[sei].GeomInfoPi(k+1).u; gi.v += lami[k] * mesh[sei].GeomInfoPi(k+1).v; } geo.ProjectPointGI(surfnr[facenr], pp, gi); } else geo.ProjectPoint(surfnr[facenr], pp); Vec<3> dist = pp-xa[jj]; /* CalcTrigShape (order1, lami[fnums[1]]-lami[fnums[0]], 1-lami[fnums[1]]-lami[fnums[0]], &shape(0)); */ // CalcQuadShapeLambda (order1, 2*x-1, 2*y-1, [&](int i, double val) { shape(i) = val; }); CalcQuadShapeLambda (order1, mui[fnums[1]]-mui[fnums[0]], mui[fnums[3]]-mui[fnums[0]], [&](int i, double val) { shape(i) = val; }); for (int k = 0; k < ndof; k++) dmat(k) += wi * shape(k) * shape(k); dist *= wi; for (int k = 0; k < ndof; k++) for (int l = 0; l < 3; l++) rhs(k,l) += shape(k) * dist(l); } for (int i = 0; i < ndof; i++) for (int j = 0; j < 3; j++) sol(i,j) = rhs(i,j) / dmat(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); } } } // compress edge and face tables int newbase = 0; for (int i = 0; i < edgeorder.Size(); i++) { bool curved = 0; int oldbase = edgecoeffsindex[i]; int 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]; int 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; if (working) ishighorder = (order > 1); // (*testout) << "edgecoeffs = " << endl << edgecoeffs << endl; // (*testout) << "facecoeffs = " << endl << facecoeffs << endl; #ifdef PARALLEL comm.Barrier(); #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.GetEdge (elnr); info.ndof += edgeorder[info.edgenr]-1; } return (info.ndof > info.nv); } template void CurvedElements :: CalcSegmentTransformation (const T & xi, SegmentIndex elnr, Point<3,T> * x, Vec<3,T> * dxdxi, bool * curved) { if (mesh.coarsemesh) { const HPRefElement & hpref_el = (*mesh.hpelements) [mesh[elnr].hp_elnr]; // xi umrechnen T lami[2] = { xi, 1-xi }; T dlami[2] = { 1, -1 }; T coarse_xi = 0; T 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; } // TVector shapes, dshapes; // NgArray > coefs; SegmentInfo info; info.elnr = elnr; info.order = order; info.ndof = info.nv = 2; if (order == 1) { auto & seg = mesh.LineSegment(elnr); if (seg.GetNP() == 2) { if (x) *x = Point<3,T>(xi * Vec<3>(mesh[seg.PNums()[0]]) + (1-xi) * Vec<3>(mesh[seg.PNums()[1]])); if (dxdxi) *dxdxi = Vec<3>(mesh[seg.PNums()[0]])-Vec<3>(mesh[seg.PNums()[1]]); } else { if (x) { *x = Point<3,T>(2*(xi-1)*(xi-0.5) * Vec<3>(mesh[seg.PNums()[1]]) + 4*xi*(1-xi) * Vec<3>(mesh[seg.PNums()[2]]) + 2*xi*(xi-0.5) * Vec<3>(mesh[seg.PNums()[0]])); } if (dxdxi) *dxdxi = (4*xi-1)*Vec<3>(mesh[seg.PNums()[0]]) + (4*xi-3)*Vec<3>(mesh[seg.PNums()[1]]) + (4-8*xi)*Vec<3>(mesh[seg.PNums()[2]]); } return; } if (info.order > 1) { const MeshTopology & top = mesh.GetTopology(); info.edgenr = top.GetEdge (elnr); info.ndof += edgeorder[info.edgenr]-1; } NgArrayMem,100> coefs(info.ndof); NgArrayMem shapes_mem(info.ndof); TFlatVector shapes(info.ndof, &shapes_mem[0]); NgArrayMem dshapes_mem(info.ndof); TFlatVector dshapes(info.ndof, &dshapes_mem[0]); CalcElementShapes (info, xi, shapes); GetCoefficients (info, coefs); *x = 0; for (int i = 0; i < shapes.Size(); i++) // *x += shapes(i) * coefs[i]; for (int j = 0; j < 3; j++) (*x)(j) += shapes(i) * coefs[i](j); 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; } template void CurvedElements :: CalcElementShapes (SegmentInfo & info, T xi, TFlatVector 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)); } } template void CurvedElements :: CalcElementDShapes (SegmentInfo & info, T xi, TFlatVector 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) { T 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, NgArray > & 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 (mesh[elnr].GetType() != TRIG) return true; if (!IsHighOrder()) return false; if (mesh.coarsemesh) { const HPRefElement & hpref_el = (*mesh.hpelements) [mesh[elnr].GetHpElnr()]; 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]--; */ /* auto edgs = top.GetEdges(SurfaceElementIndex(elnr)); info.edgenrs.SetSize(edgs.Size()); for (auto [i,nr] : Enumerate(edgs)) info.edgenrs[i] = nr; */ info.SetEdges (top.GetEdges(SurfaceElementIndex(elnr))); info.facenr = top.GetFace(elnr); 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].GetHpElnr()]; // 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; } 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; case QUAD8 : info.nv = 8; 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.SetEdges(top.GetEdges(SurfaceElementIndex(elnr))); info.facenr = top.GetFace(elnr); 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; } } Point<2> _xi(xi); Point<3> _x; Mat<3,2> _dxdxi; if (EvaluateMapping (info, _xi, _x, _dxdxi)) { if (x) *x = _x; if (dxdxi) *dxdxi = _dxdxi; return; } NgArrayMem,100> coefs(info.ndof); NgArrayMem shapes_mem(info.ndof); TFlatVector shapes(info.ndof, &shapes_mem[0]); NgArrayMem dshapes_mem(2*info.ndof); MatrixFixWidth<2> dshapes(info.ndof, &dshapes_mem[0]); 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); } template void CurvedElements :: CalcElementShapes (SurfaceElementInfo & info, const Point<2,T> xi, TFlatVector shapes) const { const Element2d & el = mesh[info.elnr]; // shapes.SetSize(info.ndof); if (rational && info.order >= 2) { // shapes.SetSize(6); T w(1); T 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++) { T 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::GetEdges0 (TRIG); for (int i = 0; i < 3; i++) { int eorder = edgeorder[info.edgenrs[i]]; if (eorder >= 2) { int vi1 = edges[i][0], vi2 = edges[i][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 { T x = xi(0); T y = xi(1); T 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; T 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)); T 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; } case QUAD8: { auto x = xi(0), y = xi(1); shapes(0) = (1-x)*(1-y); shapes(1) = x*(1-y); shapes(2) = x*y; shapes(3) = (1-x)*y; shapes(4) = 4*(1-x)*x*(1-y); shapes(5) = 4*(1-x)*x*y; shapes(6) = 4*(1-y)*y*(1-x); shapes(7) = 4*(1-y)*y*x; shapes(0) -= 0.5*(shapes(4)+shapes(6)); shapes(1) -= 0.5*(shapes(4)+shapes(7)); shapes(2) -= 0.5*(shapes(5)+shapes(7)); shapes(3) -= 0.5*(shapes(5)+shapes(6)); break; } default: throw NgException("CurvedElements::CalcShape 2d, element type not handled"); }; } template void CurvedElements :: CalcElementDShapes (SurfaceElementInfo & info, const Point<2,T> xi, MatrixFixWidth<2,T> & dshapes) const { const Element2d & el = mesh[info.elnr]; ELEMENT_TYPE type = el.GetType(); T lami[4]; dshapes.SetSize(info.ndof); // dshapes = 0; // *testout << "calcelementdshapes, info.ndof = " << info.ndof << endl; if (rational && info.order >= 2) { T w = 1; T dw[2] = { 0, 0 }; lami[0] = xi(0); lami[1] = xi(1); lami[2] = 1-xi(0)-xi(1); T dlami[3][2] = { { 1, 0 }, { 0, 1 }, { -1, -1 }}; T 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++) { T 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,T> 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++) { T ddx = dshapes(ii+j,0); T 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,T> 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++) { T ddx = dshapes(ii+j,0); T 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 = T(0.0); dshapes(0,0) = 1; dshapes(1,1) = 1; dshapes(2,0) = -1; dshapes(2,1) = -1; } else { AutoDiff<2,T> x(xi(0), 0); AutoDiff<2,T> y(xi(1), 1); AutoDiff<2,T> lam3 = 1-x-y; AutoDiff<2,T> 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; T shapes[4] = { (1-xi(0))*(1-xi(1)), xi(0) *(1-xi(1)), xi(0) * xi(1) , (1-xi(0))* xi(1) }; T mu[4] = { 1 - xi(0) + 1 - xi(1), xi(0) + 1 - xi(1), xi(0) + xi(1), 1 - xi(0) + xi(1), }; T dmu[4][2] = { { -1, -1 }, { 1, -1 }, { 1, 1 }, { -1, 1 } }; // double hshapes[20], hdshapes[20]; NgArrayMem 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]); T lame = shapes[vi1]+shapes[vi2]; T 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; } // TODO (if still needed???) /* int forder = faceorder[info.facenr]; if (forder >= 2) { } */ for (int i = ii; i < info.ndof; i++) for (int k = 0; k < 2; k++) dshapes(i,k) = 0; } /* *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 bool CurvedElements :: EvaluateMapping (SurfaceElementInfo & info, const Point<2,T> xi, Point & mx, Mat & jac) const { const Element2d & el = mesh[info.elnr]; if (rational && info.order >= 2) return false; // not supported AutoDiff<2,T> x(xi(0), 0); AutoDiff<2,T> y(xi(1), 1); AutoDiff<2,T> mapped_x[DIM_SPACE]; for (int i = 0; i < DIM_SPACE; i++) mapped_x[i] = AutoDiff<2,T>(0.0); switch (el.GetType()) { case TRIG6: { AutoDiff<2,T> lam3 = 1-x-y; AutoDiff<2,T> lami[6] = { x * (2*x-1), y * (2*y-1), lam3 * (2*lam3-1), 4 * y * lam3, 4 * x * lam3, 4 * x * y }; for (int j = 0; j < 6; j++) { Point<3> p = mesh[el[j]]; for (int k = 0; k < DIM_SPACE; k++) mapped_x[k] += p(k) * lami[j]; } break; } case TRIG: { // if (info.order >= 2) return false; // not yet supported AutoDiff<2,T> lami[4] = { x, y, 1-x-y }; for (int j = 0; j < 3; j++) { Point<3> p = mesh[el[j]]; for (int k = 0; k < DIM_SPACE; k++) mapped_x[k] += p(k) * lami[j]; } if (info.order == 1) break; const ELEMENT_EDGE * edges = MeshTopology::GetEdges1 (TRIG); for (int i = 0; i < 3; i++) { int eorder = edgeorder[info.edgenrs[i]]; if (eorder >= 2) { int first = edgecoeffsindex[info.edgenrs[i]]; int vi1 = edges[i][0]-1, vi2 = edges[i][1]-1; if (el[vi1] > el[vi2]) swap (vi1, vi2); CalcScaledEdgeShapeLambda (eorder, lami[vi1]-lami[vi2], lami[vi1]+lami[vi2], [&](int i, AutoDiff<2,T> shape) { for (int k = 0; k < DIM_SPACE; k++) mapped_x[k] += edgecoeffs[first+i](k) * shape; }); } } int forder = faceorder[info.facenr]; if (forder >= 3) { int first = facecoeffsindex[info.facenr]; 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]); CalcScaledTrigShapeLambda (forder, lami[fnums[1]]-lami[fnums[0]], lami[fnums[2]], AutoDiff<2,T>(1.0), [&](int i, AutoDiff<2,T> shape) { for (int k = 0; k < DIM_SPACE; k++) mapped_x[k] += facecoeffs[first+i](k) * shape; }); } break; } case QUAD: { AutoDiff<2,T> lami[4] = { (1-x)*(1-y), x*(1-y), x*y, (1-x)*y }; AutoDiff<2,T> mui[4] = { (1-x)+(1-y), x+(1-y), x+y, (1-x)+y }; for (int j = 0; j < 4; j++) { Point<3> p = mesh[el[j]]; for (int k = 0; k < DIM_SPACE; k++) mapped_x[k] += p(k) * lami[j]; } if (info.order == 1) break; const ELEMENT_EDGE * edges = MeshTopology::GetEdges1 (QUAD); for (int i = 0; i < 4; i++) { int eorder = edgeorder[info.edgenrs[i]]; if (eorder >= 2) { int first = edgecoeffsindex[info.edgenrs[i]]; int vi1 = edges[i][0]-1, vi2 = edges[i][1]-1; if (el[vi1] > el[vi2]) swap (vi1, vi2); auto lame = lami[vi1]+lami[vi2]; CalcEdgeShapeLambda(eorder, mui[vi1]-mui[vi2], [&](int i, AutoDiff<2,T> shape) { for (int k = 0; k < DIM_SPACE; k++) mapped_x[k] += edgecoeffs[first+i](k) * (lame*shape); }); } } int forder = faceorder[info.facenr]; if (forder >= 2) { int first = facecoeffsindex[info.facenr]; int fnums[4]; int fmin = 0; for (int j = 1; j < 4; j++) if (el[j] < el[fmin]) fmin = j; fnums[0] = fmin; fnums[1] = (fmin+1)%4; fnums[2] = (fmin+2)%4; fnums[3] = (fmin+3)%4; if (el[fnums[3]] < el[fnums[1]]) swap (fnums[1], fnums[3]); AutoDiff<2,T> mui[4]; mui[0] = (1-x)+(1-y); mui[1] = ( x)+(1-y); mui[2] = ( x)+( y); mui[3] = (1-x)+( y); CalcQuadShapeLambda (forder, // 1-2*x, 1-2*y, mui[fnums[1]]-mui[fnums[0]], mui[fnums[3]]-mui[fnums[0]], [&](int i, AutoDiff<2,T> shape) { for (int k = 0; k < DIM_SPACE; k++) mapped_x[k] += facecoeffs[first+i](k) * shape; }); } break; } case QUAD8: { // AutoDiff<2,T> lami[4] = { (1-x)*(1-y), x*(1-y), x*y, (1-x)*y }; AutoDiff<2,T> lami[8] = { (1-x)*(1-y), x*(1-y), x*y, (1-x)*y, 4*(1-x)*x*(1-y), 4*(1-x)*x*y, 4*(1-y)*y*(1-x), 4*(1-y)*y*x }; lami[0] -= 0.5*(lami[4]+lami[6]); lami[1] -= 0.5*(lami[4]+lami[7]); lami[2] -= 0.5*(lami[5]+lami[7]); lami[3] -= 0.5*(lami[5]+lami[6]); for (int j = 0; j < 8; j++) { Point<3> p = mesh[el[j]]; for (int k = 0; k < DIM_SPACE; k++) mapped_x[k] += p(k) * lami[j]; } break; } default: return false; } for (int i = 0; i < DIM_SPACE; i++) { mx(i) = mapped_x[i].Value(); for (int j = 0; j < 2; j++) jac(i,j) = mapped_x[i].DValue(j); } return true; } template void CurvedElements :: GetCoefficients (SurfaceElementInfo & info, NgArray > & coefs) const { const Element2d & el = mesh[info.elnr]; coefs.SetSize (info.ndof); for (int i = 0; i < info.nv; i++) { Point<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, NgArray > & coefs) const; template void CurvedElements :: GetCoefficients<3> (SurfaceElementInfo & info, NgArray > & coefs) const; // ********************** Transform volume elements ******************* bool CurvedElements :: IsElementCurved (ElementIndex elnr) const { if (mesh[elnr].GetType() != TET) return true; if (mesh.coarsemesh) { const HPRefElement & hpref_el = (*mesh.hpelements) [mesh[elnr].GetHpElnr()]; return mesh.coarsemesh->GetCurvedElements().IsElementCurved (ElementIndex(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(); for (auto e : top.GetEdges(elnr)) info.ndof += edgecoeffsindex[e+1] - edgecoeffsindex[e]; for (auto f : top.GetFaces(elnr)) info.ndof += facecoeffsindex[f+1] - facecoeffsindex[f]; } return (info.ndof > info.nv); } bool CurvedElements :: IsElementHighOrder (ElementIndex elnr) const { if (mesh.coarsemesh) { const HPRefElement & hpref_el = (*mesh.hpelements) [mesh[elnr].GetHpElnr()]; return mesh.coarsemesh->GetCurvedElements().IsElementHighOrder (ElementIndex(hpref_el.coarse_elnr)); } 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(); for (auto e : top.GetEdges(elnr)) if (edgecoeffsindex[e+1] > edgecoeffsindex[e]) return true; for (auto f : top.GetFaces(elnr)) if (facecoeffsindex[f+1] > facecoeffsindex[f]) return true; } return false; } 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].GetHpElnr()]; // 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, ElementIndex(hpref_el.coarse_elnr), x, &dxdxic /* , curved */); if (dxdxi) *dxdxi = dxdxic * trans; return; } const Element & el = mesh[elnr]; ELEMENT_TYPE type = el.GetType(); ElementInfo hinfo; ElementInfo & info = (buffer) ? *static_cast (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]--; */ info.SetEdges (top.GetEdges(elnr)); info.SetFaces (top.GetFaces(elnr)); /* 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]]; */ for (auto e : info.GetEdges()) info.ndof += edgecoeffsindex[e+1] - edgecoeffsindex[e]; for (auto f : info.GetFaces()) info.ndof += facecoeffsindex[f+1] - facecoeffsindex[f]; } } NgArrayMem mem(info.ndof); TFlatVector shapes(info.ndof, &mem[0]); NgArrayMem dshapes_mem(info.ndof*3); MatrixFixWidth<3> dshapes(info.ndof, &dshapes_mem[0]); 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; } template void CurvedElements :: CalcElementShapes (ElementInfo & info, Point<3,T> xi, TFlatVector shapes) const { const Element & el = mesh[info.elnr]; if (rational && info.order >= 2) { // shapes.SetSize(10); T w = 1; T 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: { T x = xi(0); T y = xi(1); T z = xi(2); T 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: { T lami[6] = { xi(0), xi(1), 1-xi(0)-xi(1), xi(0), xi(1), 1-xi(0)-xi(1) }; T 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)); T 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); T bubxy = lami[vi1]; /* T bubz = lamiz[vi1]*lamiz[vi2]; T polyz = lamiz[vi1] - lamiz[vi2]; for (int j = 0; j < eorder-1; j++) { shapes(ii+j) = bubxy * bubz; bubz *= polyz; } */ CalcEdgeShape (eorder, lamiz[vi1]-lamiz[vi2], &shapes(ii)); for (int j = 0; j < eorder-1; j++) shapes(ii+j) *= bubxy; 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 PRISM15: { shapes = 0.0; T x = xi(0); T y = xi(1); T z = xi(2); T lam = 1-x-y; T lamz = 1-z; shapes[0] = (2*x*x-x) * (2*lamz*lamz-lamz); shapes[1] = (2*y*y-y) * (2*lamz*lamz-lamz); shapes[2] = (2*lam*lam-lam) * (2*lamz*lamz-lamz); shapes[3] = (2*x*x-x) * (2*z*z-z); shapes[4] = (2*y*y-y) * (2*z*z-z); shapes[5] = (2*lam*lam-lam) * (2*z*z-z); shapes[6] = 4 * x * y * (2*lamz*lamz-lamz); shapes[7] = 4 * x * lam * (2*lamz*lamz-lamz); shapes[8] = 4 * y * lam * (2*lamz*lamz-lamz); shapes[9] = x * 4 * z * (1-z); shapes[10] = y * 4 * z * (1-z); shapes[11] = lam * 4 * z * (1-z); shapes[12] = 4 * x * y * (2*z*z-z); shapes[13] = 4 * x * lam * (2*z*z-z); shapes[14] = 4 * y * lam * (2*z*z-z); break; } case PYRAMID: { shapes = 0.0; T x = xi(0); T y = xi(1); T z = xi(2); // if (z == 1.) z = 1-1e-10; z *= (1-1e-12); 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; T sigma[4] = { sigma[0] = ( (1-z-x) + (1-z-y) ), sigma[1] = ( x + (1-z-y) ), sigma[2] = ( x + y ), sigma[3] = ( (1-z-x) + y ), }; 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, sigma[vi1]-sigma[vi2], 1-z, &shapes(ii)); T fac = (shapes[vi1]+shapes[vi2]) / (1-z); for (int j = 0; j < eorder-1; j++) shapes(ii+j) *= fac; ii += eorder-1; } } break; } case PYRAMID13: { shapes = 0.0; T x = xi(0); T y = xi(1); T z = xi(2); z *= 1-1e-12; shapes[0] = (-z + z*(2*x + z - 1)*(2*y + z - 1)/(-z + 1) + (-2*x - z + 2)*(-2*y - z + 2))*(-0.5*x - 0.5*y - 0.5*z + 0.25); shapes[1] = (0.5*x - 0.5*y - 0.25)*(-z - z*(2*x + z - 1)*(2*y + z - 1)/(-z + 1) + (2*x + z)*(-2*y - z + 2)); shapes[2] = (-z + z*(2*x + z - 1)*(2*y + z - 1)/(-z + 1) + (2*x + z)*(2*y + z))*(0.5*x + 0.5*y + 0.5*z - 0.75); shapes[3] = (-0.5*x + 0.5*y - 0.25)*(-z - z*(2*x + z - 1)*(2*y + z - 1)/(-z + 1) + (2*y + z)*(-2*x - z + 2)); shapes[4] = z*(2*z - 1); shapes[5] = 2*x*(-2*x - 2*z + 2)*(-2*y - 2*z + 2)/(-2*z + 2); shapes[6] = 4*x*y*(-2*x - 2*z + 2)/(-2*z + 2); shapes[7] = 2*y*(-2*x - 2*z + 2)*(-2*y - 2*z + 2)/(-2*z + 2); shapes[8] = 4*x*y*(-2*y - 2*z + 2)/(-2*z + 2); shapes[9] = z*(-2*x - 2*z + 2)*(-2*y - 2*z + 2)/(-z + 1); shapes[10] = 2*x*z*(-2*y - 2*z + 2)/(-z + 1); shapes[11] = 4*x*y*z/(-z + 1); shapes[12] = 2*y*z*(-2*x - 2*z + 2)/(-z + 1); break; } case HEX: { shapes = 0.0; T x = xi(0); T y = xi(1); T 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); if (info.order == 1) return; T mu[8] = { (1-x)+(1-y)+(1-z), x +(1-y)+(1-z), x + y +(1-z), (1-x)+ y +(1-z), (1-x)+(1-y)+(z), x +(1-y)+(z), x + y +(z), (1-x)+ y +(z), }; int ii = 8; const ELEMENT_EDGE * edges = MeshTopology::GetEdges1 (HEX); for (int i = 0; i < 12; 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)); T lame = shapes(vi1)+shapes(vi2); for (int j = 0; j < order-1; j++) shapes(ii+j) *= lame; ii += eorder-1; } } break; } case HEX20: { shapes = 0.0; T x = xi(0); T y = xi(1); T 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); T sigma[8]={(1-x)+(1-y)+(1-z),x+(1-y)+(1-z),x+y+(1-z),(1-x)+y+(1-z), (1-x)+(1-y)+z,x+(1-y)+z,x+y+z,(1-x)+y+z}; static const int e[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 }, }; for (int i = 0; i < 12; i++) { T lame = shapes[e[i][0]]+shapes[e[i][1]]; T xi = sigma[e[i][1]]-sigma[e[i][0]]; shapes[8+i] = (1-xi*xi)*lame; } for (int i = 0; i < 12; i++) { shapes[e[i][0]] -= 0.5 * shapes[8+i]; shapes[e[i][1]] -= 0.5 * shapes[8+i]; } break; } default: throw NgException("CurvedElements::CalcShape 3d, element type not handled"); }; } template void CurvedElements :: CalcElementDShapes (ElementInfo & info, const Point<3,T> xi, MatrixFixWidth<3,T> & dshapes) const { // static int timer = NgProfiler::CreateTimer ("calcelementdshapes"); const Element & el = mesh[info.elnr]; // dshapes.SetSize(info.ndof); // if ( (long int)(&dshapes(0,0)) % alignof(T) != 0) // throw NgException ("alignment problem"); if (dshapes.Height() != info.ndof) throw NgException ("wrong height"); if (rational && info.order >= 2) { T w = 1; T dw[3] = { 0, 0, 0 }; T lami[4] = { xi(0), xi(1), xi(2), 1-xi(0)-xi(1)-xi(2) }; T dlami[4][3] = { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 }, { -1, -1, -1 }}; T 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++) { T 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; } /* if (typeid(T) == typeid(SIMD)) { if (el.GetType() == HEX) dshapes = T(0.0); return; } */ switch (el.GetType()) { case TET: { // if (typeid(T) == typeid(SIMD)) return; dshapes = T(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; if (info.order == 1) return; T 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,T> 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++) { T ddx = dshapes(ii+j,0); T 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,T> 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++) { T ddx = dshapes(ii+j,0); T ddy = dshapes(ii+j,1); T 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 (typeid(T) == typeid(SIMD)) return; if (dshapes.Height() == 4) { dshapes = T(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,T> x(xi(0), 0); AutoDiff<3,T> y(xi(1), 1); AutoDiff<3,T> z(xi(2), 2); AutoDiff<3,T> lam4 = 1-x-y-z; AutoDiff<3,T> 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: { T lami[6] = { xi(0), xi(1), 1-xi(0)-xi(1), xi(0), xi(1), 1-xi(0)-xi(1) }; T lamiz[6] = { 1-xi(2), 1-xi(2), 1-xi(2), xi(2), xi(2), xi(2) }; T dlamiz[6] = { -1, -1, -1, 1, 1, 1 }; T 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; NgArrayMem hshapes(order+1), hdshapes(order+1); 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; NgArrayMem shapei_mem(order+1); TFlatVector shapei(order+1, &shapei_mem[0]); 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,T> 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++) { T ddx = dshapes(ii+j,0); T 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); } T facz = (i < 3) ? (1-xi(2)) : xi(2); T 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; } } // if (typeid(T) == typeid(SIMD)) return; 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); // T bubz = lamiz[vi1] * lamiz[vi2]; // T dbubz = dlamiz[vi1]*lamiz[vi2] + lamiz[vi1]*dlamiz[vi2]; // T polyz = lamiz[vi1] - lamiz[vi2]; // T dpolyz = dlamiz[vi1] - dlamiz[vi2]; T bubxy = lami[(vi1)%3]; T dbubxydx = dlami[(vi1)%3][0]; T 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; } */ CalcEdgeShapeDx (eorder, lamiz[vi1]-lamiz[vi2], &hshapes[0], &hdshapes[0]); for (int j = 0; j < eorder-1; j++) { dshapes(ii+j,0) = dbubxydx * hshapes[j]; dshapes(ii+j,1) = dbubxydy * hshapes[j]; dshapes(ii+j,2) = bubxy * hdshapes[j]; } 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]); NgArrayMem dshapei_mem(ndf); NgArrayMem shapei_mem(ndf); MatrixFixWidth<2,T> dshapei(ndf, &dshapei_mem[0]); TFlatVector shapei(ndf, &shapei_mem[0]); 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,T> 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); T ddx = dshapei(j,0); T 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 PRISM15: { AutoDiff<3,T> x(xi(0), 0); AutoDiff<3,T> y(xi(1), 1); AutoDiff<3,T> z(xi(2), 2); AutoDiff<3,T> ad[15]; AutoDiff<3,T> lam = 1-x-y; AutoDiff<3,T> lamz = 1-z; ad[0] = (2*x*x-x) * (2*lamz*lamz-lamz); ad[1] = (2*y*y-y) * (2*lamz*lamz-lamz); ad[2] = (2*lam*lam-lam) * (2*lamz*lamz-lamz); ad[3] = (2*x*x-x) * (2*z*z-z); ad[4] = (2*y*y-y) * (2*z*z-z); ad[5] = (2*lam*lam-lam) * (2*z*z-z); ad[6] = 4 * x * y * (2*lamz*lamz-lamz); ad[7] = 4 * x * lam * (2*lamz*lamz-lamz); ad[8] = 4 * y * lam * (2*lamz*lamz-lamz); ad[9] = x * 4 * z * (1-z); ad[10] = y * 4 * z * (1-z); ad[11] = lam * 4 * z * (1-z); ad[12] = 4 * x * y * (2*z*z-z); ad[13] = 4 * x * lam * (2*z*z-z); ad[14] = 4 * y * lam * (2*z*z-z); for(int i=0; i<15; i++) for(int j=0; j<3; j++) dshapes(i,j) = ad[i].DValue(j); break; } case PYRAMID: { // if (typeid(T) == typeid(SIMD)) return; dshapes = T(0.0); T x = xi(0); T y = xi(1); T z = xi(2); // if (z == 1.) z = 1-1e-10; z *= 1-1e-12; T z1 = 1-z; T 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; if (info.order == 1) return; int ii = 5; const ELEMENT_EDGE * edges = MeshTopology::GetEdges1 (PYRAMID); // if (z == 1.) z = 1-1e-10; z *= 1-1e-12; T shapes[5]; 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; T sigma[4] = { ( (1-z-x) + (1-z-y) ), ( x + (1-z-y) ), ( x + y ), ( (1-z-x) + y ), }; T dsigma[4][3] = { { -1, -1, -2 }, { 1, -1, -1 }, { 1, 1, 0 }, { -1, 1, -1 } }; T dz[3] = { 0, 0, 1 }; 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); NgArrayMem shapei_mem(eorder+1); TFlatVector shapei(eorder+1,&shapei_mem[0]); CalcScaledEdgeShapeDxDt<3> (eorder, sigma[vi1]-sigma[vi2], 1-z, &dshapes(ii,0) ); CalcScaledEdgeShape(eorder, sigma[vi1]-sigma[vi2], 1-z, &shapei(0) ); T fac = (shapes[vi1]+shapes[vi2]) / (1-z); T dfac[3]; for (int k = 0; k < 3; k++) dfac[k] = ( (dshapes(vi1,k)+dshapes(vi2,k)) * (1-z) - (shapes[vi1]+shapes[vi2]) *(-dshapes(4,k)) ) / sqr(1-z); for (int j = 0; j < eorder-1; j++) { T ddx = dshapes(ii+j,0); T ddt = dshapes(ii+j,1); for (int k = 0; k < 3; k++) dshapes(ii+j,k) = fac * (ddx * (dsigma[vi1][k]-dsigma[vi2][k]) - ddt*dz[k]) + dfac[k] * shapei(j); } ii += eorder-1; } } break; } case PYRAMID13: { T x = xi(0); T y = xi(1); T z = xi(2); z *= 1-1e-12; dshapes(0,0) = 0.5*z - 0.5*z*(2*x + z - 1)*(2*y + z - 1)/(-z + 1) - 0.5*(-2*x - z + 2)*(-2*y - z + 2) + (-0.5*x - 0.5*y - 0.5*z + 0.25)*(4*y + 2*z + 2*z*(2*y + z - 1)/(-z + 1) - 4); dshapes(0,1) = 0.5*z - 0.5*z*(2*x + z - 1)*(2*y + z - 1)/(-z + 1) - 0.5*(-2*x - z + 2)*(-2*y - z + 2) + (-0.5*x - 0.5*y - 0.5*z + 0.25)*(4*x + 2*z + 2*z*(2*x + z - 1)/(-z + 1) - 4); dshapes(0,2) = 0.5*z - 0.5*z*(2*x + z - 1)*(2*y + z - 1)/(-z + 1) - 0.5*(-2*x - z + 2)*(-2*y - z + 2) + (-0.5*x - 0.5*y - 0.5*z + 0.25)*(2*x + 2*y + 2*z + z*(2*x + z - 1)/(-z + 1) + z*(2*y + z - 1)/(-z + 1) + z*(2*x + z - 1)*(2*y + z - 1)/((-z + 1)*(-z + 1)) - 5 + (2*x + z - 1)*(2*y + z - 1)/(-z + 1)); dshapes(1,0) = -0.5*z - 0.5*z*(2*x + z - 1)*(2*y + z - 1)/(-z + 1) + 0.5*(2*x + z)*(-2*y - z + 2) + (0.5*x - 0.5*y - 0.25)*(-4*y - 2*z - 2*z*(2*y + z - 1)/(-z + 1) + 4); dshapes(1,1) = 0.5*z + 0.5*z*(2*x + z - 1)*(2*y + z - 1)/(-z + 1) - 0.5*(2*x + z)*(-2*y - z + 2) + (-4*x - 2*z - 2*z*(2*x + z - 1)/(-z + 1))*(0.5*x - 0.5*y - 0.25); dshapes(1,2) = (0.5*x - 0.5*y - 0.25)*(-2*x - 2*y - 2*z - z*(2*x + z - 1)/(-z + 1) - z*(2*y + z - 1)/(-z + 1) - z*(2*x + z - 1)*(2*y + z - 1)/((-z + 1)*(-z + 1)) + 1 - (2*x + z - 1)*(2*y + z - 1)/(-z + 1)); dshapes(2,0) = -0.5*z + 0.5*z*(2*x + z - 1)*(2*y + z - 1)/(-z + 1) + 0.5*(2*x + z)*(2*y + z) + (4*y + 2*z + 2*z*(2*y + z - 1)/(-z + 1))*(0.5*x + 0.5*y + 0.5*z - 0.75); dshapes(2,1) = -0.5*z + 0.5*z*(2*x + z - 1)*(2*y + z - 1)/(-z + 1) + 0.5*(2*x + z)*(2*y + z) + (4*x + 2*z + 2*z*(2*x + z - 1)/(-z + 1))*(0.5*x + 0.5*y + 0.5*z - 0.75); dshapes(2,2) = -0.5*z + 0.5*z*(2*x + z - 1)*(2*y + z - 1)/(-z + 1) + 0.5*(2*x + z)*(2*y + z) + (0.5*x + 0.5*y + 0.5*z - 0.75)*(2*x + 2*y + 2*z + z*(2*x + z - 1)/(-z + 1) + z*(2*y + z - 1)/(-z + 1) + z*(2*x + z - 1)*(2*y + z - 1)/((-z + 1)*(-z + 1)) - 1 + (2*x + z - 1)*(2*y + z - 1)/(-z + 1)); dshapes(3,0) = 0.5*z + 0.5*z*(2*x + z - 1)*(2*y + z - 1)/(-z + 1) - 0.5*(2*y + z)*(-2*x - z + 2) + (-0.5*x + 0.5*y - 0.25)*(-4*y - 2*z - 2*z*(2*y + z - 1)/(-z + 1)); dshapes(3,1) = -0.5*z - 0.5*z*(2*x + z - 1)*(2*y + z - 1)/(-z + 1) + 0.5*(2*y + z)*(-2*x - z + 2) + (-0.5*x + 0.5*y - 0.25)*(-4*x - 2*z - 2*z*(2*x + z - 1)/(-z + 1) + 4); dshapes(3,2) = (-0.5*x + 0.5*y - 0.25)*(-2*x - 2*y - 2*z - z*(2*x + z - 1)/(-z + 1) - z*(2*y + z - 1)/(-z + 1) - z*(2*x + z - 1)*(2*y + z - 1)/((-z + 1)*(-z + 1)) + 1 - (2*x + z - 1)*(2*y + z - 1)/(-z + 1)); dshapes(4,0) = 0; dshapes(4,1) = 0; dshapes(4,2) = 4*z - 1; dshapes(5,0) = -4*x*(-2*y - 2*z + 2)/(-2*z + 2) + 2*(-2*x - 2*z + 2)*(-2*y - 2*z + 2)/(-2*z + 2); dshapes(5,1) = -4*x*(-2*x - 2*z + 2)/(-2*z + 2); dshapes(5,2) = -4*x*(-2*x - 2*z + 2)/(-2*z + 2) - 4*x*(-2*y - 2*z + 2)/(-2*z + 2) + 4*x*(-2*x - 2*z + 2)*(-2*y - 2*z + 2)/((-2*z + 2)*(-2*z + 2)); dshapes(6,0) = -8*x*y/(-2*z + 2) + 4*y*(-2*x - 2*z + 2)/(-2*z + 2); dshapes(6,1) = 4*x*(-2*x - 2*z + 2)/(-2*z + 2); dshapes(6,2) = -8*x*y/(-2*z + 2) + 8*x*y*(-2*x - 2*z + 2)/((-2*z + 2)*(-2*z + 2)); dshapes(7,0) = -4*y*(-2*y - 2*z + 2)/(-2*z + 2); dshapes(7,1) = -4*y*(-2*x - 2*z + 2)/(-2*z + 2) + 2*(-2*x - 2*z + 2)*(-2*y - 2*z + 2)/(-2*z + 2); dshapes(7,2) = -4*y*(-2*x - 2*z + 2)/(-2*z + 2) - 4*y*(-2*y - 2*z + 2)/(-2*z + 2) + 4*y*(-2*x - 2*z + 2)*(-2*y - 2*z + 2)/((-2*z + 2)*(-2*z + 2)); dshapes(8,0) = 4*y*(-2*y - 2*z + 2)/(-2*z + 2); dshapes(8,1) = -8*x*y/(-2*z + 2) + 4*x*(-2*y - 2*z + 2)/(-2*z + 2); dshapes(8,2) = -8*x*y/(-2*z + 2) + 8*x*y*(-2*y - 2*z + 2)/((-2*z + 2)*(-2*z + 2)); dshapes(9,0) = -2*z*(-2*y - 2*z + 2)/(-z + 1); dshapes(9,1) = -2*z*(-2*x - 2*z + 2)/(-z + 1); dshapes(9,2) = -2*z*(-2*x - 2*z + 2)/(-z + 1) - 2*z*(-2*y - 2*z + 2)/(-z + 1) + z*(-2*x - 2*z + 2)*(-2*y - 2*z + 2)/((-z + 1)*(-z + 1)) + (-2*x - 2*z + 2)*(-2*y - 2*z + 2)/(-z + 1); dshapes(10,0) = 2*z*(-2*y - 2*z + 2)/(-z + 1); dshapes(10,1) = -4*x*z/(-z + 1); dshapes(10,2) = -4*x*z/(-z + 1) + 2*x*z*(-2*y - 2*z + 2)/((-z + 1)*(-z + 1)) + 2*x*(-2*y - 2*z + 2)/(-z + 1); dshapes(11,0) = 4*y*z/(-z + 1); dshapes(11,1) = 4*x*z/(-z + 1); dshapes(11,2) = 4*x*y*z/((-z + 1)*(-z + 1)) + 4*x*y/(-z + 1); dshapes(12,0) = -4*y*z/(-z + 1); dshapes(12,1) = 2*z*(-2*x - 2*z + 2)/(-z + 1); dshapes(12,2) = -4*y*z/(-z + 1) + 2*y*z*(-2*x - 2*z + 2)/((-z + 1)*(-z + 1)) + 2*y*(-2*x - 2*z + 2)/(-z + 1); break; } case HEX: { // if (typeid(T) == typeid(SIMD)) return; // NgProfiler::StartTimer(timer); T x = xi(0); T y = xi(1); T 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; // NgProfiler::StopTimer(timer); if (info.order == 1) return; T shapes[8] = { (1-x)*(1-y)*(1-z), x *(1-y)*(1-z), x * y *(1-z), (1-x)* y *(1-z), (1-x)*(1-y)*(z), x *(1-y)*(z), x * y *(z), (1-x)* y *(z), }; T mu[8] = { (1-x)+(1-y)+(1-z), x +(1-y)+(1-z), x + y +(1-z), (1-x)+ y +(1-z), (1-x)+(1-y)+(z), x +(1-y)+(z), x + y +(z), (1-x)+ y +(z) }; T dmu[8][3] = { { -1, -1, -1 }, { 1, -1, -1 }, { 1, 1, -1 }, { -1, 1, -1 }, { -1, -1, 1 }, { 1, -1, 1 }, { 1, 1, 1 }, { -1, 1, 1 } }; NgArrayMem hshapes(order+1), hdshapes(order+1); int ii = 8; const ELEMENT_EDGE * edges = MeshTopology::GetEdges1 (HEX); for (int i = 0; i < 12; 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]); T lame = shapes[vi1]+shapes[vi2]; T dlame[3] = { dshapes(vi1, 0) + dshapes(vi2, 0), dshapes(vi1, 1) + dshapes(vi2, 1), dshapes(vi1, 2) + dshapes(vi2, 2) }; for (int j = 0; j < eorder-1; j++) for (int k = 0; k < 3; 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; } case HEX20: { AutoDiff<3,T> x(xi(0), 0); AutoDiff<3,T> y(xi(1), 1); AutoDiff<3,T> z(xi(2), 2); AutoDiff<3,T> ad[20]; ad[0] = (1-x)*(1-y)*(1-z); ad[1] = x *(1-y)*(1-z); ad[2] = x * y *(1-z); ad[3] = (1-x)* y *(1-z); ad[4] = (1-x)*(1-y)*(z); ad[5] = x *(1-y)*(z); ad[6] = x * y *(z); ad[7] = (1-x)* y *(z); AutoDiff<3,T> sigma[8]={(1-x)+(1-y)+(1-z),x+(1-y)+(1-z),x+y+(1-z),(1-x)+y+(1-z), (1-x)+(1-y)+z,x+(1-y)+z,x+y+z,(1-x)+y+z}; static const int e[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 }, }; for (int i = 0; i < 12; i++) { auto lame = ad[e[i][0]]+ad[e[i][1]]; auto xi = sigma[e[i][1]]-sigma[e[i][0]]; ad[8+i] = (1-xi*xi)*lame; } for (int i = 0; i < 12; i++) { ad[e[i][0]] -= 0.5 * ad[8+i]; ad[e[i][1]] -= 0.5 * ad[8+i]; } for (int i = 0; i < 20; i++) for (int j = 0; j < 3; j++) dshapes(i,j) = ad[i].DValue(j); 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; */ } // extern int mappingvar; template bool CurvedElements :: EvaluateMapping (ElementInfo & info, Point<3,T> xi, Point<3,T> & mx, Mat<3,3,T> & jac) const { const Element & el = mesh[info.elnr]; if (rational && info.order >= 2) return false; // not supported AutoDiff<3,T> x(xi(0), 0); AutoDiff<3,T> y(xi(1), 1); AutoDiff<3,T> z(xi(2), 2); AutoDiff<3,T> mapped_x[3] = { T(0.0), T(0.0), T(0.0) } ; switch (el.GetType()) { case TET: { // if (info.order >= 2) return false; // not yet supported AutoDiff<3,T> lami[4] = { x, y, z, 1-x-y-z }; for (int j = 0; j < 4; j++) { Point<3> p = mesh[el[j]]; for (int k = 0; k < 3; k++) mapped_x[k] += p(k) * lami[j]; } if (info.order == 1) break; const ELEMENT_EDGE * edges = MeshTopology::GetEdges1 (TET); for (int i = 0; i < 6; i++) { int eorder = edgeorder[info.edgenrs[i]]; if (eorder >= 2) { int first = edgecoeffsindex[info.edgenrs[i]]; int vi1 = edges[i][0]-1, vi2 = edges[i][1]-1; if (el[vi1] > el[vi2]) swap (vi1, vi2); CalcScaledEdgeShapeLambda (eorder, lami[vi1]-lami[vi2], lami[vi1]+lami[vi2], [&](int i, AutoDiff<3,T> shape) { Vec<3> coef = edgecoeffs[first+i]; for (int k = 0; k < 3; k++) mapped_x[k] += coef(k) * shape; }); } } const ELEMENT_FACE * faces = MeshTopology::GetFaces1 (TET); for (int i = 0; i < 4; i++) { int forder = faceorder[info.facenrs[i]]; if (forder >= 3) { int first = facecoeffsindex[info.facenrs[i]]; 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]); CalcScaledTrigShapeLambda (forder, lami[fnums[1]]-lami[fnums[0]], lami[fnums[2]], lami[fnums[0]]+lami[fnums[1]]+lami[fnums[2]], [&](int i, AutoDiff<3,T> shape) { Vec<3> coef = facecoeffs[first+i]; for (int k = 0; k < 3; k++) mapped_x[k] += coef(k) * shape; }); } } break; } case HEX: { // if (info.order >= 2) return false; // not yet supported AutoDiff<3,T> lami[8] = { (1-x)*(1-y)*(1-z), ( x)*(1-y)*(1-z), ( x)* y *(1-z), (1-x)* y *(1-z), (1-x)*(1-y)*(z), ( x)*(1-y)*(z), ( x)* y *(z), (1-x)* y *(z) }; for (int j = 0; j < 8; j++) { Point<3> p = mesh[el[j]]; for (int k = 0; k < 3; k++) mapped_x[k] += p(k) * lami[j]; } if (info.order == 1) break; AutoDiff<3,T> mu[8] = { (1-x)+(1-y)+(1-z), x +(1-y)+(1-z), x + y +(1-z), (1-x)+ y +(1-z), (1-x)+(1-y)+(z), x +(1-y)+(z), x + y +(z), (1-x)+ y +(z), }; // int ii = 8; const ELEMENT_EDGE * edges = MeshTopology::GetEdges1 (HEX); const ELEMENT_FACE * faces = MeshTopology::GetFaces0 (HEX); for (int i = 0; i < 12; i++) { int eorder = edgeorder[info.edgenrs[i]]; if (eorder >= 2) { int first = edgecoeffsindex[info.edgenrs[i]]; int vi1 = edges[i][0]-1, vi2 = edges[i][1]-1; if (el[vi1] > el[vi2]) swap (vi1, vi2); AutoDiff<3,T> lame = lami[vi1]+lami[vi2]; CalcEdgeShapeLambda (eorder, mu[vi1]-mu[vi2], [&](int i, AutoDiff<3,T> shape) { Vec<3> coef = edgecoeffs[first+i]; for (int k = 0; k < 3; k++) mapped_x[k] += coef(k) * (lame*shape); }); } } for (int i = 0; i < 6; i++) { int forder = faceorder[info.facenrs[i]]; if (forder >= 2) { int first = facecoeffsindex[info.facenrs[i]]; int fmin = 0; for (int j = 1; j < 4; j++) if (el[faces[i][j]] < el[faces[i][fmin]]) fmin = j; int fx = (fmin+1)%4; int fy = (fmin+3)%4; if (el[faces[i][fy]] < el[faces[i][fx]]) swap(fx,fy); auto lamf = lami[faces[i][0]] + lami[faces[i][1]] + lami[faces[i][2]] + lami[faces[i][3]]; CalcQuadShapeLambda (forder, mu[faces[i][fx]]-mu[faces[i][fmin]], mu[faces[i][fy]]-mu[faces[i][fmin]], [&](int i, AutoDiff<3,T> shape) { for (int k = 0; k < 3; k++) mapped_x[k] += facecoeffs[first+i](k) * lamf * shape; }); } } break; } case PRISM: { AutoDiff<3,T> lami[6] = { x, y,1-x-y, x, y, 1-x-y }; AutoDiff<3,T> lamiz[6] = { 1-z, 1-z, 1-z, z, z, z }; AutoDiff<3,T> sigma[6]; for (int i = 0; i < 6; i++) sigma[i] = lami[i] + lamiz[i]; for (int j = 0; j < 6; j++) { Point<3> p = mesh[el[j]]; for (int k = 0; k < 3; k++) mapped_x[k] += p(k) * (lami[j]*lamiz[j]); } if (info.order == 1) break; auto edges = MeshTopology::GetEdges (PRISM); for (int i = 0; i < 6; i++) // horizontal edges { int eorder = edgeorder[info.edgenrs[i]]; if (eorder >= 2) { int first = edgecoeffsindex[info.edgenrs[i]]; int vi1 = edges[i][0], vi2 = edges[i][1]; if (el[vi1] > el[vi2]) swap (vi1, vi2); CalcScaledEdgeShapeLambda (eorder, lami[vi1]-lami[vi2], lami[vi1]+lami[vi2], [&](int j, AutoDiff<3,T> shape) { Vec<3> coef = edgecoeffs[first+j]; for (int k = 0; k < 3; k++) mapped_x[k] += coef(k) * (lamiz[vi1]*shape); }); } } for (int i = 6; i < 9; i++) // vertical edges { int eorder = edgeorder[info.edgenrs[i]]; if (eorder >= 2) { int first = edgecoeffsindex[info.edgenrs[i]]; int vi1 = edges[i][0], vi2 = edges[i][1]; if (el[vi1] > el[vi2]) swap (vi1, vi2); auto bubxy = lami[vi1]; CalcEdgeShapeLambda (eorder, lamiz[vi1]-lamiz[vi2], [&](int j, AutoDiff<3,T> shape) { Vec<3> coef = edgecoeffs[first+j]; for (int k = 0; k < 3; k++) mapped_x[k] += coef(k) * (bubxy*shape); }); } } // FACE SHAPES auto faces = MeshTopology::GetFaces0 (PRISM); for (int i = 0; i < 2; i++) // triangular faces { int forder = faceorder[info.facenrs[i]]; if ( forder < 3 ) continue; int first = facecoeffsindex[info.facenrs[i]]; int fav[3] = { faces[i][0], faces[i][1], faces[i][2] }; 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]); auto lamf = lamiz[fav[0]]; CalcScaledTrigShapeLambda (forder, lami[fav[2]]-lami[fav[1]], lami[fav[0]], AutoDiff<3,T>(1.0), [&](int j, AutoDiff<3,T> shape) { Vec<3> coef = facecoeffs[first+j]; for (int k = 0; k < 3; k++) mapped_x[k] += coef(k) * lamf * shape; }); } for (int i = 2; i < 5; i++) // quad faces { int forder = faceorder[info.facenrs[i]]; if (forder >= 2) { int first = facecoeffsindex[info.facenrs[i]]; int fmin = 0; for (int j = 1; j < 4; j++) if (el[faces[i][j]] < el[faces[i][fmin]]) fmin = j; int fx = (fmin+1)%4; int fy = (fmin+3)%4; if (el[faces[i][fy]] < el[faces[i][fx]]) swap(fx,fy); auto xi = sigma[faces[i][fx]]-sigma[faces[i][fmin]]; auto eta = sigma[faces[i][fy]]-sigma[faces[i][fmin]]; AutoDiff<3,T> scalexi(1.0), scaleeta(1.0); if (faces[i][fmin] / 3 == faces[i][fx] / 3) scalexi = lami[faces[i][fmin]]+lami[faces[i][fx]]; // xi is horizontal else scaleeta = lami[faces[i][fmin]]+lami[faces[i][fy]]; CalcScaledQuadShapeLambda (forder, xi, eta, scalexi, scaleeta, [&](int j, AutoDiff<3,T> shape) { Vec<3> coef = facecoeffs[first+j]; for (int k = 0; k < 3; k++) mapped_x[k] += coef(k) * shape; }); } } break; } case PYRAMID: { z *= (1-1e-10); auto xt = x / (1-z); auto yt = y / (1-z); AutoDiff<3,T> sigma[4] = { (1-xt)+(1-yt), xt+(1-yt), xt+yt, (1-xt)+yt }; AutoDiff<3,T> lambda[4] = { (1-xt)*(1-yt), xt*(1-yt), xt*yt, (1-xt)*yt }; AutoDiff<3,T> lambda3d[5]; for (int i = 0; i < 4; i++) lambda3d[i] = lambda[i] * (1-z); lambda3d[4] = z; for (int j = 0; j < 5; j++) { Point<3> p = mesh[el[j]]; for (int k = 0; k < 3; k++) mapped_x[k] += p(k) * lambda3d[j]; } if (info.order == 1) break; auto edges = MeshTopology::GetEdges (PYRAMID); for (int i = 0; i < 4; i++) // horizontal edges { int eorder = edgeorder[info.edgenrs[i]]; if (eorder >= 2) { int first = edgecoeffsindex[info.edgenrs[i]]; int vi1 = edges[i][0], vi2 = edges[i][1]; if (el[vi1] > el[vi2]) swap (vi1, vi2); CalcScaledEdgeShapeLambda (eorder, (sigma[vi1]-sigma[vi2])*(1-z), 1-z, [&](int j, AutoDiff<3,T> shape) { Vec<3> coef = edgecoeffs[first+j]; for (int k = 0; k < 3; k++) mapped_x[k] += coef(k) * shape; }); } } for (int i = 4; i < 8; i++) // vertical edges { int eorder = edgeorder[info.edgenrs[i]]; if (eorder >= 2) { int first = edgecoeffsindex[info.edgenrs[i]]; int vi1 = edges[i][0], vi2 = edges[i][1]; if (el[vi1] > el[vi2]) swap (vi1, vi2); CalcScaledEdgeShapeLambda (eorder, lambda3d[vi1]-lambda3d[vi2], lambda3d[vi1]+lambda3d[vi2], [&](int j, AutoDiff<3,T> shape) { Vec<3> coef = edgecoeffs[first+j]; for (int k = 0; k < 3; k++) mapped_x[k] += coef(k) * shape; }); } } // TODO: face dofs break; } default: return false; } for (int i = 0; i < 3; i++) { mx(i) = mapped_x[i].Value(); for (int j = 0; j < 3; j++) jac(i,j) = mapped_x[i].DValue(j); } return true; } 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 (NgArray * xi, SegmentIndex segnr, NgArray > * x, NgArray > * dxdxi) { ; } */ template void CurvedElements :: CalcMultiPointSegmentTransformation (SegmentIndex elnr, int n, const T * xi, size_t sxi, T * x, size_t sx, T * dxdxi, size_t sdxdxi) { for (int ip = 0; ip < n; ip++) { Point<3,T> xg; Vec<3,T> 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 (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); template void CurvedElements :: CalcMultiPointSegmentTransformation<2> (SegmentIndex elnr, int npts, const SIMD * xi, size_t sxi, SIMD * x, size_t sx, SIMD * dxdxi, size_t sdxdxi); template void CurvedElements :: CalcMultiPointSegmentTransformation<3> (SegmentIndex elnr, int npts, const SIMD * xi, size_t sxi, SIMD * x, size_t sx, SIMD * dxdxi, size_t sdxdxi); template void CurvedElements :: CalcSegmentTransformation (const double & xi, SegmentIndex elnr, Point<3,double> * x, Vec<3,double> * dxdxi, bool * curved); void CurvedElements :: CalcMultiPointSurfaceTransformation (NgArray< Point<2> > * xi, SurfaceElementIndex elnr, NgArray< Point<3> > * x, NgArray< 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); } template void CurvedElements :: CalcMultiPointSurfaceTransformation (SurfaceElementIndex elnr, int npts, const T * xi, size_t sxi, T * x, size_t sx, T * dxdxi, size_t sdxdxi) { if (mesh.coarsemesh) { const HPRefElement & hpref_el = (*mesh.hpelements) [mesh[elnr].GetHpElnr()]; // xi umrechnen T lami[4]; TFlatVector vlami(4, lami); ArrayMem, 50> coarse_xi (npts); for (int pi = 0; pi < npts; pi++) { vlami = 0; Point<2,T> hxi(xi[pi*sxi], xi[pi*sxi+1]); mesh[elnr].GetShapeNew ( hxi, vlami); Point<2,T> 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 (hpref_el.coarse_elnr, npts, &coarse_xi[0](0), sizeof(Point<2,T>)/sizeof(T), x, sx, dxdxi, sdxdxi); // Mat<3,2> dxdxic; if (dxdxi) { T mem_dlami[8]; // avoid alignment problems if T is SIMD MatrixFixWidth<2,T> dlami(4, mem_dlami); dlami = T(0.0); for (int pi = 0; pi < npts; pi++) { Point<2,T> hxi(xi[pi*sxi], xi[pi*sxi+1]); mesh[elnr].GetDShapeNew ( hxi, dlami); Mat<2,2,T> 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 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; } 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; case QUAD8 : info.nv = 8; break; default: cerr << "undef element in CalcMultPointSurfaceTrafo" << 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]; // } // Michael Woopen: THESE FOLLOWING LINES ARE COPIED FROM CurvedElements::CalcSurfaceTransformation 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.SetEdges(top.GetEdges(elnr)); info.facenr = top.GetFace (elnr); 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; } } bool ok = true; for (int i = 0; i < npts; i++) { Point<2,T> _xi(xi[i*sxi], xi[i*sxi+1]); Point _x; Mat _dxdxi; if (!EvaluateMapping (info, _xi, _x, _dxdxi)) { ok = false; break; } // *testout << "x = " << _x << ", dxdxi = " << _dxdxi << endl; if (x) for (int j = 0; j < DIM_SPACE; j++) x[i*sx+j] = _x[j]; if (dxdxi) for (int j = 0; j < DIM_SPACE; j++) for (int k = 0; k < 2; k++) dxdxi[i*sdxdxi+2*j+k] = _dxdxi(j,k); } if (ok) return; // THESE LAST LINES ARE COPIED FROM CurvedElements::CalcSurfaceTransformation NgArrayMem,100> coefs(info.ndof); GetCoefficients (info, coefs); NgArrayMem shapes_mem(info.ndof); TFlatVector shapes(info.ndof, &shapes_mem[0]); NgArrayMem dshapes_mem(info.ndof*2); MatrixFixWidth<2,T> dshapes(info.ndof,&shapes_mem[0]); if (x) { if (info.order == 1 && type == TRIG) { for (int j = 0; j < npts; j++) { Point<2,T> vxi(xi[j*sxi], xi[j*sxi+1]); Point val; for (int k = 0; k < DIM_SPACE; k++) val(k) = coefs[2](k) + (coefs[0](k)-coefs[2](k)) * vxi(0) + (coefs[1](k)-coefs[2](k)) * vxi(1); /* (coefs[2]); val += (coefs[0]-coefs[2]) * vxi(0); val += (coefs[1]-coefs[2]) * vxi(1); */ for (int k = 0; k < DIM_SPACE; k++) x[j*sx+k] = val(k); } } else for (int j = 0; j < npts; j++) { Point<2,T> vxi(xi[j*sxi], xi[j*sxi+1]); CalcElementShapes (info, vxi, shapes); Point val = T(0.0); for (int i = 0; i < coefs.Size(); i++) for (int k = 0; k < DIM_SPACE; k++) val(k) += shapes(i) * coefs[i](k); for (int k = 0; k < DIM_SPACE; k++) x[j*sx+k] = val(k); } } if (dxdxi) { if (info.order == 1 && type == TRIG) { Point<2,T> xij(xi[0], xi[1]); CalcElementDShapes (info, xij, dshapes); Mat<3,2,T> dxdxij; dxdxij = 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++) dxdxij(j,k) += dshapes(i,k) * coefs[i](j); for (int ip = 0; ip < npts; ip++) for (int j = 0; j < DIM_SPACE; j++) for (int k = 0; k < 2; k++) dxdxi[ip*sdxdxi+2*j+k] = dxdxij(j,k); } else { for (int j = 0; j < npts; j++) { Point<2,T> vxi(xi[j*sxi], xi[j*sxi+1]); CalcElementDShapes (info, vxi, dshapes); Mat 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); template void CurvedElements :: CalcMultiPointSurfaceTransformation<2> (SurfaceElementIndex elnr, int npts, const SIMD * xi, size_t sxi, SIMD * x, size_t sx, SIMD * dxdxi, size_t sdxdxi); template void CurvedElements :: CalcMultiPointSurfaceTransformation<3> (SurfaceElementIndex elnr, int npts, const SIMD * xi, size_t sxi, SIMD * x, size_t sx, SIMD * dxdxi, size_t sdxdxi); void CurvedElements :: CalcMultiPointElementTransformation (NgArray< Point<3> > * xi, ElementIndex elnr, NgArray< Point<3> > * x, NgArray< 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); NgArrayMem, 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]; } NgArray > 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 } // extern int multipointtrafovar; template void CurvedElements :: CalcMultiPointElementTransformation (ElementIndex elnr, int n, const T * xi, size_t sxi, T * x, size_t sx, T * dxdxi, size_t sdxdxi) { // multipointtrafovar++; /* static int timer = NgProfiler::CreateTimer ("calcmultipointelementtrafo"); static int timer1 = NgProfiler::CreateTimer ("calcmultipointelementtrafo 1"); static int timer2 = NgProfiler::CreateTimer ("calcmultipointelementtrafo 2"); static int timer3 = NgProfiler::CreateTimer ("calcmultipointelementtrafo 3"); static int timer4 = NgProfiler::CreateTimer ("calcmultipointelementtrafo 4"); static int timer5 = NgProfiler::CreateTimer ("calcmultipointelementtrafo 5"); NgProfiler::RegionTimer reg(timer); */ // NgProfiler::StartTimer (timer); // NgProfiler::StartTimer (timer1); if (mesh.coarsemesh) { const HPRefElement & hpref_el = (*mesh.hpelements) [mesh[elnr].GetHpElnr()]; // xi umrechnen T lami[8]; TFlatVector vlami(8, &lami[0]); NgArrayMem coarse_xi (3*n); for (int pi = 0; pi < n; pi++) { vlami = 0; Point<3,T> pxi; for (int j = 0; j < 3; j++) pxi(j) = xi[pi*sxi+j]; mesh[elnr].GetShapeNew (pxi, vlami); Point<3,T> 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 (ElementIndex(hpref_el.coarse_elnr), n, &coarse_xi[0], 3, x, sx, dxdxi, sdxdxi); Mat<3,3,T> trans, dxdxic; if (dxdxi) { MatrixFixWidth<3,T> dlami(8); dlami = T(0); for (int pi = 0; pi < n; pi++) { Point<3,T> 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,3,T> 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; } // NgProfiler::StopTimer (timer1); // NgProfiler::StartTimer (timer2); 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.SetEdges (top.GetEdges(elnr)); info.SetFaces (top.GetFaces(elnr)); for (auto e : info.GetEdges()) info.ndof += edgecoeffsindex[e+1] - edgecoeffsindex[e]; for (auto f : info.GetFaces()) info.ndof += facecoeffsindex[f+1] - facecoeffsindex[f]; } // NgProfiler::StopTimer (timer2); // NgProfiler::StartTimer (timer3); bool ok = true; for (int i = 0; i < n; i++) { Point<3,T> _xi(xi[i*sxi], xi[i*sxi+1], xi[i*sxi+2]); Point<3,T> _x; Mat<3,3,T> _dxdxi; if (!EvaluateMapping (info, _xi, _x, _dxdxi)) { ok = false; break; } // cout << "x = " << _x << ", dxdxi = " << _dxdxi << endl; if (x) for (int j = 0; j < 3; j++) x[i*sx+j] = _x[j]; if (dxdxi) for (int j = 0; j < 3; j++) for (int k = 0; k < 3; k++) dxdxi[i*sdxdxi+3*j+k] = _dxdxi(j,k); } if (ok) return; NgArrayMem,100> coefs(info.ndof); NgArrayMem shapes_mem(info.ndof); TFlatVector shapes(info.ndof, &shapes_mem[0]); NgArrayMem dshapes_mem(3*info.ndof); MatrixFixWidth<3,T> dshapes(info.ndof, &dshapes_mem[0]); // NgProfiler::StopTimer (timer3); // NgProfiler::StartTimer (timer4); GetCoefficients (info, &coefs[0]); if (x) { for (int j = 0; j < n; j++) { Point<3,T> xij, xj; for (int k = 0; k < 3; k++) xij(k) = xi[j*sxi+k]; CalcElementShapes (info, xij, shapes); xj = T(0.0); for (int i = 0; i < coefs.Size(); i++) for (int k = 0; k < 3; k++) xj(k) += shapes(i) * coefs[i](k); // cout << "old, xj = " << xj << endl; for (int k = 0; k < 3; k++) x[j*sx+k] = xj(k); } } // NgProfiler::StopTimer (timer4); // NgProfiler::StartTimer (timer5); if (dxdxi) { if (info.order == 1 && type == TET) { if (n > 0) { Point<3,T> xij; for (int k = 0; k < 3; k++) xij(k) = xi[k]; CalcElementDShapes (info, xij, dshapes); Mat<3,3,T> 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,T> xij; for (int k = 0; k < 3; k++) xij(k) = xi[ip*sxi+k]; CalcElementDShapes (info, xij, dshapes); Mat<3,3,T> 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); // cout << "old, jac = " << dxdxij << endl; for (int j = 0; j < 3; j++) for (int k = 0; k < 3; k++) dxdxi[ip*sdxdxi+3*j+k] = dxdxij(j,k); /* T dxdxi00 = T(0.0); T dxdxi01 = T(0.0); T dxdxi02 = T(0.0); T dxdxi10 = T(0.0); T dxdxi11 = T(0.0); T dxdxi12 = T(0.0); T dxdxi20 = T(0.0); T dxdxi21 = T(0.0); T dxdxi22 = T(0.0); for (int i = 0; i < coefs.Size(); i++) { T ds0 = dshapes(i,0); T ds1 = dshapes(i,1); T ds2 = dshapes(i,2); T cf0 = coefs[i](0); T cf1 = coefs[i](1); T cf2 = coefs[i](2); dxdxi00 += ds0*cf0; dxdxi01 += ds1*cf0; dxdxi02 += ds2*cf0; dxdxi10 += ds0*cf1; dxdxi11 += ds1*cf1; dxdxi12 += ds2*cf1; dxdxi20 += ds0*cf2; dxdxi21 += ds1*cf2; dxdxi22 += ds2*cf2; } dxdxi[ip*sdxdxi+3*0+0] = dxdxi00; dxdxi[ip*sdxdxi+3*0+1] = dxdxi01; dxdxi[ip*sdxdxi+3*0+2] = dxdxi02; dxdxi[ip*sdxdxi+3*1+0] = dxdxi10; dxdxi[ip*sdxdxi+3*1+1] = dxdxi11; dxdxi[ip*sdxdxi+3*1+2] = dxdxi12; dxdxi[ip*sdxdxi+3*2+0] = dxdxi20; dxdxi[ip*sdxdxi+3*2+1] = dxdxi21; dxdxi[ip*sdxdxi+3*2+2] = dxdxi22; */ } } } // NgProfiler::StopTimer (timer5); // NgProfiler::StopTimer (timer); } template void CurvedElements :: CalcMultiPointElementTransformation (ElementIndex elnr, int n, const double * xi, size_t sxi, double * x, size_t sx, double * dxdxi, size_t sdxdxi); template void CurvedElements :: CalcMultiPointElementTransformation (ElementIndex elnr, int n, const SIMD * xi, size_t sxi, SIMD * x, size_t sx, SIMD * dxdxi, size_t sdxdxi); }; ================================================ FILE: libsrc/meshing/curvedelems.hpp ================================================ #ifndef NETGEN_CURVEDELEMS_HPP #define NETGEN_CURVEDELEMS_HPP /**************************************************************************/ /* File: curvedelems.hpp */ /* Author: Robert Gaisbauer (first version) */ /* redesign by Joachim Schoeberl */ /* Date: 27. Sep. 02, Feb 2006 */ /**************************************************************************/ #include #include #include #include "meshtype.hpp" #include "meshclass.hpp" namespace netgen { class Refinement; class Mesh; class CurvedElements { const Mesh & mesh; NgArray edgeorder; NgArray faceorder; NgArray edgecoeffsindex; NgArray facecoeffsindex; NgArray< Vec<3> > edgecoeffs; NgArray< Vec<3> > facecoeffs; NgArray< double > edgeweight; // for rational 2nd order splines int order; bool rational; bool ishighorder; public: DLL_HEADER CurvedElements (const Mesh & amesh); DLL_HEADER ~CurvedElements(); // bool IsHighOrder() const { return order > 1; } bool IsHighOrder() const { return ishighorder; } // void SetHighOrder (int aorder) { order=aorder; } void SetIsHighOrder (bool ho) { ishighorder = ho; } DLL_HEADER void BuildCurvedElements(const Refinement * ref, int aorder, bool arational = false); int GetOrder () { return order; } void DoArchive(Archive& ar); DLL_HEADER bool IsSegmentCurved (SegmentIndex segnr) const; DLL_HEADER bool IsSurfaceElementCurved (SurfaceElementIndex sei) const; DLL_HEADER bool IsElementCurved (ElementIndex ei) const; DLL_HEADER bool IsElementHighOrder (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 (NgArray * xi, SegmentIndex segnr, NgArray > * x, NgArray > * dxdxi); */ template void CalcMultiPointSegmentTransformation (SegmentIndex elnr, int n, const T * xi, size_t sxi, T * x, size_t sx, T * dxdxi, size_t sdxdxi); DLL_HEADER void CalcMultiPointSurfaceTransformation (NgArray< Point<2> > * xi, SurfaceElementIndex elnr, NgArray< Point<3> > * x, NgArray< Mat<3,2> > * dxdxi); template void CalcMultiPointSurfaceTransformation (SurfaceElementIndex elnr, int n, const T * xi, size_t sxi, T * x, size_t sx, T * dxdxi, size_t sdxdxi); DLL_HEADER void CalcMultiPointElementTransformation (NgArray< Point<3> > * xi, ElementIndex elnr, NgArray< Point<3> > * x, NgArray< Mat<3,3> > * dxdxi); template void CalcMultiPointElementTransformation (ElementIndex elnr, int n, const T * xi, size_t sxi, T * x, size_t sx, T * dxdxi, size_t sdxdxi); private: template DLL_HEADER void CalcSegmentTransformation (const T & xi, SegmentIndex segnr, Point<3,T> * x = NULL, Vec<3,T> * dxdxi = NULL, bool * curved = NULL); DLL_HEADER void CalcSurfaceTransformation (Point<2> xi, SurfaceElementIndex elnr, Point<3> * x = NULL, Mat<3,2> * dxdxi = NULL, bool * curved = NULL); DLL_HEADER 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; }; template void CalcElementShapes (SegmentInfo & elnr, T xi, TFlatVector shapes) const; void GetCoefficients (SegmentInfo & elnr, NgArray > & coefs) const; template void CalcElementDShapes (SegmentInfo & elnr, T xi, TFlatVector 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 SetEdges (FlatArray edges) { nedges = edges.Size(); for (int i = 0; i < edges.Size(); i++) edgenrs[i] = edges[i]; } auto GetEdges() const { return FlatArray(nedges, edgenrs); } void SetFaces (FlatArray faces) { nfaces = faces.Size(); for (int i = 0; i < faces.Size(); i++) facenrs[i] = faces[i]; } auto GetFaces() const { return FlatArray(nfaces, facenrs); } }; template void CalcElementShapes (ElementInfo & info, Point<3,T> xi, TFlatVector shapes) const; void GetCoefficients (ElementInfo & info, Vec<3> * coefs) const; template void CalcElementDShapes (ElementInfo & info, const Point<3,T> xi, MatrixFixWidth<3,T> & dshapes) const; template bool EvaluateMapping (ElementInfo & info, const Point<3,T> xi, Point<3,T> & x, Mat<3,3,T> & jac) const; class SurfaceElementInfo { public: SurfaceElementIndex elnr; int order; int nv; int ndof; NgArrayMem edgenrs; int facenr; void SetEdges (FlatArray edges) { edgenrs.SetSize(edges.Size()); for (int i = 0; i < edges.Size(); i++) edgenrs[i] = edges[i]; } }; template void CalcElementShapes (SurfaceElementInfo & elinfo, const Point<2,T> xi, TFlatVector shapes) const; template void GetCoefficients (SurfaceElementInfo & elinfo, NgArray > & coefs) const; template void CalcElementDShapes (SurfaceElementInfo & elinfo, const Point<2,T> xi, MatrixFixWidth<2,T> & dshapes) const; template bool EvaluateMapping (SurfaceElementInfo & info, const Point<2,T> xi, Point & x, Mat & jac) const; }; } //namespace netgen #endif // NETGEN_CURVEDELEMS_HPP ================================================ FILE: libsrc/meshing/debugging.cpp ================================================ #include #include "debugging.hpp" namespace netgen { unique_ptr GetOpenElements( const Mesh & m, int dom, bool only_quads ) { static Timer t("GetOpenElements"); RegionTimer rt(t); auto mesh = make_unique(); *mesh = m; Array interesting_points(mesh->GetNP()); interesting_points = false; mesh->FindOpenElements(dom); NgArray openelements; openelements = mesh->OpenElements(); for (auto & el : openelements) for (auto i : el.PNums()) interesting_points[i] = true; for (auto & el : mesh->VolumeElements()) { int num_interesting_points = 0; for (auto pi : el.PNums()) if(interesting_points[pi]) num_interesting_points++; if(num_interesting_points==0) el.Delete(); el.SetIndex(num_interesting_points); } mesh->SetMaterial(1, "1_point"); mesh->SetMaterial(2, "2_points"); mesh->SetMaterial(3, "3_points"); mesh->SetMaterial(4, "4_points"); mesh->ClearSurfaceElements(); for (auto & el : openelements) if(!only_quads || el.GetNP() == 4) mesh->AddSurfaceElement( el ); mesh->Compress(); return mesh; } unique_ptr FilterMesh( const Mesh & m, FlatArray points, FlatArray sels, FlatArray els ) { static Timer t("GetOpenElements"); RegionTimer rt(t); auto mesh_ptr = make_unique(); auto & mesh = *mesh_ptr; mesh = m; Array keep_point(mesh.GetNP()); Array keep_sel(mesh.GetNSE()); Array keep_el(mesh.GetNE()); mesh.LineSegments().DeleteAll(); keep_point = false; for(auto pi : points) keep_point[pi] = true; auto set_keep = [&] (auto & input, auto & keep_array, auto & els) { keep_array = false; for(auto ind : input) keep_array[ind] = true; for(auto ind : Range(els)) { bool & keep = keep_array[ind]; if(keep) continue; for(auto pi : mesh[ind].PNums()) keep |= keep_point[pi]; if(!keep) mesh[ind].Delete(); } for(auto i = 0; i> edges; auto elementsonnode = mesh.CreatePoint2ElementTable(); BuildEdgeList(mesh, elementsonnode, edges); mesh.BoundaryEdge(1, 2); // trigger build of boundary edges ArrayMem hasbothpoints; for (auto [pi0, pi1] : edges) { if (mesh.BoundaryEdge(pi0, pi1)) continue; hasbothpoints.SetSize(0); for (ElementIndex ei : elementsonnode[pi0]) if (mesh[ei].PNums().Contains(pi1)) hasbothpoints.Append(ei); bool skip = false; for (ElementIndex ei : hasbothpoints) { if (mesh[ei].GetType() != TET) { skip = true; break; } } if (skip) continue; int nsuround = hasbothpoints.Size(); ArrayMem suroundpts(nsuround + 1); suroundpts = PointIndex::INVALID; ArrayMem tetused(nsuround); tetused = false; tetused[0] = true; auto el = mesh[hasbothpoints[0]]; PointIndex pi2 = PointIndex::INVALID; PointIndex pi3 = PointIndex::INVALID; for (auto pi : el.PNums()) if (pi != pi0 && pi != pi1) { pi3 = pi2; pi2 = pi; } suroundpts[0] = pi2; suroundpts[1] = pi3; for (auto i : Range(2, nsuround + 1)) { PointIndex oldpi = suroundpts[i - 1]; PointIndex newpi = PointIndex::INVALID; for (int k = 0; k < nsuround && !newpi.IsValid(); k++) if (!tetused[k]) { const Element& nel = mesh[hasbothpoints[k]]; for (int k2 = 0; k2 < 4 && !newpi.IsValid(); k2++) if (nel[k2] == oldpi) { newpi = nel[0] - pi0 + nel[1] - pi1 + nel[2] - oldpi + nel[3]; tetused[k] = true; suroundpts[i] = newpi; ArrayMem nelpts{nel[0], nel[1], nel[2], nel[3]}; ArrayMem check_points{pi0, pi1, oldpi, newpi}; QuickSort(check_points); QuickSort(nelpts); if (check_points != nelpts) { cout << __FILE__ << ":" << __LINE__ << "\tFound error" << endl; cout << "i = " << i << endl; cout << "oldpi = " << oldpi << endl; cout << "newpi = " << newpi << endl; cout << "Elements: " << endl; cout << "nel " << nel << endl; for (auto ei : hasbothpoints) cout << mesh[ei] << endl; cout << endl; cout << "check_points: " << check_points << endl; cout << "nelpts: " << nelpts << endl; cout << "hasbothpoints: " << hasbothpoints << endl; cout << "suroundpts: " << suroundpts << endl; throw Exception("Found error"); } } } } if (suroundpts.Last() != suroundpts[0]) { cout << __FILE__ << ":" << __LINE__ << "\tFound error" << endl; cout << "hasbothpoints: " << hasbothpoints << endl; cout << "suroundpts: " << suroundpts << endl; for (auto ei : hasbothpoints) cout << mesh[ei] << endl; throw Exception("Found error"); } } } } // namespace netgen ================================================ FILE: libsrc/meshing/debugging.hpp ================================================ #include "meshfunc.hpp" namespace netgen { unique_ptr GetOpenElements( const Mesh & m, int dom = 0, bool only_quads = false ); unique_ptr FilterMesh( const Mesh & m, FlatArray points, FlatArray sels = Array{}, FlatArray els = Array{} ); // Checks if the mesh is valid. This is called automatically on various places if debugparam.slowchecks is set void CheckMesh( const Mesh & m, MESHING_STEP meshing_step ); // Sometimes during SwapImprove we discover topological errors in the mesh. For instance, an edge is adjacent to 8 tets around it, but // the 8 "other" points of the tets don't form a closed path around the edge. Instead there are 2 sets of 4 points/tets each, which are not connected. // This function checks for such errors and returns true if any are found. void CheckElementsAroundEdges( const Mesh & m ); } ================================================ FILE: libsrc/meshing/delaunay.cpp ================================================ #include #include "meshing.hpp" namespace netgen { // typedef BoxTree<3> DTREE; typedef DelaunayTree<3> DTREE; 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] = {0,0,0,0}; public: DelaunayTet () = default; 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 & NB(int i) { return nb[i]; } int NB(int i) const { return nb[i]; } int FaceNr (const PointIndices<3> & face) const // which face nr is it ? { for (int i = 0; i < 3; i++) if (pnums[i] != face[0] && pnums[i] != face[1] && pnums[i] != face[2]) return i; return 3; } PointIndices<3> GetFace (int i) const { return { pnums[deltetfaces[i][0]], pnums[deltetfaces[i][1]], pnums[deltetfaces[i][2]] }; } void GetFace (int i, Element2d & face) const { // face.SetType(TRIG); face[0] = pnums[deltetfaces[i][0]]; face[1] = pnums[deltetfaces[i][1]]; face[2] = pnums[deltetfaces[i][2]]; } }; /* Table to maintain neighbour elements */ class MeshNB { // face nodes -> one element INDEX_3_CLOSED_HASHTABLE faces; // NgArray & tets; public: // estimated number of points MeshNB (NgArray & 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).NB(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 { NgArray 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, NgArray & linked) const; template void IterateList (int eli, TFUNC func) { int pi = eli; do { func(pi); pi = links.Get(pi); } while (pi != eli); } }; void SphereList :: GetList (int eli, NgArray & linked) const { linked.SetSize (0); int pi = eli; do { #ifdef DELAUNAY_DEBUG 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); } #endif linked.Append (pi); pi = links.Get(pi); } while (pi != eli); } void AddDelaunayPoint (PointIndex newpi, const Point3d & newp, NgArray & tempels, Mesh & mesh, DTREE & tettree, MeshNB & meshnb, NgArray > & centers, NgArray & radi2, NgArray & connected, NgArray & treesearch, NgArray & freelist, SphereList & list, IndexSet & insphere, IndexSet & closesphere, Array & newels) { static Timer t("Meshing3::AddDelaunayPoint", NoTracing, NoTiming); RegionTimer reg(t); static Timer tsearch("addpoint, search", NoTracing, NoTiming); static Timer tfind("addpoint, find all tets", NoTracing, NoTiming); static Timer tnewtets("addpoint, build new tets", NoTracing, NoTiming); static Timer tinsert("addpoint, insert", NoTracing, NoTiming); /* find any sphere, such that newp is contained in */ // DelaunayTet el; int cfelind = -1; const Point<3> * pp[4]; Point<3> pc; Point3d tpmin, tpmax; /* // stop search if intersecting point is close enough to center tettree.GetFirstIntersecting (newp, newp, treesearch, [&](const auto pi) { double quot = Dist2 (centers.Get(pi), newp); return (quot < 0.917632 * radi2.Get(pi)); } ); // tettree.GetIntersecting (newp, newp, treesearch); double quot,minquot(1e20); for (auto jjj : treesearch) { 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; } } */ tsearch.Start(); double minquot{1e20}; tettree.GetFirstIntersecting (newp, newp, [&](const auto pi) { double rad2 = radi2.Get(pi); double d2 = Dist2 (centers.Get(pi), newp); // / radi2.Get(pi); if (d2 >= rad2) return false; // if (d2 < 0.917632 * rad2) if (d2 < 0.99 * rad2) { cfelind = pi; return true; } if (cfelind == -1 || d2 < 0.99*minquot*rad2) { minquot = d2/rad2; cfelind = pi; } return false; } ); tsearch.Stop(); if (cfelind == -1) { PrintWarning ("Delaunay, point not in any sphere"); return; } tfind.Start(); /* 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); bool changed = true; int nstarti = 1, starti; while (changed) { changed = false; 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.IterateList (insphere.GetArray().Get(j), [&](int celind) { if (tempels.Get(celind)[0] != PointIndex(PointIndex::INVALID) && !insphere.IsIn (celind)) { changed = true; insphere.Add (celind); } }); } // check neighbour-tets for (int j = starti; j < nstarti; j++) for (int k = 0; k < 4; k++) { int helind = insphere.GetArray().Get(j); int nbind = meshnb.GetNB (helind, k); if (nbind && !insphere.IsIn (nbind) ) { double d2 = Dist2 (centers.Get(nbind), newp); if (d2 < radi2.Get(nbind) * (1+1e-8) ) closesphere.Add (nbind); if (d2 < radi2.Get(nbind) * (1 + 1e-12)) { // point is in sphere -> remove tet insphere.Add (nbind); changed = true; } else { PointIndices<3> i3 = tempels.Get(helind).GetFace (k); const Point<3> & p1 = mesh[i3[0]]; const Point<3> & p2 = mesh[i3[1]]; const Point<3> & p3 = mesh[i3[2]]; Vec<3> n = Cross (p2-p1, p3-p1); n /= n.Length(); double dist = n * (newp-p1); double scal = n * (mesh.Point (tempels.Get(helind)[k])-p1); if (scal > 0) dist *= -1; if (dist > -1e-10) // 1e-10 { insphere.Add (nbind); changed = true; } } } } } // while (changed) tfind.Stop(); tnewtets.Start(); newels.SetSize(0); Element2d face(TRIG); for (int celind : insphere.GetArray()) for (int k = 0; k < 4; k++) { int nbind = meshnb.GetNB (celind, k); if (!nbind || !insphere.IsIn (nbind)) { tempels.Get (celind).GetFace (k, face); // Element newel(TET); DelaunayTet newel; for (int l = 0; l < 3; l++) newel[l] = face[l]; newel[3] = newpi; newels.Append (newel); #ifdef DEBUG_DELAUNAY 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(celind)[k])) > 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; } #endif } } meshnb.ResetFaceHT (10*insphere.GetArray().Size()+1); for (auto celind : insphere.GetArray()) { meshnb.Delete (celind); list.DeleteElement (celind); for (int k = 0; k < 4; k++) tempels.Elem(celind)[k] = PointIndex::INVALID; tettree.DeleteElement (celind); freelist.Append (celind); } bool hasclose = false; for (int ind : closesphere.GetArray()) { if (!insphere.IsIn(ind) && fabs (Dist2 (centers.Get (ind), newp) - radi2.Get(ind)) < 1e-8 ) hasclose = true; } /* for (int j = 1; j <= newels.Size(); j++) { const auto & newel = newels.Get(j); */ for (const auto & newel : newels) { int nelind; if (!freelist.Size()) { tempels.Append (newel); nelind = tempels.Size(); } else { nelind = freelist.Last(); freelist.DeleteLast(); tempels.Elem(nelind) = newel; } meshnb.Add (nelind); list.AddElement (nelind); for (int k = 0; k < 4; k++) pp[k] = &mesh.Point (newel[k]); if (CalcSphereCenter (&pp[0], pc) ) { #ifdef DEBUG_DELAUNAY PrintSysError ("Delaunay: New tet is flat"); (*testout) << "new tet is flat" << endl; for (int k = 0; k < 4; k++) (*testout) << newel[k] << " "; (*testout) << endl; for (int k = 0; k < 4; k++) (*testout) << *pp[k-1] << " "; (*testout) << endl; #endif ; } double r2 = Dist2 (*pp[0], pc); if (hasclose) /* for (int k = 1; k <= closesphere.GetArray().Size(); k++) { int csameind = closesphere.GetArray().Get(k); */ for (int csameind : closesphere.GetArray()) { if (!insphere.IsIn(csameind) && fabs (r2 - radi2.Get(csameind)) < 1e-10 && Dist2 (pc, centers.Get(csameind)) < 1e-20) { 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); tinsert.Start(); tettree.Insert (tpmin, tpmax, nelind); tinsert.Stop(); } tnewtets.Stop(); } void Delaunay1 (Mesh & mesh, int domainnr, const MeshingParameters & mp, const AdFront3 & adfront, NgArray & tempels, int oldnp, DelaunayTet & startel, Point3d & pmin, Point3d & pmax) { static Timer t("Meshing3::Delaunay1"); RegionTimer reg(t); NgArray> centers; NgArray radi2; Box<3> bbox(Box<3>::EMPTY_BOX); for (auto & face : adfront.Faces()) for (PointIndex pi : face.Face().PNums()) bbox.Add (mesh.Point(pi)); for (PointIndex pi : mesh.LockedPoints()) bbox.Add (mesh.Point (pi)); pmin = bbox.PMin(); pmax = bbox.PMax(); Vec<3> vdiag = pmax-pmin; // double r1 = vdiag.Length(); double r1 = sqrt (3.0) * max3(vdiag(0), vdiag(1), vdiag(2)); vdiag = Vec<3> (r1, r1, r1); //double r2; Point<3> pmin2 = pmin - 8 * vdiag; Point<3> pmax2 = pmax + 8 * vdiag; Point<3> cp1(pmin2), cp2(pmax2), cp3(pmax2), cp4(pmax2); cp2(0) = pmin2(0); cp3(1) = pmin2(1); cp4(2) = pmin2(2); size_t 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: Array usep(np); usep = false; for (auto & face : adfront.Faces()) for (PointIndex pi : face.Face().PNums()) usep[pi] = true; /* for (size_t i = oldnp + PointIndex::BASE; i < np + PointIndex::BASE; i++) */ for (auto i : mesh.Points().Range().Modify(oldnp, -4)) usep[i] = true; for (PointIndex pi : mesh.LockedPoints()) usep[pi] = true; // mark points of free edge segments (no adjacent face) for (auto & seg : mesh.LineSegments()) if(seg.domin == domainnr && seg.domout == domainnr) { usep[seg[0]] = true; usep[seg[1]] = true; } NgArray freelist; int cntp = 0; MeshNB meshnb (tempels, mesh.GetNP() + 5); SphereList list; pmin2 = pmin2 + 0.1 * (pmin2 - pmax2); pmax2 = pmax2 + 0.1 * (pmax2 - pmin2); DTREE tettree(pmin2, pmax2); tempels.Append (startel); meshnb.Add (1); list.AddElement (1); NgArray connected, treesearch; Box<3> tbox(Box<3>::EMPTY_BOX); for (size_t k = 0; k < 4; k++) tbox.Add (mesh.Point(startel[k])); Point<3> tpmin = tbox.PMin(); Point<3> tpmax = tbox.PMax(); tpmax = tpmax + 0.01 * (tpmax - tpmin); tettree.Insert (tpmin, tpmax, 1); Point<3> pc; const Point<3> * pp[4]; for (int 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 mixed(np); // int prims[] = { 11, 13, 17, 19, 23, 29, 31, 37 }; // int prims[] = { 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97 }; int prims[] = { 211, 223, 227, 229, 233, 239, 241, 251, 257, 263 }; int prim; { int i = 0; while (np % prims[i] == 0) i++; prim = prims[i]; } // for (PointIndex pi = mesh.Points().Begin(); pi < mesh.Points().End()-4; pi++) for (PointIndex pi : mesh.Points().Range().Modify(0, -4)) // mixed[pi] = PointIndex ( (prim * pi) % np + PointIndex::BASE ); mixed[pi] = (prim * (pi-IndexBASE()+1)) % np + IndexBASE() ; Array newels; // for (PointIndex pi = mesh.Points().Begin(); pi < mesh.Points().End()-4; pi++) for (PointIndex pi : mesh.Points().Range().Modify(0, -4)) { if ((pi-IndexBASE()) % 1000 == 0) { if ((pi-IndexBASE()) % 10000 == 0) PrintDot ('+'); else PrintDot ('.'); } multithread.percent = 100.0 * (pi-IndexBASE()) / np; if (multithread.terminate) break; PointIndex newpi = mixed[pi]; if (!usep[newpi]) continue; cntp++; const MeshPoint & newp = mesh[newpi]; AddDelaunayPoint (newpi, newp, tempels, mesh, tettree, meshnb, centers, radi2, connected, treesearch, freelist, list, insphere, closesphere, newels); } for (int i = tempels.Size(); i >= 1; i--) if (!tempels.Get(i)[0].IsValid()) tempels.DeleteElement (i); PrintDot ('\n'); PrintMessage (3, "Points: ", cntp); PrintMessage (3, "Elements: ", tempels.Size()); PrintMessage (3, "Tree data entries per element: ", 1.0*tettree.N*tettree.GetNLeaves() / tempels.Size()); PrintMessage (3, "Tree nodes per element: ", 1.0*tettree.GetNNodes() / 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 DelaunayRemoveDegenerated( const Mesh::T_POINTS & points, NgArray & tempels, int np ) { static Timer tdegenerated("Delaunay - remove degenerated"); RegionTimer rt(tdegenerated); TBitArray badnode(points.Size()); 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 = points[el[0]]; const Point3d & lp2 = points[el[1]]; const Point3d & lp3 = points[el[2]]; const Point3d & lp4 = points[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] < IndexBASE()+np && el[1] < IndexBASE()+np && el[2] < IndexBASE()+np && el[3] < IndexBASE()+np) ) // old: 1e-12 { badnode.SetBitAtomic(el[0]); badnode.SetBitAtomic(el[1]); badnode.SetBitAtomic(el[2]); badnode.SetBitAtomic(el[3]); ndeg++; (*testout) << "vol = " << vol << " h = " << h << endl; } if (vol > 0) Swap (el[2], el[3]); } auto 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"); } // Remove flat tets containing two adjacent surface trigs void DelaunayRemoveTwoTriaTets( const Mesh & mesh, NgArray & tempels, NgArray & openels ) { static Timer topenel("Delaunay - find openel"); RegionTimer rt(topenel); // find surface triangles which are no face of any tet TBitArray bnd_points( mesh.GetNP() ); bnd_points.Clear(); for (int i = 1; i <= mesh.GetNOpenElements(); i++) { const Element2d & tri = mesh.OpenElement(i); bnd_points.SetBit(tri[0]); bnd_points.SetBit(tri[1]); bnd_points.SetBit(tri[2]); } auto ne = tempels.Size(); Array tets_with_3_bnd_points(ne); atomic cnt = 0; // table of tets with >= 2 boundary points, store in extra array tets with >=3 boundary points auto p2el = ngcore::CreateSortedTable( ne, [&](auto & table, int ei) { const auto & el = tempels[ei]; int num_bnd_points = 0; for( auto i : Range(4) ) if(bnd_points[el[i]]) num_bnd_points++; if(num_bnd_points>1) { table.Add (el[0], ei); table.Add (el[1], ei); table.Add (el[2], ei); table.Add (el[3], ei); } // table creator is running this code 2 times, only store tets on last run if(table.GetMode()==3 && num_bnd_points>2) tets_with_3_bnd_points[cnt++] = ei; }, mesh.GetNP()); tets_with_3_bnd_points.SetSize(cnt); static Timer t1("Build face table"); t1.Start(); // ngcore::ClosedHashTable< ngcore::IVec<3>, int > face_table( 4*cnt + 3 ); ngcore::ClosedHashTable< PointIndices<3>, int > face_table( 4*cnt + 3 ); for (auto ei : tets_with_3_bnd_points) for (auto j : Range(4)) { PointIndices<3> i3 = tempels[ei].GetFace (j); // ngcore::IVec<3> i3 = {i3_[0], i3_[1], i3_[2]}; if(bnd_points[i3[0]] && bnd_points[i3[1]] && bnd_points[i3[2]]) { i3.Sort(); face_table.Set( i3, true ); } } t1.Stop(); static Timer t2("check faces"); t2.Start(); openels.SetSize(0); for (int i = 1; i <= mesh.GetNOpenElements(); i++) { const Element2d & tri = mesh.OpenElement(i); // ngcore::IVec<3,PointIndex> i3(tri[0], tri[1], tri[2]); PointIndices<3> i3(tri[0], tri[1], tri[2]); i3.Sort(); if(!face_table.Used(i3)) openels.Append(i); } t2.Stop(); auto p2sel = ngcore::CreateSortedTable( Range(openels.Size()), [&](auto & table, int i) { auto openel_i = openels[i]; const Element2d & tri = mesh.OpenElement(openel_i); table.Add(tri[0], openel_i); table.Add(tri[1], openel_i); table.Add(tri[2], openel_i); }, mesh.GetNP()); TBitArray badnode(mesh.GetNP()); badnode.Clear(); ngcore::ParallelForRange(openels.Size(), [&] (auto myrange) { for (auto i_ : myrange) { auto i = openels[i_]; const Element2d & tri = mesh.OpenElement(i); for( auto edge : Range(3) ) { auto pi0 = tri[edge]; auto pi1 = tri[(edge+1)%3]; if(pi0>pi1) Swap(pi0, pi1); // find other trig with edge pi0, pi1 int i_other = -1; for(auto ii : p2sel[pi0]) { if(ii==i) continue; auto & tri_other = mesh.OpenElement(ii); if(tri_other[0]==pi1 || tri_other[1]==pi1 || tri_other[2]==pi1) { i_other = ii; break; } } if(i_other>i) { auto & tri_other = mesh.OpenElement(i_other); PointIndex pi2 = tri[(edge+2)%3]; PointIndex pi3 = tri_other[0]-pi0+tri_other[1]-pi1+tri_other[2]; if(pi2>pi3) Swap(pi2, pi3); // search for tet with edge pi2-pi3 for(auto ei : p2el[pi2]) { auto & el = tempels[ei]; if(el[0]==pi3 || el[1]==pi3 || el[2]==pi3 || el[3]==pi3) { const Point3d & p1 = mesh[pi0]; const Point3d & p2 = mesh[pi1]; const Point3d & p3 = mesh[pi2]; const Point3d & p4 = mesh[pi3]; 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.SetBitAtomic(pi2); badnode.SetBitAtomic(pi3); } break; } } } } } }); for (int i = ne; i >= 1; i--) { const DelaunayTet & el = tempels.Get(i); if (badnode[el[0]] || badnode[el[1]] || badnode[el[2]] || badnode[el[3]] ) tempels.DeleteElement(i); } } void DelaunayRemoveIntersecting( const Mesh & mesh, NgArray & tempels, NgArray & openels, Point3d pmin, Point3d pmax ) { static Timer trem_intersect("Delaunay - remove intersecting"); RegionTimer rt(trem_intersect); // find intersecting: PrintMessage (3, "Remove intersecting"); if (openels.Size()) { BoxTree<3> 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); } } NgArray 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]-IndexBASE()+1; } 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)-IndexBASE()+1; } 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--; } } } } void DelaunayRemoveOuter( const Mesh & mesh, NgArray & tempels, const AdFront3 & adfront ) { static Timer trem_outer("Delaunay - remove outer"); RegionTimer rt(trem_outer); PrintMessage (3, "Remove outer"); // find connected tets (with no face between, and no hole due // to removed intersecting tets. // INDEX_3_HASHTABLE innerfaces(np); INDEX_3_HASHTABLE 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); } */ for (const Element2d & tri : mesh.OpenElements()) { PointIndices<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); PointIndices<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; */ for (auto & el : tempels) for (int j = 0; j < 4; j++) el.NB(j) = 0; /* TABLE elsonpoint(mesh.GetNP()); for (const DelaunayTet & el : tempels) { PointIndices<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]; PointIndices<4> i4(el[0], el[1], el[2], el[3]); i4.Sort(); elsonpoint.Add (i4.I1(), i+1); elsonpoint.Add (i4.I2(), i+1); } */ TableCreator creator(mesh.GetNP()); while (!creator.Done()) { for (int i = 0; i < tempels.Size(); i++) { const DelaunayTet & el = tempels[i]; PointIndices<4> i4(el[0], el[1], el[2], el[3]); i4.Sort(); creator.Add (i4[0], i+1); creator.Add (i4[1], i+1); } creator++; } auto elsonpoint = creator.MoveTable(); // cout << "elsonpoint mem: "; // elsonpoint.PrintMemInfo(cout); INDEX_3_CLOSED_HASHTABLE faceht(100); Element2d hel(TRIG); // for (PointIndex pi = mesh.Points().Begin(); pi < mesh.Points().End(); pi++) for (PointIndex pi : mesh.Points().Range()) { 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.GetFace (j-1, hel); hel.Invert(); hel.NormalizeNumbering(); if (hel[0] == pi) { PointIndices<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).NB(j-1) = i2.I1(); tempels.Elem(i2.I1()).NB(i2.I2()-1) = i; } else { hel.Invert(); hel.NormalizeNumbering(); PointIndices<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"); auto ne = tempels.Size(); BitArray inner(ne+1), outer(ne+1); inner.Clear(); outer.Clear(); NgArray 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; } } */ int lowest_undefined_el = 1; while (1) { int inside; bool done = 1; int i; for (i = lowest_undefined_el; i <= ne; i++) if (!inner.Test(i) && !outer.Test(i)) { lowest_undefined_el = i+1; 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.SetBit(ei); else outer.SetBit(ei); for (int j = 1; j <= 4; j++) { INDEX_3 i3 = tempels.Get(ei).GetFace(j-1); /* Element2d face; tempels.Get(ei).GetFace(j, face); for (int kk = 1; kk <= 3; kk++) i3.I(kk) = face.PNum(kk); */ i3.Sort(); if (tempels.Get(ei).NB(j-1)) elstack.Append (tempels.Get(ei).NB(j-1)); /* 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.SetBit(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); PrintMessage (5, "outer removed"); } void Meshing3 :: Delaunay (Mesh & mesh, int domainnr, const MeshingParameters & mp) { static Timer t("Meshing3::Delaunay"); RegionTimer reg(t); PrintMessage (1, "Delaunay meshing"); PrintMessage (3, "number of points: ", mesh.GetNP()); // PushStatus ("Delaunay meshing"); NgArray tempels; Point3d pmin, pmax; DelaunayTet startel; int oldnp = mesh.GetNP(); if (mp.blockfill) { BlockFillLocalH (mesh, mp); PrintMessage (3, "number of points: ", mesh.GetNP()); } int np = mesh.GetNP(); Delaunay1 (mesh, domainnr, mp, *adfront, tempels, oldnp, startel, pmin, pmax); { // improve delaunay - mesh by swapping !!!! Mesh tempmesh; tempmesh.GetMemoryTracer().SetName("delaunay-tempmesh"); for (auto & meshpoint : mesh.Points()) tempmesh.AddPoint (meshpoint); for (auto & tempel : tempels) { Element el(4); for (int j = 0; j < 4; j++) el[j] = tempel[j]; el.SetIndex (1); const Point<3> & lp1 = mesh.Point (el[0]); const Point<3> & lp2 = mesh.Point (el[1]); const Point<3> & lp3 = mesh.Point (el[2]); const Point<3> & lp4 = mesh.Point (el[3]); Vec<3> v1 = lp2-lp1; Vec<3> v2 = lp3-lp1; Vec<3> v3 = lp4-lp1; Vec<3> n = Cross (v1, v2); double vol = n * v3; if (vol > 0) swap (el[2], el[3]); tempmesh.AddVolumeElement (el); } tempels.DeleteAll(); 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.GetFace (i-1, self); tempmesh.AddSurfaceElement (self); } // for (i = mesh.GetNP() - 3; i <= mesh.GetNP(); i++) // tempmesh.AddLockedPoint (i); for (auto pi : tempmesh.Points().Range()) tempmesh.AddLockedPoint (pi); // tempmesh.PrintMemInfo(cout); // tempmesh.Save ("tempmesh.vol"); { MeshOptimize3d meshopt(tempmesh, mp); meshopt.SetGoal(OPT_CONFORM); tempmesh.Compress(); tempmesh.FindOpenElements (); #ifndef EMSCRIPTEN RegionTaskManager rtm(mp.parallel_meshing ? mp.nthreads : 0); #endif // EMSCRIPTEN for (auto i : Range(10)) { PrintMessage (5, "Num open: ", tempmesh.GetNOpenElements()); if(i%5==0) tempmesh.FreeOpenElementsEnvironment (1); meshopt.SwapImprove(); } tempmesh.Compress(); } MeshQuality3d (tempmesh); tempels.SetSize(tempmesh.GetNE()); tempels.SetSize(0); for (auto & el : tempmesh.VolumeElements()) tempels.Append (el); } DelaunayRemoveDegenerated(mesh.Points(), tempels, np); NgArray openels; DelaunayRemoveTwoTriaTets(mesh, tempels, openels); DelaunayRemoveIntersecting(mesh, tempels, openels, pmin, pmax); DelaunayRemoveOuter(mesh, tempels, *adfront); 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); } mesh.FindOpenElements(domainnr); mesh.Compress(); // PopStatus (); } } ================================================ FILE: libsrc/meshing/delaunay2d.cpp ================================================ #include #include "delaunay2d.hpp" #include namespace netgen { using namespace std; void DelaunayTrig::CalcCenter (FlatArray, PointIndex> points) { Point<2> p1 = points[pnums[0]]; Point<2> p2 = points[pnums[1]]; Point<2> p3 = points[pnums[2]]; Vec<2> v1 = p2-p1; Vec<2> v2 = p3-p1; // without normal equation ... Mat<2,2> mat, inv; mat(0,0) = v1(0); mat(0,1) = v1(1); mat(1,0) = v2(0); mat(1,1) = v2(1); CalcInverse (mat, inv); Vec<2> rhs, sol; rhs(0) = 0.5 * v1*v1; rhs(1) = 0.5 * v2*v2; sol = inv * rhs; c = p1 + sol; rad2 = Dist2(c, p1); r = sqrt(rad2); } int DelaunayMesh::GetNeighbour( int eli, int edge ) { auto p0 = trigs[eli][(edge+1)%3]; auto p1 = trigs[eli][(edge+2)%3]; if(p1 hash = {p0,p1}; auto pos = edge_to_trig.Position(hash); if (pos == -1) return -1; auto i2 = edge_to_trig.GetData(pos); return i2[0] == eli ? i2[1] : i2[0]; } void DelaunayMesh::SetNeighbour( int eli, int edge ) { auto p0 = trigs[eli][(edge+1)%3]; auto p1 = trigs[eli][(edge+2)%3]; if(p1 hash = {p0,p1}; auto pos = edge_to_trig.Position(hash); if (pos == -1) edge_to_trig[hash] = {eli, -1}; else { auto i2 = edge_to_trig.GetData(pos); if(i2[0]==-1) i2[0] = eli; else { if(i2[1]==-1) i2[1] = eli; } edge_to_trig.SetData (pos, i2); } } void DelaunayMesh::UnsetNeighbours( int eli ) { for(int edge : Range(3)) { auto p0 = trigs[eli][(edge+1)%3]; auto p1 = trigs[eli][(edge+2)%3]; if(p1 hash = {p0,p1}; auto pos = edge_to_trig.Position(hash); auto i2 = edge_to_trig.GetData(pos); if(i2[0]==eli) i2[0] = i2[1]; i2[1] = -1; edge_to_trig.SetData (pos, i2); } } void DelaunayMesh::AppendTrig( PointIndex pi0, PointIndex pi1, PointIndex pi2 ) { DelaunayTrig el; el[0] = pi0; el[1] = pi1; el[2] = pi2; el.CalcCenter(points); trigs.Append(el); int ti = trigs.Size()-1; tree->Insert(el.BoundingBox(), ti); for(int i : Range(3)) SetNeighbour(ti, i); } DelaunayMesh::DelaunayMesh( Array, PointIndex> & points_, Box<2> box ) : points(points_) { Vec<2> vdiag = box.PMax()-box.PMin(); double w = vdiag(0); double h = vdiag(1); Point<2> p0 = box.PMin() + Vec<2> ( -3*h, -h); Point<2> p1 = box.PMin() + Vec<2> (w+3*h, -h); Point<2> p2 = box.Center() + Vec<2> (0, 1.5*h+0.5*w); box.Add( p0 ); box.Add( p1 ); box.Add( p2 ); tree = make_unique>(box); auto pi0 = points.Append (p0); auto pi1 = points.Append (p1); auto pi2 = points.Append (p2); AppendTrig(pi0, pi1, pi2); } void DelaunayMesh::CalcIntersecting( PointIndex pi_new ) { static Timer t("CalcIntersecting"); RegionTimer reg(t); Point<2> newp = points[pi_new]; intersecting.SetSize(0); edges.SetSize(0); int definitive_overlapping_trig = -1; double minquot{1e20}; tree->GetFirstIntersecting (newp, newp, [&] (const auto i_trig) { const auto trig = trigs[i_trig]; double rad2 = trig.Radius2(); double d2 = Dist2 (trig.Center(), newp); if (d2 >= rad2) return false; if (d2 < 0.999 * rad2) { definitive_overlapping_trig = i_trig; return true; } if (definitive_overlapping_trig == -1 || d2 < 0.99*minquot*rad2) { minquot = d2/rad2; definitive_overlapping_trig = i_trig; } return false; }); if(definitive_overlapping_trig==-1) { static Timer t("slow check"); RegionTimer reg(t); PrintMessage (5, "Warning in delaunay tree - didn't find overlapping circle, check all trigs again"); for(auto i_trig : trigs.Range()) { const auto trig = trigs[i_trig]; // if(trig[0]==-1) if(!trig[0].IsValid()) continue; double rad2 = trig.Radius2(); double d2 = Dist2 (trig.Center(), newp); // if (d2 < 0.999 * rad2) if (d2 < (1-1e-10)*rad2) { definitive_overlapping_trig = i_trig; break; } } } if(definitive_overlapping_trig==-1) { // GetMesh(pi_new)->Save("error.vol.gz"); throw Exception("point not in any circle "+ ToString(pi_new)); } Array trigs_to_visit; trigs_to_visit.Append(definitive_overlapping_trig); intersecting.Append(definitive_overlapping_trig); trigs[definitive_overlapping_trig].visited_pi = pi_new; while(trigs_to_visit.Size()) { int ti = trigs_to_visit.Last(); trigs_to_visit.DeleteLast(); auto & trig = trigs[ti]; trig.visited_pi = pi_new; for(auto ei : Range(3)) { auto nb = GetNeighbour(ti, ei); if(nb==-1) continue; const auto & trig_nb = trigs[nb]; if (trig_nb.visited_pi == pi_new) continue; trig_nb.visited_pi = pi_new; bool is_intersecting = Dist2(newp, trig_nb.Center()) < trig_nb.Radius2()*(1+1e-12); if(!is_intersecting) { const Point<2> p0 = points[PointIndex (trig[(ei+1)%3])]; const Point<2> p1 = points[PointIndex (trig[(ei+2)%3])]; const Point<2> p2 = points[PointIndex (trig[ei])]; auto v = p1-p0; Vec<2> n = {-v[1], v[0]}; n /= n.Length(); double dist = n * (newp-p1); double scal = n * (p2 - p1); if (scal > 0) dist *= -1; if (dist > -1e-10) is_intersecting = true; } if(is_intersecting) { trigs_to_visit.Append(nb); intersecting.Append(nb); } } } // find outer edges for (auto j : intersecting) { const DelaunayTrig & trig = trigs[j]; for (int k = 0; k < 3; k++) { PointIndex p1 = trig[k]; PointIndex p2 = trig[(k+1)%3]; PointIndices<2> edge{p1,p2}; edge.Sort(); bool found = false; for (int l = 0; l < edges.Size(); l++) if (edges[l] == edge) { edges.RemoveElement(l); found = true; break; } if (!found) edges.Append (edge); } } } void DelaunayMesh::CalcWeights( PointIndex pi_new, std::map & weights ) { double eps = tree->GetTolerance(); weights.clear(); double sum = 0.0; auto p = points[pi_new]; auto pi_last = *points.Range().end()-3; for(auto edge : edges) { auto v0 = points[edge[0]] - p; auto v1 = points[edge[1]] - p; v0.Normalize(); v1.Normalize(); double angle = acos(v0*v1); for(PointIndex pi : {edge[0], edge[1]}) { if(pi>=pi_last) continue; double weight = angle/(eps+Dist(p, points[pi])); sum += weight; weights[pi] += weight; } } double isum = 1.0/sum; for(auto & [pi, weight] : weights) weight *= isum; } void DelaunayMesh::AddPoint( PointIndex pi_new) { static Timer t("AddPoint"); RegionTimer reg(t); CalcIntersecting(pi_new); for (int j : intersecting) { UnsetNeighbours(j); trigs[j][0] = PointIndex::INVALID; trigs[j][1] = PointIndex::INVALID; trigs[j][2] = PointIndex::INVALID; } for (auto edge : edges) AppendTrig( edge[0], edge[1], pi_new ); for (int j : intersecting) tree->DeleteElement (j); } unique_ptr DelaunayMesh::GetMesh(PointIndex pi_new) { auto mesh = make_unique(); Mesh & m = *mesh; m.AddFaceDescriptor (FaceDescriptor (1, 1, 0, 0)); for(auto pi : points.Range()) m.AddPoint(P3(points[pi])); for (DelaunayTrig & trig : trigs) { // if (trig[0] < 0) continue; if (!trig[0].IsValid()) continue; Vec<3> n = Cross (P3(points[trig[1]])-P3(points[trig[0]]), P3(points[trig[2]])-P3(points[trig[0]])); if (n(2) < 0) Swap (trig[1], trig[2]); Element2d el(trig[0], trig[1], trig[2]); el.SetIndex (1); m.AddSurfaceElement (el); } m.Compress(); m.AddPoint(P3(points[pi_new])); return mesh; } ostream & operator<< (ostream & ost, DelaunayTrig trig) { ost << trig[0] << "-" << trig[1] << "-" << trig[2] << endl; return ost; } void Meshing2 :: BlockFillLocalH (Mesh & mesh, const MeshingParameters & mp) { static Timer timer("Meshing2::BlockFill"); static Timer timer1("Meshing2::BlockFill 1"); static Timer timer2("Meshing2::BlockFill 2"); static Timer timer3("Meshing2::BlockFill 3"); static Timer timer4("Meshing2::BlockFill 4"); RegionTimer reg (timer); timer1.Start(); double filldist = mp.filldist; PrintMessage (6, "blockfill local h"); NgArray > 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()); maxh = max (maxh, Dist (p1, p2)); bbox.Add (p1); bbox.Add (p2); } // Point<3> mpc = bbox.Center(); bbox.Increase (bbox.Diam()/2); Box<3> meshbox = bbox; timer1.Stop(); timer2.Start(); LocalH loch2 (bbox, 1, 2); if (mp.maxh < maxh) maxh = mp.maxh; bool changed; do { static Timer tcf("clear flags"); tcf.Start(); // mesh.LocalHFunction().ClearFlags(); mesh.LocalHFunction().ClearRootFlags(); tcf.Stop(); static Timer tcut("tcut"); tcut.Start(); 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); } tcut.Stop(); 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.2 * maxh) { mesh.LocalHFunction().SetH (npoints[i], maxh); changed = true; } } } while (changed); timer2.Stop(); timer3.Start(); if (debugparam.slowchecks) { (*testout) << "Blockfill with points: " << endl; *testout << "loch = " << mesh.LocalHFunction() << endl; *testout << "npoints = " << endl << npoints << endl; } int prims[] = { 211, 223, 227, 229, 233, 239, 241, 251, 257, 263 }; int prim; { int i = 0; if (npoints.Size()) while (npoints.Size() % prims[i] == 0) i++; prim = prims[i]; } for (int i = 0; i < npoints.Size(); i++) { size_t hi = (size_t(prim) * size_t(i)) % npoints.Size(); if (meshbox.IsIn (npoints[hi])) { PointIndex gpnum = mesh.AddPoint (npoints[hi]); adfront.AddPoint (npoints[hi], gpnum); if (debugparam.slowchecks) { (*testout) << npoints[hi] << endl; Point<2> p2d (npoints[hi](0), npoints[hi](1)); if (!adfront.Inside(p2d)) { cout << "add outside point" << endl; (*testout) << "outside" << endl; } } } } timer3.Stop(); timer4.Start(); // 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); // outer points : smooth mesh-grading npoints.SetSize(0); loch2.GetOuterPoints (npoints); /* for (int i = 1; i <= npoints.Size(); i++) { if (meshbox.IsIn (npoints.Get(i))) { PointIndex gpnum = mesh.AddPoint (npoints.Get(i)); adfront.AddPoint (npoints.Get(i), gpnum); } } */ for (const Point<3> p : npoints) if (meshbox.IsIn(p)) { PointIndex gpnum = mesh.AddPoint (p); adfront.AddPoint (p, gpnum); } timer4.Stop(); } void Meshing2 :: Delaunay (Mesh & mesh, int domainnr, const MeshingParameters & mp) { static Timer timer("Meshing2::Delaunay"); static Timer t1("Meshing2::Delaunay1"); static Timer t2("Meshing2::Delaunay2"); static Timer t3("Meshing2::Delaunay3"); static Timer timer_addpoints("add points"); RegionTimer reg (timer); PrintMessage (4, "2D Delaunay meshing"); auto first_point_blockfill = mesh.Points().Range().Next(); BlockFillLocalH (mesh, mp); auto last_point_blockfill = mesh.Points().Range().Next(); t1.Start(); // Bounding box for starting trig in delaunay Box<2> bbox (Box<2>::EMPTY_BOX); for (int i = 0; i < adfront.GetNFL(); i++) { const FrontLine & line = adfront.GetLine(i); bbox.Add (P2(Point<3> (adfront.GetPoint (line.L()[0])))); bbox.Add (P2(Point<3> (adfront.GetPoint (line.L()[1])))); } for (PointIndex pi : Range(first_point_blockfill, last_point_blockfill)) bbox.Add(P2(mesh[pi])); for (int i = 0; i < mesh.LockedPoints().Size(); i++) bbox.Add (P2(mesh.Point (mesh.LockedPoints()[i]))); t1.Stop(); t2.Start(); Array old_points; TBitArray add_point(mesh.Points().Size()+1); Array addpoints; add_point.Clear(); /* for (SegmentIndex si = 0; si < mesh.GetNSeg(); si++) { const auto & s = mesh[si]; if ( s.domin==domainnr || s.domout==domainnr ) { add_point.SetBit(s[0]); add_point.SetBit(s[1]); } } */ /* for (int i = 0; i < adfront.GetNFL(); i++) { const FrontLine & line = adfront.GetLine(i); for (int j = 0; j < 2; j++) add_point.SetBit (adfront.GetGlobalIndex (line.L()[j]))adfront.GetGlobalIndex (line.L()[j])); } */ for (const auto & line : adfront.GetLines()) for (int j = 0; j < 2; j++) { PointIndex pnum = adfront.GetGlobalIndex (line.L()[j]); if (!add_point.Test(pnum)) addpoints.Append(pnum); add_point.SetBit (pnum); } t2.Stop(); t3.Start(); Mesh tempmesh; tempmesh.AddFaceDescriptor (FaceDescriptor (1, 1, 0, 0)); tempmesh.AddFaceDescriptor (FaceDescriptor (2, 1, 0, 0)); tempmesh.AddFaceDescriptor (FaceDescriptor (3, 1, 0, 0)); Array compress; Array icompress(mesh.Points().Size()); Array, PointIndex> temp_points; for (PointIndex pi : addpoints) { icompress[pi] = tempmesh.AddPoint(mesh[pi]); compress.Append(pi); temp_points.Append(P2(mesh[pi])); } for (PointIndex pi : Range(first_point_blockfill, last_point_blockfill)) { icompress[pi] = tempmesh.AddPoint(mesh[pi]); compress.Append(pi); temp_points.Append(P2(mesh[pi])); } t3.Stop(); // DelaunayMesh adds surrounding trig (don't add the last 3 points to delaunay AGAIN! auto points_range = temp_points.Range(); DelaunayMesh dmesh(temp_points, bbox); timer_addpoints.Start(); // // reorder points // NgArray mixed(old_points.Size()); // int prims[] = { 11, 13, 17, 19, 23, 29, 31, 37 }; // int prim; // // { // int i = 0; // while (old_points.Size() % prims[i] == 0) i++; // prim = prims[i]; // } // // for (PointIndex pi : old_points) // mixed[pi] = PointIndex ( (prim * pi) % old_points.Size() + PointIndex::BASE ); for (auto pi : points_range) dmesh.AddPoint(pi); auto first_new_point = points_range.Next(); tempmesh.AddPoint(P3(temp_points[first_new_point])); tempmesh.AddPoint(P3(temp_points[first_new_point+1])); tempmesh.AddPoint(P3(temp_points[first_new_point+2])); timer_addpoints.Stop(); static Timer taddseg("addseg"); taddseg.Start(); /* for (auto seg : mesh.LineSegments()) { if ( seg.domin == domainnr || seg.domout == domainnr ) { if(seg.domin==domainnr) seg.domout = 0; if(seg.domout==domainnr) seg.domin = 0; seg[0] = icompress[seg[0]]; seg[1] = icompress[seg[1]]; tempmesh.AddSegment(seg); } } */ for (const auto & line : adfront.GetLines()) { Segment seg; for (int j = 0; j < 2; j++) seg[j] = icompress [adfront.GetGlobalIndex (line.L()[j])]; seg.domin = domainnr; seg.domout = 0; tempmesh.AddSegment(seg); } taddseg.Stop(); for (auto & trig : dmesh.GetElements()) { // if (trig[0] < 0) continue; if (!trig[0].IsValid()) continue; Element2d el(trig[0], trig[1], trig[2]); el.SetIndex (1); tempmesh.AddSurfaceElement (el); } bool conforming = false; while(!conforming) { conforming = true; TBitArray marked_points(tempmesh.Points().Size()+1); marked_points = false; // Check for trigs cutting a boundary edge (non-conforming mesh) auto point_to_trigs = tempmesh.CreatePoint2SurfaceElementTable( 0 ); for (auto & seg : tempmesh.LineSegments()) { int count_adjacent = 0;; PointIndex pi0 = seg[0]; PointIndex pi1 = seg[1]; if(marked_points.Test(pi0)) continue; if(marked_points.Test(pi1)) continue; for(auto sei : point_to_trigs[pi0]) for( auto i : Range(3)) if(tempmesh[sei][i] == pi1) count_adjacent++; if(count_adjacent==2) continue; PointIndex pi2; PointIndex pi3; ArrayMem cutting_trigs; for(auto sei : point_to_trigs[pi0]) { auto & el = tempmesh[sei]; pi2 = el[0] == pi0 ? el[1] : el[0]; pi3 = el[2] == pi0 ? el[1] : el[2]; double alpha, beta; auto itype = intersect( P2(tempmesh[pi0]), P2(tempmesh[pi1]), P2(tempmesh[pi2]), P2(tempmesh[pi3]), alpha, beta ); if(itype == X_INTERSECTION) { cutting_trigs.Append(sei); break; } } if(cutting_trigs.Size()==0) continue; for(auto sei : point_to_trigs[pi2]) { if(sei==cutting_trigs[0]) continue; for(auto i : IntRange(3)) if(tempmesh[sei][i]==pi3) cutting_trigs.Append(sei); } // Found two trigs cutting a boundary edge -> perform swap if(cutting_trigs.Size()==2) { conforming = false; if(marked_points.Test(pi2)) continue; if(marked_points.Test(pi3)) continue; auto & el0 = tempmesh[cutting_trigs[0]]; auto & el1 = tempmesh[cutting_trigs[1]]; pi1 = el1[0]-pi2+el1[1]-pi3+el1[2]; if(marked_points.Test(pi1)) continue; marked_points.SetBit(pi0); marked_points.SetBit(pi1); marked_points.SetBit(pi2); marked_points.SetBit(pi3); el0[0] = pi2; el0[1] = pi1; el0[2] = pi0; el1[0] = pi3; el1[1] = pi0; el1[2] = pi1; } } } auto point_to_trigs = tempmesh.CreatePoint2SurfaceElementTable( 0 ); // Mark edges and trigs as inside or outside, starting with boundary edges enum POSITION { UNKNOWN, BOUNDARY, INSIDE, OUTSIDE }; Array trig_pos(tempmesh.SurfaceElements().Size()); ngcore::ClosedHashTable, POSITION> edge_pos(3*tempmesh.SurfaceElements().Size()); trig_pos = UNKNOWN; for (auto & seg : tempmesh.LineSegments()) { ArrayMem els; PointIndices<2> edge{seg[0], seg[1]}; edge.Sort(); edge_pos[edge] = BOUNDARY; for(auto sei : point_to_trigs[seg[0]]) for( auto i : Range(3)) if(tempmesh[sei][i] == seg[1]) els.Append(sei); for(auto sei : els) { auto & el = tempmesh[sei]; PointIndex pi2 = el[0]-seg[0]+el[1]-seg[1]+el[2]; bool is_left = ::netgen::Area(P2(tempmesh[seg[0]]), P2(tempmesh[seg[1]]), P2(tempmesh[pi2]))>0.0; POSITION pos; if(is_left == (seg.domin==domainnr)) pos = INSIDE; else pos = OUTSIDE; PointIndices<2> e1{seg[0], pi2}; PointIndices<2> e2{seg[1], pi2}; e1.Sort(); e2.Sort(); if(!edge_pos.Used(e1)) edge_pos[e1] = pos; if(!edge_pos.Used(e2)) edge_pos[e2] = pos; trig_pos[sei] = pos; } } // Advance from boundary edges/trigs to all others bool have_unknown_trigs = true; while(have_unknown_trigs) { have_unknown_trigs = false; for (auto sei : Range(tempmesh.SurfaceElements())) { auto & el = tempmesh[sei]; if(trig_pos[sei] == UNKNOWN) { have_unknown_trigs = true; // any edge of unknown trig already marked? for(auto i : IntRange(3)) { PointIndices<2> edge{el[(i+1)%3], el[(i+2)%3]}; edge.Sort(); if(edge_pos.Used(edge) && edge_pos[edge]!=BOUNDARY) { trig_pos[sei] = edge_pos[edge]; break; } } } // if we could mark the trig -> also mark all edges if(trig_pos[sei] != UNKNOWN) for(auto i : IntRange(3)) { PointIndices<2> edge{el[(i+1)%3], el[(i+2)%3]}; edge.Sort(); if(!edge_pos.Used(edge) || edge_pos[edge]==BOUNDARY) edge_pos[edge] = trig_pos[sei]; } } } // add inside trigs to actual mesh for (auto sei : Range(tempmesh.SurfaceElements())) { if(trig_pos[sei] == INSIDE) { auto el = tempmesh[sei]; Vec<3> n = Cross (tempmesh[el[1]]-tempmesh[el[0]], tempmesh[el[2]]-tempmesh[el[0]]); if (n(2) < 0) Swap (el[1], el[2]); el[0] = compress[el[0]]; el[1] = compress[el[1]]; el[2] = compress[el[2]]; el.SetIndex(domainnr); mesh.AddSurfaceElement(el); } } // mesh.Compress(); // don't compress whole mesh after every sub-domain } } ================================================ FILE: libsrc/meshing/delaunay2d.hpp ================================================ #include "meshing.hpp" namespace netgen { static inline Point<2> P2( Point<3> p ) { return {p[0], p[1]}; } static inline Point<3> P3( Point<2> p ) { return {p[0], p[1], 0}; } class DelaunayTrig { PointIndex pnums[3]; Point<2> c; public: double r; double rad2; DelaunayTrig () = default; DelaunayTrig (PointIndex p1, PointIndex p2, PointIndex p3) { pnums[0] = p1; pnums[1] = p2; pnums[2] = p3; } PointIndex & operator[] (int j) { return pnums[j]; } const PointIndex & operator[] (int j) const { return pnums[j]; } void CalcCenter (FlatArray, PointIndex> points); Point<2> Center() const { return c; } double Radius2() const { return rad2; } Box<2> BoundingBox() const { return Box<2> (c-Vec<2>(r,r), c+Vec<2>(r,r)); } mutable PointIndex visited_pi = PointIndex::INVALID; // -1; }; class DelaunayMesh { ngcore::ClosedHashTable, IVec<2>> edge_to_trig; Array trigs; unique_ptr> tree; Array, PointIndex> & points; Array closeels; Array intersecting; Array> edges; int GetNeighbour( int eli, int edge ); void SetNeighbour( int eli, int edge ); void UnsetNeighbours( int eli ); void AppendTrig( PointIndex pi0, PointIndex pi1, PointIndex pi2 ); public: DelaunayMesh( Array, PointIndex> & points_, Box<2> box ); void CalcIntersecting( PointIndex pi_new ); void CalcWeights( PointIndex pi_new, std::map & weights ); void AddPoint( PointIndex pi_new ); Array & GetElements() { return trigs; } unique_ptr GetMesh(PointIndex pi_new); // for debugging purposes }; } // namespace netgen ================================================ FILE: libsrc/meshing/fieldlines.cpp ================================================ #include #include #include #include #include #include "fieldlines.hpp" namespace netgen { inline int GetVolElement(const Mesh& mesh, const Point<3>& p, double* lami) { if(mesh.GetDimension() == 3) { auto ei = mesh.GetElementOfPoint(p, lami, true); if(!ei.IsValid()) return -1; return ei; } else { auto ei = mesh.GetSurfaceElementOfPoint(p, lami, true); if(!ei.IsValid()) return -1; return ei; } } 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; NgArray size(2); size[0] = 0; size[1] = 1; a = new TABLE(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.; NgArray size(3); size[0] = 0; size[1] = 1; size[2] = 2; a = new TABLE(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.; NgArray size(4); size[0] = 0; size[1] = 1; size[2] = 2; size[3] = 3; a = new TABLE(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 Point<3> & 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(Point<3> & val, double & t, double & ah) { bool finished = false; if(stepcount <= steps && stepcount>0) { t = startt + c[stepcount-1]*h; val = startval; for(int i=0; iGet(stepcount,i+1) * K[i]; } if(stepcount == steps) { val = startval; for(int i=0; i valh2 = val; val = valh2 + 1./(pow(2.,order)-1.) * (valh2 - valh); auto 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; iGet(stepcount,i) * K[i]; } return finished; } bool RKStepper :: FeedNextF(const Vec<3> & f) { K[stepcount] = f; stepcount++; return true; } void FieldLineCalc :: GenerateFieldLines(Array> & potential_startpoints, const int numlines) { Array> line_points; Array line_values; Array drawelems; Array dirstart; pstart.SetSize0(); pend.SetSize0(); values.SetSize0(); double crit = 1.0; if(randomized) { double sum = 0; double lami[3]; Vec<3> v; for(int i=0; i= numlines) break; Calc(potential_startpoints[i],line_points,line_values,drawelems,dirstart); bool usable = false; for(int j=1; j 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; } critical_value = -1; randomized = false; } FieldLineCalc :: ~FieldLineCalc() {;} void FieldLineCalc :: Calc(const Point<3> & startpoint, Array> & points, Array & vals, Array & drawelems, Array & dirstart) { Vec<3> v = 0.0; double startlami[3] = {0.0, 0.0, 0.0}; points.SetSize(0); vals.SetSize(0); drawelems.SetSize(0); dirstart.SetSize(0); dirstart.Append(0); int startelnr = GetVolElement(mesh, startpoint,startlami); (*testout) << "p = " << startpoint << "; elnr = " << startelnr << endl; if (startelnr == -1) return; mesh.SetPointSearchStartElement(startelnr); Vec<3> startv; bool startdraw = func(startelnr, startlami, startv); double 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); double h = 0.001*rad/startval; // otherwise no nice lines; should be made accessible from outside v = startv; if(dir == -1) v *= -1.; int elnr = startelnr; double lami[3] = { startlami[0], startlami[1], 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; } double dummyt{0}; stepper.StartNextValCalc(points.Last(),dummyt,h,true); stepper.FeedNextF(v); bool drawelem = false; Point<3> newp; while(!stepper.GetNextData(newp,dummyt,h) && elnr != -1) { elnr = GetVolElement(mesh, newp, lami); if(elnr != -1) { mesh.SetPointSearchStartElement(elnr); drawelem = func(elnr, lami, v); if(dir == -1) v *= -1.; stepper.FeedNextF(v); } } if (elnr == -1) { //cout << "direction " < 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()); } } } ================================================ FILE: libsrc/meshing/fieldlines.hpp ================================================ #ifndef FIELDLINES_HPP_INCLUDED #define FIELDLINES_HPP_INCLUDED namespace netgen { class RKStepper { private: Array c,b; TABLE *a; int steps; int order; double tolerance; Array> K; int stepcount; double h; double startt; double startt_bak; Point<3> startval; Point<3> startval_bak; bool adaptive; int adrun; Point<3> valh; int notrestarted; public: DLL_HEADER ~RKStepper(); RKStepper(int type = 0); void SetTolerance(const double tol){tolerance = tol;} void StartNextValCalc(const Point<3> & astartval, const double astartt, const double ah, const bool aadaptive = false); bool GetNextData(Point<3> & val, double & t, double & ah); bool FeedNextF(const Vec<3> & f); }; class FieldLineCalc { private: const Mesh & mesh; typedef std::function &)> VectorFunction; const VectorFunction & func; RKStepper stepper; Array values; Array> pstart, pend; double maxlength; int maxpoints; int direction; Point3d pmin, pmax; double rad; double critical_value; bool randomized; double thickness; public: DLL_HEADER FieldLineCalc(const Mesh & amesh, const VectorFunction & afunc, 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); DLL_HEADER ~FieldLineCalc(); void SetCriticalValue(const double val) { critical_value = val; } void Randomized(void) { randomized = true; } void NotRandomized(void) { randomized = false; } DLL_HEADER void Calc(const Point<3> & startpoint, Array> & points, Array & vals, Array & drawelems, Array & dirstart); DLL_HEADER void GenerateFieldLines(Array> & potential_startpoints, const int numlines); const auto & GetPStart() const { return pstart; } const auto & GetPEnd() const { return pend; } const auto & GetValues() const { return values; } const auto GetThickness() const { return thickness; } }; } // namespace netgen #endif // VSFIELDLINES_HPP_INCLUDED ================================================ FILE: libsrc/meshing/findip.hpp ================================================ #ifndef NETGEN_FINDIP_HPP #define NETGEN_FINDIP_HPP // find inner point namespace netgen { inline void Minimize (const NgArray & a, const NgArray & 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 inline int FindInnerPoint (POINTArray & points, FACEArray & faces, Point3d & p) { static int timer = NgProfiler::CreateTimer ("FindInnerPoint"); NgProfiler::RegionTimer reg (timer); NgArray a; NgArray 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[faces[i][0]]; a[i] = Cross (points[faces[i][1]] - p1, points[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[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 : Range(3)) { double hi = Dist (points[faces[i][j%3]], points[faces[i][(j+1)%3]]); 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); } } // namespace netgen #endif // FILE_FINDINNERPOINT_HPP ================================================ FILE: libsrc/meshing/findip2.hpp ================================================ #ifndef NETGEN_FINDIP2_HPP #define NETGEN_FINDIP2_HPP // find inner point namespace netgen { template inline int FindInnerPoint2 (POINTArray & points, FACEArray & faces, Point3d & p) { static int timer = NgProfiler::CreateTimer ("FindInnerPoint2"); NgProfiler::RegionTimer reg (timer); NgArray a; NgArray 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); } } // namespace netgen #endif // NETGEN_FINDIP2_HPP ================================================ FILE: libsrc/meshing/geomsearch.cpp ================================================ #include #include "geomsearch.hpp" #include "adfront3.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 *pointsi, NgArray *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); int nfaces = faces->Size(); size.i1 = min(size.i1, nfaces); size.i2 = min(size.i2, nfaces); size.i3 = min(size.i3, nfaces); // 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 NgArray (); } } } } 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(NgArray & locfaces, NgArray & 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); PointIndex 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; [[maybe_unused]] int cnt1 = 0; // test, how efficient hashtable is [[maybe_unused]] int cnt2 = 0; [[maybe_unused]] 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 NgArray & 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; } */ } } ================================================ FILE: libsrc/meshing/geomsearch.hpp ================================================ #ifndef NETGEN_GEOMSEARCH_HPP #define NETGEN_GEOMSEARCH_HPP /**************************************************************************/ /* File: geomsearch.hh */ /* Author: Johannes Gerstmayr */ /* Date: 19. Nov. 97 */ /**************************************************************************/ #include "meshtype.hpp" namespace netgen { 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 *pointsi, NgArray *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(NgArray & locfaces, NgArray & findex, INDEX fstind, const Point3d& p0, double xh); private: NgArray *faces; // Pointers to Arrays in Adfront Array *points; NgArray *> 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; }; } // namespace netgen #endif // NETGEN_GEOMSEARCH_HPP ================================================ FILE: libsrc/meshing/global.cpp ================================================ #include #include "global.hpp" #include #include "msghandler.hpp" #include "meshtype.hpp" namespace netgen { class NetgenGeometry; class TraceGlobal { string name; public: TraceGlobal(string _name) : name(_name) { cout << "init global " << name << endl; } ~TraceGlobal() { cout << "exit global " << name << endl; } }; // stringstream emptystr; // ostream * testout = &emptystr; // testout -> clear(ios::failbit); // ostream * testout = &cout; // NetgenOutStream * testout = new NetgenOutStream; const string netgen_version = NETGEN_VERSION; ostream * mycout = &cout; ostream * myerr = &cerr; // some functions (visualization) still need a global mesh // TraceGlobal glob1("global1"); DLL_HEADER shared_ptr mesh; DLL_HEADER shared_ptr ng_geometry; // TraceGlobal glob2("global2"); // global communicator for netgen // DLL_HEADER NgMPI_Comm ng_comm; weak_ptr global_mesh; void(*on_set_global_mesh)(shared_ptr) = nullptr; void SetGlobalMesh (shared_ptr m) { if(GetGlobalMesh() == m) return; PrintMessage(5, "set global mesh"); global_mesh = m; if (on_set_global_mesh) on_set_global_mesh(m); } shared_ptr GetGlobalMesh () { try { return global_mesh.lock(); } catch (const bad_weak_ptr & e) { return nullptr; } } // true if netgen was started using the netgen executable // false if netgen.gui was imported from python DLL_HEADER bool netgen_executable_started = false; // Flags parameters; int silentflag = 0; int testmode = 0; string ngdir = "."; void Ng_PrintDest(const char * s) { if (id == 0) (*mycout) << s << flush; } DLL_HEADER void MyError(const char * ch) { cout << ch; (*testout) << "Error !!! " << ch << endl << flush; } static double starttimea; void ResetTime () { starttimea = WallTime(); } double GetTime () { return WallTime() - starttimea; } mutex tcl_todo_mutex; int h_argc = 0; char ** h_argv = NULL; DebugParameters debugparam; bool verbose = 0; size_t timestamp = 0; /* int GetTimeStamp() { return timestamp; } int NextTimeStamp() { timestamp++; return timestamp; } */ } ================================================ FILE: libsrc/meshing/global.hpp ================================================ #ifndef NETGEN_GLOBAL_HPP #define NETGEN_GLOBAL_HPP /**************************************************************************/ /* File: global.hh */ /* Author: Joachim Schoeberl */ /* Date: 01. Okt. 95 */ /**************************************************************************/ /* global functions and variables */ #include namespace netgen { using namespace ngcore; /// DLL_HEADER extern double GetTime (); DLL_HEADER extern void ResetTime (); /// DLL_HEADER extern int testmode; /// calling parameters // extern Flags parameters; // extern DLL_HEADER MeshingParameters mparam; DLL_HEADER extern mutex tcl_todo_mutex; class DebugParameters; class Mesh; DLL_HEADER extern string ngdir; DLL_HEADER extern DebugParameters debugparam; DLL_HEADER extern bool verbose; DLL_HEADER extern int h_argc; DLL_HEADER extern char ** h_argv; DLL_HEADER extern void(*on_set_global_mesh)(shared_ptr); DLL_HEADER extern weak_ptr global_mesh; DLL_HEADER void SetGlobalMesh (shared_ptr m); DLL_HEADER shared_ptr GetGlobalMesh (); // global communicator for netgen (dummy if no MPI) // extern DLL_HEADER NgMPI_Comm ng_comm; } // namespace netgen #endif // NETGEN_GLOBAL_HPP ================================================ FILE: libsrc/meshing/hpref_hex.hpp ================================================ // 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 }; // HP_HEX ... no refinement int refhex7_splitedges[][3] = { { 0, 0, 0 } }; HPREF_ELEMENT_TYPE refhex7_newelstypes[] = { HP_HEX7, HP_NONE, }; int refhex7_newels[][8] = { { 1, 2, 3, 4, 5, 6, 7 } }; HPRef_Struct refhex7 = { HP_HEX7, refhex7_splitedges, 0, 0, refhex7_newelstypes, refhex7_newels }; // HP_HEX_1FA ... face (1 - 4 - 3 -2) singular int refhex7_1fa_splitedges[][3] = { { 1, 5, 8 }, { 2, 6, 9 }, { 3, 7, 10 }, { 4, 7, 11 }, { 0, 0, 0 } }; HPREF_ELEMENT_TYPE refhex7_1fa_newelstypes[] = { HP_HEX_1F_0E_0V, HP_HEX7, HP_NONE, }; int refhex7_1fa_newels[][8] = { { 1, 2, 3, 4, 8, 9, 10, 11 }, { 8, 9, 10, 11, 5, 6, 7 } }; HPRef_Struct refhex7_1fa = { HP_HEX7, refhex7_1fa_splitedges, 0, 0, refhex7_1fa_newelstypes, refhex7_1fa_newels }; // HP_HEX_1FB ... face (5,6,7) singular int refhex7_1fb_splitedges[][3] = { { 5, 1, 8 }, { 6, 2, 9 }, { 7, 3, 10 }, { 7, 4, 11 }, { 0, 0, 0 } }; HPREF_ELEMENT_TYPE refhex7_1fb_newelstypes[] = { HP_HEX, HP_HEX7_1FB, HP_NONE, }; int refhex7_1fb_newels[][8] = { { 1, 2, 3, 4, 8, 9, 10, 11 }, { 8, 9, 10, 11, 5, 6, 7 } }; HPRef_Struct refhex7_1fb = { HP_HEX7, refhex7_1fb_splitedges, 0, 0, refhex7_1fb_newelstypes, refhex7_1fb_newels }; ================================================ FILE: libsrc/meshing/hpref_prism.hpp ================================================ // 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, edge is 1-4 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 }; */ ================================================ FILE: libsrc/meshing/hpref_pyramid.hpp ================================================ // 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 // HP_PYRAMID_1FB_0E_0V int refpyramid_1fb_0e_0v_splitedges[][3] = { { 1, 4, 6 }, { 2, 3, 7 }, { 5, 3, 8 }, { 5, 4, 9 }, { 0, 0, 0 }, }; HPREF_ELEMENT_TYPE refpyramid_1fb_0e_0v_newelstypes[] = { HP_HEX7_1FB, HP_PRISM, HP_NONE, }; int refpyramid_1fb_0e_0v_newels[][8] = { { 6, 7, 8, 9, 1, 2, 5 }, { 3, 7, 8, 4, 6, 9 }, }; HPRef_Struct refpyramid_1fb_0e_0v = { HP_PYRAMID, refpyramid_1fb_0e_0v_splitedges, 0, 0, refpyramid_1fb_0e_0v_newelstypes, refpyramid_1fb_0e_0v_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 }; ================================================ FILE: libsrc/meshing/hpref_quad.hpp ================================================ // 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 }; ================================================ FILE: libsrc/meshing/hpref_segm.hpp ================================================ // 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 }; ================================================ FILE: libsrc/meshing/hpref_tet.hpp ================================================ enum VNUM { V1, V2, V3, V4, E12, E13, E14, E21, E23, E24, E31, E32, E34, E41, E42, E43, F123, F124, F134, F213, F214, F234, F312, F314, F324, F412, F413, F423 }; class El { public: HPREF_ELEMENT_TYPE type; std::vector vertices; El (HPREF_ELEMENT_TYPE atype, std::vector avertices) : type(atype), vertices(avertices) { } }; extern std::map & GetHPRegistry(); template class HPRefStruct : public HPRef_Struct { typedef int int3[3]; typedef int int4[4]; typedef int int8[8]; std::vector> refedges; std::vector> reffaces; std::vector neweltypes_vec; std::vector> newelverts; public: HPRefStruct(HPREF_ELEMENT_TYPE type, std::vector list) { GetHPRegistry()[type] = this; geom = GEOM; std::map mapnums; int ii = 0; for (auto v : { V1, V2, V3, V4}) mapnums[v] = ++ii; for (auto el : list) for (auto v : el.vertices) if (mapnums.count(v)==0) mapnums[v] = ++ii; int elist[][3] = { { 1, 2, E12 }, { 1, 3, E13 }, { 1, 4, E14 }, { 2, 1, E21 }, { 2, 3, E23 }, { 2, 4, E24 }, { 3, 1, E31 }, { 3, 2, E32 }, { 3, 4, E34 }, { 4, 1, E41 }, { 4, 2, E42 }, { 4, 3, E43 } }; int flist[][4] = { { 1, 2, 3, F123 }, { 1, 2, 4, F124 }, { 1, 3, 4, F134 }, { 2, 1, 3, F213 }, { 2, 1, 4, F214 }, { 2, 3, 4, F234 }, { 3, 1, 2, F312 }, { 3, 1, 4, F314 }, { 3, 2, 4, F324 }, { 4, 1, 2, F412 }, { 4, 1, 3, F413 }, { 4, 2, 3, F423 } }; /* // too advanced ... for (auto [i1,i2,inew] : elist) if (mapnums.count(VNUM(inew))) refedges.push_back( { i1, i2, mapnums[VNUM(inew)] }); */ for (int i = 0; i < size(elist); i++) { int i1 = elist[i][0]; int i2 = elist[i][1]; int inew = elist[i][2]; if (mapnums.count(VNUM(inew))) refedges.push_back( { i1, i2, mapnums[VNUM(inew)] }); } refedges.push_back( { 0, 0, 0 } ); splitedges = (int3*) &refedges[0][0]; /* // too advanced ... for (auto [i1,i2,i3,inew] : flist) if (mapnums.count(VNUM(inew))) reffaces.push_back( { i1, i2, i3, mapnums[VNUM(inew)] }); */ for (int i = 0; i < size(flist); i++) { int i1 = flist[i][0]; int i2 = flist[i][1]; int i3 = flist[i][2]; int inew = flist[i][3]; if (mapnums.count(VNUM(inew))) reffaces.push_back( { i1, i2, i3, mapnums[VNUM(inew)] }); } reffaces.push_back( { 0, 0, 0 } ); splitfaces = (int4*) &reffaces[0][0]; splitelements = nullptr; for (auto el : list) { neweltypes_vec.push_back (el.type); std::array verts; for (int j = 0; j < std::min(verts.size(), el.vertices.size()); j++) verts[j] = mapnums[VNUM(el.vertices[j])]; newelverts.push_back(verts); } neweltypes_vec.push_back (HP_NONE); neweltypes = &neweltypes_vec[0]; newels = (int8*) &newelverts[0][0]; /* int ind = 0; cout << "rule, split edges:" << endl; while (splitedges[ind][0]) { cout << splitedges[ind][0] << "-" << splitedges[ind][1] << ": " << splitedges[ind][2] << endl; ind++; } ind = 0; cout << "rule, split faces:" << endl; while (splitfaces[ind][0]) { cout << splitfaces[ind][0] << "-" << splitfaces[ind][1] << "-" << splitfaces[ind][2] << ": " << splitfaces[ind][3] << endl; ind++; } ind = 0; cout << "rule, new els:" << endl; while (neweltypes[ind] != HP_NONE) { cout << "new type " << neweltypes[ind] << ", verts: "; for (int j = 0; j < 8; j++) cout << newels[ind][j] << " "; ind++; } */ } }; // HP_NONETET int refnonetet_splitedges[][3] = { { 0, 0, 0 } }; HPREF_ELEMENT_TYPE refnonetet_newelstypes[] = { HP_TET, HP_NONE, }; int refnonetet_newels[][8] = { { 1, 1, 1, 1 }, }; HPRef_Struct refnonetet = { HP_TET, refnonetet_splitedges, 0, 0, refnonetet_newelstypes, refnonetet_newels }; // HP_TET int reftet_splitedges[][3] = { { 0, 0, 0 } }; HPREF_ELEMENT_TYPE reftet_newelstypes[] = { HP_TET, HP_NONE, }; int reftet_newels[][8] = { { 1, 2, 3, 4 }, }; HPRef_Struct reftet = { HP_TET, reftet_splitedges, 0, 0, reftet_newelstypes, reftet_newels }; /* *********** Tet - Refinement - 0 edges *************** */ // HP_TET_0E_1V int reftet_0e_1v_splitedges[][3] = { { 1, 2, 5 }, { 1, 3, 6 }, { 1, 4, 7 }, { 0, 0, 0 } }; HPREF_ELEMENT_TYPE reftet_0e_1v_newelstypes[] = { HP_TET_0E_1V, HP_PRISM, HP_NONE, }; int reftet_0e_1v_newels[][8] = { { 1, 5, 6, 7 }, { 5, 6, 7, 2, 3, 4 } }; HPRef_Struct reftet_0e_1v = { HP_TET, reftet_0e_1v_splitedges, 0, 0, reftet_0e_1v_newelstypes, reftet_0e_1v_newels }; /* // new syntax ??? HPRef_Struct2 str = { HP_TET_0E_1V, HP_TET, El(HP_TET_0E_1V, { V1, V12, V13, V14 }) }; */ // 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 }; // HP_TET_3ED_3V, int reftet_3ed_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_3ed_3v_splitfaces[][4] = { { 1, 2, 3, 14 }, { 2, 3, 1, 15 }, { 3, 1, 2, 16 }, { 0, 0, 0, 0 } }; int reftet_3ed_3v_splitelements[][5] = { { 0 }, }; HPREF_ELEMENT_TYPE reftet_3ed_3v_newelstypes[] = { HP_TET, HP_PRISM, HP_PRISM_SINGEDGE, HP_PRISM_SINGEDGE, HP_PRISM_SINGEDGE, HP_TET_1E_1VA, HP_TET_1E_1VA, HP_TET_1E_1VA, HP_TET_1E_1VA, HP_TET_1E_1VA, HP_TET_1E_1VA, HP_NONE, }; int reftet_3ed_3v_newels[][8] = { { 7, 10, 13, 4 }, { 14, 15, 16, 7, 10, 13 }, { 5, 14, 7, 8, 15, 10 }, { 9, 15, 10, 12, 16, 13 }, { 11, 16, 13, 6, 14, 7 }, { 1, 5, 14, 7 }, { 1, 6, 7, 14 }, { 2, 8, 10, 15 }, { 2, 9, 15, 10 }, { 3, 12, 13, 16 }, { 3, 11, 16, 13 } }; HPRef_Struct reftet_3ed_3v = { HP_TET, reftet_3ed_3v_splitedges, reftet_3ed_3v_splitfaces, reftet_3ed_3v_splitelements, reftet_3ed_3v_newelstypes, reftet_3ed_3v_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_HEX7_1FA, HP_TET_1F_0E_1VA, HP_TET, HP_NONE, }; int reftet_1f_0e_1va_newels[][8] = { // { 3, 6, 7, 4, 8, 5, 5, 9 }, { 4, 3, 6, 7, 9, 8, 5 }, { 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 }; */ HPRefStruct reftet_1f_0e_1va { HP_TET_1F_0E_1VA, { El(HP_HEX7_1FA, { V4, V3, E23, E24, E41, E31, E21 }), El(HP_TET_1F_0E_1VA, { E21, V2, E23, E24 }), El(HP_TET, { E21, E41, E31, V1 }) } }; // 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_0E_2V ... face 234, sing verts v2,v3 int reftet_1f_0e_2v_splitedges[][3] = { { 2, 1, 5 }, { 2, 3, 6 }, { 2, 4, 7 }, { 3, 1, 8 }, { 3, 2, 9 }, { 3, 4, 10 }, { 4, 1, 11 }, { 0, 0, 0 } }; HPREF_ELEMENT_TYPE reftet_1f_0e_2v_newelstypes[] = { HP_TET_0E_1V, HP_PRISM_1FA_0E_0V, HP_PRISM_1FB_0E_0V, HP_TET_1F_0E_1VA, HP_TET_1F_0E_1VA, HP_NONE, }; int reftet_1f_0e_2v_newels[][8] = { { 1, 5, 8, 11 }, { 4, 10, 7, 11, 8, 5 }, { 9, 10, 8, 6, 7, 5 }, { 5, 2, 6, 7 }, { 8, 3, 10, 9 } }; HPRef_Struct reftet_1f_0e_2v = { HP_TET, reftet_1f_0e_2v_splitedges, 0, 0, reftet_1f_0e_2v_newelstypes, reftet_1f_0e_2v_newels }; HPRefStruct reftet_1f_0e_3v { HP_TET_1F_0E_3V, { El(HP_TET, { V1, E21, E31, E41 }), El(HP_PRISM_1FA_0E_0V, { F234, F423, F324, E21, E41, E31 }), El(HP_PRISM_1FB_1EA_0V, { E32, F324, E31, E23, F234, E21 }), El(HP_PRISM_1FB_1EA_0V, { E43, F423, E41, E34, F324, E31 }), El(HP_PRISM_1FB_1EA_0V, { E24, F234, E21, E42, F423, E41 }), El(HP_TET_1F_0E_0V, { E21, E24, E23, F234 }), El(HP_TET_1F_0E_1VA, { E21, V2, E23, E24 }), El(HP_TET_1F_0E_0V, { E31, E32, E34, F324 }), El(HP_TET_1F_0E_1VA, { E31, V3, E34, E32 }), El(HP_TET_1F_0E_0V, { E41, E43, E42, F423 }), El(HP_TET_1F_0E_1VA, { E41, V4, E42, E43 }), } }; // 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 }; // HP_TET_1F_1E_1VA // 1 sing edge in face e23, sing vert 2 int reftet_1f_1e_1va_splitedges[][3] = { { 2, 1, 5 }, { 2, 3, 10 }, { 2, 4, 6 }, { 3, 1, 7 }, { 3, 4, 8 }, { 4, 1, 9 }, { 0, 0, 0 } }; HPREF_ELEMENT_TYPE reftet_1f_1e_1va_newelstypes[] = { HP_PRISM_1FB_1EA_0V, HP_PRISM_1FA_0E_0V, HP_TET, HP_TET_1F_1E_1VA, HP_NONE, }; int reftet_1f_1e_1va_newels[][8] = { { 3, 8, 7, 10, 6, 5 }, { 6, 4, 8, 5, 9, 7 }, { 5, 9, 7, 1}, { 5, 2, 10, 6 } }; HPRef_Struct reftet_1f_1e_1va = { HP_TET, reftet_1f_1e_1va_splitedges, 0, 0, reftet_1f_1e_1va_newelstypes, reftet_1f_1e_1va_newels }; // HP_TET_1F_1E_1VB // 1 sing edge in face e24, sing vert 2 int reftet_1f_1e_1vb_splitedges[][3] = { { 2, 1, 5 }, { 2, 3, 6 }, { 2, 4, 7 }, { 3, 1, 8 }, { 4, 1, 9 }, { 4, 3, 10 }, { 0, 0, 0 } }; HPREF_ELEMENT_TYPE reftet_1f_1e_1vb_newelstypes[] = { HP_PRISM_1FB_1EA_0V, HP_PRISM_1FA_0E_0V, HP_TET, HP_TET_1F_1E_1VB, HP_NONE, }; int reftet_1f_1e_1vb_newels[][8] = { { 4, 9, 10, 7, 5, 6 }, { 3, 6, 10, 8, 5, 9 }, { 5, 9, 8, 1}, { 5, 2, 6, 7 } }; HPRef_Struct reftet_1f_1e_1vb = { HP_TET, reftet_1f_1e_1vb_splitedges, 0, 0, reftet_1f_1e_1vb_newelstypes, reftet_1f_1e_1vb_newels }; // HP_TET_1F_1E_2VA // 1 sing edge not in face (e12), sing v2,v3 int reftet_1f_1e_2va_splitedges[][3] = { { 1, 3, 5 }, { 1, 4, 6 }, { 2, 1, 7 }, { 2, 3, 8 }, { 2, 4, 9 }, { 3, 1, 10 }, { 3, 2, 11 }, { 3, 4, 12 }, { 4, 1, 13 }, { 0, 0, 0 } }; int reftet_1f_1e_2va_splitfaces[][4] = { { 2, 1, 3, 14 }, { 2, 1, 4, 15 }, { 0, 0, 0, 0 } }; HPREF_ELEMENT_TYPE reftet_1f_1e_2va_newelstypes[] = { HP_PRISM, HP_PRISM_SINGEDGE, HP_PRISM_1FB_0E_0V, HP_TET_1F_0E_1VA, HP_TET_1F_0E_1VA, HP_TET_1E_1VA, HP_TET_1E_1VA, HP_HEX7_1FB, HP_NONE, }; int reftet_1f_1e_2va_newels[][8] = { { 5, 14, 10, 6, 15, 13 }, { 1, 5, 6, 7, 14, 15 }, { 8, 14, 9, 11, 10, 12 }, { 10, 3, 12, 11 }, { 14, 2, 8, 9 }, { 2, 7, 15, 14 }, { 2, 9, 14, 15 }, // { 13, 10, 14, 15, 4, 12, 9 } { 10, 13, 15, 14, 12, 4, 9 } }; HPRef_Struct reftet_1f_1e_2va = { HP_TET, reftet_1f_1e_2va_splitedges, reftet_1f_1e_2va_splitfaces, 0, reftet_1f_1e_2va_newelstypes, reftet_1f_1e_2va_newels }; // HP_TET_1F_1E_2VB // 1 sing edge not in face (e12), sing v2,v4 int reftet_1f_1e_2vb_splitedges[][3] = { { 1, 3, 5 }, { 1, 4, 6 }, { 2, 1, 7 }, { 2, 3, 8 }, { 2, 4, 9 }, { 3, 1, 10 }, { 4, 1, 11 }, { 4, 2, 12 }, { 4, 3, 13 }, { 0, 0, 0 } }; int reftet_1f_1e_2vb_splitfaces[][4] = { { 2, 1, 3, 14 }, { 2, 1, 4, 15 }, { 0, 0, 0, 0 } }; HPREF_ELEMENT_TYPE reftet_1f_1e_2vb_newelstypes[] = { HP_PRISM, HP_PRISM_SINGEDGE, HP_PRISM_1FB_0E_0V, HP_TET_1F_0E_1VA, HP_TET_1F_0E_1VA, HP_TET_1E_1VA, HP_TET_1E_1VA, HP_HEX7_1FB, HP_NONE, }; int reftet_1f_1e_2vb_newels[][8] = { { 5, 14, 10, 6, 15, 11 }, { 1, 5, 6, 7, 14, 15 }, { 8, 15, 9, 13, 11, 12 }, { 11, 4, 12, 13 }, { 15, 2, 8, 9 }, { 2, 7, 15, 14 }, { 2, 8, 14, 15 }, { 10, 11, 15, 14, 3, 13, 8 } }; HPRef_Struct reftet_1f_1e_2vb = { HP_TET, reftet_1f_1e_2vb_splitedges, reftet_1f_1e_2vb_splitfaces, 0, reftet_1f_1e_2vb_newelstypes, reftet_1f_1e_2vb_newels }; // HP_TET_1F_1EA_3V HPRefStruct reftet_1f_1ea_3v { HP_TET_1F_1EA_3V, { El(HP_PRISM, { E14, E41, F214, E13, E31, F213 }), El(HP_PRISM_SINGEDGE, { V1, E13, E14, E21, F213, F214 }), El(HP_HEX7_1FB, { E31, E41, F214, F213, F324, F423, F234 }), El(HP_PRISM_1FB_0E_0V, { F234, E23, F213, F324, E32, E31 }), El(HP_PRISM_1FB_0E_0V, { F423, E42, E41, F234, E24, F214 }), El(HP_PRISM_1FB_0E_0V, { F324, E34, E31, F423, E43, E41 }), El(HP_TET_1F_0E_0V, { E31, E32, E34, F324 }), El(HP_TET_1F_0E_1VA, { E31, V3, E34, E32 }), El(HP_TET_1F_0E_0V, { E41, E43, E42, F423 }), El(HP_TET_1F_0E_1VA, { E41, V4, E42, E43 }), El(HP_PYRAMID_1FB_0E_0V, { E24, E23, F213, F214, F234 }), // needs check El(HP_PYRAMID_1FB_0E_1VA, { E23, E24, F214, F213, V2 }), El(HP_TET_1E_1VA, { V2, E21, F214, F213 }), } }; // HP_TET_1F_1E_3V e4 (E23), V2, V3, V4 HPRefStruct reftet_1f_1e_3v { HP_TET_1F_1E_3V, { El(HP_TET, { V1, E21, E31, E41 }), El(HP_HEX7_1FA, { E34, E24, E42, E43, E31, E21, E41 }), El(HP_PRISM_1FB_1EA_0V, { E32, E34, E31, E23, E24, E21 }), El(HP_TET_1F_0E_1VA, { E41, V4, E42, E43 }), El(HP_TET_1F_1E_1VB, { E21, V2, E23, E24 }), El(HP_TET_1F_1E_1VA, { E31, V3, E34, E32 }), } }; HPRefStruct reftet_1f_2eoo_3v { HP_TET_1F_2Eoo_3V, { El(HP_TET, { E14, E41, F214, F314 }), El(HP_PRISM_1FA_0E_0V, { V4, E34, E24, E41, F314, F214 }), El(HP_PRISM, { F123, F213, F312, E14, F214, F314 }), El(HP_PRISM_SINGEDGE, { E12, F123, E14, E21, F213, F214 }), El(HP_PRISM_SINGEDGE, { E13, E14, F123, E31, F314, F312 }), El(HP_HEX_1F_0E_0V, { E32, E23, E24, E34, F312, F213, F214, F314 }), El(HP_TET_1E_1VA, { V1, E12, F123, E14 }), El(HP_TET_1E_1VA, { V1, E13, E14, F123 }), El(HP_PYRAMID_1FB_0E_1VA, { E34, E32, F312, F314, V3 }), El(HP_PYRAMID_1FB_0E_1VA, { E23, E24, F214, F213, V2 }), El(HP_TET_1E_1VA, { V2, E21, F214, F213 }), El(HP_TET_1E_1VA, { V3, E31, F312, F314 }), } }; // HP_TET_1F_2E_0VA singular edge in face 234 is 34, and edge not in face is 14 int reftet_1f_2e_0va_splitedges[][3] = { { 1, 2, 5 }, { 1, 3, 6 }, { 2, 1, 7 }, { 3, 1, 8 }, { 3, 2, 9 }, { 4, 1, 10 }, { 4, 2, 11 }, { 4, 3, 12 }, { 0, 0, 0 } }; int reftet_1f_2e_0va_splitfaces[][4] = { { 4, 1, 2, 13 }, { 4, 1, 3, 14 }, { 0, 0, 0, 0 } }; HPREF_ELEMENT_TYPE reftet_1f_2e_0va_newelstypes[] = { HP_PRISM, HP_PRISM_SINGEDGE, HP_HEX7_1FB, HP_PRISM_1FB_1EA_0V, HP_TET_1F_1E_1VA, HP_TET_1E_1VA, HP_TET_1E_1VA, HP_NONE, }; int reftet_1f_2e_0va_newels[][8] = { { 6, 8, 14, 5, 7, 13 }, { 1, 5, 6, 10, 13, 14 }, { 7, 8, 14, 13, 2, 9, 11 }, { 3, 8, 9, 12, 14, 11 }, { 14, 4, 11, 12 }, { 4, 11, 13, 14 }, { 4, 10, 14, 13 } }; HPRef_Struct reftet_1f_2e_0va = { HP_TET, reftet_1f_2e_0va_splitedges, reftet_1f_2e_0va_splitfaces, 0, reftet_1f_2e_0va_newelstypes, reftet_1f_2e_0va_newels }; // HP_TET_1F_2E_0VB singular edge in face 234 is 34, and edge not in face is 13 int reftet_1f_2e_0vb_splitedges[][3] = { { 1, 2, 5 }, { 1, 4, 6 }, { 2, 1, 7 }, { 3, 1, 8 }, { 3, 2, 9 }, { 3, 4, 10 }, { 4, 1, 11 }, { 4, 2, 12 }, { 0, 0, 0 } }; int reftet_1f_2e_0vb_splitfaces[][4] = { { 3, 1, 2, 13 }, { 3, 1, 4, 14 }, { 0, 0, 0, 0 } }; HPREF_ELEMENT_TYPE reftet_1f_2e_0vb_newelstypes[] = { HP_PRISM, HP_PRISM_SINGEDGE, HP_HEX7_1FB, HP_PRISM_1FB_1EA_0V, HP_TET_1F_1E_1VA, HP_TET_1E_1VA, HP_TET_1E_1VA, HP_NONE, }; int reftet_1f_2e_0vb_newels[][8] = { { 6, 14, 11, 5, 13, 7 }, { 1, 6, 5, 8, 14, 13 }, { 11, 7, 13, 14, 12, 2, 9 }, { 4, 12, 11, 10, 9, 14 }, { 14, 3, 10, 9 }, { 3, 8, 13, 14 }, { 3, 9, 14, 13 } }; HPRef_Struct reftet_1f_2e_0vb = { HP_TET, reftet_1f_2e_0vb_splitedges, reftet_1f_2e_0vb_splitfaces, 0, reftet_1f_2e_0vb_newelstypes, reftet_1f_2e_0vb_newels }; // HP_TET_1F_2E_1V e4,e5 (E23,E24), V2 HPRefStruct reftet_1f_2e_1v { HP_TET_1F_2E_1V, { El(HP_TET, { V1, E21, E31, E41 }), El(HP_PRISM_1FA_0E_0V, { F234, E43, E34, E21, E41, E31 }), El(HP_PRISM_1FB_1EA_0V, { V3, E34, E31, E23, F234, E21 }), El(HP_PRISM_1FB_1EA_0V, { E24, F234, E21, V4, E43, E41 }), El(HP_TET_1F_1E_1VA, { E21, V2, E23, F234 }), El(HP_TET_1F_1E_1VB, { E21, V2, F234, E24 }), } }; // HP_TET_1F_2E_3V e4,e5 (E23,E24), V2, V3, V4 HPRefStruct reftet_1f_2e_3v { HP_TET_1F_2E_3V, { El(HP_TET, { V1, E21, E31, E41 }), El(HP_PRISM_1FA_0E_0V, { F234, E43, E34, E21, E41, E31 }), El(HP_PRISM_1FB_1EA_0V, { E32, E34, E31, E23, F234, E21 }), El(HP_PRISM_1FB_1EA_0V, { E24, F234, E21, E42, E43, E41 }), El(HP_TET_1F_1E_1VA, { E21, V2, E23, F234 }), El(HP_TET_1F_1E_1VB, { E21, V2, F234, E24 }), El(HP_TET_1F_1E_1VA, { E31, V3, E34, E32 }), El(HP_TET_1F_1E_1VB, { E41, V4, E42, E43 }), } }; /* ************************ 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 }; // HP_TET_2F_0E_1V int reftet_2f_0e_1v_splitedges[][3] = { { 1, 2, 5 }, { 2, 1, 6 }, { 3, 1, 7 }, { 3, 2, 8 }, { 4, 1, 9 }, { 4, 2, 10 }, { 4, 3, 13 }, { 0, 0, 0 } }; int reftet_2f_0e_1v_splitfaces[][4] = { { 3, 1, 2, 11 }, { 4, 1, 2, 12 }, { 0, 0, 0, 0 } }; HPREF_ELEMENT_TYPE reftet_2f_0e_1v_newelstypes[] = { HP_PRISM_1FA_0E_0V, HP_PRISM_1FA_0E_0V, HP_PRISM_1FB_1EA_0V, HP_PRISM_1FB_1EA_0V, HP_TET, HP_TET_1F_1E_1VB, HP_TET_1F_1E_1VA, HP_NONE }; int reftet_2f_0e_1v_newels[][8] = { { 2, 10, 8, 6, 12, 11 }, { 1, 7, 9, 5, 11, 12 }, // { 3, 11, 8, 4, 12, 10 }, { 13, 10, 12, 3, 8, 11 }, { 3, 7, 11, 13, 9, 12 }, { 5, 6, 11, 12 }, { 12, 4, 10, 13 }, { 12, 4, 13, 9 } }; HPRef_Struct reftet_2f_0e_1v = { HP_TET, reftet_2f_0e_1v_splitedges, reftet_2f_0e_1v_splitfaces, 0, reftet_2f_0e_1v_newelstypes, reftet_2f_0e_1v_newels }; // HP_TET_2F_1E_0VA, // 2 singular faces, sing edge e4 int reftet_2f_1e_0va_splitedges[][3] = { { 1, 2, 5 }, { 2, 1, 6 }, { 2, 4, 7 }, { 3, 1, 8 }, { 3, 2, 9 }, { 3, 4, 10 }, { 4, 1, 11 }, { 4, 2, 12 }, { 0, 0, 0 } }; int reftet_2f_1e_0va_splitfaces[][4] = { { 3, 2, 1, 13 }, { 3, 2, 4, 14 }, { 4, 1, 2, 15 }, { 0, 0, 0, 0 } }; HPREF_ELEMENT_TYPE reftet_2f_1e_0va_newelstypes[] = { HP_TET, HP_PRISM_1FA_0E_0V, HP_PRISM_1FA_0E_0V, HP_PRISM_SINGEDGE, HP_PRISM_SINGEDGE, HP_PRISM_SINGEDGE, HP_TET_1F_1E_1VA, HP_TET_1F_1E_1VB, HP_TET_1F_1E_1VB, HP_NONE, }; int reftet_2f_1e_0va_newels[][8] = { { 5, 6, 13, 15 }, { 1, 8, 11, 5, 13, 15 }, { 7, 12, 14, 6, 15, 13 }, { 2, 6, 7, 9, 13, 14 }, { 4, 15, 11, 10, 13, 8 }, { 4, 12, 15, 10, 14, 13, }, { 13, 3, 10, 14 }, { 13, 3, 14, 9 }, { 13, 3, 8, 10 }, }; HPRef_Struct reftet_2f_1e_0va = { HP_TET, reftet_2f_1e_0va_splitedges, reftet_2f_1e_0va_splitfaces, 0, reftet_2f_1e_0va_newelstypes, reftet_2f_1e_0va_newels }; // HP_TET_2F_1E_0VB = 602, // 2 singular faces f234,f134, sing edge e5=e24 int reftet_2f_1e_0vb_splitedges[][3] = { { 1, 2, 5 }, { 2, 1, 6 }, { 2, 3, 7 }, { 3, 1, 8 }, { 3, 2, 9 }, { 4, 1, 10 }, { 4, 2, 11 }, { 4, 3, 12 }, { 0, 0, 0 } }; int reftet_2f_1e_0vb_splitfaces[][4] = { { 4, 2, 3, 13 }, { 4, 1, 2, 14 }, { 3, 1, 2, 15 }, { 0, 0, 0, 0 } }; HPREF_ELEMENT_TYPE reftet_2f_1e_0vb_newelstypes[] = { HP_TET, HP_PRISM_1FA_0E_0V, HP_PRISM_1FA_0E_0V, HP_PRISM_SINGEDGE, HP_PRISM_SINGEDGE, HP_PRISM_SINGEDGE, HP_TET_1F_1E_1VA, HP_TET_1F_1E_1VB, HP_TET_1F_1E_1VB, HP_NONE, }; int reftet_2f_1e_0vb_newels[][8] = { { 5, 6, 15, 14 }, { 1, 8, 10, 5, 15, 14 }, { 7, 13, 9, 6, 14, 15 }, { 2, 7, 6, 11, 13, 14 }, { 3, 8, 15, 12, 10, 14 }, { 3, 15, 9, 12, 14, 13 }, { 14, 4, 11, 13 }, { 14, 4, 13, 12 }, { 14, 4, 12, 10 }, }; HPRef_Struct reftet_2f_1e_0vb = { HP_TET, reftet_2f_1e_0vb_splitedges, reftet_2f_1e_0vb_splitfaces, 0, reftet_2f_1e_0vb_newelstypes, reftet_2f_1e_0vb_newels }; // HP_TET_3F_0E_0V = 610, // 3 singular faces, no additional points or edges int reftet_3f_0e_0v_splitedges[][3] = { { 1, 2, 5 }, { 1, 3, 6 }, { 2, 1, 7 }, { 2, 3, 8 }, { 3, 1, 9 }, { 3, 2, 10 }, { 4, 1, 11 }, { 4, 2, 12 }, { 4, 3, 13 }, { 0, 0, 0 } }; int reftet_3f_0e_0v_splitfaces[][4] = { { 1, 2, 3, 14 }, { 2, 3, 1, 15 }, { 3, 1, 2, 16 }, { 4, 1, 2, 17 }, { 4, 1, 3, 18 }, { 4, 2, 3, 19 }, { 0, 0, 0, 0 } }; int reftet_3f_0e_0v_splitelements[][5] = { { 4, 1, 2, 3, 20 }, { 0 } }; HPREF_ELEMENT_TYPE reftet_3f_0e_0v_newelstypes[] = { HP_TET, HP_PRISM_1FA_0E_0V, HP_PRISM_1FA_0E_0V, HP_PRISM_1FA_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_TET_1F_1E_1VA, // 1E_1VA HP_TET_1F_0E_0V, HP_TET_1F_0E_0V, // 1E_1VA HP_TET_1F_0E_0V, // 1E_1VA HP_TET_1F_0E_0V, // 1E_1VA HP_TET_1F_0E_0V, // 1E_1VA HP_NONE, }; int reftet_3f_0e_0v_newels[][8] = { { 14, 15, 16, 20 }, { 5, 17, 7, 14, 20, 15 }, { 6, 9, 18, 14, 16, 20 }, { 10, 8, 19, 16, 15, 20 }, { 1, 5, 14, 11, 17, 20 }, { 11, 18, 20, 1, 6, 14 }, { 2, 8, 15, 12, 19, 20 }, { 12, 17, 20, 2, 7, 15 }, { 3, 9, 16, 13, 18, 20 }, { 13, 19, 20, 3, 10, 16 }, { 20, 4, 11, 17 }, { 20, 4, 17, 12 }, { 20, 4, 12, 19 }, { 20, 4, 19, 13 }, { 20, 4, 13, 18 }, { 20, 4, 18, 11 } }; HPRef_Struct reftet_3f_0e_0v = { HP_TET, reftet_3f_0e_0v_splitedges, reftet_3f_0e_0v_splitfaces, reftet_3f_0e_0v_splitelements, reftet_3f_0e_0v_newelstypes, reftet_3f_0e_0v_newels }; // HP_TET_ALFELD int reftet_Alfeld_splitedges[][3] = { { 0, 0, 0 } }; int reftet_Alfeld_splitfaces[][4] = { { 0, 0, 0, 0 } }; int reftet_Alfeld_splitelements[][5] = { { 1, 2, 3, 4, 5}, { 0 } }; HPREF_ELEMENT_TYPE reftet_Alfeld_newelstypes[] = { HP_TET, HP_TET, HP_TET, HP_TET, HP_NONE, }; int reftet_Alfeld_newels[][8] = { { 1, 2, 3, 5 }, { 1, 4, 2, 5 }, { 1, 3, 4, 5 }, { 3, 2, 4, 5 } }; HPRef_Struct reftet_Alfeld = { HP_TET, reftet_Alfeld_splitedges, reftet_Alfeld_splitfaces, reftet_Alfeld_splitelements, reftet_Alfeld_newelstypes, reftet_Alfeld_newels }; /* */ ================================================ FILE: libsrc/meshing/hpref_trig.hpp ================================================ // 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 }; // HP_TRIG_ALFELD int reftrig_Alfeld_splitedges[][3] = { { 0, 0, 0 } }; int reftrig_Alfeld_splitfaces[][4] = { { 1, 2, 3, 4 }, { 0, 0, 0, 0 } }; HPREF_ELEMENT_TYPE reftrig_Alfeld_newelstypes[] = { HP_TRIG, HP_TRIG, HP_TRIG, HP_NONE, }; int reftrig_Alfeld_newels[][8] = { { 1, 2, 4 }, { 2, 3, 4 }, { 3, 1, 4 }, }; HPRef_Struct reftrig_Alfeld = { HP_TRIG, reftrig_Alfeld_splitedges, reftrig_Alfeld_splitfaces, 0, reftrig_Alfeld_newelstypes, reftrig_Alfeld_newels }; // HP_TRIG_POWELL int reftrig_Powell_splitedges[][3] = { { 1, 2, 4 }, { 2, 3, 5 }, { 3, 1, 6 }, { 0, 0, 0 }, }; int reftrig_Powell_splitfaces[][4] = { { 1, 2, 3, 7 }, { 0, 0, 0, 0 } }; HPREF_ELEMENT_TYPE reftrig_Powell_newelstypes[] = { HP_TRIG, HP_TRIG, HP_TRIG, HP_TRIG, HP_TRIG, HP_TRIG, HP_NONE, }; int reftrig_Powell_newels[][8] = { { 1, 4, 7 }, { 4, 2, 7 }, { 2, 5, 7 }, { 5, 3, 7 }, { 3, 6, 7 }, { 6, 1, 7 }, }; HPRef_Struct reftrig_Powell = { HP_TRIG, reftrig_Powell_splitedges, reftrig_Powell_splitfaces, 0, reftrig_Powell_newelstypes, reftrig_Powell_newels }; ================================================ FILE: libsrc/meshing/hprefinement.cpp ================================================ #include #include "meshing.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: levelx = 0; levely = 0; levelz = 0; } HPRefElement :: HPRefElement () { Reset(); } HPRefElement :: HPRefElement(Element & el) : type(HP_NONE), index(el.GetIndex()), levelx(0), levely(0), levelz(0), np(el.GetNV()), domin(-1), domout(-1) //domin,out for segments { //Reset(); for (int i=0; i & GetHPRegistry()\ { static std::map registry; return registry; } HPRef_Struct * Get_HPRef_Struct (HPREF_ELEMENT_TYPE type) { HPRef_Struct * hps = NULL; /* if (type >= 100 && type < 1000) if (type != HP_TET_1F_0E_1VA) type = HP_NONETET; */ 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_TRIG_ALFELD: hps = &reftrig_Alfeld; break; case HP_TRIG_POWELL: hps = &reftrig_Powell; 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_NONETET: hps = &refnonetet; 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_3ED_3V: hps = &reftet_3ed_3v; 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_0E_2V: hps = &reftet_1f_0e_2v; break; // case HP_TET_1F_0E_3V: // hps = &reftet_1f_0e_3v; 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_1F_1E_1VA: hps = &reftet_1f_1e_1va; break; case HP_TET_1F_1E_1VB: hps = &reftet_1f_1e_1vb; break; case HP_TET_1F_1E_2VA: hps = &reftet_1f_1e_2va; break; case HP_TET_1F_1E_2VB: hps = &reftet_1f_1e_2vb; break; case HP_TET_1F_2E_0VA: hps = &reftet_1f_2e_0va; break; case HP_TET_1F_2E_0VB: hps = &reftet_1f_2e_0vb; break; case HP_TET_2F_0E_0V: hps = &reftet_2f_0e_0v; break; case HP_TET_2F_0E_1V: hps = &reftet_2f_0e_1v; break; case HP_TET_2F_1E_0VA: hps = &reftet_2f_1e_0va; break; case HP_TET_2F_1E_0VB: hps = &reftet_2f_1e_0vb; break; case HP_TET_3F_0E_0V: hps = &reftet_3f_0e_0v; break; case HP_TET_ALFELD: hps = &reftet_Alfeld; 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_0V: hps = &refpyramid_1fb_0e_0v; 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; case HP_HEX7: hps = &refhex7; break; case HP_HEX7_1FA: hps = &refhex7_1fa; break; case HP_HEX7_1FB: hps = &refhex7_1fb; break; default: { if (GetHPRegistry().count(type)) hps = GetHPRegistry()[type]; else hps = NULL; } } /* 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; } template bool CheckSingularities(Mesh & mesh, INDEX_2_HASHTABLE & edges, HT_EDGEPOINT_DOM & edgepoiclt_dom, NgBitArray & cornerpoint, NgBitArray & edgepoint, INDEX_3_HASHTABLE & faces, INDEX_2_HASHTABLE & face_edges, INDEX_2_HASHTABLE & surf_edges, Array & facepoint, int & levels, int & act_ref); bool ClassifyHPElements (Mesh & mesh, NgArray & elements, SplittingType split, int & act_ref, int & levels); void InitHPElements(Mesh & mesh, NgArray & elements) { // for(ElementIndex i = 0; i < mesh.GetNE(); i++) for(ElementIndex i : mesh.VolumeElements().Range()) { HPRefElement hpel(mesh[i]); hpel.coarse_elnr = int(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; hpel.index = seg.GetIndex(); hpel.edgenr = seg.GetEdgeNr(); /* if(seg.edgenr >= 10000) { throw NgException("assumption that seg.edgenr < 10000 is wrong"); } */ elements.Append(hpel); } } /* ******************************* DoRefinement *************************************** */ void DoRefinement (Mesh & mesh, NgArray & elements, Refinement * ref, double fac1) { elements.SetAllocSize (5 * elements.Size()); INDEX_2_HASHTABLE newpts(elements.Size()+1); INDEX_3_HASHTABLE newfacepts(elements.Size()+1); double fac2 = max(0.001,min(1.0/3,fac1)); // factor for face points PrintMessage(3, " in HP-REFINEMENT with fac1 ", fac1); *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 (fac1 == 0.5) i2.Sort(); 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*fac2)*mesh.Point(i3.I1())(l) + fac2*mesh.Point(i3.I2())(l) + fac2*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; 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; case HP_HEX7: oldnp = 7; 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_HEX7 || 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]); if (fac1 == 0.5) i2.Sort(); 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*fac2) * el.param[hprs->splitfaces[j][0]-1][l] + fac2 * el.param[hprs->splitfaces[j][1]-1][l] + fac2 * 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; if (newel.type == HP_SEGM || newel.type == HP_TRIG || newel.type == HP_QUAD || newel.type == HP_TET || newel.type == HP_PRISM || newel.type == HP_HEX || newel.type == HP_HEX7 || newel.type == HP_PYRAMID) newel.levelx = newel.levely = newel.levelz = newlevel; else newel.levelx = newel.levely = newel.levelz = newlevel+1; 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_HEX7: newel.np=7; 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, NgArray & 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.edgenr = el.edgenr; 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, NgArray & 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++) { NgArray 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 (NgArray & 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(p), 6.0); cpucost = (ntet + nprism + nhex) * pow (static_cast(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(p1), 6.0) << " (p1-3)^6 = " << pow ( static_cast(max2(p1-3, 0)), 6.0) << " p1^3 = " << pow ( static_cast(p1), 3.0) << " (p1-3)^3 = " << pow ( static_cast(p1-3), 3.0) << " [p1^3-(p1-3)^3]^2 = " << sqr (pow (static_cast(p1),3.0) - pow ( static_cast(p1-3), 3.0)) << endl; p1 /= 2 +1; memcosttet += pow (static_cast(p1), 6.0); memcostsctet += pow (static_cast(p1), 6.0) - pow ( static_cast(max2(p1-3, 1)), 6.0); cpucosttet += pow (static_cast(p1), 9.0); break; } case HP_PRISM: case HP_PRISM_SINGEDGE: { int p1 = maxlevel - el.level + 1; p1 /= 2 +1; memcostprism += pow (static_cast(p1), 6.0); memcostscprism += pow (static_cast(p1), 6.0) - pow ( static_cast(max2(p1-3, 1)), 6.0); cpucostprism += pow (static_cast(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(p1), 4.0) * pow (static_cast(p2), 2.0); memcostschex += pow (static_cast(p1), 6.0) - pow ( static_cast(max2(p1-2, 0)), 6.0); cpucosthex += pow (static_cast(p1), 6.0) * pow (static_cast(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, NgArray & hpelements) { NgArray 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; } PrintMessage(3, nwrong, " wrong prisms, ", nright, " right prisms"); NgArray 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, SplittingType split, int levels, double fac1, bool setorders, bool reflevels) { PrintMessage (1, "HP Refinement called, levels = ", levels); // NgLock mem_lock (mem_mutex,1); mesh.coarsemesh = make_unique(); *mesh.coarsemesh = mesh; // #ifdef CURVEDELEMS_NEW const_cast (mesh.coarsemesh->GetCurvedElements() ). BuildCurvedElements (ref, mesh.GetCurvedElements().GetOrder()); // #endif // delete mesh.hpelements; mesh.hpelements = make_unique>(); NgArray & hpelements = *mesh.hpelements; InitHPElements(mesh,hpelements); NgArray nplevel; nplevel.Append (mesh.GetNP()); int act_ref=1; bool sing = ClassifyHPElements (mesh,hpelements, split, act_ref, levels); sing = true; // iterate at least once while(sing) { PrintMessage(3, " Start new hp-refinement: step ", act_ref); 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.SetEdgeNr (hpel.edgenr); seg.SetIndex (hpel.index); /* 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; seg.SetCurved (coarseseg.IsCurved()); mesh.AddSegment (seg); break; } case HP_TRIG: case HP_QUAD: { Element2d el(hpel.np); for(int j=0;j geom)); } } PrintMessage(5, " Start with Update Topology "); mesh.UpdateTopology(); // mesh.ComputeNVertices(); PrintMessage(5, " Mesh Update Topology done "); act_ref++; sing = ClassifyHPElements(mesh,hpelements, split, act_ref, levels); } PrintMessage(3, " HP-Refinement done with ", --act_ref, " refinement steps."); if(act_ref>=1) { // for(ElementIndex i=0;i 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 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; } } } template bool CheckSingularities(Mesh & mesh, INDEX_2_HASHTABLE & edges, HT_EDGEPOINT_DOM & edgepoint_dom, TBitArray & cornerpoint, TBitArray & edgepoint, INDEX_3_HASHTABLE & faces, INDEX_2_HASHTABLE & face_edges, INDEX_2_HASHTABLE & surf_edges, Array & facepoint, int & levels, int & act_ref) { bool sing = 0; if (mesh.GetDimension() == 3) { /* // check, if point has as least 3 different surfs: NgArray 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.SetBit(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.SetBit (i2.I1()); edgepoint.SetBit (i2.I2()); sing = 1; } // if 2 adjacent edges of an element are singular, the // common point must be a singular point // for (int i = 1; i <= mesh.GetNE(); i++) for (auto ei : mesh.VolumeElements().Range()) { const Element & el = mesh[ei]; 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.SetBit (ek.I1()); if (ej.I1() == ek.I2()) cornerpoint.SetBit (ek.I2()); if (ej.I2() == ek.I1()) cornerpoint.SetBit (ek.I1()); if (ej.I2() == ek.I2()) cornerpoint.SetBit (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); *testout << "set face " << i3 << ", domnr = " << domnr << endl; 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 edges = " << edges << endl; // (*testout) << "singular faces = " << faces << endl; // (*testout) << "singular faces_edges = " << face_edges << endl; } else { // 2D case // check, if point has as least 3 different surfs: NgArray 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 = INDEX_2::Sort(mesh.LineSegment(i)[0], mesh.LineSegment(i)[1]); edges.Set(i2,1); edgepoint.SetBit(i2.I1()); edgepoint.SetBit(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 ( { mesh.LineSegment(i).domin, i2.I1() }, 1); edgepoint_dom.Set ( { mesh.LineSegment(i).domin, i2.I2() }, 1); sing = 1; } if (seg.singedge_right * levels >= act_ref) { PointIndices<2> i2 = INDEX_2::Sort(mesh.LineSegment(i)[1], mesh.LineSegment(i)[0]); edges.Set (i2, 1); edgepoint.SetBit(i2.I1()); edgepoint.SetBit(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 ( { mesh.LineSegment(i).domout, i2.I1() }, 1); edgepoint_dom.Set ( { 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.SetBit(i); } // mark points for refinement that are explicitly specified in input file if (mesh.Point(i).Singularity()*levels >= act_ref) { cornerpoint.SetBit(i); edgepoint.SetBit(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) PrintMessage(3, "PrepareElements no more to do for actual refinement ", act_ref); return(sing); } bool ClassifyHPElements (Mesh & mesh, NgArray & elements, SplittingType split, int & act_ref, int & levels) { INDEX_2_HASHTABLE edges(mesh.GetNSeg()+1); TBitArray edgepoint(mesh.GetNP()); // INDEX_2_HASHTABLE edgepoint_dom(mesh.GetNSeg()+1); HT_EDGEPOINT_DOM edgepoint_dom; edgepoint.Clear(); TBitArray cornerpoint(mesh.GetNP()); cornerpoint.Clear(); // value = nr > 0 ... refine elements in domain nr // value = -1 ..... refine elements in any domain INDEX_3_HASHTABLE faces(mesh.GetNSE()+1); INDEX_2_HASHTABLE face_edges(mesh.GetNSE()+1); INDEX_2_HASHTABLE surf_edges(mesh.GetNSE()+1); Array facepoint(mesh.GetNP()); bool sing = CheckSingularities(mesh, edges, edgepoint_dom, cornerpoint, edgepoint, faces, face_edges, surf_edges, facepoint, levels, act_ref); if (act_ref == 1 && split == SPLIT_ALFELD) sing = true; if (act_ref == 1 && split == SPLIT_POWELL) sing = true; if(sing==0) return(sing); int cnt_undef = 0, cnt_nonimplement = 0; NgArray misses(10000); misses = 0; // (*testout) << "edgepoint_dom = " << endl << edgepoint_dom << endl; for( int i = 0; igeom) { case HP_TET: { hpel.type = ClassifyTet(hpel, edges, edgepoint_dom, cornerpoint, edgepoint, faces,face_edges, surf_edges, facepoint); /* // if (i != 182) if ( (!hpel.PNums().Contains(40)) || (!hpel.PNums().Contains(41)) ) hpel.type = HP_NONETET; else cout << "type = " << hpel.type << endl; */ if (split == SPLIT_ALFELD && mesh.GetDimension()==3) hpel.type = HP_TET_ALFELD; break; } case HP_PRISM: { hpel.type = ClassifyPrism(hpel, edges, edgepoint_dom, cornerpoint, edgepoint, faces, face_edges, surf_edges, facepoint); break; } case HP_HEX7: { hpel.type = ClassifyHex7(hpel, edges, edgepoint_dom, cornerpoint, edgepoint, faces, face_edges, surf_edges, facepoint); break; } case HP_HEX: { 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()); if (split == SPLIT_HP) hpel.type = ClassifyTrig(hpel, edges, edgepoint_dom, cornerpoint, edgepoint, faces, face_edges, surf_edges, facepoint, dim, fd); else if (split == SPLIT_ALFELD && mesh.GetDimension()==2) hpel.type = HP_TRIG_ALFELD; else if (split == SPLIT_POWELL && mesh.GetDimension()==2) hpel.type = HP_TRIG_POWELL; 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: { if (split == SPLIT_HP) hpel.type = ClassifySegm(hpel, edges, edgepoint_dom, cornerpoint, edgepoint, faces, face_edges, surf_edges, facepoint); else if (split == SPLIT_POWELL) hpel.type = HP_SEGM_SINGCORNERL; dd = 1; break; } case HP_PYRAMID: { hpel.type = ClassifyPyramid(hpel, edges, edgepoint_dom, cornerpoint, edgepoint, faces, face_edges, surf_edges, facepoint); 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; jgeom) { 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 si; int edgenr; int levelx; int levely; int levelz; int np; int coarse_elnr; // issue (JS): same class is for ElementIndex, SurfaceElementIndex, SegmentIndex 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; auto PNums() const { return FlatArray(np, &pnums[0]); } // EdgePointGeomInfo epgeominfo[2]; }; enum SplittingType { SPLIT_HP, SPLIT_ALFELD, SPLIT_POWELL}; DLL_HEADER extern void HPRefinement (Mesh & mesh, Refinement * ref, SplittingType split, int levels, double fac1=0.125, bool setorders=true, bool ref_level = false); inline void HPRefinement (Mesh & mesh, Refinement * ref, int levels, double fac1=0.125, bool setorders=true, bool ref_level = false) { HPRefinement (mesh, ref, SPLIT_HP, levels, fac1, setorders, ref_level); } } // namespace netgen #endif ================================================ FILE: libsrc/meshing/improve2.cpp ================================================ #include #include "meshing.hpp" #include namespace netgen { class trionedge { public: SurfaceElementIndex tnr; int sidenr; trionedge () { tnr = 0; sidenr = 0; } trionedge (SurfaceElementIndex atnr, int asidenr) { tnr = atnr; sidenr = asidenr; } }; // check if element is quad with at least one surface point -> relevant for optimization // (quads with 4 edge points are not optimized and can be ignored) bool checkMixedElement(const Mesh & mesh, FlatArray seia) { bool mixed = false; ParallelForRange( Range(seia), [&] (auto myrange) NETGEN_LAMBDA_INLINE { for (auto i : myrange) { const auto & sel = mesh[seia[i]]; if(sel.GetNP() == 3) continue; for(auto pi : Range(sel.GetNP())) if(mesh[sel[pi]].Type() == SURFACEPOINT) mixed = true; } }); return mixed; } bool MeshOptimize2d :: EdgeSwapping (const int usemetric, Array &neighbors, Array &swapped, const SurfaceElementIndex t1, const int o1, const int t, Array &pdef, const bool check_only) { bool should; bool do_swap = false; SurfaceElementIndex t2 = neighbors[t1].GetNr (o1); int o2 = neighbors[t1].GetOrientation (o1); if (t2 == -1) return false; if (swapped[t1] || swapped[t2]) return false; if (mesh[t2].IsDeleted()) return false; if (mesh[t2].GetNP() != 3) return false; const int faceindex = mesh[t1].GetIndex(); const int surfnr = mesh.GetFaceDescriptor (faceindex).SurfNr(); 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) return false; // 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) return false; 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(); auto nvp3 = geo.GetNormal (surfnr, mesh.Point(pi3), &gi3); nvp3.Normalize(); auto nvp4 = geo.GetNormal (surfnr, mesh.Point(pi4), &gi4); 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[pi1], mesh[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[pi1], mesh[pi2]) - Dist2 (mesh[pi3], mesh[pi4]); should = e >= t && (e > 2 || d > 0); } else { double loch = 0.25*(mesh.GetH(pi1) + mesh.GetH(pi2) + mesh.GetH(pi3) + mesh.GetH(pi4)); should = CalcTriangleBadness (mesh[pi4], mesh[pi3], mesh[pi1], metricweight, loch) + CalcTriangleBadness (mesh[pi3], mesh[pi4], mesh[pi2], metricweight, loch) < CalcTriangleBadness (mesh[pi1], mesh[pi2], mesh[pi3], metricweight, loch) + CalcTriangleBadness (mesh[pi2], mesh[pi1], mesh[pi4], metricweight, loch); } if (allowswap) { Element2d sw1 (pi4, pi3, pi1); Element2d sw2 (pi3, pi4, pi2); int legal1 = mesh.LegalTrig (mesh[t1]) + mesh.LegalTrig (mesh[t2]); int legal2 = mesh.LegalTrig (sw1) + mesh.LegalTrig (sw2); if (legal1 < legal2) should = true; if (legal2 < legal1) should = false; } do_swap = should; if (should && !check_only) { // do swapping ! mesh[t1] = { { pi1, gi1 }, { pi4, gi4 }, { pi3, gi3 } }; mesh[t2] = { { pi2, gi2 }, { pi3, gi3 }, { pi4, gi4 } }; pdef[pi1]--; pdef[pi2]--; pdef[pi3]++; pdef[pi4]++; swapped[t1] = true; swapped[t2] = true; } } return do_swap; } void MeshOptimize2d :: EdgeSwapping (int usemetric) { static Timer timer("EdgeSwapping (2D)"); RegionTimer reg(timer); static Timer timer_nb("EdgeSwapping-Find neighbors"); if (usemetric) PrintMessage (3, "Edgeswapping, metric"); else PrintMessage (3, "Edgeswapping, topological"); static Timer timerstart("EdgeSwapping 2D start"); timerstart.Start(); Array seia; mesh.GetSurfaceElementsOfFace (faceindex, seia); if(checkMixedElement(mesh, seia)) { timerstart.Stop(); return GenericImprove(); } Array neighbors(mesh.GetNSE()); auto elements_on_node = mesh.CreateCompressedPoint2SurfaceElementTable(faceindex); Array swapped(mesh.GetNSE()); Array pdef(mesh.GetNP()); Array pangle(mesh.GetNP()); static const double minangle[] = { 0, 1.481, 2.565, 3.627, 4.683, 5.736, 7, 9 }; if(faceindex == 0) { ParallelFor( Range(pangle), [&] (auto i) NETGEN_LAMBDA_INLINE { pangle[i] = 0.0; }); } else { ParallelFor( Range(seia), [&] (auto i) NETGEN_LAMBDA_INLINE { const Element2d & sel = mesh[seia[i]]; for (int j = 0; j < 3; j++) pangle[sel[j]] = 0.0; }); } ParallelFor( Range(seia), [&] (auto i) NETGEN_LAMBDA_INLINE { const Element2d & sel = mesh[seia[i]]; for (int j = 0; j < 3; j++) { POINTTYPE typ = mesh[sel[j]].Type(); if (typ == FIXEDPOINT || typ == EDGEPOINT) { AtomicAdd(pangle[sel[j]], Angle (mesh[sel[(j+1)%3]] - mesh[sel[j]], mesh[sel[(j+2)%3]] - mesh[sel[j]])); } } }); ParallelFor( Range(seia), [&] (auto i) NETGEN_LAMBDA_INLINE { 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; } }); ParallelFor( Range(seia), [this, &pdef, &neighbors, &seia, &elements_on_node] (auto i) NETGEN_LAMBDA_INLINE { auto sei = seia[i]; for (PointIndex pi : mesh[sei].template PNums<3>()) AsAtomic(pdef[pi])++; for (int j = 0; j < 3; j++) { neighbors[sei].SetNr (j, -1); neighbors[sei].SetOrientation (j, 0); } const auto sel = mesh[sei]; auto index = sel.GetIndex(); for (int j = 0; j < 3; j++) { PointIndex pi1 = sel.PNumMod(j+2); PointIndex pi2 = sel.PNumMod(j+3); if(mesh.IsSegment(pi1, pi2)) continue; for (auto sei_other : elements_on_node[pi1]) { if(sei_other==sei) continue; if(mesh[sei_other].GetIndex()!=index) continue; const auto & other = mesh[sei_other]; int pi1_other = -1; int pi2_other = -1; bool common_edge = false; for (int k = 0; k < 3; k++) { if(other[k] == pi1) pi1_other = k; if(other[k] == pi2) { pi2_other = k; common_edge = true; } } if(common_edge) { neighbors[sei].SetNr (j, sei_other); neighbors[sei].SetOrientation (j, 3-pi1_other-pi2_other); } } } }); for (SurfaceElementIndex sei : seia) swapped[sei] = false; timerstart.Stop(); Array> improvement_candidates(3*seia.Size()); atomic cnt(0); int t = 4; bool done = false; while (!done && t >= 2) { cnt = 0; ParallelFor( Range(seia), [&] (auto i) NETGEN_LAMBDA_INLINE { SurfaceElementIndex t1 = seia[i]; if (mesh[t1].IsDeleted()) return; if (swapped[t1]) return; if(mesh[t1].GetNP() != 3) return; if (multithread.terminate) throw NgException ("Meshing stopped"); for (int o1 = 0; o1 < 3; o1++) if(EdgeSwapping(usemetric, neighbors, swapped, t1, o1, t, pdef, true)) improvement_candidates[cnt++]= std::make_pair(t1,o1); }); auto elements_with_improvement = improvement_candidates.Range(0, cnt.load()); QuickSort(elements_with_improvement); for (auto [t1,o1] : elements_with_improvement) done |= EdgeSwapping(usemetric, neighbors, swapped, t1, o1, t, pdef, false); t--; } mesh.SetNextTimeStamp(); } template double CombineImproveEdge( Mesh & mesh, const T_PI2SEI & elementsonnode, Array, PointIndex> & normals, Array & fixed, PointIndex pi1, PointIndex pi2, double metricweight, bool check_only = true) { Vec<3> nv; ArrayMem hasonepi, hasbothpi; if (!pi1.IsValid() || !pi2.IsValid()) return 0.0; bool debugflag = 0; if (debugflag) { (*testout) << "Combineimprove " << "pi1 = " << pi1 << " pi2 = " << pi2 << endl; } if (fixed[pi2]) return 0.0; double loch = 0.5*(mesh.GetH(pi1) + mesh.GetH(pi2)); int faceindex = -1; for (SurfaceElementIndex sei2 : elementsonnode[pi1]) { const Element2d & el2 = mesh[sei2]; if (el2.IsDeleted()) continue; if (el2[0] == pi2 || el2[1] == pi2 || el2[2] == pi2) { faceindex = el2.GetIndex(); hasbothpi.Append (sei2); } } if(hasbothpi.Size()==0) return 0.0; nv = normals[pi2]; for (SurfaceElementIndex sei2 : elementsonnode[pi2]) { const Element2d & el2 = mesh[sei2]; if (el2.IsDeleted()) continue; if (!el2.PNums<3>().Contains (pi1)) hasonepi.Append (sei2); } double bad1 = 0; int illegal1 = 0, illegal2 = 0; /* for (SurfaceElementIndex sei : hasonepi) { const Element2d & el = mesh[sei]; bad1 += CalcTriangleBadness (mesh[el[0]], mesh[el[1]], mesh[el[2]], nv, -1, loch); illegal1 += 1-mesh.LegalTrig(el); } */ for (const Element2d & el : mesh.SurfaceElements()[hasonepi]) { bad1 += CalcTriangleBadness (mesh[el[0]], mesh[el[1]], mesh[el[2]], nv, metricweight, 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, metricweight, loch); illegal1 += 1-mesh.LegalTrig(el); } double bad2 = 0; for (int k = 0; k < hasonepi.Size(); k++) { Element2d el = mesh[hasonepi[k]]; for (auto i : Range(3)) if(el[i]==pi2) el[i] = pi1; double err = CalcTriangleBadness (mesh[el[0]], mesh[el[1]], mesh[el[2]], nv, metricweight, 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++) { auto normal = normals[el[l]]; if(mesh[el[l]].Type() != SURFACEPOINT) { // point possibly on edge -> multiple normal vectors (for each surface), need to calculate it to be sure const int surfnr = mesh.GetFaceDescriptor (el.GetIndex()).SurfNr(); normal = mesh.GetGeometry()->GetNormal (surfnr, mesh[el[l]], &el.GeomInfo()[l]); } if ( ( normal * nv) < 0.5) bad2 += 1e10; } illegal2 += 1-mesh.LegalTrig(el); } if (debugflag) { (*testout) << "bad1 = " << bad1 << ", bad2 = " << bad2 << endl; } bool should = (illegal2<=illegal1 && bad2 < bad1 && bad2 < 1e4); if(illegal2 < illegal1) { should = true; bad1 += 1e4; } double d_badness = should * (bad2-bad1); if(check_only) return d_badness; if (should) { /* (*testout) << "combine !" << endl; (*testout) << "bad1 = " << bad1 << ", bad2 = " << bad2 << endl; (*testout) << "illegal1 = " << illegal1 << ", illegal2 = " << illegal2 << endl; (*testout) << "loch = " << loch << endl; */ PointGeomInfo gi; // bool gi_set(false); /* Element2d *el1p(NULL); int l = 0; while(mesh[elementsonnode[pi1][l]].IsDeleted() && lGetNP(); l++) if ((*el1p)[l] == pi1) { gi = el1p->GeomInfoPi (l+1); // gi_set = true; } */ for (auto sei : hasbothpi) { const Element2d & el1p = mesh[sei]; if (el1p.IsDeleted()) continue; if(el1p.GetIndex() != faceindex) continue; for (int l = 0; l < el1p.GetNP(); l++) if (el1p[l] == pi1) gi = el1p.GeomInfo()[l]; break; } // (*testout) << "Connect point " << pi2 << " to " << pi1 << "\n"; // for (int k = 0; k < elementsonnode[pi2].Size(); k++) for (SurfaceElementIndex sei2 : elementsonnode[pi2]) { Element2d & el = mesh[sei2]; if (el.IsDeleted()) continue; if (el.PNums().Contains(pi1)) continue; for (auto l : Range(el.GetNP())) { if (el[l] == pi2) { el[l] = pi1; el.GeomInfo()[l] = gi; } fixed[el[l]] = true; } } for (auto sei : hasbothpi) mesh[sei].Delete(); } return d_badness; } void MeshOptimize2d :: CombineImprove () { SplitImprove(); PrintMessage (3, "Combine improve"); if (multithread.terminate) throw NgException ("Meshing stopped"); static Timer timer ("Combineimprove 2D"); RegionTimer reg (timer); static Timer timerstart ("Combineimprove 2D start"); timerstart.Start(); static Timer timerstart1 ("Combineimprove 2D start1"); timerstart1.Start(); Array seia; mesh.GetSurfaceElementsOfFace (faceindex, seia); if(checkMixedElement(mesh, seia)) { timerstart1.Stop(); timerstart.Stop(); return; } int np = mesh.GetNP(); auto elementsonnode = mesh.CreateCompressedPoint2SurfaceElementTable(faceindex); // int ntasks = ngcore::TaskManager::GetMaxThreads(); Array> edges; BuildEdgeList( mesh, elementsonnode, edges ); Array fixed(np); ParallelFor( fixed.Range(), [&] (auto i) NETGEN_LAMBDA_INLINE { fixed[i] = mesh[i].Type() != SURFACEPOINT; }); timerstart1.Stop(); ParallelFor( mesh.LockedPoints().Range(), [&] (auto i) NETGEN_LAMBDA_INLINE { fixed[mesh.LockedPoints()[i]] = true; }); Array,PointIndex> normals(np); ParallelFor( mesh.Points().Range(), [&] (auto pi) NETGEN_LAMBDA_INLINE { if (elementsonnode[pi].Size()) { Element2d & hel = mesh[elementsonnode[pi][0]]; for (int k = 0; k < 3; k++) if (hel[k] == pi) { const int faceindex = hel.GetIndex(); const int surfnr = mesh.GetFaceDescriptor (faceindex).SurfNr(); normals[pi] = geo.GetNormal (surfnr, mesh[pi], &hel.GeomInfoPi(k+1)); break; } } }, TasksPerThread(4)); timerstart.Stop(); // Find edges with improvement Array> candidate_edges(edges.Size()); std::atomic improvement_counter(0); ParallelFor( Range(edges), [&] (auto i) NETGEN_LAMBDA_INLINE { auto [pi1, pi2] = edges[i]; double d_badness = CombineImproveEdge(mesh, elementsonnode, normals, fixed, pi1, pi2, metricweight, true); if(d_badness < 0.0) candidate_edges[improvement_counter++] = make_tuple(d_badness, i); d_badness = CombineImproveEdge(mesh, elementsonnode, normals, fixed, pi2, pi1, metricweight, true); if(d_badness < 0.0) candidate_edges[improvement_counter++] = make_tuple(d_badness, -i); }, TasksPerThread(4)); auto edges_with_improvement = candidate_edges.Part(0, improvement_counter.load()); QuickSort(edges_with_improvement); for(auto [d_badness, ei] : edges_with_improvement) { auto [pi1, pi2] = edges[ei < 0 ? -ei : ei]; if(ei<0) Swap(pi1,pi2); CombineImproveEdge(mesh, elementsonnode, normals, fixed, pi1, pi2, metricweight, false); } // mesh.Compress(); mesh.SetNextTimeStamp(); } void MeshOptimize2d :: SplitImprove() { if (!faceindex) { PrintMessage (3, "Split improve"); mesh.CalcSurfacesOfNode(); // TODO: needed? for (faceindex = 1; faceindex <= mesh.GetNFD(); faceindex++) { SplitImprove(); if (multithread.terminate) throw NgException ("Meshing stopped"); } faceindex = 0; mesh.Compress(); // TODO: needed? return; } Array elements; mesh.GetSurfaceElementsOfFace (faceindex, elements); // return if we have quads in this surface for (auto & ei : elements) if (mesh[ei].GetNP() != 3) return; // maps from edges to adjacent trigs INDEX_2_HASHTABLE> els_on_edge(2*elements.Size() + 2); // build els_on_edge table for (SurfaceElementIndex sei : elements) { const Element2d & sel = mesh[sei]; for (int j = 0; j < 3; j++) { PointIndex pi1 = sel.PNumMod(j+2); PointIndex pi2 = sel.PNumMod(j+3); if (mesh.IsSegment (pi1, pi2)) continue; PointIndices<2> ii2 (pi1, pi2); ii2.Sort(); if (els_on_edge.Used (ii2)) { auto els = els_on_edge.Get(ii2); get<1>(els) = sei; els_on_edge.Set(ii2, els); } else { els_on_edge.Set (ii2, make_tuple(sei, sei)); } } } // split edges of illegal trigs for (SurfaceElementIndex sei : elements) { Element2d & sel = mesh[sei]; if (sel.IsDeleted()) continue; // TODO: split also bad trigs, nut just illegal ones if (mesh.LegalTrig(sel)) continue; // find longest edge PointIndices<2> edge; double edge_len = 0; PointIndex pi1, pi2, pi3, pi4; PointGeomInfo gi1, gi2, gi3, gi4; for(auto j : Range(1,4)) { auto test_pi1 = sel.PNumMod(j); auto test_pi2 = sel.PNumMod(j+1); if (mesh.IsSegment(test_pi1, test_pi2)) continue; auto len = (mesh[test_pi2]-mesh[test_pi1]).Length(); if(len > edge_len) { edge = {test_pi1, test_pi2}; edge.Sort(); edge_len = len; pi1 = test_pi1; pi2 = test_pi2; pi3 = sel.PNumMod(j+2); gi1 = sel.GeomInfoPiMod(j); gi2 = sel.GeomInfoPiMod(j+1); gi3 = sel.GeomInfoPiMod(j+2); } } if(!edge_len) throw Exception("Couldn't find edge to split, something is wrong"); // get neighbor element auto els = els_on_edge.Get(edge); SurfaceElementIndex other_i = get<0>(els); if(other_i==sei) other_i = get<1>(els); auto & other = mesh[other_i]; // find opposite point of neighbor element for (int j = 0; j < 3; j++) if(other[j]!=pi1 && other[j]!=pi2) { pi4 = other[j]; gi4 = other.GeomInfoPi(j); break; } // split edge pi1,pi2 Point<3> p5; PointIndex pi5; PointGeomInfo gi5; geo.PointBetween(mesh[pi1], mesh[pi2], 0.5, faceindex, gi1, gi2, p5, gi5); pi5 = mesh.AddPoint(p5); Element2d e1(3); e1.SetIndex(faceindex); e1={ {pi1,gi1}, {pi5,gi5}, {pi3,gi3} }; mesh.AddSurfaceElement( e1 ); Element2d e2(3); e2.SetIndex(faceindex); e2 ={ {pi5,gi5}, {pi2,gi2}, {pi3,gi3} }; mesh.AddSurfaceElement( e2 ); Element2d e3(3); e3.SetIndex(faceindex); e3 ={ {pi1,gi1}, {pi4,gi4}, {pi5,gi5} }; mesh.AddSurfaceElement( e3 ); Element2d e4(3); e4.SetIndex(faceindex); e4 ={ {pi4,gi4}, {pi2,gi2}, {pi5,gi5} }; mesh.AddSurfaceElement( e4 ); sel.Delete(); other.Delete(); } 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; NgArray ngs(3); (*mycout) << "Check Surface Approximation" << endl; (*testout) << "Check Surface Approximation" << 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; } } } */ } } ================================================ FILE: libsrc/meshing/improve2.hpp ================================================ #ifndef NETGEN_IMPROVE2_HPP #define NETGEN_IMPROVE2_HPP #include "meshtype.hpp" namespace netgen { inline void AppendEdges( const Element2d & elem, PointIndex pi, Array> & edges ) { for (int j = 0; j < 3; j++) { PointIndex pi0 = elem[j]; PointIndex pi1 = elem[(j+1)%3]; if (pi1 < pi0) Swap(pi0, pi1); if(pi0==pi) edges.Append(std::make_tuple(pi0, pi1)); } } inline void AppendEdges( const Element & elem, PointIndex pi, Array> & edges ) { static constexpr int tetedges[6][2] = { { 0, 1 }, { 0, 2 }, { 0, 3 }, { 1, 2 }, { 1, 3 }, { 2, 3 } }; if(elem.Flags().fixed) return; for (int j = 0; j < 6; j++) { PointIndex pi0 = elem[tetedges[j][0]]; PointIndex pi1 = elem[tetedges[j][1]]; if (pi1 < pi0) Swap(pi0, pi1); if(pi0==pi) edges.Append(std::make_tuple(pi0, pi1)); } } template void BuildEdgeList( const Mesh & mesh, const T_PI2SEI & elementsonnode, Array> & edges ) { // static_assert(is_same_v||is_same_v, "Invalid type for TINDEX"); static Timer tbuild_edges("Build edges"); RegionTimer reg(tbuild_edges); int ntasks = 4*ngcore::TaskManager::GetMaxThreads(); Array>> task_edges(ntasks); ParallelFor(IntRange(ntasks), [&] (int ti) { auto myrange = mesh.Points().Range().Split(ti, ntasks); ArrayMem, 100> local_edges; for (auto pi : myrange) { local_edges.SetSize(0); for(auto ei : elementsonnode[pi]) { const auto & elem = mesh[ei]; if (elem.IsDeleted()) continue; AppendEdges(elem, pi, local_edges); } QuickSort(local_edges); auto edge_prev = std::make_tuple(PointIndex::INVALID, PointIndex::INVALID); for(auto edge : local_edges) if(edge != edge_prev) { task_edges[ti].Append(edge); edge_prev = edge; } } }, ntasks); int num_edges = 0; for (auto & edg : task_edges) num_edges += edg.Size(); edges.SetAllocSize(num_edges); for (auto & edg : task_edges) edges.Append(edg); } 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]; } }; /// class MeshOptimize2d { int faceindex = 0; int improveedges = 0; double metricweight = 0.; int writestatus = 1; Mesh& mesh; const NetgenGeometry& geo; public: /// MeshOptimize2d(Mesh& amesh) : mesh(amesh), geo(*mesh.GetGeometry()) {} virtual ~MeshOptimize2d() { ; } /// DLL_HEADER void ImproveMesh (const MeshingParameters & mp); DLL_HEADER void ImproveMeshJacobian (const MeshingParameters & mp); DLL_HEADER void ImproveVolumeMesh (); DLL_HEADER void ProjectBoundaryPoints(NgArray & surfaceindex, const NgArray* > & from, NgArray* > & dest); DLL_HEADER bool EdgeSwapping (const int usemetric, Array &neighbors, Array &swapped, const SurfaceElementIndex t1, const int edge, const int t, Array &pdef, const bool check_only=false); DLL_HEADER void EdgeSwapping (int usemetric); DLL_HEADER void CombineImprove (); DLL_HEADER void SplitImprove (); DLL_HEADER void GenericImprove (); void SetFaceIndex (int fi) { faceindex = fi; } void SetImproveEdges (int ie) { improveedges = ie; } void SetMetricWeight (double mw) { metricweight = mw; } void SetWriteStatus (int ws) { writestatus = ws; } /// liefert zu einem 3d-Punkt die geominfo (Dreieck) und liefert 1, wenn erfolgreich, /// 0, wenn nicht (Punkt ausserhalb von chart) /// 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 Point<3> & p1, const Point<3> & p2, const Point<3> & p3, double metricweight, double h); extern double CalcTriangleBadness (const Point<3> & p1, const Point<3> & p2, const Point<3> & p3, const Vec<3> & n, double metricweight, double h); } // namespace netgen #endif // NETGEN_IMPROVE2_HPP ================================================ FILE: libsrc/meshing/improve2gen.cpp ================================================ #include #include "meshing.hpp" #include namespace netgen { class ImprovementRule { public: NgArray oldels; NgArray newels; NgArray> deledges; Array incelsonnode; Array reused; int bonus; int onp; }; void MeshOptimize2d :: GenericImprove () { static Timer timer("MeshOptimize2d::GenericImprove"); RegionTimer reg(timer); if (!faceindex) { if (writestatus) PrintMessage (3, "Generic Improve"); for (faceindex = 1; faceindex <= mesh.GetNFD(); faceindex++) GenericImprove (); faceindex = 0; return; } // 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 << ": " < rules; NgArray elmap; NgArray elrot; Array pmap; Array pgi; int surfnr = mesh.GetFaceDescriptor (faceindex).SurfNr(); ImprovementRule * r1; PointIndex p1 = IndexBASE(); PointIndex p2 = p1+1; PointIndex p3 = p2+1; PointIndex p4 = p3+1; PointIndex p5 = p4+1; PointIndex p6 = p5+1; PointIndex p7 = p6+1; // 2 triangles to quad r1 = new ImprovementRule; r1->oldels.Append (Element2d (p1, p2, p3)); r1->oldels.Append (Element2d (p3, p2, p4)); r1->newels.Append (Element2d (p1, p2, p4, p3)); r1->deledges.Append ( { p2, p3 } ); r1->onp = 4; r1->bonus = 2; rules.Append (r1); // 2 quad to 1 quad r1 = new ImprovementRule; r1->oldels.Append (Element2d (p1, p2, p3, p4)); r1->oldels.Append (Element2d (p4, p3, p2, p5)); r1->newels.Append (Element2d (p1, p2, p5, p4)); r1->deledges.Append ( { p2, p3 } ); r1->deledges.Append ( { p3, p4 } ); r1->onp = 5; r1->bonus = 0; rules.Append (r1); // swap quads r1 = new ImprovementRule; r1->oldels.Append (Element2d (p1, p2, p3, p4)); r1->oldels.Append (Element2d (p3, p2, p5, p6)); r1->newels.Append (Element2d (p1, p6, p3, p4)); r1->newels.Append (Element2d (p1, p2, p5, p6)); r1->deledges.Append ( { p2, p3 } ); r1->onp = 6; r1->bonus = 0; rules.Append (r1); // three quads to 2 r1 = new ImprovementRule; r1->oldels.Append (Element2d (p1, p2, p3, p4)); r1->oldels.Append (Element2d (p2, p5, p6, p3)); r1->oldels.Append (Element2d (p3, p6, p7, p4)); r1->newels.Append (Element2d (p1, p2, p5, p4)); r1->newels.Append (Element2d (p4, p5, p6, p7)); r1->deledges.Append ( { p2, p3 } ); r1->deledges.Append ( { p3, p4 } ); r1->deledges.Append ( { p3, p6 } ); r1->onp = 7; r1->bonus = -1; rules.Append (r1); // quad + 2 connected trigs to quad r1 = new ImprovementRule; r1->oldels.Append (Element2d (p1, p2, p3, p4)); r1->oldels.Append (Element2d (p2, p5, p3)); r1->oldels.Append (Element2d (p3, p5, p4)); r1->newels.Append (Element2d (p1, p2, p5, p4)); r1->deledges.Append ( { p2, p3 } ); r1->deledges.Append ( { p3, p4 } ); r1->deledges.Append ( { p3, p5 } ); 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 (p1, p2, p3, p4)); r1->oldels.Append (Element2d (p2, p6, p3)); r1->oldels.Append (Element2d (p1, p4, p5)); r1->newels.Append (Element2d (p1, p3, p4, p5)); r1->newels.Append (Element2d (p1, p2, p6, p3)); r1->deledges.Append ( { p1, p4 } ); r1->deledges.Append ( { p2, p3 } ); r1->onp = 6; r1->bonus = 0; rules.Append (r1); r1 = new ImprovementRule; r1->oldels.Append (Element2d (p1, p2, p3, p4)); r1->oldels.Append (Element2d (p2, p6, p3)); r1->oldels.Append (Element2d (p1, p4, p5)); r1->newels.Append (Element2d (p1, p2, p4, p5)); r1->newels.Append (Element2d (p4, p2, p6, p3)); r1->deledges.Append ( { p1, p4 } ); r1->deledges.Append ( { p2, p3 } ); r1->onp = 6; r1->bonus = 0; rules.Append (r1); // two quad + trig -> one quad + trig r1 = new ImprovementRule; r1->oldels.Append (Element2d (p1, p2, p3, p4)); r1->oldels.Append (Element2d (p2, p5, p6, p3)); r1->oldels.Append (Element2d (p4, p3, p6)); r1->newels.Append (Element2d (p1, p2, p6, p4)); r1->newels.Append (Element2d (p2, p5, p6)); r1->deledges.Append ( { p2, p3 } ); r1->deledges.Append ( { p3, p4 } ); r1->deledges.Append ( { p3, p6 } ); r1->onp = 6; r1->bonus = -1; rules.Append (r1); // swap quad + trig (a and b) r1 = new ImprovementRule; r1->oldels.Append (Element2d (p1, p2, p3, p4)); r1->oldels.Append (Element2d (p2, p5, p3)); r1->newels.Append (Element2d (p2, p5, p3, p4)); r1->newels.Append (Element2d (p1, p2, p4)); r1->deledges.Append ( { p2, p3 } ); r1->onp = 5; r1->bonus = 0; rules.Append (r1); r1 = new ImprovementRule; r1->oldels.Append (Element2d (p1, p2, p3, p4)); r1->oldels.Append (Element2d (p2, p5, p3)); r1->newels.Append (Element2d (p1, p2, p5, p3)); r1->newels.Append (Element2d (p1, p3, p4)); r1->deledges.Append ( { p2, p3 } ); r1->onp = 5; r1->bonus = 0; rules.Append (r1); // 2 quads to quad + 2 trigs r1 = new ImprovementRule; r1->oldels.Append (Element2d (p1, p2, p3, p4)); r1->oldels.Append (Element2d (p3, p2, p5, p6)); r1->newels.Append (Element2d (p1, p5, p6, p4)); r1->newels.Append (Element2d (p1, p2, p5)); r1->newels.Append (Element2d (p4, p6, p3)); r1->deledges.Append ( { p2, p3 } ); r1->onp = 6; r1->bonus = 0; // rules.Append (r1); NgArray mapped(rules.Size()); NgArray 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 = 0; j < rule.onp; j++) { rule.incelsonnode[j] = 0; rule.reused[j] = 0; } */ rule.incelsonnode = 0; rule.reused = 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 (const Element2d & el : rule.oldels) for (PointIndex pi : el.PNums()) rule.incelsonnode[pi]--; 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[el.PNum(k)]++; rule.reused[el.PNum(k)] = 1; } } } DynamicTable elonnode(np); Array nelonnode(np); TABLE 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; NgFlatArray 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 = PointIndex (-1); for (auto & p : pmap) p.Invalidate(); for (int k = 0; k < el0.GetNP(); k++) { pmap[rel0[k]] = el0.PNumMod(k+elrot[0]+1); pgi[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[rel[k]].IsValid() && pmap[rel[k]] != el.PNumMod (k+elrot[i]+1)) possible = 0; if (possible) { for (int k = 0; k < el.GetNP(); k++) { pmap[rel[k]] = el.PNumMod(k+elrot[i]+1); pgi[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 olddef) continue; // calc metric badness double bad1 = 0, bad2 = 0; // SelectSurfaceOfPoint (mesh.Point(pmap.Get(1)), pgi.Get(1)); // auto n = geo.GetNormal(surfnr, mesh.Point(pmap.Get(1)), &pgi.Elem(1)); auto n = geo.GetNormal(surfnr, mesh.Point(pmap.First()), pgi.Data()); for (int j = 0; j < rule.oldels.Size(); j++) bad1 += mesh[elmap[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[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[rnel.PNum(k)]; nel.GeomInfoPi(k) = pgi[rnel.PNum(k)]; } mesh.AddSurfaceElement(nel); } for (int j = 0; j < rule.oldels.Size(); j++) mesh.Delete (elmap[j]); for (PointIndex j : pmap.Range()) nelonnode[pmap[j]] += rule.incelsonnode[j]; used[ri]++; } } } mesh.Compress(); for (int ri = 0; ri < rules.Size(); ri++) { PrintMessage (5, "rule ", ri+1, " ", mapped[ri], "/", used[ri], " mapped/used"); } } } ================================================ FILE: libsrc/meshing/improve3.cpp ================================================ #include #include #include #include #include "meshing.hpp" #ifdef SOLIDGEOM #include #endif #include namespace netgen { bool WrongOrientation(Point<3> p1, Point<3> p2, Point<3> p3, Point<3> p4) { Vec<3> v1 = p2 - p1; Vec<3> v2 = p3 - p1; Vec<3> v3 = p4 - p1; Vec<3> n = Cross(v1, v2); return n * v3 > 0; } static constexpr int tetedges[6][2] = { { 0, 1 }, { 0, 2 }, { 0, 3 }, { 1, 2 }, { 1, 3 }, { 2, 3 } }; static constexpr int IMPROVEMENT_CONFORMING_EDGE = -1e6; static inline bool NotTooBad(double bad1, double bad2) { return (bad2 <= bad1) || (bad2 <= 100 * bad1 && bad2 <= 1e18) || (bad2 <= 1e8); } // Calc badness of new element where pi1 and pi2 are replaced by pnew double CalcBadReplacePoints (const Mesh::T_POINTS & points, const MeshingParameters & mp, const Element & elem, double h, PointIndex &pi1, PointIndex &pi2, MeshPoint &pnew) { if (elem.GetType() != TET) return 0; MeshPoint* p[] = {&points[elem[0]], &points[elem[1]], &points[elem[2]], &points[elem[3]]}; for (auto i : Range(4)) if(elem[i]==pi1 || elem[i]==pi2) p[i] = &pnew; return CalcTetBadness (*p[0], *p[1], *p[2], *p[3], h, mp); } static ArrayMem SplitElement (Element old, PointIndex pi0, PointIndex pi1, PointIndex pinew) { ArrayMem new_elements; // split element by cutting edge pi0,pi1 at pinew auto np = old.GetNP(); old.Touch(); if(np == 4) { // Split tet into two tets Element newel0 = old; Element newel1 = old; for (int i : Range(4)) { if(newel0[i] == pi0) newel0[i] = pinew; if(newel1[i] == pi1) newel1[i] = pinew; } new_elements.Append(newel0); new_elements.Append(newel1); } else if (np == 5) { // split pyramid into pyramid and two tets Element new_pyramid = old; new_pyramid[4] = pinew; new_elements.Append(new_pyramid); auto pibase = (pi0==old[4]) ? pi1 : pi0; auto pitop = (pi0==old[4]) ? pi0 : pi1; Element new_tet0 = old; Element new_tet1 = old; new_tet0.SetType(TET); new_tet1.SetType(TET); size_t pibase_index=0; for(auto i : Range(4)) if(old[i]==pibase) pibase_index = i; new_tet0[0] = old[(pibase_index+1)%4]; new_tet0[1] = old[(pibase_index+2)%4]; new_tet0[2] = pinew; new_tet0[3] = pitop; new_elements.Append(new_tet0); new_tet1[0] = old[(pibase_index+2)%4]; new_tet1[1] = old[(pibase_index+3)%4]; new_tet1[2] = pinew; new_tet1[3] = pitop; new_elements.Append(new_tet1); } return new_elements; } static double SplitElementBadness (const Mesh::T_POINTS & points, const MeshingParameters & mp, Element old, PointIndex pi0, PointIndex pi1, MeshPoint & pnew) { double badness = 0; auto np = old.GetNP(); PointIndex dummy{PointIndex::INVALID}; if(np == 4) { // Split tet into two tets badness += CalcBadReplacePoints ( points, mp, old, 0, pi0, dummy, pnew ); badness += CalcBadReplacePoints ( points, mp, old, 0, pi1, dummy, pnew ); } else if (np == 5) { // split pyramid into pyramid and two tets auto pibase = (pi0==old[4]) ? pi1 : pi0; auto pitop = (pi0==old[4]) ? pi0 : pi1; badness += CalcBadReplacePoints ( points, mp, old, 0, pitop, dummy, pnew ); Element tet = old; tet.SetType(TET); size_t pibase_index=0; for(auto i : Range(4)) if(old[i]==pibase) pibase_index = i; MeshPoint p[4]; p[0] = points[old[(pibase_index+1)%4]]; p[1] = points[old[(pibase_index+2)%4]]; p[2] = pnew; p[3] = points[pitop]; badness += CalcTetBadness (p[0], p[1], p[2], p[3], 0, mp); p[0] = points[old[(pibase_index+2)%4]]; p[1] = points[old[(pibase_index+3)%4]]; p[2] = pnew; p[3] = points[pitop]; badness += CalcTetBadness (p[0], p[1], p[2], p[3], 0, mp); } return badness; } tuple MeshOptimize3d :: UpdateBadness() { static Timer tbad("UpdateBadness"); RegionTimer reg(tbad); double totalbad = 0.0; double maxbad = 0.0; atomic bad_elements = 0; ParallelForRange(Range(mesh.GetNE()), [&] (auto myrange) { double totalbad_local = 0.0; double maxbad_local = 0.0; int bad_elements_local = 0; for (ElementIndex ei : myrange) { auto & el = mesh[ei]; if(mp.only3D_domain_nr && mp.only3D_domain_nr != el.GetIndex()) continue; if(!el.BadnessValid()) el.SetBadness(CalcBad(mesh.Points(), el, 0)); double bad = el.GetBadness(); totalbad_local += bad; maxbad_local = max(maxbad_local, bad); if(bad > min_badness) bad_elements_local++; } AtomicAdd(totalbad, totalbad_local); AtomicMax(maxbad, maxbad_local); bad_elements += bad_elements_local; }); return {totalbad, maxbad, bad_elements}; } bool MeshOptimize3d :: HasBadElement(FlatArray els) { for(auto ei : els) if(mesh[ei].GetBadness()>min_badness) return true; return false; } bool MeshOptimize3d :: HasIllegalElement(FlatArray els) { for(auto ei : els) if(!mesh.LegalTet(mesh[ei])) return true; return false; } bool MeshOptimize3d :: NeedsOptimization(FlatArray els) { if(goal == OPT_LEGAL) return HasIllegalElement(els); if(goal == OPT_QUALITY) return HasBadElement(els); return true; } /* 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. */ double MeshOptimize3d :: CombineImproveEdge ( Table & elements_of_point, PointIndex pi0, PointIndex pi1, FlatArray is_point_removed, bool check_only) { if (pi1 < pi0) Swap (pi0, pi1); if(is_point_removed[pi0] || is_point_removed[pi1]) return false; MeshPoint p0 = mesh[pi0]; MeshPoint p1 = mesh[pi1]; if (p1.Type() != INNERPOINT) return false; ArrayMem has_one_point; ArrayMem has_both_points; for (auto ei : elements_of_point[pi0] ) { Element & elem = mesh[ei]; if (elem.IsDeleted()) return false; if(elem.GetType() != TET) return false; // TODO: implement case where pi0 or pi1 is top of a pyramid if (elem[0] == pi1 || elem[1] == pi1 || elem[2] == pi1 || elem[3] == pi1) { if(!has_both_points.Contains(ei)) has_both_points.Append (ei); } else { if(!has_one_point.Contains(ei)) has_one_point.Append (ei); } } for (auto ei : elements_of_point[pi1] ) { Element & elem = mesh[ei]; if (elem.IsDeleted()) return false; if(elem.GetType() != TET) return false; // TODO: implement case where pi0 or pi1 is top of a pyramid if (elem[0] == pi0 || elem[1] == pi0 || elem[2] == pi0 || elem[3] == pi0) { ; } else { if(!has_one_point.Contains(ei)) has_one_point.Append (ei); } } double badness_old = 0.0; for (auto ei : has_one_point) badness_old += mesh[ei].GetBadness(); for (auto ei : has_both_points) badness_old += mesh[ei].GetBadness(); if (goal == OPT_CONFORM && p0.Type() <= EDGEPOINT) { // check if the optimization improves conformity with free segments std::set edges_before, edges_after; for (auto ei : has_one_point) { const auto el = mesh[ei]; for(auto i : Range(6)) { auto e0 = el[tetedges[i][0]]; auto e1 = el[tetedges[i][1]]; if(e0 == pi0 || e1 == pi0) edges_before.insert(e0 == pi0 ? e1 : e0); if(e0 == pi1 || e1 == pi1) edges_after.insert(e0 == pi1 ? e1 : e0); } } for(auto new_edge : edges_after) { if (edges_before.count(new_edge) == 0 && mesh[new_edge].Type() <= EDGEPOINT && mesh.BoundaryEdge (new_edge, pi0)) badness_old += GetLegalPenalty(); } } MeshPoint pnew = p0; if (p0.Type() == INNERPOINT) pnew = Center (p0, p1); ArrayMem one_point_badness(has_one_point.Size()); double badness_new = 0; for (auto i : Range(has_one_point)) { const Element & elem = mesh[has_one_point[i]]; double badness = CalcBadReplacePoints (mesh.Points(), mp, elem, 0, pi0, pi1, pnew); badness_new += badness; one_point_badness[i] = badness; } // Check if changed tets are topologically legal if (p0.Type() != INNERPOINT) { for (auto ei : has_one_point) { Element elem = mesh[ei]; // int l; for (int l = 0; l < 4; l++) if (elem[l] == pi1) { elem[l] = pi0; break; } elem.Touch(); if (!mesh.LegalTet(elem)) badness_new += GetLegalPenalty(); } } double d_badness = badness_new / has_one_point.Size() - badness_old / (has_one_point.Size()+has_both_points.Size()); // Do the actual combine operation if (d_badness < 0.0 && !check_only) { is_point_removed[pi1] = true; mesh[pi0] = pnew; for (auto ei : elements_of_point[pi1]) { Element & elem = mesh[ei]; if (elem.IsDeleted()) continue; for (int l = 0; l < elem.GetNP(); l++) if (elem[l] == pi1) elem[l] = pi0; elem.Touch(); if (!mesh.LegalTet (elem)) (*testout) << "illegal tet " << ei << endl; } for (auto i : Range(has_one_point)) mesh[has_one_point[i]].SetBadness(one_point_badness[i]); for (auto ei : has_both_points) { mesh[ei].Touch(); mesh[ei].Delete(); } } return d_badness; } void MeshOptimize3d :: CombineImprove () { static Timer t("MeshOptimize3d::CombineImprove"); RegionTimer reg(t); static Timer topt("Optimize"); static Timer tsearch("Search-combine"); static Timer tbuild_elements_table("Build elements table"); mesh.BuildBoundaryEdges(false); int np = mesh.GetNP(); int ne = mesh.GetNE(); int ntasks = 4*ngcore::TaskManager::GetNumThreads(); Array is_point_removed (np); is_point_removed = false; PrintMessage (3, "CombineImprove"); (*testout) << "Start CombineImprove" << "\n"; // mesh.CalcSurfacesOfNode (); const char * savetask = multithread.task; multithread.task = "Optimize Volume: Combine Improve"; UpdateBadness(); if (goal == OPT_QUALITY && testout->good()) { double totalbad = mesh.CalcTotalBad (mp); (*testout) << "Total badness = " << totalbad << endl; } auto elementsonnode = mesh.CreatePoint2ElementTable(nullopt, mp.only3D_domain_nr); Array> edges; BuildEdgeList(mesh, elementsonnode, edges); // Find edges with improvement Array> combine_candidate_edges(edges.Size()); std::atomic improvement_counter(0); tsearch.Start(); ParallelForRange(Range(edges), [&] (auto myrange) { for(auto i : myrange) { auto [p0,p1] = edges[i]; double d_badness = CombineImproveEdge (elementsonnode, p0, p1, is_point_removed, true); if(d_badness<0.0) { int index = improvement_counter++; combine_candidate_edges[index] = make_tuple(d_badness, i); } } }, ntasks); tsearch.Stop(); auto edges_with_improvement = combine_candidate_edges.Part(0, improvement_counter.load()); QuickSort(edges_with_improvement); PrintMessage(5, edges.Size(), " edges"); PrintMessage(5, edges_with_improvement.Size(), " edges with improvement"); // Apply actual optimizations topt.Start(); int cnt = 0; for(auto [d_badness, ei] : edges_with_improvement) { auto [p0,p1] = edges[ei]; if (CombineImproveEdge (elementsonnode, p0, p1, is_point_removed, false) < 0.0) cnt++; } topt.Stop(); mesh.Compress(); mesh.MarkIllegalElements(); PrintMessage (5, cnt, " elements combined"); (*testout) << "CombineImprove done" << "\n"; if (goal == OPT_QUALITY && testout->good()) { double totalbad = mesh.CalcTotalBad (mp); (*testout) << "Total badness = " << totalbad << endl; int cntill = 0; // for (ElementIndex ei = 0; ei < ne; ei++) for (ElementIndex ei : ngcore::T_Range(ne)) if(!(mesh.GetDimension()==3 && mp.only3D_domain_nr && mp.only3D_domain_nr != mesh.VolumeElement(ei).GetIndex())) if (!mesh.LegalTet (mesh[ei])) cntill++; PrintMessage (5, cntill, " illegal tets"); } multithread.task = savetask; } double MeshOptimize3d :: SplitImproveEdge (Table & elementsonnode, NgArray> &locfaces, double badmax, PointIndex pi1, PointIndex pi2, PointIndex ptmp, bool check_only) { double d_badness = 0.0; // int cnt = 0; ArrayMem hasbothpoints; if (mesh.BoundaryEdge (pi1, pi2)) return 0.0; for (ElementIndex ei : elementsonnode[pi1]) { Element & el = mesh[ei]; if(el.IsDeleted()) return 0.0; if (mesh[ei].GetType() != TET) return 0.0; bool has1 = el.PNums().Contains(pi1); bool has2 = el.PNums().Contains(pi2); if (has1 && has2) if (!hasbothpoints.Contains (ei)) hasbothpoints.Append (ei); } if(mp.only3D_domain_nr) for(auto ei : hasbothpoints) if(mp.only3D_domain_nr != mesh[ei].GetIndex()) return 0.0; if (!NeedsOptimization(hasbothpoints)) return 0.0; double bad1 = 0.0; double bad1_max = 0.0; for (ElementIndex ei : hasbothpoints) { double bad = mesh[ei].GetBadness(); bad1 += bad; bad1_max = max(bad1_max, bad); } if(bad1_max < 100.0) return 0.0; bool puretet = 1; for (ElementIndex ei : hasbothpoints) if (mesh[ei].GetType() != TET) puretet = 0; if (!puretet) return 0.0; Point3d p1 = mesh[pi1]; Point3d p2 = mesh[pi2]; locfaces.SetSize(0); for (ElementIndex ei : hasbothpoints) { const Element & el = mesh[ei]; for (int l = 0; l < 4; l++) if (el[l] == pi1 || el[l] == pi2) { PointIndices<3> i3; Element2d face(TRIG); el.GetFace (l+1, face); for (int kk = 0; kk < 3; kk++) i3[kk] = face[kk]; locfaces.Append (i3); } } PointFunction1 pf (mesh.Points(), locfaces, mp, -1); OptiParameters par; par.maxit_linsearch = 50; par.maxit_bfgs = 20; Point3d pnew = Center (p1, p2); Vector px(3); px(0) = pnew.X(); px(1) = pnew.Y(); px(2) = pnew.Z(); if (bad1_max > 0.1 * badmax) { int pok = pf.Func (px) < 1e10; if (!pok) pok = FindInnerPoint (mesh.Points(), locfaces, pnew); if(pok) { px(0) = pnew.X(); px(1) = pnew.Y(); px(2) = pnew.Z(); BFGS (px, pf, par); pnew.X() = px(0); pnew.Y() = px(1); pnew.Z() = px(2); } } double bad2 = pf.Func (px); for (int k = 0; k < hasbothpoints.Size(); k++) { Element & oldel = mesh[hasbothpoints[k]]; Element newel1 = oldel; Element newel2 = oldel; newel1.Touch(); newel2.Touch(); Point<3> pel1[4]; Point<3> pel2[4]; for (int l = 0; l < 4; l++) { pel1[l] = pel2[l] = mesh[oldel[l]]; if (newel1[l] == pi2) { newel1[l] = ptmp; pel1[l] = pnew; } if (newel2[l] == pi1) { newel2[l] = ptmp; pel2[l] = pnew; } } if (!mesh.LegalTet (oldel)) return 0.0; if (!mesh.LegalTet (newel1)) return 0.0; if (!mesh.LegalTet (newel2)) return 0.0; if( WrongOrientation(pel1[0], pel1[1], pel1[2], pel1[3]) || WrongOrientation(pel2[0], pel2[1], pel2[2], pel2[3]) ) return 0.0; } if(bad2 >= 1e24) return 0.0; d_badness = bad2-bad1; if(check_only) return d_badness; if (d_badness<0.0) { // cnt++; PointIndex pinew = mesh.AddPoint (pnew); for (ElementIndex ei : hasbothpoints) { Element & oldel = mesh[ei]; Element newel1 = oldel; Element newel2 = oldel; newel1.Touch(); newel2.Touch(); for (int l = 0; l < 4; l++) { if (newel1[l] == pi2) newel1[l] = pinew; if (newel2[l] == pi1) newel2[l] = pinew; } oldel.Touch(); oldel.Delete(); mesh.AddVolumeElement (newel1); mesh.AddVolumeElement (newel2); } } return d_badness; } void MeshOptimize3d :: SplitImprove () { static Timer t("MeshOptimize3d::SplitImprove"); RegionTimer reg(t); static Timer topt("Optimize"); static Timer tsearch("Search-split"); // int np = mesh.GetNP(); int ne = mesh.GetNE(); double bad = 0.0; double badmax = 0.0; auto elementsonnode = mesh.CreatePoint2ElementTable(nullopt, mp.only3D_domain_nr); const char * savetask = multithread.task; multithread.task = "Optimize Volume: Split Improve"; PrintMessage (3, "SplitImprove"); (*testout) << "start SplitImprove" << "\n"; mesh.BuildBoundaryEdges(false); UpdateBadness(); if (goal == OPT_QUALITY && testout->good()) { bad = mesh.CalcTotalBad (mp); (*testout) << "Total badness = " << bad << endl; } Array> edges; BuildEdgeList(mesh, elementsonnode, edges); // Find edges with improvement Array> candidate_edges(edges.Size()); std::atomic improvement_counter(0); auto ptmp = mesh.AddPoint( {0,0,0} ); tsearch.Start(); ParallelForRange(Range(edges), [&] (auto myrange) { NgArray> locfaces; for(auto i : myrange) { auto [p0,p1] = edges[i]; double d_badness = SplitImproveEdge (elementsonnode, locfaces, badmax, p0, p1, ptmp, true); if(d_badness<0.0) { int index = improvement_counter++; candidate_edges[index] = make_tuple(d_badness, i); } } }, ngcore::TasksPerThread(4)); tsearch.Stop(); auto edges_with_improvement = candidate_edges.Part(0, improvement_counter.load()); QuickSort(edges_with_improvement); PrintMessage(5, edges.Size(), " edges"); PrintMessage(5, edges_with_improvement.Size(), " edges with improvement"); // Apply actual optimizations topt.Start(); int cnt = 0; NgArray> locfaces; for(auto [d_badness, ei] : edges_with_improvement) { auto [p0,p1] = edges[ei]; if (SplitImproveEdge (elementsonnode, locfaces, badmax, p0, p1, ptmp, false) < 0.0) cnt++; } topt.Stop(); mesh.Compress(); PrintMessage (5, cnt, " splits performed"); (*testout) << "Splitt - Improve done" << "\n"; if (goal == OPT_QUALITY) { if(testout->good()) { bad = mesh.CalcTotalBad (mp); (*testout) << "Total badness = " << bad << endl; } [[maybe_unused]] int cntill = 0; ne = mesh.GetNE(); // for (ElementIndex ei = 0; ei < ne; ei++) for (auto ei : ngcore::T_Range(ne)) if (!mesh.LegalTet (mesh[ei])) cntill++; // cout << cntill << " illegal tets" << endl; } multithread.task = savetask; } double MeshOptimize3d :: SwapImproveEdge ( const TBitArray * working_elements, Table & elementsonnode, INDEX_3_HASHTABLE & faces, PointIndex pi1, PointIndex pi2, bool check_only) { ArrayMem hasbothpoints; double d_badness = 0.0; if (pi2 < pi1) Swap (pi1, pi2); if (mesh.BoundaryEdge (pi1, pi2)) return 0.0; hasbothpoints.SetSize (0); for (ElementIndex elnr : elementsonnode[pi1]) { bool has1 = 0, has2 = 0; const Element & elem = mesh[elnr]; if (elem.IsDeleted()) return 0.0; 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 if (hasbothpoints.Contains (elnr)) has1 = false; if (has1) { hasbothpoints.Append (elnr); } } } for (ElementIndex ei : hasbothpoints) { if (mesh[ei].GetType () != TET) return 0.0; if (mp.only3D_domain_nr && mp.only3D_domain_nr != mesh.VolumeElement(ei).GetIndex()) return 0.0; if ((mesh.ElementType(ei)) == FIXEDELEMENT) return 0.0; if(working_elements && ei < working_elements->Size() && !working_elements->Test(ei)) return 0.0; if (mesh[ei].IsDeleted()) return 0.0; if(WrongOrientation(mesh.Points(), mesh[ei])) return 0.0; } if(!NeedsOptimization(hasbothpoints)) return 0.0; int nsuround = hasbothpoints.Size(); int mattyp = mesh[hasbothpoints[0]].GetIndex(); /* // unused ? auto fix_orientation = [&] (Element & el) { if (WrongOrientation (mesh.Points(), el)) el.Invert(); }; */ auto El = [&] ( PointIndex pi0, PointIndex pi1, PointIndex pi2, PointIndex pi3) -> Element { Element el(TET); el[0] = pi0; el[1] = pi1; el[2] = pi2; el[3] = pi3; el.SetIndex (mattyp); // fix_orientation(el); return el; }; auto combined_badness = [&] (std::initializer_list els, bool apply_illegal_penalty = true) { double bad = 0.0; bool have_illegal = false; for (auto el : els) { bad += CalcBad(mesh.Points(), el, 0); if(apply_illegal_penalty && !have_illegal) { el.Touch(); have_illegal = !mesh.LegalTet(el); } } if(have_illegal && apply_illegal_penalty) bad += GetLegalPenalty(); return bad; }; if ( nsuround == 3 ) { PointIndex pi3(PointIndex::INVALID), pi4(PointIndex::INVALID), pi5(PointIndex::INVALID); Element & elem = mesh[hasbothpoints[0]]; for (int l = 0; l < 4; l++) if (elem[l] != pi1 && elem[l] != pi2) { pi4 = pi3; pi3 = elem[l]; } auto el31 = El(pi1, pi2, pi3, pi4); if (WrongOrientation (mesh.Points(), el31)) { Swap (pi3, pi4); el31[2] = pi3; el31[3] = pi4; } pi5.Invalidate(); for (int k = 0; k < 3; k++) // JS, 201212 { const Element & elemk = mesh[hasbothpoints[k]]; bool has1 = false; for (int l = 0; l < 4; l++) if (elemk[l] == pi4) has1 = true; if (has1) { for (int l = 0; l < 4; l++) if (elemk[l] != pi1 && elemk[l] != pi2 && elemk[l] != pi4) pi5 = elemk[l]; } } if (!pi5.IsValid()) throw NgException("Illegal state observed in SwapImprove"); auto el32 = El(pi1, pi2, pi4, pi5); auto el33 = El(pi1, pi2, pi5, pi3); auto el21 = El(pi3, pi4, pi5, pi2); auto el22 = El(pi5, pi4, pi3, pi1); double bad1 = combined_badness({el31, el32, el33}); double bad2 = combined_badness({el21, el22}); if ((goal == OPT_CONFORM) && NotTooBad(bad1, bad2)) { PointIndices<3> face(pi3, pi4, pi5); face.Sort(); if (faces.Used(face)) { // (*testout) << "3->2 swap, could improve conformity, bad1 = " << bad1 // << ", bad2 = " << bad2 << endl; bad2 = bad1 + IMPROVEMENT_CONFORMING_EDGE; } } if (bad2 < bad1) { // (*mycout) << "3->2 " << flush; // (*testout) << "3->2 conversion" << endl; d_badness = bad2-bad1; if(check_only) return d_badness; /* (*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; */ mesh[hasbothpoints[0]].Delete(); mesh[hasbothpoints[1]].Delete(); mesh[hasbothpoints[2]].Delete(); mesh.AddVolumeElement(el21); mesh.AddVolumeElement(el22); } } if (nsuround == 4) { PointIndex pi3(PointIndex::INVALID), pi4(PointIndex::INVALID); PointIndex pi5(PointIndex::INVALID), pi6(PointIndex::INVALID); 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]; } auto el1 = El(pi1, pi2, pi3, pi4); if (WrongOrientation (mesh.Points(), el1)) { Swap (pi3, pi4); el1[2] = pi3; el1[3] = pi4; } pi5.Invalidate(); for (int k = 0; k < 4; k++) { const Element & elem = mesh[hasbothpoints[k]]; bool has1 = elem.PNums().Contains(pi4); if (has1) { for (int l = 0; l < 4; l++) if (elem[l] != pi1 && elem[l] != pi2 && elem[l] != pi4) pi5 = elem[l]; } } pi6.Invalidate(); for (int k = 0; k < 4; k++) { const Element & elem = mesh[hasbothpoints[k]]; bool has1 = elem.PNums().Contains(pi3); if (has1) { for (int l = 0; l < 4; l++) if (elem[l] != pi1 && elem[l] != pi2 && elem[l] != pi3) pi6 = elem[l]; } } el1 = El(pi1, pi2, pi3, pi4); auto el2 = El(pi1, pi2, pi4, pi5); auto el3 = El(pi1, pi2, pi5, pi6); auto el4 = El(pi1, pi2, pi6, pi3); double bad1 = combined_badness({el1, el2, el3, el4}, goal != OPT_CONFORM); el1 = El(pi3, pi5, pi2, pi4); el2 = El(pi3, pi5, pi4, pi1); el3 = El(pi3, pi5, pi1, pi6); el4 = El(pi3, pi5, pi6, pi2); double bad2 = combined_badness({el1, el2, el3, el4}, goal != OPT_CONFORM); auto el1b = El(pi4, pi6, pi3, pi2); auto el2b = El(pi4, pi6, pi2, pi5); auto el3b = El(pi4, pi6, pi5, pi1); auto el4b = El(pi4, pi6, pi1, pi3); double bad3 = combined_badness({el1b, el2b, el3b, el4b}, goal != OPT_CONFORM); bool swap2=false; bool swap3=false; if (goal == OPT_CONFORM) { swap2 = mesh.BoundaryEdge (pi3, pi5) && NotTooBad(bad1, bad2); swap3 = mesh.BoundaryEdge (pi4, pi6) && NotTooBad(bad1, bad3); if(swap2 || swap3) d_badness = IMPROVEMENT_CONFORMING_EDGE; } if (goal != OPT_CONFORM || (!swap2 && !swap3)) { swap2 = (bad2 < bad1) && (bad2 < bad3); swap3 = !swap2 && (bad3 < bad1); d_badness = swap2 ? bad2-bad1 : bad3-bad1; } if(check_only) return d_badness; if (swap2) { for (auto i : IntRange(4)) mesh[hasbothpoints[i]].Delete(); mesh.AddVolumeElement (el1); mesh.AddVolumeElement (el2); mesh.AddVolumeElement (el3); mesh.AddVolumeElement (el4); } else if (swap3) { for (auto i : IntRange(4)) mesh[hasbothpoints[i]].Delete(); mesh.AddVolumeElement (el1b); mesh.AddVolumeElement (el2b); mesh.AddVolumeElement (el3b); mesh.AddVolumeElement (el4b); } } // if (goal == OPT_QUALITY) if (nsuround >= 5) { PointIndex pi3(PointIndex::INVALID), pi4(PointIndex::INVALID); NgArrayMem suroundpts(nsuround); NgArrayMem 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]; } if (WrongOrientation (mesh.Points(), El(pi1, pi2, pi3, pi4))) Swap (pi3, pi4); // suroundpts.SetSize (nsuround); suroundpts = PointIndex::INVALID; suroundpts[0] = pi3; suroundpts[1] = pi4; tetused = false; tetused[0] = true; for (int l = 2; l < nsuround; l++) { PointIndex oldpi = suroundpts[l-1]; PointIndex newpi; newpi.Invalidate(); for (int k = 0; k < nsuround && !newpi.IsValid(); k++) if (!tetused[k]) { const Element & nel = mesh[hasbothpoints[k]]; for (int k2 = 0; k2 < 4 && !newpi.IsValid(); k2++) if (nel[k2] == oldpi) { newpi = nel[0] - pi1 + nel[1] - pi2 + nel[2] - oldpi + nel[3]; tetused[k] = true; suroundpts[l] = newpi; } } } double bad1 = 0; for (auto k : Range(nsuround)) bad1 += CalcBad (mesh.Points(), El(pi1, pi2, suroundpts[k], suroundpts[(k+1) % nsuround]), 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++) { double bad2 = 0; for (int k = l+1; k <= nsuround + l - 2; k++) { PointIndex pil = suroundpts[l]; PointIndex pik0 = suroundpts[k % nsuround]; PointIndex pik1 = suroundpts[(k+1) % nsuround]; bad2 += combined_badness({El(pil, pik0, pik1, pi2)}); bad2 += combined_badness({El(pil, pik1, pik0, pi1)}); } // (*testout) << "bad2," << l << " = " << bad2 << endl; if ( bad2 < badopt ) { bestl = l; badopt = bad2; } if (goal == OPT_CONFORM) { bool nottoobad = NotTooBad(bad1, bad2); for (int k = l+1; k <= nsuround + l - 2; k++) { PointIndices<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(confface != -1 || confedge != -1) badopt = bad1 + IMPROVEMENT_CONFORMING_EDGE; if (bestl != -1) { // (*mycout) << nsuround << "->" << 2 * (nsuround-2) << " " << flush; d_badness = badopt-bad1; if(check_only) return d_badness; for (int k = bestl+1; k <= nsuround + bestl - 2; k++) { // int k1; PointIndex pi = suroundpts[bestl]; PointIndex pik0 = suroundpts[k % nsuround]; PointIndex pik1 = suroundpts[(k+1) % nsuround]; auto el = El(pi, pik0, pik1, pi2); /* (*testout) << nsuround << "-swap, new el,top = " << el << endl; */ mesh.AddVolumeElement (el); el = El(pi, pik1, pik0, pi1); /* (*testout) << nsuround << "-swap, new el,bot = " << el << endl; */ mesh.AddVolumeElement (el); } 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].Invalidate(); } } } return d_badness; } void MeshOptimize3d :: SwapImprove (const TBitArray * working_elements) { static Timer t("MeshOptimize3d::SwapImprove"); RegionTimer reg(t); static Timer tloop("MeshOptimize3d::SwapImprove loop"); int cnt = 0; // int np = mesh.GetNP(); // int ne = mesh.GetNE(); mesh.BuildBoundaryEdges(false); TBitArray free_points(mesh.GetNP()); free_points.Clear(); ParallelForRange(mesh.VolumeElements().Range(), [&] (auto myrange) { for (ElementIndex eli : myrange) { const auto & el = mesh[eli]; if(el.Flags().fixed || el.GetType() != TET) continue; if(mp.only3D_domain_nr && mp.only3D_domain_nr != el.GetIndex()) continue; for (auto pi : el.PNums()) if(!free_points[pi]) free_points.SetBitAtomic(pi); } }); auto elementsonnode = mesh.CreatePoint2ElementTable(free_points, mp.only3D_domain_nr ); NgArray hasbothpoints; PrintMessage (3, "SwapImprove "); (*testout) << "\n" << "Start SwapImprove" << endl; const char * savetask = multithread.task; multithread.task = "Optimize Volume: Swap Improve"; INDEX_3_HASHTABLE faces(mesh.GetNOpenElements()/3 + 2); if (goal == OPT_CONFORM) { for (int i = 1; i <= mesh.GetNOpenElements(); i++) { const Element2d & hel = mesh.OpenElement(i); PointIndices<3> face(hel[0], hel[1], hel[2]); face.Sort(); faces.Set (face, i); } } // Calculate total badness if (goal == OPT_QUALITY && testout->good()) { double bad1 = mesh.CalcTotalBad (mp); (*testout) << "Total badness = " << bad1 << endl; } Array> edges; BuildEdgeList(mesh, elementsonnode, edges); Array> candidate_edges(edges.Size()); std::atomic improvement_counter(0); UpdateBadness(); tloop.Start(); auto num_elements_before = mesh.VolumeElements().Range().Next(); ParallelForRange(Range(edges), [&] (auto myrange) { for(auto i : myrange) { if (multithread.terminate) break; auto [pi0, pi1] = edges[i]; double d_badness = SwapImproveEdge (working_elements, elementsonnode, faces, pi0, pi1, true); if(d_badness<0.0) { int index = improvement_counter++; candidate_edges[index] = make_tuple(d_badness, i); } } }, TasksPerThread (4)); auto edges_with_improvement = candidate_edges.Part(0, improvement_counter.load()); QuickSort(edges_with_improvement); for(auto [d_badness, ei] : edges_with_improvement) { auto [pi0,pi1] = edges[ei]; if(SwapImproveEdge (working_elements, elementsonnode, faces, pi0, pi1, false) < 0.0) cnt++; } tloop.Stop(); PrintMessage (5, cnt, " swaps performed"); if(goal == OPT_CONFORM) { // Remove open elements that were closed by new tets auto & open_els = mesh.OpenElements(); for (auto & el : mesh.VolumeElements().Range( num_elements_before, mesh.VolumeElements().Range().Next() )) { for (auto i : Range(1,5)) { Element2d sel; el.GetFace(i, sel); PointIndices<3> face(sel[0], sel[1], sel[2]); face.Sort(); if(faces.Used(face)) open_els[faces.Get(face)-1].Delete(); } } for(int i=open_els.Size()-1; i>=0; i--) if(open_els[i].IsDeleted()) open_els.Delete(i); mesh.DeleteBoundaryEdges(); } mesh.Compress (); multithread.task = savetask; } void MeshOptimize3d :: SwapImproveSurface ( const TBitArray * working_elements, const NgArray< idmap_type* > * idmaps) { NgArray< idmap_type* > locidmaps; const NgArray< idmap_type* > * 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 idmap_type); 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 DynamicTable elementsonnode(np); DynamicTable surfaceelementsonnode(np); DynamicTable surfaceindicesonnode(np); NgArray hasbothpoints; NgArray 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 edgeused(2 * ne + 5); INDEX_2_CLOSED_HASHTABLE 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])) 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 pi1 = elemi[tetedges[j][0]]; pi2 = elemi[tetedges[j][1]]; if (pi2 < pi1) Swap (pi1, pi2); bool found = false; for(int k=0; !found && kSize(); k++) { if(pi2 < (*used_idmaps)[k]->Size() + IndexBASE()) { pi1other = (*(*used_idmaps)[k])[pi1]; pi2other = (*(*used_idmaps)[k])[pi2]; found = (pi1other.IsValid() && pi2other.IsValid() && 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; PointIndices<2> i2 (pi1, pi2); i2.Sort(); if (edgeused.Used(i2)) continue; edgeused.Set (i2, 1); if(periodic) { i2[0] = pi1other; i2[1] = 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 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(); NgArray < PointIndex > outerpoints(nsuround+1); outerpoints[0] = sp1; for(int i=0; i outerpointsother; if(nsuroundother > 0) { outerpointsother.SetSize(nsuroundother+1); outerpointsother[0] = sp2other; } for(int i=0; i 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 * > newelts(startpoints); NgArray < NgArray < 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(2*(nsuround-1)); for(int jj=0; jjSize(); jj++) wrongorientation = wrongorientation && WrongOrientation(mesh.Points(), *(*newelts[i])[jj]); currbad = 0; for(int jj=0; jjSize(); jj++) { if(wrongorientation) Swap((*(*newelts[i])[jj])[2],(*(*newelts[i])[jj])[3]); // not two new faces on same surface NgArray face_index; for(int k = 0; kSize()); if(currbad < minbad) { minbad = currbad; minpos = i; } } if(startpointsother == 0) minbadother = 0; for(int i=0; i(2*(nsuroundother)); for(int jj=0; jjSize(); jj++) wrongorientation = wrongorientation && WrongOrientation(mesh.Points(), *(*neweltsother[i])[jj]); currbad = 0; for(int jj=0; jjSize(); 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 0) { for(int i=0; iSize(); jj++) delete (*newelts[i])[jj]; delete newelts[i]; } for(int i=0; iSize(); jj++) delete (*neweltsother[i])[jj]; delete neweltsother[i]; } } } PrintMessage (5, cnt, " swaps performed"); for(int i=0; i 3 conversion */ double MeshOptimize3d :: SwapImprove2 ( ElementIndex eli1, int face, Table & elementsonnode, DynamicTable & belementsonnode, bool conform_segments, bool check_only ) { PointIndex pi1, pi2, pi3, pi4, pi5; Element el21(TET), el22(TET), el31(TET), el32(TET), el33(TET); int j = face; double bad1, bad2; double d_badness = 0.0; Element & elem = mesh[eli1]; if (elem.IsDeleted()) return 0.0; 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; } if(!conform_segments) { 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) return 0.0; } FlatArray row = elementsonnode[pi1]; for(auto ei : row) if (mesh[ei].IsDeleted()) return 0.0; for(auto ei : elementsonnode[pi2]) if (mesh[ei].IsDeleted()) return 0.0; for(auto ei : elementsonnode[pi3]) if (mesh[ei].IsDeleted()) return 0.0; for(auto ei : elementsonnode[pi4]) if (mesh[ei].IsDeleted()) return 0.0; for (int k = 0; k < row.Size(); k++) { ElementIndex eli2 = row[k]; if ( eli1 != eli2 ) { Element & elem2 = mesh[eli2]; if (elem2.GetType() != TET) continue; ArrayMem elis = {eli1, eli2}; if(!NeedsOptimization(elis)) 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 = elem.GetBadness() + elem2.GetBadness(); if (!mesh.LegalTet(elem) || !mesh.LegalTet(elem2)) bad1 += GetLegalPenalty(); if(mesh.BoundaryEdge (pi4, pi5)) bad1 += GetLegalPenalty(); 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.Touch(); el32.Touch(); el33.Touch(); if (!mesh.LegalTet(el31) || !mesh.LegalTet(el32) || !mesh.LegalTet(el33)) bad2 += GetLegalPenalty(); d_badness = bad2 - bad1; if ( ((bad2 < 1e6) || (bad2 < 10 * bad1)) && mesh.BoundaryEdge (pi4, pi5)) d_badness = -1e4; if(check_only) return d_badness; if (d_badness<0.0) { el31.Touch(); el32.Touch(); el33.Touch(); mesh[eli1].Delete(); mesh[eli2].Delete(); mesh.AddVolumeElement (el31); mesh.AddVolumeElement (el32); mesh.AddVolumeElement (el33); } return d_badness; } } } return d_badness; } /* 2 -> 3 conversion */ void MeshOptimize3d :: SwapImprove2 (bool conform_segments) { static Timer t("MeshOptimize3d::SwapImprove2"); RegionTimer reg(t); if (!conform_segments && goal == OPT_CONFORM) return; mesh.BuildBoundaryEdges(false); int cnt = 0; // double bad1, bad2; int np = mesh.GetNP(); int ne = mesh.GetNE(); int nse = mesh.GetNSE(); // contains at least all elements at node DynamicTable belementsonnode(np); PrintMessage (3, "SwapImprove2 "); (*testout) << "\n" << "Start SwapImprove2" << "\n"; if(testout->good()) { double bad1 = mesh.CalcTotalBad (mp); (*testout) << "Total badness = " << bad1 << endl; } // find elements on node auto elementsonnode = mesh.CreatePoint2ElementTable(nullopt, mp.only3D_domain_nr); // todo: respect mp.only3D_domain_nr for (SurfaceElementIndex sei = 0; sei < nse; sei++) for (int j = 0; j < 3; j++) belementsonnode.Add (mesh[sei][j], sei); int num_threads = ngcore::TaskManager::GetNumThreads(); Array> faces_with_improvement; Array>> faces_with_improvement_threadlocal(num_threads); UpdateBadness(); ParallelForRange( Range(ne), [&]( auto myrange ) { int tid = ngcore::TaskManager::GetThreadId(); auto & my_faces_with_improvement = faces_with_improvement_threadlocal[tid]; for (ElementIndex eli1 : myrange) { if (multithread.terminate) break; if (mesh.ElementType (eli1) == FIXEDELEMENT) continue; if (mesh[eli1].GetType() != TET) continue; if (goal == OPT_LEGAL && mesh.LegalTet (mesh[eli1])) continue; if(mesh.GetDimension()==3 && mp.only3D_domain_nr && mp.only3D_domain_nr != mesh.VolumeElement(eli1).GetIndex()) continue; for (int j = 0; j < 4; j++) { double d_badness = SwapImprove2( eli1, j, elementsonnode, belementsonnode, conform_segments, true); if(d_badness<0.0) my_faces_with_improvement.Append( std::make_tuple(d_badness, eli1, j) ); } } }); for (auto & a : faces_with_improvement_threadlocal) faces_with_improvement.Append(a); QuickSort(faces_with_improvement); for (auto [dummy, eli,j] : faces_with_improvement) { if(mesh[eli].IsDeleted()) continue; if(SwapImprove2( eli, j, elementsonnode, belementsonnode, conform_segments, false) < 0.0) cnt++; } PrintMessage (5, cnt, " swaps performed"); mesh.Compress(); if(testout->good()) { double bad1 = mesh.CalcTotalBad (mp); (*testout) << "Total badness = " << bad1 << endl; (*testout) << "swapimprove2 done" << "\n"; } } double MeshOptimize3d :: SplitImprove2Element ( ElementIndex ei, const Table & elements_of_point, bool check_only) { auto & el = mesh[ei]; if(el.GetType() != TET) return false; // Optimize only bad elements if(el.GetBadness() < 100) return false; // search for very flat tets, with two disjoint edges nearly crossing, like a rectangle with diagonals int minedge = -1; double mindist = 1e99; double minlam0=0, minlam1=0; for (int i : Range(3)) { auto pi0 = el[tetedges[i][0]]; auto pi1 = el[tetedges[i][1]]; auto pi2 = el[tetedges[5-i][0]]; auto pi3 = el[tetedges[5-i][1]]; double lam0, lam1; double dist = MinDistLL2(mesh[pi0], mesh[pi1], mesh[pi2], mesh[pi3], lam0, lam1 ); if(dist has_both_points0; ArrayMem has_both_points1; Point3d p[4] = { mesh[el[0]], mesh[el[1]], mesh[el[2]], mesh[el[3]] }; auto center = Center(p[0]+minlam0*(p[1]-p[0]), p[2]+minlam1*(p[3]-p[2])); MeshPoint pnew; pnew(0) = center.X(); pnew(1) = center.Y(); pnew(2) = center.Z(); // find all tets with edge (pi0,pi1) or (pi2,pi3) for (auto ei0 : elements_of_point[pi0] ) { Element & elem = mesh[ei0]; if (elem.IsDeleted()) return false; if (ei0 == ei) continue; if (elem.GetType() != TET) return false; if (elem[0] == pi1 || elem[1] == pi1 || elem[2] == pi1 || elem[3] == pi1 || (elem.GetNP()==5 && elem[4]==pi1) ) if(!has_both_points0.Contains(ei0)) has_both_points0.Append (ei0); } for (auto ei1 : elements_of_point[pi2] ) { Element & elem = mesh[ei1]; if (elem.IsDeleted()) return false; if (ei1 == ei) continue; if (elem.GetType() != TET) return false; if (elem[0] == pi3 || elem[1] == pi3 || elem[2] == pi3 || elem[3] == pi3 || (elem.GetNP()==5 && elem[4]==pi3)) if(!has_both_points1.Contains(ei1)) has_both_points1.Append (ei1); } double badness_before = mesh[ei].GetBadness(); double badness_after = 0.0; for (auto ei0 : has_both_points0) { if(mesh[ei0].GetType()!=TET) return false; badness_before += mesh[ei0].GetBadness(); badness_after += SplitElementBadness (mesh.Points(), mp, mesh[ei0], pi0, pi1, pnew); } for (auto ei1 : has_both_points1) { if(mesh[ei1].GetType()!=TET) return false; badness_before += mesh[ei1].GetBadness(); badness_after += SplitElementBadness (mesh.Points(), mp, mesh[ei1], pi2, pi3, pnew); } if(check_only) return badness_after-badness_before; if(badness_after new point where diagonals cross, remove the flat tet void MeshOptimize3d :: SplitImprove2 () { static Timer t("MeshOptimize3d::SplitImprove2"); RegionTimer reg(t); static Timer tsearch("Search"); static Timer topt("Optimize"); int ne = mesh.GetNE(); auto elements_of_point = mesh.CreatePoint2ElementTable(nullopt, mp.only3D_domain_nr); int ntasks = 4*ngcore::TaskManager::GetNumThreads(); const char * savetask = multithread.task; multithread.task = "Optimize Volume: Split Improve 2"; UpdateBadness(); mesh.BuildBoundaryEdges(false); Array> split_candidates(ne); std::atomic improvement_counter(0); tsearch.Start(); ParallelForRange(Range(ne), [&] (auto myrange) { for(ElementIndex ei : myrange) { if(mp.only3D_domain_nr && mp.only3D_domain_nr != mesh[ei].GetIndex()) continue; double d_badness = SplitImprove2Element(ei, elements_of_point, true); if(d_badness<0.0) { int index = improvement_counter++; split_candidates[index] = make_tuple(d_badness, ei); } } }, ntasks); tsearch.Stop(); auto elements_with_improvement = split_candidates.Part(0, improvement_counter.load()); QuickSort(elements_with_improvement); size_t cnt = 0; topt.Start(); for(auto [d_badness, ei] : elements_with_improvement) { if( SplitImprove2Element(ei, elements_of_point, false) < 0.0) cnt++; } topt.Stop(); PrintMessage (5, cnt, " elements split"); (*testout) << "SplitImprove2 done" << "\n"; if(cnt>0) mesh.Compress(); multithread.task = savetask; } /* 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 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); // } } } NgBitArray 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"; } */ } ================================================ FILE: libsrc/meshing/improve3.hpp ================================================ #ifndef FILE_IMPROVE3 #define FILE_IMPROVE3 namespace netgen { /// class MeshOptimize3d { Mesh & mesh; const MeshingParameters & mp; OPTIMIZEGOAL goal = OPT_QUALITY; double min_badness = 0; bool HasBadElement(FlatArray els); bool HasIllegalElement(FlatArray els); bool NeedsOptimization(FlatArray els); public: MeshOptimize3d (Mesh & m, const MeshingParameters & amp, OPTIMIZEGOAL agoal = OPT_QUALITY) : mesh(m), mp(amp), goal(agoal) { ; } void SetGoal(OPTIMIZEGOAL agoal) { goal = agoal; } void SetMinBadness(double badness) { min_badness = badness; } tuple UpdateBadness(); double CombineImproveEdge ( Table & elements_of_point, PointIndex pi0, PointIndex pi1, FlatArray is_point_removed, bool check_only=false); void CombineImprove (); void SplitImprove (); double SplitImproveEdge (Table & elementsonnode, NgArray> &locfaces, double badmax, PointIndex pi1, PointIndex pi2, PointIndex ptmp, bool check_only=false); void SplitImprove2 (); double SplitImprove2Element (ElementIndex ei, const Table & elements_of_point, bool check_only); double SwapImproveEdge (const TBitArray * working_elements, Table & elementsonnode, INDEX_3_HASHTABLE & faces, PointIndex pi1, PointIndex pi2, bool check_only=false); void SwapImprove (const TBitArray * working_elements = NULL); void SwapImproveSurface (const TBitArray * working_elements = NULL, const NgArray< idmap_type* > * idmaps = NULL); void SwapImprove2 (bool conform_segments = false); double SwapImprove2 (ElementIndex eli1, int face, Table & elementsonnode, DynamicTable & belementsonnode, bool conform_segments, bool check_only=false ); void ImproveMesh() { mesh.ImproveMesh(mp, goal); } 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 GetLegalPenalty() { return goal == OPT_LEGAL ? 1e15 : 1e6; } }; 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: NgArray 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 NgArray> & faces; const MeshingParameters & mp; double h; public: PointFunction1 (Mesh::T_POINTS & apoints, const NgArray> & 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 Array & elements; TABLE elementsonpoint; PointIndex actpind; bool onplane; Vec<3> nv; public: JacobianPointFunction (Mesh::T_POINTS & apoints, const Array & aelements); virtual ~JacobianPointFunction () { ; } 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;} }; } // namespace netgen #endif ================================================ FILE: libsrc/meshing/localh.cpp ================================================ #include #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]); flags.cutboundary = 0; flags.isinner = 0; flags.oldcell = 0; flags.pinner = 0; hopt = 2 * h2; } void GradingBox :: DoArchive(Archive& ar) { ar & xmid[0] & xmid[1] & xmid[2] & h2 & father & hopt & flags.cutboundary & flags.isinner & flags.oldcell & flags.pinner; for(auto i : Range(8)) ar & childs[i]; } 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 (Point<3> pmin, Point<3> pmax, double agrading, int adimension) : dimension(adimension) { double x1[3], x2[3]; double hmax; boundingbox = Box<3> (pmin, pmax); grading = agrading; // a small enlargement, non-regular points double val = 0.0879; for (int i = 0; i < dimension; i++) { x1[i] = (1 + val * (i+1)) * pmin(i) - val * (i+1) * pmax(i); x2[i] = 1.1 * pmax(i) - 0.1 * pmin(i); } for (int i = dimension; i < 3; i++) x1[i] = x2[i] = 0; hmax = x2[0] - x1[0]; for (int i = 1; i < dimension; i++) hmax = max2(x2[i]-x1[i], hmax); for (int i = 0; i < dimension; i++) x2[i] = x1[i] + hmax; root = new GradingBox (x1, x2); boxes.Append (root); } LocalH :: ~LocalH () { root->DeleteChilds(); delete root; } unique_ptr LocalH :: Copy () { static Timer t("LocalH::Copy"); RegionTimer rt(t); auto lh = make_unique(boundingbox, grading, dimension); std::map mapping; lh->boxes.SetSize(boxes.Size()); for(auto i : boxes.Range()) { lh->boxes[i] = new GradingBox(); auto & bnew = *lh->boxes[i]; auto & b = *boxes[i]; bnew.xmid[0] = b.xmid[0]; bnew.xmid[1] = b.xmid[1]; bnew.xmid[2] = b.xmid[2]; bnew.h2 = b.h2; bnew.hopt = b.hopt; bnew.flags = b.flags; mapping[&b] = &bnew; } for(auto i : boxes.Range()) { auto & bnew = *lh->boxes[i]; auto & b = *boxes[i]; for(auto k : Range(8)) { if(b.childs[k]) bnew.childs[k] = mapping[b.childs[k]]; } if(b.father) bnew.father = mapping[b.father]; } lh->root = mapping[root]; return lh; } unique_ptr LocalH :: Copy( const Box<3> & bbox ) { static Timer t("LocalH::Copy with bounding box"); RegionTimer rt(t); auto lh = make_unique(boundingbox, grading, dimension); std::map mapping; lh->boxes.SetAllocSize(boxes.Size()); for(auto i : boxes.Range()) { auto & b = *boxes[i]; auto h = b.H2(); Vec<3> vh = {h,h,h}; Box<3> box( b.PMid() - vh, b.PMid() + vh); if(!box.Intersect(bbox)) continue; lh->boxes.Append(new GradingBox()); auto & bnew = *lh->boxes.Last(); bnew.xmid[0] = b.xmid[0]; bnew.xmid[1] = b.xmid[1]; bnew.xmid[2] = b.xmid[2]; bnew.h2 = b.h2; bnew.hopt = b.hopt; bnew.flags = b.flags; mapping[&b] = &bnew; } for(auto i : boxes.Range()) { auto & b = *boxes[i]; if(mapping.count(&b)==0) continue; auto & bnew = *mapping[&b]; for(auto k : Range(8)) { if(b.childs[k] && mapping.count(b.childs[k])) bnew.childs[k] = mapping[b.childs[k]]; } if(b.father && mapping.count(b.father)) bnew.father = mapping[b.father]; } lh->root = mapping[root]; return lh; } void LocalH :: Delete () { root->DeleteChilds(); } void LocalH :: DoArchive(Archive& ar) { ar & root & grading & boxes & boundingbox & dimension; } void LocalH :: SetH (Point<3> p, double h) { if (dimension == 2) { if (fabs (p(0) - root->xmid[0]) > root->h2 || fabs (p(1) - root->xmid[1]) > root->h2) return; GradingBox * box = Find(p); if (box->HOpt() <= 1.2 * h) return; while (2 * box->h2 > h) { int childnr = 0; double x1[3], x2[3]; double h2 = box->h2; if (p(0) > box->xmid[0]) { childnr += 1; x1[0] = box->xmid[0]; x2[0] = x1[0]+h2; } else { x2[0] = box->xmid[0]; x1[0] = x2[0]-h2; } if (p(1) > box->xmid[1]) { childnr += 2; x1[1] = box->xmid[1]; x2[1] = x1[1]+h2; } else { x2[1] = box->xmid[1]; x1[1] = x2[1]-h2; } x1[2] = x2[2] = 0; auto 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; Point<3> np; for (int i = 0; i < 2; i++) { np = p; np(i) = p(i) + hbox; SetH (np, hnp); np(i) = p(i) - hbox; SetH (np, hnp); } } else { if (fabs (p(0) - root->xmid[0]) > root->h2 || fabs (p(1) - root->xmid[1]) > root->h2 || fabs (p(2) - root->xmid[2]) > root->h2) return; GradingBox * box = Find(p); if (box->HOpt() <= 1.2 * h) return; while (2 * box->h2 > h) { double x1[3], x2[3]; int childnr = 0; double h2 = box->h2; if (p(0) > box->xmid[0]) { childnr += 1; x1[0] = box->xmid[0]; x2[0] = x1[0]+h2; } else { x2[0] = box->xmid[0]; x1[0] = x2[0]-h2; } if (p(1) > box->xmid[1]) { childnr += 2; x1[1] = box->xmid[1]; x2[1] = x1[1]+h2; } else { x2[1] = box->xmid[1]; x1[1] = x2[1]-h2; } if (p(2) > box->xmid[2]) { childnr += 4; x1[2] = box->xmid[2]; x2[2] = x1[2]+h2; } else { x2[2] = box->xmid[2]; x1[2] = x2[2]-h2; } auto 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; Point<3> np; for (int i = 0; i < 3; i++) { np = p; np(i) = p(i) + hbox; SetH (np, hnp); np(i) = p(i) - hbox; SetH (np, hnp); } } } double LocalH :: GetH (Point<3> x) const { return Find(x)->HOpt(); } /// minimal h in box (pmin, pmax) double LocalH :: GetMinH (Point<3> pmin, Point<3> pmax) const { Point<3> pmin2, pmax2; for (int j = 0; j < 3; j++) if (pmin(j) < pmax(j)) { pmin2(j) = pmin(j); pmax2(j) = pmax(j); } else { pmin2(j) = pmax(j); pmax2(j) = pmin(j); } return GetMinHRec (pmin2, pmax2, root); } double LocalH :: GetMinHRec (const Point3d & pmin, const Point3d & pmax, const GradingBox * box) const { if (dimension == 2) { 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) 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; } else { 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 (dimension == 2) { 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) return; } else { if (pmax.X() < box->xmid[0]-h2 || pmin.X() > box->xmid[0]+h2 || pmax.Y() < box->xmid[1]-h2 || pmin.Y() > box->xmid[1]+h2 || pmax.Z() < box->xmid[2]-h2 || pmin.Z() > box->xmid[2]+h2) return; } if (!box->flags.cutboundary) for (int i = 0; i < 8; i++) if (box->childs[i]) box->childs[i]->flags.cutboundary = false; box->flags.cutboundary = true; for (int i = 0; i < 8; i++) if (box->childs[i]) CutBoundaryRec (pmin, pmax, box->childs[i]); } GradingBox * LocalH :: Find (Point<3> p) const { GradingBox * box = root; if (dimension == 2) { while (1) { int childnr = 0; if (p(0) > box->xmid[0]) childnr += 1; if (p(1) > box->xmid[1]) childnr += 2; if (box->childs[childnr]) box = box->childs[childnr]; else return box; } } else { while (1) { int childnr = 0; if (p(0) > box->xmid[0]) childnr += 1; if (p(1) > box->xmid[1]) childnr += 2; if (p(2) > box->xmid[2]) childnr += 4; if (box->childs[childnr]) box = box->childs[childnr]; else return box; } } return nullptr; } void LocalH :: FindInnerBoxes (const AdFront3 & adfront, int (*testinner)(const Point3d & p1)) { static Timer timer("LocalH::FindInnerBoxes"); RegionTimer reg (timer); 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; NgArray faceinds(nf); NgArray 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, const AdFront3 & adfront, NgArray & faceboxes, NgArray & 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); NgArrayMem faceused; NgArrayMem faceused2; NgArrayMem 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 (const AdFront2 & adfront, int (*testinner)(const Point<2> & p1)) { static Timer t("LocalH::FindInnerBoxes 2d"); RegionTimer reg (t); static Timer trec("LocalH::FindInnerBoxes 2d - rec"); static Timer tinit("LocalH::FindInnerBoxes 2d - init"); /* tinit.Start(); for (int i = 0; i < boxes.Size(); i++) boxes[i] -> flags.isinner = 0; tinit.Stop(); */ root->flags.isinner = 0; root->flags.cutboundary = true; 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; int nf = adfront.GetNFL(); Array faceinds(nf); Array> faceboxes(nf); for (int i = 0; i < nf; i++) { faceinds[i] = i; const FrontLine & line = adfront.GetLine(i); Point<3> p1 = adfront.GetPoint (line.L().I1()); Point<3> p2 = adfront.GetPoint (line.L().I2()); faceboxes[i].Set (Point<2> (p1(0), p1(1))); faceboxes[i].Add (Point<2> (p2(0), p2(1))); } RegionTimer regrc(trec); for (int i = 0; i < 8; i++) FindInnerBoxesRec2 (root->childs[i], adfront, faceboxes, faceinds); // , nf); } void LocalH :: FindInnerBoxesRec2 (GradingBox * box, const class AdFront2 & adfront, FlatArray> faceboxes, FlatArray faceinds) // , int nfinbox) { if (!box) return; GradingBox * father = box -> father; if (!father->flags.cutboundary) { box->flags.isinner = father->flags.isinner; box->flags.pinner = father->flags.pinner; box->flags.cutboundary = false; } else { if (father->flags.isinner) { cout << "how is this possible ???" << endl; box->flags.pinner = 1; } else { Point<2> c(box->xmid[0], box->xmid[1]); Point<2> fc(father->xmid[0], father->xmid[1]); Box<2> boxcfc(c,fc); // reorder: put faces cutting boxcfc first: int iused = 0; int inotused = faceinds.Size()-1; while (iused <= inotused) { while ( (iused <= inotused) && boxcfc.Intersect (faceboxes[faceinds[iused]])) iused++; while ( (iused <= inotused) && !boxcfc.Intersect (faceboxes[faceinds[inotused]])) inotused--; if (iused < inotused) { Swap (faceinds[iused], faceinds[inotused]); iused++; inotused--; } } // bool sameside = adfront->SameSide (c2d, cf2d, &faceused2); auto sub = faceinds.Range(0, iused); bool sameside = adfront.SameSide (c, fc, &sub); if (sameside) box->flags.pinner = father->flags.pinner; else box->flags.pinner = 1 - father->flags.pinner; } if (box->flags.cutboundary) box->flags.isinner = 0; else box->flags.isinner = box->flags.pinner; } int iused = 0; if (faceinds.Size()) { Point<2> c(box->xmid[0], box->xmid[1]); // box->xmid[2]); Vec<2> v(box->h2, box->h2); Box<2> boxc(c-v, c+v); // reorder again: put faces cutting boxc first: int inotused = faceinds.Size()-1; while (iused <= inotused) { while ( (iused <= inotused) && boxc.Intersect (faceboxes[faceinds[iused]])) iused++; while ( (iused <= inotused) && !boxc.Intersect (faceboxes[faceinds[inotused]])) inotused--; if (iused < inotused) { Swap (faceinds[iused], faceinds[inotused]); iused++; inotused--; } } } if (box->flags.isinner || box->flags.cutboundary) for (int i = 0; i < 8; i++) FindInnerBoxesRec2 (box->childs[i], adfront, faceboxes, faceinds.Range(0,iused)); } 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 :: ClearRootFlags () { root->flags.cutboundary = false; root->flags.isinner = false; } 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 (NgArray > & points) const { static Timer t("GetInnerPoints"); RegionTimer reg(t); if (dimension == 2) { GetInnerPointsRec (root, points); /* for (int i = 0; i < boxes.Size(); i++) if (boxes[i] -> flags.isinner && boxes[i] -> HasChilds()) points.Append ( boxes[i] -> PMid() ); */ } else { for (int i = 0; i < boxes.Size(); i++) if (boxes[i] -> flags.isinner) points.Append ( boxes[i] -> PMid() ); } } void LocalH :: GetInnerPointsRec (const GradingBox * box, NgArray > & points) const { if (box -> flags.isinner && box -> HasChilds()) points.Append ( box -> PMid() ); if (box->flags.isinner || box->flags.cutboundary) for (int i = 0; i < 8; i++) if (box->childs[i]) GetInnerPointsRec (box->childs[i], points); } void LocalH :: GetOuterPoints (NgArray > & points) { static Timer t("LocalH::GetOuterPoints"); RegionTimer rt(t); 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; } } ================================================ FILE: libsrc/meshing/localh.hpp ================================================ #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] = {nullptr}; /// GradingBox * father = nullptr; /// double hopt; /// public: struct { /* unsigned int cutboundary:1; unsigned int isinner:1; unsigned int oldcell:1; unsigned int pinner:1; */ bool cutboundary; bool isinner; bool oldcell; bool pinner; } flags; /// GradingBox (const double * ax1, const double * ax2); /// default constructor for Archive GradingBox() = default; /// void DeleteChilds(); /// void DoArchive(Archive& ar); Point<3> PMid() const { return Point<3> (xmid[0], xmid[1], xmid[2]); } double H2() const { return h2; } double HOpt() const { return hopt; } bool HasChilds() const { for (int i = 0; i < 8; i++) if (childs[i]) return true; return false; } 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 boxes; /// Box<3> boundingbox; /// octree or quadtree int dimension; public: /// DLL_HEADER LocalH (Point<3> pmin, Point<3> pmax, double grading, int adimension = 3); /// LocalH (const Box<3> & box, double grading, int adimension = 3) : LocalH (box.PMin(), box.PMax(), grading, adimension) { ; } /// Default ctor for archive LocalH() = default; DLL_HEADER ~LocalH(); /// DLL_HEADER unique_ptr Copy(); DLL_HEADER unique_ptr Copy( const Box<3> & bbox ); /// DLL_HEADER void Delete(); /// DLL_HEADER void DoArchive(Archive& ar); /// void SetGrading (double agrading) { grading = agrading; } /// DLL_HEADER void SetH (Point<3> x, double h); /// DLL_HEADER double GetH (Point<3> x) const; /// minimal h in box (pmin, pmax) DLL_HEADER double GetMinH (Point<3> pmin, Point<3> 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); } GradingBox * Find(Point<3> p) const; /// find inner boxes void FindInnerBoxes (const class AdFront3 & adfront, int (*testinner)(const Point3d & p1)); void FindInnerBoxes (const class AdFront2 & adfront, int (*testinner)(const Point<2> & p1)); /// clears all flags void ClearFlags () { ClearFlagsRec(root); } void ClearRootFlags (); /// widen refinement zone void WidenRefinement (); /// get points in inner elements void GetInnerPoints (NgArray > & points) const; void GetInnerPointsRec (const GradingBox * box, NgArray > & points) const; /// get points in outer closure void GetOuterPoints (NgArray > & points); /// void Convexify (); /// int GetNBoxes () { return boxes.Size(); } const Box<3> & 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, const class AdFront3 & adfront, NgArray & faceboxes, NgArray & finds, int nfinbox); void FindInnerBoxesRec ( int (*inner)(const Point<2> & p), GradingBox * box); /// void FindInnerBoxesRec2 (GradingBox * box, const class AdFront2 & adfront, FlatArray> faceboxes, FlatArray finds); // , int nfinbox); /// void SetInnerBoxesRec (GradingBox * box); /// void ClearFlagsRec (GradingBox * box); /// void ConvexifyRec (GradingBox * box); unique_ptr CopyRec( const Box<3> & bbox, GradingBox * current ); 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 ================================================ FILE: libsrc/meshing/meshclass.cpp ================================================ #include #include #include #include #include #include "core/array.hpp" #include "meshing.hpp" #include "../general/gzstream.h" #include #include "basegeom.hpp" namespace netgen { ElementIndex Find3dElement (const Mesh& mesh, const netgen::Point<3> & p, double * lami, optional> indices, BoxTree<3, ElementIndex> * searchtree, const bool allowindex, double tol=1e-4) { int ne = 0; Array locels; if (searchtree) { searchtree->GetIntersecting (p, p, locels); ne = locels.Size(); } else ne = mesh.GetNE(); for (auto i : Range(ne)) { ElementIndex ei; if (searchtree) ei = locels[i]; else ei = i; if(indices && indices->Size() > 0) { bool contained = indices->Contains(mesh[ei].GetIndex()); if((allowindex && !contained) || (!allowindex && contained)) continue; } if(mesh.PointContainedIn3DElement(p,lami,ei, tol)) return ei; } // Not found, try uncurved variant: for (auto i : Range(ne)) { ElementIndex ei; if (searchtree) ei = locels[i]; else ei = i; if(indices && indices->Size() > 0) { bool contained = indices->Contains(mesh[ei].GetIndex()); if((allowindex && !contained) || (!allowindex && contained)) continue; } if(mesh.PointContainedIn3DElementOld(p,lami,ei, tol)) { (*testout) << "WARNING: found element of point " << p <<" only for uncurved mesh" << endl; return ei; } } return ElementIndex::INVALID; } SurfaceElementIndex Find2dElement (const Mesh& mesh, const netgen::Point<3> & p, double * lami, std::optional> indices, BoxTree<3, SurfaceElementIndex> * searchtree, bool allowindex) { double vlam[3]; ElementIndex velement = ElementIndex::INVALID; if(mesh.GetNE()) { if(searchtree) const_cast(mesh).BuildElementSearchTree(3); velement = Find3dElement(mesh, p,vlam, nullopt,searchtree ? mesh.GetElementSearchTree() : nullptr,allowindex); } //(*testout) << "p " << p << endl; //(*testout) << "velement " << velement << endl; // first try to find a volume element containing p and project to face if(velement.IsValid()) { auto & topology = mesh.GetTopology(); const auto & fnrs = topology.GetFaces(velement); auto faces = ArrayMem(); for(auto face : fnrs) faces.Append(topology.GetFace2SurfaceElement(face)); for(int i=0; iSize() > 0 && !indices->Contains(sel.GetIndex())) continue; auto & el = mesh[velement]; if (el.GetType() == TET) { double lam4[4] = { vlam[0], vlam[1], vlam[2], 1.0-vlam[0]-vlam[1]-vlam[2] }; double face_lam = lam4[i]; if(face_lam < 1e-5) { // found volume point very close to a face -> use barycentric coordinates directly lami[2] = 0.0; for(auto j : Range(1,3)) for(auto k : Range(4)) if(sel[j] == el[k]) lami[j-1] = lam4[k]/(1.0-face_lam); return SurfaceElementIndex(faces[i]); } } if(mesh.PointContainedIn2DElement(p,lami,faces[i],true)) return faces[i]; } } // Did't find any matching face of a volume element, search 2d elements directly int ne; Array locels; if (searchtree) { searchtree->GetIntersecting (p, p, locels); ne = locels.Size(); } else ne = mesh.GetNSE(); for (auto i : Range(ne)) { SurfaceElementIndex ii; if (locels.Size()) ii = locels[i]; else ii = i; if(indices && indices->Size() > 0) { bool contained = indices->Contains(mesh[ii].GetIndex()); if((allowindex && !contained) || (!allowindex && contained)) continue; } if(mesh.PointContainedIn2DElement(p,lami,ii)) return ii; } return SurfaceElementIndex::INVALID; } SegmentIndex Find1dElement (const Mesh& mesh, const netgen::Point<3> & p, double * lami, std::optional> indices, BoxTree<3> * searchtree, const bool allowindex = true) { double vlam[3]; if(searchtree) const_cast(mesh).BuildElementSearchTree(2); auto velement = Find2dElement(mesh, p, vlam, nullopt, searchtree ? mesh.GetSurfaceElementSearchTree() : nullptr, allowindex); if(!velement.IsValid()) return 0; vlam[2] = 1.-vlam[0] - vlam[1]; // NgArray edges; auto & topology = mesh.GetTopology(); /* topology.GetSurfaceElementEdges(velement, edges); Array segs(edges.Size()); for(auto i : Range(edges)) segs[i] = topology.GetSegmentOfEdge(edges[i]); */ auto hedges = topology.GetEdges(SurfaceElementIndex(velement-1)); Array segs(hedges.Size()); for(auto i : Range(hedges)) segs[i] = topology.GetSegmentOfEdge(hedges[i]+1); for(auto i : Range(segs)) { if(IsInvalid(segs[i])) continue; auto& el = mesh.SurfaceElement(velement); if(el.GetType() == TRIG) { double seg_lam=-1; double lam=-1; auto seg = mesh.LineSegment(segs[i]); for(auto k : Range(3)) { if(seg[0] == el[k]) lam = vlam[k]; if(seg[1] == el[k]) seg_lam = vlam[k]; } if(1.- seg_lam - lam < 1e-5) { // found point close to segment -> use barycentric coordinates directly lami[0] = lam; return int(segs[i])+1; } } else throw NgException("Quad not implemented yet!"); } return 0; } static mutex buildsearchtree_mutex; Mesh :: Mesh () : topology(*this), surfarea(*this) { lochfunc = {nullptr}; for(auto i : Range(4)) elementsearchtreets[i] = NextTimeStamp(); majortimestamp = timestamp = NextTimeStamp(); hglob = 1e10; hmin = 0; numvertices = -1; dimension = 3; curvedelems = make_unique (*this); clusters = make_unique (*this); ident = make_unique (*this); ps_startelement = 0; geomtype = NO_GEOM; bcnames.SetSize(0); cd2names.SetSize(0); #ifdef PARALLEL paralleltop = make_unique (*this); #endif } Mesh :: ~Mesh() { 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++ ) delete bcnames[i]; for (int i = 0; i < cd2names.Size(); i++) delete cd2names[i]; for (int i = 0; i < cd3names.Size(); i++) delete cd3names[i]; // #ifdef PARALLEL // delete paralleltop; // #endif } shared_ptr Mesh :: GetGeometry() const { static auto global_geometry = make_shared(); return geometry ? geometry : global_geometry; } void Mesh :: SetCommunicator(NgMPI_Comm acomm) { this->comm = acomm; } Mesh & Mesh :: operator= (const Mesh & mesh2) { geometry = mesh2.geometry; dimension = mesh2.dimension; points = mesh2.points; segments = mesh2.segments; surfelements = mesh2.surfelements; volelements = mesh2.volelements; lockedpoints = mesh2.lockedpoints; facedecoding = mesh2.facedecoding; dimension = mesh2.dimension; hglob = mesh2.hglob; hmin = mesh2.hmin; maxhdomain = mesh2.maxhdomain; pointelements = mesh2.pointelements; // Remap string* values to new mesh std::map names_map; for (auto fi : Range(facedecoding)) names_map[&mesh2.facedecoding[fi].bcname] = &facedecoding[fi].bcname; auto get_name = [&](const string *old_name) -> string* { if (!old_name) return nullptr; if (names_map.count(old_name)) return names_map[old_name]; return new string(*old_name); }; materials.SetSize( mesh2.materials.Size() ); for ( int i = 0; i < mesh2.materials.Size(); i++ ) { const string * old_name = mesh2.materials[i]; if ( old_name ) materials[i] = dimension == 2 ? get_name(old_name) : new string ( *old_name ); else materials[i] = 0; } bcnames.SetSize( mesh2.bcnames.Size() ); for ( int i = 0; i < mesh2.bcnames.Size(); i++ ) { const string * old_name = mesh2.bcnames[i]; if ( old_name ) bcnames[i] = dimension == 3 ? get_name(old_name) : new string ( *old_name ); else bcnames[i] = 0; } cd2names.SetSize(mesh2.cd2names.Size()); for (int i=0; i < mesh2.cd2names.Size(); i++) if (mesh2.cd2names[i]) cd2names[i] = new string(*mesh2.cd2names[i]); else cd2names[i] = 0; cd3names.SetSize(mesh2.cd3names.Size()); for (int i=0; i < mesh2.cd3names.Size(); i++) if (mesh2.cd3names[i]) cd3names[i] = new string(*mesh2.cd3names[i]); else cd3names[i] = 0; numvertices = mesh2.numvertices; 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 = nullptr; segmentht = nullptr; surfelementht = nullptr; openelements.SetSize(0); facedecoding.SetSize(0); ident = make_unique (*this); topology = MeshTopology (*this); curvedelems = make_unique (*this); clusters = make_unique (*this); for ( int i = 0; i < bcnames.Size(); i++ ) if ( bcnames[i] ) delete bcnames[i]; for (int i= 0; i< cd2names.Size(); i++) if (cd2names[i]) delete cd2names[i]; #ifdef PARALLEL paralleltop = make_unique (*this); #endif lock.UnLock(); timestamp = NextTimeStamp(); } void Mesh :: ClearSurfaceElements() { surfelements.SetSize(0); /* for (int i = 0; i < facedecoding.Size(); i++) facedecoding[i].firstelement = -1; */ for (auto & fd : facedecoding) fd.firstelement = -1; timestamp = NextTimeStamp(); } PointIndex Mesh :: AddPoint (const Point3d & p, int layer) { return AddPoint (p, layer, INNERPOINT); } PointIndex Mesh :: AddPoint (const Point3d & p, int layer, POINTTYPE type) { // PointIndex pi = points.End(); PointIndex pi = *points.Range().end(); if (points.Size() == points.AllocSize()) { NgLock lock(mutex); lock.Lock(); points.Append ( MeshPoint (p, layer, type) ); lock.UnLock(); } else { points.Append ( MeshPoint (p, layer, type) ); } timestamp = NextTimeStamp(); return pi; } SegmentIndex Mesh :: AddSegment (const Segment & s) { NgLock lock(mutex); lock.Lock(); timestamp = NextTimeStamp(); // int maxn = max2 (s[0], s[1]); // maxn += 1-PointIndex::BASE; int maxn = max2 (s[0]-IndexBASE()+1, s[1]-IndexBASE()+1); /* 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) { timestamp = NextTimeStamp(); PointIndex maxn = el[0]; for (int i = 1; i < el.GetNP(); i++) if (el[i] > maxn) maxn = el[i]; /* maxn += 1-PointIndex::BASE; if (maxn <= points.Size()) { for (int i = 0; i < el.GetNP(); i++) if (points[el[i]].Type() > SURFACEPOINT) points[el[i]].SetType(SURFACEPOINT); } */ // if (maxn < points.End()) if (maxn < *points.Range().end()) for (PointIndex pi : el.PNums()) if (points[pi].Type() > SURFACEPOINT) points[pi].SetType(SURFACEPOINT); SurfaceElementIndex si = surfelements.Size(); if (surfelements.AllocSize() == surfelements.Size()) { NgLock lock(mutex); lock.Lock(); surfelements.Append (el); lock.UnLock(); } else { surfelements.Append (el); } if (el.index<=0 || 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; if (SurfaceArea().Valid()) SurfaceArea().Add (el); return si; } void Mesh :: SetSurfaceElement (SurfaceElementIndex sei, const Element2d & el) { /* int maxn = el[0]; for (int i = 1; i < el.GetNP(); i++) if (el[i] > maxn) maxn = el[i]; maxn += 1-PointIndex::BASE; */ PointIndex maxpi = el[0]; for (int i = 1; i < el.GetNP(); i++) if (el[i] > maxpi) maxpi = el[i]; int maxn = maxpi-IndexBASE()+1; if (maxn <= points.Size()) { for (int i = 0; i < el.GetNP(); i++) if (points[el[i]].Type() > SURFACEPOINT) points[el[i]].SetType(SURFACEPOINT); } surfelements[sei] = el; if (el.index > facedecoding.Size()) cerr << "has no facedecoding: fd.size = " << facedecoding.Size() << ", ind = " << el.index << endl; // add lock-free to list ... slow, call RebuildSurfaceElementLists later /* surfelements[sei].next = facedecoding[el.index-1].firstelement; auto & head = reinterpret_cast&> (facedecoding[el.index-1].firstelement); while (!head.compare_exchange_weak (surfelements[sei].next, sei)) ; */ /* if (SurfaceArea().Valid()) SurfaceArea().Add (el); */ } ElementIndex Mesh :: AddVolumeElement (const Element & el) { /* 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(); if (volelements.Size() == volelements.AllocSize()) { NgLock lock(mutex); lock.Lock(); volelements.Append (el); lock.UnLock(); } else { volelements.Append (el); } volelements.Last().Touch(); volelements.Last().Flags().fixed = 0; volelements.Last().Flags().deleted = 0; // while (volelements.Size() > eltyps.Size()) // eltyps.Append (FREEELEMENT); timestamp = NextTimeStamp(); return ve; } void Mesh :: SetVolumeElement (ElementIndex ei, const Element & el) { /* int maxn = el[0]; for (int i = 1; i < el.GetNP(); i++) if (el[i] > maxn) maxn = el[i]; maxn += 1-PointIndex::BASE; */ volelements[ei] = el; volelements[ei].Touch(); volelements[ei].Flags().fixed = 0; volelements[ei].Flags().deleted = 0; } void Mesh :: Save (const filesystem::path & filename) const { string ext0 = filename.stem().extension().string(); string ext = filename.extension().string(); if (ext0 == ".vol" && ext == ".bin") { BinaryOutArchive in(filename); in & const_cast(*this); return; } ostream * outfile; if (ext0 == ".vol" && ext == ".gz") outfile = new ogzstream(filename); else if (ext == ".vol") outfile = new ofstream(filename); else outfile = new ogzstream(filesystem::path(filename).concat(".vol.gz")); Save(*outfile); delete outfile; } void Mesh :: Save (ostream & outfile) const { static Timer timer("Mesh::Save"); RegionTimer rt(timer); int i, j; double scale = 1; // globflags.GetNumFlag ("scale", 1); int inverttets = 0; // globflags.GetDefineFlag ("inverttets"); int invertsurf = 0; // globflags.GetDefineFlag ("invertsurfacemesh"); outfile << "# Generated by NETGEN " << GetLibraryVersion("netgen") << endl << endl; outfile << "mesh3d" << "\n"; outfile << "dimension\n" << GetDimension() << "\n"; outfile << "geomtype\n" << int(geomtype) << "\n"; outfile << "\n"; outfile << "# surfnr\tdomin\tdomout\ttlosurf\tbcprop\n"; outfile << "facedescriptors\n"; outfile << GetNFD() << "\n"; for(auto & fd : FaceDescriptors()) outfile << fd.SurfNr() << ' ' << fd.DomainIn() << ' ' << fd.DomainOut() << ' ' << fd.TLOSurface() << ' ' << fd.BCProperty() << '\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"; for (SurfaceElementIndex sei = 0; sei < GetNSE(); sei++) { if ((*this)[sei].GetIndex()) { outfile << " " << GetFaceDescriptor((*this)[sei].GetIndex ()).SurfNr()+1; outfile << " " << GetFaceDescriptor((*this)[sei].GetIndex ()).BCProperty(); outfile << " " << GetFaceDescriptor((*this)[sei].GetIndex ()).DomainIn(); outfile << " " << GetFaceDescriptor((*this)[sei].GetIndex ()).DomainOut(); } else outfile << " 0 0 0"; Element2d sel = (*this)[sei]; if (invertsurf) sel.Invert(); outfile << " " << sel.GetNP(); for (j = 0; j < sel.GetNP(); j++) outfile << " " << sel[j]; switch (geomtype) { case GEOM_STL: for (j = 1; j <= sel.GetNP(); j++) outfile << " " << sel.GeomInfoPi(j).trignum; break; case GEOM_OCC: case GEOM_ACIS: for (j = 1; j <= sel.GetNP(); j++) { outfile << " " << sel.GeomInfoPi(j).u; outfile << " " << sel.GeomInfoPi(j).v; } break; default: ; } 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 << (*this)[ei].GetIndex(); outfile << " " << (*this)[ei].GetNP(); Element el = (*this)[ei]; if (inverttets) el.Invert(); for (j = 0; j < el.GetNP(); j++) 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++) */ for (PointIndex pi : (*this).Points().Range()) { 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"; } outfile << "\n" << "\n"; outfile << "# pnum index" << "\n"; outfile << "pointelements" << "\n"; outfile << pointelements.Size() << "\n"; for (i = 0; i < pointelements.Size(); i++) { outfile.width(8); outfile << pointelements[i].pnum << " "; outfile.width(8); outfile << pointelements[i].index << "\n"; } if (ident -> GetMaxNr() > 0) { outfile << "identifications\n"; NgArray 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"; outfile << "identificationnames\n"; outfile << ident -> GetMaxNr() << "\n"; for (i = 1; i <= ident -> GetMaxNr(); i++) { string name = ident -> GetName(i); if(name == "") name = "default"; outfile << name << "\n"; } } int cntmat = 0; for (int i = 0; i < materials.Size(); i++) if (materials[i] && materials[i]->length()) cntmat++; if (cntmat) { outfile << "materials" << endl; outfile << cntmat << endl; for (int i = 0; i < materials.Size(); i++) if (materials[i] && materials[i]->length()) outfile << i+1 << " " << *materials[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; } int cntcd2names = 0; for (int ii = 0; ii=1.) cnt_sing++; for (auto & p : points) if (p.Singularity() >= 1.) cnt_sing++; if (cnt_sing) { outfile << "singular_points" << endl << cnt_sing << endl; // for (PointIndex pi = points.Begin(); pi < points.End(); pi++) for (PointIndex pi : points.Range()) if ((*this)[pi].Singularity()>=1.) outfile << 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()[0] << " "; outfile.width(12); outfile << GetFaceDescriptor(i).SurfColour()[1] << " "; outfile.width(12); outfile << GetFaceDescriptor(i).SurfColour()[2]; outfile << endl; } outfile << "face_transparencies" << endl << cnt_facedesc << endl; for(i = 1; i <= cnt_facedesc; i++) { outfile.width(8); outfile << GetFaceDescriptor(i).SurfNr()+1 << " "; outfile.width(12); outfile << GetFaceDescriptor(i).SurfColour()[3] << endl; } } if (curvedelems && curvedelems->IsHighOrder()) { if (level_nv.Size() > 1 && (MeshTopology().HasParentEdges() || MeshTopology().HasParentFaces())) cerr << "Waring: cannot store curvedelements on refined meshes with full hierarchy" << endl; else { outfile << "curvedelements" << endl; shared_ptr spoutfile(&outfile, [](void*) noexcept {}); TextOutArchive out(std::move(spoutfile)); out & (*curvedelems); } } outfile << endl << endl << "endmesh" << endl << endl; if (geometry) geometry -> SaveToMeshFile (outfile); } void Mesh :: Load (const filesystem::path & filename) { PrintMessage (1, "filename = ", filename); string ext0 = filename.stem().extension().string(); string ext = filename.extension().string(); if (ext0 == ".vol" && ext == ".bin") { BinaryInArchive in(filename); in & (*this); return; } istream * infile = NULL; if (ext0 == ".vol" && ext == ".gz") infile = new igzstream (filename); else infile = new ifstream (filename); if (! (infile -> good()) ) throw NgException ("mesh file not found"); Load(*infile); delete infile; } // Reads mandatory integer and optional string token from input stream // used for parsing bcnames, cd2names etc. void ReadNumberAndName( istream & infile, int & i, string & s ) { string line; std::istringstream iline; bool empty_line = true; while(empty_line && infile) { std::getline(infile, line); iline = std::istringstream{line}; iline >> i; if(iline) empty_line = false; iline >> s; } if(!infile) throw Exception("Reached end of file while parsing"); } void Mesh :: Load (istream & infile) { static Timer timer("Mesh::Load"); RegionTimer rt(timer); if (! (infile.good()) ) { cout << "cannot load mesh" << endl; throw NgException ("mesh file not found"); } // int rank = GetCommunicator().Rank(); int ntasks = GetCommunicator().Size(); 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; bool has_facedescriptors = 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, "facedescriptors") == 0) { has_facedescriptors = true; int nfd; infile >> nfd; for([[maybe_unused]] auto i : Range(nfd)) { int surfnr, domin, domout, tlosurf, bcprop; infile >> surfnr >> domin >> domout >> tlosurf >> bcprop; auto faceind = AddFaceDescriptor (FaceDescriptor(surfnr, domin, domout, tlosurf)); GetFaceDescriptor(faceind).SetBCProperty(bcprop); } } if (strcmp (str, "surfaceelements") == 0 || strcmp (str, "surfaceelementsgi")==0 || strcmp (str, "surfaceelementsuv") == 0) { static Timer t1("read surface elements"); RegionTimer rt1(t1); infile >> n; PrintMessage (3, n, " surface elements"); bool geominfo = strcmp (str, "surfaceelementsgi") == 0; bool uv = strcmp (str, "surfaceelementsuv") == 0; 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 (facedecoding.Size()) faceind = 1; // for timing 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 (geominfo) for (int j = 1; j <= nep; j++) infile >> tri.GeomInfoPi(j).trignum; if (uv) 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) { static Timer t1("read volume elements"); RegionTimer rt1(t1); infile >> n; PrintMessage (3, n, " volume elements"); for (i = 1; i <= n; i++) { Element el(TET); int hi, nep; infile >> hi; if (hi == 0) hi = 1; el.SetIndex(hi); infile >> nep; el.SetNP(nep); el.SetCurved (nep != 4); for (int j = 0; j < nep; j++) infile >> el[j]; if (inverttets) el.Invert(); AddVolumeElement (el); } } if (strcmp (str, "edgesegments") == 0) { static Timer t1("read edge segments"); RegionTimer rt1(t1); 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) { static Timer t1("read edge segmentsgi"); RegionTimer rt1(t1); 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) { static Timer t1("read edge segmentsgi2"); RegionTimer rt1(t1); 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; if (geomtype == GEOM_OCC) seg.index = seg.epgeominfo[0].edgenr+1; else if (geomtype == GEOM_CSG) seg.index = seg.edgenr; else seg.index = seg.si; seg.domin = seg.surfnr1; seg.domout = seg.surfnr2; seg.surfnr1--; seg.surfnr2--; AddSegment (seg); } } if (strcmp (str, "points") == 0) { static Timer t1("read points"); RegionTimer rt1(t1); 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); } PrintMessage (3, n, " points done"); } if (strcmp (str, "pointelements") == 0) { static Timer t1("read point elements"); RegionTimer rt1(t1); infile >> n; PrintMessage (3, n, " pointelements"); for (i = 1; i <= n; i++) { Element0d el; infile >> el.pnum >> el.index; pointelements.Append (el); } PrintMessage (3, n, " pointelements done"); } if (strcmp (str, "identifications") == 0) { infile >> n; PrintMessage (3, n, " identifications"); 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; PrintMessage (3, n, " identificationtypes"); for (i = 1; i <= n; i++) { int type; infile >> type; ident -> SetType(i,Identifications::ID_TYPE(type)); } } if (strcmp (str, "identificationnames") == 0) { infile >> n; PrintMessage (3, n, " identificationnames"); for (i = 1; i <= n; i++) { string name; infile >> name; ident -> SetName(i,name); } } if (strcmp (str, "materials") == 0) { infile >> n; for ([[maybe_unused]] auto i : Range(n) ) { int nr; string mat; ReadNumberAndName( infile, nr, mat ); SetMaterial (nr, mat.c_str()); } } if ( strcmp (str, "bcnames" ) == 0 ) { infile >> n; Array bcnrs(n); SetNBCNames(n); for ( auto i : Range(n) ) { string nextbcname; ReadNumberAndName( infile, bcnrs[i], nextbcname ); bcnames[bcnrs[i]-1] = new string(nextbcname); } if ( GetDimension() == 3 ) { 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, "cd2names" ) == 0) { infile >> n; Array cd2nrs(n); SetNCD2Names(n); for ( auto i : Range(n) ) { string nextcd2name; ReadNumberAndName( infile, cd2nrs[i], nextcd2name ); cd2names[cd2nrs[i]-1] = new string(nextcd2name); } if (GetDimension() < 2) { throw NgException("co dim 2 elements not implemented for dimension < 2"); } } if ( strcmp (str, "cd3names" ) == 0) { infile >> n; Array cd3nrs(n); SetNCD3Names(n); for( auto i : Range(n) ) { string nextcd3name; ReadNumberAndName( infile, cd3nrs[i], nextcd3name ); cd3names[cd3nrs[i]-1] = new string(nextcd3name); } if (GetDimension() < 3) { throw NgException("co dim 3 elements not implemented for dimension < 3"); } } 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; Vec<4> surfcolour(0.0,1.0,0.0,1.0); infile >> surfnr >> surfcolour[0] >> surfcolour[1] >> surfcolour[2]; surfnr--; if(has_facedescriptors) { GetFaceDescriptor(i).SetSurfColour(surfcolour); } else if(surfnr > 0) { for(int facedesc = 1; facedesc <= cnt_facedesc; facedesc++) { if(surfnr == GetFaceDescriptor(facedesc).SurfNr()) { GetFaceDescriptor(facedesc).SetSurfColour(surfcolour); } } } } } } if (strcmp (str, "face_transparencies") == 0) { int cnt_facedesc = GetNFD(); infile >> n; // int index = 1; if(n == cnt_facedesc) { for(int index = 1; index <= n; index++) { int surfnr; double transp; infile >> surfnr >> transp; surfnr--; if(has_facedescriptors) { auto& fd = GetFaceDescriptor(index); auto scol = fd.SurfColour(); scol[3] = transp; fd.SetSurfColour(scol); } else if(surfnr > 0) { for(int facedesc = 1; facedesc <= cnt_facedesc; facedesc++) { if(surfnr == GetFaceDescriptor(facedesc).SurfNr()) { auto& fd = GetFaceDescriptor(facedesc); auto scol = fd.SurfColour(); scol[3] = transp; fd.SetSurfColour(scol); } } } } } } if (strcmp (str, "curvedelements") == 0) { topology.Update(); shared_ptr spinfile(&infile, [](void*) noexcept {}); TextInArchive in(std::move(spinfile)); in & (*curvedelems); for (SegmentIndex seg = 0; seg < GetNSeg(); seg++) (*this)[seg].SetCurved (GetCurvedElements().IsSegmentCurved (seg)); for (SurfaceElementIndex sei = 0; sei < GetNSE(); sei++) (*this)[sei].SetCurved (GetCurvedElements().IsSurfaceElementCurved (sei)); for (ElementIndex ei = 0; ei < GetNE(); ei++) (*this)[ei].SetCurved (GetCurvedElements().IsElementCurved (ei)); } if (strcmp (str, "endmesh") == 0) endmesh = true; strcpy (str, ""); } CalcSurfacesOfNode (); if (ntasks == 1) // sequential run only { topology.Update(); clusters -> Update(); } SetNextMajorTimeStamp(); // PrintMemInfo (cout); } void Mesh :: DoArchive (Archive & archive) { static Timer t("Mesh::Archive"); RegionTimer r(t); #ifdef PARALLEL auto comm = GetCommunicator(); if (archive.IsParallel() && comm.Size() > 1) { // parallel pickling supported only for output archives if (comm.Rank() == 0) archive & dimension; // auto rank = comm.Rank(); auto & partop = GetParallelTopology(); // global enumration of points: // not used now, but will be needed for refined meshes // GridFunciton pickling is not compatible, now // should go to paralleltopology // merge points Array globnum(points.Size()); PointIndex maxglob = -1; for (auto pi : Range(points)) { globnum[pi] = partop.GetGlobalPNum(pi); // globnum[pi] = global_pnums[pi]; maxglob = max(globnum[pi], maxglob); } maxglob = comm.AllReduce (maxglob, NG_MPI_MAX); int numglob = maxglob+1-IndexBASE(); if (comm.Rank() > 0) { comm.Send (globnum, 0, 200); comm.Send (points, 0, 200); } else { Array globnumi; Array pointsi; Array globpoints(numglob); for (int j = 1; j < comm.Size(); j++) { comm.Recv (globnumi, j, 200); comm.Recv (pointsi, j, 200); for (auto i : Range(globnumi)) globpoints[globnumi[i]] = pointsi[i]; } archive & globpoints; } // sending surface elements auto copy_el2d (surfelements); for (auto & el : copy_el2d) for (auto & pi : el.PNums()) pi = globnum[pi]; if (comm.Rank() > 0) comm.Send(copy_el2d, 0, 200); else { Array el2di; for (int j = 1; j < comm.Size(); j++) { comm.Recv(el2di, j, 200); for (auto & el : el2di) copy_el2d += el; } archive & copy_el2d; } // sending volume elements auto copy_el3d (volelements); for (auto & el : copy_el3d) for (auto & pi : el.PNums()) pi = globnum[pi]; if (comm.Rank() > 0) comm.Send(copy_el3d, 0, 200); else { Array el3di; for (int j = 1; j < comm.Size(); j++) { comm.Recv(el3di, j, 200); for (auto & el : el3di) copy_el3d += el; } archive & copy_el3d; } // sending 1D elements auto copy_el1d (segments); for (auto & el : copy_el1d) for (auto & pi : el.pnums) if (pi != PointIndex(PointIndex::INVALID)) pi = globnum[pi]; if (comm.Rank() > 0) comm.Send(copy_el1d, 0, 200); else { Array el1di; for (int j = 1; j < comm.Size(); j++) { comm.Recv(el1di, j, 200); for (auto & el : el1di) copy_el1d += el; } archive & copy_el1d; } // sending 0D elements auto copy_el0d (pointelements); for (auto & el : copy_el0d) { auto & pi = el.pnum; if (pi != PointIndex(PointIndex::INVALID)) pi = globnum[pi]; } if (comm.Rank() > 0) comm.Send(copy_el0d, 0, 200); else { Array el0di; for (int j = 1; j < comm.Size(); j++) { comm.Recv(el0di, j, 200); for (auto & el : el0di) copy_el0d += el; } archive & copy_el0d; } if (comm.Rank() == 0) { archive & facedecoding; archive & materials & bcnames & cd2names & cd3names; auto mynv = numglob; archive & mynv; // numvertices; archive & *ident; if(archive.GetVersion("netgen") >= "v6.2.2103-1") { archive.NeedsVersion("netgen", "v6.2.2103-1"); archive & vol_partition & surf_partition & seg_partition; } archive.Shallow(geometry); archive & *curvedelems; } if (comm.Rank() == 0) return; } #endif archive & dimension; archive & points; archive & surfelements; archive & volelements; archive & segments; archive & pointelements; archive & facedecoding; archive & materials & bcnames & cd2names & cd3names; archive & numvertices; archive & *ident; // cout << "archive, ngsversion = " << archive.GetVersion("netgen") << endl; if(archive.GetVersion("netgen") >= "v6.2.2103-1") { // cout << "do the partition" << endl; archive.NeedsVersion("netgen", "v6.2.2103-1"); archive & vol_partition & surf_partition & seg_partition; } // else // cout << "no partition" << endl; archive.Shallow(geometry); archive & *curvedelems; if (archive.Input()) { // int rank = GetCommunicator().Rank(); int ntasks = GetCommunicator().Size(); RebuildSurfaceElementLists(); CalcSurfacesOfNode (); if (ntasks == 1) // sequential run only { topology.Update(); clusters -> Update(); } SetNextMajorTimeStamp(); } } void Mesh :: Merge (const filesystem::path & filename, const int surfindex_offset) { ifstream infile(filename); 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; *testout << "old edgenr: " << seg.edgenr << endl; seg.edgenr = seg.edgenr + oldne; *testout << "new edgenr: " << seg.edgenr << endl; 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(TET); 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 >> 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].IsValid()) { (*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(bool rebuild) { static Timer t("Mesh::BuildBoundaryEdges"); RegionTimer reg(t); if(!rebuild && boundaryedges) return; boundaryedges = make_unique> (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(); if (sel.GetNP() <= 4) for (int j = 0; j < sel.GetNP(); j++) { PointIndices<2> i2; i2[0] = sel.PNumMod(j+1); i2[1] = sel.PNumMod(j+2); i2.Sort(); boundaryedges->Set (i2, 1); } else if (sel.GetType()==TRIG6) { for (int j = 0; j < 3; j++) { PointIndices<2> i2; i2[0] = sel[j]; i2[1] = sel[(j+1)%3]; i2.Sort(); boundaryedges->Set (i2, 1); } } else cerr << "illegal element for buildboundaryedges" << endl; } /* 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 (const Element2d & sel : openelements) for (int j = 0; j < sel.GetNP(); j++) { PointIndices<2> i2 { sel.PNumMod(j+1), 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); } */ for (const Segment & seg : segments) { PointIndices<2> i2 { seg[0], seg[1] }; i2.Sort(); boundaryedges -> Set (i2, 2); //segmentht -> Set (i2, i); } } void Mesh :: CalcSurfacesOfNode () { static Timer t("Mesh::CalcSurfacesOfNode"); RegionTimer reg (t); static Timer tn2se("Mesh::CalcSurfacesOfNode - surf on node"); static Timer tht("Mesh::CalcSurfacesOfNode - surfelementht"); // surfacesonnode.SetSize (GetNP()); DynamicTable surfacesonnode(GetNP()); // delete boundaryedges; // boundaryedges = NULL; boundaryedges = nullptr; // delete surfelementht; // surfelementht = nullptr; surfelementht = nullptr; // delete segmentht; /* surfelementht = new INDEX_3_HASHTABLE (GetNSE()/4 + 1); segmentht = new INDEX_2_HASHTABLE (GetNSeg() + 1); */ if (dimension == 3) surfelementht = make_unique> (3*GetNSE() + 1); segmentht = make_unique> (3*GetNSeg() + 1); tn2se.Start(); if (dimension == 3) /* for (SurfaceElementIndex sei = 0; sei < GetNSE(); sei++) { const Element2d & sel = surfelements[sei]; */ for (const Element2d & sel : surfelements) { if (sel.IsDeleted()) continue; int si = sel.GetIndex(); /* for (int j = 0; j < sel.GetNP(); j++) { PointIndex pi = sel[j]; */ for (PointIndex pi : sel.PNums()) { if (!surfacesonnode[pi].Contains(si)) surfacesonnode.Add (pi, si); /* bool found = 0; for (int 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(); */ tn2se.Stop(); tht.Start(); if (dimension==3) for (SurfaceElementIndex sei = 0; sei < GetNSE(); sei++) { const Element2d & sel = surfelements[sei]; if (sel.IsDeleted()) continue; PointIndices<3> i3; i3[0] = sel.PNum(1); i3[1] = sel.PNum(2); i3[2] = sel.PNum(3); i3.Sort(); surfelementht -> Set (i3, sei); // war das wichtig ??? sel.GetIndex()); } tht.Stop(); // int np = GetNP(); if (dimension == 3) { static Timer t("Mesh::CalcSurfacesOfNode, pointloop"); RegionTimer reg (t); /* for (PointIndex pi = points.Begin(); pi < points.End(); pi++) points[pi].SetType (INNERPOINT); */ for (auto & p : points) p.SetType (INNERPOINT); if (GetNFD() == 0) { for (SurfaceElementIndex sei = 0; sei < GetNSE(); sei++) { const Element2d & sel = surfelements[sei]; if (sel.IsDeleted()) continue; for (int j = 0; j < sel.GetNP(); j++) { PointIndex pi = SurfaceElement(sei)[j]; points[pi].SetType(FIXEDPOINT); } } } else { for (SurfaceElementIndex sei = 0; sei < GetNSE(); sei++) { const Element2d & sel = surfelements[sei]; if (sel.IsDeleted()) continue; for (int 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 (int i = 0; i < segments.Size(); i++) { const Segment & seg = segments[i]; */ for (const Segment & seg : segments) { for (int 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 (int i = 0; i < lockedpoints.Size(); i++) points[lockedpoints[i]].SetType(FIXEDPOINT); for(const auto& pointel : pointelements) points[pointel.pnum].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 (int i = 0; i < GetNSeg(); i++) { const Segment & seg = segments[i]; PointIndices<2> i2(seg[0], seg[1]); i2.Sort(); //boundaryedges -> Set (i2, 2); segmentht -> Set (i2, i); } } // NgBitArray base is PointIndex::BASE ... void Mesh :: FixPoints (const TBitArray & 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); } */ for (PointIndex pi : points.Range()) if (fixpoints.Test(pi)) points[pi].SetType(FIXEDPOINT); } void Mesh :: FindOpenElements (int dom) { static Timer t("Mesh::FindOpenElements"); RegionTimer reg (t); static Timer t_table("Mesh::FindOpenElements - build table"); static Timer t_pointloop("Mesh::FindOpenElements - pointloop"); int np = GetNP(); // int ne = GetNE(); int nse = GetNSE(); t_table.Start(); auto elsonpoint = ngcore::CreateSortedTable( volelements.Range(), [&](auto & table, ElementIndex ei) { const Element & el = (*this)[ei]; if(el.IsDeleted()) return; if (dom == 0 || dom == el.GetIndex()) { if (el.GetNP() == 4) { PointIndices<4> i4(el[0], el[1], el[2], el[3]); i4.Sort(); table.Add (i4.I1(), ei); table.Add (i4.I2(), ei); } else { for (PointIndex pi : el.PNums()) table.Add(pi, ei); } } }, GetNP()); NgArray 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 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); } } */ t_table.Stop(); NgArray hasface(GetNFD()); for (int 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 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); } } // PointIndex pi; // SurfaceElementIndex sei; // Element2d hel; struct tval { int index; PointIndex p4; }; openelements.SetSize(0); t_pointloop.Start(); /* INDEX_3_CLOSED_HASHTABLE faceht(100); for (PointIndex pi : points.Range()) if (selsonpoint[pi].Size()+elsonpoint[pi].Size()) { faceht.SetSize (2 * selsonpoint[pi].Size() + 4 * elsonpoint[pi].Size()); for (SurfaceElementIndex sei : selsonpoint[pi]) { Element2d hel = SurfaceElement(sei); if (hel.GetType() == TRIG6) hel.SetType(TRIG); 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]); tval i2; i2.index = GetFaceDescriptor(ind).DomainIn(); i2.p4 = (hel.GetNP() == 3) ? PointIndex (PointIndex::INVALID) : 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]); tval i2; i2.index = GetFaceDescriptor(ind).DomainOut(); i2.p4 = (hel.GetNP() == 3) ? PointIndex (PointIndex::INVALID) : hel.PNum(4); faceht.Set (i3, i2); } } } for (ElementIndex ei : elsonpoint[pi]) { const Element & el = VolumeElement(ei); if (dom == 0 || el.GetIndex() == dom) { for (int j = 1; j <= el.GetNFaces(); j++) { Element2d hel(TRIG); 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)) { tval i2 = faceht.Get(i3); if (i2.index == el.GetIndex()) { i2.index = PointIndex::BASE-1; faceht.Set (i3, i2); } else { if (i2.index == 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]); tval i2; i2.index = el.GetIndex(); i2.p4 = (hel.GetNP() == 3) ? PointIndex (PointIndex::INVALID) : hel[3]; faceht.Set (i3, i2); } } } } } for (int i = 0; i < faceht.Size(); i++) if (faceht.UsedPos (i)) { INDEX_3 i3; //INDEX_2 i2; tval i2; faceht.GetData (i, i3, i2); if (i2.index != PointIndex::BASE-1) { Element2d tri ( (i2.p4 == PointIndex::BASE-1) ? TRIG : QUAD); for (int l = 0; l < 3; l++) tri[l] = i3.I(l+1); tri.PNum(4) = i2.p4; tri.SetIndex (i2.index); openelements.Append (tri); } } } */ size_t numtasks = 4*ngcore::TaskManager::GetNumThreads(); Array> thread_openelements(numtasks); ParallelJob ( [&](TaskInfo & ti) { auto myrange = points.Range().Split(ti.task_nr, ti.ntasks); INDEX_3_CLOSED_HASHTABLE faceht(100); for (PointIndex pi : myrange) if (selsonpoint[pi].Size()+elsonpoint[pi].Size()) { faceht.SetSize (2 * selsonpoint[pi].Size() + 4 * elsonpoint[pi].Size()); for (SurfaceElementIndex sei : selsonpoint[pi]) { Element2d hel = SurfaceElement(sei); if (hel.GetType() == TRIG6) hel.SetType(TRIG); int ind = hel.GetIndex(); if (GetFaceDescriptor(ind).DomainIn() && (dom == 0 || dom == GetFaceDescriptor(ind).DomainIn()) ) { hel.NormalizeNumbering(); if (hel.PNum(1) == pi) { PointIndices<3> i3(hel[0], hel[1], hel[2]); tval i2; i2.index = GetFaceDescriptor(ind).DomainIn(); i2.p4 = (hel.GetNP() == 3) ? PointIndex (PointIndex::INVALID) : 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) { PointIndices<3> i3(hel[0], hel[1], hel[2]); tval i2; i2.index = GetFaceDescriptor(ind).DomainOut(); i2.p4 = (hel.GetNP() == 3) ? PointIndex (PointIndex::INVALID) : hel.PNum(4); faceht.Set (i3, i2); } } } for (ElementIndex ei : elsonpoint[pi]) { const Element & el = VolumeElement(ei); if(el.IsDeleted()) continue; if (dom == 0 || el.GetIndex() == dom) { for (int j = 1; j <= el.GetNFaces(); j++) { Element2d hel(TRIG); el.GetFace (j, hel); hel.Invert(); hel.NormalizeNumbering(); if (hel[0] == pi) { PointIndices<3> i3(hel[0], hel[1], hel[2]); if (faceht.Used (i3)) { tval i2 = faceht.Get(i3); if (i2.index == el.GetIndex()) { i2.index = long(PointIndex::BASE)-1; faceht.Set (i3, i2); } else { if (i2.index == 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(); PointIndices<3> i3(hel[0], hel[1], hel[2]); tval i2; i2.index = el.GetIndex(); i2.p4 = (hel.GetNP() == 3) ? PointIndex (PointIndex::INVALID) : hel[3]; faceht.Set (i3, i2); } } } } } for (int i = 0; i < faceht.Size(); i++) if (faceht.UsedPos (i)) { INDEX_3 i3; tval i2; faceht.GetData (i, i3, i2); if (i2.index != PointIndex::BASE-1) { Element2d tri ( (!i2.p4.IsValid()) ? TRIG : QUAD); for (int l = 0; l < 3; l++) tri[l] = i3.I(l+1); tri.PNum(4) = i2.p4; tri.SetIndex (i2.index); thread_openelements[ti.task_nr].Append (tri); } } }}, numtasks); for (auto & a : thread_openelements) for (auto & el : a) openelements.Append (el); t_pointloop.Stop(); int cnt3 = 0; for (int 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++) { PointIndex pi = sel.PNum(j); // if (pi < points.End()) if (pi < *points.Range().end()) 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 elements // hash index: pnum1-2, surfnr // hash data : surfel-nr (pos) or segment nr(neg) INDEX_3_HASHTABLE faceht(4 * GetNSE()+GetNSeg()+1); PrintMessage (5, "Test Opensegments"); for (int i = 1; i <= GetNSeg(); i++) { const Segment & seg = LineSegment (i); if (surfnr == 0 || seg.si == surfnr) { INDEX_3 key(seg[0], seg[1], seg.si); int data = -i; if (faceht.Used (key)) { cerr << "ERROR: Segment " << seg << " already used" << endl; (*testout) << "ERROR: Segment " << seg << " already used" << endl; } faceht.Set (key, data); } } /* // not possible with surfnr as hash-index for (int 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; } } } */ // bool buggy = false; // ofstream bout("buggy.out"); for (int i = 1; i <= GetNSE(); i++) { const Element2d & el = SurfaceElement(i); if (el.IsDeleted()) continue; if (surfnr == 0 || el.GetIndex() == surfnr) { for (int j = 1; j <= el.GetNP(); j++) { PointIndices<3> seg (el.PNumMod(j), el.PNumMod(j+1), el.GetIndex()); // int data; if (!seg.I1().IsValid() || !seg.I2().IsValid()) cerr << "seg = " << seg << endl; if (faceht.Used(seg)) { faceht.Set (seg, 0); /* data = faceht.Get(seg); if (data.I1() == el.GetIndex()) { data.I1() = 0; faceht.Set (seg, data); } else { // buggy = true; PrintWarning ("hash table si not fitting for segment: ", seg.I1(), "-", seg.I2(), " other = ", data.I2(), ", surfnr = ", surfnr); } */ } else { Swap (seg.I1(), seg.I2()); // data.I1() = el.GetIndex(); // data.I2() = i; faceht.Set (seg, i); } } } } /* if (buggy) { for (int i = 1; i <= GetNSeg(); i++) bout << "seg" << i << " " << LineSegment(i) << endl; for (int i = 1; i <= GetNSE(); i++) bout << "sel" << i << " " << SurfaceElement(i) << " ind = " << SurfaceElement(i).GetIndex() << endl; bout << "hashtable: " << endl; for (int j = 1; j <= faceht.GetNBags(); j++) { bout << "bag " << j << ":" << endl; for (int k = 1; k <= faceht.GetBagSize(j); k++) { INDEX_2 i2, data; faceht.GetData (j, k, i2, data); bout << "key = " << i2 << ", data = " << data << endl; } } exit(1); } */ (*testout) << "open segments: " << endl; opensegments.SetSize(0); for (int i = 1; i <= faceht.GetNBags(); i++) for (int j = 1; j <= faceht.GetBagSize(i); j++) { PointIndices<3> i2; int data; faceht.GetData (i, j, i2, data); if (data) // surfnr { Segment seg; seg[0] = i2.I1(); seg[1] = i2.I2(); seg.si = i2.I3(); // find geomdata: if (data > 0) { // segment due to triangle const Element2d & el = SurfaceElement (data); for (int 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); 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 (int i = 1; i <= points.Size(); i++) points.Elem(i).SetType(SURFACEPOINT); */ for (auto & p : points) p.SetType (SURFACEPOINT); for (int i = 1; i <= GetNSeg(); i++) { const Segment & seg = LineSegment (i); points[seg[0]].SetType(EDGEPOINT); points[seg[1]].SetType(EDGEPOINT); } for (int 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 np = GetNP(); FindOpenSegments(); TBitArray frontpoints(np); // for 0- and 1-based frontpoints.Clear(); for (int i = 1; i <= GetNOpenSegments(); i++) { const Segment & seg = GetOpenSegment(i); frontpoints.SetBit (seg[0]); frontpoints.SetBit (seg[1]); } for (int i = 1; i <= GetNSE(); i++) { Element2d & sel = surfelements[i-1]; bool remove = false; for (int j = 1; j <= sel.GetNP(); j++) if (frontpoints.Test(sel.PNum(j))) remove = true; if (remove) sel.PNum(1).Invalidate(); } for (int i = surfelements.Size(); i >= 1; i--) { if (!surfelements[i-1].PNum(1).IsValid()) { surfelements[i-1] = 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) { static Timer timer("FreeOpenElementsEnvironment"); RegionTimer rt(timer); const int large = 9999; Array dist(GetNP()); dist = large; for (int i = 1; i <= GetNOpenElements(); i++) { const Element2d & face = OpenElement(i); for (int j = 0; j < face.GetNP(); j++) dist[face[j]] = 1; } for (int k = 1; k <= layers; k++) /* for (i = 1; i <= GetNE(); i++) { const Element & el = VolumeElement(i); */ for (auto & el : VolumeElements()) { if (!el[0].IsValid() || el.IsDeleted()) continue; int elmin = large; for (int j = 0; j < el.GetNP(); j++) if (dist[el[j]] < elmin) elmin = dist[el[j]]; if (elmin < large) { for (int j = 0; j < el.GetNP(); j++) if (dist[el[j]] > elmin+1) dist[el[j]] = elmin+1; } } int cntfree = 0; /* for (int i = 1; i <= GetNE(); i++) { Element & el = VolumeElement(i); */ for (auto & el : VolumeElements()) { if (!el[0].IsValid() || el.IsDeleted()) continue; int elmin = large; for (int 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 (PointIndex pi = IndexBASE(); pi < GetNP()+IndexBASE(); pi++) { if (dist[pi] > layers+1) points[pi].SetType(FIXEDPOINT); } } void Mesh :: SetLocalH (netgen::Point<3> pmin, netgen::Point<3> pmax, double grading, int layer) { using netgen::Point; Point<3> c = Center (pmin, pmax); double d = max3 (pmax(0)-pmin(0), pmax(1)-pmin(1), pmax(2)-pmin(2)); d /= 2; Point<3> pmin2 = c - Vec<3> (d, d, d); Point<3> pmax2 = c + Vec<3> (d, d, d); SetLocalH(make_unique (pmin2, pmax2, grading, dimension), layer); } void Mesh :: RestrictLocalH (const Point3d & p, double hloc, int layer) { if(hloc < hmin) hloc = hmin; //cout << "restrict h in " << p << " to " << hloc << endl; if (!lochfunc[layer-1]) { PrintWarning("RestrictLocalH called, creating mesh-size tree"); Point3d boxmin, boxmax; GetBox (boxmin, boxmax); SetLocalH (boxmin, boxmax, 0.8, layer); } lochfunc[layer-1] -> SetH (p, hloc); } void Mesh :: RestrictLocalHLine (const Point3d & p1, const Point3d & p2, double hloc, int layer) { 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, layer); } } void Mesh :: SetMinimalH (double h) { hmin = h; } void Mesh :: SetGlobalH (double h) { hglob = h; } double Mesh :: MaxHDomain (int dom) const { if (dom >= 0 && dom < maxhdomain.Size()) return maxhdomain.Get(dom); else return 1e10; } void Mesh :: SetMaxHDomain (const NgArray & 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, int layer) const { const auto& lh = GetLocalH(layer); double hmin = hglob; if (lh) { double hl = lh->GetH (p); if (hl < hglob) hmin = hl; } return hmin; } double Mesh :: GetMinH (const Point3d & pmin, const Point3d & pmax, int layer) { const auto& lh = GetLocalH(layer); double hmin = hglob; if (lh) { double hl = lh->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, int layer) { static Timer t("Mesh::CalcLocalH"); RegionTimer reg(t); if (!lochfunc[layer-1]) { Point3d pmin, pmax; GetBox (pmin, pmax); // SetLocalH (pmin, pmax, mparam.grading); SetLocalH (pmin, pmax, grading, layer); } 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[layer-1]->SetH (Center (p1, p2, p3), hel); } } else { { const Point3d & p1 = points[el.PNum(1)]; const Point3d & p2 = points[el.PNum(2)]; lochfunc[layer-1]->SetH (Center (p1, p2), 2 * Dist (p1, p2)); } { const Point3d & p1 = points[el.PNum(3)]; const Point3d & p2 = points[el.PNum(4)]; lochfunc[layer-1]->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[layer-1]->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, int layer) { PrintMessage (3, "Calculating local h from point distances"); if (!lochfunc[layer-1]) { Point3d pmin, pmax; GetBox (pmin, pmax); // SetLocalH (pmin, pmax, mparam.grading); SetLocalH (pmin, pmax, grading, layer); } // double hl; for (PointIndex i = IndexBASE(); i < GetNP()+IndexBASE(); i++) { for(PointIndex j=i+1; j(); j++) { const Point3d & p1 = points[i]; const Point3d & p2 = points[j]; double 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, int layer) { PrintMessage (3, "Calculating local h from surface curvature"); if (!lochfunc[layer-1]) { Point3d pmin, pmax; GetBox (pmin, pmax); // SetLocalH (pmin, pmax, mparam.grading); SetLocalH (pmin, pmax, grading, layer); } INDEX_2_HASHTABLE edges(3 * GetNP() + 2); INDEX_2_HASHTABLE bedges(GetNSeg() + 2); int i, j; for (i = 1; i <= GetNSeg(); i++) { const Segment & seg = LineSegment(i); PointIndices<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).IsValid()) continue; for (j = 1; j <= 3; j++) { PointIndices<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[0]) || (sel.PNum(pi3_) == i2[1])) pi3_++; PointIndex pi3 = sel.PNum(pi3_); int pi4_ = 1; while ( (elother.PNum(pi4_) == i2[0]) || (elother.PNum(pi4_) == i2[1])) pi4_++; PointIndex pi4 = elother.PNum(pi4_); double rad = ComputeCylinderRadius (Point (i2[0]), Point (i2[1]), Point (pi3), Point (pi4)); RestrictLocalHLine (Point(PointIndex(i2.I1())), Point(PointIndex(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(); NgArray normals(np); NgBitArray 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 filesystem::path & meshsizefilename) { // Philippose - 10/03/2009 // Improve error checking when loading and reading // the local mesh size file if (meshsizefilename.empty()) 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 :: SetLocalH(shared_ptr loch, int layer) { if(layer>lochfunc.Size()) { auto pre_size = lochfunc.Size(); lochfunc.SetSize(layer); for(auto & func : lochfunc.Range(pre_size, layer-1)) func = lochfunc[0]; } lochfunc[layer-1] = loch; } 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 = points.Begin(); pi < points.End(); pi++) for (PointIndex pi : points.Range()) { 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 = points.Begin(); pi < points.End(); pi++) for (PointIndex pi : points.Range()) 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[eli-1]; return CalcTetBadness (points[el[0]], points[el[1]], points[el[2]], points[el[3]], -1, mp); } void Mesh :: AddLockedPoint (PointIndex pi) { lockedpoints.Append (pi); } void Mesh :: ClearLockedPoints () { lockedpoints.SetSize (0); } void Mesh :: Compress () { static Timer t("Mesh::Compress"); RegionTimer reg(t); NgLock lock(mutex); lock.Lock(); Array op2np(GetNP()); Array 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 (int i = 0; i < volelements.Size(); i++) if (!volelements[i][0].IsValid() || volelements[i].IsDeleted()) { volelements.DeleteElement(i); i--; } for (int i = 0; i < surfelements.Size(); i++) if (surfelements[i].IsDeleted()) { surfelements.DeleteElement(i); i--; } for (int i = 0; i < segments.Size(); i++) if (!segments[i][0].IsValid()) { segments.DeleteElement(i); i--; } for(int i=0; i < segments.Size(); i++) if(segments[i].edgenr < 0) segments.DeleteElement(i--); pused = false; /* for (int i = 0; i < volelements.Size(); i++) { const Element & el = volelements[i]; for (int j = 0; j < el.GetNP(); j++) pused[el[j]] = true; } */ /* for (const Element & el : volelements) for (PointIndex pi : el.PNums()) pused[pi] = true; */ ParallelForRange (volelements.Range(), [&] (auto myrange) { for (const Element & el : volelements.Range(myrange)) for (PointIndex pi : el.PNums()) pused[pi] = true; }); /* for (int i = 0; i < surfelements.Size(); i++) { const Element2d & el = surfelements[i]; for (int j = 0; j < el.GetNP(); j++) pused[el[j]] = true; } */ ParallelForRange (surfelements.Range(), [&] (auto myrange) { for (const Element2d & el : surfelements.Range(myrange)) for (PointIndex pi : el.PNums()) pused[pi] = true; }); for (int i = 0; i < segments.Size(); i++) { const Segment & seg = segments[i]; for (int j = 0; j < seg.GetNP(); j++) pused[seg[j]] = true; } for(auto& pe : pointelements) pused[pe.pnum] = true; for (int i = 0; i < openelements.Size(); i++) { const Element2d & el = openelements[i]; for (int j = 0; j < el.GetNP(); j++) pused[el[j]] = true; } for (int i = 0; i < lockedpoints.Size(); i++) pused[lockedpoints[i]] = true; /* // compress points doesn't work for identified points ! if (identifiedpoints) { for (i = 1; i <= identifiedpoints->GetNBags(); i++) if (identifiedpoints->GetBagSize(i)) { pused.Set (); break; } } */ // pused.Set(); { Array hpoints; PointIndex npi = IndexBASE(); for (PointIndex pi : points.Range()) if (pused[pi]) { op2np[pi] = npi; npi++; hpoints.Append (points[pi]); } else { op2np[pi].Invalidate(); } points.SetSize(0); for (int i = 0; i < hpoints.Size(); i++) points.Append (hpoints[i]); } /* for (int i = 1; i <= volelements.Size(); i++) { Element & el = VolumeElement(i); for (int j = 0; j < el.GetNP(); j++) el[j] = op2np[el[j]]; } */ ParallelForRange (volelements.Range(), [&] (auto myrange) { for (Element & el : volelements.Range(myrange)) for (PointIndex & pi : el.PNums()) pi = op2np[pi]; }); /* for (int i = 1; i <= surfelements.Size(); i++) { Element2d & el = SurfaceElement(i); for (int j = 0; j < el.GetNP(); j++) el[j] = op2np[el[j]]; } */ ParallelForRange (surfelements.Range(), [&] (auto myrange) { for (Element2d & el : surfelements.Range(myrange)) for (PointIndex & pi : el.PNums()) pi = op2np[pi]; }); for (int i = 0; i < segments.Size(); i++) { Segment & seg = segments[i]; for (int j = 0; j < seg.GetNP(); j++) seg[j] = op2np[seg[j]]; } for(auto& pe : pointelements) pe.pnum = op2np[pe.pnum]; for (int i = 1; i <= openelements.Size(); i++) { Element2d & el = openelements.Elem(i); for (int j = 0; j < el.GetNP(); j++) el[j] = op2np[el[j]]; } for (int i = 0; i < lockedpoints.Size(); i++) lockedpoints[i] = op2np[lockedpoints[i]]; GetIdentifications().MapPoints(op2np); /* 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; } */ RebuildSurfaceElementLists (); CalcSurfacesOfNode(); // FindOpenElements(); timestamp = NextTimeStamp(); lock.UnLock(); } void Mesh :: OrderElements() { for (auto & el : surfelements) { if (el.GetType() == TRIG) while (el[0] > el[1] || el[0] > el[2]) { // rotate element auto hp = el[0]; el[0] = el[1]; el[1] = el[2]; el[2] = hp; auto hgi = el.GeomInfoPi(1); el.GeomInfoPi(1) = el.GeomInfoPi(2); el.GeomInfoPi(2) = el.GeomInfoPi(3); el.GeomInfoPi(3) = hgi; } } for (auto & el : volelements) if (el.GetType() == TET) { // lowest index first ... int mini = 0; for (int i = 1; i < 4; i++) if (el[i] < el[mini]) mini = i; if (mini != 0) { // swap 0 with mini, and the other two ... int i3 = -1, i4 = -1; for (int i = 1; i < 4; i++) if (i != mini) { i4 = i3; i3 = i; } swap (el[0], el[mini]); swap (el[i3], el[i4]); } while (el[1] > el[2] || el[1] > el[3]) { // rotate element to move second index to second position auto hp = el[1]; el[1] = el[2]; el[2] = el[3]; el[3] = hp; } } } int Mesh :: CheckConsistentBoundary () const { int nf = GetNOpenElements(); INDEX_2_HASHTABLE 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 () { static Timer t("Mesh::CheckOverlappingBoundary"); RegionTimer reg(t); Point3d pmin, pmax; GetBox (pmin, pmax); BoxTree<3, SurfaceElementIndex> setree(pmin, pmax); // NgArray inters; bool overlap = 0; bool incons_layers = 0; for (Element2d & el : SurfaceElements()) el.badel = false; for (SurfaceElementIndex sei : Range(SurfaceElements())) { const Element2d & tri = SurfaceElement(sei); Box<3> box(Box<3>::EMPTY_BOX); for (PointIndex pi : tri.PNums()) box.Add (Point(pi)); box.Increase(1e-3*box.Diam()); setree.Insert (box, sei); } std::mutex m; // for (SurfaceElementIndex sei : Range(SurfaceElements())) ParallelForRange (Range(SurfaceElements()), [&] (auto myrange) { for (SurfaceElementIndex sei : myrange) { const Element2d & tri = SurfaceElement(sei); Box<3> box(Box<3>::EMPTY_BOX); for (PointIndex pi : tri.PNums()) box.Add (Point(pi)); setree.GetFirstIntersecting (box.PMin(), box.PMax(), [&] (SurfaceElementIndex sej) { const Element2d & tri2 = SurfaceElement(sej); if ( (*this)[tri[0]].GetLayer() != (*this)[tri2[0]].GetLayer()) return false; 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 (int k = 0; k < 3; k++) { trip1[k] = &Point (tri[k]); trip2[k] = &Point (tri2[k]); } if (IntersectTriangleTriangle (&trip1[0], &trip2[0])) { overlap = 1; lock_guard guard(m); if(!incons_layers) { PrintWarning ("Intersecting elements " ,int(sei), " and ", int(sej)); (*testout) << "Intersecting: " << endl; (*testout) << "openelement " << sei << " with open element " << sej << endl; cout << "el1 = " << tri << endl; cout << "el2 = " << tri2 << endl; cout << "layer1 = " << (*this)[tri[0]].GetLayer() << endl; cout << "layer2 = " << (*this)[tri2[0]].GetLayer() << endl; } for (int k = 1; k <= 3; k++) (*testout) << tri.PNum(k) << " "; (*testout) << endl; for (int k = 1; k <= 3; k++) (*testout) << tri2.PNum(k) << " "; (*testout) << endl; for (int k = 0; k <= 2; k++) (*testout) << *trip1[k] << " "; (*testout) << endl; for (int k = 0; k <= 2; k++) (*testout) << *trip2[k] << " "; (*testout) << endl; (*testout) << "Face1 = " << GetFaceDescriptor(tri.GetIndex()) << endl; (*testout) << "Face1 = " << GetFaceDescriptor(tri2.GetIndex()) << endl; SurfaceElement(sei).badel = 1; SurfaceElement(sej).badel = 1; } return false; }); } }); // 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; } // Search for surface trigs with same vertices ( may happen for instance with close surfaces in stl geometies ) int Mesh :: FindIllegalTrigs () { // Temporary table to store the vertex numbers of all triangles INDEX_3_CLOSED_HASHTABLE temp_tab(3*GetNSE() + 1); size_t cnt = 0; for (SurfaceElementIndex sei = 0; sei < GetNSE(); sei++) { const Element2d & sel = surfelements[sei]; if (sel.IsDeleted()) continue; INDEX_3 i3(sel[0], sel[1], sel[2]); i3.Sort(); if(temp_tab.Used(i3)) { temp_tab.Set (i3, -1); cnt++; } else { temp_tab.Set (i3, sei); } } illegal_trigs = make_unique> (2*cnt+1); for (SurfaceElementIndex sei = 0; sei < GetNSE(); sei++) { const Element2d & sel = surfelements[sei]; if (sel.IsDeleted()) continue; INDEX_3 i3(sel[0], sel[1], sel[2]); i3.Sort(); if(temp_tab.Get(i3)==-1) illegal_trigs -> Set (i3, 1); } return cnt; } bool Mesh :: LegalTrig (const Element2d & el) const { if(illegal_trigs) { INDEX_3 i3 (el[0], el[1], el[2]); i3.Sort(); if(illegal_trigs->Used(i3)) return false; } 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; } double Mesh :: CalcTotalBad (const MeshingParameters & mp ) { static Timer t("CalcTotalBad"); RegionTimer reg(t); static constexpr int n_classes = 20; double sum = 0; tets_in_qualclass.SetSize(n_classes); tets_in_qualclass = 0; ParallelForRange( IntRange(volelements.Size()), [&] (auto myrange) { double local_sum = 0.0; double teterrpow = mp.opterrpow; // std::array classes_local{}; size_t n_classes = tets_in_qualclass.Size(); Array classes_local(n_classes); for (int i = 0; i < n_classes; i++) classes_local[i] = 0; for (auto i : myrange) { double elbad = pow (max2(CalcBad (points, volelements[i], 0, mp),1e-10), 1/teterrpow); int qualclass = int (n_classes / elbad + 1); if (qualclass < 1) qualclass = 1; if (qualclass > n_classes) qualclass = n_classes; classes_local[qualclass-1]++; local_sum += elbad; } AtomicAdd(sum, local_sum); for (auto i : Range(n_classes)) AsAtomic(tets_in_qualclass[i]) += classes_local[i]; }); return sum; } /// 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(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 -> Position0(INDEX_2::Sort(el[i], el[j])); if (pos != -1) { be = true; if (boundaryedges -> GetData0(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 without 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 :: SetDimension (int dim) { if (dimension == 3 && dim == 2) { // change mesh-dim from 3 to 2 (currently needed for OCC) for (auto str : materials) delete str; materials.SetSize(0); for (auto str : bcnames) materials.Append(str); bcnames.SetSize(0); for (auto str : cd2names) bcnames.Append(str); cd2names.SetSize(0); for (auto str : cd3names) cd2names.Append(str); cd3names.SetSize(0); for (auto & seg : LineSegments()) seg.si = seg.edgenr; } if (dimension == 3 && dim == 1) { for(auto str : materials) delete str; materials.SetSize(0); for(auto str : bcnames) delete str; bcnames.SetSize(0); for(auto str: cd2names) materials.Append(str); cd2names.SetSize(0); for(auto str : cd3names) bcnames.Append(str); cd3names.SetSize(0); } dimension = dim; } void Mesh :: SurfaceMeshOrientation () { // int i, j; int nse = GetNSE(); BitArray used(nse+1); used.Clear(); INDEX_2_HASHTABLE edges(nse+1); bool haschanged = 0; const Element2d & tri = SurfaceElement(1); for (int j = 1; j <= 3; j++) { INDEX_2 i2(tri.PNumMod(j), tri.PNumMod(j+1)); edges.Set (i2, 1); } used.SetBit(1); bool unused; do { bool changed; do { changed = 0; for (int i = 1; i <= nse; i++) if (!used.Test(i)) { Element2d & el = surfelements[i-1]; int found = 0, foundrev = 0; for (int 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 (int j = 1; j <= 3; j++) { INDEX_2 i2(el.PNumMod(j), el.PNumMod(j+1)); edges.Set (i2, 1); } used.SetBit (i); } } if (changed) haschanged = 1; } while (changed); unused = 0; for (int i = 1; i <= nse; i++) if (!used.Test(i)) { unused = 1; const Element2d & tri = SurfaceElement(i); for (int j = 1; j <= 3; j++) { INDEX_2 i2(tri.PNumMod(j), tri.PNumMod(j+1)); edges.Set (i2, 1); } used.SetBit(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 = IndexBASE()+GetNP(); 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) { for (int j = 0; j <= 3; j+= 3) { PointIndex 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 = GetNP() + IndexBASE(); 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) { for (int j = 0; j <= 4; j+= 4) { PointIndex 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(); } RebuildSurfaceElementLists(); } void Mesh :: BuildElementSearchTree (int dim) { if(dim < 2) return; if (elementsearchtreets[dim] == GetTimeStamp()) return; { std::lock_guard guard(buildsearchtree_mutex); // check again to see if some other thread built while waiting for lock if (elementsearchtreets[dim] == GetTimeStamp()) return; PrintMessage (4, "Rebuild element searchtree dim " + ToString(dim)); Point3d pmin, pmax; GetBox(pmin, pmax); Box<3> box(pmin, pmax); box.Scale(1.2); if (dim == 3) elementsearchtree_vol = make_unique>(box); else elementsearchtree_surf = make_unique>(box); if (dim == 3) { for(auto ei : volelements.Range()) { const auto& el = volelements[ei]; Box<3> box (Box<3>::EMPTY_BOX); for (auto pi : el.PNums()) box.Add (points[pi]); if(el.IsCurved() && curvedelems->IsElementCurved(ei)) { // add edge/face midpoints to box auto eltype = el.GetType(); const auto verts = topology.GetVertices(eltype); const auto edges = FlatArray(topology.GetNEdges(eltype), topology.GetEdges0(eltype)); for (const auto & edge: edges) { netgen::Point<3> lam = netgen::Point<3>(0.5* (verts[edge[0]] + verts[edge[1]])); auto p = netgen::Point<3>(0.0); curvedelems->CalcElementTransformation(lam,ei,p); box.Add(p); } const auto faces = FlatArray(topology.GetNFaces(eltype), topology.GetFaces0(eltype)); for (const auto & face: faces) { netgen::Vec<3> lam = netgen::Vec<3>(verts[face[0]] + verts[face[1]] + verts[face[2]]); if(face[3] != -1) { lam += netgen::Vec<3>(verts[face[3]]); lam *= 0.25; } else lam *= 1.0/3; auto p = netgen::Point<3>(0.0); curvedelems->CalcElementTransformation(netgen::Point<3>(lam),ei,p); box.Add(p); } } box.Scale(1.2); elementsearchtree_vol -> Insert (box, ei); } } else if (dim == 2) { for (auto ei : Range(surfelements)) { const auto& el = surfelements[ei]; Box<3> box (Box<3>::EMPTY_BOX); for (auto pi : el.PNums()) box.Add (points[pi]); if(el.IsCurved() && curvedelems->IsSurfaceElementCurved(ei)) { netgen::Point<2> lami [4] = {netgen::Point<2>(0.5,0), netgen::Point<2>(0,0.5), netgen::Point<2>(0.5,0.5), netgen::Point<2>(1./3,1./3)}; for (auto lam : lami) { netgen::Point<3> x; Mat<3,2> Jac; curvedelems->CalcSurfaceTransformation(lam,ei,x,Jac); box.Add (x); } box.Scale(1.2); } elementsearchtree_surf -> Insert (box, ei); } } elementsearchtreets[dim] = GetTimeStamp(); } } int SolveLinearSystemLS (const Vec3d & col1, const Vec3d & col2, const Vec3d & rhs, Vec2d & 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 = Vec2d (0, 0); return 1; } Vec2d aTrhs; aTrhs.X() = col1*rhs; aTrhs.Y() = col2*rhs; sol.X() = ( a22 * aTrhs.X() - a12 * aTrhs.Y()) / det; sol.Y() = (-a12 * aTrhs.X() + a11 * aTrhs.Y()) / det; return 0; } bool ValidBarCoord(double lami[3], double eps=1e-12) { return (lami[0]<=1.+eps && lami[0]>=0.-eps && lami[1]<=1.+eps && lami[1]>=0.-eps && lami[2]<=1.+eps && lami[2]>=0.-eps ); } bool Mesh :: PointContainedIn2DElement(const Point3d & p, double lami[3], SurfaceElementIndex ei, bool consider3D) const { Vec3d col1, col2, col3; Vec3d rhs, sol; const double eps = 1e-6; NgArray loctrigs; //SZ if(surfelements[ei].GetType()==QUAD) { const Element2d & el = surfelements[ei]; 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)); if (el.GetOrder() > 1 || el.GetHpElnr() != -1) { netgen::Point<2> lam(0.5,0.5); Vec<3> rhs; Vec<2> deltalam; netgen::Point<3> x; Mat<3,2> Jac; double delta = 1.; const int maxits = 30; int i = 0; while(delta > 1e-16 && i < maxits) { curvedelems->CalcSurfaceTransformation(lam,ei,x,Jac); rhs = p - x; Jac.Solve(rhs,deltalam); lam += deltalam; delta = deltalam.Length2(); i++; } if(i == maxits) return false; lami[0] = lam[0]; lami[1] = lam[1]; if(lami[0] < -eps || lami[0] > 1+eps || lami[1] < -eps || lami[1] > 1+eps) return false; return true; } // 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; /*cout << "p = " << p << endl; cout << "p1 = " << p1 << endl; cout << "p2 = " << p2 << endl; cout << "p3 = " << p3 << endl; cout << "p4 = " << p4 << endl; cout << "a = " << a << endl; cout << "b = " << b << endl; cout << "c = " << c << endl; cout << "d = " << d << endl;*/ Vec3d pa = p-a; double dxb = d.X()*b.Y()-d.Y()*b.X(); double dxc = d.X()*c.Y()-d.Y()*c.X(); double bxc = b.X()*c.Y()-b.Y()*c.X(); double bxpa = b.X()*pa.Y()-b.Y()*pa.X(); double cxpa = c.X()*pa.Y()-c.Y()*pa.X(); double dxpa = d.X()*pa.Y()-d.Y()*pa.X(); /*cout << "dxb = " << dxb << endl; cout << "dxc = " << dxc << endl; cout << "bxc = " << bxc << endl; cout << "bxpa = " << bxpa << endl; cout << "cxpa = " << cxpa << endl; cout << "dxpa = " << dxpa << endl;*/ /* P = a + b x + c y + d x y 1) P1 = a1 + b1 x + c1 y + d1 x y 2) P2 = a2 + b2 x + c2 y + d2 x y -> det(x,d) = det(a,d) + det(b,d) x + det(c,d) y -> x = 1/det(b,d) *( det(P-a,d)-det(c,d) y ) -> y = 1/det(c,d) *( det(P-a,d)-det(b,d) x ) -> x = (P1 - a1 - c1 y)/(b1 + d1 y) -> det(c,d) y**2 + [det(d,P-a) + det(c,b)] y + det(b,P-a) = 0 ( same if we express x = (P2 - a2 - c2 y)/(b2 + d2 y) ) -> y = (P1 - a1 - b1 x)/(c1 + d1 x) -> det(b,d) x**2 + [det(d,P-a) + det(b,c)] x + det(c,P-a) = 0 ( same if we express y = (P2 - a2 - b2 x)/(c2 + d2 x) */ lami[2]=0.; // double eps = 1.E-12; double c1,c2,r; //First check if point is "exactly" a vertex point Vec3d d1 = p-p1; Vec3d d2 = p-p2; Vec3d d3 = p-p3; Vec3d d4 = p-p4; //cout << " d1 = " << d1 << ", d2 = " << d2 << ", d3 = " << d3 << ", d4 = " << d4 << endl; if (d1.Length2() < sqr(eps)*d2.Length2() && d1.Length2() < sqr(eps)*d3.Length2() && d1.Length2() < sqr(eps)*d4.Length2()) { lami[0] = lami[1] = 0.; return true; } else if (d2.Length2() < sqr(eps)*d1.Length2() && d2.Length2() < sqr(eps)*d3.Length2() && d2.Length2() < sqr(eps)*d4.Length2()) { lami[0] = 1.; lami[1] = 0.; return true; } else if (d3.Length2() < sqr(eps)*d1.Length2() && d3.Length2() < sqr(eps)*d2.Length2() && d3.Length2() < sqr(eps)*d4.Length2()) { lami[0] = lami[1] = 1.; return true; } else if (d4.Length2() < sqr(eps)*d1.Length2() && d4.Length2() < sqr(eps)*d2.Length2() && d4.Length2() < sqr(eps)*d3.Length2()) { lami[0] = 0.; lami[1] = 1.; return true; }//if d is nearly 0: solve resulting linear system else if (d.Length2() < sqr(eps)*b.Length2() && d.Length2() < sqr(eps)*c.Length2()) { Vec2d sol; SolveLinearSystemLS (b, c, p-a, sol); lami[0] = sol.X(); lami[1] = sol.Y(); return ValidBarCoord(lami, eps); }// if dxc is nearly 0: solve resulting linear equation for y and compute x else if (fabs(dxc) < sqr(eps)) { lami[1] = -bxpa/(dxpa-bxc); lami[0] = (dxpa-dxc*lami[1])/dxb; return ValidBarCoord(lami, eps); }// if dxb is nearly 0: solve resulting linear equation for x and compute y else if (fabs(dxb) < sqr(eps)) { lami[0] = -cxpa/(dxpa+bxc); lami[1] = (dxpa-dxb*lami[0])/dxc; return ValidBarCoord(lami, eps); }//if dxb >= dxc: solve quadratic equation in y and compute x else if (fabs(dxb) >= fabs(dxc)) { c1 = (bxc-dxpa)/dxc; c2 = -bxpa/dxc; r = c1*c1/4.0-c2; //quadratic equation has only 1 (unstable) solution if (fabs(r) < eps) //not eps^2! { lami[1] = -c1/2; lami[0] = (dxpa-dxc*lami[1])/dxb; return ValidBarCoord(lami, eps); } if (r < 0) return false; lami[1] = -c1/2+sqrt(r); lami[0] = (dxpa-dxc*lami[1])/dxb; if (ValidBarCoord(lami, eps)) return true; else { lami[1] = -c1/2-sqrt(r); lami[0] = (dxpa-dxc*lami[1])/dxb; return ValidBarCoord(lami, eps); } }//if dxc > dxb: solve quadratic equation in x and compute y else { c1 = (-bxc-dxpa)/dxb; c2 = -cxpa/dxb; r = c1*c1/4.0-c2; //quadratic equation has only 1 (unstable) solution if (fabs(r) < eps) //not eps^2! { lami[0] = -c1/2; lami[1] = (dxpa-dxb*lami[0])/dxc; return ValidBarCoord(lami, eps); } if (r < 0) return false; lami[0] = -c1/2+sqrt(r); lami[1] = (dxpa-dxb*lami[0])/dxc; if (ValidBarCoord(lami, eps)) return true; else { lami[0] = -c1/2-sqrt(r); lami[1] = (dxpa-dxb*lami[0])/dxc; return ValidBarCoord(lami, eps); } } /* 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; Vec3d dp13 = p3-p1; Vec3d dp24 = p4-p2; double d1 = dp13.Length2(); double d2 = dp24.Length2(); // if(fabs(d.X()) <= eps && fabs(d.Y())<= eps) //if (d.Length2() < sqr(eps)) if (d.Length2() < sqr(eps)*d1 && d.Length2() < sqr(eps)*d2) { //Solve Linear System Vec2d sol; SolveLinearSystemLS (b, c, p-a, sol); lami[0] = sol.X(); lami[1] = sol.Y(); if(lami[1]<=1.+eps && lami[1]>=0.-eps && lami[0]<=1.+eps && lami[0]>=0.-eps) return true; //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*fabs(dxc)) { lami[1] = (dxp-dxa)/dxc; if(fabs(b.X()+d.X()*lami[1])>=fabs(b.Y()+d.Y()*lami[1])) 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]); if(lami[1]<=1.+eps && lami[1]>=0.-eps && lami[0]<=1.+eps && lami[0]>=0.-eps) return true; } else if(fabs(dxc) <= eps*fabs(dxb)) { lami[0] = (dxp-dxa)/dxb; if(fabs(c.X()+d.X()*lami[0])>=fabs(c.Y()+d.Y()*lami[0])) 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]); if(lami[1]<=1.+eps && lami[1]>=0.-eps && lami[0]<=1.+eps && lami[0]>=0.-eps) return true; } else //Solve quadratic equation { c2 = -d.X()*dxb; c1 = b.X()*dxc - c.X()*dxb + d.X()*(dxp-dxa); c0 = c.X()*(dxp-dxa) + (a.X()-p.X())*dxc; double rt = c1*c1 - 4*c2*c0; if (rt < 0.) return false; lami[1] = (-c1 + sqrt(rt))/2/c2; if(lami[1]<=1.+eps && lami[1]>=0.-eps) { lami[0] = (dxp - dxa -dxb*lami[1])/dxc; if(lami[0]<=1.+eps && lami[0]>=0.-eps) return true; } lami[1] = (-c1 - sqrt(rt))/2/c2; lami[0] = (dxp - dxa -dxb*lami[1])/dxc; if(lami[1]<=1.+eps && lami[1]>=0.-eps && lami[0]<=1.+eps && lami[0]>=0.-eps) return true; c2 = d.Y()*dxb; c1 = b.Y()*dxc - c.Y()*dxb + d.Y()*(dxp-dxa); c0 = c.Y()*(dxp -dxa) + (a.Y()-p.Y())*dxc; rt = c1*c1 - 4*c2*c0; if (rt < 0.) return false; lami[1] = (-c1 + sqrt(rt))/2/c2; if(lami[1]<=1.+eps && lami[1]>=0.-eps) { lami[0] = (dxp - dxa -dxb*lami[1])/dxc; if(lami[0]<=1.+eps && lami[0]>=0.-eps) return true; } lami[1] = (-c1 - sqrt(rt))/2/c2; lami[0] = (dxp - dxa -dxb*lami[1])/dxc; if(lami[1]<=1.+eps && lami[1]>=0.-eps && lami[0]<=1.+eps && lami[0]>=0.-eps) return true; c2 = -d.X()*dxc; c1 = -b.X()*dxc + c.X()*dxb + d.X()*(dxp-dxa); c0 = b.X()*(dxp -dxa) + (a.X()-p.X())*dxb; rt = c1*c1 - 4*c2*c0; if (rt < 0.) return false; lami[1] = (-c1 + sqrt(rt))/2/c2; if(lami[1]<=1.+eps && lami[1]>=0.-eps) { lami[0] = (dxp - dxa -dxc*lami[1])/dxb; if(lami[0]<=1.+eps && lami[0]>=0.-eps) return true; } lami[1] = (-c1 - sqrt(rt))/2/c2; lami[0] = (dxp - dxa -dxc*lami[1])/dxb; if(lami[1]<=1.+eps && lami[1]>=0.-eps && lami[0]<=1.+eps && lami[0]>=0.-eps) return true; }*/ //cout << "lam0,1 = " << lami[0] << ", " << lami[1] << endl; /*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) = surfelements[ei]; 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 (surfelements[ei].GetType() ==TRIG6 || curvedelems->IsSurfaceElementCurved(ei)) { // netgen::Point<2> lam(1./3,1./3); netgen::Point<2> lam(sol.X(), sol.Y()); if(surfelements[ei].GetType() != TRIG6) { lam[0] = 1-sol.X()-sol.Y(); lam[1] = sol.X(); } Vec<3> rhs; Vec<2> deltalam; netgen::Point<3> x; Mat<3,2> Jac,Jact; double delta=1; // bool retval; int i = 0; const int maxits = 30; while(delta > 1e-16 && iCalcSurfaceTransformation(lam,ei,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; sol.X() = lam(0); sol.Y() = lam(1); if (surfelements[ei].GetType() !=TRIG6 ) { sol.Z() = sol.X(); sol.X() = sol.Y(); sol.Y() = 1.0 - sol.Z() - sol.X(); } } 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], ElementIndex ei, double eps) 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 Element & el = volelements[ei]; netgen::Point<3> lam = 0.0; if (el.GetType() == TET || el.GetType() == TET10) { 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 && iCalcElementTransformation(lam,ei,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 || el.GetType() == TET10) { retval = (lam(0) > -eps && lam(1) > -eps && lam(2) > -eps && lam(0) + lam(1) + lam(2) < 1+eps); } else if (el.GetType() == PRISM || el.GetType() == PRISM15) { 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 || el.GetType() == PYRAMID13) { 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 || el.GetType() == HEX20) { 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], ElementIndex element, double eps) const { Vec3d col1, col2, col3; Vec3d rhs, sol; NgArray 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) { NgArray loctetsloc; NgArray > 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; } ElementIndex Mesh :: GetElementOfPoint (const netgen::Point<3> & p, double* lami, bool build_searchtree, int index, bool allowindex, double tol) const { if(index != -1) { Array dummy(1); dummy[0] = index; return GetElementOfPoint(p,lami,dummy,build_searchtree,allowindex, tol); } else return GetElementOfPoint(p,lami,nullopt,build_searchtree,allowindex, tol); } ElementIndex Mesh :: GetElementOfPoint (const netgen::Point<3> & p, double* lami, std::optional> indices, bool build_searchtree, bool allowindex, double tol) const { if (build_searchtree) const_cast(*this).BuildElementSearchTree (3); return Find3dElement(*this, p, lami, indices, elementsearchtree_vol.get(), allowindex, tol); } SurfaceElementIndex Mesh :: GetSurfaceElementOfPoint (const netgen::Point<3> & p, double* lami, bool build_searchtree, int index, bool allowindex) const { if(index != -1) { Array dummy(1); dummy[0] = index; return GetSurfaceElementOfPoint(p,lami,dummy,build_searchtree,allowindex); } else return GetSurfaceElementOfPoint(p,lami,nullopt,build_searchtree,allowindex); } SurfaceElementIndex Mesh :: GetSurfaceElementOfPoint (const netgen::Point<3> & p, double* lami, std::optional> indices, bool build_searchtree, bool allowindex) const { if (build_searchtree) const_cast(*this).BuildElementSearchTree(2); return Find2dElement(*this, p, lami, indices, elementsearchtree_surf.get(), allowindex); } void Mesh::GetIntersectingVolEls(const Point3d& p1, const Point3d& p2, Array & locels) const { elementsearchtree_vol->GetIntersecting (p1, p2, locels); } void Mesh :: SplitIntoParts() { // int i, j, dom; int ne = GetNE(); int np = GetNP(); int nse = GetNSE(); BitArray surfused(nse+1); TBitArray pused (np); surfused.Clear(); int dom = 0; while (1) { int cntd = 1; dom++; pused.Clear(); int found = 0; for (int i = 1; i <= nse; i++) if (!surfused.Test(i)) { SurfaceElement(i).SetIndex (dom); for (int j = 1; j <= 3; j++) pused.SetBit (SurfaceElement(i).PNum(j)); found = 1; cntd = 1; surfused.SetBit(i); break; } if (!found) break; int change; do { change = 0; for (int i = 1; i <= nse; i++) { int is = 0, isnot = 0; for (int j = 1; j <= 3; j++) if (pused.Test(SurfaceElement(i).PNum(j))) is = 1; else isnot = 1; if (is && isnot) { change = 1; for (int j = 1; j <= 3; j++) pused.SetBit (SurfaceElement(i).PNum(j)); } if (is) { if (!surfused.Test(i)) { surfused.SetBit(i); SurfaceElement(i).SetIndex (dom); cntd++; } } } for (int i = 1; i <= ne; i++) { int is = 0, isnot = 0; for (int j = 1; j <= 4; j++) if (pused.Test(VolumeElement(i).PNum(j))) is = 1; else isnot = 1; if (is && isnot) { change = 1; for (int j = 1; j <= 4; j++) pused.SetBit (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 (int 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(); TBitArray usedp(np); Array els_of_face; fdi = 1; while (fdi <= GetNFD()) { GetSurfaceElementsOfFace (fdi, els_of_face); if (els_of_face.Size() == 0) { fdi++; continue; } SurfaceElementIndex firstel = els_of_face[0]; usedp.Clear(); for (int j = 1; j <= SurfaceElement(firstel).GetNP(); j++) usedp.SetBit (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.SetBit (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]; } // map the segments for(auto& seg : segments) if(!usedp.Test(seg[0]) || !usedp.Test(seg[1])) if(seg.si == fdi) seg.si = nface; } 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 :: ZRefine(const string& name, const Array& slices) { auto nr = GetIdentifications().GetNr(name); auto& identpts = GetIdentifications().GetIdentifiedPoints(); UpdateTopology(); std::map, Array> inserted_points; BitArray mapped_points(GetNV()+1); mapped_points = false; // Add new points for(auto [hash, dummy] : identpts) { auto [hash_pts, hash_nr] = hash; if(hash_nr != nr) continue; // auto& ipts = inserted_points[{p1p2.I1(), p1p2.I2()}]; auto& ipts = inserted_points[ { hash_pts[0], hash_pts[1] }]; auto p1 = Point(hash_pts.I1()); auto p2 = Point(hash_pts.I2()); ipts.Append(hash_pts.I1()); mapped_points.SetBit(hash_pts.I1()); for(auto slice : slices) { auto np = p1 + slice * (p2-p1); auto npi = AddPoint(np); ipts.Append(npi); } ipts.Append(hash_pts.I2()); } // Split segments for(auto si : Range(segments)) { auto& seg = segments[si]; // Copy segment, as reference above might get invalidated in AddSegment() auto reference_seg = seg; auto p1 = seg[0]; auto p2 = seg[1]; auto c1 = inserted_points.count({p1, p2}); auto c2 = inserted_points.count({p2, p1}); if(c1 == 0 && c2 == 0) continue; if(c2) Swap(p1,p2); const auto& ipts = inserted_points[{p1,p2}]; if(c2) seg[1] = ipts[ipts.Size()-2]; else seg[1] = ipts[1]; for(auto i : Range(size_t(1), ipts.Size()-1)) { Segment snew = reference_seg; if(c2) { snew[0] = ipts[ipts.Size()-1-i]; snew[1] = ipts[ipts.Size()-2-i]; } else { snew[0] = ipts[i]; snew[1] = ipts[i+1]; } AddSegment(snew); } } BitArray sel_done(surfelements.Size()); sel_done = false; // Split surface elements auto p2sel = CreatePoint2SurfaceElementTable(); for(const auto& [pair, inserted] : inserted_points) { for(auto si : p2sel[pair.first]) { if(sel_done[si]) continue; sel_done.SetBit(si); auto sel = surfelements[si]; map> mapped_points; int nmapped = 0; for(auto i : Range(sel.GetNP())) { auto p1 = sel[i]; auto p2 = sel[(i+1)%sel.GetNP()]; auto c1 = inserted_points.count({p1, p2}); auto c2 = inserted_points.count({p2, p1}); if(c1 == 0 && c2 == 0) continue; if(c2) Swap(p1, p2); auto& ipts = inserted_points[{p1, p2}]; auto& a1 = mapped_points[p1]; auto& a2 = mapped_points[p2]; a1 = ipts.Range(0, ipts.Size()-1); a2 = ipts.Range(1, ipts.Size()); nmapped = ipts.Size()-1; } for(auto i : Range(nmapped)) { Element2d nsel = sel; for(auto& pi : nsel.PNums()) if(mapped_points.count(pi)) pi = mapped_points[pi][i]; AddSurfaceElement(nsel); } if(nmapped) surfelements[si].Delete(); } } // Split volume elements BitArray vol_done(volelements.Size()); vol_done = false; auto p2el = CreatePoint2ElementTable(); // mapped_points); for(const auto& [pair, inserted] : inserted_points) { for(auto ei : p2el[pair.first]) { if(vol_done[ei]) continue; vol_done.SetBit(ei); auto el = volelements[ei]; map> mapped_points; int nmapped = 0; // NgArray eledges; // topology.GetElementEdges(ei+1, eledges); // for(auto edgei : eledges) for(auto edgei : topology.GetEdges(ElementIndex(ei))) { // int p1, p2; // topology.GetEdgeVertices(edgei+1, p1, p2); auto [p1, p2] = topology.GetEdgeVertices(edgei); auto c1 = inserted_points.count({p1, p2}); auto c2 = inserted_points.count({p2, p1}); if(c1 == 0 && c2 == 0) continue; if(c2) Swap(p1, p2); auto& ipts = inserted_points[{p1, p2}]; auto& a1 = mapped_points[p1]; auto& a2 = mapped_points[p2]; a1 = ipts.Range(0, ipts.Size()-1); a2 = ipts.Range(1, ipts.Size()); nmapped = ipts.Size()-1; } for(auto i : Range(nmapped)) { Element nel = el; for(auto& pi : nel.PNums()) if(mapped_points.count(pi)) pi = mapped_points[pi][i]; AddVolumeElement(nel); } if(nmapped) volelements[ei].Delete(); } } Compress(); SetNextMajorTimeStamp(); } void Mesh :: RebuildSurfaceElementLists () { static Timer t("Mesh::LinkSurfaceElements"); RegionTimer reg (t); 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 & sei) const { static int timer = NgProfiler::CreateTimer ("GetSurfaceElementsOfFace"); NgProfiler::RegionTimer reg (timer); if(facenr==0) { sei.SetSize(GetNSE()); ParallelForRange( IntRange(GetNSE()), [&sei] (auto myrange) { for(auto i : myrange) sei[i] = i; }); return; } sei.SetSize(0); SurfaceElementIndex si = facedecoding[facenr-1].firstelement; while (si != -1) { if ( (*this)[si].GetIndex () == facenr && (*this)[si][0].IsValid() && !(*this)[si].IsDeleted() ) { sei.Append (si); } si = (*this)[si].next; } } void Mesh :: CalcMinMaxAngle (double badellimit, double * retvalues) { int lpi1, lpi2, lpi3, lpi4; double phimax = 0, phimin = 10; double facephimax = 0, facephimin = 10; int illegaltets = 0, negativetets = 0, badtets = 0; // for (int i = 1; i <= GetNE(); i++) for (ElementIndex ei : Range(VolumeElements())) { int badel = 0; Element & el = VolumeElement(ei); if (el.GetType() != TET) { VolumeElement(ei).Flags().badel = 0; continue; } if (el.Volume(Points()) < 0) { badel = 1; negativetets++; } if (!LegalTet (el)) { badel = 1; illegaltets++; (*testout) << "illegal tet: " << ei << " "; for (int 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 (int j = 1; j <= 4; j++) { Element2d face(TRIG); 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(ei).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 domain) { if(!boundaryedges) BuildBoundaryEdges(); atomic cnt = 0; ParallelForRange( Range(volelements), [&] (auto myrange) { int cnt_local = 0; for(auto & el : volelements.Range(myrange)) if ((domain==0 || el.GetIndex() == domain) && !LegalTet (el)) cnt_local++; cnt += cnt_local; }); 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, NgArray & 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, NgArray & 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 int Mesh::IdentifyPeriodicBoundaries(const string& id_name, const string &s1, const Transformation<3> &mapping, double pointTolerance) { auto nr = ident->GetNr(id_name); ident->SetType(nr, Identifications::PERIODIC); // double lami[4]; set identified_points; if(pointTolerance < 0.) { Point3d pmin, pmax; GetBox(pmin, pmax); pointTolerance = 1e-8 * (pmax-pmin).Length(); } size_t nse = GetDimension() == 3 ? surfelements.Size() : segments.Size(); for(auto sei : Range(nse)) { auto name = GetDimension() == 3 ? GetBCName(surfelements[sei].index-1) : GetBCName(segments[sei].edgenr-1); if(name != s1) continue; const auto& pnums = GetDimension() == 3 ? surfelements[sei].PNums() : segments[sei].PNums(); for(const auto& pi : pnums) { if(identified_points.find(pi) != identified_points.end()) continue; auto pt = (*this)[pi]; auto mapped_pt = mapping(pt); bool found = false; for(auto other_pi : Range(points)) { if((mapped_pt - (*this)[other_pi]).Length() < pointTolerance) { identified_points.insert(pi); ident->Add(pi, other_pi, nr); found = true; break; } } if(!found) { cout << "point coordinates = " << pt << endl; cout << "mapped coordinates = " << mapped_pt << endl; throw Exception("Did not find mapped point with nr " + ToString(pi) + ", are you sure your mesh is periodic?"); } } } return nr; } 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 () { numvertices = 0; /* for (const Element & el : VolumeElements()) for (PointIndex v : el.Vertices()) if (v > numvertices) numvertices = v; for (const Element2d & el : SurfaceElements()) for (PointIndex v : el.Vertices()) if (v > numvertices) numvertices = v; numvertices += 1-PointIndex::BASE; */ numvertices = 0; numvertices = ParallelReduce (VolumeElements().Size(), [&](size_t nr) { return int(Max(VolumeElements()[nr].Vertices())); }, [](auto a, auto b) { return a > b ? a : b; }, numvertices); numvertices = ParallelReduce (SurfaceElements().Size(), [&](size_t nr) { return int(Max(SurfaceElements()[nr].Vertices())); }, [](auto a, auto b) { return a > b ? a : b; }, numvertices); numvertices = ParallelReduce (LineSegments().Size(), [&](size_t nr) { return int(Max(LineSegments()[nr].Vertices())); }, [](auto a, auto b) { return a > b ? a : b; }, numvertices); 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 (PointIndex i = mlold+IndexBASE(); i < np+IndexBASE(); i++) { mlbetweennodes[i][0].Invalidate(); mlbetweennodes[i][1].Invalidate(); } GetIdentifications().SetMaxPointNr (np + PointIndex::BASE-1); } Table Mesh :: CreatePoint2ElementTable(std::optional> points, int domain) const { static Timer timer("Mesh::CreatePoint2VolumeElementTable"); RegionTimer rt(timer); if(points) { const auto & free_points = *points; return ngcore::CreateSortedTable( volelements.Range(), [&](auto & table, ElementIndex ei) { const auto & el = (*this)[ei]; if(el.IsDeleted()) return; if(domain && el.GetIndex() != domain) return; for (PointIndex pi : el.PNums()) if(free_points[pi]) table.Add (pi, ei); }, GetNP()); } else return ngcore::CreateSortedTable( volelements.Range(), [&](auto & table, ElementIndex ei) { const auto & el = (*this)[ei]; if(el.IsDeleted()) return; if(domain && el.GetIndex() != domain) return; for (PointIndex pi : el.PNums()) table.Add (pi, ei); }, GetNP()); } Table Mesh :: CreatePoint2SurfaceElementTable( int faceindex ) const { static Timer timer("Mesh::CreatePoint2SurfaceElementTable"); RegionTimer rt(timer); if(faceindex==0) { return ngcore::CreateSortedTable( surfelements.Range(), [&](auto & table, SurfaceElementIndex ei) { for (PointIndex pi : (*this)[ei].PNums()) table.Add (pi, ei); }, GetNP()); } Array face_els; GetSurfaceElementsOfFace(faceindex, face_els); return ngcore::CreateSortedTable( face_els.Range(), [&](auto & table, size_t i) { for (PointIndex pi : (*this)[face_els[i]].PNums()) table.Add (pi, face_els[i]); }, GetNP()); } CompressedTable Mesh :: CreateCompressedPoint2SurfaceElementTable( int faceindex ) const { static Timer timer("Mesh::CreatePoint2SurfaceElementTable"); RegionTimer rt(timer); CompressedTableCreator creator; if(faceindex==0) { for ( ; !creator.Done(); creator++) for (auto sei : SurfaceElements().Range()) for (auto pi : (*this)[sei].PNums()) creator.Add(pi, sei); } else { Array face_els; GetSurfaceElementsOfFace(faceindex, face_els); for ( ; !creator.Done(); creator++) for (auto sei : face_els) for (auto pi : (*this)[sei].PNums()) creator.Add(pi, sei); } auto compressed_table = creator.MoveTable(); for (auto row : compressed_table.GetTable()) QuickSort (row); return compressed_table; } /* void Mesh :: BuildConnectedNodes () { if (PureTetMesh()) { connectedtonode.SetSize(0); return; } int i, j, k; int np = GetNP(); int ne = GetNE(); TABLE 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 & 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 (NgTaskManager tm, NgTracer tracer) { static Timer t("Update Topology"); RegionTimer reg(t); ComputeNVertices(); topology.Update(tm, tracer); (*tracer)("call update clusters", false); clusters->Update(); (*tracer)("call update clusters", true); #ifdef PARALLEL if (paralleltop) { paralleltop->Reset(); paralleltop->UpdateCoarseGrid(); } #endif updateSignal.Emit(); } void Mesh :: BuildCurvedElements (const Refinement * ref, int aorder, bool arational) { GetCurvedElements().BuildCurvedElements (ref, aorder, arational); for (SegmentIndex seg = 0; seg < GetNSeg(); seg++) (*this)[seg].SetCurved (GetCurvedElements().IsSegmentCurved (seg)); for (SurfaceElementIndex sei = 0; sei < GetNSE(); sei++) (*this)[sei].SetCurved (GetCurvedElements().IsSurfaceElementCurved (sei)); for (ElementIndex ei = 0; ei < GetNE(); ei++) (*this)[ei].SetCurved (GetCurvedElements().IsElementCurved (ei)); SetNextMajorTimeStamp(); } void Mesh :: BuildCurvedElements (int aorder) { if (!GetGeometry()) throw NgException ("don't have a geometry for mesh curving"); GetCurvedElements().BuildCurvedElements (&GetGeometry()->GetRefinement(), aorder, false); for (SegmentIndex seg = 0; seg < GetNSeg(); seg++) (*this)[seg].SetCurved (GetCurvedElements().IsSegmentCurved (seg)); for (SurfaceElementIndex sei = 0; sei < GetNSE(); sei++) (*this)[sei].SetCurved (GetCurvedElements().IsSurfaceElementCurved (sei)); for (ElementIndex ei = 0; ei < GetNE(); ei++) (*this)[ei].SetCurved (GetCurvedElements().IsElementCurved (ei)); SetNextMajorTimeStamp(); } void Mesh :: SplitFacesByAdjacentDomains () { UpdateTopology(); std::map, int> face_doms_2_new_face; int nfaces = FaceDescriptors().Size(); Array first_visit(nfaces); first_visit = true; for (auto sei : Range(SurfaceElements())) { int eli0, eli1; GetTopology().GetSurface2VolumeElement(sei+1, eli0, eli1); // auto [ei0,ei1] = GetTopology().GetSurface2VolumeElement(sei); // the way to go if(eli0 == 0) continue; auto & sel = (*this)[sei]; int face = sel.GetIndex(); int domin = VolumeElement(eli0).GetIndex(); int domout = eli1 ? VolumeElement(eli1).GetIndex() : 0; if(domin < domout) swap(domin, domout); auto key = std::make_tuple(face, domin, domout); if(face_doms_2_new_face.find(key) == face_doms_2_new_face.end()) { { auto & fd = FaceDescriptors()[face-1]; if(domout == 0 && min(fd.DomainIn(), fd.DomainOut()) > 0) continue; } if(!first_visit[face-1]) { nfaces++; FaceDescriptor new_fd = FaceDescriptors()[face-1]; new_fd.bcprop = nfaces; new_fd.domin = domin; new_fd.domout = domout; AddFaceDescriptor(new_fd); SetBCName(nfaces-1, new_fd.GetBCName()); face_doms_2_new_face[key] = nfaces; } else { face_doms_2_new_face[key] = face; auto & fd = FaceDescriptors()[face-1]; fd.domin = domin; fd.domout = domout; } first_visit[face-1] = false; } sel.SetIndex(face_doms_2_new_face[key]); } SetNextMajorTimeStamp(); RebuildSurfaceElementLists (); CalcSurfacesOfNode(); UpdateTopology(); } shared_ptr Mesh :: GetSubMesh(string domains, string faces) const { // Copy the mesh into a new one, then delete unwanted elements // Unused points are deleted by the Compress() function at the end auto mesh_ptr = make_unique(); auto & mesh = *mesh_ptr; mesh = (*this); auto ndomains = GetNDomains(); auto nfaces = GetNFD(); BitArray keep_point(GetNP()+1); BitArray keep_face(nfaces+1); BitArray keep_domain(ndomains+1); keep_point.Clear(); keep_face.Clear(); keep_domain.Clear(); regex regex_faces(faces); regex regex_domains(domains); if(dimension == 3) { for(auto dom : Range(ndomains)) if(regex_match(mesh.GetMaterial(dom+1), regex_domains)) keep_domain.SetBit(dom+1); for(auto fi : Range(nfaces)) { auto & fd = mesh.FaceDescriptors()[fi]; if (regex_match(fd.GetBCName(), regex_faces) || keep_domain[fd.DomainIn()] || keep_domain[fd.DomainOut()]) keep_face.SetBit(fd.BCProperty()); } } else { for(auto fi : Range(nfaces)) { auto & fd = mesh.FaceDescriptors()[fi]; auto mat = GetMaterial(fd.BCProperty()); if (regex_match(mat, regex_faces)) keep_face.SetBit(fd.BCProperty()); } } auto filter_elements = [&keep_point](auto & elements, auto & keep_region) { for(auto & el : elements) { if(keep_region[el.GetIndex()]) for (auto pi : el.PNums()) keep_point.SetBit(pi); else el.Delete(); } }; filter_elements(mesh.VolumeElements(), keep_domain); filter_elements(mesh.SurfaceElements(), keep_face); // Keep line segments only if all points are kept // Check them in reverse order because they are deleted from the end auto nsegments = mesh.LineSegments().Size(); for(auto i : Range(nsegments)) { SegmentIndex segi = nsegments-i-1; auto seg = mesh[segi]; bool keep = true; for(auto pi : seg.PNums()) keep &= keep_point[pi]; if(!keep) mesh.LineSegments().DeleteElement(segi); } // Check in reverse order because they are deleted from the end auto npointelements = mesh.pointelements.Size(); for(auto i : Range(npointelements)) { auto pel = mesh.pointelements[npointelements-i-1]; if(!keep_point[pel.pnum]) mesh.pointelements.DeleteElement(npointelements-i-1); } mesh.Compress(); return mesh_ptr; } void Mesh :: SetMaterial (int domnr, const string & mat) { if (domnr > materials.Size()) { int olds = materials.Size(); materials.SetSize (domnr); for (int i = olds; i < domnr-1; i++) materials[i] = new string("default"); } /* materials.Elem(domnr) = new char[strlen(mat)+1]; strcpy (materials.Elem(domnr), mat); */ materials[domnr-1] = new string(mat); } string Mesh :: defaultmat = "default"; string_view Mesh :: defaultmat_sv = "default"; const string & Mesh :: GetMaterial (int domnr) const { if (domnr <= materials.Size() && materials[domnr-1]) return *materials[domnr-1]; static string emptystring("default"); return emptystring; } 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 (bcnr >= bcnames.Size()) { int oldsize = bcnames.Size(); bcnames.SetSize (bcnr+1); // keeps contents for (int i = oldsize; i <= bcnr; i++) bcnames[i] = new string("default"); } if ( bcnames[bcnr] ) delete bcnames[bcnr]; bcnames[bcnr] = new string ( abcname ); for (auto & fd : facedecoding) if (fd.BCProperty() <= bcnames.Size()) fd.SetBCName (bcnames[fd.BCProperty()-1]); } const string & Mesh ::GetBCName ( int bcnr ) const { static string defaultstring = "default"; if ( !bcnames.Size() ) return defaultstring; if (bcnr < 0 || bcnr >= bcnames.Size()) throw RangeException("Illegal bc number ", bcnr, 0, bcnames.Size()); if ( bcnames[bcnr] ) return *bcnames[bcnr]; else return defaultstring; } void Mesh :: SetNCD2Names( int ncd2n ) { if (cd2names.Size()) for(int i=0; i= cd2names.Size()) { int oldsize = cd2names.Size(); cd2names.SetSize(cd2nr+1); for(int i= oldsize; i<= cd2nr; i++) cd2names[i] = nullptr; } //if (cd2names[cd2nr]) delete cd2names[cd2nr]; if (abcname != "default" && abcname != "") cd2names[cd2nr] = new string(abcname); else cd2names[cd2nr] = nullptr; } string Mesh :: cd2_default_name = "default"; string Mesh :: default_bc = "default"; const string & Mesh :: GetCD2Name (int cd2nr) const { static string defaultstring = "default"; if (!cd2names.Size()) return defaultstring; if (cd2nr < 0 || cd2nr >= cd2names.Size()) return defaultstring; if (cd2names[cd2nr]) return *cd2names[cd2nr]; else return defaultstring; } void Mesh :: SetNCD3Names( int ncd3n ) { if (cd3names.Size()) for(int i=0; i= cd3names.Size()) { int oldsize = cd3names.Size(); cd3names.SetSize(cd3nr+1); for(int i= oldsize; i<= cd3nr; i++) cd3names[i] = nullptr; } if (abcname != "default") cd3names[cd3nr] = new string(abcname); else cd3names[cd3nr] = nullptr; } int Mesh :: AddCD3Name (const string & aname) { for (int i = 0; i < cd3names.Size(); i++) if (*cd3names[i] == aname) return i; cd3names.Append (new string(aname)); return cd3names.Size()-1; } string Mesh :: cd3_default_name = "default"; static string defaultstring = "default"; const string & Mesh :: GetCD3Name (int cd3nr) const { if (!cd3names.Size()) return defaultstring; if (cd3nr < 0 || cd3nr >= cd3names.Size()) return defaultstring; if (cd3names[cd3nr]) return *cd3names[cd3nr]; else return defaultstring; } Array & Mesh :: GetRegionNamesCD (int codim) { switch (codim) { case 0: return materials; case 1: return bcnames; case 2: return cd2names; case 3: return cd3names; default: throw Exception("don't have regions of co-dimension "+ToString(codim)); } } FlatArray Mesh :: GetRegionNamesCD (int codim) const { switch (codim) { case 0: return materials; case 1: return bcnames; case 2: return cd2names; case 3: return cd3names; default: throw Exception("don't have regions of co-dimension "+ToString(codim)); } } std::string_view Mesh :: GetRegionName (const Segment & el) const { return *const_cast(*this).GetRegionNamesCD(GetDimension()-1)[el.edgenr-1]; } std::string_view Mesh :: GetRegionName (const Element2d & el) const { // return *const_cast(*this).GetRegionNamesCD(GetDimension()-2)[GetFaceDescriptor(el).BCProperty()-1]; auto ind = GetFaceDescriptor(el).BCProperty()-1; auto names = this->GetRegionNamesCD(GetDimension()-2); if (!names.Range().Contains(ind)) return defaultstring; if (!names[ind]) return defaultstring; return *names[ind]; } std::string_view Mesh :: GetRegionName (const Element & el) const { const auto& names = const_cast(*this).GetRegionNamesCD(GetDimension()-3); if(names.Size() <= el.GetIndex()) return defaultstring; return *const_cast(*this).GetRegionNamesCD(GetDimension()-3)[el.GetIndex()-1]; } void Mesh :: SetUserData(const char * id, NgArray & data) { if(userdata_int.Used(id)) delete userdata_int[id]; NgArray * newdata = new NgArray(data); userdata_int.Set(id,newdata); } bool Mesh :: GetUserData(const char * id, NgArray & data, int shift) const { if(userdata_int.Used(id)) { if(data.Size() < (*userdata_int[id]).Size()+shift) data.SetSize((*userdata_int[id]).Size()+shift); for(int i=0; i<(*userdata_int[id]).Size(); i++) data[i+shift] = (*userdata_int[id])[i]; return true; } else { data.SetSize(0); return false; } } void Mesh :: SetUserData(const char * id, NgArray & data) { if(userdata_double.Used(id)) delete userdata_double[id]; NgArray * newdata = new NgArray(data); userdata_double.Set(id,newdata); } bool Mesh :: GetUserData(const char * id, NgArray & data, int shift) const { if(userdata_double.Used(id)) { if(data.Size() < (*userdata_double[id]).Size()+shift) data.SetSize((*userdata_double[id]).Size()+shift); for(int i=0; i<(*userdata_double[id]).Size(); i++) data[i+shift] = (*userdata_double[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); } shared_ptr Mesh :: Mirror ( netgen::Point<3> p_plane, Vec<3> n_plane ) { Mesh & m = *this; auto nm_ = make_shared(); Mesh & nm = *nm_; nm = m; Point3d pmin, pmax; GetBox(pmin, pmax); auto v = pmax-pmin; double eps = v.Length()*1e-8; /* auto onPlane = [&] (const MeshPoint & p) -> bool { auto v = p_plane-p; auto l = v.Length(); if(l PointIndex { auto & p = m[pi]; auto v = p_plane-p; auto l = v.Length(); if(l point_map; point_map.SetSize(GetNP()); point_map = -1; for(auto pi : Range(points)) point_map[pi] = mirror(pi); */ Array point_map(GetNP()); Array point_map1(GetNP()); nm.Points().SetSize(0); for(auto pi : Range(points)) { auto & p = m[pi]; auto v = p_plane-p; auto l = v.Length(); if(l < eps || fabs(v*n_plane)/l < eps) { auto npi = nm.AddPoint(p, p.GetLayer(), p.Type()); point_map[pi] = npi; point_map1[pi] = npi; } else { auto new_point = p + 2*(v*n_plane)*n_plane; point_map1[pi] = nm.AddPoint(p, p.GetLayer(), p.Type()); point_map[pi] = nm.AddPoint( new_point, p.GetLayer(), p.Type() ); } } for(auto & el : nm.VolumeElements()) for(auto i : Range(el.GetNP())) el[i] = point_map1[el[i]]; for(auto & el : nm.SurfaceElements()) for(auto i : Range(el.GetNP())) el[i] = point_map1[el[i]]; for(auto & el : nm.LineSegments()) for(auto i : Range(el.GetNP())) el[i] = point_map1[el[i]]; for(auto & el : VolumeElements()) { auto nel = el; for(auto i : Range(el.GetNP())) nel[i] = point_map[el[i]]; nm.AddVolumeElement(nel); } for (auto ei : Range(SurfaceElements())) { auto & el = m[ei]; auto nel = el; for(auto i : Range(el.GetNP())) nel[i] = point_map[el[i]]; if(!(nel==el)) { nel.Invert(); nm.AddSurfaceElement(nel); } } for (auto ei : Range(LineSegments())) { auto & el = LineSegments()[ei]; auto nel = el; bool is_same = true; for(auto i : Range(el.GetNP())) { auto pi = el[i]; nel[i] = point_map[pi]; if(point_map[pi]!=pi) is_same = false; } if(!is_same) nm.AddSegment(nel); } nm.ComputeNVertices(); return nm_; } void AddFacesBetweenDomains(Mesh & mesh) { static Timer timer("AddFacesBetweenDomains"); RegionTimer rt(timer); auto & topo = mesh.GetTopology(); auto p2el = mesh.CreatePoint2ElementTable(); Array els_per_domain(mesh.GetNDomains()+1); els_per_domain = 0; for(const auto & el : mesh.VolumeElements()) els_per_domain[el.GetIndex()]++; std::map, int> doms_2_new_face; for(const auto & [facei, fd]: Enumerate(mesh.FaceDescriptors())) { auto dom0 = fd.DomainIn(); auto dom1 = fd.DomainOut(); if(dom0 > dom1) swap(dom0, dom1); doms_2_new_face[{dom0, dom1}] = facei+1; } for(auto dom : Range(1, 1+mesh.GetNDomains())) { if(els_per_domain[dom] == 0) continue; mesh.UpdateTopology(); mesh.FindOpenElements(dom); for(const auto & openel : mesh.OpenElements()) { std::set has_p1, has_p2, has_p3; for (auto ei: topo.GetVertexElements(openel[0])) has_p1.insert(ei); for (auto ei: topo.GetVertexElements(openel[1])) has_p2.insert(ei); for (auto ei: topo.GetVertexElements(openel[2])) has_p3.insert(ei); std::set has_p12, has_all; set_intersection(has_p1.begin(), has_p1.end(), has_p2.begin(), has_p2.end(), inserter(has_p12, has_p12.begin())); set_intersection(has_p12.begin(), has_p12.end(), has_p3.begin(), has_p3.end(), inserter(has_all, has_all.begin())); ArrayMem els; for(auto ei : has_all) els.Append(ei); if(els.Size() == 2 && mesh[els[0]].GetIndex() != mesh[els[1]].GetIndex()) { auto dom0 = mesh[els[0]].GetIndex(); auto dom1 = mesh[els[1]].GetIndex(); ElementIndex ei0 = els[0]; if(dom0 > dom1) { Swap(dom0, dom1); ei0 = els[1]; } if(dom1 == dom) continue; if(doms_2_new_face.count({dom0, dom1}) == 0) { auto fd = FaceDescriptor(-1, dom0, dom1, -1); auto new_si = mesh.GetNFD()+1; fd.SetBCProperty(new_si); auto new_face = mesh.AddFaceDescriptor(fd); mesh.SetBCName(new_si - 1, "default"); doms_2_new_face[{dom0, dom1}] = new_face; } for(auto face : topo.GetFaces(ei0)) { auto verts = topo.GetFaceVertices(face); if(verts.Contains(openel[0]) && verts.Contains(openel[1]) && verts.Contains(openel[2])) { Element2d sel(static_cast(verts.Size())); sel.SetIndex(doms_2_new_face[{dom0, dom1}]); for(auto j : Range(verts.Size())) sel[j] = verts[j]; auto normal = Cross(mesh[sel[1]]-mesh[sel[0]], mesh[sel[2]]-mesh[sel[0]]); Vec<3> surf_center = Vec<3>(Center(mesh[sel[0]] , mesh[sel[1]] , mesh[sel[2]])); Vec<3> center(0., 0., 0.); for(auto pi : mesh[ei0].PNums()) center += Vec<3>(mesh[pi]); center *= 1.0/mesh[ei0].GetNP(); if((normal * (center - surf_center)) < 0) sel.Invert(); mesh.AddSurfaceElement(sel); break; } } } } } } } ================================================ FILE: libsrc/meshing/meshclass.hpp ================================================ #ifndef NETGEN_MESHCLASS_HPP #define NETGEN_MESHCLASS_HPP /**************************************************************************/ /* File: meshclass.hpp */ /* Author: Joachim Schoeberl */ /* Date: 20. Nov. 99 */ /**************************************************************************/ /* The mesh class */ #include #include #include #include "meshtype.hpp" #include "localh.hpp" #include "topology.hpp" #include "paralleltop.hpp" namespace netgen { class NetgenGeometry; using namespace std; static constexpr int NG_MPI_TAG_MESH = 210; enum resthtype { RESTRICTH_FACE, RESTRICTH_EDGE, RESTRICTH_SURFACEELEMENT, RESTRICTH_POINT, RESTRICTH_SEGMENT }; class HPRefElement; class CurvedElements; class AnisotropicClusters; class ParallelMeshTopology; class MarkedTet; class MarkedPrism; class MarkedIdentification; class MarkedTri; class MarkedQuad; typedef Array T_MTETS; typedef NgArray T_MPRISMS; typedef NgArray T_MIDS; typedef NgArray T_MTRIS; typedef NgArray T_MQUADS; struct BisectionInfo { unique_ptr mtets; unique_ptr mprisms; unique_ptr mids; unique_ptr mtris; unique_ptr mquads; BisectionInfo(); ~BisectionInfo(); }; /// 2d/3d mesh class Mesh { public: // typedef Array T_POINTS; typedef netgen::T_POINTS T_POINTS; private: /// point coordinates T_POINTS points; // The communicator for this mesh. Just a dummy if compiled without MPI. NgMPI_Comm comm; /// line-segments at edges Array segments; /// surface elements, 2d-inner elements Array surfelements; /// volume elements Array volelements; /// points will be fixed forever Array lockedpoints; /// surface indices at boundary nodes // TABLE surfacesonnode; /// boundary edges (1..normal bedge, 2..segment) unique_ptr> boundaryedges; /// unique_ptr> segmentht; /// unique_ptr> surfelementht; unique_ptr> illegal_trigs; /// faces of rest-solid NgArray openelements; /// open segments for surface meshing NgArray opensegments; Array tets_in_qualclass; /** Representation of local mesh-size h (one function per mesh layer) */ Array> lochfunc; /// double hglob; /// double hmin; /// NgArray maxhdomain; /** the face-index of the surface element maps into this table. */ Array facedecoding; /** the edge-index of the line element maps into this table. */ NgArray edgedecoding; Array region_name_cd[4]; Array & materials = region_name_cd[0]; Array & bcnames = region_name_cd[1]; Array & cd2names = region_name_cd[2]; Array & cd3names = region_name_cd[3]; /* /// sub-domain materials Array materials; /// labels for boundary conditions Array bcnames; /// labels for co dim 2 bboundary conditions Array cd2names; /// labels for co dim 3 bbboundary conditions Array cd3names; */ /// Periodic surface, close surface, etc. identifications unique_ptr ident; /// number of vertices (if < 0, use np) int numvertices; /// geometric search tree for interval intersection search unique_ptr> elementsearchtree_vol; unique_ptr> elementsearchtree_surf; /// time stamp for tree mutable size_t elementsearchtreets[4]; /// element -> face, element -> edge etc ... MeshTopology topology; /// methods for high order elements unique_ptr curvedelems; /// nodes identified by close points unique_ptr 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 semaphores. NgMutex mutex; /// mesh access semaphores. NgMutex majormutex; SymbolTable< NgArray* > userdata_int; SymbolTable< NgArray* > userdata_double; mutable NgArray< Point3d > pointcurves; mutable NgArray pointcurves_startpoint; mutable NgArray pointcurves_red,pointcurves_green,pointcurves_blue; /// start element for point search (GetElementOfPoint) mutable int ps_startelement; #ifdef PARALLEL /// connection to parallel meshes unique_ptr paralleltop; #endif shared_ptr geometry; public: DLL_HEADER void BuildBoundaryEdges(bool rebuild=true); DLL_HEADER bool PointContainedIn2DElement(const Point3d & p, double lami[3], SurfaceElementIndex element, bool consider3D = false) const; DLL_HEADER bool PointContainedIn3DElement(const Point3d & p, double lami[3], ElementIndex element, double tol=1e-4) const; DLL_HEADER bool PointContainedIn3DElementOld(const Point3d & p, double lami[3], ElementIndex element, double tol=1e-4) const; public: Signal<> updateSignal; BisectionInfo bisectioninfo; // store coarse mesh before hp-refinement unique_ptr> hpelements; unique_ptr coarsemesh; /// number of refinement levels // int mglevels; // number of vertices on each refinement level: NgArray level_nv; /// refinement hierarchy Array,PointIndex> mlbetweennodes; /// parent element of volume element Array mlparentelement; /// parent element of surface element Array mlparentsurfaceelement; /// DLL_HEADER Mesh(); /// DLL_HEADER ~Mesh(); DLL_HEADER Mesh & operator= (const Mesh & mesh2); /// DLL_HEADER void DeleteMesh(); /// void ClearSurfaceElements(); /// DLL_HEADER void ClearVolumeElements() { volelements.SetSize(0); timestamp = NextTimeStamp(); } /// DLL_HEADER 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); auto GetNP () const { return points.Size(); } // [[deprecated("Use Point(PointIndex) instead of int !")]] MeshPoint & Point(int i) // 1-based { // return points.Elem(i); // return Point (PointIndex(i+PointIndex::BASE-1)); return Point (PointIndex(IndexBASE()+i-1)); } MeshPoint & Point(PointIndex pi) { return points[pi]; } // [[deprecated("Use Point(PointIndex) instead of int !")]] const MeshPoint & Point(int i) const { // return points.Get(i); // return Point (PointIndex(i+PointIndex::BASE-1)); return Point (PointIndex(IndexBASE()+i-1)); } 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[segnr-1][0].Invalidate(); segments[segnr-1][1].Invalidate(); } /* void FullDeleteSegment (int segnr) // von wem ist das ??? { segments.Delete(segnr-PointIndex::BASE); } */ int GetNSeg () const { return segments.Size(); } // [[deprecated("Use LineSegment(SegmentIndex) instead of int !")]] Segment & LineSegment(int i) { return segments[i-1]; } // [[deprecated("Use LineSegment(SegmentIndex) instead of int !")]] const Segment & LineSegment(int i) const { return segments[i-1]; } 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]; } const auto & LineSegments() const { return segments; } auto & LineSegments() { return segments; } Array pointelements; // only via python interface DLL_HEADER SurfaceElementIndex AddSurfaceElement (const Element2d & el); // write to pre-allocated container, thread-safe DLL_HEADER void SetSurfaceElement (SurfaceElementIndex sei, const Element2d & el); [[deprecated("Use Delete(SurfaceElementIndex) instead of int !")]] void DeleteSurfaceElement (int eli) { /* surfelements.Elem(eli).Delete(); surfelements.Elem(eli).PNum(1).Invalidate(); surfelements.Elem(eli).PNum(2).Invalidate(); surfelements.Elem(eli).PNum(3).Invalidate(); */ surfelements[eli-1].Delete(); /* surfelements[eli-1].PNum(1).Invalidate(); surfelements[eli-1].PNum(2).Invalidate(); surfelements[eli-1].PNum(3).Invalidate(); */ timestamp = NextTimeStamp(); } [[deprecated("Use Delete(SurfaceElementIndex) instead !")]] void DeleteSurfaceElement (SurfaceElementIndex eli) { // for (auto & p : surfelements[eli].PNums()) p.Invalidate(); surfelements[eli].Delete(); timestamp = NextTimeStamp(); } void Delete (SurfaceElementIndex eli) { // for (auto & p : surfelements[eli].PNums()) p.Invalidate(); surfelements[eli].Delete(); timestamp = NextTimeStamp(); } auto GetNSE () const { return surfelements.Size(); } // [[deprecated("Use SurfaceElement(SurfaceElementIndex) instead of int !")]] Element2d & SurfaceElement(int i) { return surfelements[i-1]; } // [[deprecated("Use SurfaceElement(SurfaceElementIndex) instead of int !")]] const Element2d & SurfaceElement(int i) const { return surfelements[i-1]; } // [[deprecated("Use mesh[](SurfaceElementIndex) instead !")]] Element2d & SurfaceElement(SurfaceElementIndex i) { return surfelements[i]; } // [[deprecated("Use mesh[](SurfaceElementIndex) instead !")]] 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]; } const auto & SurfaceElements() const { return surfelements; } auto & SurfaceElements() { return surfelements; } DLL_HEADER void RebuildSurfaceElementLists (); DLL_HEADER void GetSurfaceElementsOfFace (int facenr, Array & sei) const; DLL_HEADER ElementIndex AddVolumeElement (const Element & el); // write to pre-allocated container, thread-safe DLL_HEADER void SetVolumeElement (ElementIndex sei, const Element & el); auto GetNE () const { return volelements.Size(); } // [[deprecated("Use VolumeElement(ElementIndex) instead of int !")]] Element & VolumeElement(int i) { return volelements[IndexBASE()+(i-1)]; } // [[deprecated("Use VolumeElement(ElementIndex) instead of int !")]] const Element & VolumeElement(int i) const { return volelements[IndexBASE()+(i-1)]; } // [[deprecated("Use mesh[](VolumeElementIndex) instead !")]] Element & VolumeElement(ElementIndex i) { return volelements[i]; } // [[deprecated("Use mesh[](VolumeElementIndex) instead !")]] 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 auto & VolumeElements() const { return volelements; } auto & VolumeElements() { return volelements; } /// DLL_HEADER double ElementError (int eli, const MeshingParameters & mp) const; /// DLL_HEADER void AddLockedPoint (PointIndex pi); /// void ClearLockedPoints (); const auto & LockedPoints() const { return lockedpoints; } /// Returns number of domains DLL_HEADER int GetNDomains() const; /// int GetDimension() const { return dimension; } DLL_HEADER void SetDimension (int dim); // { dimension = dim; } /// sets internal tables DLL_HEADER void CalcSurfacesOfNode (); /// additional (temporarily) fix points void FixPoints (const TBitArray & 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, int layer=1); /// DLL_HEADER void SetLocalH (netgen::Point<3> pmin, netgen::Point<3> pmax, double grading, int layer=1); /// DLL_HEADER void RestrictLocalH (const Point3d & p, double hloc, int layer=1); /// DLL_HEADER void RestrictLocalHLine (const Point3d & p1, const Point3d & p2, double hloc, int layer=1); /// number of elements per radius DLL_HEADER void CalcLocalHFromSurfaceCurvature(double grading, double elperr, int layer=1); /// DLL_HEADER void CalcLocalHFromPointDistances(double grading, int layer=1); /// DLL_HEADER void RestrictLocalH (resthtype rht, int nr, double loch); /// DLL_HEADER void LoadLocalMeshSize (const filesystem::path & meshsizefilename); /// DLL_HEADER void SetGlobalH (double h); /// DLL_HEADER void SetMinimalH (double h); /// DLL_HEADER double MaxHDomain (int dom) const; /// DLL_HEADER void SetMaxHDomain (const NgArray & mhd); /// DLL_HEADER double GetH (const Point3d & p, int layer=1) const; DLL_HEADER double GetH (PointIndex pi) const { return GetH(points[pi], points[pi].GetLayer()); } /// double GetMinH (const Point3d & pmin, const Point3d & pmax, int layer=1); /// bool HasLocalHFunction (int layer=1) { return lochfunc[layer-1] != nullptr; } /// LocalH & LocalHFunction (int layer=1) { return * lochfunc[layer-1]; } shared_ptr & GetLocalH(int layer=1) const { if(lochfunc.Size() == 1) return lochfunc[0]; return lochfunc[layer-1]; } DLL_HEADER void SetLocalH(shared_ptr loch, int layer=1); /// bool LocalHFunctionGenerated(int layer=1) const { return (lochfunc[layer-1] != 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); } auto & OpenElements() const { return openelements; } auto & OpenElements() { return openelements; } /// are also quads open elements bool HasOpenQuads () const; /// split into connected pieces DLL_HEADER void SplitIntoParts (); /// DLL_HEADER void SplitSeparatedFaces (); /// Refines mesh and projects points to true surface // void Refine (int levels, const CSGeometry * geom); void ZRefine(const string& name, const Array& slices); bool BoundaryEdge (PointIndex pi1, PointIndex pi2) const { if(!boundaryedges) const_cast(this)->BuildBoundaryEdges(); PointIndices<2> i2(pi1, pi2); i2.Sort(); return boundaryedges->Used (i2); } void DeleteBoundaryEdges () { boundaryedges = nullptr; } bool IsSegment (PointIndex pi1, PointIndex pi2) const { PointIndices<2> i2 (pi1, pi2); i2.Sort(); return segmentht->Used (i2); } SegmentIndex SegmentNr (PointIndex pi1, PointIndex pi2) const { PointIndices<2> i2(pi1, pi2); i2.Sort(); return segmentht->Get (i2); } /** Remove unused points. etc. */ DLL_HEADER void Compress (); /// first vertex has lowest index void OrderElements(); /// DLL_HEADER void Save (ostream & outfile) const; /// DLL_HEADER void Load (istream & infile); /// DLL_HEADER void Merge (istream & infile, const int surfindex_offset = 0); /// DLL_HEADER void Save (const filesystem::path & filename) const; /// DLL_HEADER void Load (const filesystem::path & filename); /// DLL_HEADER void Merge (const filesystem::path & filename, const int surfindex_offset = 0); DLL_HEADER void DoArchive (Archive & archive); /// DLL_HEADER void ImproveMesh (const MeshingParameters & mp, OPTIMIZEGOAL goal = OPT_QUALITY); /// void ImproveMeshJacobian (const MeshingParameters & mp, OPTIMIZEGOAL goal = OPT_QUALITY, const TBitArray * usepoint = NULL); /// void ImproveMeshJacobianOnSurface (const MeshingParameters & mp, const TBitArray & usepoint, const NgArray< Vec<3>* > & nv, OPTIMIZEGOAL goal = OPT_QUALITY, const NgArray< idmap_type* > * idmaps = NULL); /** free nodes in environment of openelements for optimiztion */ void FreeOpenElementsEnvironment (int layers); DLL_HEADER double CalcTotalBad (const MeshingParameters & mp); FlatArray GetQualityHistogram() { return tets_in_qualclass; } /// bool LegalTet (Element & el) const { if (el.IllegalValid()) return !el.Illegal(); return LegalTet2 (el); } /// bool LegalTet2 (Element & el) const; /// // Find trigs with same vertices // return: number of illegal trigs int FindIllegalTrigs (); 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 */ DLL_HEADER void CalcMinMaxAngle (double badellimit, double * retvalues = NULL); /* Marks elements which are dangerous to refine return: number of illegal elements */ DLL_HEADER int MarkIllegalElements (int domain=0); /// orient surface mesh, for one sub-domain only DLL_HEADER void SurfaceMeshOrientation (); /// convert mixed element mesh to tet-mesh DLL_HEADER void Split2Tets(); /// build box-search tree DLL_HEADER void BuildElementSearchTree (int dim); BoxTree<3, ElementIndex>* GetElementSearchTree () const { return elementsearchtree_vol.get(); } BoxTree<3, SurfaceElementIndex>* GetSurfaceElementSearchTree () const { return elementsearchtree_surf.get(); } void SetPointSearchStartElement(const int el) const {ps_startelement = el;} /// gives element of point, barycentric coordinates DLL_HEADER ElementIndex GetElementOfPoint (const netgen::Point<3> & p, double * lami, bool build_searchtree = false, int index = -1, bool allowindex = true, double tol=1e-4) const; DLL_HEADER ElementIndex GetElementOfPoint (const netgen::Point<3> & p, double * lami, std::optional> indices, bool build_searchtree = 0, bool allowindex = true, double tol=1e-4) const; DLL_HEADER SurfaceElementIndex GetSurfaceElementOfPoint (const netgen::Point<3> & p, double * lami, bool build_searchtree = false, int index = -1, bool allowindex = true) const; DLL_HEADER SurfaceElementIndex GetSurfaceElementOfPoint (const netgen::Point<3> & p, double * lami, std::optional> indices, bool build_searchtree = false, 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 & locels) const; /// int AddFaceDescriptor(const FaceDescriptor& fd) { facedecoding.Append(fd); return facedecoding.Size(); } int AddEdgeDescriptor(const EdgeDescriptor & fd) { edgedecoding.Append(fd); return edgedecoding.Size() - 1; } auto & GetCommunicator() const { return this->comm; } void SetCommunicator(NgMPI_Comm acomm); DLL_HEADER void SplitFacesByAdjacentDomains(); DLL_HEADER shared_ptr GetSubMesh(string domains="", string faces="") const; /// DLL_HEADER void SetMaterial (int domnr, const string & mat); /// DLL_HEADER const string & GetMaterial (int domnr) const; DLL_HEADER static string defaultmat; const string * GetMaterialPtr (int domnr) const // 1-based { return domnr <= materials.Size() ? materials[domnr-1] : &defaultmat; } DLL_HEADER void SetNBCNames ( int nbcn ); DLL_HEADER void SetBCName ( int bcnr, const string & abcname ); DLL_HEADER const string & GetBCName ( int bcnr ) const; DLL_HEADER void SetNCD2Names (int ncd2n); DLL_HEADER void SetCD2Name (int cd2nr, const string & abcname); DLL_HEADER const string & GetCD2Name (int cd2nr ) const; DLL_HEADER static string cd2_default_name; string * GetCD2NamePtr (int cd2nr ) const { if (cd2nr < cd2names.Size() && cd2names[cd2nr]) return cd2names[cd2nr]; return &cd2_default_name; } size_t GetNCD2Names() const { return cd2names.Size(); } DLL_HEADER void SetNCD3Names (int ncd3n); DLL_HEADER void SetCD3Name (int cd3nr, const string & abcname); DLL_HEADER int AddCD3Name (const string & aname); DLL_HEADER const string & GetCD3Name (int cd3nr ) const; DLL_HEADER static string cd3_default_name; string * GetCD3NamePtr (int cd3nr ) const { if (cd3nr < cd3names.Size() && cd3names[cd3nr]) return cd3names[cd3nr]; return &cd3_default_name; } size_t GetNCD3Names() const { return cd3names.Size(); } DLL_HEADER static string default_bc; string * GetBCNamePtr (int bcnr) const { return (bcnr < bcnames.Size() && bcnames[bcnr]) ? bcnames[bcnr] : &default_bc; } DLL_HEADER Array & GetRegionNamesCD (int codim); DLL_HEADER FlatArray GetRegionNamesCD (int codim) const; DLL_HEADER std::string_view GetRegionName(const Segment & el) const; DLL_HEADER std::string_view GetRegionName(const Element2d & el) const; DLL_HEADER std::string_view GetRegionName(const Element & el) const; std::string_view GetRegionName(SegmentIndex ei) const { return GetRegionName((*this)[ei]); } std::string_view GetRegionName(SurfaceElementIndex ei) const { return GetRegionName((*this)[ei]); } std::string_view GetRegionName(ElementIndex ei) const { return GetRegionName((*this)[ei]); } DLL_HEADER static string_view defaultmat_sv; std::string_view GetRegionName (int dim, int domnr) // 1-based domnr { domnr--; auto & names = region_name_cd[dimension-dim]; if (domnr < names.Size() && names[domnr]) return *names[domnr]; return defaultmat_sv; } /// void ClearFaceDescriptors() { facedecoding.SetSize(0); } void FreeFaceDescriptors() { facedecoding = Array(); } /// int GetNFD () const { return facedecoding.Size(); } const FaceDescriptor & GetFaceDescriptor (const Element2d & el) const { return facedecoding[el.GetIndex()-1]; } const FaceDescriptor & GetFaceDescriptor (int i) const { return facedecoding[i-1]; } // { return facedecoding.Get(i); } auto & FaceDescriptors () const { return facedecoding; } const EdgeDescriptor & GetEdgeDescriptor (int i) const { return edgedecoding[i]; } /// FaceDescriptor & GetFaceDescriptor (int i) { return facedecoding[i-1]; } // { return facedecoding.Elem(i); } int IdentifyPeriodicBoundaries(const string& id_name, const string& s1, const Transformation<3>& mapping, double pointTolerance); // #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 & GetIdentifiedPoints () // { // return *identifiedpoints; // } // /// // void GetIdentificationMap (int identnr, NgArray & identmap) const; // /// // void GetIdentificationPairs (int identnr, NgArray & 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; } /// bool HasIdentifications() const { return ident != nullptr; } DLL_HEADER void InitPointCurve(double red = 1, double green = 0, double blue = 0) const; DLL_HEADER void AddPointCurvePoint(const Point3d & pt) const; DLL_HEADER int GetNumPointCurves(void) const; DLL_HEADER int GetNumPointsOfPointCurve(int curve) const; DLL_HEADER Point3d & GetPointCurvePoint(int curve, int n) const; DLL_HEADER void GetPointCurveColor(int curve, double & red, double & green, double & blue) const; /// find number of vertices DLL_HEADER void ComputeNVertices (); /// number of vertices (no edge-midpoints) DLL_HEADER int GetNV () const; /// remove edge points DLL_HEADER void SetNP (int np); DLL_HEADER Table CreatePoint2ElementTable(std::optional> points = std::nullopt, int domain = 0) const; // DLL_HEADER Table CreatePoint2SurfaceElementTable( int faceindex=0 ) const; DLL_HEADER Table CreatePoint2SurfaceElementTable( int faceindex=0 ) const; DLL_HEADER CompressedTable CreateCompressedPoint2SurfaceElementTable( int faceindex=0 ) const; DLL_HEADER bool PureTrigMesh (int faceindex = 0) const; DLL_HEADER bool PureTetMesh () const; const MeshTopology & GetTopology () const { return topology; } MeshTopology & GetTopology () { return topology; } DLL_HEADER void UpdateTopology (NgTaskManager tm = &DummyTaskManager, NgTracer tracer = &DummyTracer); class CurvedElements & GetCurvedElements () const { return *curvedelems; } DLL_HEADER void BuildCurvedElements (const class Refinement * ref, int aorder, bool arational = false); DLL_HEADER void BuildCurvedElements (int aorder); const class AnisotropicClusters & GetClusters () const { return *clusters; } class CSurfaceArea { const Mesh & mesh; bool valid; double area; public: CSurfaceArea (const Mesh & amesh) : mesh(amesh), valid(false), area(0.) { ; } void Add (const Element2d & sel) { if (sel.GetNP() == 3) area += Cross ( mesh[sel[1]]-mesh[sel[0]], mesh[sel[2]]-mesh[sel[0]] ).Length() / 2; else area += Cross (Vec3d (mesh[sel.PNum(1)], mesh[sel.PNum(3)]), Vec3d (mesh[sel.PNum(1)], mesh[sel.PNum(4)])).Length() / 2;; } void ReCalc () { area = 0; /* for (SurfaceElementIndex sei = 0; sei < mesh.GetNSE(); sei++) Add (mesh[sei]); */ for (const Element2d & el : mesh.SurfaceElements()) Add (el); valid = true; } operator double () const { return area; } bool Valid() const { return valid; } }; CSurfaceArea surfarea; CSurfaceArea & SurfaceArea() { return surfarea; } const CSurfaceArea & SurfaceArea() const { return surfarea; } 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; } DLL_HEADER shared_ptr GetGeometry() const; void SetGeometry (shared_ptr geom) { geometry = geom; } /// void SetUserData(const char * id, NgArray & data); /// bool GetUserData(const char * id, NgArray & data, int shift = 0) const; /// void SetUserData(const char * id, NgArray & data); /// bool GetUserData(const char * id, NgArray & data, int shift = 0) const; /// friend void OptimizeRestart (Mesh & mesh3d); /// void PrintMemInfo (ostream & ost) const; /// friend class Meshing3; // only for saving the geometry 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 DLL_HEADER void Distribute (); DLL_HEADER void Distribute (NgArray & volume_weights, NgArray & surface_weights, NgArray & segment_weights); /// find connection to parallel meshes // void FindExchangePoints () ; // void FindExchangeEdges (); // void FindExchangeFaces (); /// use metis to decompose master mesh DLL_HEADER void ParallelMetis (int nproc); DLL_HEADER void ParallelMetis (NgArray & volume_weights, NgArray & surface_weights, NgArray & segment_weights); void PartHybridMesh (); void PartDualHybridMesh (); void PartDualHybridMesh2D (); /// send mesh from master to local procs void SendRecvMesh (); /// send mesh to parallel machine, keep global mesh at master void SendMesh ( ) const; /// loads a mesh sent from master processor void ReceiveParallelMesh (); #else void ParallelMetis (int /* nproc */) {} void Distribute () {} void SendRecvMesh () {} void Distribute (NgArray & volume_weights, NgArray & surface_weights, NgArray & segment_weights){ } #endif Array vol_partition; NgArray surf_partition; NgArray seg_partition; shared_ptr Mirror( netgen::Point<3> p, Vec<3> n ); private: MemoryTracer mem_tracer = {"Mesh", points, "points", segments, "segments", surfelements, "surfelements", volelements, "volelements" }; public: const MemoryTracer & GetMemoryTracer() { return mem_tracer; } }; inline ostream& operator<<(ostream& ost, const Mesh& mesh) { ost << "mesh: " << endl; mesh.Save(ost); return ost; } FlatArray MeshTopology :: GetEdges (SurfaceElementIndex elnr) const { return FlatArray(GetNEdges ( (*mesh)[elnr].GetType()), &surfedges[elnr][0]); } FlatArray MeshTopology :: GetEdges (ElementIndex elnr) const { return FlatArray(GetNEdges ( (*mesh)[elnr].GetType()), &edges[elnr][0]); } FlatArray MeshTopology :: GetFaces (ElementIndex elnr) const { return FlatArray(GetNFaces ( (*mesh)[elnr].GetType()), &faces[elnr][0]); } DLL_HEADER void AddFacesBetweenDomains(Mesh & mesh); } #endif // NETGEN_MESHCLASS_HPP ================================================ FILE: libsrc/meshing/meshfunc.cpp ================================================ #include #include #include "meshing.hpp" #include "debugging.hpp" #include "boundarylayer.hpp" namespace netgen { extern const char * tetrules[]; // extern const char * tetrules2[]; extern const char * prismrules2[]; extern const char * pyramidrules[]; extern const char * pyramidrules2[]; extern const char * hexrules[]; struct MeshingData { int domain; // mesh for one domain (contains all adjacent surface elements) unique_ptr mesh; // maps from local (domain) mesh to global mesh Array pmap; // Array connected_pairs; MeshingParameters mp; unique_ptr meshing; }; // extract surface meshes belonging to individual domains Array DivideMesh(Mesh & mesh, const MeshingParameters & mp) { static Timer timer("DivideMesh"); RegionTimer rt(timer); Array ret; auto num_domains = mesh.GetNDomains(); if(num_domains==1 || mp.only3D_domain_nr) { ret.SetSize(1); // no need to divide mesh, just fill in meshing data ret[0].domain = 1; if(mp.only3D_domain_nr) ret[0].domain = mp.only3D_domain_nr; ret[0].mesh.reset(&mesh); // careful, this unique_ptr must not delete &mesh! (it will be released in MergeMeshes after meshing) ret[0].mp = mp; return ret; } ret.SetSize(num_domains); Array> ipmap; ipmap.SetSize(num_domains); // auto dim = mesh.GetDimension(); auto num_points = mesh.GetNP(); auto num_facedescriptors = mesh.GetNFD(); constexpr PointIndex state0 = IndexBASE()-1; constexpr PointIndex state1 = state0+1; constexpr PointIndex state2 = state0+2; for(auto i : Range(ret)) { auto & md = ret[i]; md.domain = i+1; md.mp = mp; md.mp.maxh = min2 (mp.maxh, mesh.MaxHDomain(md.domain)); ret[i].mesh = make_unique(); auto & m = *ret[i].mesh; m.SetLocalH(mesh.GetLocalH()); ipmap[i].SetSize(num_points); ipmap[i] = state0; // 0; // PointIndex::INVALID; m.SetDimension( mesh.GetDimension() ); m.SetGeometry( mesh.GetGeometry() ); } // mark interior edge points for(const auto& seg : mesh.LineSegments()) { if(seg.domin > 0 && seg.domin == seg.domout) { ipmap[seg.domin-1][seg[0]] = state1; // 1; ipmap[seg.domin-1][seg[1]] = state1; // 1; } } // mark used points for each domain, add surface elements (with wrong point numbers) to domain mesh for(const auto & sel : mesh.SurfaceElements()) { const auto & fd = mesh.GetFaceDescriptor(sel.GetIndex()); int dom_in = fd.DomainIn(); int dom_out = fd.DomainOut(); for( auto dom : {dom_in, dom_out} ) { if(dom<=0) continue; auto & sels = ret[dom-1].mesh->SurfaceElements(); for(auto pi : sel.PNums()) ipmap[dom-1][pi] = state1; // 1; sels.Append(sel); } } // mark used points for already existing volume elements, add them (with wrong point numbers) to domain mesh for(const auto & el : mesh.VolumeElements()) { auto dom = el.GetIndex(); auto & els = ret[dom-1].mesh->VolumeElements(); for(auto pi : el.PNums()) ipmap[dom-1][pi] = state1; // 1; els.Append(el); } // mark locked/fixed points for each domain TODO: domain bounding box to add only relevant points? for(auto pi : mesh.LockedPoints()) for(auto i : Range(ret)) ipmap[i][pi] = state2; // 2; // add used points to domain mesh, build point mapping for(auto i : Range(ret)) { auto & m = *ret[i].mesh; auto & pmap = ret[i].pmap; for(auto pi : Range(ipmap[i])) if(ipmap[i][pi] != state0) { const auto& mp = mesh[pi]; auto pi_new = m.AddPoint( mp, mp.GetLayer(), mp.Type() ); if(ipmap[i][pi] == state2) // 2) mesh.AddLockedPoint(pi_new); ipmap[i][pi] = pi_new; pmap.Append( pi ); } } // add segments for(auto i : Range(ret)) { auto & imap = ipmap[i]; auto & m = *ret[i].mesh; for(auto seg : mesh.LineSegments()) if(imap[seg[0]].IsValid() && imap[seg[1]].IsValid()) { seg[0] = imap[seg[0]]; seg[1] = imap[seg[1]]; m.AddSegment(seg); } } auto & identifications = mesh.GetIdentifications(); for(auto i : Range(ret)) { auto & m = *ret[i].mesh; auto & imap = ipmap[i]; auto nmax = identifications.GetMaxNr (); auto & m_ident = m.GetIdentifications(); for (auto & sel : m.SurfaceElements()) for(auto & pi : sel.PNums()) pi = imap[pi]; for (auto & el : m.VolumeElements()) for(auto & pi : el.PNums()) pi = imap[pi]; for(auto n : Range(1,nmax+1)) { NgArray pairs; identifications.GetPairs(n, pairs); for(auto pair : pairs) { auto pi0 = imap[pair[0]]; auto pi1 = imap[pair[1]]; if(!pi0.IsValid() || !pi1.IsValid()) continue; m_ident.Add(pi0, pi1, n); } m_ident.SetType( n, identifications.GetType(n) ); } } return ret; } // Add between identified surface elements (only consider closesurface identifications) void FillCloseSurface( MeshingData & md) { static Timer timer("FillCloseSurface"); RegionTimer rtimer(timer); auto & mesh = *md.mesh; auto & identifications = mesh.GetIdentifications(); auto nmax = identifications.GetMaxNr(); bool have_closesurfaces = false; for(auto i : Range(1,nmax+1)) if(identifications.GetType(i) == Identifications::CLOSESURFACES) have_closesurfaces = true; if(!have_closesurfaces) return; idmap_type map; std::set> hex_faces; for(auto identnr : Range(1,nmax+1)) { if(identifications.GetType(identnr) != Identifications::CLOSESURFACES) continue; identifications.GetMap(identnr, map); mesh.FindOpenElements(md.domain); for(auto & sel : mesh.OpenElements()) { // For quads: check if this open element is already closed by a hex // this happens when we have identifications in two directions if(sel.GetNP() == 4) { Element2d face = sel; face.NormalizeNumbering(); if(hex_faces.count({face[0], face[1], face[2]})) continue; } bool is_mapped = true; for(auto pi : sel.PNums()) if(!PointIndex(map[pi]).IsValid()) is_mapped = false; if(!is_mapped) continue; // insert prism/hex auto np = sel.GetNP(); Element el(2*np); std::set pis; for(auto i : Range(np)) { el[i] = sel[i]; el[i+np] = map[sel[i]]; pis.insert(sel[i]); pis.insert(map[sel[i]]); } // degenerate element (mapped element onto itself, might happen for surface elements connecting two identified faces) if(pis.size() < 2*np) continue; // check if new element is inside current domain auto p0 = mesh[sel[0]]; Vec<3> n = -Cross(mesh[sel[1]] - p0, mesh[sel[2]] - p0 ); if(n*(mesh[el[np]]-p0) < 0.0) continue; el.SetIndex(md.domain); mesh.AddVolumeElement(el); if(el.NP()==8) { // remember all adjacent faces of the new hex (to skip corresponding openelements accordingly) for(auto facei : Range(1,7)) { Element2d face; el.GetFace(facei, face); face.NormalizeNumbering(); hex_faces.insert({face[0], face[1], face[2]}); } } } } } void CloseOpenQuads( MeshingData & md) { static Timer t("CloseOpenQuads"); RegionTimer rt(t); auto & mesh = *md.mesh; auto domain = md.domain; MeshingParameters & mp = md.mp; int oldne; if (multithread.terminate) return; mesh.CalcSurfacesOfNode(); mesh.FindOpenElements(domain); if (!mesh.GetNOpenElements()) return; for (int qstep = 0; qstep <= 3; qstep++) { if (qstep == 0 && !mp.try_hexes) continue; if (mesh.HasOpenQuads()) { string rulefile = ngdir; const char ** rulep = NULL; switch (qstep) { case 0: rulep = hexrules; break; case 1: rulep = prismrules2; break; case 2: // connect pyramid to triangle rulep = pyramidrules2; break; case 3: // connect to vis-a-vis point rulep = pyramidrules; break; } Meshing3 meshing(rulep); MeshingParameters mpquad = mp; mpquad.giveuptol = mp.giveuptolopenquads; mpquad.baseelnp = 4; mpquad.starshapeclass = 1000; mpquad.check_impossible = qstep == 1; // for prisms only (air domain in trafo) for (PointIndex pi : mesh.Points().Range()) meshing.AddPoint (mesh[pi], pi); NgArray connectednodes; for (int nr = 1; nr <= mesh.GetIdentifications().GetMaxNr(); nr++) if (mesh.GetIdentifications().GetType(nr) != Identifications::PERIODIC) { mesh.GetIdentifications().GetPairs (nr, connectednodes); for (auto pair : connectednodes) { meshing.AddConnectedPair (pair); meshing.AddConnectedPair ({pair[1], pair[0]}); } } for (int i = 1; i <= mesh.GetNOpenElements(); i++) { Element2d hel = mesh.OpenElement(i); meshing.AddBoundaryElement (hel); } oldne = mesh.GetNE(); meshing.GenerateMesh (mesh, mpquad); // for (int i = oldne + 1; i <= mesh.GetNE(); i++) for (ElementIndex i : mesh.VolumeElements().Range().Modify(oldne, 0)) mesh.VolumeElement(i).SetIndex (domain); (*testout) << "mesh has " << mesh.GetNE() << " prism/pyramid elements" << endl; mesh.FindOpenElements(domain); } } if (mesh.HasOpenQuads()) { if(debugparam.write_mesh_on_error) { md.mesh->Save("open_quads_starting_mesh_"+ToString(md.domain)+".vol.gz"); GetOpenElements(*md.mesh, md.domain)->Save("open_quads_rest_" + ToString(md.domain)+".vol.gz"); GetOpenElements(*md.mesh, md.domain, true)->Save("open_quads_rest_" + ToString(md.domain)+"_only_quads.vol.gz"); } PrintSysError ("mesh has still open quads"); throw NgException ("Stop meshing since too many attempts"); // return MESHING3_GIVEUP; } } void MeshDomain( MeshingData & md) { auto & mesh = *md.mesh; auto domain = md.domain; MeshingParameters & mp = md.mp; mesh.CalcSurfacesOfNode(); mesh.FindOpenElements(md.domain); md.meshing = make_unique(nullptr); for (PointIndex pi : mesh.Points().Range()) md.meshing->AddPoint (mesh[pi], pi); for (int i = 1; i <= mesh.GetNOpenElements(); i++) md.meshing->AddBoundaryElement (mesh.OpenElement(i)); if (mp.delaunay && mesh.GetNOpenElements()) { int oldne = mesh.GetNE(); md.meshing->Delaunay (mesh, domain, mp); // for (int i = oldne + 1; i <= mesh.GetNE(); i++) for (ElementIndex i : mesh.VolumeElements().Range().Modify(oldne, 0)) mesh.VolumeElement(i).SetIndex (domain); PrintMessage (3, mesh.GetNP(), " points, ", mesh.GetNE(), " elements"); mesh.FindOpenElements(domain); } Box<3> domain_bbox( Box<3>::EMPTY_BOX ); for (auto & sel : mesh.SurfaceElements()) { if (sel.IsDeleted() ) continue; for (auto pi : sel.PNums()) domain_bbox.Add (mesh[pi]); } domain_bbox.Increase (0.01 * domain_bbox.Diam()); int cntsteps = 0; int meshed; if (mesh.GetNOpenElements()) do { if (multithread.terminate) break; mesh.FindOpenElements(domain); PrintMessage (5, mesh.GetNOpenElements(), " open faces"); // GetOpenElements( mesh, domain )->Save("open_"+ToString(domain)+"_"+ToString(cntsteps)+".vol"); cntsteps++; if (cntsteps > mp.maxoutersteps) { if(debugparam.write_mesh_on_error) { md.mesh->Save("meshing_error_domain_"+ToString(md.domain)+".vol.gz"); if(mesh.GetNOpenElements()) GetOpenElements(*md.mesh, md.domain)->Save("meshing_error_rest_" + ToString(md.domain)+".vol.gz"); } throw NgException ("Stop meshing since too many attempts in domain " + ToString(md.domain)); } PrintMessage (1, "start tetmeshing"); Meshing3 meshing(tetrules); Array glob2loc(mesh.GetNP()); glob2loc = PointIndex::INVALID; for (PointIndex pi : mesh.Points().Range()) if (domain_bbox.IsIn (mesh[pi])) glob2loc[pi] = meshing.AddPoint (mesh[pi], pi); for (auto sel : mesh.OpenElements()) { for(auto & pi : sel.PNums()) pi = glob2loc[pi]; meshing.AddBoundaryElement (sel); } int oldne = mesh.GetNE(); mp.giveuptol = 15 + 10 * cntsteps; mp.sloppy = 5; meshing.GenerateMesh (mesh, mp); for (auto & el : mesh.VolumeElements().Range(oldne, END)) el.SetIndex (domain); mesh.CalcSurfacesOfNode(); mesh.FindOpenElements(domain); // teterrpow = 2; if (mesh.GetNOpenElements() != 0) { meshed = 0; PrintMessage (5, mesh.GetNOpenElements(), " open faces found"); MeshOptimize3d optmesh(mesh, mp, OPT_REST); const char * optstr = "mcmstmcmstmcmstmcm"; for (size_t j = 1; j <= strlen(optstr); j++) { mesh.FindOpenElements(); mesh.CalcSurfacesOfNode(); mesh.FreeOpenElementsEnvironment(2); mesh.CalcSurfacesOfNode(); switch (optstr[j-1]) { case 'c': optmesh.CombineImprove(); break; case 'd': optmesh.SplitImprove(); break; case 's': optmesh.SwapImprove(); break; case 't': optmesh.SwapImprove2(); break; case 'm': optmesh.ImproveMesh(); break; } } mesh.FindOpenElements(domain); PrintMessage (3, "Call remove problem"); RemoveProblem (mesh, domain); mesh.FindOpenElements(domain); } else { meshed = 1; PrintMessage (1, "Success !"); } } while (!meshed); PrintMessage (3, "Check subdomain ", domain, " / ", mesh.GetNDomains()); mesh.FindOpenElements(domain); bool res = (mesh.CheckConsistentBoundary() != 0); if (res) { if(debugparam.write_mesh_on_error) md.mesh->Save("inconsistent_surface_domain_"+ToString(md.domain)+".vol.gz"); PrintError ("Surface mesh not consistent"); throw NgException ("Stop meshing since surface mesh not consistent"); } RemoveIllegalElements (mesh, domain); ConformToFreeSegments (mesh, domain); } void MergeMeshes( Mesh & mesh, Array & md ) { // todo: optimize: count elements, alloc all memory, copy vol elements in parallel static Timer t("MergeMeshes"); RegionTimer rt(t); if(md.Size()==1) { // assume that mesh was never divided, no need to do anything if(&mesh != md[0].mesh.get()) throw Exception("Illegal Mesh pointer in MeshingData"); md[0].mesh.release(); return; } mesh.VolumeElements().DeleteAll(); // Keep identifications in the mesh, except the ones containing inner points // Inner points will be renumbered, the identifcations will not be valid anymore // These inner identifications are inserted at boundary layers when // 4 or more faces meet at a vertex -> insert pyramids to fill the gap // But pyramids are only inserted if the quad edges are identified mesh.GetIdentifications().DeleteInnerPointIdentifications(); for(auto & m_ : md) { auto first_new_pi = m_.pmap.Range().Next(); auto & m = *m_.mesh; Array pmap(m.Points().Size()); for(auto pi : Range(IndexBASE(), first_new_pi)) pmap[pi] = m_.pmap[pi]; for (auto pi : Range(first_new_pi, m.Points().Range().Next())) pmap[pi] = mesh.AddPoint(m[pi]); for ( auto el : m.VolumeElements() ) { for (auto i : Range(el.GetNP())) el[i] = pmap[el[i]]; el.SetIndex(m_.domain); mesh.AddVolumeElement(el); } // for(const auto& [p1p2, dummy] : m.GetIdentifications().GetIdentifiedPoints()) // mesh.GetIdentifications().Add(pmap[p1p2[0]], pmap[p1p2[1]], p1p2[2]); for(const auto& [p1p2, dummy] : m.GetIdentifications().GetIdentifiedPoints()) mesh.GetIdentifications().Add( pmap[ get<0>(p1p2)[0] ], pmap[ get<0>(p1p2)[1]] , get<1>(p1p2) ); for(auto i : Range(m.GetIdentifications().GetMaxNr())) { mesh.GetIdentifications().SetType(i+1, m.GetIdentifications().GetType(i+1)); if(auto name = m.GetIdentifications().GetName(i+1); name != "") mesh.GetIdentifications().SetName(i+1, name); } } } void MergeMeshes( Mesh & mesh, FlatArray meshes, PointIndex first_new_pi ) { // todo: optimize: count elements, alloc all memory, copy vol elements in parallel static Timer t("MergeMeshes"); RegionTimer rt(t); for(auto & m : meshes) { Array pmap(m.Points().Size()); for(auto pi : Range(IndexBASE(), first_new_pi)) pmap[pi] = pi; for (auto pi : Range(first_new_pi, m.Points().Range().Next())) pmap[pi] = mesh.AddPoint(m[pi]); for ( auto el : m.VolumeElements() ) { for (auto i : Range(el.GetNP())) el[i] = pmap[el[i]]; mesh.AddVolumeElement(el); } } } // extern double teterrpow; MESHING3_RESULT MeshVolume (const MeshingParameters & mp, Mesh& mesh3d) { static Timer t("MeshVolume"); RegionTimer reg(t); mesh3d.Compress(); if(mesh3d.GetNDomains()==0) return MESHING3_OK; auto geo = mesh3d.GetGeometry(); for (auto i : Range(std::min(geo->GetNSolids(), (size_t)mesh3d.GetNDomains()))) if (auto name = geo->GetSolid(i).properties.name) mesh3d.SetMaterial (i+1, *name); for (auto bl : mp.boundary_layers) GenerateBoundaryLayer(mesh3d, bl); if (!mesh3d.HasLocalHFunction()) mesh3d.CalcLocalH(mp.grading); auto md = DivideMesh(mesh3d, mp); try { ParallelFor( md.Range(), [&](int i) { try { auto & mesh = *md[i].mesh; if(&mesh != &mesh3d) { mesh.ClearFaceDescriptors(); for(auto face_descriptor : mesh3d.FaceDescriptors()) mesh.AddFaceDescriptor(face_descriptor); } if (mp.checkoverlappingboundary) if (mesh.CheckOverlappingBoundary()) { if(debugparam.write_mesh_on_error) mesh.Save("overlapping_mesh_domain_"+ToString(md[i].domain)+".vol.gz"); throw NgException ("Stop meshing since boundary mesh is overlapping"); } if(mesh.GetGeometry()->GetGeomType() == Mesh::GEOM_OCC) FillCloseSurface( md[i] ); CloseOpenQuads( md[i] ); MeshDomain(md[i]); if(&mesh != &mesh3d) mesh.FreeFaceDescriptors(); } catch (const Exception & e) { if(debugparam.write_mesh_on_error) md[i].mesh->Save("meshing_error_domain_"+ToString(md[i].domain)+".vol.gz"); cerr << "Meshing of domain " << i+1 << " failed with error: " << e.what() << endl; throw e; } }, md.Size()); } catch(...) { MergeMeshes(mesh3d, md); return MESHING3_GIVEUP; } MergeMeshes(mesh3d, md); MeshQuality3d (mesh3d); return MESHING3_OK; } MESHING3_RESULT OptimizeVolume (const MeshingParameters & mp, Mesh & mesh3d) // const CSGeometry * geometry) { static Timer t("OptimizeVolume"); RegionTimer reg(t); #ifndef EMSCRIPTEN RegionTaskManager rtm(mp.parallel_meshing ? mp.nthreads : 0); #endif // EMSCRIPTEN const char* savetask = multithread.task; multithread.task = "Optimize Volume"; // 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(); MeshOptimize3d optmesh(mesh3d, mp); // optimize only bad elements first optmesh.SetMinBadness(1000.); bool do_split = mp.optimize3d.find('d') != string::npos; bool do_swap = mp.optimize3d.find('s') != string::npos; bool do_swap2 = mp.optimize3d.find('t') != string::npos; for([[maybe_unused]] auto i : Range(mp.optsteps3d)) { auto [total_badness, max_badness, bad_els] = optmesh.UpdateBadness(); if(bad_els==0) break; if(do_split) optmesh.SplitImprove(); if(do_swap) optmesh.SwapImprove(); if(do_swap2) optmesh.SwapImprove2(); } // Now optimize all elements optmesh.SetMinBadness(0); for (auto i : Range(mp.optsteps3d)) { if (multithread.terminate) break; // teterrpow = mp.opterrpow; // for (size_t j = 1; j <= strlen(mp.optimize3d); j++) for (auto j : Range(mp.optimize3d.size())) { multithread.percent = 100.* (double(j)/mp.optimize3d.size() + i)/mp.optsteps3d; if (multithread.terminate) break; switch (mp.optimize3d[j]) { case 'c': optmesh.SetGoal(OPT_REST); optmesh.CombineImprove(); optmesh.SetGoal(OPT_QUALITY); break; case 'd': optmesh.SplitImprove(); break; case 'D': optmesh.SplitImprove2(); break; case 's': optmesh.SwapImprove(); break; // case 'u': optmesh.SwapImproveSurface(mesh3d); break; case 't': optmesh.SwapImprove2(); 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); } multithread.task = savetask; return MESHING3_OK; } void ConformToFreeSegments (Mesh & mesh, int domain) { auto geo = mesh.GetGeometry(); if(!geo) return; auto n_solids = geo->GetNSolids(); if(n_solids < domain) return; if(geo->GetSolid(domain-1).free_edges.Size() == 0) return; Array free_segs; for (auto segi : Range(mesh.LineSegments())) if(mesh[segi].domin == domain && mesh[segi].domout == domain) free_segs.Append(segi); auto get_nonconforming = [&] (const auto & p2el) { Array nonconforming; for (auto segi : free_segs) { auto seg = mesh[segi]; auto has_p0 = p2el[seg[0]]; bool has_both = false; for(auto ei : has_p0) { if(mesh[ei].PNums().Contains(seg[1])) has_both = true; } if(!has_both) nonconforming.Append(segi); } return nonconforming; }; auto split_segment = [&] (SegmentIndex segi, const auto & p2el) { auto seg = mesh[segi]; auto p_new = Center(mesh[seg[0]], mesh[seg[1]]); double lam[3]; ElementIndex ei_start = mesh.GetElementOfPoint(p_new, lam, false, domain); if(!ei_start.IsValid()) { PrintMessage(1, "Could not find volume element with new point"); return; } if(mesh[ei_start].IsDeleted()) return; double max_inside = -1.; ElementIndex ei_max_inside = ElementIndex::INVALID; // search for adjacent volume element, where the new point is "most inside", // i.e. the minimal barycentric coordinate is maximal for(auto pi : mesh[ei_start].PNums()) { for(auto ei1 : p2el[pi]) { double lam[3]; if(mesh[ei1].IsDeleted()) return; if(!mesh.PointContainedIn3DElement(p_new, lam, ei1)) continue; double inside = min(min(lam[0], lam[1]), min(lam[2], 1.0-lam[0]-lam[1])); if(inside > max_inside) { max_inside = inside; ei_max_inside = ei1; } } } if(max_inside < 1e-4) { PrintMessage(3, "Could not find volume element with new point inside"); return; } // split tet into 4 new tests, with new point inside auto el = mesh[ei_max_inside]; if(el.GetNP() != 4) { PrintMessage(3, "Only tet elements are supported to split around free segments"); return; } if(el.IsDeleted()) { PrintMessage(3,"Element to split is already deleted"); return; } auto pi_new = mesh.AddPoint(p_new); auto seg_new0 = seg; auto seg_new1 = seg; seg_new0[1] = pi_new; seg_new1[0] = pi_new; mesh[segi][0] = PointIndex::INVALID; mesh.AddSegment(seg_new0); mesh.AddSegment(seg_new1); int pmap[4][4] = { {0,1,2,4}, {1,3,2,4}, {0,2,3,4}, {0,3,1,4} }; PointIndex pis[5] = {el[0], el[1], el[2], el[3], pi_new}; for (auto i : Range(4)) { Element el_new; el_new = el; for (auto j : Range(4)) el_new[j] = pis[pmap[i][j]]; mesh.AddVolumeElement(el_new); } mesh[ei_max_inside].Delete(); }; size_t last_num_bad_segs = -1; for ([[maybe_unused]] auto i : Range(10)) { auto p2el = mesh.CreatePoint2ElementTable(); auto bad_segs = get_nonconforming(p2el); auto num_bad_segs = bad_segs.Size(); if(num_bad_segs == 0) return; PrintMessage(3, "Non-conforming free segments in domain ", domain, ": ", num_bad_segs); if(i>=5 || num_bad_segs != last_num_bad_segs) { for(auto i : bad_segs) split_segment(i, p2el); mesh.Compress(); } MeshingParameters dummymp; MeshOptimize3d optmesh(mesh, dummymp, OPT_CONFORM); for ([[maybe_unused]] auto i : Range(3)) { optmesh.ImproveMesh(); optmesh.SwapImprove2(true); optmesh.ImproveMesh(); optmesh.SwapImprove(); optmesh.ImproveMesh(); optmesh.CombineImprove(); } last_num_bad_segs = num_bad_segs; } auto p2el = mesh.CreatePoint2ElementTable(); auto bad_segs = get_nonconforming(p2el); if(bad_segs.Size() > 0) { auto bad_seg = mesh[bad_segs[0]]; if(debugparam.write_mesh_on_error) mesh.Save("free_segment_not_conformed_dom_"+ToString(domain)+"_seg_"+ToString(bad_seg[0])+"_"+ToString(bad_seg[1])+".vol.gz"); throw Exception("Segment not resolved in volume mesh in domain " + ToString(domain)+ ", seg: " + ToString(bad_seg)); } } void RemoveIllegalElements (Mesh & mesh3d, int domain) { static Timer t("RemoveIllegalElements"); RegionTimer reg(t); // return, if non-pure tet-mesh /* if (!mesh3d.PureTetMesh()) return; */ mesh3d.CalcSurfacesOfNode(); int nillegal = mesh3d.MarkIllegalElements(domain); if(nillegal) PrintMessage (1, "Remove Illegal Elements"); int oldn = nillegal; int nillegal_min = nillegal; MeshingParameters dummymp; MeshOptimize3d optmesh(mesh3d, dummymp, OPT_LEGAL); int it = 10; while (nillegal && (it--) > 0) { if (multithread.terminate) break; PrintMessage (5, nillegal, " illegal tets"); optmesh.SplitImprove (); mesh3d.MarkIllegalElements(); // test optmesh.SwapImprove (); mesh3d.MarkIllegalElements(); // test optmesh.SwapImprove2 (); oldn = nillegal; nillegal = mesh3d.MarkIllegalElements(); nillegal_min = min(nillegal_min, nillegal); if(nillegal > nillegal_min) break; if (oldn != nillegal) it = 10; } PrintMessage (5, nillegal, " illegal tets"); } } ================================================ FILE: libsrc/meshing/meshfunc.hpp ================================================ #ifndef FILE_MESHFUNC #define FILE_MESHFUNC /**************************************************************************/ /* File: meshfunc.hpp */ /* Author: Johannes Gerstmayr, Joachim Schoeberl */ /* Date: 26. Jan. 98 */ /**************************************************************************/ #include #include "meshing3.hpp" #include "meshtype.hpp" namespace netgen { /* Functions for mesh-generations strategies */ class Mesh; // class CSGeometry; /// Build tet-mesh DLL_HEADER MESHING3_RESULT MeshVolume (const MeshingParameters & mp, Mesh& mesh3d); /// Build mixed-element mesh // MESHING3_RESULT MeshMixedVolume (MeshingParameters & mp, Mesh& mesh3d); /// Optimize tet-mesh DLL_HEADER MESHING3_RESULT OptimizeVolume (const MeshingParameters & mp, Mesh& mesh3d); // const CSGeometry * geometry = NULL); DLL_HEADER void RemoveIllegalElements (Mesh & mesh3d, int domain = 0); DLL_HEADER void ConformToFreeSegments (Mesh & mesh3d, int domain); enum MESHING_STEP { MESHCONST_ANALYSE = 1, MESHCONST_MESHEDGES = 2, MESHCONST_MESHSURFACE = 3, MESHCONST_OPTSURFACE = 4, MESHCONST_MESHVOLUME = 5, MESHCONST_OPTVOLUME = 6 }; } // namespace netgen #endif ================================================ FILE: libsrc/meshing/meshfunc2d.cpp ================================================ #include #include "meshing.hpp" namespace netgen { DLL_HEADER void Optimize2d (Mesh & mesh, MeshingParameters & mp, int faceindex) { static Timer timer("optimize2d"); RegionTimer reg(timer); mesh.CalcSurfacesOfNode(); bool secondorder = mesh.GetNP() > mesh.GetNV(); if (secondorder) { for (SurfaceElementIndex ei = 0; ei < mesh.GetNSE(); ei++) mesh[ei].SetType(TRIG); } mesh.Compress(); bool optimize_swap_separate_faces = false; if(!mp.quad) { bool mixed = false; ParallelFor( Range(mesh.GetNSE()), [&] (auto i) NETGEN_LAMBDA_INLINE { if (mesh[SurfaceElementIndex(i)].GetNP() != 3) mixed = true; }); if(mixed) optimize_swap_separate_faces = true; } if(faceindex) optimize_swap_separate_faces = false; const char * optstr = mp.optimize2d.c_str(); int optsteps = mp.optsteps2d; // reset topology mesh.GetTopology() = MeshTopology(mesh); for (int i = 1; i <= optsteps; i++) for (size_t j = 1; j <= strlen(optstr); j++) { if (multithread.terminate) break; MeshOptimize2d meshopt(mesh); meshopt.SetMetricWeight (mp.elsizeweight); meshopt.SetFaceIndex(faceindex); switch (optstr[j-1]) { case 's': { // topological swap if(optimize_swap_separate_faces) { for(auto i : Range(1, mesh.GetNFD()+1)) { meshopt.SetFaceIndex(i); meshopt.EdgeSwapping (0); } } else { meshopt.EdgeSwapping (0); } break; } case 'S': { // metric swap if(optimize_swap_separate_faces) { for(auto i : Range(1, mesh.GetNFD()+1)) { meshopt.SetFaceIndex(i); meshopt.EdgeSwapping (1); } } else { meshopt.EdgeSwapping (1); } break; } case 'm': { meshopt.ImproveMesh(mp); break; } case 'c': { meshopt.CombineImprove(); break; } default: cerr << "Optimization code " << optstr[j-1] << " not defined" << endl; } } mesh.Compress(); // better: compress in individual steps, if necessary if (secondorder) { mesh.GetGeometry()->GetRefinement().MakeSecondOrder(mesh); } } } ================================================ FILE: libsrc/meshing/meshing.hpp ================================================ #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; using namespace std; class NetgenGeometry; } // #include "msghandler.hpp" // #include "meshtype.hpp" // #include "localh.hpp" // #include "topology.hpp" // #include "meshclass.hpp" // #include "global.hpp" #include "meshtool.hpp" #include "ruler2.hpp" #include "adfront2.hpp" #include "meshing2.hpp" #include "improve2.hpp" #include "geomsearch.hpp" #include "adfront3.hpp" #include "ruler3.hpp" #include "findip.hpp" #include "findip2.hpp" #include "meshing3.hpp" #include "improve3.hpp" #include "curvedelems.hpp" #include "clusters.hpp" #include "meshfunc.hpp" #include "bisect.hpp" #include "hprefinement.hpp" #include "specials.hpp" #include "validate.hpp" #include "basegeom.hpp" #include "surfacegeom.hpp" #include "paralleltop.hpp" #endif ================================================ FILE: libsrc/meshing/meshing2.cpp ================================================ #include #include "meshing2.hpp" #include "visual_interface.hpp" namespace netgen { static void glrender (int wait) { // cout << "plot adfront" << endl; if (multithread.drawing) { // vssurfacemeshing.DrawScene(); Render (); if (wait || multithread.testmode) { multithread.pause = 1; } while (multithread.pause); } } ostream& operator << (ostream& ost, const MultiPointGeomInfo& mpgi) { for(auto i : Range(mpgi.GetNPGI())) { ost << "gi[" << i << "] = " << mpgi.GetPGI(i+1) << endl; } return ost; } static Array> global_trig_rules; static Array> global_quad_rules; Meshing2 :: Meshing2 (const NetgenGeometry& ageo, const MeshingParameters & mp, const Box<3> & aboundingbox) : adfront(aboundingbox), boundingbox(aboundingbox), geo(ageo) { static Timer t("Mesing2::Meshing2"); RegionTimer r(t); auto & globalrules = mp.quad ? global_quad_rules : global_trig_rules; { static mutex mut; lock_guard guard(mut); if (!globalrules.Size()) { LoadRules (NULL, mp.quad); for (auto & rule : rules) globalrules.Append (make_unique(*rule)); rules.SetSize(0); } /* else { for (auto i : globalrules.Range()) rules.Append (globalrules[i].get()); } */ } for (auto i : globalrules.Range()) rules.Append (make_unique(*globalrules[i])); // LoadRules ("rules/quad.rls"); // LoadRules ("rules/triangle.rls"); // adfront = new AdFront2(boundingbox); starttime = GetTime(); maxarea = -1; } Meshing2 :: ~Meshing2 () { ; } int Meshing2 :: AddPoint (const Point3d & p, PointIndex globind, MultiPointGeomInfo * mgi, bool pointonsurface) { //(*testout) << "add point " << globind << endl; return adfront.AddPoint (p, globind, mgi, pointonsurface); } PointIndex Meshing2 :: GetGlobalIndex(int pi) const { return adfront.GetGlobalIndex(pi); } 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 Point<3> & /* p */, double gh) const { return gh; } // should be class variables !!(?) // static Vec3d ex, ey; // static Point3d globp1; void Meshing2 :: DefineTransformation (const Point<3> & ap1, const Point<3> & ap2, const PointGeomInfo * gi1, const PointGeomInfo * gi2) { p1 = ap1; p2 = ap2; auto n1 = geo.GetNormal(gi1->trignum, p1, gi1); auto n2 = geo.GetNormal(gi2->trignum, p2, gi2); ez = 0.5 * (n1+n2); ez.Normalize(); ex = (p2-p1).Normalize(); ez -= (ez*ex)*ex; ez.Normalize(); ey = Cross(ez, ex); } void Meshing2 :: TransformToPlain (const Point<3> & locpoint, const MultiPointGeomInfo & geominfo, Point<2> & plainpoint, double h, int & zone) { auto& gi = geominfo.GetPGI(1); auto n = geo.GetNormal(gi.trignum, locpoint, &gi); auto p1p = locpoint - p1; plainpoint(0) = (p1p * ex) / h; plainpoint(1) = (p1p * ey) / h; if(n*ez < 0) zone = -1; else zone = 0; } int Meshing2 :: TransformFromPlain (const Point<2> & plainpoint, Point<3> & locpoint, PointGeomInfo & gi, double h) { locpoint = p1 + (h*plainpoint(0)) * ex + (h* plainpoint(1)) * ey; if (!geo.ProjectPointGI(gi.trignum, locpoint, gi)) gi = geo.ProjectPoint(gi.trignum, locpoint); 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 (NgArray> & points, NgArray> & points3d, NgArray & 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, int layer) { static Timer timer("surface meshing"); RegionTimer reg(timer); static Timer timer1("surface meshing1"); static Timer timer2("surface meshing2"); static int timer3 = NgProfiler::CreateTimer ("surface meshing3"); static int ts1 = NgProfiler::CreateTimer ("surface meshing start 1"); static int ts2 = NgProfiler::CreateTimer ("surface meshing start 2"); static int ts3 = NgProfiler::CreateTimer ("surface meshing start 3"); NgProfiler::StartTimer (ts1); NgArray pindex, lindex; NgArray delpoints, dellines; NgArray upgeominfo; // unique info NgArray mpgeominfo; // multiple info NgArray locelements; int z1, z2, oldnp(-1); bool found; int rulenr(-1); const PointGeomInfo * blgeominfo1; const PointGeomInfo * blgeominfo2; bool morerisc; bool debugflag; // double h; auto locpointsptr = make_shared>>(); auto& locpoints = *locpointsptr; NgArray legalpoints; auto plainpointsptr = make_shared>>(); auto& plainpoints = *plainpointsptr; NgArray plainzones; auto loclinesptr = make_shared>(); auto &loclines = *loclinesptr; int trials = 0, nfaces = 0; int oldnl = 0; UpdateVisSurfaceMeshData(oldnl, locpointsptr, loclinesptr, plainpointsptr); int qualclass; // test for 3d overlaps BoxTree<3> surfeltree (boundingbox.PMin(), boundingbox.PMax()); NgArray intersecttrias; NgArray critpoints; // test for doubled edges //INDEX_2_HASHTABLE doubleedge(300000); testmode = 0; StartMesh(); NgArray> chartboundpoints; NgArray> chartboundpoints3d; NgArray chartboundlines; // illegal points: points with more then 50 elements per node int maxlegalpoint(-1), maxlegalline(-1); NgArray trigsonnode; NgArray 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 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, seia[i]); } NgProfiler::StopTimer (ts1); NgProfiler::StartTimer (ts2); if (totalarea > 0 || maxarea > 0) meshedarea = mesh.SurfaceArea(); /* 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; } */ // cout << "meshedarea = " << meshedarea << " =?= " // << mesh.SurfaceArea() << endl; NgProfiler::StopTimer (ts2); NgProfiler::StartTimer (ts3); const char * savetask = multithread.task; multithread.task = "Surface meshing"; adfront.SetStartFront (); int plotnexttrial = 999; double meshedarea_before = meshedarea; NgProfiler::StopTimer (ts3); static Timer tloop("surfacemeshing mainloop"); // static Timer tgetlocals("surfacemeshing getlocals"); { RegionTimer rloop(tloop); while (!adfront.Empty() && !multithread.terminate) { // 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.SetSize0(); loclines.SetSize0(); pindex.SetSize0(); lindex.SetSize0(); delpoints.SetSize0(); dellines.SetSize0(); locelements.SetSize0(); // 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.SetSize0(); mpgeominfo.SetSize0(); 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[i-1]->Name() << "\n"; } (*testout) << "\n"; } Point<3> p1, p2; int baselineindex = adfront.SelectBaseLine (p1, p2, blgeominfo1, blgeominfo2, qualclass); found = 1; double his = Dist (p1, p2); Point<3> pmid = Center (p1, p2); double hshould = CalcLocalH (pmid, mesh.GetH (pmid, layer)); if (gh < hshould) hshould = gh; mesh.RestrictLocalH (pmid, hshould); double h = hshould; double hinner = (3 + qualclass) * max2 (his, hshould); // tgetlocals.Start(); adfront.GetLocals (baselineindex, locpoints, mpgeominfo, loclines, pindex, lindex, 2*hinner); // tgetlocals.Stop(); // 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()+IndexBASE()) && (gpi2 < illegalpoint.Size()+IndexBASE()) ) { if (illegalpoint[gpi1] || illegalpoint[gpi2]) found = 0; } // Point2d p12d, p22d; if (found) { oldnp = locpoints.Size(); oldnl = loclines.Size(); UpdateVisSurfaceMeshData(oldnl); 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; } { // RegionTimer reg2 (timer2); for (size_t i = 0; i < locpoints.Size(); i++) { Point<2> pp; TransformToPlain (locpoints[i], mpgeominfo[i], pp, h, plainzones[i]); plainpoints[i] = pp; } } /* 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 = loclines.Get(i).I(innerp); int pouti = loclines.Get(i).I(3-innerp); const auto& pin = plainpoints.Get(pini); const auto& pout = plainpoints.Get(pouti); auto 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; */ Point<2> newpout = pin + 1000. * v; newpout = pout; plainpoints.Append (newpout); auto 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()); legalpoints = 1; /* for (int i = 1; i <= legalpoints.Size(); i++) legalpoints.Elem(i) = 1; */ double avy = 0; for (size_t i = 0; i < plainpoints.Size(); i++) avy += plainpoints[i][1]; avy *= 1./plainpoints.Size(); for (auto i : Range(plainpoints)) { if (plainzones[i] < 0) { plainpoints[i] = {1e4, 1e4}; legalpoints[i] = 0; } if (pindex[i] == -1) { legalpoints[i] = 0; } if (plainpoints[i][1] < -1e-10*avy) // changed { legalpoints[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++) { pindex.Append(-1); 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) { // static Timer t("ApplyRules"); // RegionTimer r(t); 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) if (el.PNum(j) < IndexBASE()+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++) { Point<3> locp; upgeominfo.Elem(i) = *blgeominfo1; int err = TransformFromPlain (plainpoints.Elem(i), locp, upgeominfo.Elem(i), h); locpoints.Elem(i) = locp; 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 (int jj = 0; jj < intersecttrias.Size(); jj++) { // int j = intersecttrias.Get(jj); // const Element2d & el = mesh.SurfaceElement(j); SurfaceElementIndex j = intersecttrias[jj]; const Element2d & el = mesh[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++) { PointIndex 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()-1); 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[rulenr-1]->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[rulenr-1]->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; UpdateVisSurfaceMeshData(oldnl); 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; } } ================================================ FILE: libsrc/meshing/meshing2.hpp ================================================ #ifndef NETGEN_MESHING2_HPP #define NETGEN_MESHING2_HPP /**************************************************************************/ /* File: meshing2.hpp */ /* Author: Joachim Schoeberl */ /* Date: 01. Okt. 95 */ /**************************************************************************/ #include "adfront2.hpp" #include "ruler2.hpp" #include "basegeom.hpp" namespace netgen { 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> rules; /// statistics NgArray ruleused, canuse, foundmap; /// Box<3> boundingbox; /// double starttime; /// double maxarea; Vec3d ex, ey, ez; Point<3> p1, p2; const NetgenGeometry& geo; public: /// DLL_HEADER Meshing2 (const NetgenGeometry& geo, 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, int layer=1); DLL_HEADER void Delaunay (Mesh & mesh, int domainnr, const MeshingParameters & mp); DLL_HEADER void BlockFillLocalH (Mesh & mesh, const MeshingParameters & mp); /// DLL_HEADER int AddPoint (const Point3d & p, PointIndex globind, MultiPointGeomInfo * mgi = NULL, bool pointonsurface = true); DLL_HEADER PointIndex GetGlobalIndex(int pi) const; /// 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 Point<3> & p, double gh) const; /// virtual void DefineTransformation (const Point<3> & p1, const Point<3> & p2, const PointGeomInfo * geominfo1, const PointGeomInfo * geominfo2); /// virtual void TransformToPlain (const Point<3> & locpoint, const MultiPointGeomInfo & geominfo, Point<2> & plainpoint, double h, int & zone); /// return 0 .. ok /// return >0 .. cannot transform point to true surface virtual int TransformFromPlain (const Point<2>& plainpoint, Point<3> & 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 (NgArray> & points, NgArray> & points3d, NgArray & lines, double p) const; virtual double Area () const; /** Applies 2D rules. Tests all 2D rules */ int ApplyRules (NgArray> & lpoints, NgArray & legalpoints, int maxlegalpoint, NgArray & llines, int maxlegelline, NgArray & elements, NgArray & dellines, int tolerance, const MeshingParameters & mp); }; } // namespace netgen #endif // NETGEN_MESHING2_HPP ================================================ FILE: libsrc/meshing/meshing3.cpp ================================================ #include #include "meshing3.hpp" #include "findip.hpp" #include "findip2.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 = make_unique(); 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; } */ foundmap = 0; canuse = 0; ruleused = 0; } Meshing3 :: Meshing3 (const char ** rulep) { tolfak = 1; LoadRules (NULL, rulep); adfront = make_unique(); 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; } */ foundmap = 0; canuse = 0; ruleused = 0; } Meshing3 :: ~Meshing3 () { // delete adfront; /* for (int i = 0; i < rules.Size(); i++) { delete [] problems[i]; delete rules[i]; } */ } /* // was war das ???? static double CalcLocH (const NgArray & locpoints, const NgArray & locfaces, double h) { return h; 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(int 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 Timer t("Meshing3::GenerateMesh"); RegionTimer reg(t); // static Timer meshing3_timer_a("Meshing3::GenerateMesh a", 2); // static Timer meshing3_timer_b("Meshing3::GenerateMesh b", 2); // static Timer meshing3_timer_c("Meshing3::GenerateMesh c", 1); // static Timer meshing3_timer_d("Meshing3::GenerateMesh d", 2); // 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 locpoints; // local points Array locfaces; // local faces Array pindex; // mapping from local to front point numbering Array allowpoint; // point is allowed (0/1/2) ? Array findex; // mapping from local to front face numbering //INDEX_2_HASHTABLE connectedpairs(100); // connecgted pairs for prism meshing Array plainpoints; // points in reference coordinates // NgArray delpoints; // points to be deleted NgArray delfaces; // lines to be deleted NgArray locelements; // new generated elements int j, oldnp, oldnf; int found; referencetransform trans; 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 grouppoints; Array groupfaces; Array grouppindex; Array groupfindex; float minerr; int hasfound; [[maybe_unused]] double tetvol; // int giveup = 0; NgArray tempnewpoints; NgArray tempnewfaces; NgArray tempdelfaces; NgArray 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 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 Point<3> p1 = adfront->GetPoint (bel[0]); const Point<3> p2 = adfront->GetPoint (bel[1]); const Point<3> p3 = adfront->GetPoint (bel[2]); Point<3> pmid = Center (p1, p2, p3); double his = (Dist (p1, p2) + Dist(p1, p3) + Dist(p2, p3)) / 3; double 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); // meshing3_timer_a.Start(); stat.qualclass = adfront -> GetLocals (baseelem, locpoints, locfaces, pindex, findex, connectedpairs, houter, hinner, locfacesplit); // meshing3_timer_a.Stop(); // (*testout) << "locfaces = " << endl << locfaces << endl; //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[0] << endl; int pi1 = pindex[locfaces[0].PNum(1)]; int pi2 = pindex[locfaces[0].PNum(2)]; int pi3 = pindex[locfaces[0].PNum(3)]; (*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(int i = 1; i <= allowpoint.Size(); i++) for(auto i : allowpoint.Range()) { allowpoint[i] = (mesh.GetH (locpoints[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 (auto & f : groupfaces) if (f.GetNP() != 3) onlytri = 0; if (onlytri && groupfaces.Size() <= 20 + 2*stat.qualclass && FindInnerPoint (grouppoints, groupfaces, inp) && !adfront->PointInsideGroup(grouppindex, groupfaces)) { (*testout) << "inner point found" << endl; for(int i = 0; i < groupfaces.Size(); i++) adfront -> DeleteFace (groupfindex[i]); for(int i = 1; i <= groupfaces.Size(); i++) for (j = 1; j <= locfaces.Size(); j++) if (findex[j-1] == groupfindex[i-1]) delfaces.Append (j); delfaces.SetSize (0); Element newel(TET); PointIndex npi = mesh.AddPoint (inp); newel.SetNP(4); newel.PNum(4) = npi; for(int i = 0; i < groupfaces.Size(); i++) { for (j = 1; j <= 3; j++) { newel.PNum(j) = adfront->GetGlobalIndex (grouppindex[groupfaces[i].PNum(j)]); } mesh.AddVolumeElement (newel); } continue; } } found = 0; hasfound = 0; minerr = 1e6; // int optother = 0; /* for(int 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(int 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 (int rotind = 1; rotind <= locfaces[0].GetNP(); rotind++) { // set transformatino to reference coordinates if (locfaces[0].GetNP() == 3) { trans.Set (locpoints[locfaces[0].PNumMod(1+rotind)], locpoints[locfaces[0].PNumMod(2+rotind)], locpoints[locfaces[0].PNumMod(3+rotind)], hshould); } else { trans.Set (locpoints[locfaces[0].PNumMod(1+rotind)], locpoints[locfaces[0].PNumMod(2+rotind)], locpoints[locfaces[0].PNumMod(4+rotind)], hshould); } // trans.ToPlain (locpoints, plainpoints); plainpoints.SetSize (locpoints.Size()); for (auto i : locpoints.Range()) trans.ToPlain (locpoints[i], plainpoints[i]); for (auto i : allowpoint.Range()) if (plainpoints[i].Z() > 0) allowpoint[i] = false; stat.cnttrials++; if (stat.cnttrials % 100 == 0) { (*testout) << "\n"; for(int i : canuse.Range()) { (*testout) << foundmap[i] << "/" << canuse[i] << "/" << ruleused[i] << " map/can/use rule " << rules[i]->Name() << "\n"; } (*testout) << endl; } // NgProfiler::StartTimer (meshing3_timer_c); // meshing3_timer_c.Start(); 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; // meshing3_timer_c.Stop(); // 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 (int i = oldnp+1; i <= plainpoints.Size(); i++) trans.FromPlain (plainpoints.Elem(i), locpoints.Elem(i)); */ for (auto i : plainpoints.Range().Modify(oldnp,0)) trans.FromPlain (plainpoints[i], locpoints[i]); // avoid meshing from large to small mesh-size if (uselocalh && found && stat.qualclass <= 3) { for (int i = 1; i <= locelements.Size(); i++) { Point3d pmin = locpoints[locelements.Get(i).PNum(1)]; Point3d pmax = pmin; for (j = 2; j <= 4; j++) { const Point3d & hp = locpoints[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 (int i = 1; i <= locelements.Size(); i++) for (int j = 1; j <= 4; j++) { const Point3d & hp = locpoints[locelements.Get(i).PNum(j)]; if (Dist (hp, pmid) > hinner) found = 0; } } if (found) ruleused[found-1]++; // plotstat->Plot(stat); if (stat.cntelem != plotstat_oldne) { plotstat_oldne = stat.cntelem; PrintMessageCR (5, "El: ", stat.cntelem, // << " trials: " << stat.cnttrials " faces: ", stat.nff, " vol = ", float(100 * stat.vol / stat.vol0)); multithread.percent = 100 - 100.0 * stat.vol / stat.vol0; } if (found && (!hasfound || err < minerr) ) { if (testmode) { (*testout) << "found is active, 3" << endl; //for(int i = 1; i <= plainpoints.Size(); i++) for(auto i : plainpoints.Range()) { (*testout) << "p"; if (i < pindex.Range().Next()) (*testout) << pindex[i] << ": "; else (*testout) << "new: "; (*testout) << plainpoints[i] << endl; } } hasfound = found; minerr = err; tempnewpoints.SetSize (0); // for(int i = oldnp+1; i <= locpoints.Size(); i++) for (auto i : locpoints.Range().Modify(oldnp,0)) tempnewpoints.Append (locpoints[i]); tempnewfaces.SetSize (0); // for(int i = oldnf+1; i <= locfaces.Size(); i++) for (auto i : locfaces.Range().Modify(oldnf,0)) tempnewfaces.Append (locfaces[i]); tempdelfaces.SetSize (0); // for(int i = 1; i <= delfaces.Size(); i++) for (auto i : delfaces.Range()) tempdelfaces.Append (delfaces[i]); templocelements.SetSize (0); // for(int i = 1; i <= locelements.Size(); i++) for (auto i : locelements.Range()) templocelements.Append (locelements[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(int i = 1; i <= tempnewpoints.Size(); i++) locpoints.Append (tempnewpoints.Get(i)); for(int i = 1; i <= tempnewfaces.Size(); i++) locfaces.Append (tempnewfaces.Get(i)); for(int i = 1; i <= tempdelfaces.Size(); i++) delfaces.Append (tempdelfaces.Get(i)); for(int i = 1; i <= templocelements.Size(); i++) locelements.Append (templocelements.Get(i)); if (loktestmode) { (*testout) << "apply rule" << endl; for (auto i : locpoints.Range()) { (*testout) << "p"; if (pindex.Range().Contains(i)) (*testout) << pindex[i] << ": "; else (*testout) << "new: "; (*testout) << locpoints[i] << endl; } } pindex.SetSize(locpoints.Size()); // for (int i = oldnp+1; i <= locpoints.Size(); i++) for (auto i : locpoints.Range().Modify(oldnp,0)) { PointIndex globind = mesh.AddPoint (locpoints[i]); pindex[i] = adfront -> AddPoint (locpoints[i], globind); } for (int i = 1; i <= locelements.Size(); i++) { Point3d * hp1, * hp2, * hp3, * hp4; hp1 = &locpoints[locelements.Get(i).PNum(1)]; hp2 = &locpoints[locelements.Get(i).PNum(2)]; hp3 = &locpoints[locelements.Get(i).PNum(3)]; hp4 = &locpoints[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[locelements.Get(i).PNum(j)]); mesh.AddVolumeElement (locelements.Get(i)); stat.cntelem++; } for(int i = oldnf; i < locfaces.Size(); i++) { for (j = 1; j <= locfaces[i].GetNP(); j++) locfaces[i].PNum(j) = pindex[locfaces[i].PNum(j)]; // (*testout) << "add face " << locfaces.Get(i) << endl; adfront->AddFace (locfaces[i]); } for(int i = 1; i <= delfaces.Size(); i++) adfront->DeleteFace (findex[delfaces.Get(i)-1]); } else { adfront->IncrementClass (findex[0]); if (impossible && mp.check_impossible) { (*testout) << "skip face since it is impossible" << endl; for (j = 0; j < 100; j++) adfront->IncrementClass (findex[0]); } } locelements.SetSize (0); // delpoints.SetSize(0); delfaces.SetSize(0); if (stat.qualclass >= mp.giveuptol) break; } PrintMessage (5, ""); // line feed after statistics for(int i : ruleused.Range()) (*testout) << setw(4) << ruleused[i] << " times used rule " << rules[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) { static Timer t("Mesing3::BlockFill"); RegionTimer reg(t); 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(int i = 1; i <= adfront->GetNP(); i++) { const Point3d & p = adfront->GetPoint(PointIndex(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); NgArray inner(n); NgArray pointnr(n); NgArray frontpointnr(n); // initialize inner to 1 for(int i = 1; i <= n; i++) inner.Elem(i) = BLOCKUNDEF; // set blocks cutting surfaces to 0 for(int 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(int i = 1; i <= n; i++) if (inner.Elem(i) == BLOCKINNER) { filled++; } PrintMessage (5, "Filled blocks: ", filled); for(int i = 1; i <= n; i++) { pointnr.Elem(i) = PointIndex::INVALID; 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).IsValid()) { 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) { static Timer t("Mesing3::BlockFillLocalH"); RegionTimer reg(t); double filldist = mp.filldist; // (*testout) << "blockfill local h" << endl; // (*testout) << "rel filldist = " << filldist << endl; PrintMessage (3, "blockfill local h"); NgArray > 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; auto loch_ptr = mesh.LocalHFunction().Copy(bbox); auto & loch = *loch_ptr; bool changed; static Timer t1("loop1"); t1.Start(); do { loch.ClearFlags(); static Timer tbox("adfront-bbox"); tbox.Start(); 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); loch.CutBoundary (bbox); // .PMin(), bbox.PMax()); } tbox.Stop(); // locadfront = adfront; loch.FindInnerBoxes (*adfront, NULL); npoints.SetSize(0); loch.GetInnerPoints (npoints); changed = false; for (int i = 1; i <= npoints.Size(); i++) { if (loch.GetH(npoints.Get(i)) > 1.5 * maxh) { loch.SetH (npoints.Get(i), maxh); changed = true; } } } while (changed); t1.Stop(); if (debugparam.slowchecks) (*testout) << "Blockfill with points: " << endl; for (int i = 1; i <= npoints.Size(); i++) { if (meshbox.IsIn (npoints.Get(i))) { PointIndex 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 static Timer tloch2("build loch2"); tloch2.Start(); 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); } tloch2.Stop(); // 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))) { PointIndex gpnum = mesh.AddPoint (npoints.Get(i)); adfront->AddPoint (npoints.Get(i), gpnum); } } } } ================================================ FILE: libsrc/meshing/meshing3.hpp ================================================ #ifndef FILE_MESHING3 #define FILE_MESHING3 #include "meshclass.hpp" #include "adfront3.hpp" #include "ruler3.hpp" namespace netgen { 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 unique_ptr adfront; /// 3d generation rules Array> rules; /// counts how often a rule is used Array ruleused, canuse, foundmap; /// describes, why a rule is not applied Array 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 & lpoints, Array & allowpoint, Array & lfaces, INDEX lfacesplit, INDEX_2_HASHTABLE & connectedpairs, NgArray & elements, NgArray & 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 extern int FindInnerPoint (POINTArray & grouppoints, FACEArray & groupfaces, Point3d & p); */ } // namespace netgen #endif ================================================ FILE: libsrc/meshing/meshtool.cpp ================================================ #include #include "meshing.hpp" #include #include namespace netgen { int CheckSurfaceMesh (const Mesh & mesh) { PrintMessage (3, "Check Surface mesh"); int nf = mesh.GetNSE(); INDEX_2_HASHTABLE 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; NgArray 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; } else if (teterrpow == 2) { errpow = err*err; grad = (2 * err) * graderr; } else { 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 NgArray & 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 NgArray & points, const NgArray & 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, NgArray * inclass) { int ncl = 20; signed int cl; NgArray 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 NgArray * 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 NetgenGeometry & 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 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(); Array ppoints(np); // int ndom = mesh.GetNDomains(); PrintMessage (3, "Elements before Remove: ", mesh.GetNE()); // for (k = 1; k <= ndom; k++) k = domainnr; { ppoints = false; 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[sel.PNum(j)] = true; } } 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[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()); } } ================================================ FILE: libsrc/meshing/meshtool.hpp ================================================ #ifndef NETGEN_MESHTOOL_HPP #define NETGEN_MESHTOOL_HPP // #include "../general/ngarray.hpp" // #include "../gprim/geom3d.hpp" // #include "../gprim/geomobjects.hpp" #include "meshtype.hpp" #include "meshclass.hpp" namespace netgen { /// extern void MeshQuality2d (const Mesh & mesh); /// extern void MeshQuality3d (const Mesh & mesh, NgArray * 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 NgArray * splines, ostream & outfile); */ class Surface; /// extern void SaveVolumeMesh ( const NgArray & points, const NgArray & elements, const NgArray & volelements, const NgArray & surfaces, char * filename); /// void SaveVolumeMesh (const Mesh & mesh, const class NetgenGeometry & 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 NgArray & points, // const Element & el); /** The total volume of all elements is computed. This function calculates the volume of the mesh */ extern double CalcVolume (const NgArray & points, const NgArray & 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); } // namespace netgen #endif // NETGEN_MESHTOOL_HPP ================================================ FILE: libsrc/meshing/meshtype.cpp ================================================ #include #include "meshing.hpp" namespace netgen { int MultiPointGeomInfo :: AddPointGeomInfo (const PointGeomInfo & gi) { for (auto & pgi : mgi) if (pgi.trignum == gi.trignum) return 0; mgi.Append(gi); return 0; } #ifdef PARALLEL /* working locally, but not too much at once ... template NG_MPI_Datatype NgMPI_CommitType ( std::array ablocklen, std::array adispl, std::array atypes, size_t aext ) { std::array displ; for (int i = 0; i < N; i++) displ[i] = adispl[i]; NG_MPI_Datatype htype, type; NG_MPI_Type_create_struct (N, &ablocklen[0], &displ[0], &atypes[0], &htype); NG_MPI_Type_commit ( &htype ); NG_MPI_Aint lb, ext; ext = aext; NG_MPI_Type_get_extent (htype, &lb, &ext); NG_MPI_Type_create_resized (htype, lb, ext, &type); NG_MPI_Type_commit ( &type ); return type; } NG_MPI_Datatype MeshPoint :: MyGetMPIType ( ) { static NG_MPI_Datatype type = NG_MPI_DATATYPE_NULL; if (type != NG_MPI_DATATYPE_NULL) return type; MeshPoint hp; array ablocklen = { 3, 1, 1 }; array adispl = { (char*)&hp.x[0] - (char*)&hp, (char*)&hp.layer - (char*)&hp, (char*)&hp.singular - (char*)&hp }; array atypes = { GetMPIType(hp.x[0]), GetMPIType(hp.layer), GetMPIType(hp.singular) }; type = NgMPI_CommitType<3> ( ablocklen, adispl, atypes, sizeof(MeshPoint) ); return type; } */ NG_MPI_Datatype MeshPoint :: MyGetMPIType ( ) { static NG_MPI_Datatype type = NG_MPI_DATATYPE_NULL; static NG_MPI_Datatype htype = NG_MPI_DATATYPE_NULL; if (type == NG_MPI_DATATYPE_NULL) { MeshPoint hp; int blocklen[] = { 3, 1, 1 }; NG_MPI_Aint displ[] = { (char*)&hp.x[0] - (char*)&hp, (char*)&hp.layer - (char*)&hp, (char*)&hp.singular - (char*)&hp }; NG_MPI_Datatype types[] = { NG_MPI_DOUBLE, NG_MPI_INT, NG_MPI_DOUBLE }; // *testout << "displ = " << displ[0] << ", " << displ[1] << ", " << displ[2] << endl; // *testout << "sizeof = " << sizeof (MeshPoint) << endl; NG_MPI_Type_create_struct (3, blocklen, displ, types, &htype); NG_MPI_Type_commit ( &htype ); NG_MPI_Aint lb, ext; NG_MPI_Type_get_extent (htype, &lb, &ext); // *testout << "lb = " << lb << endl; // *testout << "ext = " << ext << endl; ext = sizeof (MeshPoint); NG_MPI_Type_create_resized (htype, lb, ext, &type); NG_MPI_Type_commit ( &type ); } return type; } NG_MPI_Datatype Element2d :: MyGetMPIType ( ) { static NG_MPI_Datatype type = NG_MPI_DATATYPE_NULL; static NG_MPI_Datatype htype = NG_MPI_DATATYPE_NULL; if (type == NG_MPI_DATATYPE_NULL) { Element2d hel; int blocklen[] = { ELEMENT2D_MAXPOINTS, 1, 1, 1 }; NG_MPI_Aint displ[] = { (char*)&hel.pnum[0] - (char*)&hel, (char*)&hel.index - (char*)&hel, (char*)&hel.typ - (char*)&hel, (char*)&hel.np - (char*)&hel }; NG_MPI_Datatype types[] = { GetMPIType(), GetMPIType(hel.index), GetMPIType(hel.typ), GetMPIType(hel.np) }; // *testout << "displ = " << displ[0] << ", " << displ[1] << ", " << displ[2] << endl; // *testout << "sizeof = " << sizeof (MeshPoint) << endl; NG_MPI_Type_create_struct (4, blocklen, displ, types, &htype); NG_MPI_Type_commit ( &htype ); NG_MPI_Aint lb, ext; NG_MPI_Type_get_extent (htype, &lb, &ext); // *testout << "lb = " << lb << endl; // *testout << "ext = " << ext << endl; ext = sizeof (Element2d); NG_MPI_Type_create_resized (htype, lb, ext, &type); NG_MPI_Type_commit ( &type ); } return type; } NG_MPI_Datatype Element :: MyGetMPIType ( ) { static NG_MPI_Datatype type = NG_MPI_DATATYPE_NULL; static NG_MPI_Datatype htype = NG_MPI_DATATYPE_NULL; if (type == NG_MPI_DATATYPE_NULL) { Element hel; int blocklen[] = { ELEMENT_MAXPOINTS, 1, 1, 1 }; NG_MPI_Aint displ[] = { (char*)&hel.pnum[0] - (char*)&hel, (char*)&hel.index - (char*)&hel, (char*)&hel.typ - (char*)&hel, (char*)&hel.np - (char*)&hel }; NG_MPI_Datatype types[] = { GetMPIType(), GetMPIType(hel.index), GetMPIType(hel.typ), GetMPIType(hel.np) }; // *testout << "displ = " << displ[0] << ", " << displ[1] << ", " << displ[2] << endl; // *testout << "sizeof = " << sizeof (MeshPoint) << endl; NG_MPI_Type_create_struct (4, blocklen, displ, types, &htype); NG_MPI_Type_commit ( &htype ); NG_MPI_Aint lb, ext; NG_MPI_Type_get_extent (htype, &lb, &ext); // *testout << "lb = " << lb << endl; // *testout << "ext = " << ext << endl; ext = sizeof (Element); NG_MPI_Type_create_resized (htype, lb, ext, &type); NG_MPI_Type_commit ( &type ); } return type; } NG_MPI_Datatype Segment :: MyGetMPIType ( ) { static NG_MPI_Datatype type = NG_MPI_DATATYPE_NULL; static NG_MPI_Datatype htype = NG_MPI_DATATYPE_NULL; if (type == NG_MPI_DATATYPE_NULL) { Segment hel; int blocklen[] = { 3, 1, 1, 1 }; NG_MPI_Aint displ[] = { (char*)&hel.pnums[0] - (char*)&hel, (char*)&hel.edgenr - (char*)&hel, (char*)&hel.index - (char*)&hel, (char*)&hel.si - (char*)&hel }; NG_MPI_Datatype types[] = { GetMPIType(), GetMPIType(hel.edgenr), GetMPIType(hel.index), GetMPIType(hel.si) }; // *testout << "displ = " << displ[0] << ", " << displ[1] << ", " << displ[2] << endl; // *testout << "sizeof = " << sizeof (MeshPoint) << endl; NG_MPI_Type_create_struct (4, blocklen, displ, types, &htype); NG_MPI_Type_commit ( &htype ); NG_MPI_Aint lb, ext; NG_MPI_Type_get_extent (htype, &lb, &ext); // *testout << "lb = " << lb << endl; // *testout << "ext = " << ext << endl; ext = sizeof (Segment); NG_MPI_Type_create_resized (htype, lb, ext, &type); NG_MPI_Type_commit ( &type ); } return type; } #endif #ifdef PARALLEL NG_MPI_Datatype Element0d :: MyGetMPIType() { static NG_MPI_Datatype type = NG_MPI_DATATYPE_NULL; static NG_MPI_Datatype htype = NG_MPI_DATATYPE_NULL; if (type == NG_MPI_DATATYPE_NULL) { Element0d hel; int blocklen[] = { 1, 1 }; NG_MPI_Aint displ[] = { (char*)&hel.pnum - (char*)&hel, (char*)&hel.index - (char*)&hel, }; NG_MPI_Datatype types[] = { GetMPIType(hel.pnum), GetMPIType(hel.index) }; NG_MPI_Type_create_struct (2, blocklen, displ, types, &htype); NG_MPI_Type_commit ( &htype ); NG_MPI_Aint lb, ext; NG_MPI_Type_get_extent (htype, &lb, &ext); // *testout << "lb = " << lb << endl; // *testout << "ext = " << ext << endl; ext = sizeof (Element0d); NG_MPI_Type_create_resized (htype, lb, ext, &type); NG_MPI_Type_commit ( &type ); } return type; } #endif void Element0d :: DoArchive (Archive & ar) { ar & pnum & index; } Segment :: Segment() : is_curved(false) { pnums[0] = PointIndex::INVALID; pnums[1] = PointIndex::INVALID; edgenr = -1; index = -1; singedge_left = 0.; singedge_right = 0.; seginfo = 0; si = -1; domin = -1; domout = -1; tlosurf = -1; surfnr1 = -1; surfnr2 = -1; pnums[2] = PointIndex::INVALID; 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; } void Segment :: DoArchive (Archive & ar) { string * bcname_dummy = nullptr; ar & pnums[0] & pnums[1] & pnums[2] & edgenr & singedge_left & singedge_right & si & index & domin & domout & tlosurf & surfnr1 & surfnr2 & bcname_dummy // keep this for backward compatibility & epgeominfo[0].edgenr & epgeominfo[1].edgenr; } 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; } // needed, e.g. for MPI communication Element2d :: Element2d () { for (int i = 0; i < ELEMENT2D_MAXPOINTS; i++) { pnum[i].Invalidate(); geominfo[i].trignum = 0; } np = 3; index = 0; badel = 0; deleted = 0; visible = 1; typ = TRIG; orderx = ordery = 1; refflag = 1; strongrefflag = false; is_curved = 0; } Element2d :: Element2d (int anp) { for (int i = 0; i < ELEMENT2D_MAXPOINTS; i++) { pnum[i].Invalidate(); 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; is_curved = (np >= 4); // false; } Element2d :: Element2d (ELEMENT_TYPE atyp) { for (int i = 0; i < ELEMENT2D_MAXPOINTS; i++) { pnum[i].Invalidate(); geominfo[i].trignum = 0; } SetType (atyp); index = 0; badel = 0; deleted = 0; visible = 1; orderx = ordery = 1; refflag = 1; strongrefflag = false; is_curved = (np >= 4); // false; } Element2d :: Element2d (PointIndex pi1, PointIndex pi2, PointIndex pi3) { pnum[0] = pi1; pnum[1] = pi2; pnum[2] = pi3; np = 3; typ = TRIG; for (int i = 3; i < ELEMENT2D_MAXPOINTS; i++) pnum[i].Invalidate(); 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; is_curved = false; } Element2d :: Element2d (PointIndex pi1, PointIndex pi2, PointIndex pi3, PointIndex pi4) { pnum[0] = pi1; pnum[1] = pi2; pnum[2] = pi3; pnum[3] = pi4; np = 4; typ = QUAD; pnum[4].Invalidate(); pnum[5].Invalidate(); 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; is_curved = true; } /* 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[pnum[0]]); for (unsigned i = 1; i < np; i++) box.AddPoint (points[pnum[i]]); } bool Element2d :: operator==(const Element2d & el2) const { bool retval = (el2.GetNP() == np); for(int i= 0; retval && i ipdtrig; NgArray 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, Point<2> & 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 ", int(typ)); } p[0] = pp[0]; p[1] = pp[1]; weight = pp[2]; } void Element2d :: GetTransformation (int ip, const NgArray> & points, DenseMatrix & trans) const { int np = GetNP(); DenseMatrix pmat(2, np), dshape(2, np); pmat.SetSize (2, np); dshape.SetSize (2, np); Point<2> 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 ", int(typ)); } CalcABt (pmat, *dshapep, trans); } void Element2d :: GetShape (const Point<2> & p, Vector & shape) const { if (shape.Size() != GetNP()) { cerr << "Element::GetShape: Length not fitting" << endl; return; } switch (typ) { case TRIG: shape(0) = 1 - p[0] - p[1]; shape(1) = p[0]; shape(2) = 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; default: PrintSysError ("Element2d::GetShape, illegal type ", int(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; } default: throw NgException ("illegal element type in GetShapeNew"); } } template void Element2d :: GetShapeNew (const Point<2,T> & p, TFlatVector 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; } default: throw NgException ("illegal element type in GetShapeNew"); } } void Element2d :: GetDShape (const Point<2> & 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[1]); dshape.Elem(1, 2) = (1-p[1]); dshape.Elem(1, 3) = p[1]; dshape.Elem(1, 4) = -p[1]; dshape.Elem(2, 1) = -(1-p[0]); dshape.Elem(2, 2) = -p[0]; dshape.Elem(2, 3) = p[0]; dshape.Elem(2, 4) = (1-p[0]); break; default: PrintSysError ("Element2d::GetDShape, illegal type ", int(typ)); } } template void Element2d :: GetDShapeNew (const Point<2,T> & p, MatrixFixWidth<2,T> & dshape) const { switch (typ) { case TRIG: { dshape = T(0.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; } default: throw NgException ("illegal element type in GetDShapeNew"); } } void Element2d :: GetPointMatrix (const NgArray> & 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 auto& p = points.Get(PNum(i)); pmat.Elem(1, i) = p[0]; pmat.Elem(2, i) = p[1]; } } double Element2d :: CalcJacobianBadness (const NgArray> & 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 NgArray> & points, int pi, Vec<2> & 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 auto& p = points.Get( (*this)[j] ); pmat(0, j) = p[0]; pmat(1, j) = p[1]; } vmat = 0.0; vmat(0, pi-1) = dir[0]; vmat(1, pi-1) = dir[1]; 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[0]; vmat.Elem(2, pi) = dir[1]; 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++) { const auto& p = points[PNum(i)]; pmat.Elem(1, i) = p[0] * t1(0) + p[1] * t1(1) + p[2] * t1(2); pmat.Elem(2, i) = p[0] * t2(0) + p[1] * t2(1) + p[2] * 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; Point<2> hp; GetIntegrationPoint (i, hp, ipd->weight); ipd->p(0) = hp[0]; ipd->p(1) = hp[1]; 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 Element0d & el) { s << el.pnum << ", index = " << el.index; return s; } 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 << " " << 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; is_curved = false; #ifdef PARALLEL partitionNumber = -1; #endif } */ Element :: Element (int anp) { np = anp; for (int i = 0; i < ELEMENT_MAXPOINTS; i++) pnum[i].Invalidate(); 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 7: typ = HEX7; break; case 8: typ = HEX; break; case 10: typ = TET10; break; case 13: typ = PYRAMID13; break; case 15: typ = PRISM15; break; case 20: typ = HEX20; break; default: cerr << "Element::Element: unknown element with " << np << " points" << endl; } orderx = ordery = orderz = 1; is_curved = typ != TET; // false; } 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); for (int i = 0; i < ELEMENT_MAXPOINTS; i++) pnum[i].Invalidate(); 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; is_curved = typ != TET; // false; // #ifdef PARALLEL // partitionNumber = -1; // #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; is_curved = el2.is_curved; 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 7: typ = HEX7; break; case 8: typ = HEX; break; case 10: typ = TET10; break; case 13: typ = PYRAMID13; break; case 15: typ = PRISM15; break; case 20: typ = HEX20; 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 HEX7: np = 7; break; case HEX: np = 8; break; case TET10: np = 10; break; case PYRAMID13: np = 13; break; case PRISM12: np = 12; break; case PRISM15: np = 15; break; case HEX20: np = 20; break; default: break; cerr << "Element::SetType unknown type " << int(typ) << endl; } is_curved = (np > 4); } 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[PNum(1)]); box.AddPoint (points[PNum(2)]); box.AddPoint (points[PNum(3)]); box.AddPoint (points[PNum(4)]); } double Element :: Volume (const T_POINTS & points) const { Vec<3> v1 = points[PNum(2)] - points[PNum(1)]; Vec<3> v2 = points[PNum(3)] - points[PNum(1)]; Vec<3> v3 = points[PNum(4)] - points[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 } }; static const int hex7faces[][5] = { { 4, 4, 3, 2, 1 }, { 4, 3, 7, 6, 2 }, { 3, 7, 5, 6 }, { 4, 7, 4, 1, 5 }, { 4, 1, 2, 6, 5 }, { 3, 3, 4, 7 } }; static const int hexfaces[][5] = { { 4, 4, 3, 2, 1 }, { 4, 3, 7, 6, 2 }, { 4, 7, 8, 5, 6 }, { 4, 8, 4, 1, 5 }, { 4, 1, 2, 6, 5 }, { 4, 3, 4, 8, 7 } }; 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; } case 7: // hex7 { // face.SetNP(prismfaces[i-1][0]); face.SetType ( ((i == 3) || (i==6)) ? TRIG : QUAD); for (int j = 1; j <= face.GetNP(); j++) face.PNum(j) = PNum(hex7faces[i-1][j]); break; } case 8: { face.SetType(QUAD); for (int j = 1; j <= 4; j++) face.PNum(j) = PNum(hexfaces[i-1][j]); break; } } } void Element :: GetTets (NgArray & 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 (NgArray & 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 & 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 implemented 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 (NgArray > & 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 implemented 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 (NgArray & 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 hex7trigs[][3] = { { 1, 3, 2 }, { 1, 4, 3 }, { 5, 6, 7 }, { 1, 2, 6 }, { 1, 6, 5 }, { 2, 3, 7 }, { 2, 7, 6 }, { 3, 4, 7 }, { 4, 1, 7 }, { 1, 5, 7 } }; 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 HEX7: { nf = 10; fp = hex7trigs; 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]; } } NgArray< shared_ptr < IntegrationPointData > > ipdtet; NgArray< shared_ptr < 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; default: throw NgException ("illegal element shape in GetIntegrationPoint"); } 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 { if (shape.Size() != GetNP()) { cerr << "Element::GetShape: Length not fitting" << endl; return; } switch (typ) { case TET: { shape(0) = 1 - hp[0] - hp[1] - hp[2]; shape(1) = hp[0]; shape(2) = hp[1]; shape(3) = hp[2]; break; } case TET10: { double lam1 = 1 - hp[0] - hp[1] - hp[2]; double lam2 = hp[0]; double lam3 = hp[1]; double lam4 = hp[2]; 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: { 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: { 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; } default: throw NgException("Element :: GetShape not implemented for that element"); } } template void Element :: GetShapeNew (const Point<3,T> & p, TFlatVector 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: { T lam1 = p(0); T lam2 = p(1); T lam3 = p(2); T 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: { T noz = 1-p(2); // if (noz == 0.0) noz = 1e-10; noz += T(1e-12); T xi = p(0) / noz; T 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 PYRAMID13: { T x = p(0); T y = p(1); T z = p(2); z *= 1-1e-12; shape[0] = (-z + z*(2*x + z - 1)*(2*y + z - 1)/(-z + 1) + (-2*x - z + 2)*(-2*y - z + 2))*(-0.5*x - 0.5*y - 0.5*z + 0.25); shape[1] = (0.5*x - 0.5*y - 0.25)*(-z - z*(2*x + z - 1)*(2*y + z - 1)/(-z + 1) + (2*x + z)*(-2*y - z + 2)); shape[2] = (-z + z*(2*x + z - 1)*(2*y + z - 1)/(-z + 1) + (2*x + z)*(2*y + z))*(0.5*x + 0.5*y + 0.5*z - 0.75); shape[3] = (-0.5*x + 0.5*y - 0.25)*(-z - z*(2*x + z - 1)*(2*y + z - 1)/(-z + 1) + (2*y + z)*(-2*x - z + 2)); shape[4] = z*(2*z - 1); shape[5] = 2*x*(-2*x - 2*z + 2)*(-2*y - 2*z + 2)/(-2*z + 2); shape[6] = 4*x*y*(-2*x - 2*z + 2)/(-2*z + 2); shape[7] = 2*y*(-2*x - 2*z + 2)*(-2*y - 2*z + 2)/(-2*z + 2); shape[8] = 4*x*y*(-2*y - 2*z + 2)/(-2*z + 2); shape[9] = z*(-2*x - 2*z + 2)*(-2*y - 2*z + 2)/(-z + 1); shape[10] = 2*x*z*(-2*y - 2*z + 2)/(-z + 1); shape[11] = 4*x*y*z/(-z + 1); shape[12] = 2*y*z*(-2*x - 2*z + 2)/(-z + 1); 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 PRISM15: { T x = p(0); T y = p(1); T z = p(2); T lam = 1-x-y; T lamz = 1-z; shape[0] = (2*x*x-x) * (2*lamz*lamz-lamz); shape[1] = (2*y*y-y) * (2*lamz*lamz-lamz); shape[2] = (2*lam*lam-lam) * (2*lamz*lamz-lamz); shape[3] = (2*x*x-x) * (2*z*z-z); shape[4] = (2*y*y-y) * (2*z*z-z); shape[5] = (2*lam*lam-lam) * (2*z*z-z); shape[6] = 4 * x * y * (2*lamz*lamz-lamz); shape[7] = 4 * x * lam * (2*lamz*lamz-lamz); shape[8] = 4 * y * lam * (2*lamz*lamz-lamz); shape[9] = x * 4 * z * (1-z); shape[10] = y * 4 * z * (1-z); shape[11] = lam * 4 * z * (1-z); shape[12] = 4 * x * y * (2*z*z-z); shape[13] = 4 * x * lam * (2*z*z-z); shape[14] = 4 * y * lam * (2*z*z-z); break; } case HEX7: { T y = p(1); T z = p(2); // T den = (1-y)*(1-z); T den = (1-y*z); den += T(1e-12); T x = p(0) / den; shape(0) = (1-x)*(1-y)*(1-z); shape(1) = ( x)*(1-y)*(1-z); shape(2) = ( x)*( y)*(1-z); shape(3) = (1-x)*( y)*(1-z); shape(4) = (1-x)*(1-y)*( z); shape(5) = ( x)*(1-y)*( z); shape(6) = ( y)*( z); 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; } case HEX20: { T x = p(0); T y = p(1); T z = p(2); shape[0] = (1-x)*(1-y)*(1-z); shape[1] = x *(1-y)*(1-z); shape[2] = x * y *(1-z); shape[3] = (1-x)* y *(1-z); shape[4] = (1-x)*(1-y)*(z); shape[5] = x *(1-y)*(z); shape[6] = x * y *(z); shape[7] = (1-x)* y *(z); T sigma[8]={(1-x)+(1-y)+(1-z),x+(1-y)+(1-z),x+y+(1-z),(1-x)+y+(1-z), (1-x)+(1-y)+z,x+(1-y)+z,x+y+z,(1-x)+y+z}; static const int e[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 }, }; for (int i = 0; i < 12; i++) { T lame = shape[e[i][0]]+shape[e[i][1]]; T xi = sigma[e[i][1]]-sigma[e[i][0]]; shape[8+i] = (1-xi*xi)*lame; } for (int i = 0; i < 12; i++) { shape[e[i][0]] -= 0.5 * shape[8+i]; shape[e[i][1]] -= 0.5 * shape[8+i]; } break; } default: throw NgException("Element :: GetNewShape not implemented for that element"); } } void Element :: GetDShape (const Point<3> & hp, DenseMatrix & dshape) const { 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 (auto i : Range(3)) { Point<3> pr(hp), pl(hp); pr[i] += eps; pl[i] -= eps; GetShape (pr, shaper); GetShape (pl, shapel); for (int j = 0; j < np; j++) dshape(i, j) = (shaper(j) - shapel(j)) / (2 * eps); } } template void Element :: GetDShapeNew (const Point<3,T> & p, MatrixFixWidth<3,T> & dshape) const { switch (typ) { case TET: { dshape = T(0.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 = T(0.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; NgArrayMem mem(2*np); TFlatVector shaper(np, &mem[0]); TFlatVector shapel(np, &mem[np]); // Vector shaper(np), shapel(np); for (int i = 0; i < 3; i++) { Point<3,T> pr(p), pl(p); pr(i) += eps; pl(i) -= eps; GetShapeNew (pr, shaper); GetShapeNew (pl, shapel); for (int j = 0; j < np; j++) dshape(j, i) = (shaper(j) - shapel(j)) / (2 * eps); } */ AutoDiff<3,T> adx(p(0), 0); AutoDiff<3,T> ady(p(1), 1); AutoDiff<3,T> adz(p(2), 2); Point<3,AutoDiff<3,T>> adp{adx, ady, adz}; NgArrayMem,100> mem(np); TFlatVector> adshape(np, &mem[0]); GetShapeNew (adp, adshape); for (int j = 0; j < np; j++) for (int k = 0; k < 3; k++) dshape(j,k) = adshape(j).DValue(k); } } } template void Element2d :: GetShapeNew (const Point<2,double> & p, TFlatVector shape) const; template void Element2d :: GetShapeNew (const Point<2,SIMD> & p, TFlatVector> shape) const; template void Element2d::GetDShapeNew (const Point<2> &, MatrixFixWidth<2> &) const; template void Element2d::GetDShapeNew> (const Point<2,SIMD> &, MatrixFixWidth<2,SIMD> &) const; template DLL_HEADER void Element :: GetShapeNew (const Point<3,double> & p, TFlatVector shape) const; template DLL_HEADER void Element :: GetShapeNew (const Point<3,SIMD> & p, TFlatVector> shape) const; template void Element::GetDShapeNew (const Point<3> &, MatrixFixWidth<3> &) const; template void Element::GetDShapeNew> (const Point<3,SIMD> &, MatrixFixWidth<3,SIMD> &) const; void Element :: GetPointMatrix (const T_POINTS & points, DenseMatrix & pmat) const { int np = GetNP(); for (int i = 1; i <= np; i++) { const auto& p = points[PNum(i)]; pmat.Elem(1, i) = p[0]; pmat.Elem(2, i) = p[1]; pmat.Elem(3, i) = p[2]; } } 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 = Vec<4>(0.0,1.0,0.0,1.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 = Vec<4>(0.0,1.0,0.0,1.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 = Vec<4>(0.0,1.0,0.0,1.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 :: default_bcname = "default"; /* const string & FaceDescriptor :: GetBCName () const { static string defaultstring = "default"; if (bcname) return *bcname; return defaultstring; } */ void FaceDescriptor :: SetBCName (string * bcn) { if (bcn) bcname = *bcn; else bcname = "default"; } void FaceDescriptor :: DoArchive (Archive & ar) { ar & surfnr & domin & domout & tlosurf & bcprop & surfcolour & bcname & domin_singular & domout_singular ; // don't need: firstelement } ostream & operator<<(ostream & s, const FaceDescriptor & fd) { s << "surfnr = " << fd.SurfNr() << ", domin = " << fd.DomainIn() << ", domout = " << fd.DomainOut() << ", tlosurf = " << fd.TLOSurface() << ", bcprop = " << fd.BCProperty() << ", bcname = " << fd.GetBCName() << ", domin_sing = " << fd.DomainInSingular() << ", domout_sing = " << fd.DomainOutSingular() << ", colour = " << fd.SurfColour(); return s; } Identifications :: Identifications (Mesh & amesh) : mesh(amesh), identifiedpoints(100), identifiedpoints_nr(100) { // identifiedpoints = new INDEX_2_HASHTABLE(100); // identifiedpoints_nr = new INDEX_3_HASHTABLE(100); maxidentnr = 0; } Identifications :: ~Identifications () { ; // delete identifiedpoints; // delete identifiedpoints_nr; } void Identifications :: Delete () { identifiedpoints.DeleteData(); identifiedpoints_nr.DeleteData(); idpoints_table.SetSize(0); /* delete identifiedpoints; identifiedpoints = new INDEX_2_HASHTABLE(100); delete identifiedpoints_nr; identifiedpoints_nr = new INDEX_3_HASHTABLE(100); */ maxidentnr = 0; } void Identifications :: DeleteInnerPointIdentifications () { Array> entries; for(auto [pis, nr]: identifiedpoints) { PointIndex pi0 = pis[0]; PointIndex pi1 = pis[1]; if(mesh[pi0].Type() != INNERPOINT || mesh[pi1].Type() != INNERPOINT) entries.Append( { pi0, pi1, nr } ); } identifiedpoints.DeleteData(); identifiedpoints_nr.DeleteData(); idpoints_table.SetSize(0); for (auto [pi0, pi1, nr]: entries) Add(pi0, pi1, nr); } void Identifications :: DoArchive (Archive & ar) { ar & maxidentnr; ar & identifiedpoints & identifiedpoints_nr; ar & idpoints_table; if (ar.Output()) { size_t s = type.Size(); ar & s; for (auto & t : type) ar & (unsigned char&)(t); } else { size_t s; ar & s; type.SetSize(s); for (auto & t : type) ar & (unsigned char&)(t); } if (ar.GetVersion("netgen") > "v6.2.2404-66") ar & names; } void Identifications :: Add (PointIndex pi1, PointIndex pi2, int identnr) { // (*testout) << "Identification::Add, pi1 = " << pi1 << ", pi2 = " << pi2 << ", identnr = " << identnr << endl; PointIndices<2> pair (pi1, pi2); identifiedpoints.Set (pair, identnr); // INDEX_3 tripl (pi1, pi2, identnr); identifiedpoints_nr.Set ( { { pi1, pi2 }, identnr }, 1); if (identnr > maxidentnr) maxidentnr = identnr; names.SetSize(maxidentnr); 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)) if (identifiedpoints_nr.Used ( { { pi1, pi1 }, nr } ) ) 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, idmap_type & 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++) */ for (auto [hash, val] : identifiedpoints_nr) { /* INDEX_3 i3; int dummy; identifiedpoints_nr.GetData (i, j, i3, dummy); */ auto [hash_pts, hash_nr] = hash; if (hash_nr == identnr || !identnr) { /* identmap.Elem(i3.I1()) = i3.I2(); if(symmetric) identmap.Elem(i3.I2()) = i3.I1(); */ identmap[hash_pts.I1()] = hash_pts.I2(); if(symmetric) identmap[hash_pts.I2()] = hash_pts.I1(); } } } } Array Identifications :: GetPairs () const { Array pairs; for(auto [hash, dummy] : identifiedpoints_nr) // pairs.Append(i3); { auto [pts,nr] = hash; pairs.Append ( { pts[0], pts[1], nr } ); } return pairs; } void Identifications :: GetPairs (int identnr, NgArray & 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); } */ for (auto [hash,val] : identifiedpoints) identpairs.Append (hash); } 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())); } */ for (auto [hash,val] : identifiedpoints_nr) { auto [hash_pts, hash_nr] = hash; if (hash_nr == identnr) identpairs.Append (hash_pts); } } } 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); } } */ // can we get data by reference ? for (auto [hash,data] : identifiedpoints) { if (hash.I1() > IndexBASE()+maxpnum-1 || hash.I2() > IndexBASE()+maxpnum-1) { identifiedpoints[hash] = -1; } } } // Map points in the identifications to new point numbers // deletes identifications with invalid (mapped) points void Identifications :: MapPoints(FlatArray op2np) { auto pairs = GetPairs(); Delete(); for(auto pair : pairs) { auto p1 = op2np[pair.I1()]; auto p2 = op2np[pair.I2()]; if(p1.IsValid() && p2.IsValid()) Add(p1, p2, pair.I3()); } } void Identifications :: Print (ostream & ost) const { ost << "Identifications:" << endl; ost << "pairs: " << endl << identifiedpoints << endl; // ost << "pairs and nr: " << endl << identifiedpoints_nr << endl; ost << "pairs and nr: " << endl; for (auto [key,val] : identifiedpoints_nr) ost << get<0>(key) << "," << get<1>(key) << ": " << val << endl; ost << "table: " << endl << idpoints_table << endl; } ostream & operator<< (ostream & ost, const BoundaryLayerParameters & mp) { auto print_vec = [&ost](auto & v) { ost << "["; for (const auto & val : v) ost << val << " "; ost << "]"; }; ost << "BoundaryLayerParameters" << endl; ost << " boundary: "; switch(mp.boundary.index()) { case 0: ost << std::get<0>(mp.boundary); break; case 1: ost << std::get<1>(mp.boundary); break; case 2: print_vec(std::get<2>(mp.boundary)); break; } ost << "\n thickness: "; switch(mp.thickness.index()) { case 0: ost << std::get<0>(mp.thickness); break; case 1: print_vec(std::get<1>(mp.thickness)); break; } ost <<"\n new_material: "; if(!mp.new_material) ost << "nullopt"; else { switch(mp.new_material->index()) { case 0: ost << std::get<0>(*mp.new_material); break; case 1: for (const auto & [key, value] : std::get<1>(*mp.new_material)) ost << key << " -> " << value << ", "; break; } } ost << "\n domain: "; switch(mp.domain.index()) { case 0: ost << std::get<0>(mp.domain); break; case 1: ost << std::get<1>(mp.domain); break; case 2: print_vec(std::get<2>(mp.domain)); break; } ost << "\n outside: " << mp.outside; ost << "\n project_boundaries: "; if(mp.project_boundaries) { auto & proj_bnd = *mp.project_boundaries; switch(proj_bnd.index()) { case 0: ost << std::get<0>(proj_bnd); break; case 1: print_vec(std::get<1>(proj_bnd)); break; } } else ost << "nullopt"; ost << "\n grow_edges: " << mp.grow_edges; ost << "\n limit_growth_vectors: " << mp.limit_growth_vectors; ost << "\n sides_keep_surfaceindex: " << (mp.sides_keep_surfaceindex ? ToString(*mp.sides_keep_surfaceindex) : "nullopt"); ost << "\n disable_curving: " << mp.disable_curving; ost << endl; return ost; } 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 << " meshsizefilename = " << meshsizefilename << endl << " 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 << "closeedge enabled = " << closeedgefac.has_value() << endl << "closeedgefac = " << closeedgefac.value_or(0.) << 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(meshsizefilename), other.meshsizefilename); //const_cast(meshsizefilename) = other.meshsizefilename; //??? 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; write_mesh_on_error = getenv("NG_WRITE_MESH_ON_ERROR"); }; } ================================================ FILE: libsrc/meshing/meshtype.hpp ================================================ #ifndef MESHTYPE #define MESHTYPE /**************************************************************************/ /* File: meshtype.hpp */ /* Author: Joachim Schoeberl */ /* Date: 01. Okt. 95 */ /**************************************************************************/ #include #include #include #include #include #include #include "core/exception.hpp" #include "msghandler.hpp" namespace netgen { /* Classes for NETGEN */ enum ELEMENT_TYPE : unsigned char { SEGMENT = 1, SEGMENT3 = 2, TRIG = 10, QUAD=11, TRIG6 = 12, QUAD6 = 13, QUAD8 = 14, TET = 20, TET10 = 21, PYRAMID = 22, PRISM = 23, PRISM12 = 24, PRISM15 = 27, PYRAMID13 = 28, HEX = 25, HEX20 = 26, HEX7 = 29 }; using ELEMENT_EDGE = std::array; using ELEMENT_FACE = std::array; #define ELEMENT_MAXPOINTS 20 #define ELEMENT2D_MAXPOINTS 8 enum POINTTYPE : unsigned char { 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 size_t timestamp; inline size_t GetTimeStamp() { return timestamp; } inline size_t NextTimeStamp() { timestamp++; return timestamp; } class PointGeomInfo { public: int trignum; // for STL Meshing double u, v; // for OCC Meshing PointGeomInfo () = default; PointGeomInfo (const PointGeomInfo&) = default; PointGeomInfo (PointGeomInfo &&) = default; PointGeomInfo & operator= (const PointGeomInfo&) = default; PointGeomInfo & operator= (PointGeomInfo&&) = default; }; 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); } class MultiPointGeomInfo { ArrayMem mgi; public: int AddPointGeomInfo (const PointGeomInfo & gi); void Init () { mgi.SetSize(0); } void DeleteAll () { mgi.SetSize(0); } int GetNPGI () const { return mgi.Size(); } const PointGeomInfo & GetPGI (int i) const { return mgi[i-1]; } MultiPointGeomInfo () = default; MultiPointGeomInfo (const MultiPointGeomInfo&) = default; MultiPointGeomInfo (MultiPointGeomInfo &&) = default; MultiPointGeomInfo & operator= (const MultiPointGeomInfo&) = delete; MultiPointGeomInfo & operator= (MultiPointGeomInfo&&) = default; }; class EdgePointGeomInfo { public: int edgenr; int body; // for ACIS double dist; // for 2d meshing double u, v; // for OCC Meshing public: EdgePointGeomInfo () : edgenr(-1), body(0), dist(0.0), u(0.0), v(0.0) { ; } EdgePointGeomInfo (const EdgePointGeomInfo&) = default; EdgePointGeomInfo & operator= (const EdgePointGeomInfo & gi2) = default; }; inline ostream & operator<< (ostream & ost, const EdgePointGeomInfo & gi) { ost << "epgi: edgnr=" << gi.edgenr << ", dist=" << gi.dist; return ost; } template class Index { public: T i; static constexpr int BASE = BASE_; static constexpr TIndex Base() { return TIndex(BASE_); } class t_invalid { public: constexpr t_invalid() = default; }; static constexpr t_invalid INVALID{}; typedef decltype( declval()-declval() ) T_diff; public: constexpr Index () = default; constexpr Index (const Index& i2) = default; constexpr Index (Index &&) = default; Index & operator= (const Index&) = default; Index & operator= (Index&&) = default; // private: constexpr Index (T ai) : i(ai) { #ifdef DEBUG if (ai < BASE_) cout << "illegal Index, use Index::INVALID instead" << endl; #endif } /* // didn't manage constexpr friend functions so far ??? friend auto operator+ (Index, int) -> TIndex; friend TIndex operator+ (Index, size_t); friend TIndex operator+ (int, Index); friend TIndex operator+ (size_t, Index); friend constexpr TIndex operator- (Index, int); friend int operator- (Index, Index); friend bool operator< (Index a, Index b); friend bool operator> (Index a, Index b); friend bool operator>= (Index a, Index b); friend bool operator<= (Index a, Index b); friend bool operator== (Index a, Index b); friend bool operator!= (Index a, Index b); */ public: constexpr Index (t_invalid inv) : i(long(BASE)-1) { ; } // protected: constexpr operator T () const { return i; } explicit constexpr operator T& () { return i; } public: TIndex operator++ (int) { TIndex hi{*this}; i++; return hi; } TIndex operator-- (int) { TIndex hi(*this); i--; return hi; } TIndex & operator++ () { i++; return static_cast(*this); } TIndex & operator-- () { i--; return static_cast(*this); } /* constexpr TIndex operator+= (int add) { i += add; return TIndex{*this}; } constexpr TIndex operator+= (size_t add) { i += add; return TIndex{*this}; } constexpr TIndex operator-= (int add) { i -= add; return TIndex{*this}; } constexpr TIndex operator-= (size_t add) { i -= add; return TIndex{*this}; } */ constexpr TIndex operator+= (T_diff add) { i += add; return TIndex{*this}; } constexpr TIndex operator-= (T_diff add) { i -= add; return TIndex{*this}; } constexpr auto operator- (Index i2) const { return i-i2.i; } // bool operator== (Index i2) const { return i==i2.i; } // bool operator!= (Index i2) const { return i!=i2.i; } void Invalidate() { i = long(TIndex::BASE)-1; } bool IsValid() const { return i+1 != TIndex::BASE; } // operator bool() const { return IsValid(); } void DoArchive (Archive & ar) { ar & i; } }; template constexpr auto operator+ (Index ind, int i) { Index res(ind); return res += i; } template constexpr auto operator+ (Index ind, size_t i) { Index res(ind); return res += i; } template constexpr TIndex operator+ (int i, Index ind) { return ind+i; } // Indexx res(ind); return res += i; template inline TIndex operator+ (size_t i, Index ind) { return ind+i; } // TIndex res(ind); res += i; return res; } template constexpr inline auto operator- (Index ind, int i) { Index res(ind); return res -= i; } // template // constexpr inline auto operator- (Index pa, Index pb) { return pa.i-pb.i; } template inline bool operator< (Index a, Index b) { return a-b < 0; } template inline bool operator> (Index a, Index b) { return a-b > 0; } template inline bool operator>= (Index a, Index b) { return a-b >= 0; } template inline bool operator<= (Index a, Index b) { return a-b <= 0; } template inline bool operator== (Index a, Index b) { return a.i == b.i; } template inline bool operator!= (Index a, Index b) { return a.i != b.i; } template inline void SetInvalid (Index & id) { id.Invalidate(); } template inline bool IsInvalid (const Index & id) { return !id.IsValid(); } class PointIndex : public Index { public: using Index::Index; template friend class PointIndices; }; } namespace ngcore { template<> constexpr netgen::PointIndex IndexBASE () { return netgen::PointIndex::Base(); } } namespace netgen { // input-output is 1-based inline istream & operator>> (istream & ist, PointIndex & pi) { // int i; ist >> i; pi = PointIndex(i); return ist; int i; ist >> i; pi = IndexBASE()+i-1; return ist; } inline ostream & operator<< (ostream & ost, const PointIndex & pi) { // return (ost << int(pi)); int intpi = pi - IndexBASE() + 1; return (ost << intpi); } /* PointIndices<2> etc are derived from historic INDEX_2 etc to be useable in old HASHTABLEs. Will change to IVec<2> or std::array when INDEX_2 is not needed anymore */ template class PointIndices; template <> class PointIndices<2> : public INDEX_2 { public: PointIndices () = default; constexpr PointIndices (const PointIndices&) = default; constexpr PointIndices (PointIndices&&) = default; PointIndices & operator= (const PointIndices&) = default; PointIndices & operator= (PointIndices&&) = default; constexpr PointIndices (INDEX_2 i2) : INDEX_2(i2) { ; } constexpr PointIndices (PointIndex i1, PointIndex i2) : INDEX_2(i1,i2) { ; } constexpr PointIndex operator[] (int i) const { return PointIndex(INDEX_2::operator[](i)); } PointIndex & operator[] (int i) { return reinterpret_cast(INDEX_2::operator[](i)); } template void DoArchive(ARCHIVE& ar) { ar.Do(&I1(), 2); } PointIndex & I1 () { return (*this)[0]; } PointIndex & I2 () { return (*this)[1]; } PointIndex I1 () const { return (*this)[0]; } PointIndex I2 () const { return (*this)[1]; } using INDEX_2::Sort; static PointIndices Sort(PointIndex i1, PointIndex i2) { return INDEX_2::Sort(i1, i2); } template PointIndex get() const { return PointIndex(INDEX_2::operator[](J)); } }; template <> class PointIndices<3> : public INDEX_3 { public: PointIndices () = default; PointIndices (const PointIndices&) = default; PointIndices (PointIndices&&) = default; PointIndices & operator= (const PointIndices&) = default; PointIndices & operator= (PointIndices&&) = default; constexpr PointIndices (INDEX_3 i3) : INDEX_3(i3) { ; } constexpr PointIndices (PointIndex i1, PointIndex i2, PointIndex i3) : INDEX_3(i1,i2,i3) { ; } PointIndex operator[] (int i) const { return PointIndex(INDEX_3::operator[](i)); } PointIndex & operator[] (int i) { return reinterpret_cast(INDEX_3::operator[](i)); } template void DoArchive(ARCHIVE& ar) { ar.Do(&I1(), 3); } PointIndex & I1 () { return (*this)[0]; } PointIndex & I2 () { return (*this)[1]; } PointIndex & I3 () { return (*this)[2]; } PointIndex I1 () const { return (*this)[0]; } PointIndex I2 () const { return (*this)[1]; } PointIndex I3 () const { return (*this)[2]; } using INDEX_3::Sort; static PointIndices Sort(PointIndex i1, PointIndex i2, PointIndex i3) { return INDEX_3::Sort(i1, i2, i3); } template PointIndex get() const { return PointIndex(INDEX_3::operator[](J)); } }; template <> class PointIndices<4> : public INDEX_4 { public: PointIndices () = default; PointIndices (INDEX_4 i4) : INDEX_4(i4) { ; } PointIndices (PointIndex i1, PointIndex i2, PointIndex i3, PointIndex i4) : INDEX_4(i1,i2,i3,i4) { ; } PointIndex operator[] (int i) const { return PointIndex(INDEX_4::operator[](i)); } PointIndex & operator[] (int i) { return reinterpret_cast(INDEX_4::operator[](i)); } template void DoArchive(ARCHIVE& ar) { ar.Do(&I1(), 4); } PointIndex & I1 () { return (*this)[0]; } PointIndex & I2 () { return (*this)[1]; } PointIndex & I3 () { return (*this)[2]; } PointIndex & I4 () { return (*this)[3]; } PointIndex I1 () const { return (*this)[0]; } PointIndex I2 () const { return (*this)[1]; } PointIndex I3 () const { return (*this)[2]; } PointIndex I4 () const { return (*this)[3]; } using INDEX_4::Sort; // static PointIndices Sort(PointIndex i1, PointIndex i2, PointIndex i3, PointIndex i4) { return INDEX_4::Sort(i1, i2, i3, i4); } template PointIndex get() const { return PointIndex(INDEX_4::operator[](J)); } }; template class SortedPointIndices : public PointIndices { using PointIndices::Sort; public: constexpr SortedPointIndices (PointIndices pnts) : PointIndices(pnts.Sort()) { } template constexpr SortedPointIndices (Pnts ...pnts) : PointIndices(pnts...) { Sort(); } }; } namespace ngcore { template <> struct CHT_trait { constexpr static inline netgen::PointIndex Invalid() { return netgen::PointIndex::INVALID; } constexpr static inline size_t HashValue (const netgen::PointIndex & hash, size_t mask) { return (hash-IndexBASE()) & mask; } }; template <> struct CHT_trait> { constexpr static inline netgen::PointIndices<2> Invalid() { return { netgen::PointIndex::INVALID, netgen::PointIndex::INVALID} ; } constexpr static inline size_t HashValue (const netgen::PointIndices<2> & hash, size_t mask) { return HashValue2(IVec<2>(hash[0]-IndexBASE(), hash[1]-IndexBASE()), mask); } }; template <> struct CHT_trait> { constexpr static inline netgen::SortedPointIndices<2> Invalid() { return { netgen::PointIndex::INVALID, netgen::PointIndex::INVALID} ; } constexpr static inline size_t HashValue (const netgen::SortedPointIndices<2> & hash, size_t mask) // { return HashValue2(IVec<2,netgen::INDEX>(hash[0], hash[1]), mask); } { return CHT_trait>::HashValue (hash, mask); } }; template <> constexpr inline netgen::PointIndices<3> InvalidHash> () { return netgen::PointIndices<3>{netgen::PointIndex::INVALID, netgen::PointIndex::INVALID, netgen::PointIndex::INVALID}; } /* template <> constexpr inline netgen::SortedPointIndices<2> InvalidHash> () // { return InvalidHash>(); } { return CHT_trait>::Invalid(); } */ } namespace std { // structured binding support template struct tuple_size> : std::integral_constant {}; template struct tuple_element> { using type = netgen::PointIndex; }; } namespace netgen { class ElementIndex : public Index { public: using Index::Index; // ::Index; }; inline istream & operator>> (istream & ist, ElementIndex & ei) { int i; ist >> i; ei = ElementIndex::Base()+i; return ist; } inline ostream & operator<< (ostream & ost, const ElementIndex & ei) { return ost << int(ei-ElementIndex::Base()); } /* // these should not be needed soon inline bool operator== (Index ei1, int ei2) { return int(ei1) == int(ei2); }; inline bool operator< (size_t s, Index ei2) { return int(s) < int(ei2); }; inline bool operator< ( Index ei1, size_t s) { return int(ei1) < int(s); }; // should not need inline bool operator< ( Index ei1, int s) { return int(ei1) < int(s); }; // should not need inline bool operator>= (size_t s, Index ei2) { return int(s) >= int(ei2); }; */ class SurfaceElementIndex : public Index { public: using Index::Index; }; // these should not be needed soon /* inline bool operator== (Index ei1, int ei2) { return int(ei1) == int(ei2); }; inline bool operator== (int ei2, Index ei1) { return int(ei1) == int(ei2); }; inline bool operator!= (Index ei1, int ei2) { return int(ei1) != int(ei2); }; inline bool operator< (size_t s, Index ei2) { return int(s) < int(ei2); }; inline bool operator< (Index ei1, size_t s) { return int(ei1) < int(s); }; // should not need inline bool operator< (Index ei1, int s) { return int(ei1) < int(s); }; // should not need inline bool operator>= (size_t s, Index ei2) { return int(s) >= int(ei2); }; inline bool operator>= (Index ei1, int s) { return int(ei1) >= int(s); }; */ // inline void SetInvalid (SurfaceElementIndex & id) { id.Invalidate(); } // inline bool IsInvalid (SurfaceElementIndex & id) { return !id.IsValid(); } inline istream & operator>> (istream & ist, SurfaceElementIndex & pi) { int i; ist >> i; pi = i; return ist; } inline ostream & operator<< (ostream & ost, const SurfaceElementIndex & si) { return ost << (si-IndexBASE(si)); } class SegmentIndex : public Index { public: using Index::Index; }; // these should not be needed soon /* inline bool operator== (Index ei1, int ei2) { return int(ei1) == int(ei2); }; inline bool operator< (size_t s, Index ei2) { return int(s) < int(ei2); }; inline bool operator< (Index ei1, size_t s) { return int(ei1) < int(s); }; inline bool operator< (Index ei1, int s) { return int(ei1) < int(s); }; */ // inline void SetInvalid (SegmentIndex & id) { id = -1; } // inline bool IsInvalid (SegmentIndex & id) { return id == -1; } inline istream & operator>> (istream & ist, SegmentIndex & pi) { int i; ist >> i; pi = i; return ist; } inline ostream & operator<< (ostream & ost, const SegmentIndex & si) { return ost << (si - IndexBASE(si)); } /** Point in the mesh. Contains layer (a new feature in 4.3 for overlapping meshes. */ class MeshPoint : public Point<3> { double singular; // singular factor for hp-refinement int layer; POINTTYPE type; public: MeshPoint () { ; } MeshPoint (const Point<3> & ap, int alayer = 1, POINTTYPE apt = INNERPOINT) : Point<3> (ap), singular(0.), layer(alayer), type(apt) { ; } void SetPoint (const Point<3> & ap) { Point<3>::operator= (ap); layer = 0; singular = 0; } void Scale(double factor) { *testout << "before: " << x[0] << endl; x[0] *= factor; x[1] *= factor; x[2] *= factor; *testout << "after: " << x[0] << endl;} 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 static NG_MPI_Datatype MyGetMPIType ( ); #endif void DoArchive (Archive & ar) { // ar & x[0] & x[1] & x[2] & layer & singular; // ar.Do(&x[0], 3); // ar & layer & singular; // ar & (unsigned char&)(type); ar.DoPacked (x[0], x[1], x[2], layer, singular, (unsigned char&)(type)); } }; inline ostream & operator<<(ostream & s, const MeshPoint & pt) { return (s << Point<3> (pt)); } typedef Array 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; /// ELEMENT_TYPE typ; /// number of points int8_t np; bool refflag; // marked for refinement bool badel:1; 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 bool is_curved; // element is (high order) curved int8_t newest_vertex = -1; // from refinement via bisection /// order for hp-FEM unsigned int orderx:6; unsigned int ordery:6; /// a linked list for all elements in the same face SurfaceElementIndex next; /// int hp_elnr; public: static auto GetDataLayout() { return std::map({ { "pnum", offsetof(Element2d, pnum)}, { "index", offsetof(Element2d, index) }, { "np", offsetof(Element2d, np) }, { "refine", offsetof(Element2d, refflag) }, { "curved", offsetof(Element2d, is_curved)} }); } /// DLL_HEADER Element2d (); Element2d (const Element2d &) = default; Element2d (Element2d &&) = default; Element2d & operator= (const Element2d &) = default; Element2d & operator= (Element2d &&) = default; Element2d & operator= (initializer_list list) { size_t cnt = 0; for (auto val : list) pnum[cnt++] = val; return *this; } Element2d & operator= (initializer_list> list) { size_t cnt = 0; for (auto val : list) { pnum[cnt] = get<0>(val); geominfo[cnt++] = get<1>(val); } return *this; } /// DLL_HEADER Element2d (int anp); /// DLL_HEADER Element2d (ELEMENT_TYPE type); /// DLL_HEADER Element2d (PointIndex pi1, PointIndex pi2, PointIndex pi3); /// DLL_HEADER Element2d (PointIndex pi1, PointIndex pi2, PointIndex pi3, PointIndex 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 ", int(typ)); } is_curved = (np >= 4); } /// int GetNP() const { return np; } /// int GetNV() const { if (typ == TRIG || typ == TRIG6) return 3; else { #ifdef DEBUG if (typ != QUAD && typ != QUAD6 && typ != QUAD8) PrintSysError ("element2d::GetNV not implemented for typ", int(typ)); #endif return 4; } /* 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]; } auto PNums () const { return FlatArray (np, &pnum[0]); } auto PNums () { return FlatArray (np, &pnum[0]); } template auto PNums() const { return FlatArray (NP, &pnum[0]); } auto Vertices() const { return FlatArray (GetNV(), &pnum[0]); } auto GeomInfo() const { return FlatArray (np, &geominfo[0]); } auto GeomInfo() { return FlatArray (np, &geominfo[0]); } /// 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]; } auto & NewestVertex() { return newest_vertex; } auto NewestVertex() const { return newest_vertex; } void DoArchive (Archive & ar) { short _np, _typ; bool _curved, _vis, _deleted; if (ar.Output()) { _np = np; _typ = typ; _curved = is_curved; _vis = visible; _deleted = deleted; } // ar & _np & _typ & index & _curved & _vis & _deleted; ar.DoPacked (_np, _typ, index, _curved, _vis, _deleted); // ar & next; don't need if (ar.Input()) { np = _np; typ = ELEMENT_TYPE(_typ); is_curved = _curved; visible = _vis; deleted = _deleted; } /* for (size_t i = 0; i < np; i++) ar & pnum[i]; */ static_assert(sizeof(int) == sizeof (PointIndex)); ar.Do( (int*)&pnum[0], np); } #ifdef PARALLEL static NG_MPI_Datatype MyGetMPIType(); #endif 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;} int GetHpElnr() const { return hp_elnr; } void SetHpElnr(int _hp_elnr) { hp_elnr = _hp_elnr; } /// void GetBox (const T_POINTS & points, Box3d & box) const; /// invert orientation inline void Invert (); /// DLL_HEADER 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, Point<2> & p, double & weight) const; void GetTransformation (int ip, const NgArray> & points, class DenseMatrix & trans) const; void GetTransformation (int ip, class DenseMatrix & pmat, class DenseMatrix & trans) const; void GetShape (const Point<2> & p, class Vector & shape) const; DLL_HEADER void GetShapeNew (const Point<2> & p, class FlatVector & shape) const; template DLL_HEADER void GetShapeNew (const Point<2,T> & p, TFlatVector shape) const; /// matrix 2 * np DLL_HEADER void GetDShape (const Point<2> & p, class DenseMatrix & dshape) const; template DLL_HEADER void GetDShapeNew (const Point<2,T> & p, class MatrixFixWidth<2,T> & dshape) const; /// matrix 2 * np void GetPointMatrix (const NgArray> & points, class DenseMatrix & pmat) const; void ComputeIntegrationPointData () const; double CalcJacobianBadness (const NgArray> & points) const; double CalcJacobianBadness (const T_POINTS & points, const Vec<3> & n) const; double CalcJacobianBadnessDirDeriv (const NgArray> & points, int pi, Vec<2> & dir, double & dd) const; void Delete () { deleted = true; // for (PointIndex & p : pnum) p.Invalidate(); } bool IsDeleted () const { #ifdef DEBUG if ((pnum[0]-IndexBASE() < 0) && !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 = true) { visible = vis; } bool IsVisible () const { return visible; } void SetRefinementFlag (bool rflag = true) { refflag = rflag; } bool TestRefinementFlag () const { return refflag; } void SetStrongRefinementFlag (bool rflag = true) { strongrefflag = rflag; } bool TestStrongRefinementFlag () const { return strongrefflag; } bool IsCurved () const { return is_curved; } void SetCurved (bool acurved) { is_curved = acurved; } SurfaceElementIndex NextElement() { return next; } bool operator==(const Element2d & el2) const; int HasFace(const Element2d& el) const; }; DLL_HEADER 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; /// number of points (4..tet, 5..pyramid, 6..prism, 8..hex, 10..quad tet, 12..quad prism) int8_t np; int8_t newest_vertex = -1; // from refinement via bisection /// sub-domain index 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; bool is_curved; // element is (high order) curved class flagstruct { public: bool refflag; // mark element for refinement 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 swapped bool illegal_valid:1; // is illegal-flag valid ? bool badness_valid:1; // is badness valid ? bool strongrefflag:1; bool deleted:1; // element is deleted, will be removed from array bool fixed:1; // don't change element in optimization }; flagstruct flags; int hp_elnr; public: static auto GetDataLayout() { return std::map({ { "pnum", offsetof(Element, pnum)}, { "index", offsetof(Element, index) }, { "np", offsetof(Element, np) }, { "refine", offsetof(Element, flags.refflag) }, { "curved", offsetof(Element, is_curved)} }); } /// DLL_HEADER Element () = default; Element (const Element &) = default; Element (Element &&) = default; Element & operator= (const Element &) = default; Element & operator= (Element &&) = default; /// DLL_HEADER Element (int anp); /// DLL_HEADER Element (ELEMENT_TYPE type); /// // Element & operator= (const Element & el2); const flagstruct& Flags() const { return flags; } flagstruct& Flags() { return flags; } /// DLL_HEADER void SetNP (int anp); /// DLL_HEADER void SetType (ELEMENT_TYPE atyp); /// int GetNP () const { return np; } /// uint8_t GetNV() const { // __assume(typ >= TET && typ <= PYRAMID13); switch (typ) { case TET: case TET10: return 4; case PRISM12: case PRISM15: case PRISM: return 6; case PYRAMID: case PYRAMID13: return 5; case HEX7: return 7; case HEX: case HEX20: return 8; default: // not a 3D element #ifdef DEBUG PrintSysError ("Element3d::GetNV not implemented for typ ", int(typ)); #endif __assume(false); return -1; } } DLL_HEADER 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]; } auto PNums () const { return FlatArray (np, &pnum[0]); } auto PNums () { return FlatArray (np, &pnum[0]); } template auto PNums() const { return FlatArray (NP, &pnum[0]); } FlatArray Vertices() const { return { GetNV(), &pnum[0] }; } /// 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]; } auto & NewestVertex() { return newest_vertex; } auto NewestVertex() const { return newest_vertex; } void DoArchive (Archive & ar) { short _np, _typ; bool _curved; if (ar.Output()) { _np = np; _typ = typ; _curved = is_curved; } // ar & _np & _typ & index & _curved; ar.DoPacked (_np, _typ, index, _curved); if (ar.Input()) { np = _np; typ = ELEMENT_TYPE(_typ); is_curved = _curved; 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; } static_assert(sizeof(int) == sizeof (PointIndex)); ar.Do( (int*)&pnum[0], np); } #ifdef PARALLEL static NG_MPI_Datatype MyGetMPIType(); #endif /// 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 element double Volume (const T_POINTS & points) const; /// DLL_HEADER void Print (ostream & ost) const; /// int GetNFaces () const { switch (typ) { case TET: case TET10: return 4; case PYRAMID: case PYRAMID13: return 5; case PRISM: case PRISM15: case PRISM12: return 5; case HEX7: return 6; case HEX: case HEX20: return 6; default: #ifdef DEBUG PrintSysError ("element3d::GetNFaces not implemented for typ", int(typ)) #endif ; } return 0; } /// inline void GetFace (int i, Element2d & face) const; /// DLL_HEADER void GetFace2 (int i, Element2d & face) const; /// DLL_HEADER void Invert (); int GetHpElnr() const { return hp_elnr; } void SetHpElnr(int _hp_elnr) { hp_elnr = _hp_elnr; } /// split into 4 node tets void GetTets (NgArray & locels) const; /// split into 4 node tets, local point nrs void GetTetsLocal (NgArray & locels) const; /// returns coordinates of nodes // void GetNodesLocal (NgArray > & points) const; void GetNodesLocalNew (NgArray > & points) const; /// split surface into 3 node trigs DLL_HEADER void GetSurfaceTriangles (NgArray & 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; template DLL_HEADER void GetShapeNew (const Point<3,T> & p, TFlatVector shape) const; /// matrix 2 * np void GetDShape (const Point<3> & p, class DenseMatrix & dshape) const; template void GetDShapeNew (const Point<3,T> & p, class MatrixFixWidth<3,T> & 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 { NETGEN_CHECK_SAME(flags.illegal_valid, true); 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; } bool BadnessValid() { return flags.badness_valid; } float GetBadness() { NETGEN_CHECK_SAME(flags.badness_valid, true); return badness; } void SetBadness(float value) { badness = value; flags.badness_valid = 1; } void Touch() { flags.illegal_valid = 0; flags.badness_valid = 0; } void Delete () { flags.deleted = 1; } bool IsDeleted () const { #ifdef DEBUG if (pnum[0]-IndexBASE() < 0 && !flags.deleted) cerr << "Volelement has illegal pnum, but not marked as deleted" << endl; #endif return flags.deleted; } bool IsCurved () const { return is_curved; } void SetCurved (bool acurved) { is_curved = acurved; } }; ostream & operator<<(ostream & s, const Element & el); /** Edge segment. How indices are used up to 2026-03-29 edgenr: OCC: the geometry edge, 1-based Spline2D: edge-nr, 1-based CSG: edge counter si: CSG: one surface of the edge Spline2d: bc-number OCC: edgenr, 1-based cd2i: ???? epgeominfo: OCC: geometry edgenr, 0-based Spline2D: edgenr, 1-based NGSoleve Interface: GetIndex mesh.dim == 3 -> edgenr mesh.dim == 2 -> si Python interface: edgenr -> segmnr index -> si Python ctor: index -> si, segmnr edgenr -> epgeominfo DECREMENT 1 NEW from 2026-03-29 GetEdgeNr() -> the geometry edge GetIndex() -> the index for boundary conditions */ class Segment { public: /// DLL_HEADER Segment(); Segment (const Segment& other) = default; // 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; /// co dim 2 decoding index // int cd2i /// index for boundary conditions (1-based) int index; /// 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; bool is_curved; int hp_elnr; /* PointIndex operator[] (int i) const { return (i == 0) ? p1 : p2; } PointIndex & operator[] (int i) { return (i == 0) ? p1 : p2; } */ Segment& operator=(const Segment & other) = default; int GetNP() const { return pnums[2].IsValid() ? 3 : 2; } auto PNums() const { return FlatArray (GetNP(), &pnums[0]); } auto PNums() { return FlatArray (GetNP(), &pnums[0]); } auto Vertices() const { return FlatArray (2, &pnums[0]); } ELEMENT_TYPE GetType() const { return pnums[2].IsValid() ? SEGMENT3 : SEGMENT; } PointIndex & operator[] (int i) { return pnums[i]; } const PointIndex & operator[] (int i) const { return pnums[i]; } bool IsCurved () const { return is_curved; } void SetCurved (bool acurved) { is_curved = acurved; } int GetEdgeNr() const { return epgeominfo[0].edgenr; } // 0 or 1-based (geometry dependent) void SetEdgeNr (int nr) { epgeominfo[0].edgenr=nr; } int GetIndex() const { return index; } // 1-based void SetIndex (int i) { index=i; } // 1-based void DoArchive (Archive & ar); #ifdef PARALLEL static NG_MPI_Datatype MyGetMPIType(); #endif }; ostream & operator<<(ostream & s, const Segment & seg); class Element0d { public: PointIndex pnum; string name; int index; Element0d () = default; Element0d (PointIndex _pnum, int _index) : pnum(_pnum), index(_index) { ; } #ifdef PARALLEL static NG_MPI_Datatype MyGetMPIType(); #endif void DoArchive (Archive & ar); }; ostream & operator<<(ostream & s, const Element0d & el); // 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) Vec<4> surfcolour; /// // static string default_bcname; // string * bcname = &default_bcname; string bcname = "default"; /// 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 Vec<4> SurfColour () const { return surfcolour; } /* DLL_HEADER */ const string & GetBCName () const { return bcname; } // 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; } DLL_HEADER void SetBCName (string * bcn); // { bcname = bcn; } void SetBCName (const string & bcn) { bcname = bcn; } // Philippose - 06/07/2009 // Set the surface colour void SetSurfColour (Vec<4> 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; void DoArchive (Archive & ar); }; 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; } }; struct BoundaryLayerParameters { std::variant> thickness; std::variant> domain; std::variant> boundary = ".*"; std::optional>> new_material = nullopt; std::optional>> project_boundaries = nullopt; bool outside = false; bool grow_edges = true; bool limit_growth_vectors = false; // automatic reduction of layer thickness to avoid intersections std::optional sides_keep_surfaceindex = nullopt; // !outside by default bool disable_curving = true; // disable curving affected boundaries/edges (could lead to self-intersecting volume elements) }; ostream & operator<< (ostream & ost, const BoundaryLayerParameters & mp); 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 // D .. divide and join opposite edges, remove element // p .. plot, no pause // P .. plot, Pause // h .. Histogramm, no pause // H .. Histogramm, pause */ string optimize3d = "cmdDmustm"; /// number of 3d optimization steps int optsteps3d = 3; /** 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 **/ string optimize2d = "smcmSmcmSmcm"; /// number of 2d optimization steps int optsteps2d = 3; /// power of error (to approximate max err optimization) double opterrpow = 2; /// do block filling ? bool blockfill = true; /// block filling up to distance double filldist = 0.1; /// radius of local environment (times h) double safety = 5; /// radius of active environment (times h) double relinnersafety = 3; /// use local h ? bool uselocalh = true; /// grading for local h double grading = 0.3; /// use delaunay for 3d meshing bool delaunay = true; /// use delaunay for 2d meshing bool delaunay2d = false; /// maximal mesh size double maxh = 1e10; /// minimal mesh size double minh = 0.0; /// file for meshsize string meshsizefilename = ""; /// restrict h based on close edges optional closeedgefac = nullopt; /// start surfacemeshing from everywhere in surface bool startinsurface = false; /// check overlapping surfaces (debug) bool checkoverlap = true; /// check overlapping surface mesh before volume meshing bool checkoverlappingboundary = true; /// check chart boundary (sometimes too restrictive) bool checkchartboundary = true; /// safety factor for curvatures (elements per radius) double curvaturesafety = 2; /// minimal number of segments per edge double segmentsperedge = 1; /// use parallel threads bool parthread = 0; /// weight of element size w.r.t element shape double elsizeweight = 0.2; /// init with default values /// start at step int perfstepsstart = 0; /// end at step int perfstepsend = 6; /// from mp3: /// give up quality class, 2d meshing int giveuptol2d = 200; /// give up quality class, 3d meshing int giveuptol = 10; /// give up quality class for closing open quads, > 100 for /// free pyramids int giveuptolopenquads = 15; /// maximal outer steps int maxoutersteps = 10; /// class starting star-shape filling int starshapeclass = 5; /// if non-zero, baseelement must have baseelnp points int baseelnp = 0; /// quality tolerances are handled less careful int sloppy = 1; /// limit for max element angle (150-180) double badellimit = 175; bool check_impossible = false; int only3D_domain_nr = 0; /// bool secondorder = false; /// high order element curvature int elementorder = 1; /// quad-dominated surface meshing bool quad = false; /// bool try_hexes = false; /// bool inverttets = false; /// bool inverttrigs = false; /// bool autozrefine = false; bool parallel_meshing = true; int nthreads = 4; Flags geometrySpecificParameters; Array boundary_layers; /// MeshingParameters (); /// MeshingParameters (const MeshingParameters & mp2) = default; MeshingParameters (MeshingParameters && mp2) = default; MeshingParameters & operator= (const MeshingParameters & mp2) = default; MeshingParameters & operator= (MeshingParameters && mp2) = default; /// void Print (ostream & ost) const; /// // void CopyFrom(const MeshingParameters & other); class MeshSizePoint { public: Point<3> pnt; double h; int layer = 1; MeshSizePoint (Point<3> pnt_, double h_, int layer_ = 1) : pnt(pnt_), h(h_), layer(layer_) { ; } MeshSizePoint () = default; MeshSizePoint (const MeshSizePoint &) = default; MeshSizePoint (MeshSizePoint &&) = default; MeshSizePoint & operator= (const MeshSizePoint &) = default; MeshSizePoint & operator= (MeshSizePoint &&) = default; }; NgArray meshsize_points; void (*render_function)(bool) = NULL; void Render(bool blocking = false) const { if (render_function) (*render_function)(blocking); } }; inline ostream & operator<< (ostream & ost, const MeshingParameters & mp) { mp.Print (ost); return ost; } class DebugParameters { public: /// int debugoutput; /// use slow checks int slowchecks; /// int haltsuccess; /// int haltnosuccess; /// int haltlargequalclass; /// int haltsegment; /// int haltnode; /// PointIndex haltsegmentp1; /// PointIndex haltsegmentp2; /// int haltexistingline; /// int haltoverlap; /// int haltface; /// int haltfacenr; /// bool write_mesh_on_error; /// 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); } // typedef NgArray idmap_type; typedef Array idmap_type; /** Identification of periodic surfaces, close surfaces, etc. */ class Identifications { public: enum ID_TYPE : unsigned char { UNDEFINED = 1, PERIODIC = 2, CLOSESURFACES = 3, CLOSEEDGES = 4}; private: class Mesh & mesh; /// identify points (thin layers, periodic b.c.) // INDEX_2_HASHTABLE identifiedpoints; ClosedHashTable, int> identifiedpoints; /// the same, with info about the id-nr // INDEX_3_HASHTABLE identifiedpoints_nr; ClosedHashTable, int>, int> identifiedpoints_nr; /// sorted by identification nr TABLE> idpoints_table; NgArray type; /// number of identifications (or, actually used identifications ?) int maxidentnr; Array names; public: /// DLL_HEADER Identifications (class Mesh & amesh); /// DLL_HEADER ~Identifications (); DLL_HEADER void Delete (); // Removes identifications if one point is an INNERPOINT DLL_HEADER void DeleteInnerPointIdentifications (); /* Identify points pi1 and pi2, due to identification nr identnr */ DLL_HEADER void Add (PointIndex pi1, PointIndex pi2, int identnr); void Add (PointIndex pi1, PointIndex pi2, string name, ID_TYPE type) { auto nr = GetNr(name); Add(pi1, pi2, nr); SetType(nr, type); } 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; // bool HasIdentifiedPoints() const { return identifiedpoints != nullptr; } /// auto & GetIdentifiedPoints () { return identifiedpoints_nr; } bool Used (PointIndex pi1, PointIndex pi2) { // return identifiedpoints.Used (INDEX_2 (pi1, pi2)); return identifiedpoints.Used (PointIndices<2>(pi1, pi2)); } bool UsedSymmetric (PointIndex pi1, PointIndex pi2) { return identifiedpoints.Used (PointIndices<2>(pi1, pi2)) || identifiedpoints.Used (PointIndices<2>(pi2, pi1)); } /// void GetMap (int identnr, idmap_type & 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; } /// DLL_HEADER void GetPairs (int identnr, NgArray & identpairs) const; DLL_HEADER Array GetPairs () const; /// int GetMaxNr () const { return maxidentnr; } int GetNr(string name) { if(!names.Contains(name)) names.Append(name); return names.Pos(name)+1; } string GetName(int nr) const { if (nr <= names.Size()) return names[nr - 1]; else return ""; } void SetName(int nr, string name) { while(names.Size() < nr) names.Append(""); names[nr-1] = name; } /// remove secondorder void SetMaxPointNr (int maxpnum); void MapPoints(FlatArray op2np); DLL_HEADER void Print (ostream & ost) const; void DoArchive (Archive & ar); }; } #ifdef PARALLEL namespace ngcore { template <> struct MPI_typetrait { static NG_MPI_Datatype MPIType () { return NG_MPI_INT; } }; template <> struct MPI_typetrait { static NG_MPI_Datatype MPIType () { return NG_MPI_CHAR; } }; template <> struct MPI_typetrait { static NG_MPI_Datatype MPIType () { return netgen::MeshPoint::MyGetMPIType(); } }; template <> struct MPI_typetrait { static NG_MPI_Datatype MPIType () { return netgen::Element::MyGetMPIType(); } }; template <> struct MPI_typetrait { static NG_MPI_Datatype MPIType () { return netgen::Element2d::MyGetMPIType(); } }; template <> struct MPI_typetrait { static NG_MPI_Datatype MPIType () { return netgen::Segment::MyGetMPIType(); } }; template <> struct MPI_typetrait { static NG_MPI_Datatype MPIType () { return netgen::Element0d::MyGetMPIType(); } }; } #endif #endif ================================================ FILE: libsrc/meshing/msghandler.cpp ================================================ //File for handling warnings, errors, messages #include namespace netgen { // int printmessage_importance = 3; 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) if (printmessage_importance >= 4) { 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")); } /* #ifdef SMALLLIB #define SMALLLIBORNOTCL #endif #ifdef NOTCL #define SMALLLIBORNOTCL #endif #ifdef SMALLLIBORNOTCL void Ng_PrintDest(const char * s){cout << s < 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=""); inline void PushStatusF(const std::string& s) { PushStatus (s); PrintFnStart(s); } } #endif ================================================ FILE: libsrc/meshing/netrule2.cpp ================================================ #include #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); auto& fzi = freezone_i[tolclass-1]; for (int i = 0; i < fzs; i++) { transfreezone[i][0] = fzi[i][0] + devfree[2*i]; transfreezone[i][1] = fzi[i][1] + 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][0] = lam1 * freezone[i][0] + lam2 * freezonelimit[i][0] + devfree[2*i]; transfreezone[i][1] = lam1 * freezone[i][1] + lam2 * freezonelimit[i][1] + devfree[2*i+1]; } } if (fzs > 0) { fzmaxx = fzminx = transfreezone[0][0]; fzmaxy = fzminy = transfreezone[0][1]; } for (int i = 1; i < fzs; i++) { if (transfreezone[i][0] > fzmaxx) fzmaxx = transfreezone[i][0]; if (transfreezone[i][0] < fzminx) fzminx = transfreezone[i][0]; if (transfreezone[i][1] > fzmaxy) fzmaxy = transfreezone[i][1]; if (transfreezone[i][1] < fzminy) fzminy = transfreezone[i][1]; } for (int i = 0; i < fzs; i++) { const auto& p1 = transfreezone[i]; const auto& p2 = transfreezone[(i+1) % fzs]; Vec<2> vn = { p2[1] - p1[1], p1[0] - p2[0] }; 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[0]; freesetinequ(i,1) = vn[1]; freesetinequ(i,2) = -(p1[0] * vn[0] + p1[1] * vn[1]); } } } /* 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[1] + freesetinequ(i, 2) > 0) return 0; } return 1; } */ int netrule :: IsLineInFreeZone2 (const Point<2> & p1, const Point<2> & p2) const { if ( (p1[0] > fzmaxx && p2[0] > fzmaxx) || (p1[0] < fzminx && p2[0] < fzminx) || (p1[1] > fzmaxy && p2[1] > fzmaxy) || (p1[1] < fzminy && p2[1] < fzminy) ) return 0; for (int i = 1; i <= transfreezone.Size(); i++) { if (freesetinequ.Get(i, 1) * p1[0] + freesetinequ.Get(i, 2) * p1[1] + freesetinequ.Get(i, 3) > -1e-8 && // -1e-6 freesetinequ.Get(i, 1) * p2[0] + freesetinequ.Get(i, 2) * p2[1] + freesetinequ.Get(i, 3) > -1e-8 // -1e-6 ) return 0; } double nx = (p2[1] - p1[1]); double ny = -(p2[0] - p1[0]); double nl = sqrt (nx * nx + ny * ny); if (nl > 1e-8) { nx /= nl; ny /= nl; double c = - (p1[0] * nx + p1[1] * ny); bool allleft = true; bool allright = true; for (int i = 1; i <= transfreezone.Size(); i++) { bool left = transfreezone.Get(i)[0] * nx + transfreezone.Get(i)[1] * ny + c < 1e-7; bool right = transfreezone.Get(i)[0] * nx + transfreezone.Get(i)[1] * ny + c > -1e-7; if (!left) allleft = false; if (!right) allright = false; } if (allleft || allright) return false; } return true; } 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 Vec<2> & v) const { float dx = v[0] - linevecs.Get(li)[0]; float dy = v[1] - linevecs.Get(li)[1]; const threefloat * ltf = &linetolerances.Get(li); return ltf->f1 * dx * dx + ltf->f2 * dx * dy + ltf->f3 * dy * dy; } } // namespace netgen ================================================ FILE: libsrc/meshing/netrule3.cpp ================================================ #include #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)); fzbox.IncreaseRel(1e-8); // MARK(setfz3); for (fs = 1; fs <= freesets.Size(); fs++) { NgArray & 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 NgArray & freeset = *freesets.Get(fs); const NgArray & freesetedges = *freeedges.Get(fs); // const NgArray & 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; NgArray & 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 NgArray & pi, int newone) { int fs; int infreeset, cannot = 0; NgArrayMem 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 NgArray & 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 NgArray & 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; NgArray activefaces; int isin; // MARK(triinfz); NgArray & 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; } NgArray 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); NgArray 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 NgArray & pi, int newone) { int fs; int infreeset, cannot = 0; NgArrayMem 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 NgArray & 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 NgArray & 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; } NgArrayMem 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 { NgArray cntpused(points.Size()); NgArray edge1, edge2; NgArray 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; } } ================================================ FILE: libsrc/meshing/parallelmesh.cpp ================================================ #ifdef PARALLEL #include #include "paralleltop.hpp" // #define METIS4 #ifdef METIS namespace metis { extern "C" { #include #if METIS_VER_MAJOR >= 5 #define METIS5 typedef idx_t idxtype; #else #define METIS4 typedef idxtype idx_t; #endif } } using namespace metis; #endif /* namespace ngcore { template <> struct MPI_typetrait { static MPI_Datatype MPIType () { return MPI_INT; } }; } */ namespace ngcore { /** An MPI-Package for a Surface element **/ class SurfPointPackage { public: int num; // point number int trignum; // STL geo info double u, v; // OCC geo info SurfPointPackage () { ; } SurfPointPackage & operator = (const SurfPointPackage & other) { num = other.num; trignum = other.trignum; u = other.u; v = other.v; return *this; } }; // class SurfPointPackage template<> struct MPI_typetrait { static NG_MPI_Datatype MPIType () { static NG_MPI_Datatype MPI_T = 0; if (!MPI_T) { int block_len[2] = { 2, 2 }; NG_MPI_Aint displs[3] = { 0, 2*sizeof(int) }; NG_MPI_Datatype types[2] = { NG_MPI_INT, NG_MPI_DOUBLE }; NG_MPI_Type_create_struct(2, block_len, displs, types, &MPI_T); NG_MPI_Type_commit(&MPI_T); } return MPI_T; } }; // struct MPI_typetrait class SelPackage { public: int sei; int index; int np; /** we send too much here, especially in 2d! **/ SurfPointPackage points[ELEMENT2D_MAXPOINTS]; SelPackage () { ; } SelPackage (const netgen::Mesh & mesh, netgen::SurfaceElementIndex _sei) { const netgen::Element2d & el = mesh[_sei]; sei = _sei; index = el.GetIndex(); np = el.GetNP(); for (int k : Range(1, np+1)) { auto & pnt = points[k-1];; pnt.num = el.PNum(k); pnt.trignum = el.GeomInfoPi(k).trignum; pnt.u = el.GeomInfoPi(k).u; pnt.v = el.GeomInfoPi(k).v; } /** otherwise, we use uninitialized values **/ for (int k : Range(np, ELEMENT2D_MAXPOINTS)) { points[k].num = -1; points[k].trignum = -1; points[k].u = -1; points[k].v = -1; } } void Unpack (netgen::Element2d & el) const { el.SetIndex(index); for (int k : Range(1, np + 1)) { auto & pnt = points[k-1]; el.PNum(k) = pnt.num; el.GeomInfoPi(k).trignum = pnt.trignum; el.GeomInfoPi(k).u = pnt.u; el.GeomInfoPi(k).v = pnt.v; } } SelPackage & operator = (const SelPackage & other) { sei = other.sei; index = other.index; np = other.np; for (int k : Range(ELEMENT2D_MAXPOINTS)) { points[k] = other.points[k]; } return *this; } }; // class SelPackage template<> struct MPI_typetrait { static NG_MPI_Datatype MPIType () { static NG_MPI_Datatype MPI_T = 0; if (!MPI_T) { int block_len[2] = { 3, ELEMENT2D_MAXPOINTS }; NG_MPI_Aint displs[3] = { 0, 3*sizeof(int) }; NG_MPI_Datatype types[2] = { NG_MPI_INT, GetMPIType() }; NG_MPI_Type_create_struct(2, block_len, displs, types, &MPI_T); NG_MPI_Type_commit(&MPI_T); } return MPI_T; } }; // MPI_typetrait class PointElPackage { public: netgen::PointIndex pnum; int index; PointElPackage () { pnum = -1; index = -1; } PointElPackage (const netgen::Element0d & el) { pnum = el.pnum; index = el.index; } }; // class PointElPackage template<> struct MPI_typetrait { static NG_MPI_Datatype MPIType () { static NG_MPI_Datatype MPI_T = 0; if (!MPI_T) { int block_len[2] = { 1, 1 }; NG_MPI_Aint displs[3] = { 0, sizeof(netgen::PointIndex) }; NG_MPI_Datatype types[2] = { GetMPIType(), NG_MPI_INT }; NG_MPI_Type_create_struct(2, block_len, displs, types, &MPI_T); NG_MPI_Type_commit(&MPI_T); } return MPI_T; } }; // MPI_typetrait } // namespace ngcore namespace netgen { /* template <> inline MPI_Datatype MyGetMPIType ( ) { return MPI_INT; } */ void Mesh :: SendRecvMesh () { int id = GetCommunicator().Rank(); int np = GetCommunicator().Size(); if (np == 1) { throw NgException("SendRecvMesh called, but only one rank in communicator!!"); } if (id == 0) PrintMessage (1, "Send/Receive mesh"); // Why is this here?? if (id == 0) { paralleltop -> SetNV (GetNV()); paralleltop -> SetNV_Loc2Glob (GetNV()); paralleltop -> SetNE (GetNE()); paralleltop -> SetNSegm (GetNSeg()); paralleltop -> SetNSE (GetNSE()); } if (id == 0) SendMesh (); else ReceiveParallelMesh(); paralleltop -> UpdateCoarseGrid(); } void Mesh :: SendMesh () const { static Timer tsend("SendMesh"); RegionTimer reg(tsend); static Timer tbuildvertex("SendMesh::BuildVertex"); static Timer tbuildvertexa("SendMesh::BuildVertex a"); static Timer tbuildvertexb("SendMesh::BuildVertex b"); static Timer tbuilddistpnums("SendMesh::Build_distpnums"); static Timer tbuildelementtable("SendMesh::Build_elementtable"); NgMPI_Comm comm = GetCommunicator(); // int id = comm.Rank(); int ntasks = comm.Size(); int dim = GetDimension(); comm.Bcast(dim); NgMPI_Requests sendrequests; // (8*(ntasks-1)); // sendrequests.SetSize0(); // If the topology is not already updated, we do not need to // build edges/faces. auto & top = const_cast(GetTopology()); if(top.NeedsUpdate()) { top.SetBuildVertex2Element(false); top.SetBuildEdges(false); top.SetBuildFaces(false); top.Update(); } PrintMessage ( 3, "Sending nr of elements"); Array num_els_on_proc(ntasks); num_els_on_proc = 0; for (ElementIndex ei = 0; ei < GetNE(); ei++) num_els_on_proc[vol_partition[ei]]++; comm.ScatterRoot (num_els_on_proc); Table els_of_proc (num_els_on_proc); num_els_on_proc = 0; for (ElementIndex ei = 0; ei < GetNE(); ei++) { auto nr = vol_partition[ei]; els_of_proc[nr][num_els_on_proc[nr]++] = ei; } PrintMessage ( 3, "Building vertex/proc mapping"); Array num_sels_on_proc(ntasks); num_sels_on_proc = 0; for (SurfaceElementIndex ei = 0; ei < GetNSE(); ei++) num_sels_on_proc[surf_partition[ei]]++; Table sels_of_proc (num_sels_on_proc); num_sels_on_proc = 0; for (SurfaceElementIndex ei = 0; ei < GetNSE(); ei++) { auto nr = surf_partition[ei]; sels_of_proc[nr][num_sels_on_proc[nr]++] = ei; } NgArray num_segs_on_proc(ntasks); num_segs_on_proc = 0; for (SegmentIndex ei = 0; ei < GetNSeg(); ei++) // num_segs_on_proc[(*this)[ei].GetPartition()]++; num_segs_on_proc[seg_partition[ei]]++; TABLE segs_of_proc (num_segs_on_proc); for (SegmentIndex ei = 0; ei < GetNSeg(); ei++) segs_of_proc.Add (seg_partition[ei], ei); /** ----- STRATEGY FOR PERIODIC MESHES ----- Whenever two vertices are identified by periodicity, any proc that gets one of the vertices actually gets both of them. This has to be transitive, that is, if a <-> b and b <-> c, then any proc that has vertex a also has vertices b and c! Surfaceelements and Segments that are identified by periodicity are treated the same way. We need to duplicate these so we have containers to hold the edges/facets. Afaik, a mesh cannot have nodes that are not part of some sort of element. **/ /** First, we build tables for vertex identification. **/ NgArray per_pairs; NgArray pp2; auto & idents = GetIdentifications(); bool has_periodic = false; for (int idnr = 1; idnr < idents.GetMaxNr()+1; idnr++) { if(idents.GetType(idnr)!=Identifications::PERIODIC) continue; has_periodic = true; idents.GetPairs(idnr, pp2); per_pairs.Append(pp2); } NgArray npvs(GetNV()); npvs = 0; for (int k = 0; k < per_pairs.Size(); k++) { npvs[per_pairs[k].I1()]++; npvs[per_pairs[k].I2()]++; } /** for each vertex, gives us all identified vertices **/ TABLE per_verts(npvs); for (int k = 0; k < per_pairs.Size(); k++) { per_verts.Add(per_pairs[k].I1(), per_pairs[k].I2()); per_verts.Add(per_pairs[k].I2(), per_pairs[k].I1()); } for (int k = PointIndex::BASE; k < GetNV()+PointIndex::BASE; k++) { BubbleSort(per_verts[k]); } /** The same table as per_verts, but TRANSITIVE!! **/ auto iterate_per_verts_trans = [&](auto f){ NgArray allvs; // for (int k = PointIndex::BASE; k < GetNV()+PointIndex::BASE; k++) for (PointIndex k = IndexBASE(); k < GetNV()+IndexBASE(); k++) { allvs.SetSize(0); allvs.Append(per_verts[k]); bool changed = true; while(changed) { changed = false; for (int j = 0; j per_verts_trans(npvs); iterate_per_verts_trans([&](auto k, auto & allvs) { for (int j = 0; j vert_flag (GetNV()); NgArray num_procs_on_vert (GetNV()); NgArray num_verts_on_proc (ntasks); num_verts_on_proc = 0; num_procs_on_vert = 0; auto iterate_vertices = [&](auto f) { vert_flag = -1; for (int dest = 1; dest < ntasks; dest++) { for (auto ei : els_of_proc[dest]) for (auto pnum : (*this)[ei].PNums()) f(pnum, dest); for (auto ei : sels_of_proc[dest]) for (auto pnum : (*this)[ei].PNums()) f(pnum, dest); /* NgFlatArray segs = segs_of_proc[dest]; for (int hi = 0; hi < segs.Size(); hi++) { const Segment & el = (*this) [segs[hi]]; for (int i = 0; i < 2; i++) f(el[i], dest); } */ for (auto segi : segs_of_proc[dest]) for (auto pnum : (*this)[segi].PNums()) f(pnum, dest); } }; /** count vertices per proc and procs per vertex **/ tbuildvertexa.Start(); iterate_vertices([&](auto vertex, auto dest){ auto countit = [&] (auto vertex, auto dest) { if (vert_flag[vertex] < dest) { vert_flag[vertex] = dest; num_verts_on_proc[dest]++; num_procs_on_vert[vertex]++; } }; countit(vertex, dest); for (auto v : per_verts_trans[vertex]) countit(v, dest); }); tbuildvertexa.Stop(); tbuildvertexb.Start(); TABLE verts_of_proc (num_verts_on_proc); TABLE procs_of_vert (num_procs_on_vert); TABLE loc_num_of_vert (num_procs_on_vert); /** Write vertex/proc mappingfs to tables **/ iterate_vertices([&](auto vertex, auto dest) { auto addit = [&] (auto vertex, auto dest) { if (vert_flag[vertex] < dest) { vert_flag[vertex] = dest; procs_of_vert.Add (vertex, dest); } }; addit(vertex, dest); for (auto v : per_verts_trans[vertex]) addit(v, dest); }); tbuildvertexb.Stop(); /** local vertex numbers on distant procs (I think this was only used for debugging??) **/ // for (int vert = 1; vert <= GetNP(); vert++ ) for (PointIndex vert : Points().Range()) { NgFlatArray procs = procs_of_vert[vert]; for (int j = 0; j < procs.Size(); j++) { int dest = procs[j]; // !! we also use this as offsets for MPI-type, if this is changed, also change ReceiveParallelMesh verts_of_proc.Add (dest, vert - IndexBASE()); loc_num_of_vert.Add (vert, verts_of_proc[dest].Size() -1+IndexBASE()); } } tbuildvertex.Stop(); PrintMessage ( 3, "Sending Vertices - vertices"); Array point_types(ntasks-1); for (int dest = 1; dest < ntasks; dest++) { NgFlatArray verts = verts_of_proc[dest]; // sendrequests.Append (MyMPI_ISend (verts, dest, NG_MPI_TAG_MESH+1, comm)); sendrequests += comm.ISend (FlatArray(verts), dest, NG_MPI_TAG_MESH+1); NG_MPI_Datatype mptype = MeshPoint::MyGetMPIType(); int numv = verts.Size(); NgArray blocklen (numv); blocklen = 1; NG_MPI_Type_indexed (numv, (numv == 0) ? nullptr : &blocklen[0], (numv == 0) ? nullptr : reinterpret_cast (&verts[0]), mptype, &point_types[dest-1]); NG_MPI_Type_commit (&point_types[dest-1]); NG_MPI_Request request; NG_MPI_Isend( points.Data(), 1, point_types[dest-1], dest, NG_MPI_TAG_MESH+1, comm, &request); sendrequests += request; } /** Next, we send the identifications themselves. Info about periodic identifications sent to each proc is an array of integers. - maxidentnr - type for each identification - nr of pairs for each identification (each pair is local!) - pairs for each periodic ident (global numbers) **/ PrintMessage ( 3, "Sending Vertices - identifications"); int maxidentnr = idents.GetMaxNr(); NgArray ppd_sizes(ntasks); ppd_sizes = 1 + 2*maxidentnr; for (int idnr = 1; idnr < idents.GetMaxNr()+1; idnr++) { if(idents.GetType(idnr)!=Identifications::PERIODIC) continue; idents.GetPairs(idnr, pp2); for(int j = 0; j pp_data(ppd_sizes); for(int dest = 0; dest < ntasks; dest++) pp_data.Add(dest, maxidentnr); for (int dest = 0; dest < ntasks; dest++) { for (int idnr = 1; idnr < idents.GetMaxNr()+1; idnr++) pp_data.Add(dest, idents.GetType(idnr)); for (int idnr = 1; idnr < idents.GetMaxNr()+1; idnr++) pp_data.Add(dest, 0); } for (int idnr = 1; idnr < idents.GetMaxNr()+1; idnr++) { if(idents.GetType(idnr)!=Identifications::PERIODIC) continue; idents.GetPairs(idnr, pp2); for(int j = 0; j(pp_data[dest]), dest, NG_MPI_TAG_MESH+1); req_per.WaitAll(); PrintMessage ( 3, "Sending Vertices - distprocs"); tbuilddistpnums.Start(); Array num_distpnums(ntasks); num_distpnums = 0; // for (int vert = 1; vert <= GetNP(); vert++) for (PointIndex vert : Points().Range()) { FlatArray procs = procs_of_vert[vert]; for (auto p : procs) num_distpnums[p] += 3 * (procs.Size()-1); } DynamicTable distpnums (num_distpnums); // for (int vert = 1; vert <= GetNP(); vert++) for (PointIndex vert : Points().Range()) { NgFlatArray 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]); } } tbuilddistpnums.Stop(); for ( int dest = 1; dest < ntasks; dest ++ ) sendrequests += comm.ISend (distpnums[dest], dest, NG_MPI_TAG_MESH+1); PrintMessage ( 3, "Sending elements" ); tbuildelementtable.Start(); Array elarraysize (ntasks); elarraysize = 0; // for (int ei = 1; ei <= GetNE(); ei++) for (ElementIndex ei : VolumeElements().Range()) { const Element & el = VolumeElement (ei); // int dest = el.GetPartition(); int dest = vol_partition[ei]; elarraysize[dest] += 3 + el.GetNP(); } DynamicTable elementarrays(elarraysize); for (ElementIndex ei : VolumeElements().Range()) { const Element & el = VolumeElement (ei); int dest = vol_partition[ei]; elementarrays.Add (dest, int(ei+1)); elementarrays.Add (dest, el.GetIndex()); elementarrays.Add (dest, el.GetNP()); for (PointIndex pi : el.PNums()) elementarrays.Add (dest, pi); } tbuildelementtable.Stop(); for (int dest = 1; dest < ntasks; dest ++ ) sendrequests += comm.ISend (elementarrays[dest], dest, NG_MPI_TAG_MESH+2); PrintMessage ( 3, "Sending Face Descriptors" ); Array 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 += comm.ISend (fddata, dest, NG_MPI_TAG_MESH+3); /** Surface Elements **/ PrintMessage ( 3, "Sending Surface elements" ); // build sel-identification size_t nse = GetNSE(); NgArray ided_sel(nse); ided_sel = -1; [[maybe_unused]] bool has_ided_sels = false; if(GetNE() && has_periodic) //we can only have identified surf-els if we have vol-els (right?) { Array os1, os2; for(SurfaceElementIndex sei = 0; sei < GetNSE(); sei++) { if(ided_sel[sei]!=-1) continue; const Element2d & sel = (*this)[sei]; auto points = sel.PNums(); auto ided1 = per_verts[points[0]]; os1.SetSize(0); for (int j = 0; j < ided1.Size(); j++) os1.Append(GetTopology().GetVertexSurfaceElements(ided1[j])); for (int j = 1; j < points.Size(); j++) { os2.SetSize(0); auto p2 = points[j]; auto ided2 = per_verts[p2]; for (int l = 0; l < ided2.Size(); l++) os2.Append(GetTopology().GetVertexSurfaceElements(ided2[l])); for (int m = 0; m1) { throw NgException("SurfaceElement identified with more than one other??"); } // const Element2d & sel2 = (*this)[sei]; // auto points2 = sel2.PNums(); has_ided_sels = true; ided_sel[sei] = os1[0]; ided_sel[os1[0]] = sei; } } // build sel data to send auto iterate_sels = [&](auto f) { for (SurfaceElementIndex sei = 0; sei < GetNSE(); sei++ ) { const Element2d & sel = (*this)[sei]; // int dest = (*this)[sei].GetPartition(); int dest = surf_partition[sei]; f(sei, sel, dest); if(ided_sel[sei]!=-1) { // int dest2 = (*this)[ided_sel[sei]].GetPartition(); int dest2 = surf_partition[ided_sel[sei]]; f(sei, sel, dest2); } } }; Array nlocsel(ntasks), bufsize(ntasks); nlocsel = 0; bufsize = 0; iterate_sels([&](SurfaceElementIndex sei, const Element2d & sel, int dest){ nlocsel[dest]++; bufsize[dest]++; }); DynamicTable selbuf(bufsize); iterate_sels([&](SurfaceElementIndex sei, const auto & sel, int dest) { selbuf.Add (dest, SelPackage(*this, sei)); }); // distribute sel data for (int dest = 1; dest < ntasks; dest++) sendrequests += comm.ISend(selbuf[dest], dest, NG_MPI_TAG_MESH+4); /** Segments **/ PrintMessage ( 3, "Sending Edge Segments"); auto iterate_segs1 = [&](auto f) { NgArray osegs1, osegs2, osegs_both; NgArray type1, type2; for(SegmentIndex segi = 0; segi < GetNSeg(); segi++) { const Segment & seg = (*this)[segi]; int segnp = seg.GetNP(); PointIndex pi1 = seg[0]; auto ided1 = per_verts[pi1]; PointIndex pi2 = seg[1]; auto ided2 = per_verts[pi2]; if (!(ided1.Size() && ided2.Size())) continue; osegs1.SetSize(0); type1.SetSize(0); for (int l = 0; l per_seg_size(GetNSeg()); per_seg_size = 0; iterate_segs1([&](SegmentIndex segi1, SegmentIndex segi2) { per_seg_size[segi1]++; }); TABLE per_seg(per_seg_size); iterate_segs1([&](SegmentIndex segi1, SegmentIndex segi2) { per_seg.Add(segi1, segi2); }); // make per_seg transitive auto iterate_per_seg_trans = [&](auto f){ NgArray allsegs; for (SegmentIndex segi = 0; segi < GetNSeg(); segi++) { allsegs.SetSize(0); allsegs.Append(per_seg[segi]); bool changed = true; while (changed) { changed = false; for (int j = 0; j & segs){ for (int j = 0; j < segs.Size(); j++) per_seg_size[segi] = segs.Size(); }); TABLE per_seg_trans(per_seg_size); iterate_per_seg_trans([&](SegmentIndex segi, NgArray & segs){ for (int j = 0; j < segs.Size(); j++) per_seg_trans.Add(segi, segs[j]); }); // build segment data NgArray dests; auto iterate_segs2 = [&](auto f) { for (SegmentIndex segi = 0; segi nloc_seg(ntasks); // bufsize = 1; //was originally this - why?? bufsize = 0; nloc_seg = 0; iterate_segs2([&](auto segi, const auto & seg, int dest) { nloc_seg[dest]++; bufsize[dest] += 15; }); DynamicTable segm_buf(bufsize); iterate_segs2([&](auto segi, const auto & seg, int dest) { segm_buf.Add (dest, segi); segm_buf.Add (dest, seg.si); segm_buf.Add (dest, seg.pnums[0]); segm_buf.Add (dest, seg.pnums[1]); segm_buf.Add (dest, seg.geominfo[0].trignum); segm_buf.Add (dest, seg.geominfo[1].trignum); segm_buf.Add (dest, seg.surfnr1); segm_buf.Add (dest, seg.surfnr2); segm_buf.Add (dest, seg.edgenr); segm_buf.Add (dest, seg.index); segm_buf.Add (dest, seg.epgeominfo[0].dist); segm_buf.Add (dest, seg.epgeominfo[1].edgenr); segm_buf.Add (dest, seg.epgeominfo[1].dist); segm_buf.Add (dest, seg.singedge_right); segm_buf.Add (dest, seg.singedge_left); }); // distribute segment data for (int dest = 1; dest < ntasks; dest++) sendrequests += comm.ISend(segm_buf[dest], dest, NG_MPI_TAG_MESH+5); /** Point-Elements **/ PrintMessage ( 3, "Point-Elements ..."); auto iterate_zdes = [&](auto f) { for (auto k : Range(pointelements)) { auto & el = pointelements[k]; PointElPackage pack(el); auto dests = procs_of_vert[el.pnum]; for (auto dest : dests) { f(pack, dest); } } }; bufsize = 0; iterate_zdes([&](const auto & pack, auto dest) { bufsize[dest]++; }); DynamicTable zde_buf(bufsize); // zero dim elements iterate_zdes([&](const auto & pack, auto dest) { zde_buf.Add(dest, pack); }); for (int dest = 1; dest < ntasks; dest++) sendrequests += comm.ISend(zde_buf[dest], dest, NG_MPI_TAG_MESH+6); PrintMessage ( 3, "now wait ..."); sendrequests.WaitAll(); // clean up MPI-datatypes we allocated earlier for (auto t : point_types) { NG_MPI_Type_free(&t); } paralleltop -> SetNV_Loc2Glob (0); paralleltop -> SetNV (0); paralleltop -> EnumeratePointsGlobally(); PrintMessage ( 3, "Sending names"); /** Send bc/mat/cd*-names **/ // nr of names std::array nnames{0,0,0,0}; nnames[0] = materials.Size(); nnames[1] = bcnames.Size(); nnames[2] = GetNCD2Names(); nnames[3] = GetNCD3Names(); int tot_nn = nnames[0] + nnames[1] + nnames[2] + nnames[3]; NgMPI_Requests requ; requ += comm.IBcast (nnames); auto iterate_names = [&](auto func) { for (int k = 0; k < nnames[0]; k++) func(materials[k]); for (int k = 0; k < nnames[1]; k++) func(bcnames[k]); for (int k = 0; k < nnames[2]; k++) func(cd2names[k]); for (int k = 0; k < nnames[3]; k++) func(cd3names[k]); }; // sizes of names Array name_sizes(tot_nn); tot_nn = 0; iterate_names([&](auto ptr) { name_sizes[tot_nn++] = (ptr==NULL) ? 0 : ptr->size(); }); requ += comm.IBcast (name_sizes); // names int strs = 0; iterate_names([&](auto ptr) { strs += (ptr==NULL) ? 0 : ptr->size(); }); Array compiled_names(strs); strs = 0; iterate_names([&](auto ptr) { if (ptr==NULL) return; auto& name = *ptr; for (int j=0; j < name.size(); j++) compiled_names[strs++] = name[j]; }); requ += comm.IBcast (compiled_names); PrintMessage ( 3, "wait for names"); requ.WaitAll(); comm.Barrier(); PrintMessage( 3, "Clean up local memory"); auto & self = const_cast(*this); self.points = T_POINTS(0); self.surfelements = Array(0); self.volelements = Array(0); self.segments = Array(0); self.pointelements = Array(0); self.lockedpoints = Array(0); /* auto cleanup_ptr = [](auto & ptr) { if (ptr != nullptr) { delete ptr; ptr = nullptr; } }; cleanup_ptr(self.boundaryedges); cleanup_ptr(self.segmentht); cleanup_ptr(self.surfelementht); */ self.boundaryedges = nullptr; self.segmentht = nullptr; self.surfelementht = nullptr; self.openelements = NgArray(0); self.opensegments = NgArray(0); self.numvertices = 0; self.mlbetweennodes = Array,PointIndex> (0); self.mlparentelement = Array(0); self.mlparentsurfaceelement = Array(0); self.curvedelems = make_unique (self); self.clusters = make_unique (self); self.ident = make_unique (self); self.topology = MeshTopology(*this); self.topology.Update(); self.BuildElementSearchTree(3); // const_cast(*this).DeleteMesh(); // paralleltop -> SetNV (0); // paralleltop->EnumeratePointsGlobally(); PrintMessage( 3, "send mesh complete"); } // workers receive the mesh from the master void Mesh :: ReceiveParallelMesh ( ) { Timer timer("ReceiveParallelMesh"); Timer timer_pts("Receive points"); Timer timer_els("Receive elements"); Timer timer_sels("Receive surface elements"); RegionTimer reg(timer); NgMPI_Comm comm = GetCommunicator(); int id = comm.Rank(); // int ntasks = comm.Size(); int dim; comm.Bcast(dim); SetDimension(dim); // Receive number of local elements int nelloc; comm.Scatter (nelloc); paralleltop -> SetNE (nelloc); // receive vertices timer_pts.Start(); Array verts; comm.Recv (verts, 0, NG_MPI_TAG_MESH+1); int numvert = verts.Size(); paralleltop -> SetNV (numvert); paralleltop -> SetNV_Loc2Glob (numvert); // INDEX_CLOSED_HASHTABLE glob2loc_vert_ht (3*numvert+1); INDEX_HASHTABLE glob2loc_vert_ht (3*numvert+1); for (int vert = 0; vert < numvert; vert++) { PointIndex globvert = verts[vert] + IndexBASE(); // paralleltop->SetLoc2Glob_Vert ( vert+1, globvert ); paralleltop->L2G (PointIndex(vert+PointIndex::BASE)) = globvert; glob2loc_vert_ht.Set (globvert, vert+PointIndex::BASE); } for (int i = 0; i < numvert; i++) AddPoint (netgen::Point<3> (0,0,0)); NG_MPI_Datatype mptype = MeshPoint::MyGetMPIType(); NG_MPI_Status status; NG_MPI_Recv( points.Data(), numvert, mptype, 0, NG_MPI_TAG_MESH+1, comm, &status); Array pp_data; comm.Recv(pp_data, 0, NG_MPI_TAG_MESH+1); int maxidentnr = pp_data[0]; auto & idents = GetIdentifications(); for (int idnr = 1; idnr < maxidentnr+1; idnr++) idents.SetType(idnr, (Identifications::ID_TYPE)pp_data[idnr]); int offset = 2*maxidentnr+1; for(int idnr = 1; idnr < maxidentnr+1; idnr++) { int npairs = pp_data[maxidentnr+idnr]; NgFlatArray pairdata(2*npairs, &pp_data[offset]); offset += 2*npairs; for (int k = 0; k dist_pnums; comm.Recv (dist_pnums, 0, NG_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]); AddDistantProc (PointIndex(dist_pnums[hi]), dist_pnums[hi+1]); timer_pts.Stop(); *testout << "got " << numvert << " vertices" << endl; { RegionTimer reg(timer_els); Array elarray; comm.Recv (elarray, 0, NG_MPI_TAG_MESH+2); for (int ind = 0, elnum = 1; ind < elarray.Size(); elnum++) { paralleltop->SetLoc2Glob_VolEl ( elnum, elarray[ind++]); int index = elarray[ind++]; Element el(elarray[ind++]); el.SetIndex(index); for ( int j = 0; j < el.GetNP(); j++) el[j] = glob2loc_vert_ht.Get (elarray[ind++]); AddVolumeElement (el); } } { Array fddata; comm.Recv (fddata, 0, NG_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]; } } { RegionTimer reg(timer_sels); Array selbuf; comm.Recv ( selbuf, 0, NG_MPI_TAG_MESH+4); int nlocsel = selbuf.Size(); paralleltop -> SetNSE ( nlocsel ); int sel = 0; for (auto k : Range(selbuf)) { auto & pack = selbuf[k]; Element2d el(pack.np); pack.Unpack(el); /** map global point numbers to local ones **/ for (int k : Range(1, 1+el.GetNP())) { el.PNum(k) = glob2loc_vert_ht.Get(el.PNum(k)); } paralleltop->SetLoc2Glob_SurfEl (sel+1, pack.sei); AddSurfaceElement (el); sel++; } } { // NgArray segmbuf; // MyMPI_Recv ( segmbuf, 0, NG_MPI_TAG_MESH+5, comm); Array segmbuf; comm.Recv (segmbuf, 0, NG_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.index = 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].IsValid() && seg.pnums[1].IsValid() ) { paralleltop-> SetLoc2Glob_Segm ( segi, globsegi ); AddSegment (seg); segi++; } } } { /** 0d-Elements **/ Array zdes; comm.Recv ( zdes, 0, NG_MPI_TAG_MESH+6); pointelements.SetSize(zdes.Size()); for (auto k : Range(pointelements)) { auto & el = pointelements[k]; el.pnum = glob2loc_vert_ht.Get(zdes[k].pnum); el.index = zdes[k].index; } } // paralleltop -> SetNV_Loc2Glob (0); paralleltop -> EnumeratePointsGlobally(); /** Recv bc-names **/ /* ArrayMem nnames{0,0,0,0}; // NG_MPI_Recv(nnames, 4, NG_MPI_INT, 0, NG_MPI_TAG_MESH+6, comm, NG_MPI_STATUS_IGNORE); comm.Recv(nnames, 0, NG_MPI_TAG_MESH+7); */ // Array recvrequests(1); std::array nnames; /* recvrequests[0] = comm.IBcast (nnames); MyMPI_WaitAll (recvrequests); */ comm.IBcast (nnames).Wait(); // cout << "nnames = " << FlatArray(nnames) << endl; materials.SetSize(nnames[0]); bcnames.SetSize(nnames[1]); cd2names.SetSize(nnames[2]); cd3names.SetSize(nnames[3]); int tot_nn = nnames[0] + nnames[1] + nnames[2] + nnames[3]; Array name_sizes(tot_nn); // NG_MPI_Recv(&name_sizes[0], tot_nn, NG_MPI_INT, 0, NG_MPI_TAG_MESH+7, comm, NG_MPI_STATUS_IGNORE); /* recvrequests[0] = comm.IBcast (name_sizes); MyMPI_WaitAll (recvrequests); */ comm.IBcast (name_sizes).Wait(); int tot_size = 0; for (int k = 0; k < tot_nn; k++) tot_size += name_sizes[k]; // NgArray compiled_names(tot_size); // NG_MPI_Recv(&(compiled_names[0]), tot_size, NG_MPI_CHAR, 0, NG_MPI_TAG_MESH+7, comm, NG_MPI_STATUS_IGNORE); Array compiled_names(tot_size); // recvrequests[0] = comm.IBcast (compiled_names); // MyMPI_WaitAll (recvrequests); comm.IBcast (compiled_names).Wait(); tot_nn = tot_size = 0; auto write_names = [&] (auto & array) { for (int k = 0; k < array.Size(); k++) { int s = name_sizes[tot_nn]; array[k] = s ? new string(&compiled_names[tot_size], s) : new string(""); tot_nn++; tot_size += s; } }; write_names(materials); write_names(bcnames); write_names(cd2names); write_names(cd3names); comm.Barrier(); int timerloc = NgProfiler::CreateTimer ("Update local mesh"); int timerloc2 = NgProfiler::CreateTimer ("CalcSurfacesOfNode"); NgProfiler::RegionTimer regloc(timerloc); stringstream str; str << "p" << id << ": got " << GetNE() << " elements and " << GetNSE() << " surface elements"; PrintMessage(2, str.str()); // cout << str.str() << endl; // 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(); // paralleltop -> UpdateCoarseGrid(); // paralleltop->EnumeratePointsGlobally(); SetNextMajorTimeStamp(); } // distribute the mesh to the worker processors // call it only for the master ! void Mesh :: Distribute () { NgMPI_Comm comm = GetCommunicator(); int id = comm.Rank(); int ntasks = comm.Size(); if (id != 0 || ntasks == 1 ) return; #ifdef METIS if (vol_partition.Size() < GetNE() || surf_partition.Size() < GetNSE() || seg_partition.Size() < GetNSeg()) ParallelMetis (comm.Size()); #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; */ // MyMPI_SendCmd ("mesh"); SendRecvMesh (); } #ifdef METIS5 void Mesh :: ParallelMetis (int nproc) { PrintMessage (3, "call metis 5 ..."); int timer = NgProfiler::CreateTimer ("Mesh::Partition"); NgProfiler::RegionTimer reg(timer); idx_t ne = GetNE() + GetNSE() + GetNSeg(); idx_t nn = GetNP(); NgArray eptr, eind; for (int i = 0; i < GetNE(); i++) { eptr.Append (eind.Size()); const Element & el = VolumeElement(i+1); for (int j = 0; j < el.GetNP(); j++) eind.Append (el[j]-IndexBASE()); } for (int i = 0; i < GetNSE(); i++) { eptr.Append (eind.Size()); const Element2d & el = SurfaceElement(i+1); for (int j = 0; j < el.GetNP(); j++) eind.Append (el[j]-IndexBASE()); } for (int i = 0; i < GetNSeg(); i++) { eptr.Append (eind.Size()); const Segment & el = LineSegment(i+1); eind.Append (el[0]-IndexBASE()); eind.Append (el[1]-IndexBASE()); } eptr.Append (eind.Size()); NgArray epart(ne), npart(nn); idxtype nparts = nproc-1; // GetCommunicator().Size()-1; vol_partition.SetSize(GetNE()); surf_partition.SetSize(GetNSE()); seg_partition.SetSize(GetNSeg()); if (nparts == 1) { for (int i = 0; i < GetNE(); i++) vol_partition[i]= 1; for (int i = 0; i < GetNSE(); i++) surf_partition[i] = 1; for (int i = 0; i < GetNSeg(); i++) seg_partition[i] = 1; } else { idxtype edgecut; idxtype ncommon = GetDimension(); PrintMessage (3, "metis start"); static Timer tm("metis library"); tm.Start(); METIS_PartMeshDual (&ne, &nn, &eptr[0], &eind[0], NULL, NULL, &ncommon, &nparts, NULL, NULL, &edgecut, &epart[0], &npart[0]); tm.Stop(); PrintMessage (3, "metis complete"); for (int i = 0; i < GetNE(); i++) vol_partition[i]= epart[i] + 1; for (int i = 0; i < GetNSE(); i++) surf_partition[i] = epart[i+GetNE()] + 1; for (int i = 0; i < GetNSeg(); i++) seg_partition[i] = epart[i+GetNE()+GetNSE()] + 1; } // surface elements attached to volume elements NgArray boundarypoints (GetNP()); boundarypoints = false; if(GetDimension() == 3) for (SurfaceElementIndex sei = 0; sei < GetNSE(); sei++) { const Element2d & el = (*this)[sei]; for (int j = 0; j < el.GetNP(); j++) boundarypoints[el[j]] = true; } else for (SegmentIndex segi = 0; segi < GetNSeg(); segi++) { const Segment & seg = (*this)[segi]; for (int j = 0; j < 2; j++) boundarypoints[seg[j]] = true; } // Build Pnt2Element table, boundary points only NgArray cnt(GetNP()); cnt = 0; auto loop_els_2d = [&](auto f) { for (SurfaceElementIndex sei = 0; sei < GetNSE(); sei++) { const Element2d & el = (*this)[sei]; for (int j = 0; j < el.GetNP(); j++) { f(el[j], sei); } } }; auto loop_els_3d = [&](auto f) { for (ElementIndex ei = 0; ei < GetNE(); ei++) { const Element & el = (*this)[ei]; for (int j = 0; j < el.GetNP(); j++) f(el[j], ei); } }; auto loop_els = [&](auto f) { if (GetDimension() == 3 ) loop_els_3d(f); else loop_els_2d(f); }; loop_els([&](auto vertex, int index) { if(boundarypoints[vertex]) cnt[vertex]++; }); TABLE pnt2el(cnt); loop_els([&](auto vertex, int index) { if(boundarypoints[vertex]) pnt2el.Add(vertex, index); }); if (GetDimension() == 3) { for (SurfaceElementIndex sei = 0; sei < GetNSE(); sei++) { Element2d & sel = (*this)[sei]; PointIndex pi1 = sel[0]; // NgFlatArray els = pnt2el[pi1]; NgFlatArray els = pnt2el[pi1]; // sel.SetPartition (-1); surf_partition[sei] = -1; for (int j = 0; j < els.Size(); j++) { const Element & el = (*this)[ElementIndex(els[j])]; bool hasall = true; for (int k = 0; k < sel.GetNP(); k++) { bool haspi = false; for (int l = 0; l < el.GetNP(); l++) if (sel[k] == el[l]) haspi = true; if (!haspi) hasall = false; } if (hasall) { // sel.SetPartition (el.GetPartition()); surf_partition[sei] = vol_partition[ElementIndex(els[j])]; break; } } // if (sel.GetPartition() == -1) if (surf_partition[sei] == -1) cerr << "no volume element found" << endl; } for (SegmentIndex si = 0; si < GetNSeg(); si++) { Segment & sel = (*this)[si]; PointIndex pi1 = sel[0]; NgFlatArray els = pnt2el[pi1]; // sel.SetPartition (-1); seg_partition[si] = -1; for (int j = 0; j < els.Size(); j++) { const Element & el = (*this)[ElementIndex(els[j])]; bool haspi[9] = { false }; // max surfnp for (int k = 0; k < 2; k++) for (int l = 0; l < el.GetNP(); l++) if (sel[k] == el[l]) haspi[k] = true; bool hasall = true; for (int k = 0; k < sel.GetNP(); k++) if (!haspi[k]) hasall = false; if (hasall) { // sel.SetPartition (el.GetPartition()); seg_partition[si] = vol_partition[ElementIndex(els[j])]; break; } } // if (sel.GetPartition() == -1) if (seg_partition[si] == -1) cerr << "no volume element found" << endl; } } else { for (SegmentIndex segi = 0; segi < GetNSeg(); segi++) { Segment & seg = (*this)[segi]; // seg.SetPartition(-1); seg_partition[segi] = -1; PointIndex pi1 = seg[0]; NgFlatArray sels = pnt2el[pi1]; for (int j = 0; j < sels.Size(); j++) { SurfaceElementIndex sei = sels[j]; Element2d & se = (*this)[sei]; bool found = false; for (int l = 0; l < se.GetNP(); l++ && !found) found |= (se[l]==seg[1]); if(found) { // seg.SetPartition(se.GetPartition()); seg_partition[segi] = surf_partition[sei]; break; } } // if (seg.GetPartition() == -1) { if (seg_partition[segi] == -1) { cout << endl << "segi: " << segi << endl; cout << "points: " << seg[0] << " " << seg[1] << endl; cout << "surfels: " << endl << sels << endl; throw NgException("no surface element found"); } } } } #endif //========================== weights ================================================================= // distribute the mesh to the worker processors // call it only for the master ! void Mesh :: Distribute (NgArray & volume_weights , NgArray & surface_weights, NgArray & segment_weights) { NgMPI_Comm comm = GetCommunicator(); int id = comm.Rank(); int ntasks = comm.Size(); if (id != 0 || ntasks == 1 ) return; #ifdef METIS ParallelMetis (volume_weights, surface_weights, segment_weights); #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; */ // MyMPI_SendCmd ("mesh"); SendRecvMesh (); } #ifdef METIS5 void Mesh :: ParallelMetis (NgArray & volume_weights , NgArray & surface_weights, NgArray & segment_weights) { PrintMessage (3, "call metis 5 with weights ..."); // cout << "segment_weights " << segment_weights << endl; // cout << "surface_weights " << surface_weights << endl; // cout << "volume_weights " << volume_weights << endl; int timer = NgProfiler::CreateTimer ("Mesh::Partition"); NgProfiler::RegionTimer reg(timer); idx_t ne = GetNE() + GetNSE() + GetNSeg(); idx_t nn = GetNP(); NgArray eptr, eind , nwgt; for (int i = 0; i < GetNE(); i++) { eptr.Append (eind.Size()); const Element & el = VolumeElement(i+1); int ind = el.GetIndex(); if (volume_weights.Size() epart(ne), npart(nn); idxtype nparts = GetCommunicator().Size()-1; vol_partition.SetSize(GetNE()); surf_partition.SetSize(GetNSE()); seg_partition.SetSize(GetNSeg()); if (nparts == 1) { for (int i = 0; i < GetNE(); i++) // VolumeElement(i+1).SetPartition(1); vol_partition[i] = 1; for (int i = 0; i < GetNSE(); i++) // SurfaceElement(i+1).SetPartition(1); surf_partition[i] = 1; for (int i = 0; i < GetNSeg(); i++) // LineSegment(i+1).SetPartition(1); seg_partition[i] = 1; return; } idxtype edgecut; idxtype ncommon = 3; METIS_PartMeshDual (&ne, &nn, &eptr[0], &eind[0], &nwgt[0], NULL, &ncommon, &nparts, NULL, NULL, &edgecut, &epart[0], &npart[0]); /* METIS_PartMeshNodal (&ne, &nn, &eptr[0], &eind[0], NULL, NULL, &nparts, NULL, NULL, &edgecut, &epart[0], &npart[0]); */ PrintMessage (3, "metis complete"); // cout << "done" << endl; for (int i = 0; i < GetNE(); i++) // VolumeElement(i+1).SetPartition(epart[i] + 1); vol_partition[i] = epart[i] + 1; for (int i = 0; i < GetNSE(); i++) // SurfaceElement(i+1).SetPartition(epart[i+GetNE()] + 1); surf_partition[i] = epart[i+GetNE()] + 1; for (int i = 0; i < GetNSeg(); i++) // LineSegment(i+1).SetPartition(epart[i+GetNE()+GetNSE()] + 1); seg_partition[i] = epart[i+GetNE()+GetNSE()] + 1; } #endif //=========================================================================================== #ifdef METIS4 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(); NgArray 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; NgArray 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(4)_PartMeshDual ... " << flush; METIS_PartMeshDual (&ne, &nn, &elmnts[0], &etype, &numflag, &nparts, &edgecut, &epart[0], &npart[0]); #else cout << "call metis(5)_PartMeshDual ... " << endl; // idx_t options[METIS_NOPTIONS]; NgArray 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 () { throw Exception("PartHybridMesh not supported"); #ifdef METISxxx int ne = GetNE(); int nn = GetNP(); int nedges = topology.GetNEdges(); idxtype *xadj, * adjacency; // 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; idxtype * part; xadj = new idxtype[nn+1]; part = new idxtype[nn]; NgArray cnt(nn+1); cnt = 0; for ( int edge = 0; edge < nedges; edge++ ) { // int v1, v2; // topology.GetEdgeVertices ( edge, v1, v2); auto [v1,v2] = topology.GetEdgeVertices(edge); 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 = 0; edge < nedges; edge++ ) { // int v1, v2; // topology.GetEdgeVertices ( edge, v1, v2); auto [v1,v2] = topology.GetEdgeVertices(edge); 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++ ) { NgFlatArray 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 NgArray nodesinpart(ntasks); vol_partition.SetSize(ne); for ( int el = 1; el <= ne; el++ ) { Element & volel = VolumeElement(el); nodesinpart = 0; 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); vol_partition[el-1] = partition; } delete [] xadj; delete [] part; delete [] adjacency; #else cout << "parthybridmesh not available" << endl; #endif } void Mesh :: PartDualHybridMesh ( ) // NgArray & neloc ) { throw Exception("PartDualHybridMesh not supported"); #ifdef OLD #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; NgArray facevolels1(nfaces), facevolels2(nfaces); facevolels1 = -1; facevolels2 = -1; // NgArray elfaces; xadj = new idxtype[ne+1]; part = new idxtype[ne]; NgArray cnt(ne+1); cnt = 0; for ( int el=1; el <= ne; el++ ) { Element volel = VolumeElement(el); // topology.GetElementFaces(el, elfaces); auto elfaces = topology.GetFaces (ElementIndex(el-1)); for ( int i = 0; i < elfaces.Size(); i++ ) { if ( facevolels1[elfaces[i]] == -1 ) facevolels1[elfaces[i]] = el; else { facevolels2[elfaces[i]] = el; cnt[facevolels1[elfaces[i]]-1]++; cnt[facevolels2[elfaces[i]]-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++ ) { NgFlatArray 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); NgArray nodesinpart(ntasks); vol_partition.SetSize(ne); for ( int el = 1; el <= ne; el++ ) { // Element & volel = VolumeElement(el); nodesinpart = 0; // VolumeElement(el).SetPartition(part[el-1 ] + 1); vol_partition[el-1] = 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 #endif } void Mesh :: PartDualHybridMesh2D ( ) { #ifdef METIS idxtype ne = GetNSE(); int nv = GetNV(); NgArray xadj(ne+1); NgArray adjacency(ne*4); // first, build the vertex 2 element table: NgArray 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 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; NgArray 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 numflag = 0; idxtype nparts = ntasks - 1; idxtype edgecut; NgArray part(ne); for ( int el = 0; el < ne; el++ ) BubbleSort (adjacency.Range (xadj[el], xadj[el+1])); #ifdef METIS4 idxtype weightflag = 0; int options[5]; options[0] = 0; 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 surf_partition.SetSize(ne); for (SurfaceElementIndex sei = 0; sei < ne; sei++) // (*this) [sei].SetPartition (part[sei]+1); surf_partition[sei] = part[sei]+1; #else cout << "partdualmesh not available" << endl; #endif } } #endif ================================================ FILE: libsrc/meshing/paralleltop.cpp ================================================ #include #include "paralleltop.hpp" namespace netgen { ParallelMeshTopology :: ParallelMeshTopology (const Mesh & amesh) : mesh(amesh) { is_updated = false; } ParallelMeshTopology :: ~ParallelMeshTopology () { ; } void ParallelMeshTopology :: Reset () { *testout << "ParallelMeshTopology::Reset" << endl; if ( mesh.GetCommunicator().Size() == 1 ) return; size_t ned = mesh.GetTopology().GetNEdges(); size_t nfa = mesh.GetTopology().GetNFaces(); if (glob_edge.Size() != ned) { glob_edge.SetSize(ned); glob_face.SetSize(nfa); glob_edge = -1; glob_face = -1; loc2distedge.ChangeSize (ned); loc2distface.ChangeSize (nfa); } if (glob_vert.Size() != mesh.GetNV()) { SetNV(mesh.GetNV()); SetNE(mesh.GetNE()); } } void ParallelMeshTopology :: Print() const { ; } void ParallelMeshTopology :: EnumeratePointsGlobally () { auto comm = mesh.GetCommunicator(); auto rank = comm.Rank(); size_t oldnv = glob_vert.Size(); size_t nv = loc2distvert.Size(); *testout << "enumerate globally, loc2distvert.size = " << loc2distvert.Size() << ", glob_vert.size = " << glob_vert.Size() << endl; if (rank == 0) nv = 0; // IntRange newvr(oldnv, nv); // new vertex range auto new_pir = Range(PointIndex(oldnv+PointIndex::BASE), PointIndex(nv+PointIndex::BASE)); glob_vert.SetSize (nv); for (auto pi : new_pir) L2G(pi) = -1; int num_master_points = 0; for (auto pi : new_pir) { auto dps = GetDistantProcs(pi); // check sorted: for (int j = 0; j+1 < dps.Size(); j++) if (dps[j+1] < dps[j]) cout << "wrong sort" << endl; if (dps.Size() == 0 || dps[0] > comm.Rank()) L2G(pi) = num_master_points++; } // *testout << "nummaster = " << num_master_points << endl; Array first_master_point(comm.Size()); comm.AllGather (num_master_points, first_master_point); auto max_oldv = comm.AllReduce (Max (glob_vert.Range(0, oldnv)), NG_MPI_MAX); if (comm.AllReduce (oldnv, NG_MPI_SUM) == 0) max_oldv = long(PointIndex::BASE)-1; size_t num_glob_points = max_oldv+1; for (int i = 0; i < comm.Size(); i++) { int cur = first_master_point[i]; first_master_point[i] = num_glob_points; num_glob_points += cur; } for (auto pi : new_pir) if (L2G(pi) != -1) L2G(pi) += first_master_point[comm.Rank()]; // ScatterDofData (global_nums); Array nsend(comm.Size()), nrecv(comm.Size()); nsend = 0; nrecv = 0; /** Count send/recv size **/ for (auto pi : new_pir) if (auto dps = GetDistantProcs(pi); dps.Size()) { if (rank < dps[0]) for (auto p : dps) nsend[p]++; else nrecv[dps[0]]++; } Table send_data(nsend); Table recv_data(nrecv); /** Fill send_data **/ nsend = 0; for (auto pi : new_pir) if (auto dps = GetDistantProcs(pi); dps.Size()) if (rank < dps[0]) for (auto p : dps) send_data[p][nsend[p]++] = L2G(pi); NgMPI_Requests requests; for (int i = 0; i < comm.Size(); i++) { if (nsend[i]) requests += comm.ISend (send_data[i], i, 200); if (nrecv[i]) requests += comm.IRecv (recv_data[i], i, 200); } // MyMPI_WaitAll (requests); requests.WaitAll(); Array cnt(comm.Size()); cnt = 0; for (auto pi : new_pir) if (auto dps = GetDistantProcs(pi); dps.Size()) if (int master = dps[0]; master < comm.Rank()) L2G(pi) = recv_data[master][cnt[master]++]; // reorder following global ordering: Array index0(glob_vert.Size()); for (int pi : Range(index0)) index0[pi] = pi; QuickSortI (glob_vert, index0); if (rank != 0) { Array inv_index(index0.Size()); for (int i = 0; i < index0.Size(); i++) inv_index[index0[i]+PointIndex::BASE] = i+PointIndex::BASE; for (auto & el : mesh.VolumeElements()) for (PointIndex & pi : el.PNums()) pi = inv_index[pi]; for (auto & el : mesh.SurfaceElements()) for (PointIndex & pi : el.PNums()) pi = inv_index[pi]; for (auto & el : mesh.LineSegments()) for (PointIndex & pi : el.PNums()) pi = inv_index[pi]; // auto hpoints (mesh.Points()); Array hpoints { mesh.Points() }; for (PointIndex pi : Range(mesh.Points())) mesh.Points()[inv_index[pi]] = hpoints[pi]; if (mesh.mlbetweennodes.Size() == mesh.Points().Size()) { Array,PointIndex> hml { mesh.mlbetweennodes }; for (PointIndex pi : Range(mesh.Points())) mesh.mlbetweennodes[inv_index[pi]] = hml[pi]; } // *testout << "index0 = " << endl << index0 << endl; // *testout << "loc2distvertold = " << endl; // for (auto i : Range(index0)) // *testout << "l " << i << " globi "<< glob_vert[i] << " dist = " << loc2distvert[i] << endl; DynamicTable oldtable = std::move(loc2distvert); loc2distvert = DynamicTable (oldtable.Size()); for (size_t i = 0; i < oldtable.Size(); i++) for (auto val : oldtable[index0[i]]) loc2distvert.Add (i, val); Array hglob_vert(glob_vert); for (int i = 0; i < index0.Size(); i++) glob_vert[i] = hglob_vert[index0[i]]; // *testout << "loc2distvertnew = " << endl; // for (auto i : Range(index0)) // *testout << "l " << i << " globi "<< glob_vert[i] << " dist = " << loc2distvert[i] << endl; } /* for (size_t i = 0; i+1 < glob_vert.Size(); i++) if (glob_vert[i] > glob_vert[i+1]) cout << "wrong ordering of globvert" << endl; */ if (glob_vert.Size() > 1) for (auto i : Range(glob_vert).Modify(0,-1)) if (glob_vert[i] > glob_vert[i+1]) cout << "wrong ordering of globvert" << endl; } /* void ParallelMeshTopology :: SetDistantFaceNum (int dest, int locnum) { for ( int i = 0; i < loc2distface[locnum-1].Size(); i+=1 ) if ( loc2distface[locnum-1][i] == dest ) return; loc2distface.Add(locnum-1, dest); } void ParallelMeshTopology :: SetDistantPNum (int dest, int locnum) { for ( int i = 0; i < loc2distvert[locnum-1].Size(); i+=1 ) if ( loc2distvert[locnum-1][i] == dest ) return; loc2distvert.Add (locnum-1, dest); } void ParallelMeshTopology :: SetDistantEdgeNum (int dest, int locnum) { for ( int i = 0; i < loc2distedge[locnum-1].Size(); i+=1 ) if ( loc2distedge[locnum-1][i] == dest ) return; loc2distedge.Add (locnum-1, dest); } */ void ParallelMeshTopology :: SetNV_Loc2Glob (int anv) { glob_vert.SetSize(anv); glob_vert = -1; } void ParallelMeshTopology :: SetNV (int anv) { // glob_vert.SetSize(anv); // glob_vert = -1; // loc2distvert.ChangeSize (anv); DynamicTable oldtable(loc2distvert.Size()); for (size_t i = 0; i < loc2distvert.Size(); i++) for (auto val : loc2distvert[i]) oldtable.Add (i, val); loc2distvert = DynamicTable (anv); for (size_t i = 0; i < min(size_t(anv), oldtable.Size()); i++) for (auto val : oldtable[i]) loc2distvert.Add (i, val); } void ParallelMeshTopology :: SetNE ( int ane ) { glob_el.SetSize (ane); glob_el = -1; } void ParallelMeshTopology :: SetNSE ( int anse ) { glob_surfel.SetSize(anse); glob_surfel = -1; } void ParallelMeshTopology :: SetNSegm ( int anseg ) { glob_segm.SetSize (anseg); glob_segm = -1; } /* void ParallelMeshTopology :: UpdateCoarseGridGlobal () { // cout << "updatecoarsegridglobal called" << endl; if (id == 0) PrintMessage ( 3, "UPDATE GLOBAL COARSEGRID STARTS" ); int timer = NgProfiler::CreateTimer ("UpdateCoarseGridGlobal"); NgProfiler::RegionTimer reg(timer); *testout << "ParallelMeshTopology :: UpdateCoarseGridGlobal" << endl; const MeshTopology & topology = mesh.GetTopology(); auto comm = mesh.GetCommunicator(); if ( id == 0 ) { NgArray*> sendarrays(ntasks); for (int dest = 1; dest < ntasks; dest++) sendarrays[dest] = new NgArray; NgArray edges, faces; for (int el = 1; el <= mesh.GetNE(); el++) { topology.GetElementFaces (el, faces); topology.GetElementEdges (el, edges); // const Element & volel = mesh.VolumeElement (el); // NgArray & sendarray = *sendarrays[volel.GetPartition()]; NgArray & sendarray = *sendarrays[mesh.vol_partition[el-1]]; for ( int i = 0; i < edges.Size(); i++ ) sendarray.Append (edges[i]); for ( int i = 0; i < faces.Size(); i++ ) sendarray.Append (faces[i]); } for (int el = 1; el <= mesh.GetNSE(); el++) { topology.GetSurfaceElementEdges (el, edges); // const Element2d & surfel = mesh.SurfaceElement (el); // NgArray & sendarray = *sendarrays[surfel.GetPartition()]; NgArray & sendarray = *sendarrays[mesh.surf_partition[el-1]]; for ( int i = 0; i < edges.Size(); i++ ) sendarray.Append (edges[i]); sendarray.Append (topology.GetSurfaceElementFace (el)); } Array sendrequests; for (int dest = 1; dest < ntasks; dest++) // sendrequests.Append (MyMPI_ISend (*sendarrays[dest], dest, NG_MPI_TAG_MESH+10, comm)); sendrequests.Append (comm.ISend (FlatArray(*sendarrays[dest]), dest, NG_MPI_TAG_MESH+10)); MyMPI_WaitAll (sendrequests); for (int dest = 1; dest < ntasks; dest++) delete sendarrays[dest]; } else { // NgArray recvarray; // MyMPI_Recv (recvarray, 0, NG_MPI_TAG_MESH+10, comm); Array recvarray; comm.Recv (recvarray, 0, NG_MPI_TAG_MESH+10); // MyMPI_Recv (recvarray, 0, NG_MPI_TAG_MESH+10, comm); int ii = 0; NgArray faces, edges; for (int volel = 1; volel <= mesh.GetNE(); volel++) { topology.GetElementEdges ( volel, edges); for ( int i = 0; i < edges.Size(); i++) SetLoc2Glob_Edge ( edges[i], recvarray[ii++]); topology.GetElementFaces( volel, faces); for ( int i = 0; i < faces.Size(); i++) SetLoc2Glob_Face ( faces[i], recvarray[ii++]); } for (int surfel = 1; surfel <= mesh.GetNSE(); surfel++) { topology.GetSurfaceElementEdges (surfel, edges); for (int i = 0; i < edges.Size(); i++) SetLoc2Glob_Edge (edges[i], recvarray[ii++]); int face = topology.GetSurfaceElementFace (surfel); SetLoc2Glob_Face ( face, recvarray[ii++]); } } is_updated = true; } */ void ParallelMeshTopology :: IdentifyVerticesAfterRefinement() { static Timer t("ParallelTopology::UpdateCoarseGrid"); RegionTimer r(t); NgMPI_Comm comm = mesh.GetCommunicator(); int id = comm.Rank(); int ntasks = comm.Size(); if (ntasks == 1) return; Reset(); static int timer = NgProfiler::CreateTimer ("UpdateCoarseGrid"); NgProfiler::RegionTimer reg(timer); (*testout) << "UPDATE COARSE GRID PARALLEL TOPOLOGY " << endl; if (id == 0) PrintMessage (1, "update parallel topology"); // const MeshTopology & topology = mesh.GetTopology(); Array cnt_send(ntasks); int maxsize = comm.AllReduce (mesh.mlbetweennodes.Size(), NG_MPI_MAX); // update new vertices after mesh-refinement if (maxsize > 0) { int newnv = mesh.mlbetweennodes.Size(); loc2distvert.ChangeSize(mesh.mlbetweennodes.Size()); bool changed = true; while (changed) { changed = false; // build exchange vertices cnt_send = 0; for (PointIndex pi : mesh.Points().Range()) for (int dist : GetDistantProcs(pi)) cnt_send[dist]++; // TABLE dest2vert(cnt_send); DynamicTable dest2vert(cnt_send); for (PointIndex pi : mesh.Points().Range()) for (int dist : GetDistantProcs(pi)) dest2vert.Add (dist, pi); for (PointIndex pi = IndexBASE(); pi < newnv+IndexBASE(); pi++) if (auto [v1,v2] = mesh.mlbetweennodes[pi]; v1.IsValid()) { auto procs1 = GetDistantProcs(v1); auto procs2 = GetDistantProcs(v2); for (int p : procs1) if (procs2.Contains(p)) cnt_send[p]++; } // TABLE dest2pair(cnt_send); DynamicTable dest2pair(cnt_send); for (PointIndex pi : mesh.mlbetweennodes.Range()) if (auto [v1,v2] = mesh.mlbetweennodes[pi]; v1.IsValid()) { auto procs1 = GetDistantProcs(v1); auto procs2 = GetDistantProcs(v2); for (int p : procs1) if (procs2.Contains(p)) dest2pair.Add (p, pi); } cnt_send = 0; for (PointIndex pi : mesh.mlbetweennodes.Range()) if (auto [v1,v2] = mesh.mlbetweennodes[pi]; v1.IsValid()) { auto procs1 = GetDistantProcs(v1); auto procs2 = GetDistantProcs(v2); for (int p : procs1) if (procs2.Contains(p)) cnt_send[p]+=2; } // TABLE send_verts(cnt_send); DynamicTable send_verts(cnt_send); NgArray loc2exchange(mesh.GetNV()); for (int dest = 0; dest < ntasks; dest++) if (dest != id) { loc2exchange = -1; int cnt = 0; for (PointIndex pi : dest2vert[dest]) loc2exchange[pi] = cnt++; for (PointIndex pi : dest2pair[dest]) if (auto [v1,v2] = mesh.mlbetweennodes[pi]; v1.IsValid()) { auto procs1 = GetDistantProcs(v1); auto procs2 = GetDistantProcs(v2); if (procs1.Contains(dest) && procs2.Contains(dest)) { send_verts.Add (dest, loc2exchange[v1]); send_verts.Add (dest, loc2exchange[v2]); } } } DynamicTable recv_verts(ntasks); comm.ExchangeTable (send_verts, recv_verts, NG_MPI_TAG_MESH+9); for (int dest = 0; dest < ntasks; dest++) if (dest != id) { loc2exchange = -1; int cnt = 0; for (PointIndex pi : dest2vert[dest]) loc2exchange[pi] = cnt++; FlatArray recvarray = recv_verts[dest]; for (int ii = 0; ii < recvarray.Size(); ii+=2) for (PointIndex pi : dest2pair[dest]) { PointIndex v1 = mesh.mlbetweennodes[pi][0]; PointIndex v2 = mesh.mlbetweennodes[pi][1]; if (v1.IsValid()) { INDEX_2 re(recvarray[ii], recvarray[ii+1]); INDEX_2 es(loc2exchange[v1], loc2exchange[v2]); // if (es == re && !IsExchangeVert(dest, pi)) if (es == re && !GetDistantProcs(pi).Contains(dest)) { // SetDistantPNum(dest, pi); AddDistantProc (pi, dest); changed = true; } } } } changed = comm.AllReduce (changed, NG_MPI_LOR); } } NgArray sendarray, recvarray; // cout << "UpdateCoarseGrid - edges" << endl; // static int timerv = NgProfiler::CreateTimer ("UpdateCoarseGrid - ex vertices"); static int timere = NgProfiler::CreateTimer ("UpdateCoarseGrid - ex edges"); // static int timerf = NgProfiler::CreateTimer ("UpdateCoarseGrid - ex faces"); NgProfiler::StartTimer (timere); // build exchange vertices cnt_send = 0; for (PointIndex pi : mesh.Points().Range()) for (int dist : GetDistantProcs(pi)) cnt_send[dist]++; // TABLE dest2vert(cnt_send); DynamicTable dest2vert(cnt_send); for (PointIndex pi : mesh.Points().Range()) for (int dist : GetDistantProcs(pi)) dest2vert.Add (dist, pi); // NG_MPI_Group_free(&NG_MPI_LocalGroup); // NG_MPI_Comm_free(&NG_MPI_LocalComm); } void ParallelMeshTopology :: UpdateCoarseGrid () { static Timer t("ParallelTopology::UpdateCoarseGrid"); RegionTimer r(t); // cout << "UpdateCoarseGrid" << endl; // if (is_updated) return; NgMPI_Comm comm = mesh.GetCommunicator(); int id = comm.Rank(); int ntasks = comm.Size(); if (ntasks == 1) return; Reset(); static int timer = NgProfiler::CreateTimer ("UpdateCoarseGrid"); NgProfiler::RegionTimer reg(timer); (*testout) << "UPDATE COARSE GRID PARALLEL TOPOLOGY " << endl; if (id == 0) PrintMessage (1, "update parallel topology"); // UpdateCoarseGridGlobal(); /* // MPI_Barrier (MPI_COMM_WORLD); MPI_Group MPI_GROUP_comm; MPI_Group MPI_LocalGroup; MPI_Comm MPI_LocalComm; int process_ranks[] = { 0 }; MPI_Comm_group (comm, &MPI_GROUP_comm); MPI_Group_excl (MPI_GROUP_comm, 1, process_ranks, &MPI_LocalGroup); MPI_Comm_create (comm, MPI_LocalGroup, &MPI_LocalComm); if (id == 0) { // SetNV(0); // EnumeratePointsGlobally(); return; } */ const MeshTopology & topology = mesh.GetTopology(); Array cnt_send(ntasks); // NgArray sendarray, recvarray; // cout << "UpdateCoarseGrid - edges" << endl; // static int timerv = NgProfiler::CreateTimer ("UpdateCoarseGrid - ex vertices"); static int timere = NgProfiler::CreateTimer ("UpdateCoarseGrid - ex edges"); static int timerf = NgProfiler::CreateTimer ("UpdateCoarseGrid - ex faces"); NgProfiler::StartTimer (timere); int nfa = topology . GetNFaces(); int ned = topology . GetNEdges(); // build exchange vertices cnt_send = 0; for (PointIndex pi : mesh.Points().Range()) for (int dist : GetDistantProcs(pi)) cnt_send[dist]++; // TABLE dest2vert(cnt_send); DynamicTable dest2vert(cnt_send); for (PointIndex pi : mesh.Points().Range()) for (int dist : GetDistantProcs(pi)) dest2vert.Add (dist, pi); // exchange edges cnt_send = 0; // int v1, v2; for (int edge = 1; edge <= ned; edge++) { // topology.GetEdgeVertices (edge, v1, v2); auto [v1,v2] = topology.GetEdgeVertices(edge-1); /* for (int dest = 1; dest < ntasks; dest++) // if (IsExchangeVert (dest, v1) && IsExchangeVert (dest, v2)) if (GetDistantProcs(v1).Contains(dest) && GetDistantProcs(v2).Contains(dest)) cnt_send[dest-1]+=1; */ for (auto p : GetDistantProcs(v1)) if (GetDistantProcs(v2).Contains(p)) cnt_send[p]+=1; } // TABLE dest2edge(cnt_send); DynamicTable dest2edge(cnt_send); for (int & v : cnt_send) v *= 2; // TABLE send_edges(cnt_send); DynamicTable send_edges(cnt_send); for (int edge = 1; edge <= ned; edge++) { // topology.GetEdgeVertices (edge, v1, v2); auto [v1,v2] = topology.GetEdgeVertices(edge-1); for (int dest = 0; dest < ntasks; dest++) // if (IsExchangeVert (dest, v1) && IsExchangeVert (dest, v2)) if (GetDistantProcs(v1).Contains(dest) && GetDistantProcs(v2).Contains(dest)) dest2edge.Add (dest, edge); } NgArray loc2exchange(mesh.GetNV()); for (int dest = 0; dest < ntasks; dest++) { loc2exchange = -1; int cnt = 0; for (PointIndex pi : dest2vert[dest]) loc2exchange[pi] = cnt++; for (int edge : dest2edge[dest]) { // topology.GetEdgeVertices (edge, v1, v2); auto [v1,v2] = topology.GetEdgeVertices(edge-1); // if (IsExchangeVert (dest, v1) && IsExchangeVert (dest, v2)) if (GetDistantProcs(v1).Contains(dest) && GetDistantProcs(v2).Contains(dest)) { send_edges.Add (dest, loc2exchange[v1]); send_edges.Add (dest, loc2exchange[v2]); } } } DynamicTable recv_edges(ntasks); comm.ExchangeTable (send_edges, recv_edges, NG_MPI_TAG_MESH+9); for (int dest = 0; dest < ntasks; dest++) { auto ex2loc = dest2vert[dest]; if (ex2loc.Size() == 0) continue; INDEX_2_CLOSED_HASHTABLE vert2edge(2*dest2edge[dest].Size()+10); for (int edge : dest2edge[dest]) { // topology.GetEdgeVertices (edge, v1, v2); auto [v1,v2] = topology.GetEdgeVertices(edge-1); vert2edge.Set(INDEX_2(v1,v2), edge); } FlatArray recvarray = recv_edges[dest]; for (int ii = 0; ii < recvarray.Size(); ii+=2) { INDEX_2 re(ex2loc[recvarray[ii]], ex2loc[recvarray[ii+1]]); if (vert2edge.Used(re)) // SetDistantEdgeNum(dest, vert2edge.Get(re)); AddDistantEdgeProc(vert2edge.Get(re)-1, dest); } } NgProfiler::StopTimer (timere); // cout << "UpdateCoarseGrid - faces" << endl; if (mesh.GetDimension() == 3) { NgProfiler::StartTimer (timerf); NgArray verts; // exchange faces cnt_send = 0; for (int face = 1; face <= nfa; face++) { topology.GetFaceVertices (face, verts); for (int dest = 0; dest < ntasks; dest++) if (dest != id) /* if (IsExchangeVert (dest, verts[0]) && IsExchangeVert (dest, verts[1]) && IsExchangeVert (dest, verts[2])) */ if (GetDistantProcs (verts[0]).Contains(dest) && GetDistantProcs (verts[1]).Contains(dest) && GetDistantProcs (verts[2]).Contains(dest)) cnt_send[dest]++; } // TABLE dest2face(cnt_send); DynamicTable dest2face(cnt_send); for (int face = 1; face <= nfa; face++) { topology.GetFaceVertices (face, verts); for (int dest = 0; dest < ntasks; dest++) if (dest != id) /* if (IsExchangeVert (dest, verts[0]) && IsExchangeVert (dest, verts[1]) && IsExchangeVert (dest, verts[2])) */ if (GetDistantProcs (verts[0]).Contains(dest) && GetDistantProcs (verts[1]).Contains(dest) && GetDistantProcs (verts[2]).Contains(dest)) dest2face.Add(dest, face); } for (int & c : cnt_send) c*=3; // TABLE send_faces(cnt_send); DynamicTable send_faces(cnt_send); NgArray loc2exchange(mesh.GetNV()); for (int dest = 0; dest < ntasks; dest++) if (dest != id) { if (dest2vert[dest].Size() == 0) continue; loc2exchange = -1; int cnt = 0; for (PointIndex pi : dest2vert[dest]) loc2exchange[pi] = cnt++; for (int face : dest2face[dest]) { topology.GetFaceVertices (face, verts); /* if (IsExchangeVert (dest, verts[0]) && IsExchangeVert (dest, verts[1]) && IsExchangeVert (dest, verts[2])) */ if (GetDistantProcs (verts[0]).Contains(dest) && GetDistantProcs (verts[1]).Contains(dest) && GetDistantProcs (verts[2]).Contains(dest)) { send_faces.Add (dest, loc2exchange[verts[0]]); send_faces.Add (dest, loc2exchange[verts[1]]); send_faces.Add (dest, loc2exchange[verts[2]]); } } } DynamicTable recv_faces(ntasks); comm.ExchangeTable (send_faces, recv_faces, NG_MPI_TAG_MESH+9); for (int dest = 0; dest < ntasks; dest++) { auto ex2loc = dest2vert[dest]; if (ex2loc.Size() == 0) continue; INDEX_3_CLOSED_HASHTABLE vert2face(2*dest2face[dest].Size()+10); for (int face : dest2face[dest]) { topology.GetFaceVertices (face, verts); vert2face.Set(INDEX_3(verts[0], verts[1], verts[2]), face); } FlatArray recvarray = recv_faces[dest]; for (int ii = 0; ii < recvarray.Size(); ii+=3) { INDEX_3 re(ex2loc[recvarray[ii]], ex2loc[recvarray[ii+1]], ex2loc[recvarray[ii+2]]); if (vert2face.Used(re)) AddDistantFaceProc(vert2face.Get(re)-1, dest); } } NgProfiler::StopTimer (timerf); } // cout << "UpdateCoarseGrid - done" << endl; // EnumeratePointsGlobally(); is_updated = true; // NG_MPI_Group_free(&NG_MPI_LocalGroup); // NG_MPI_Comm_free(&NG_MPI_LocalComm); } } ================================================ FILE: libsrc/meshing/paralleltop.hpp ================================================ #ifndef FILE_PARALLELTOP #define FILE_PARALLELTOP namespace netgen { class ParallelMeshTopology { const Mesh & mesh; /** 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) */ DynamicTable loc2distvert; DynamicTable loc2distedge, loc2distface; Array glob_vert; // will get rid of them NgArray glob_edge, glob_face; NgArray glob_el, glob_surfel, glob_segm; bool is_updated; public: ParallelMeshTopology (const Mesh & amesh); ~ParallelMeshTopology (); void Reset (); void Print() const; void UpdateCoarseGrid(); // [[deprecated("should not need it anymore")]] // void UpdateCoarseGridGlobal(); void IdentifyVerticesAfterRefinement(); void EnumeratePointsGlobally (); void AddDistantProc (PointIndex pi, int proc) { loc2distvert.AddUnique (pi-IndexBASE(), proc); } void AddDistantFaceProc (int edge, int proc) { loc2distface.AddUnique (edge, proc); } void AddDistantEdgeProc (int face, int proc) { loc2distedge.AddUnique (face, proc); } FlatArray GetDistantProcs (PointIndex pi) const { return loc2distvert[pi-IndexBASE()]; } FlatArray GetDistantFaceProcs (int locnum) const { return loc2distface[locnum]; } FlatArray GetDistantEdgeProcs (int locnum) const { return loc2distedge[locnum]; } auto & L2G (PointIndex pi) { return glob_vert[pi-IndexBASE()]; } auto L2G (PointIndex pi) const { return glob_vert[pi-IndexBASE()]; } /// set number of local vertices, reset sizes of loc2dist_vert, isexchangevert... void SetNV (int anv); void SetNV_Loc2Glob (int anv); void SetNE (int ane); void SetNSE (int anse); void SetNSegm (int anseg); [[deprecated("Use AddDistantFaceProc instead!")]] void SetDistantFaceNum (int dest, int locnum) { loc2distface.AddUnique (locnum-1, dest); } [[deprecated("Use AddDistantProc instead!")]] void SetDistantPNum (int dest, int locnum) { loc2distvert.AddUnique (locnum-1, dest); } [[deprecated("Use AddDistantEdgeProc instead!")]] void SetDistantEdgeNum (int dest, int locnum) { loc2distedge.AddUnique (locnum-1, dest); } [[deprecated("Use GetDistantFaceProcx instead!")]] FlatArray GetDistantFaceNums (int locnum) const { return loc2distface[locnum]; } [[deprecated("Use GetDistantEdgeProcx instead!")]] FlatArray GetDistantEdgeNums (int locnum) const { return loc2distedge[locnum]; } [[deprecated("Use L2G(pi) instead!")]] void SetLoc2Glob_Vert (int locnum, int globnum) { glob_vert[locnum-1] = globnum; } [[deprecated("Try to avoid global enumration!")]] void SetLoc2Glob_Edge (int locnum, int globnum) { glob_edge[locnum-1] = globnum; } [[deprecated("Try to avoid global enumration!")]] void SetLoc2Glob_Face (int locnum, int globnum) { glob_face[locnum-1] = globnum; } // [[deprecated("Try to avoid global enumration!")]] void SetLoc2Glob_VolEl (int locnum, int globnum) { glob_el[locnum-1] = globnum; } // [[deprecated("Try to avoid global enumration!")]] void SetLoc2Glob_SurfEl (int locnum, int globnum) { glob_surfel[locnum-1] = globnum; } // [[deprecated("Try to avoid global enumration!")]] void SetLoc2Glob_Segm (int locnum, int globnum) { glob_segm[locnum-1] = globnum; } // [[deprecated("Try to avoid global enumration!")]] int GetGlobalPNum (PointIndex locnum) const { return glob_vert[locnum-IndexBASE()]; } [[deprecated("Try to avoid global enumration!")]] int GetGlobalEdgeNum (int locnum) const { return glob_edge[locnum-1]; } [[deprecated("Try to avoid global enumration!")]] int GetGlobalFaceNum (int locnum) const { return glob_face[locnum-1]; } [[deprecated("Try to avoid global enumration!")]] int GetGlobalElNum (int locnum) const { return glob_el[locnum-1]; } [[deprecated("Try to avoid global enumration!")]] int GetGlobalSElNum (int locnum) const { return glob_surfel[locnum-1]; } // [[deprecated("Use GetDistantPNums(locnum).Size() instead!")]] int GetNDistantPNums (int locpnum) const { return loc2distvert[locpnum-1].Size(); } // [[deprecated("Use GetDistantFaceNums(locnum).Size() instead!")]] int GetNDistantFaceNums (int locfacenum) const { return loc2distface[locfacenum-1].Size(); } // [[deprecated("Use GetDistantEdgeNums(locnum).Size() instead!")]] int GetNDistantEdgeNums ( int locedgenum) const { return loc2distedge[locedgenum-1].Size(); } // [[deprecated("Use GetDistantPNums(locnum) -> FlatArray instead!")]] void GetDistantPNums (int locpnum, int * distpnums ) const { for (int i = 0; i < loc2distvert[locpnum-1].Size(); i++ ) distpnums[i] = loc2distvert[locpnum-1][i]; } // [[deprecated("Use GetDistantFaceNums(locnum) -> FlatArray instead!")]] void GetDistantFaceNums (int locfacenum, int * distfacenums ) const { for ( int i = 0; i < loc2distface[locfacenum-1].Size(); i++ ) distfacenums[i] = loc2distface[locfacenum-1][i]; } // [[deprecated("Use GetDistantFaceNums(locnum) -> FlatArray instead!")]] void GetDistantFaceNums (int locfacenum, NgArray & distfacenums ) const { // distfacenums = loc2distface[locfacenum-1]; auto loc = loc2distface[locfacenum-1]; distfacenums.SetSize (loc.Size()); for (int i = 0; i < loc.Size(); i++) distfacenums[i] = loc[i]; } // [[deprecated("Use GetDistantEdgeNums(locnum) -> FlatArray instead!")]] void GetDistantEdgeNums (int locedgenum, int * distedgenums ) const { for (int i = 0; i < loc2distedge[locedgenum-1].Size(); i++ ) distedgenums[i] = loc2distedge[locedgenum-1][i]; } // [[deprecated("Use GetDistantEdgeNums(locnum) -> FlatArray instead!")]] void GetDistantEdgeNums (int locedgenum, NgArray & distedgenums ) const { // distedgenums = loc2distedge[locedgenum-1]; auto loc = loc2distedge[locedgenum-1]; distedgenums.SetSize (loc.Size()); for (int i = 0; i < loc.Size(); i++) distedgenums[i] = loc[i]; } [[deprecated("Use GetDistantProcs(..)!")]] FlatArray GetDistantPNums (int locnum) const { return loc2distvert[locnum]; } [[deprecated("Use GetDistantProcs(..).Contains instead!")]] bool IsExchangeVert (int dest, int vnum) const { return loc2distvert[vnum-1].Contains (dest); } }; } #endif ================================================ FILE: libsrc/meshing/parser2.cpp ================================================ #include #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; Point<2> 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); */ name = string(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[0]; ist >> ch; // ',' ist >> p[1]; 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 \""<> 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; //(*testout) << "read next character \""<> ch; while (ch == '(') { ist >> p[0]; ist >> ch; // ',' ist >> p[1]; 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[0]; ist >> ch; // ',' ist >> p[1]; 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[0]; ist >> ch; // ',' ist >> p[1]; 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(TRIG)); ist >> (int&)elements.Last().PNum(1); ist >> ch; // ',' if (ch == COMMASIGN) { ist >> (int&)elements.Last().PNum(2); ist >> ch; // ',' } if (ch == COMMASIGN) { ist >> (int&)elements.Last().PNum(3); ist >> ch; // ',' } if (ch == COMMASIGN) { elements.Last().SetType (QUAD); ist >> (int&)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; NgArray 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] = std::move(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] = NgArray> (freezone.Size()); auto& 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; igood()) { cerr << "Rule description file " << filename << " not found" << endl; delete ist; exit (1); } Timer t("Parsing rules"); t.Start(); while (!ist->eof()) { buf[0] = 0; (*ist) >> buf; if (strcmp (buf, "rule") == 0) { //(*testout) << "found rule" << endl; auto rule = make_unique(); //(*testout) << "fr1" << endl; rule -> LoadRule(*ist); //(*testout) << "fr2" << endl; rules.Append (std::move(rule)); } //(*testout) << "loop" << endl; } //(*testout) << "POS3" << endl; t.Stop(); delete ist; //delete [] tr1; } } ================================================ FILE: libsrc/meshing/parser3.cpp ================================================ #include #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 { NgArray tr1(3); NgArray 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(TRIG); 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 >> (int&)face.PNum(1); ist >> ch; // ',' ist >> (int&)face.PNum(2); ist >> ch; // ',' ist >> (int&)face.PNum(3); ist >> ch; // ')' or ',' if (ch == COMMASIGN) { face.SetType(QUAD); ist >> (int&)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 >> (int&)face.PNum(1); ist >> ch; // ',' ist >> (int&)face.PNum(2); ist >> ch; // ',' ist >> (int&)face.PNum(3); ist >> ch; // ')' or ',' if (ch == COMMASIGN) { face.SetType(QUAD); ist >> (int&)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 NgArray); 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 >> (int&)elements.Last().PNum(1); ist >> ch; // ',' if (ch == COMMASIGN) { // elements.Last().SetNP(2); ist >> (int&)elements.Last().PNum(2); ist >> ch; // ',' } if (ch == COMMASIGN) { // elements.Last().SetNP(3); ist >> (int&)elements.Last().PNum(3); ist >> ch; // ',' } if (ch == COMMASIGN) { // elements.Last().SetNP(4); elements.Last().SetType(TET); ist >> (int&)elements.Last().PNum(4); ist >> ch; // ',' } if (ch == COMMASIGN) { // elements.Last().SetNP(5); elements.Last().SetType(PYRAMID); ist >> (int&)elements.Last().PNum(5); ist >> ch; // ',' } if (ch == COMMASIGN) { // elements.Last().SetNP(6); elements.Last().SetType(PRISM); ist >> (int&)elements.Last().PNum(6); ist >> ch; // ',' } if (ch == COMMASIGN) { // elements.Last().SetNP(6); elements.Last().SetType(HEX); ist >> (int&)elements.Last().PNum(7); ist >> ch; // ',' } if (ch == COMMASIGN) { // elements.Last().SetNP(6); elements.Last().SetType(HEX); ist >> (int&)elements.Last().PNum(8); 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 NgArray); 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 NgArray); NgArray & freeset = *freesets.Elem(fs); NgArray & 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; // NgArray 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 NgArray); // NgArray & freeset = *freesets.Get(fs); NgArray & freesetedges = *freeedges.Last(); NgArray & freesetfaces = *freefaces.Get(fs); // int k,l; // INDEX ind; for (int k = 1; k <= freesetfaces.Size(); k++) { // threeint tr = freesetfaces.Get(k); for (int l = k+1; l <= freesetfaces.Size(); l++) { INDEX 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); PointIndices<2> ed(PointIndex::INVALID, PointIndex::INVALID); 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[0] && GetPointNrMod (eli, elr+2) == ed[1]) { /* (*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; igood()) { 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; auto rule = make_unique(); rule -> LoadRule(*ist); if (!rule->TestOk()) { PrintSysError ("Parser3d: Rule ", rules.Size(), " not ok"); exit (1); } rules.Append (std::move(rule)); } else if (strcmp (buf, "tolfak") == 0) { (*ist) >> tolfak; } } delete ist; delete [] tr1; } } ================================================ FILE: libsrc/meshing/python_mesh.cpp ================================================ #ifdef NG_PYTHON #include #include <../general/ngpython.hpp> #include #include "python_mesh.hpp" #include #include "meshing.hpp" #include "boundarylayer.hpp" // #include // #include #include <../interface/rw_medit.hpp> #include <../interface/writeuser.hpp> #include <../include/nginterface.h> #include <../general/gzstream.h> class ClearSolutionClass { public: ClearSolutionClass() { } ~ClearSolutionClass() { Ng_ClearSolutionData(); } }; using namespace netgen; extern const char *ngscript[]; namespace netgen { extern bool netgen_executable_started; extern shared_ptr ng_geometry; extern void Optimize2d (Mesh & mesh, MeshingParameters & mp, int faceindex=0); #ifdef NG_CGNS extern tuple, vector, vector>, vector> ReadCGNSFile(const filesystem::path & filename, int base); extern void WriteCGNSFile(shared_ptr mesh, const filesystem::path & filename, vector fields, vector> values, vector locations); #endif // NG_CGNS } void TranslateException (const NgException & ex) { string err = string("Netgen exception: ")+ex.What(); PyErr_SetString(PyExc_RuntimeError, err.c_str()); } static Transformation<3> global_trafo(Vec<3> (0,0,0)); DLL_HEADER void ExportNetgenMeshing(py::module &m) { py::register_exception(m, "NgException"); m.attr("_netgen_executable_started") = py::cast(netgen::netgen_executable_started); string script; const char ** hcp = ngscript; while (*hcp) script += *hcp++; m.attr("_ngscript") = py::cast(script); m.def("_GetStatus", []() { std::string s; double percent; GetStatus(s, percent); return py::make_tuple(s.c_str(), percent); }); m.def("_PushStatus", [](string s) { PushStatus(s); }); m.def("_SetThreadPercentage", [](double percent) { SetThreadPercent(percent); }); py::enum_(m,"IdentificationType") .value("UNDEFINED", Identifications::UNDEFINED) .value("PERIODIC", Identifications::PERIODIC) .value("CLOSESURFACES", Identifications::CLOSESURFACES) .value("CLOSEEDGES", Identifications::CLOSEEDGES) ; py::implicitly_convertible(); py::class_(m, "NGDummyArgument") .def("__bool__", []( NGDummyArgument &self ) { return false; } ) ; py::class_>(m, "LocalH"); py::class_> (m, "Point2d") .def(py::init()) .def(py::init( [] (std::pair xy) { return Point<2>{xy.first, xy.second}; })) .def ("__str__", &ToString>) .def(py::self-py::self) .def(py::self+Vec<2>()) .def(py::self-Vec<2>()) .def("__getitem__", [](Point<2>& self, int index) { return self[index]; }) .def("__len__", [](Point<2>& /*unused*/) { return 2; }) ; py::implicitly_convertible>(); py::class_> (m, "Point3d") .def(py::init()) .def(py::init([](py::tuple p) { return Point<3> { p[0].cast(), p[1].cast(), p[2].cast() }; })) .def ("__str__", &ToString>) .def(py::self-py::self) .def(py::self+Vec<3>()) .def(py::self-Vec<3>()) .def("__getitem__", [](Point<3>& self, int index) { return self[index]; }) .def("__setitem__", [](Point<3>& self, int index, double value) { self[index] = value; }) .def("__len__", [](Point<3>& /*unused*/) { return 3; }) ; py::implicitly_convertible>(); m.def("Pnt", [](double x, double y, double z) { return global_trafo(Point<3>(x,y,z)); }); m.def("Pnt", [](double x, double y) { return Point<2>(x,y); }); m.def("Pnt", [](py::array_t np_array) { int dim = np_array.size(); if(!(dim == 2 || dim == 3)) throw Exception("Invalid dimension of input array!"); if(dim == 2) return py::cast(Point<2>(np_array.at(0), np_array.at(1))); return py::cast(global_trafo(Point<3>(np_array.at(0), np_array.at(1), np_array.at(2)))); }); py::class_> (m, "Vec2d") .def(py::init()) .def(py::init( [] (std::pair xy) { return Vec<2>{xy.first, xy.second}; })) .def ("__str__", &ToString>) .def(py::self==py::self) .def(py::self+py::self) .def(py::self-py::self) .def(-py::self) .def(double()*py::self) .def(py::self*double()) .def("Norm", &Vec<2>::Length) .def("__getitem__", [](Vec<2>& vec, int index) { return vec[index]; }) .def("__len__", [](Vec<2>& /*unused*/) { return 2; }) ; py::implicitly_convertible>(); py::class_> (m, "Vec3d") .def(py::init()) .def(py::init([](py::tuple v) { return Vec<3> { v[0].cast(), v[1].cast(), v[2].cast() }; })) .def ("__str__", &ToString>) .def(py::self==py::self) .def(py::self+py::self) .def(py::self-py::self) .def(-py::self) .def(double()*py::self) .def(py::self*double()) .def("Norm", &Vec<3>::Length) .def("__getitem__", [](Vec<3>& vec, int index) { return vec[index]; }) .def("__len__", [](Vec<3>& /*unused*/) { return 3; }) ; py::implicitly_convertible>(); py::class_>(m, "Mat33") .def(py::init([](py::tuple m) { if(m.size() != 9) throw std::length_error("Invalid dimension of input array!"); Mat<3,3> mat; for(int i = 0; i < 3; i++) for(int j = 0; j < 3; j++) mat(i,j) = m[i*3+j].cast(); return mat; })) .def("__getitem__", [](Mat<3,3>& mat, py::tuple index) { if(index.size() != 2) throw std::length_error("Invalid dimension of input array!"); return mat(index[0].cast(), index[1].cast()); }) .def("__setitem__", [](Mat<3,3>& mat, py::tuple index, double val) { if(index.size() != 2) throw std::length_error("Invalid dimension of input array!"); mat(index[0].cast(), index[1].cast()) = val; }) .def("__str__", &ToString>) ; py::implicitly_convertible>(); m.def ("Vec", FunctionPointer ([] (double x, double y, double z) { return global_trafo(Vec<3>(x,y,z)); })); m.def("Vec", [](py::array_t np_array) { int dim = np_array.size(); if(!(dim == 2 || dim == 3)) throw Exception("Invalid dimension of input array!"); if(dim == 2) return py::cast(Vec<2>(np_array.at(0), np_array.at(1))); return py::cast(global_trafo(Vec<3>(np_array.at(0), np_array.at(1), np_array.at(2)))); }); m.def ("Vec", FunctionPointer ([] (double x, double y) { return Vec<2>(x,y); })); py::class_> (m, "Trafo") .def(py::init>(), "a translation") .def(py::init,Vec<3>,double>(), "a rotation given by point on axes, direction of axes, angle") .def("__mul__", [](Transformation<3> a, Transformation<3> b)->Transformation<3> { Transformation<3> res; res.Combine(a,b); return res; }) .def("__call__", [] (Transformation<3> trafo, Point<3> p) { return trafo(p); }) .def_property("mat", &Transformation<3>::GetMatrix, [](Transformation<3>& self, const Mat<3,3>& mat) { self.GetMatrix() = mat; }) ; m.def ("GetTransformation", [] () { return global_trafo; }); m.def ("SetTransformation", [] (Transformation<3> trafo) { global_trafo = trafo; }); m.def ("SetTransformation", [](int dir, double angle) { if (dir > 0) global_trafo.SetAxisRotation (dir, angle*M_PI/180); else global_trafo = Transformation<3> (Vec<3>(0,0,0)); }, py::arg("dir")=int(0), py::arg("angle")=int(0)); m.def ("SetTransformation", [](Point<3> p0, Vec<3> ex, Vec<3> ey, Vec<3> ez) { Point<3> pnts[4]; pnts[0] = p0; pnts[1] = p0 + ex; pnts[2] = p0 + ey; pnts[3] = p0 + ez; global_trafo = Transformation<3> (pnts); }, py::arg("p0"), py::arg("ex"), py::arg("ey"), py::arg("ez")); py::class_(m, "PointId") .def(py::init()) .def("__repr__", &ToString) .def("__str__", &ToString) .def_property_readonly("nr", &PointIndex::operator int) .def("__eq__" , FunctionPointer( [](PointIndex &self, PointIndex &other) { return static_cast(self)==static_cast(other); }) ) .def("__hash__" , FunctionPointer( [](PointIndex &self ) { return static_cast(self); }) ) ; py::class_(m, "ElementId3D") .def(py::init()) .def("__repr__", &ToString) .def("__str__", &ToString) .def_property_readonly("nr", &ElementIndex::operator int) .def("__eq__" , FunctionPointer( [](ElementIndex &self, ElementIndex &other) { return static_cast(self)==static_cast(other); }) ) .def("__hash__" , FunctionPointer( [](ElementIndex &self ) { return static_cast(self); }) ) ; py::class_(m, "ElementId2D") .def(py::init()) .def("__repr__", &ToString) .def("__str__", &ToString) .def_property_readonly("nr", &SurfaceElementIndex::operator int) .def("__eq__" , FunctionPointer( [](SurfaceElementIndex &self, SurfaceElementIndex &other) { return static_cast(self)==static_cast(other); }) ) .def("__hash__" , FunctionPointer( [](SurfaceElementIndex &self ) { return static_cast(self); }) ) ; py::class_(m, "ElementId1D") .def(py::init()) .def("__repr__", &ToString) .def("__str__", &ToString) .def_property_readonly("nr", &SegmentIndex::operator int) .def("__eq__" , FunctionPointer( [](SegmentIndex &self, SegmentIndex &other) { return static_cast(self)==static_cast(other); }) ) .def("__hash__" , FunctionPointer( [](SegmentIndex &self ) { return static_cast(self); }) ) ; /* py::class_> ("Point") .def(py::init()) ; */ py::class_> */ >(m, "MeshPoint") .def(py::init>()) .def("__str__", &ToString) .def("__repr__", &ToString) .def_property_readonly("p", [](const MeshPoint & self) { py::list l; l.append ( py::cast(self[0]) ); l.append ( py::cast(self[1]) ); l.append ( py::cast(self[2]) ); return py::tuple(l); }) .def("__getitem__", [](const MeshPoint & self, int index) { if(index<0 || index>2) throw py::index_error(); return self[index]; }) .def("__setitem__", [](MeshPoint & self, int index, double val) { if(index<0 || index>2) throw py::index_error(); self(index) = val; }) .def_property("singular", [](const MeshPoint & pnt) { return pnt.Singularity(); }, [](MeshPoint & pnt, double sing) { pnt.Singularity(sing); }) ; py::class_(m, "Element3D") .def(py::init([](int index, std::vector vertices) { int np = vertices.size(); ELEMENT_TYPE et; switch (np) { case 4: et = TET; break; case 5: et = PYRAMID; break; case 6: et = PRISM; break; case 8: et = HEX; break; case 10: et = TET10; break; case 13: et = PYRAMID13; break; case 15: et = PRISM15; break; case 20: et = HEX20; break; default: throw Exception ("no Element3D with " + ToString(np) + " points"); } auto newel = new Element(et); for(int i=0; iSetIndex(index); return newel; }), py::arg("index")=1,py::arg("vertices"), "create volume element" ) .def("__repr__", &ToString) .def_property("index", &Element::GetIndex, &Element::SetIndex) .def_property("curved", &Element::IsCurved, &Element::SetCurved) .def_property("refine", &Element::TestRefinementFlag, &Element::SetRefinementFlag) .def_property_readonly("vertices", FunctionPointer ([](const Element & self) -> py::list { py::list li; for (int i = 0; i < self.GetNV(); i++) li.append (py::cast(self[i])); return li; })) .def_property_readonly("points", FunctionPointer ([](const Element & self) -> py::list { py::list li; for (int i = 0; i < self.GetNP(); i++) li.append (py::cast(self[i])); return li; })) ; if(ngcore_have_numpy) { auto data_layout = Element::GetDataLayout(); py::detail::npy_format_descriptor::register_dtype({ py::detail::field_descriptor { "nodes", data_layout["pnum"], ELEMENT_MAXPOINTS * sizeof(PointIndex), py::format_descriptor::format(), py::detail::npy_format_descriptor::dtype() }, py::detail::field_descriptor { "index", data_layout["index"], sizeof(int), py::format_descriptor::format(), py::detail::npy_format_descriptor::dtype() }, py::detail::field_descriptor { "np", data_layout["np"], sizeof(int8_t), py::format_descriptor::format(), pybind11::dtype("int8") }, py::detail::field_descriptor { "refine", data_layout["refine"], sizeof(bool), py::format_descriptor::format(), py::detail::npy_format_descriptor::dtype() }, py::detail::field_descriptor { "curved", data_layout["curved"], sizeof(bool), py::format_descriptor::format(), py::detail::npy_format_descriptor::dtype()} }); } py::class_(m, "Element2D") .def(py::init ([](int index, std::vector vertices, std::optional>> uv) { Element2d * newel = nullptr; if (vertices.size() == 3) { newel = new Element2d(TRIG); for (int i = 0; i < 3; i++) (*newel)[i] = vertices[i]; newel->SetIndex(index); } else if (vertices.size() == 4) { newel = new Element2d(QUAD); for (int i = 0; i < 4; i++) (*newel)[i] = vertices[i]; newel->SetIndex(index); } else if (vertices.size() == 6) { newel = new Element2d(TRIG6); for(int i = 0; i<6; i++) (*newel)[i] = vertices[i]; newel->SetIndex(index); } else if (vertices.size() == 8) { newel = new Element2d(QUAD8); for(int i = 0; i<8; i++) (*newel)[i] = vertices[i]; newel->SetIndex(index); } else throw NgException("Inconsistent number of vertices in Element2D"); if (uv.has_value()) { auto vecuv = *uv; if (vecuv.size() != vertices.size()) throw NgException("wrong number of uv-parameters"); for (int i = 0; i < vertices.size(); i++) { PointGeomInfo gi; gi.u = vecuv[i][0]; gi.v = vecuv[i][1]; newel->GeomInfo()[i] = gi; } } return newel; }), py::arg("index")=1,py::arg("vertices"), py::arg("uv")=std::nullopt, "create surface element" ) .def_property("index", &Element2d::GetIndex, &Element2d::SetIndex) .def_property("curved", &Element2d::IsCurved, &Element2d::SetCurved) .def_property("refine", &Element2d::TestRefinementFlag, &Element2d::SetRefinementFlag) .def_property("uv", [](const Element2d & self) { std::vector> uv(self.GetNP()); for (int i = 0; i < uv.size(); i++) { double u = self.GeomInfo()[i].u; double v = self.GeomInfo()[i].v; uv[i] = std::array{u,v}; } return uv; }, [](Element2d & self, const std::vector> & uv) { if (uv.size() != self.GetNP()) throw NgException("wrong number of uv-parameters"); for (int i = 0; i < uv.size(); i++) { PointGeomInfo gi; gi.u = uv[i][0]; gi.v = uv[i][1]; self.GeomInfo()[i] = gi; } }) .def_property_readonly("geominfo", [](const Element2d& self) -> py::list { py::list li; for (const auto &pgi : self.GeomInfo()) li.append(py::make_tuple(pgi.trignum, pgi.u, pgi.v)); return li; }) .def_property_readonly("vertices", FunctionPointer([](const Element2d & self) -> py::list { py::list li; for (int i = 0; i < self.GetNV(); i++) li.append(py::cast(self[i])); return li; })) .def_property_readonly("points", FunctionPointer ([](const Element2d & self) -> py::list { py::list li; for (int i = 0; i < self.GetNP(); i++) li.append (py::cast(self[i])); return li; })) ; if(ngcore_have_numpy) { auto data_layout = Element2d::GetDataLayout(); py::detail::npy_format_descriptor::register_dtype({ py::detail::field_descriptor { "nodes", data_layout["pnum"], ELEMENT2D_MAXPOINTS * sizeof(PointIndex), py::format_descriptor::format(), py::detail::npy_format_descriptor::dtype() }, py::detail::field_descriptor { "index", data_layout["index"], sizeof(int), py::format_descriptor::format(), py::detail::npy_format_descriptor::dtype() }, py::detail::field_descriptor { "np", data_layout["np"], sizeof(int8_t), py::format_descriptor::format(), pybind11::dtype("int8") }, py::detail::field_descriptor { "refine", data_layout["refine"], sizeof(bool), py::format_descriptor::format(), py::detail::npy_format_descriptor::dtype() }, py::detail::field_descriptor { "curved", data_layout["curved"], sizeof(bool), py::format_descriptor::format(), py::detail::npy_format_descriptor::dtype() } }); } py::class_(m, "Element1D") .def(py::init([](py::list vertices, py::list surfaces, int index, int edgenr, py::list trignums) { Segment * newel = new Segment(); for (int i = 0; i < 2; i++) (*newel)[i] = py::extract(vertices[i])(); newel -> si = index; newel -> epgeominfo[0].edgenr = edgenr; newel -> epgeominfo[1].edgenr = edgenr; newel -> edgenr = index; newel -> index = index; for(auto i : Range(len(trignums))) newel->geominfo[i].trignum = py::cast(trignums[i]); if (len(surfaces)) { newel->surfnr1 = py::extract(surfaces[0])(); newel->surfnr2 = py::extract(surfaces[1])(); } return newel; }), py::arg("vertices"), py::arg("surfaces")=py::list(), py::arg("index")=1, py::arg("edgenr")=1, py::arg("trignums")=py::list(), // for stl "create segment element" ) .def("__repr__", &ToString) .def_property_readonly("vertices", FunctionPointer ([](const Segment & self) -> py::list { py::list li; for (int i = 0; i < 2; i++) li.append (py::cast(self[i])); return li; })) .def_property_readonly("points", FunctionPointer ([](const Segment & self) -> py::list { py::list li; for (int i = 0; i < self.GetNP(); i++) li.append (py::cast(self[i])); return li; })) .def_property_readonly("surfaces", FunctionPointer ([](const Segment & self) -> py::list { py::list li; li.append (py::cast(self.surfnr1)); li.append (py::cast(self.surfnr2)); return li; })) .def_property("index", [](const Segment &self) { return self.GetIndex(); }, [](Segment& self, int index) { self.SetIndex(index); }) .def_property("edgenr", [](const Segment & self) { return self.GetEdgeNr(); }, [](Segment& self, int edgenr) { self.SetEdgeNr(edgenr); }) .def_property("singular", [](const Segment & seg) { return seg.singedge_left; }, [](Segment & seg, double sing) { seg.singedge_left = sing; seg.singedge_right=sing; }) ; if(ngcore_have_numpy) { py::detail::npy_format_descriptor::register_dtype({ py::detail::field_descriptor { "nodes", offsetof(Segment, pnums), 3 * sizeof(PointIndex), py::format_descriptor::format(), py::detail::npy_format_descriptor::dtype() }, py::detail::field_descriptor { "index", offsetof(Segment, si), sizeof(int), py::format_descriptor::format(), py::detail::npy_format_descriptor::dtype() }, py::detail::field_descriptor { "edgenr", offsetof(Segment, edgenr), sizeof(int), py::format_descriptor::format(), py::detail::npy_format_descriptor::dtype() }, }); } py::class_(m, "Element0D") .def(py::init([](PointIndex vertex, int index) { Element0d * instance = new Element0d; instance->pnum = vertex; instance->index = index; return instance; }), py::arg("vertex"), py::arg("index")=1, "create point element" ) .def("__repr__", &ToString) .def_property_readonly("vertices", FunctionPointer ([](const Element0d & self) -> py::list { py::list li; li.append (py::cast(self.pnum)); return li; })) ; py::class_(m, "FaceDescriptor") .def(py::init()) .def(py::init([](int surfnr, int domin, int domout, int bc) { FaceDescriptor * instance = new FaceDescriptor(); instance->SetSurfNr(surfnr); instance->SetDomainIn(domin); instance->SetDomainOut(domout); instance->SetBCProperty(bc); return instance; }), py::arg("surfnr")=1, py::arg("domin")=1, py::arg("domout")=py::int_(0), py::arg("bc")=py::int_(0), "create facedescriptor") .def("__str__", &ToString) .def("__repr__", &ToString) .def_property("surfnr", &FaceDescriptor::SurfNr, &FaceDescriptor::SetSurfNr) .def_property("domin", &FaceDescriptor::DomainIn, &FaceDescriptor::SetDomainIn) .def_property("domout", &FaceDescriptor::DomainOut, &FaceDescriptor::SetDomainOut) .def_property("domin_singular", &FaceDescriptor::DomainInSingular, &FaceDescriptor::SetDomainInSingular) .def_property("domout_singular", &FaceDescriptor::DomainOutSingular, &FaceDescriptor::SetDomainOutSingular) .def_property("bc", &FaceDescriptor::BCProperty, &FaceDescriptor::SetBCProperty) .def_property("bcname", [](FaceDescriptor & self) -> string { return self.GetBCName(); }, [](FaceDescriptor & self, string name) { self.SetBCName(new string(name)); } // memleak ) .def_property("color", [](const FaceDescriptor& self) { auto sc = self.SurfColour(); return py::make_tuple(sc[0], sc[1], sc[2], sc[3]); }, [](FaceDescriptor& self, py::tuple col) { Vec<4> sc = 1; sc[0] = py::cast(col[0]); sc[1] = py::cast(col[1]); sc[2] = py::cast(col[2]); if(py::len(col) > 3) sc[3] = py::cast(col[3]); self.SetSurfColour(sc); } ) .def_property("transparency", [](const FaceDescriptor& self) { return self.SurfColour()[3]; }, [](FaceDescriptor& self, double val) { auto sc = self.SurfColour(); sc[3] = val; self.SetSurfColour(sc); }) ; py::implicitly_convertible< int, SurfaceElementIndex>(); PYBIND11_NUMPY_DTYPE(SurfaceElementIndex, i); ExportArray(m); py::implicitly_convertible< int, ElementIndex>(); PYBIND11_NUMPY_DTYPE(ElementIndex, i); ExportArray(m); ExportArray(m); ExportArray(m); ExportArray(m); ExportArray(m); ExportArray(m); ExportArray(m); string export_docu = "Export mesh to other file format. Supported formats are:\n"; Array export_formats; for(auto & kv : UserFormatRegister::getFormats()) { const auto e = kv.second; if(e.write) { string s = '\t'+e.format+"\t("+e.extensions[0]; for(auto & ext : e.extensions.Range(1, e.extensions.Size())) s += ", "+ext; s += ")\n"; export_formats.Append(s); } } QuickSort(export_formats); for(const auto & s : export_formats) export_docu += s; py::implicitly_convertible< int, PointIndex>(); py::class_(m, "PointGeomInfo") .def(py::init<>()) .def_readwrite("trignum", &PointGeomInfo::trignum) .def_readwrite("u", &PointGeomInfo::u) .def_readwrite("v", &PointGeomInfo::v) ; py::class_(m, "EdgePointGeomInfo") .def(py::init<>()) .def_readwrite("edgenr", &EdgePointGeomInfo::edgenr) .def_readwrite("dist", &EdgePointGeomInfo::dist) .def_readwrite("u", &EdgePointGeomInfo::u) .def_readwrite("v", &EdgePointGeomInfo::v) ; class NetgenGeometryTrampoline : public NetgenGeometry { public: using NetgenGeometry::NetgenGeometry; NetgenGeometryTrampoline() : NetgenGeometry() { static_assert( sizeof(NetgenGeometry)==sizeof(NetgenGeometryTrampoline), "Size of NetgenGeometry and NetgenGeometryTrampoline differ"); } Vec<3> GetNormal (int surfind, const Point<3> &p, const PointGeomInfo *gi) const override { py::gil_scoped_acquire gil; if (auto overload = pybind11::get_overload(this, "GetNormal")) return py::cast> (overload(surfind, p, gi)); else throw Exception ("GetNormal not implemented"); } PointGeomInfo ProjectPoint(int surfind, Point<3> & p) const override { py::gil_scoped_acquire gil; if (auto overload = pybind11::get_overload(this, "ProjectPoint")) return py::cast (overload(surfind, py::cast(p, py::return_value_policy::reference))); else throw Exception ("ProjectPoint not implemented"); } void ProjectPointEdge(int surfind, int surfind2, Point<3> & p, EdgePointGeomInfo* gi = nullptr) const override { py::gil_scoped_acquire gil; if (auto overload = pybind11::get_overload(this, "ProjectPointEdge")) overload(surfind, surfind2, py::cast(p, py::return_value_policy::reference), py::cast(gi, py::return_value_policy::reference)); throw Exception ("ProjectPointEdge not implemented"); } bool ProjectPointGI(int surfind, Point<3> & p, PointGeomInfo & gi) const override { py::gil_scoped_acquire gil; if (auto overload = pybind11::get_overload(this, "ProjectPointGI")) return py::cast (overload(surfind, p, gi)); else if (auto overload = pybind11::get_overload(this, "ProjectPoint")) return py::cast (overload(surfind, py::cast(p, py::return_value_policy::reference))); else throw Exception ("Neither ProjectPointGI nor ProjectPoint implemented"); } bool CalcPointGeomInfo(int surfind, PointGeomInfo& gi, const Point<3> & p3) const override { py::gil_scoped_acquire gil; if (auto overload = pybind11::get_overload(this, "CalcPointGeomInfo")) return py::cast (overload(surfind, py::cast(gi, py::return_value_policy::reference), p3)); else throw Exception ("CalcPointGeomInfo not implemented"); } void PointBetweenEdge(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 override { py::gil_scoped_acquire gil; if (auto overload = pybind11::get_overload(this, "PointBetweenEdge")) overload(p1, p2, secpoint, surfi1, surfi2, ap1, ap2, py::cast(newp, py::return_value_policy::reference), py::cast(newgi, py::return_value_policy::reference)); else throw Exception ("PointBetweenEdge not implemented"); } 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 override { py::gil_scoped_acquire gil; if (auto overload = pybind11::get_overload(this, "PointBetween")) overload(p1, p2, secpoint, surfi, gi1, gi2, py::cast(newp, py::return_value_policy::reference), py::cast(newgi, py::return_value_policy::reference)); else throw Exception ("PointBetween not implemented"); } Vec<3> GetTangent(const Point<3> & p, int surfi1, int surfi2, const EdgePointGeomInfo & egi) const override { py::gil_scoped_acquire gil; if (auto overload = pybind11::get_overload(this, "GetTangent")) return py::cast> (overload(p, surfi1, surfi2, egi)); throw Exception ("GetTangent not implemented"); } }; py::class_, NetgenGeometryTrampoline> (m, "NetgenGeometry", py::dynamic_attr()) .def(py::init<> ()) .def("RestrictH", &NetgenGeometry::RestrictH) ; py::class_>(m, "Mesh") // .def(py::init<>("create empty mesh")) .def(py::init( [] (int dim, NgMPI_Comm comm) { auto mesh = make_shared(); mesh->SetCommunicator(comm); mesh -> SetDimension(dim); SetGlobalMesh(mesh); // for visualization mesh -> SetGeometry (nullptr); return mesh; } ), py::arg("dim")=3, py::arg("comm")=NgMPI_Comm{} ) .def(NGSPickle()) .def_property_readonly("comm", [](const Mesh & amesh) -> NgMPI_Comm { return amesh.GetCommunicator(); }, "MPI-communicator the Mesh lives in") /* .def("__init__", [](Mesh *instance, int dim) { new (instance) Mesh(); instance->SetDimension(dim); }, py::arg("dim")=3 ) */ .def_property_readonly("_timestamp", &Mesh::GetTimeStamp) .def_property_readonly("ne", [](Mesh& m) { return m.GetNE(); }) .def_property_readonly("bounding_box", [](Mesh& m) { Point3d pmin, pmax; m.GetBox(pmin, pmax); return py::make_tuple( Point<3>(pmin),Point<3>(pmax)); }) .def("Partition", [](shared_ptr self, int numproc) { self->ParallelMetis(numproc); }, py::arg("numproc")) .def("Distribute", [](shared_ptr self, NgMPI_Comm comm) { self->SetCommunicator(comm); if(comm.Size()==1) return self; // if(MyMPI_GetNTasks(comm)==2) throw NgException("Sorry, cannot handle communicators with NP=2!"); // cout << " rank " << MyMPI_GetId(comm) << " of " << MyMPI_GetNTasks(comm) << " called Distribute " << endl; if(comm.Rank()==0) self->Distribute(); else self->SendRecvMesh(); return self; }, py::arg("comm")) .def_static("Receive", [](NgMPI_Comm comm) -> shared_ptr { auto mesh = make_shared(); mesh->SetCommunicator(comm); mesh->SendRecvMesh(); return mesh; }, py::arg("comm")) .def("Load", FunctionPointer ([](shared_ptr self, const string & filename) { auto comm = self->GetCommunicator(); int id = comm.Rank(); int ntasks = comm.Size(); auto & mesh = self; { ifstream infile(filename.c_str()); if(!infile.good()) throw NgException(string("Error opening file ") + filename); } if ( filename.find(".vol") == string::npos ) { if(ntasks>1) throw NgException("Not sure what to do with this?? Does this work with MPI??"); mesh->SetCommunicator(comm); ReadFile(*mesh,filename.c_str()); //mesh->SetGlobalH (mparam.maxh); //mesh->CalcLocalH(); return; } istream * infile = nullptr; Array buf; // for distributing geometry! int strs; if( id == 0) { if (filename.length() > 8 && filename.substr (filename.length()-8, 8) == ".vol.bin") mesh -> Load(filename); else if (filename.substr (filename.length()-3, 3) == ".gz") infile = new igzstream (filename.c_str()); else infile = new ifstream (filename.c_str()); if(infile) { mesh -> Load(*infile); // make string from rest of file (for geometry info!) // (this might be empty, in which case we take the global ng_geometry) stringstream geom_part; geom_part << infile->rdbuf(); string geom_part_string = geom_part.str(); strs = geom_part_string.size(); // buf = new char[strs]; buf.SetSize(strs); memcpy(buf.Data(), geom_part_string.c_str(), strs*sizeof(char)); delete infile; } if (ntasks > 1) { char * weightsfilename = new char [filename.size()+1]; strcpy (weightsfilename, filename.c_str()); weightsfilename[strlen (weightsfilename)-3] = 'w'; weightsfilename[strlen (weightsfilename)-2] = 'e'; weightsfilename[strlen (weightsfilename)-1] = 'i'; ifstream weightsfile(weightsfilename); delete [] weightsfilename; if (!(weightsfile.good())) { // cout << "regular distribute" << endl; mesh -> Distribute(); } else { char str[20]; bool endfile = false; int n, dummy; NgArray segment_weights; NgArray surface_weights; NgArray volume_weights; while (weightsfile.good() && !endfile) { weightsfile >> str; if (strcmp (str, "edgeweights") == 0) { weightsfile >> n; segment_weights.SetSize(n); for (int i = 0; i < n; i++) weightsfile >> dummy >> segment_weights[i]; } if (strcmp (str, "surfaceweights") == 0) { weightsfile >> n; surface_weights.SetSize(n); for (int i=0; i> dummy >> surface_weights[i]; } if (strcmp (str, "volumeweights") == 0) { weightsfile >> n; volume_weights.SetSize(n); for (int i=0; i> dummy >> volume_weights[i]; } if (strcmp (str, "endfile") == 0) endfile = true; } mesh -> Distribute(volume_weights, surface_weights, segment_weights); } } // ntasks>1 end } // id==0 end else { mesh->SendRecvMesh(); } if(ntasks>1) { // #ifdef PARALLEL /** Scatter the geometry-string (no dummy-implementation in mpi_interface) **/ /* int strs = buf.Size(); MyMPI_Bcast(strs, comm); if(strs>0) MyMPI_Bcast(buf, comm); */ comm.Bcast(buf); // #endif } shared_ptr geo; if(buf.Size()) { // if we had geom-info in the file, take it istringstream geom_infile(string((const char*)buf.Data(), buf.Size())); geo = GeometryRegister().LoadFromMeshFile(geom_infile); } if(geo!=nullptr) mesh->SetGeometry(geo); else if(ng_geometry!=nullptr) mesh->SetGeometry(ng_geometry); }),py::call_guard()) .def("Save", static_cast(&Mesh::Save),py::call_guard()) .def("Export", [] (Mesh & self, string filename, string format) { if (WriteUserFormat (format, self, filename)) throw Exception ("Nothing known about format"+format); }, py::arg("filename"), py::arg("format"), export_docu.c_str(), py::call_guard()) .def_property("dim", &Mesh::GetDimension, &Mesh::SetDimension) .def("Elements3D", static_cast&(Mesh::*)()> (&Mesh::VolumeElements), py::return_value_policy::reference) .def("Elements2D", static_cast&(Mesh::*)()> (&Mesh::SurfaceElements), py::return_value_policy::reference) .def("Elements1D", static_cast&(Mesh::*)()> (&Mesh::LineSegments), py::return_value_policy::reference) .def("Elements0D", FunctionPointer([] (Mesh & self) -> Array& { return self.pointelements; } ), py::return_value_policy::reference) .def("Points", static_cast (&Mesh::Points), py::return_value_policy::reference) .def("Coordinates", [](Mesh & self) { return py::array ( py::memoryview::from_buffer (&self.Points()[PointIndex::BASE](0), sizeof(double), py::format_descriptor::value, { self.Points().Size(), size_t(self.GetDimension()) }, { sizeof(self.Points()[PointIndex::BASE]), sizeof(double) } ) ); }) .def_property_readonly("parentelements", py::cpp_function([](Mesh & self) { return FlatArray(self.mlparentelement); }, py::keep_alive<0,1>())) .def_property_readonly("parentsurfaceelements", py::cpp_function([](Mesh & self) { return FlatArray(self.mlparentsurfaceelement); }, py::keep_alive<0,1>())) .def_property_readonly("macromesh", [](Mesh & self) { auto coarsemesh = make_shared(); *coarsemesh = *self.coarsemesh; return coarsemesh; }, "mesh before hp-refinement") .def("MacroElementNr", [](Mesh & self, int elnr, optional dim) { // cout << "hpels = " << self.hpelements->Size() << endl; // return self[ElementIndex(elnr)].GetHpElnr(); if (!dim) dim = self.GetDimension(); switch (*dim) { case 2: return (*self.hpelements)[self[SurfaceElementIndex(elnr)].GetHpElnr()].coarse_elnr; case 3: return (*self.hpelements)[self[ElementIndex(elnr)].GetHpElnr()].coarse_elnr; } throw Exception ("MacroElementNr not implemented for dim"); }, py::arg("elnr"), py::arg("dim")=nullopt, "number of macro element of element number elnr") .def("FaceDescriptor", static_cast (&Mesh::GetFaceDescriptor), py::return_value_policy::reference) .def("GetNFaceDescriptors", &Mesh::GetNFD) .def("RestrictLocalH", [](Mesh& self, const Point<3>& pnt, double maxh, int layer) { self.RestrictLocalH(pnt, maxh, layer); }, py::arg("p"), py::arg("h"), py::arg("layer")=1) .def("FaceDescriptors", // static_cast&(Mesh::*)()> (&Mesh::FaceDescriptors), &Mesh::FaceDescriptors, py::return_value_policy::reference) .def("GetNDomains", &Mesh::GetNDomains) .def("GetVolumeNeighboursOfSurfaceElement", [](Mesh & self, size_t sel) { int elnr1, elnr2; self.GetTopology().GetSurface2VolumeElement(sel+1, elnr1, elnr2); return py::make_tuple(elnr1, elnr2); }, "Returns element nrs of volume element connected to surface element, -1 if no volume element") .def("GetNCD2Names", &Mesh::GetNCD2Names) .def("__getitem__", [](const Mesh & self, PointIndex id) { return self[id]; }) .def("__getitem__", [](const Mesh & self, ElementIndex id) { return self[id]; }) .def("__getitem__", [](const Mesh & self, SurfaceElementIndex id) { return self[id]; }) .def("__getitem__", [](const Mesh & self, SegmentIndex id) { return self[id]; }) .def("__setitem__", [](Mesh & self, PointIndex id, const MeshPoint & mp) { return self[id] = mp; }) .def ("Add", [](Mesh & self, MeshPoint p) { return self.AddPoint (Point3d(p)); }) .def ("Add", [](Mesh & self, const Element & el) { return self.AddVolumeElement (el); }) .def ("Add", [](Mesh & self, const Element2d & el) { return self.AddSurfaceElement (el); }) .def ("Add", [](Mesh & self, const Segment & el, bool project_geominfo) { if (project_geominfo) { auto &p1 = self[el[0]]; auto &p2 = self[el[1]]; auto geo = self.GetGeometry(); geo->ProjectPointEdge (0,0,p1, const_cast(&el.epgeominfo[0])); geo->ProjectPointEdge (0,0,p2, const_cast(&el.epgeominfo[1])); } return self.AddSegment (el); }, py::arg("el"), py::arg("project_geominfo")=false) .def ("Add", [](Mesh & self, const Element0d & el) { return self.pointelements.Append (el); }) .def ("Add", [](Mesh & self, const FaceDescriptor & fd) { return self.AddFaceDescriptor (fd); }) .def ("AddSingularity", [](Mesh & self, PointIndex pi, double factor) { self[pi].Singularity(factor); }) .def ("AddPoints", [](Mesh & self, py::buffer b1) { static Timer timer("Mesh::AddPoints"); static Timer timercast("Mesh::AddPoints - casting"); RegionTimer reg(timer); timercast.Start(); // casting from here: https://github.com/pybind/pybind11/issues/1908 auto b = b1.cast>(); timercast.Stop(); py::buffer_info info = b.request(); // cout << "data format = " << info.format << endl; if (info.ndim != 2) throw std::runtime_error("AddPoints needs buffer of dimension 2"); // if (info.format != py::format_descriptor::format()) // throw std::runtime_error("AddPoints needs buffer of type double"); if (info.strides[0] != sizeof(double)*info.shape[1]) throw std::runtime_error("AddPoints needs packed array"); double * ptr = static_cast (info.ptr); self.Points().SetAllocSize(self.Points().Size()+info.shape[0]); if (info.shape[1]==2) for ([[maybe_unused]] auto i : Range(info.shape[0])) { self.AddPoint (Point<3>(ptr[0], ptr[1], 0)); ptr += 2; } if (info.shape[1]==3) for ([[maybe_unused]] auto i : Range(info.shape[0])) { self.AddPoint (Point<3>(ptr[0], ptr[1], ptr[2])); ptr += 3; } }) .def ("AddElements", [](Mesh & self, int dim, int index, py::buffer b1, int base, bool project_geometry) { static Timer timer("Mesh::AddElements"); static Timer timercast("Mesh::AddElements casting"); RegionTimer reg(timer); timercast.Start(); auto b = b1.cast>(); timercast.Stop(); py::buffer_info info = b.request(); if (info.ndim != 2) throw std::runtime_error("AddElements needs buffer of dimension 2"); // if (info.format != py::format_descriptor::format()) // throw std::runtime_error("AddPoints needs buffer of type int"); int * ptr = static_cast (info.ptr); if (dim == 1) { // ELEMENT_TYPE type; int np = info.shape[1]; self.LineSegments().SetAllocSize(self.LineSegments().Size()+info.shape[0]); for ([[maybe_unused]] auto i : Range(info.shape[0])) { Segment el; for (int j = 0; j < np; j++) el[j] = ptr[j]+PointIndex::BASE-base; el.si = index; self.AddSegment(el); ptr += info.strides[0]/sizeof(int); } } if (dim == 2) { ELEMENT_TYPE type; int np = info.shape[1]; switch (np) { case 3: type = TRIG; break; case 4: type = QUAD; break; case 6: type = TRIG6; break; case 8: type = QUAD8; break; default: throw Exception("unsupported 2D element with "+ToString(np)+" points"); } self.SurfaceElements().SetAllocSize(self.SurfaceElements().Size()+info.shape[0]); for ([[maybe_unused]] auto i : Range(info.shape[0])) { Element2d el(type); for (int j = 0; j < np; j++) el[j] = ptr[j]+PointIndex::BASE-base; el.SetIndex(index); if(project_geometry) { // find some point in the mid of trig/quad for // quick + stable uv-projection of all points auto startp = Center(self[el[0]], self[el[1]], self[el[2]]); int surfnr = self.GetFaceDescriptor(index).SurfNr(); PointGeomInfo gi = self.GetGeometry()->ProjectPoint(surfnr, startp); for(auto i : Range(np)) { el.GeomInfo()[i] = gi; self.GetGeometry()->ProjectPointGI(surfnr, self[el[i]], el.GeomInfo()[i]); } } self.AddSurfaceElement (el); ptr += info.strides[0]/sizeof(int); } } if (dim == 3) { ELEMENT_TYPE type; int np = info.shape[1]; switch (np) { case 4: type = TET; break; case 5: type = PYRAMID; break; case 6: type = PRISM; break; case 8: type = HEX; break; case 10: type = TET10; break; default: throw Exception("unsupported 3D element with "+ToString(np)+" points"); } self.VolumeElements().SetAllocSize(self.VolumeElements().Size()+info.shape[0]); for ([[maybe_unused]] auto i : Range(info.shape[0])) { Element el(type); for (int j = 0; j < np;j ++) el[j] = ptr[j]+PointIndex::BASE-base; el.SetIndex(index); self.AddVolumeElement (el); ptr += info.strides[0]/sizeof(int); } } }, py::arg("dim"), py::arg("index"), py::arg("data"), py::arg("base")=0, py::arg("project_geometry")=false) .def ("DeleteSurfaceElement", [](Mesh & self, SurfaceElementIndex i) { return self.Delete(i); }) .def ("Compress", [](Mesh & self) { return self.Compress (); } ,py::call_guard()) .def ("AddRegion", [] (Mesh & self, string name, int dim) -> int { auto & regionnames = self.GetRegionNamesCD(self.GetDimension()-dim); regionnames.Append (new string(name)); int idx = regionnames.Size(); if (dim == 2) { FaceDescriptor fd; fd.SetBCName(regionnames.Last()); fd.SetBCProperty(idx); self.AddFaceDescriptor(fd); } return idx; }, py::arg("name"), py::arg("dim")) .def ("GetRegionNames", [] (Mesh & self, optional optdim, optional optcodim) { int codim; if (optdim) codim = self.GetDimension() - *optdim; else if (optcodim) codim = *optcodim; else throw Exception("either 'dim' or 'codim' must be specified"); Array & codimnames = self.GetRegionNamesCD (codim); std::vector names; for (auto name : codimnames) { if (name) names.push_back(*name); else names.push_back(""); } return names; }, py::arg("dim")=nullopt, py::arg("codim")=nullopt) .def ("SetBCName", &Mesh::SetBCName) .def ("GetBCName", FunctionPointer([](Mesh & self, int bc)->string { return self.GetBCName(bc); })) .def ("SetMaterial", &Mesh::SetMaterial) .def ("GetMaterial", FunctionPointer([](Mesh & self, int domnr) { return string(self.GetMaterial(domnr)); })) .def ("GetCD2Name", &Mesh::GetCD2Name) .def ("SetCD2Name", &Mesh::SetCD2Name) .def ("GetCD3Name", &Mesh::GetCD3Name) .def ("SetCD3Name", &Mesh::SetCD3Name) .def ("SplitFacesByAdjacentDomains", &Mesh::SplitFacesByAdjacentDomains) .def ("GetSubMesh", &Mesh::GetSubMesh, py::arg("domains")="", py::arg("faces")="") .def("GetIdentifications", [](Mesh & self) -> py::list { py::list points; for(const auto& pair : self.GetIdentifications().GetIdentifiedPoints()) { // py::tuple pnts = py::make_tuple(pair.first.I1(), pair.first.I2()); auto [pi1, pi2] = get<0> (pair.first); py::tuple pnts = py::make_tuple(pi1, pi2); points.append(pnts); } return points; }) .def ("AddPointIdentification", [](Mesh & self, py::object pindex1, py::object pindex2, int identnr, Identifications::ID_TYPE type) { if(py::extract(pindex1).check() && py::extract(pindex2).check()) { self.GetIdentifications().Add (py::extract(pindex1)(), py::extract(pindex2)(), identnr); self.GetIdentifications().SetType(identnr, type); // type = 2 ... periodic } }, //py::default_call_policies(), py::arg("pid1"), py::arg("pid2"), py::arg("identnr"), py::arg("type")=Identifications::PERIODIC) .def("IdentifyPeriodicBoundaries", &Mesh::IdentifyPeriodicBoundaries, py::arg("identification_name"), py::arg("face1"), py::arg("mapping"), py::arg("point_tolerance") = -1.) .def("GetCurveOrder", [] (Mesh & self) { return self.GetCurvedElements().GetOrder(); }) .def("GetNrIdentifications", [](Mesh& self) { return self.GetIdentifications().GetMaxNr(); }) .def ("CalcLocalH", &Mesh::CalcLocalH) .def ("SetMaxHDomain", [] (Mesh& self, py::list maxhlist) { NgArray maxh; for(auto el : maxhlist) maxh.Append(py::cast(el)); self.SetMaxHDomain(maxh); }) .def ("GenerateVolumeMesh", [](Mesh & self, MeshingParameters* pars, py::kwargs kwargs) { MeshingParameters mp; if(pars) mp = *pars; CreateMPfromKwargs(mp, kwargs); py::gil_scoped_release gil_release; MeshVolume (mp, self); OptimizeVolume (mp, self); }, py::arg("mp")=nullptr, meshingparameter_description.c_str()) .def ("OptimizeVolumeMesh", [](Mesh & self, MeshingParameters* pars) { MeshingParameters mp; if(pars) mp = *pars; else mp.optsteps3d = 5; OptimizeVolume (mp, self); }, py::arg("mp"), py::call_guard()) .def("SetLocalH",[](Mesh& self, shared_ptr localh, int layer) { self.SetLocalH(localh, layer); }, py::arg("localh"), py::arg("layer")=1) .def("GetLocalH", &Mesh::GetLocalH) .def ("OptimizeMesh2d", [](Mesh & self, MeshingParameters* pars, int faceindex) { self.CalcLocalH(0.5); MeshingParameters mp; if(pars) mp = *pars; else mp.optsteps2d = 5; if(!self.GetGeometry()) throw Exception("Cannot optimize surface mesh without geometry!"); Optimize2d (self, mp, faceindex); }, py::arg("mp")=nullptr, py::arg("faceindex")=0, py::call_guard()) .def ("Refine", FunctionPointer ([](Mesh & self, bool adaptive) { if (!adaptive) { self.GetGeometry()->GetRefinement().Refine(self); self.UpdateTopology(); } else { BisectionOptions biopt; biopt.usemarkedelements = 1; biopt.refine_p = 0; biopt.refine_hp = 0; /* biopt.onlyonce = onlyonce; if (reftype == NG_REFINE_P) biopt.refine_p = 1; if (reftype == NG_REFINE_HP) biopt.refine_hp = 1; */ self.GetGeometry()->GetRefinement().Bisect (self, biopt); self.UpdateTopology(); self.GetCurvedElements().SetIsHighOrder (false); } }), py::arg("adaptive")=false, py::call_guard()) .def("ZRefine", &Mesh::ZRefine) .def("Split2Tets", &Mesh::Split2Tets) .def ("SplitAlfeld", FunctionPointer ([](Mesh & self) { NgLock meshlock (self.MajorMutex(), true); Refinement & ref = const_cast (self.GetGeometry()->GetRefinement()); ::netgen::HPRefinement (self, &ref, SPLIT_ALFELD, 1, 0.5, true, true); } ), py::call_guard()) .def ("SplitPowellSabin", FunctionPointer ([](Mesh & self) { NgLock meshlock (self.MajorMutex(), true); Refinement & ref = const_cast (self.GetGeometry()->GetRefinement()); ::netgen::HPRefinement (self, &ref, SPLIT_POWELL, 1, 0.5, true, true); } ), py::call_guard()) .def ("SecondOrder", [](Mesh & self) { self.GetGeometry()->GetRefinement().MakeSecondOrder(self); }) .def ("Curve", [](Mesh & self, int order) { self.BuildCurvedElements(order); }) .def ("CalcElementMapping", [](Mesh & self, py::buffer refpts1, py::buffer physpts1) { auto refpts = refpts1.cast>(); auto physpts = physpts1.cast>(); py::buffer_info ref_info = refpts.request(); py::buffer_info phys_info = physpts.request(); double * ref_ptr = static_cast (ref_info.ptr); double * phys_ptr = static_cast (phys_info.ptr); if (ref_info.ndim != 2) throw std::runtime_error("Reference points need buffer of dimension 2"); if (phys_info.ndim != 3) throw std::runtime_error("Physical points need buffer of dimension 3"); /* cout << "ref_info.shape = " << FlatArray(2, &ref_info.shape[0]) << endl; cout << "ref_info.stride = " << FlatArray(2, &ref_info.strides[0]) << endl; cout << "phys_info.shape = " << FlatArray(3, &phys_info.shape[0]) << endl; cout << "phys_info.stride = " << FlatArray(3, &phys_info.strides[0]) << endl; */ size_t npts = ref_info.shape[0]; size_t dim = ref_info.shape[1]; // size_t nel = phys_info.shape[0]; size_t dim_phys = phys_info.shape[2]; size_t stride_refpts = ref_info.strides[0]/sizeof(double); size_t stride_physels = phys_info.strides[0]/sizeof(double); size_t stride_physpts = phys_info.strides[1]/sizeof(double); auto & curved = self.GetCurvedElements(); if (dim == 2) // mapping of 2D elements { for (SurfaceElementIndex i = 0; i < self.GetNSE(); i++) for (size_t j = 0; j < npts; j++) { Point<2> xref; Point<3> xphys; for (size_t k = 0; k < 2; k++) xref(k) = ref_ptr[j*stride_refpts+k]; curved.CalcSurfaceTransformation(xref, i, xphys); for (size_t k = 0; k < dim_phys; k++) phys_ptr[i*stride_physels+j*stride_physpts+k] = xphys(k); } } if (dim == 3) // mapping of 3D elements { for (ElementIndex i = 0; i < self.GetNE(); i++) for (size_t j = 0; j < npts; j++) { Point<3> xref; Point<3> xphys; for (size_t k = 0; k < 3; k++) xref(k) = ref_ptr[j*stride_refpts+k]; curved.CalcElementTransformation(xref, i, xphys); for (size_t k = 0; k < 3; k++) phys_ptr[i*stride_physels+j*stride_physpts+k] = xphys(k); } } }) .def ("GetGeometry", [](Mesh & self) { return self.GetGeometry(); }) .def ("SetGeometry", [](Mesh & self, shared_ptr geo) { self.SetGeometry(geo); }) /* .def ("SetGeometry", FunctionPointer ([](Mesh & self, shared_ptr geo) { self.SetGeometry(geo); })) */ .def ("BuildSearchTree", &Mesh::BuildElementSearchTree,py::call_guard(), py::arg("dim")=3) .def ("BoundaryLayer2", GenerateBoundaryLayer2, py::arg("domain"), py::arg("thicknesses"), py::arg("make_new_domain")=true, py::arg("boundaries")=Array{}) .def ("BoundaryLayer", [](Mesh & self, variant> boundary, variant> thickness, optional>> material, variant> domain, bool outside, optional>> project_boundaries, bool grow_edges, bool limit_growth_vectors, bool sides_keep_surfaceindex, bool disable_curving) { throw Exception("Call syntax has changed! Pass a list of BoundaryLayerParameters to the GenerateMesh call instead: \ngeo.GenerateMesh(..., boundary_layers=[BoundaryLayerParameters(...), BoundaryLayerParameters(...), ...])"); BoundaryLayerParameters blp; blp.boundary = boundary; blp.thickness = thickness; blp.new_material = material; blp.domain = domain; blp.outside = outside; blp.project_boundaries = project_boundaries; blp.grow_edges = grow_edges; blp.limit_growth_vectors = limit_growth_vectors; blp.sides_keep_surfaceindex = sides_keep_surfaceindex; blp.disable_curving = disable_curving; GenerateBoundaryLayer (self, blp); self.UpdateTopology(); }, py::arg("boundary"), py::arg("thickness"), py::arg("material")=nullopt, py::arg("domains") = ".*", py::arg("outside") = false, py::arg("project_boundaries")=nullopt, py::arg("grow_edges")=true, py::arg("limit_growth_vectors") = false, py::arg("sides_keep_surfaceindex")=false, py::arg("disable_curving")=true, "Add boundary layer to mesh. see help(BoundaryLayerParameters) for details.") .def_static ("EnableTableClass", [] (string name, bool set) { MeshTopology::EnableTableStatic(name, set); }, py::arg("name"), py::arg("set")=true) .def ("EnableTable", [] (Mesh & self, string name, bool set) { const_cast(self.GetTopology()).EnableTable(name, set); }, py::arg("name"), py::arg("set")=true) .def ("Scale", [](Mesh & self, double factor) { for(auto & pnt : self.Points()) pnt.Scale(factor); }) .def ("Copy", [](Mesh & self) { auto m2 = make_shared (); *m2 = self; return m2; }) .def ("CalcMinMaxAngle", [](Mesh & self, double badel_limit) { double values[4]; self.CalcMinMaxAngle (badel_limit, values); py::dict res; res["trig"] = py::make_tuple( values[0], values[1] ); res["tet"] = py::make_tuple( values[2], values[3] ); return res; }, py::arg("badelement_limit")=175.0) .def ("Update", [](Mesh & self) { self.SetNextTimeStamp(); }) .def ("UpdateTopology", [](Mesh & self) { self.CalcSurfacesOfNode(); self.RebuildSurfaceElementLists(); self.UpdateTopology(); }) .def ("CalcTotalBadness", &Mesh::CalcTotalBad) .def ("GetQualityHistogram", &Mesh::GetQualityHistogram) .def("Mirror", &Mesh::Mirror) .def("_getVertices", [](Mesh & self) { // std::vector verts(3*self.GetNV()); Array verts(3*self.GetNV()); ParallelForRange( self.GetNV(), [&](auto myrange) { const auto & points = self.Points(); for(auto i : myrange) { auto p = points[PointIndex::BASE+i]; auto * v = &verts[3*i]; for(auto k : Range(3)) v[k] = p[k]; } }); return verts; }) .def("_getSegments", [](Mesh & self) { // std::vector output; // output.resize(2*self.GetNSeg()); Array output(2*self.GetNSeg()); ParallelForRange( self.GetNSeg(), [&](auto myrange) { const auto & segs = self.LineSegments(); for(auto i : myrange) { const auto & seg = segs[i]; for(auto k : Range(2)) output[2*i+k] = seg[k]-IndexBASE(); } }); return output; }) .def("_getWireframe", [](Mesh & self) { const auto & topo = self.GetTopology(); size_t n = topo.GetNEdges(); /* std::vector output; output.resize(2*n); */ Array output(2*n); ParallelForRange( n, [&](auto myrange) { for(auto i : myrange) { // PointIndex p0,p1; // topo.GetEdgeVertices(i+1, p0, p1); auto [p0,p1] = topo.GetEdgeVertices(i); output[2*i] = p0-IndexBASE(); output[2*i+1] = p1-IndexBASE(); } }); return output; }) .def("_get2dElementsAsTriangles", [](Mesh & self) { /* std::vector trigs; trigs.resize(3*self.GetNSE()); */ Array trigs(3*self.GetNSE()); ParallelForRange( self.GetNSE(), [&](auto myrange) { const auto & surfels = self.SurfaceElements(); for(auto i : myrange) { const auto & sel = surfels[i]; auto * trig = &trigs[3*i]; for(auto k : Range(3)) trig[k] = sel[k]-IndexBASE(); // todo: quads (store the second trig in thread-local extra array, merge them at the end (mutex) } }); return trigs; }) .def("_get3dElementsAsTets", [](Mesh & self) { // std::vector tets; // tets.resize(4*self.GetNE()); Array tets(4*self.GetNE()); ParallelForRange( self.GetNE(), [&](auto myrange) { const auto & els = self.VolumeElements(); for(auto i : myrange) { const auto & el = els[i]; auto * trig = &tets[4*i]; for(auto k : Range(4)) trig[k] = el[k]-IndexBASE(); // todo: prisms etc (store the extra tets in thread-local extra array, merge them at the end (mutex) } }); return tets; }) ; string import_docu = "Import mesh from other file format. Leaving format parameter empty guesses based on file extension.\nSupported formats are:\n"; UserFormatRegister::IterateFormats([&](auto & e) { string s = '\t'+e.format+"\t("+e.extensions[0]; for(auto & ext : e.extensions.Range(1, e.extensions.Size())) s += ", "+ext; s += ")\n"; import_docu += s; }, true); m.def("ReadMedit", [](const string& filename) { map, int> index_map; auto mesh = make_shared(); ReadMeditFormat(*mesh, filename, index_map); return py::make_tuple(mesh, index_map); }); m.def("WriteMedit", [](const Mesh& mesh, const string& filename) { map, int> index_map; WriteMeditFormat(mesh, filename, index_map); return index_map; }); m.def("ImportMesh", [](const string& filename, const string & format) { auto mesh = make_shared(); ReadUserFormat(*mesh, filename, format); return mesh; }, py::arg("filename"), py::arg("format")="", import_docu.c_str()); py::enum_(m,"MeshingStep") .value("ANALYSE", MESHCONST_ANALYSE) .value("MESHEDGES", MESHCONST_MESHEDGES) .value("MESHSURFACE", MESHCONST_OPTSURFACE) .value("MESHVOLUME", MESHCONST_OPTVOLUME) ; typedef MeshingParameters MP; auto mp = py::class_ (m, "MeshingParameters") .def(py::init<>()) .def(py::init([](MeshingParameters* other, py::kwargs kwargs) { MeshingParameters mp; if(other) mp = *other; CreateMPfromKwargs(mp, kwargs, false); return mp; }), py::arg("mp")=nullptr, meshingparameter_description.c_str()) .def("__str__", &ToString) .def("RestrictH", [](MP & mp, double x, double y, double z, double h, int layer) { mp.meshsize_points.Append ( MeshingParameters::MeshSizePoint(Point<3> (x,y,z), h, layer)); }, py::arg("x"), py::arg("y"), py::arg("z"), py::arg("h"), py::arg("layer")=1 ) .def("RestrictH", [](MP & mp, const Point<3>& p, double h, int layer) { mp.meshsize_points.Append ({p, h, layer}); }, py::arg("p"), py::arg("h"), py::arg("layer")=1) .def("RestrictHLine", [](MP& mp, const Point<3>& p1, const Point<3>& p2, double maxh, int layer) { int steps = int(Dist(p1, p2) / maxh) + 2; auto v = p2 - p1; for (int i = 0; i <= steps; i++) { mp.meshsize_points.Append({p1 + double(i)/steps * v, maxh, layer}); } }, py::arg("p1"), py::arg("p2"), py::arg("maxh"), py::arg("layer")=1) ; m.def("SetTestoutFile", FunctionPointer ([] (const string & filename) { delete testout; testout = new ofstream (filename); })); m.def("SetMessageImportance", FunctionPointer ([] (int importance) { int old = printmessage_importance; printmessage_importance = importance; return old; })); py::class_ (m, "_DebugParameters") .def_readwrite("debugoutput", &DebugParameters::debugoutput) .def_readwrite("slowchecks", &DebugParameters::slowchecks) .def_readwrite("haltsuccess", &DebugParameters::haltsuccess) .def_readwrite("haltnosuccess", &DebugParameters::haltnosuccess) .def_readwrite("haltlargequalclass", &DebugParameters::haltlargequalclass) .def_readwrite("haltsegment", &DebugParameters::haltsegment) .def_readwrite("haltnode", &DebugParameters::haltnode) .def_readwrite("haltsegmentp1", &DebugParameters::haltsegmentp1) .def_readwrite("haltsegmentp2", &DebugParameters::haltsegmentp2) .def_readwrite("haltexistingline", &DebugParameters::haltexistingline) .def_readwrite("haltoverlap", &DebugParameters::haltoverlap) .def_readwrite("haltface", &DebugParameters::haltface) .def_readwrite("haltfacenr", &DebugParameters::haltfacenr) .def_readwrite("write_mesh_on_error", &DebugParameters::write_mesh_on_error) ; m.attr("debugparam") = py::cast(&debugparam); py::class_(m, "BoundaryLayerParameters") .def(py::init([]( std::variant> boundary, std::variant> thickness, std::optional>> new_material, std::variant> domain, bool outside, std::optional>> project_boundaries, bool grow_edges, bool limit_growth_vectors, std::optional sides_keep_surfaceindex, bool disable_curving) { BoundaryLayerParameters blp; blp.boundary = boundary; blp.thickness = thickness; blp.new_material = new_material; blp.domain = domain; blp.outside = outside; blp.project_boundaries = project_boundaries; blp.grow_edges = grow_edges; blp.limit_growth_vectors = limit_growth_vectors; blp.sides_keep_surfaceindex = sides_keep_surfaceindex; blp.disable_curving = disable_curving; return blp; }), py::arg("boundary"), py::arg("thickness"), py::arg("new_material")=nullopt, py::arg("domain") = ".*", py::arg("outside") = false, py::arg("project_boundaries")=nullopt, py::arg("grow_edges")=true, py::arg("limit_growth_vectors") = false, py::arg("sides_keep_surfaceindex")=nullopt, py::arg("disable_curving")=true, R"delimiter( Add boundary layer to mesh. Parameters ---------- boundary : string or int Boundary name or number. thickness : float or List[float] Thickness of boundary layer(s). material : str or List[str] Material name of boundary layer(s). domain : str or int Regexp for domain boundarylayer is going into. outside : bool = False If true add the layer on the outside grow_edges : bool = False Grow boundary layer over edges. project_boundaries : Optional[str] = None Project boundarylayer to these boundaries if they meet them. Set to boundaries that meet boundarylayer at a non-orthogonal edge and layer-ending should be projected to that boundary. )delimiter") .def(py::init([]( const py::dict & d ) { try { // Call other constructor with named arguments by unpacking the dictionary py::object cls = py::type::of(); return cls(**d).cast(); } catch (py::error_already_set & e) { cerr << "Error creating BoundaryLayerParameters from dict:" << endl; cerr << e.what() << endl; throw; } })) .def_readwrite("boundary", &BoundaryLayerParameters::boundary) .def_readwrite("thickness", &BoundaryLayerParameters::thickness) .def_readwrite("new_material", &BoundaryLayerParameters::new_material) .def_readwrite("domain", &BoundaryLayerParameters::domain) .def_readwrite("outside", &BoundaryLayerParameters::outside) .def_readwrite("project_boundaries", &BoundaryLayerParameters::project_boundaries) .def_readwrite("grow_edges", &BoundaryLayerParameters::grow_edges) .def_readwrite("limit_growth_vectors", &BoundaryLayerParameters::limit_growth_vectors) .def_readwrite("sides_keep_surfaceindex", &BoundaryLayerParameters::sides_keep_surfaceindex) .def_readwrite("disable_curving", &BoundaryLayerParameters::disable_curving) ; py::implicitly_convertible(); #ifdef NG_CGNS m.def("ReadCGNSFile", &ReadCGNSFile, py::arg("filename"), py::arg("base")=1, "Read mesh and solution vectors from CGNS file"); m.def("WriteCGNSFile", &WriteCGNSFile, py::arg("mesh"), py::arg("filename"), py::arg("names"), py::arg("values"), py::arg("locations"), R"(Write mesh and solution vectors to CGNS file, possible values for locations: Vertex = 0 EdgeCenter = 1 FaceCenter = 2 CellCenter = 3 )"); #endif // NG_CGNS py::class_> (m, "SurfaceGeometry") .def(py::init<>()) .def(py::init([](py::object pyfunc) { std::function (Point<2>)> func = [pyfunc](Point<2> p) { py::gil_scoped_acquire aq; py::tuple pyres = py::extract(pyfunc(p[0],p[1],0.0)) (); return Vec<3>(py::extract(pyres[0])(),py::extract(pyres[1])(),py::extract(pyres[2])()); }; auto geo = make_shared(func); return geo; }), py::arg("mapping")) .def(NGSPickle()) .def("GenerateMesh", [](shared_ptr geo, bool quads, int nx, int ny, bool flip_triangles, py::list py_bbbpts, py::list py_bbbnames, py::list py_hppnts, py::dict/*list*/ py_hpbnd, py::dict py_layers) { if (py::len(py_bbbpts) != py::len(py_bbbnames)) throw Exception("In SurfaceGeometry::GenerateMesh bbbpts and bbbnames do not have same lengths."); Array> bbbpts(py::len(py_bbbpts)); Array bbbname(py::len(py_bbbpts)); Array> hppnts(py::len(py_hppnts)); Array hppntsfac(py::len(py_hppnts)); Array hpbnd(py::len(py_hpbnd)); Array hpbndfac(py::len(py_hpbnd)); for(int i = 0; i(py_bbbpts[i])(); bbbpts[i] = Point<3>(py::extract(pnt[0])(),py::extract(pnt[1])(),py::extract(pnt[2])()); bbbname[i] = py::extract(py_bbbnames[i])(); } for(int i = 0; i(py_hppnts[i])(); hppnts[i] = Point<3>(py::extract(pnt[0])(),py::extract(pnt[1])(),py::extract(pnt[2])()); hppntsfac[i] = py::extract(pnt[3])(); } int ii=0; for(auto val : py_hpbnd) { hpbnd[ii] = py::cast(val.first); hpbndfac[ii] = py::cast(val.second); ii++; } Array layer_thickness[4]; bool layer_quad = false; for(auto val : py_layers) { int index = -1; if (py::cast(val.first) == "left") index = 0; else if (py::cast(val.first) == "top") index = 3; else if (py::cast(val.first) == "right") index = 2; else if (py::cast(val.first) == "bottom") index = 1; else if (py::cast(val.first) == "quads") layer_quad = py::cast(val.second); else throw Exception("Unknown parameter " + string(py::cast(val.first))); if (index < 0) continue; auto list = py::cast(val.second); layer_thickness[index] = Array(py::len(list)); for (size_t i = 0; i < py::len(list); i++) layer_thickness[index][i] = py::cast(list[i]); } auto mesh = make_shared(); SetGlobalMesh (mesh); mesh->SetGeometry(geo); ng_geometry = geo; auto result = geo->GenerateStructuredMesh (mesh, quads, nx, ny, flip_triangles, bbbpts, bbbname, hppnts, hppntsfac, hpbnd, hpbndfac, layer_thickness, layer_quad); if(result != 0) throw Exception("SurfaceGeometry: Meshing failed!"); return mesh; }, py::arg("quads")=true, py::arg("nx")=10, py::arg("ny")=10, py::arg("flip_triangles")=false, py::arg("bbbpts")=py::list(), py::arg("bbbnames")=py::list(), py::arg("hppnts")=py::list(), py::arg("hpbnd")=py::dict(), py::arg("boundarylayer")=py::dict());/*, R"raw_string( Generate a structured 2D surface mesh Parameters: quads : bool If True, a quadrilateral mesh is generated. If False, the quads are split to triangles. nx : int Number of cells in x-direction. ny : int Number of cells in y-direction. flip_triangles : bool If set to True together with quads=False the quads are cut the other way round bbbpts : list List of points which should be handled as BBBND and are named with bbbnames. The mesh must be constructed in such a way that the bbbpts coincide with generated points. bbbnames : list List of bbbnd names as strings. Size must coincide with size of bbbpts. hppnts : list If not None it expects a list of the form [ (px1,py1,pz1, hpref1), (px2,py2,pz2, hpref2), ... ] where px,py,pz are the point coordinates which have to be resolved in the mesh and hpref the refinement factor. hpbnd : dict If not None it expects a dictionary of the form {"boundaryname" : hpref } where boundaryname in [left, right, top, bottom] and hpref the refinement factor. boundarylayer : dict If not None it expects a dictionary of the form { "boundaryname" : [t1,...,tn], "quads" : False } where ti denote the thickness of layer i. The number of layers are included in nx/ny. After the layers are placed the remaining number of cells are used to divide the remaining grid uniformly. If quads are set to True quadrilaterals are used inside the boundarylayer. If set False the value of "quads" of the function call is used. )raw_string");*/ ; py::class_ (m, "ClearSolutionClass") .def(py::init<>()) ; m.def("SetParallelPickling", [](bool par) { parallel_pickling = par; }); m.def ("_Redraw", ([](bool blocking, double fr) { static auto last_time = std::chrono::system_clock::now()-std::chrono::seconds(10); auto now = std::chrono::system_clock::now(); double elapsed = std::chrono::duration(now-last_time).count(); if (blocking || elapsed * fr > 1) { Ng_Redraw(blocking); last_time = std::chrono::system_clock::now(); return true; } return false; }), py::arg("blocking")=false, py::arg("fr") = 25, R"raw_string( Redraw all Parameters: blocking : bool input blocking fr : double input framerate )raw_string"); } PYBIND11_MODULE(libmesh, m) { ExportNetgenMeshing(m); } #endif ================================================ FILE: libsrc/meshing/python_mesh.hpp ================================================ #ifndef NETGEN_MESHING_PYTHON_MESH_HPP #define NETGEN_MESHING_PYTHON_MESH_HPP #include #include "meshing.hpp" namespace netgen { // TODO: Clarify a lot of these parameters static string meshingparameter_description = R"delimiter( Meshing Parameters ------------------- maxh: float = 1e10 Global upper bound for mesh size. grading: float = 0.3 Mesh grading how fast the local mesh size can change. meshsizefilename: str = None Load meshsize from file. Can set local mesh size for points and along edges. File must have the format: nr_points x1, y1, z1, meshsize x2, y2, z2, meshsize ... xn, yn, zn, meshsize nr_edges x11, y11, z11, x12, y12, z12, meshsize ... xn1, yn1, zn1, xn2, yn2, zn2, meshsize segmentsperedge: float = 1. Minimal number of segments per edge. quad_dominated: bool = False Quad-dominated surface meshing. blockfill: bool = True Do fast blockfilling. filldist: float = 0.1 Block fill up to distance delaunay: bool = True Use delaunay meshing. delaunay2d : bool = True Use delaunay meshing for 2d geometries. Optimization Parameters ----------------------- optimize3d: str = "cmdmustm" 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 optsteps3d: int = 3 Number of 3d optimization steps. optimize2d: str = "smcmSmcmSmcm" 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 optsteps2d: int = 3 Number of 2d optimization steps. elsizeweight: float = 0.2 Weight of element size w.r.t. element shape in optimization. )delimiter"; inline void CreateMPfromKwargs(MeshingParameters& mp, py::kwargs kwargs, bool throw_if_not_all_parsed=true) { if(kwargs.contains("optimize3d")) mp.optimize3d = py::cast(kwargs.attr("pop")("optimize3d")); if(kwargs.contains("optsteps3d")) mp.optsteps3d = py::cast(kwargs.attr("pop")("optsteps3d")); if(kwargs.contains("optimize2d")) mp.optimize2d = py::cast(kwargs.attr("pop")("optimize2d")); if(kwargs.contains("optsteps2d")) mp.optsteps2d = py::cast(kwargs.attr("pop")("optsteps2d")); if(kwargs.contains("opterrpow")) mp.opterrpow = py::cast(kwargs.attr("pop")("opterrpow")); if(kwargs.contains("blockfill")) mp.blockfill = py::cast(kwargs.attr("pop")("blockfill")); if(kwargs.contains("filldist")) mp.filldist = py::cast(kwargs.attr("pop")("filldist")); if(kwargs.contains("safety")) mp.safety = py::cast(kwargs.attr("pop")("safety")); if(kwargs.contains("relinnersafety")) mp.relinnersafety = py::cast(kwargs.attr("pop")("relinnersafety")); if(kwargs.contains("uselocalh")) mp.uselocalh = py::cast(kwargs.attr("pop")("uselocalh")); if(kwargs.contains("grading")) mp.grading = py::cast(kwargs.attr("pop")("grading")); if(kwargs.contains("delaunay")) mp.delaunay = py::cast(kwargs.attr("pop")("delaunay")); if(kwargs.contains("delaunay2d")) mp.delaunay2d = py::cast(kwargs.attr("pop")("delaunay2d")); if(kwargs.contains("maxh")) mp.maxh = py::cast(kwargs.attr("pop")("maxh")); if(kwargs.contains("minh")) mp.minh = py::cast(kwargs.attr("pop")("minh")); if(kwargs.contains("meshsizefilename")) mp.meshsizefilename = py::cast(kwargs.attr("pop")("meshsizefilename")); if(kwargs.contains("startinsurface")) mp.startinsurface = py::cast(kwargs.attr("pop")("startinsurface")); if(kwargs.contains("checkoverlap")) mp.checkoverlap = py::cast(kwargs.attr("pop")("checkoverlap")); if(kwargs.contains("checkoverlappingboundary")) mp.checkoverlappingboundary = py::cast(kwargs.attr("pop")("checkoverlappingboundary")); if(kwargs.contains("checkchartboundary")) mp.checkchartboundary = py::cast(kwargs.attr("pop")("checkchartboundary")); if(kwargs.contains("curvaturesafety")) mp.curvaturesafety = py::cast(kwargs.attr("pop")("curvaturesafety")); if(kwargs.contains("segmentsperedge")) mp.segmentsperedge = py::cast(kwargs.attr("pop")("segmentsperedge")); if(kwargs.contains("parthread")) mp.parthread = py::cast(kwargs.attr("pop")("parthread")); if(kwargs.contains("elsizeweight")) mp.elsizeweight = py::cast(kwargs.attr("pop")("elsizeweight")); if(kwargs.contains("perfstepsstart")) mp.perfstepsstart = py::cast(kwargs.attr("pop")("perfstepsstart")); if(kwargs.contains("perfstepsend")) mp.perfstepsend = py::cast(kwargs.attr("pop")("perfstepsend")); if(kwargs.contains("giveuptol2d")) mp.giveuptol2d = py::cast(kwargs.attr("pop")("giveuptol2d")); if(kwargs.contains("giveuptol")) mp.giveuptol = py::cast(kwargs.attr("pop")("giveuptol")); if(kwargs.contains("giveuptolopenquads")) mp.giveuptolopenquads = py::cast(kwargs.attr("pop")("giveuptolopenquads")); if(kwargs.contains("maxoutersteps")) mp.maxoutersteps = py::cast(kwargs.attr("pop")("maxoutersteps")); if(kwargs.contains("starshapeclass")) mp.starshapeclass = py::cast(kwargs.attr("pop")("starshapeclass")); if(kwargs.contains("baseelnp")) mp.baseelnp = py::cast(kwargs.attr("pop")("baseelnp")); if(kwargs.contains("sloppy")) mp.sloppy = py::cast(kwargs.attr("pop")("sloppy")); if(kwargs.contains("badellimit")) mp.badellimit = py::cast(kwargs.attr("pop")("badellimit")); if(kwargs.contains("check_impossible")) mp.check_impossible = py::cast(kwargs.attr("pop")("check_impossible")); if(kwargs.contains("only3D_domain_nr")) mp.only3D_domain_nr = py::cast(kwargs.attr("pop")("only3D_domain_nr")); if(kwargs.contains("secondorder")) mp.secondorder = py::cast(kwargs.attr("pop")("secondorder")); if(kwargs.contains("elementorder")) mp.elementorder = py::cast(kwargs.attr("pop")("elementorder")); if(kwargs.contains("quad")) { cout << "WARNING: Meshing parameter 'quad' is deprecated, use 'quad_dominated' instead!" << endl; mp.quad = py::cast(kwargs.attr("pop")("quad")); } if(kwargs.contains("quad_dominated")) mp.quad = py::cast(kwargs.attr("pop")("quad_dominated")); if(kwargs.contains("try_hexes")) mp.try_hexes = py::cast(kwargs.attr("pop")("try_hexes")); if(kwargs.contains("inverttets")) mp.inverttets = py::cast(kwargs.attr("pop")("inverttets")); if(kwargs.contains("inverttrigs")) mp.inverttrigs = py::cast(kwargs.attr("pop")("inverttrigs")); if(kwargs.contains("autozrefine")) mp.autozrefine = py::cast(kwargs.attr("pop")("autozrefine")); if(kwargs.contains("parallel_meshing")) mp.parallel_meshing = py::cast(kwargs.attr("pop")("parallel_meshing")); if(kwargs.contains("nthreads")) mp.nthreads = py::cast(kwargs.attr("pop")("nthreads")); if(kwargs.contains("closeedgefac")) mp.closeedgefac = py::cast>(kwargs.attr("pop")("closeedgefac")); if(kwargs.contains("boundary_layers")) { auto layers = py::list(kwargs.attr("pop")("boundary_layers")); for(auto layer : layers) mp.boundary_layers.Append(py::cast(layer)); } if(kwargs.size()) { if(throw_if_not_all_parsed) throw Exception(string("Not all kwargs given to GenerateMesh could be parsed:") + string(py::str(kwargs))); mp.geometrySpecificParameters = CreateFlagsFromKwArgs(kwargs); } } } // namespace netgen #endif // NETGEN_MESHING_PYTHON_MESH_HPP ================================================ FILE: libsrc/meshing/refine.cpp ================================================ #include #include "meshclass.hpp" #include "bisect.hpp" #include "paralleltop.hpp" namespace netgen { void Refinement :: Refine (Mesh & mesh) const { const_cast (*this).Refine(mesh); } void Refinement :: Refine (Mesh & mesh) { if (mesh.GetCommunicator().Rank()==0) PrintMessage (3, "Refine mesh"); Timer t("Refine mesh"); RegionTimer reg(t); mesh.SetNextMajorTimeStamp(); if (ntasks > 1 && id == 0) return; // reduce 2nd order mesh.ComputeNVertices(); mesh.SetNP(mesh.GetNV()); if (mesh.mlbetweennodes.Size() < mesh.GetNV()) { mesh.mlbetweennodes.SetSize(mesh.GetNV()); mesh.mlbetweennodes = PointIndices<2>(PointIndex::INVALID, PointIndex::INVALID); } if (mesh.level_nv.Size() == 0) mesh.level_nv.Append (mesh.GetNV()); INDEX_2_HASHTABLE between(mesh.GetNP() + 5); // new version with consistent ordering across sub-domains NgArray parents; for (SegmentIndex si = 0; si < mesh.GetNSeg(); si++) { const Segment & el = mesh[si]; INDEX_2 i2 = INDEX_2::Sort(el[0], el[1]); if (!between.Used(i2)) { between.Set (i2, 0); parents.Append(i2); } } for (SurfaceElementIndex sei = 0; sei < mesh.GetNSE(); sei++) { const Element2d & el = mesh[sei]; switch (el.GetType()) { case TRIG: case TRIG6: { static int betw[3][3] = { { 1, 2, 3 }, { 0, 2, 4 }, { 0, 1, 5 } }; for (int j = 0; j < 3; j++) { auto i2 = PointIndices<2>::Sort(el[betw[j][0]],el[betw[j][1]]); if (!between.Used(i2)) { between.Set (i2, 0); parents.Append(i2); } } break; } case QUAD: { static int betw[5][3] = { { 0, 1, 4 }, { 1, 2, 5 }, { 2, 3, 6 }, { 0, 3, 7 }, { 0, 2, 8 } }; // one diagonal of the quad. should change later to mid-point of edge mid-points for (int j = 0; j < 5; j++) { auto i2 = PointIndices<2>::Sort(el[betw[j][0]],el[betw[j][1]]); if (j == 4) { auto i2a = PointIndices<2>::Sort(el[0], el[2]); auto i2b = PointIndices<2>::Sort(el[1], el[3]); i2 = i2a[0] < i2b[0] ? i2a : i2b; } if (!between.Used(i2)) { between.Set (i2, 0); parents.Append(i2); } } break; } default: throw NgException ("currently refinement for quad-elements is not supported"); } } for (ElementIndex ei = 0; ei < mesh.GetNE(); ei++) { const Element & el = mesh[ei]; switch (el.GetType()) { case TET: case TET10: { static int betw[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++) { INDEX_2 i2 = INDEX_2::Sort(el.PNum(betw[j][0]),el.PNum(betw[j][1])); if (!between.Used(i2)) { between.Set (i2, 0); parents.Append(i2); } } break; } default: throw NgException ("currently refinement for non-tet elements is not supported"); } } PrintMessage (5, "have points"); NgArray par_nr(parents.Size()); for (int i = 0; i < par_nr.Size(); i++) par_nr[i] = i; QuickSort (parents, par_nr); mesh.mlbetweennodes.SetSize(mesh.GetNV()+parents.Size()); for (int i = 0; i < parents.Size(); i++) { between.Set (parents[i], mesh.GetNV()+i+PointIndex::BASE); mesh.mlbetweennodes[mesh.GetNV()+i+PointIndex::BASE] = parents[i]; } mesh.SetNP(mesh.GetNV() + parents.Size()); NgArray pointset(mesh.GetNP()); pointset = false; PrintMessage (5, "sorting complete"); // refine edges NgArray epgi; int 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 = between.Get(i2); EdgePointGeomInfo ngi; if (pointset[pinew]) { // pinew = between.Get(i2); ngi = epgi[pinew]; } else { pointset[pinew] = true; Point<3> pnew; geo.PointBetweenEdge(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); mesh.Point(pinew) = pnew; // between.Set (i2, pinew); if (pinew >= epgi.Size()+IndexBASE()) epgi.SetSize (pinew+1-IndexBASE()); 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); } PrintMessage (5, "have 1d elements"); // refine surface elements Array surfgi (8*mesh.GetNP()); for (int i = PointIndex::BASE; i < surfgi.Size()+PointIndex::BASE; i++) surfgi[i].trignum = -1; int oldnf = mesh.GetNSE(); for (SurfaceElementIndex sei = 0; sei < oldnf; sei++) { const Element2d & el = mesh[sei]; switch (el.GetType()) { case TRIG: case TRIG6: { NgArrayMem pnums(6); NgArrayMem pgis(6); static int betw[3][3] = { { 2, 3, 4 }, { 1, 3, 5 }, { 1, 2, 6 } }; for (int j = 1; j <= 3; j++) { pnums.Elem(j) = el.PNum(j); pgis.Elem(j) = el.GeomInfoPi(j); } for (int 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; geo.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; PointIndex pinew = between.Get(i2); pnums.Elem(4+j) = pinew; if (!pointset[pinew]) { pointset[pinew] = true; mesh.Point(pinew) = pb; } /* 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)-IndexBASE()+1) surfgi.SetSize (pnums.Elem(4+j)-IndexBASE()+1); surfgi[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 (int j = 0; j < 4; j++) { Element2d nel(TRIG); for (int 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[sei] = nel; else mesh.AddSurfaceElement(nel); } break; } case QUAD: case QUAD6: case QUAD8: { PointIndex pnums[9]; PointGeomInfo pgis[9]; static int betw[5][3] = { { 0, 1, 4 }, { 1, 2, 5 }, { 2, 3, 6 }, { 0, 3, 7 }, { 0, 2, 8 } }; for (int j = 0; j < 4; j++) { pnums[j] = el[j]; pgis[j] = el.GeomInfoPi(j+1); } for (int j = 0; j < 5; j++) { int pi1 = pnums[betw[j][0]]; int pi2 = pnums[betw[j][1]]; INDEX_2 i2 (pi1, pi2); i2.Sort(); if (j == 4) { auto i2a = PointIndices<2>::Sort(el[0], el[2]); auto i2b = PointIndices<2>::Sort(el[1], el[3]); i2 = i2a[0] < i2b[0] ? i2a : i2b; } Point<3> pb; PointGeomInfo pgi; geo.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, pgi); pgis[4+j] = pgi; PointIndex pinew = between.Get(i2); pnums[4+j] = pinew; if (!pointset[pinew]) { pointset[pinew] = true; mesh.Point(pinew) = pb; } if (surfgi.Size() < pnums[4+j]-IndexBASE()+1) surfgi.SetSize (pnums[4+j]-IndexBASE()+1); surfgi[pnums[4+j]] = pgis[4+j]; } static int reftab[4][4] = { { 0, 4, 8, 7 }, { 4, 1, 5, 8 }, { 7, 8, 6, 3 }, { 8, 5, 2, 6 } }; int ind = el.GetIndex(); for (int j = 0; j < 4; j++) { Element2d nel(QUAD); for (int k = 0; k < 4; k++) { nel[k] = pnums[reftab[j][k]]; nel.GeomInfoPi(k+1) = pgis[reftab[j][k]]; } nel.SetIndex(ind); if (j == 0) mesh[sei] = nel; else mesh.AddSurfaceElement(nel); } break; } default: PrintSysError ("Refine: undefined surface element type ", int(el.GetType())); } } PrintMessage (5, "have 2d elements"); // cout << "id = " << id << ", ne = " << mesh.GetNE() << endl; // refine volume elements int oldne = mesh.GetNE(); mesh.VolumeElements().SetAllocSize(8*oldne); for (ElementIndex ei = 0; ei < oldne; ei++) { const Element & el = mesh[ei]; switch (el.GetType()) { case TET: case TET10: { NgArrayMem 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 (int j = 1; j <= 4; j++) pnums.Elem(j) = el.PNum(j); if (elrev) swap (pnums.Elem(3), pnums.Elem(4)); for (int j = 0; j < 6; j++) { PointIndex pi1 = pnums.Get(betw[j][0]); PointIndex pi2 = pnums.Get(betw[j][1]); INDEX_2 i2 (pi1, pi2); 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)); } */ PointIndex pinew = between.Get(i2); pnums.Elem(j+5) = pinew; if (!pointset[pinew]) { pointset[pinew] = true; mesh.Point(pinew) = Center(mesh.Point(pi1), mesh.Point(pi2)); } } 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 (int j = 0; j < 8; j++) { Element nel(TET); for (int 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: { NgArrayMem 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 }, }; */ // updated 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 = PointIndex(-1); for (int j = 1; j <= 8; j++) pnums.Elem(j) = el.PNum(j); for (int 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 (int 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 (int j = 0; j < 8; j++) { Element nel(HEX); for (int 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: { NgArrayMem 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 = PointIndex(-1); for (int j = 1; j <= 6; j++) pnums.Elem(j) = el.PNum(j); // if (elrev) // swap (pnums.Elem(3), pnums.Elem(4)); for (int 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 (int 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 (int j = 0; j < 8; j++) { Element nel(PRISM); for (int 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++) { idmap_type identmap; mesh.GetIdentifications().GetMap (i, identmap); for (int j = 1; j <= between.GetNBags(); j++) for (int k = 1; k <= between.GetBagSize(j); k++) { PointIndices<2> i2; PointIndex newpi; between.GetData (j, k, i2, newpi); PointIndices<2> oi2(identmap[i2[0]], identmap[i2[1]]); oi2.Sort(); if (between.Used (oi2)) { PointIndex onewpi = between.Get(oi2); mesh.GetIdentifications().Add (newpi, onewpi, i); } } } PrintMessage (5, "have 3d elements"); mesh.ComputeNVertices(); mesh.RebuildSurfaceElementLists(); mesh.level_nv.Append (mesh.GetNV()); #ifdef PARALLEL if (mesh.GetCommunicator().Size() > 1) { mesh.GetParallelTopology().IdentifyVerticesAfterRefinement(); mesh.GetCommunicator().Barrier(); mesh.GetParallelTopology().EnumeratePointsGlobally(); } #endif PrintMessage (5, "mesh updates complete"); return; int cnttrials = 10; int wrongels = 0; for (auto & el : mesh.VolumeElements()) if (el.Volume(mesh.Points()) < 0) { wrongels++; el.Flags().badel = 1; } else el.Flags().badel = 0; if (wrongels) { cout << "WARNING: " << wrongels << " with wrong orientation found" << endl; int np = mesh.GetNP(); NgArray > should(np); NgArray > 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; PointIndex child; between.GetData (i, j, parent, child); can.Elem(child) = Center (can.Elem(parent.I1()), can.Elem(parent.I2())); } TBitArray boundp(np); boundp.Clear(); for (auto & sel : mesh.SurfaceElements()) for (auto pi : sel.PNums()) boundp.SetBit(pi); 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); TBitArray free (mesh.GetNP()), fhelp(mesh.GetNP()); free.Clear(); // for (int i = 1; i <= mesh.GetNE(); i++) for (ElementIndex ei : mesh.VolumeElements().Range()) { const Element & el = mesh.VolumeElement(ei); if (el.Volume(mesh.Points()) < 0) for (int j = 1; j <= el.GetNP(); j++) free.SetBit (el.PNum(j)); } for (int k = 1; k <= 3; k++) { fhelp.Clear(); // for (int i = 1; i <= mesh.GetNE(); i++) for (const Element & el : mesh.VolumeElements()) { // 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.SetBit (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 (auto & sel : mesh.SurfaceElements()) for (auto pi : sel.PNums()) (*testout) << pi << endl; mesh.CalcSurfacesOfNode(); free.Invert(); mesh.FixPoints (free); MeshingParameters dummymp; mesh.ImproveMesh (dummymp, OPT_REST); wrongels = 0; for (ElementIndex ei : mesh.VolumeElements().Range()) { if (mesh.VolumeElement(ei).Volume(mesh.Points()) < 0) { wrongels++; mesh.VolumeElement(ei).Flags().badel = 1; (*testout) << "wrong el: "; for (int j = 1; j <= 4; j++) (*testout) << mesh.VolumeElement(ei).PNum(j) << " "; (*testout) << endl; } else mesh.VolumeElement(ei).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(); } } ================================================ FILE: libsrc/meshing/ruler2.cpp ================================================ #include #include "meshing.hpp" namespace netgen { static double CalcElementBadness (const NgArray> & points, const Element2d & elem) { // badness = sqrt(3) /36 * circumference^2 / area - 1 + // h / li + li / h - 2 Vec<2> 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[0] * v13[1] - v12[1] * v13[0]); 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 (NgArray> & lpoints, NgArray & legalpoints, int maxlegalpoint, NgArray & llines1, int maxlegalline, NgArray & elements, NgArray & dellines, int tolerance, const MeshingParameters & mp) { // static Timer timer ("meshing2::ApplyRules"); 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(); NgArrayMem pused(maxlegalpoint), lused(maxlegalline); NgArrayMem pnearness(noldlp), lnearness(llines1.Size()); NgArrayMem pmap, pfixed, lmap; NgArrayMem,100> tempnewpoints; NgArrayMem tempnewlines; NgArrayMem tempdellines; NgArrayMem tempelements; // a least 2 * maximal number of old points in rules, // what is actually 4 now double oldumem[20]; 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 NgArray llines(llines1.Size()); NgArray 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[ri-1].get(); #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); auto 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()); Vector oldu (2 * rule->GetNOldP(), &oldumem[0]); 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++) { auto np = rule->GetPoint(i); np[0] += newu (2 * (i-oldnp) - 2); np[1] += newu (2 * (i-oldnp) - 1); lpoints.Append (np); pmap.Elem(i) = lpoints.Size(); } } // 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; } } ================================================ FILE: libsrc/meshing/ruler2.hpp ================================================ #ifndef FILE_NETRULE #define FILE_NETRULE namespace netgen { /// 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; /// string name; /// NgArray> points; /// NgArray lines; /// NgArray> freezone, freezonelimit; /// NgArray>> freezone_i; /// NgArray> transfreezone; /// NgArray dellines; /// NgArray elements; /// NgArray tolerances, linetolerances; /// NgArray orientations; /// DenseMatrix oldutonewu, oldutofreearea, oldutofreearealimit; /// NgArray oldutofreearea_i; /// MatrixFixWidth<3> freesetinequ; /// NgArray> linevecs; /// int noldp, noldl; /// float fzminx, fzmaxx, fzminy, fzmaxy; /// topological distance of line to base element NgArray 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 Point<2>& 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 NgArray & GetDelLines() const { return dellines; } /// void GetFreeZone (NgArray> & afreearea); /// double CalcPointDist (int pi, const Point<2> & p) const { double dx = p[0] - points.Get(pi)[0]; double dy = p[1] - points.Get(pi)[1]; const threefloat * tfp = &tolerances.Get(pi); return tfp->f1 * dx * dx + tfp->f2 * dx * dy + tfp->f3 * dy * dy; } /// float CalcLineError (int li, const Vec<2>& v) const; /// void SetFreeZoneTransformation (const Vector & u, int tolclass); /// bool IsInFreeZone (const Point<2> & p) const { if (p[0] < fzminx || p[0] > fzmaxx || p[1] < fzminy || p[1] > fzmaxy) return 0; for (int i = 0; i < transfreezone.Size(); i++) { if (freesetinequ(i, 0) * p[0] + freesetinequ(i, 1) * p[1] + freesetinequ(i, 2) > 0) return 0; } return 1; } /// int IsLineInFreeZone (const Point<2> & p1, const Point<2> & p2) const { if ( (p1[0] > fzmaxx && p2[0] > fzmaxx) || (p1[0] < fzminx && p2[0] < fzminx) || (p1[1] > fzmaxy && p2[1] > fzmaxy) || (p1[1] < fzminy && p2[1] < fzminy) ) return 0; return IsLineInFreeZone2 (p1, p2); } /// int IsLineInFreeZone2 (const Point<2> & p1, const Point<2> & p2) const; /// int ConvexFreeZone () const; /// const NgArray> & 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 string & Name () const { return name; } /// void LoadRule (istream & ist); }; /** Draws 2D rules. Visual testing of 2D meshing rules */ extern void DrawRules (); } // namespace netgen #endif ================================================ FILE: libsrc/meshing/ruler3.cpp ================================================ #include #include "meshing.hpp" namespace netgen { extern double minother; extern double minwithoutother; static double TetBadnessFromPoints (const Point3d & p1, const Point3d & p2, const Point3d & p3, const Point3d & p4) { Vec3d v1 = p2 - p1; Vec3d v2 = p3 - p1; Vec3d v3 = p4 - p1; double vol = -(Cross(v1, v2) * v3); if (vol < 1e-8) return 1e10; double l4 = Dist(p2, p3); double l5 = Dist(p2, p4); double l6 = Dist(p3, p4); double l = v1.Length() + v2.Length() + v3.Length() + l4 + l5 + l6; return pow(l*l*l/vol, 1.0/3.0) / 12.0; } static double CalcElementBadness (const Array & points, const Element & elem) { if(elem.GetNP() == 4) return TetBadnessFromPoints (points[elem.PNum(1)], points[elem.PNum(2)], points[elem.PNum(3)], points[elem.PNum(4)]); if (elem.GetNP() == 5) { auto p1 = points[elem.PNum(1)]; auto p2 = points[elem.PNum(2)]; auto p3 = points[elem.PNum(3)]; auto p4 = points[elem.PNum(4)]; auto p5 = points[elem.PNum(5)]; double a1 = TetBadnessFromPoints(p1,p2,p3,p5); double a2 = TetBadnessFromPoints(p1,p3,p4,p5); double splitA = std::max(a1,a2); double b1 = TetBadnessFromPoints(p1,p2,p4,p5); double b2 = TetBadnessFromPoints(p2,p3,p4,p5); double splitB = std::max(b1,b2); double best = std::min(splitA, splitB); return best; } return 0.; } int Meshing3 :: ApplyRules ( Array & lpoints, // in: local points, out: old+new local points Array & allowpoint, // in: 2 .. it is allowed to use pointi, 1..will be allowed later, 0..no means Array & lfaces, // in: local faces, out: old+new local faces INDEX lfacesplit, // for local faces in outer radius INDEX_2_HASHTABLE & connectedpairs, // connected pairs for prism-meshing NgArray & elements, // out: new elements NgArray & 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 ) { // static Timer t("ruler3 - all"); RegionTimer reg(t); // static Timer tstart("ruler3 - rule start"); // static Timer tloop("ruler3 - rule loop"); // tstart.Start(); float err, minerr, teterr, minteterr; char ok, found, hc; // vnetrule * rule; Vector oldu, newu, newu1, newu2, allp; Vec3d ui; Point3d np; const MiniElement2d * locface = NULL; int loktestmode; NgArray pused; // point is already mapped, number of uses NgArrayMem fused; // face is already mapped NgArrayMem pmap; // map of reference point to local point NgArrayMem pfixed; // point mapped by face-map NgArrayMem fmapi; // face in reference is mapped to face nr ... NgArrayMem fmapr; // face in reference is rotated to map NgArrayMem transfreezone; // transformed free-zone INDEX_2_CLOSED_HASHTABLE ledges(100); // edges in local environment NgArrayMem tempnewpoints; NgArray tempnewfaces; NgArrayMem tempdelfaces; NgArray tempelements; NgArrayMem triboxes; // bounding boxes of local faces NgArray pnearness; NgArray 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 (PointIndex pi : lfaces[0].PNums()) pnearness[pi] = 0; NgProfiler::RegionTimer reg2(98); NgProfiler::StartTimer (90); for (int loop = 0; loop < 2; loop++) { for (int i = 0; i < lfacesplit; i++) { const MiniElement2d & hface = lfaces[i]; int minn = INT_MAX-1; for (PointIndex pi : hface.PNums()) { int hi = pnearness[pi]; if (hi < minn) minn = hi; } if (minn < INT_MAX/10) for (PointIndex pi : hface.PNums()) if (pnearness[pi] > minn+1) pnearness[pi] = minn+1; } for (int i = 1; i <= connectedpairs.GetNBags(); i++) for (int 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 (int i : fnearness.Range()) { int sum = 0; for (PointIndex pi : lfaces[i].PNums()) sum += pnearness[pi]; fnearness[i] = sum; } NgProfiler::StopTimer (90); NgProfiler::StartTimer (91); // find bounding boxes of faces triboxes.SetSize (lfaces.Size()); // for (int i = 0; i < lfaces.Size(); i++) for (auto i : lfaces.Range()) { const MiniElement2d & face = lfaces[i]; triboxes[i].SetPoint (lpoints[face[0]]); for (int j = 1; j < face.GetNP(); j++) triboxes[i].AddPoint (lpoints[face[j]]); } NgProfiler::StopTimer (91); NgProfiler::StartTimer (92); bool useedges = false; for (int ri = 0; ri < rules.Size(); ri++) if (rules[ri]->GetNEd()) useedges = true; if (useedges) { ledges.SetSize (5 * lfacesplit); for (int j = 0; j < lfacesplit; j++) // if (fnearness[j] <= 5) { const MiniElement2d & face = lfaces[j]; int newp, oldp; newp = face[face.GetNP()-1]; for (int 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: // tstart.Stop(); // tloop.Start(); for (int rim = 0; rim < rules.Size(); rim++) { int base = (lfaces[0].GetNP() == 3) ? 100 : 200; NgProfiler::RegionTimer regx1(base); NgProfiler::RegionTimer regx(base+rim+1); // sprintf (problems.Elem(ri), ""); // *problems.Elem(ri) = '\0'; problems[rim] = ""; vnetrule * rule = rules[rim].get(); if (rule->GetNP(1) != lfaces[0].GetNP()) continue; if (rule->GetQuality() > tolerance) { if (rule->GetQuality() < 100) impossible = 0; if (testmode) problems[rim] = "Quality not ok"; continue; } if (testmode) problems[rim] = "no mapping found"; loktestmode = testmode || rule->TestFlag ('t') || tolerance > 5; if (loktestmode) (*testout) << "Rule " << rim+1 << " = " << rule->Name() << endl; pmap.SetSize (rule->GetNP()); fmapi.SetSize (rule->GetNF()); fmapr.SetSize (rule->GetNF()); fused = 0; pused = 0; for (auto & p : pmap) p.Invalidate(); fmapi = 0; for (int i : fmapr.Range()) fmapr[i] = rule->GetNP(i+1); fused[0] = 1; fmapi[0] = 1; fmapr[0] = rotind1; for (int j = 1; j <= lfaces[0].GetNP(); j++) { PointIndex locpi = lfaces[0].PNumMod (j+rotind1); pmap.Set (rule->GetPointNr (1, j), locpi); pused[locpi]++; } /* map all faces nfok .. first nfok-1 faces are mapped properly */ int nfok = 2; NgProfiler::RegionTimer regfa(300); NgProfiler::RegionTimer regx2(base+50+rim+1); while (nfok >= 2) { if (nfok <= rule->GetNOldF()) { // not all faces mapped ok = 0; int locfi = fmapi.Get(nfok); int 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[locfi-1].GetNP() ) { // face not feasible in any rotation locfr = actfnp; } else { ok = 1; locface = &lfaces[locfi-1]; // reference point already mapped differently ? for (int j = 1; j <= actfnp && ok; j++) { PointIndex locpi = pmap.Get(rule->GetPointNr (nfok, j)); if (locpi.IsValid() && locpi != locface->PNumMod(j+locfr)) ok = 0; } // local point already used or point outside tolerance ? for (int j = 1; j <= actfnp && ok; j++) { int refpi = rule->GetPointNr (nfok, j); if (!pmap.Get(refpi).IsValid()) { PointIndex locpi = locface->PNumMod (j + locfr); if (pused[locpi]) ok = 0; else { const Point3d & lp = lpoints[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 (int j = 1; j <= rule->GetNP (nfok); j++) { PointIndex locpi = locface->PNumMod(j+locfr); if (rule->GetPointNr (nfok, j) < IndexBASE()+3 && pmap.Get(rule->GetPointNr(nfok, j)) != locpi) (*testout) << "change face1 point, mark1" << endl; pmap.Set(rule->GetPointNr (nfok, j), locpi); pused[locpi]++; } nfok++; } else { // backtrack one face fmapi.Set (nfok, 0); fmapr.Set (nfok, rule->GetNP(nfok)); nfok--; fused.Set (fmapi.Get(nfok), 0); for (int j = 1; j <= rule->GetNP (nfok); j++) { int refpi = rule->GetPointNr (nfok, j); pused[pmap.Get(refpi)]--; if (pused[pmap.Get(refpi)] == 0) { // pmap.Set(refpi, 0); pmap.Elem(refpi).Invalidate(); } } } } else { NgProfiler::RegionTimer regfb(301); // all faces are mapped // now map all isolated points: if (loktestmode) { (*testout) << "Faces Ok" << endl; problems[rim] = "Faces Ok"; } int npok = 1; int incnpok = 1; pfixed.SetSize (pmap.Size()); /* for (int i = 1; i <= pmap.Size(); i++) pfixed.Set(i, (pmap.Get(i) != 0) ); */ for (int i : pmap.Range()) pfixed[i] = pmap[i].IsValid(); while (npok >= 1) { if (npok <= rule->GetNOldP()) { if (pfixed.Get(npok)) { if (incnpok) npok++; else npok--; } else { PointIndex locpi = pmap.Elem(npok); ok = 0; if (locpi.IsValid()) pused[locpi]--; while (!ok && locpi < lpoints.Size()-1+IndexBASE()) { ok = 1; locpi++; if (pused[locpi] || pnearness[locpi] > rule->GetPNearness(npok)) { ok = 0; } else if (allowpoint[locpi] != 2) { ok = 0; if (allowpoint[locpi] == 1) impossible = 0; } else { const Point3d & lp = lpoints[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[locpi]++; npok++; incnpok = 1; } else { // pmap.Set (npok, 0); pmap.Elem(npok).Invalidate(); 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 (auto pi : pmap) (*testout) << pi << " "; (*testout) << endl; problems[rim] = "mapping found"; (*testout) << rule->GetNP(1) << " = " << lfaces[0].GetNP() << endl; } ok = 1; // check mapedges: for (int 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 (int i = 1; i <= rule->GetNE(); i++) { const Element & el = rule->GetElement (i); if (el.GetType() == PRISM) { for (int 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 (int 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 (int i = rule->GetNOldF() + 1; i <= rule->GetNF(); i++) fmapi.Set(i, 0); if (ok) foundmap[rim]++; // deviation of existing points oldu.SetSize (3 * rule->GetNOldP()); newu.SetSize (3 * (rule->GetNP() - rule->GetNOldP())); allp.SetSize (3 * rule->GetNP()); for (int i = 1; i <= rule->GetNOldP(); i++) { const Point3d & lp = lpoints[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 (int 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; problems[rim] = "Freezone not convex"; if (loktestmode) (*testout) << "Freezone not convex" << endl; } if (loktestmode) { const NgArray & fz = rule->GetTransFreeZone(); (*testout) << "Freezone: " << endl; for (int i = 1; i <= fz.Size(); i++) (*testout) << fz.Get(i) << endl; } // check freezone: // for (int i = 1; i <= lpoints.Size(); i++) for (auto i : lpoints.Range()) { if ( !pused[i] ) { const Point3d & lp = lpoints[i]; if (rule->fzbox.IsIn (lp)) { if (rule->IsInFreeZone(lp)) { if (loktestmode) { (*testout) << "Point " << i << " in Freezone" << endl; problems[rim] = "locpoint " + ToString(i) + " in Freezone"; } ok = 0; break; } } } } for (int i = 1; i <= lfaces.Size() && ok; i++) { NgArrayMem lpi(4); if (!fused.Get(i)) { int triin; const MiniElement2d & lfacei = lfaces[i-1]; if (!triboxes.Elem(i).Intersect (rule->fzbox)) triin = 0; else { int li, lj; for (li = 1; li <= lfacei.GetNP(); li++) { int lpii = 0; PointIndex 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[lfacei.PNum(1)], lpoints[lfacei.PNum(2)], lpoints[lfacei.PNum(3)], lpi, 1 ); } else { triin = rule->IsQuadInFreeZone ( lpoints[lfacei.PNum(1)], lpoints[lfacei.PNum(2)], lpoints[lfacei.PNum(3)], lpoints[lfacei.PNum(4)], lpi, 1 ); } } if (triin == -1) { ok = 0; } if (triin == 1) { #ifdef TEST_JS ok = 0; if (loktestmode) { (*testout) << "El with " << lfaces[i-1].GetNP() << " points in freezone: " << lfaces[i-1].PNum(1) << " - " << lfaces[i-1].PNum(2) << " - " << lfaces[i-1].PNum(3) << " - " << lfaces[i-1].PNum(4) << endl; for (int lj = 1; lj <= lfaces[i-1].GetNP(); lj++) (*testout) << lpoints[lfaces[i-1].PNum(lj)] << " "; (*testout) << endl; sprintf (problems.Elem(ri), "triangle (%d, %d, %d) in Freezone", lfaces[i-1].PNum(1), lfaces[i-1].PNum(2), lfaces[i-1].PNum(3)); } #else if (loktestmode) { if (lfacei.GetNP() == 3) { (*testout) << "Triangle in freezone: " << lfacei.PNum(1) << " - " << lfacei.PNum(2) << " - " << lfacei.PNum(3) << ", or " << lpoints[lfacei.PNum(1)] << " - " << lpoints[lfacei.PNum(2)] << " - " << lpoints[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[lfacei.PNum(1)] << " - " << lpoints[lfacei.PNum(2)] << " - " << lpoints[lfacei.PNum(3)] << " - " << lpoints[lfacei.PNum(4)] << endl; problems[rim] = "triangle ("+ToString(lfaces[i-1].PNum(1))+", " + ToString(lfaces[i-1].PNum(2)) + ", " + ToString(lfaces[i-1].PNum(3)) + ") in Freezone"; } hc = 0; for (int k = rule->GetNOldF() + 1; k <= rule->GetNF(); k++) { if (rule->GetPointNr(k, 1) < IndexBASE()+rule->GetNOldP() && rule->GetPointNr(k, 2) < IndexBASE()+rule->GetNOldP() && rule->GetPointNr(k, 3) < IndexBASE()+rule->GetNOldP()) { for (int j = 1; j <= 3; j++) if (lfaces[i-1].PNumMod(j ) == pmap.Get(rule->GetPointNr(k, 1)) && lfaces[i-1].PNumMod(j+1) == pmap.Get(rule->GetPointNr(k, 3)) && lfaces[i-1].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; problems[rim] = "other"; } } } if (!hc) { if (loktestmode) { (*testout) << "Triangle in freezone: " << lfaces[i-1].PNum(1) << " - " << lfaces[i-1].PNum(2) << " - " << lfaces[i-1].PNum(3) << endl; /* snprintf (problems.Elem(ri), 255, "triangle (%d, %d, %d) in Freezone", int (lfaces[i-1].PNum(1)), int (lfaces[i-1].PNum(2)), int (lfaces[i-1].PNum(3))); */ problems[rim] = "triangle (" + ToString(lfaces[i-1].PNum(1))+", " + ToString(lfaces[i-1].PNum(2)) + ", " + ToString(lfaces[i-1].PNum(3)) + ") in Freezone"; } ok = 0; } #endif } } } if (ok) { err = 0; for (int i = 1; i <= rule->GetNOldP(); i++) { double hf = rule->CalcPointDist (i, lpoints[pmap.Get(i)]); if (hf > err) err = hf; } if (loktestmode) { (*testout) << "Rule ok" << endl; problems[rim] = "Rule ok, err = "+ToString(err); } // newu = rule->GetOldUToNewU() * oldu; // set new points: int oldnp = rule->GetNOldP(); int noldlp = lpoints.Size(); int noldlf = lfaces.Size(); for (int 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); lpoints.Append (np); pmap.Elem(i) = lpoints.Size()-1+PointIndex::BASE; } // Set new Faces: for (int i = rule->GetNOldF() + 1; i <= rule->GetNF(); i++) if (!fmapi.Get(i)) { MiniElement2d nface(rule->GetNP(i)); for (int j = 1; j <= nface.GetNP(); j++) nface.PNum(j) = pmap.Get(rule->GetPointNr (i, j)); lfaces.Append (nface); } // Delete old Faces: for (int i = 1; i <= rule->GetNDelF(); i++) delfaces.Append (fmapi.Get(rule->GetDelFace(i))); for (int i = rule->GetNOldF()+1; i <= rule->GetNF(); i++) if (fmapi.Get(i)) { delfaces.Append (fmapi.Get(i)); fmapi.Elem(i) = 0; } // check orientation for (int i = 1; i <= rule->GetNO() && ok; i++) { const fourint * fouri; fouri = &rule->GetOrientation(i); Vec3d v1 (lpoints[pmap.Get(fouri->i1)], lpoints[pmap.Get(fouri->i2)]); Vec3d v2 (lpoints[pmap.Get(fouri->i1)], lpoints[pmap.Get(fouri->i3)]); Vec3d v3 (lpoints[pmap.Get(fouri->i1)], lpoints[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) { problems[rim] = "Orientation wrong"; (*testout) << "Orientation wrong ("<< n*v3 << ")" << endl; } ok = 0; } } // new points in free-zone ? for (int i = rule->GetNOldP() + 1; i <= rule->GetNP() && ok; i++) if (!rule->IsInFreeZone (lpoints[pmap.Get(i)])) { if (loktestmode) { (*testout) << "Newpoint " << lpoints[pmap.Get(i)] << " outside convex hull" << endl; problems[rim] = "newpoint outside convex hull"; } ok = 0; } // insert new elements for (int i = 1; i <= rule->GetNE(); i++) { elements.Append (rule->GetElement(i)); for (int 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 (auto i : elements.Range()) { double hf = CalcElementBadness (lpoints, elements[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 (int i = 1; i <= rule->GetNDelF(); i++) { const Element2d & face = rule->GetFace (rule->GetDelFace(i)); for (int j = 1; j <= 3; j++) { const Point3d & p1 = lpoints[pmap.Get(face.PNumMod(j))]; const Point3d & p2 = lpoints[pmap.Get(face.PNumMod(j+1))]; oldlen += Dist(p1, p2); } } for (int i = rule->GetNOldF()+1; i <= rule->GetNF(); i++) { const Element2d & face = rule->GetFace (i); for (int j = 1; j <= 3; j++) { const Point3d & p1 = lpoints[pmap.Get(face.PNumMod(j))]; const Point3d & p2 = lpoints[pmap.Get(face.PNumMod(j+1))]; newlen += Dist(p1, p2); } } if (oldlen < newlen) { ok = 0; if (loktestmode) problems[rim] = "oldlen < newlen"; } } if (loktestmode) (*testout) << "ok = " << int(ok) << "teterr = " << teterr << "minteterr = " << minteterr << endl; if (ok && teterr < tolerance) { canuse[rim] ++; /* (*testout) << "can use rule " << rule->Name() << ", err = " << teterr << endl; for (i = 1; i <= pmap.Size(); i++) (*testout) << pmap.Get(i) << " "; (*testout) << endl; */ if (problems[rim] == "other") { 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 = rim+1; minteterr = teterr; if (testmode) { for (int i = 1; i <= rule->GetNOldP(); i++) { (*testout) << "P" << i << ": Ref: " << rule->GetPoint (i) << " is: " << lpoints[pmap.Get(i)] << endl; } } tempnewpoints.SetSize (0); // for (int i = noldlp+1; i <= lpoints.Size(); i++) for (auto i : lpoints.Range().Modify(noldlp, 0)) tempnewpoints.Append (lpoints[i]); tempnewfaces.SetSize (0); // for (int i = noldlf+1; i <= lfaces.Size(); i++) for (auto i : lfaces.Range().Modify(noldlf,0)) tempnewfaces.Append (lfaces[i]); tempdelfaces.SetSize (0); // for (int i = 1; i <= delfaces.Size(); i++) for (auto i : delfaces.Range()) tempdelfaces.Append (delfaces[i]); tempelements.SetSize (0); // for (int i = 1; i <= elements.Size(); i++) for (auto i : elements.Range()) tempelements.Append (elements[i]); } lpoints.SetSize (noldlp); lfaces.SetSize (noldlf); delfaces.SetSize (0); elements.SetSize (0); } npok = rule->GetNOldP(); incnpok = 0; } } nfok = rule->GetNOldF(); for (int j = 1; j <= rule->GetNP (nfok); j++) { int refpi = rule->GetPointNr (nfok, j); pused[pmap.Get(refpi)]--; if (pused[pmap.Get(refpi)] == 0) pmap.Elem(refpi).Invalidate(); } } } if (loktestmode) (*testout) << "end rule" << endl; } // tloop.Stop(); if (found) { /* for (i = 1; i <= tempnewpoints.Size(); i++) lpoints.Append (tempnewpoints.Get(i)); */ for (Point3d p : tempnewpoints) lpoints.Append(p); /* for (i = 1; i <= tempnewfaces.Size(); i++) if (tempnewfaces.Get(i).PNum(1)) lfaces.Append (tempnewfaces.Get(i)); */ for (int i : tempnewfaces.Range()) if (tempnewfaces[i].PNum(1).IsValid()) lfaces.Append (tempnewfaces[i]); /* for (i = 1; i <= tempdelfaces.Size(); i++) delfaces.Append (tempdelfaces.Get(i)); */ for (int i : tempdelfaces.Range()) delfaces.Append (tempdelfaces[i]); /* for (i = 1; i <= tempelements.Size(); i++) elements.Append (tempelements.Get(i)); */ for (int i : tempelements.Range()) elements.Append (tempelements[i]); } retminerr = minerr; if (impossible && found == 0) return -1; return found; } } ================================================ FILE: libsrc/meshing/ruler3.hpp ================================================ #ifndef FILE_RULER3 #define FILE_RULER3 namespace netgen { /** 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 NgArray points; /// old and new faces in reference numbering NgArray faces; /// additional edges of rule NgArray edges; /// points of freezone in reference coordinates NgArray freezone; /// points of freezone in reference coordinates if tolcalss to infty NgArray freezonelimit; /// point index, if point equal to mappoint, otherwise 0 NgArray freezonepi; /// faces of each convex part of freezone NgArray*> freefaces; /// set of points of each convex part of freezone NgArray*> freesets; /// points of transformed freezone NgArray transfreezone; /// edges of each convex part of freezone NgArray*> freeedges; /// face numbers to be deleted NgArray delfaces; /// elements to be generated NgArray elements; /// tolerances for points and faces (used ??) NgArray 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 ?) */ NgArray freefaceinequ; /// NgArray orientations; /** flags specified in rule-description file: t .. test rule */ NgArray flags; /** topological distance of face to base element non-connected: > 100 (??) */ NgArray fnearness; NgArray 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 NgArray & pi, int newone); /// int IsQuadInFreeZone (const Point3d & p1, const Point3d & p2, const Point3d & p3, const Point3d & p4, const NgArray & pi, int newone); /// int IsTriangleInFreeSet (const Point3d & p1, const Point3d & p2, const Point3d & p3, int fs, const NgArray & pi, int newone); /// int IsQuadInFreeSet (const Point3d & p1, const Point3d & p2, const Point3d & p3, const Point3d & p4, int fs, const NgArray & 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(); } /// PointIndex GetPointNr (int fn, int endp) const { return faces.Get(fn).PNum(endp); } /// PointIndex 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 NgArray & GetTransFreeZone () { return transfreezone; } /// int TestOk () const; /// friend void TestRules (); /// // friend void Plot3DRule (const ROT3D & r, char key); }; } // namespace netgen #endif ================================================ FILE: libsrc/meshing/secondorder.cpp ================================================ #include #include "meshing.hpp" namespace netgen { void Refinement :: MakeSecondOrder (Mesh & mesh) const { const_cast (*this).MakeSecondOrder(mesh); } void Refinement :: MakeSecondOrder (Mesh & mesh) { /* Berlin, 2014: if we have curved surface elements, keep them ! */ mesh.ComputeNVertices(); // mesh.SetNP(mesh.GetNV()); mesh.SetNP(mesh.GetNP()); // setup multilevel-table INDEX_2_HASHTABLE between(mesh.GetNP() + 5); for (SegmentIndex si = 0; si < mesh.GetNSeg(); si++) { auto & seg = mesh[si]; if (seg.GetType() == SEGMENT3) between.Set(INDEX_2::Sort(seg[0],seg[1]), seg[2]); } for (SurfaceElementIndex sei = 0; sei < mesh.GetNSE(); sei++) { const Element2d & el = mesh[sei]; 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 onp = 0; int (*betw)[3] = NULL; switch (el.GetType()) { case TRIG6: { betw = betw_trig; onp = 3; break; } case QUAD6: { betw = betw_quad6; onp = 4; break; } case QUAD8: { betw = betw_quad8; onp = 4; break; } default: ; } if (betw) for (int j = 0; j < el.GetNP()-onp; j++) { int pi1 = el[betw[j][0]]; int pi2 = el[betw[j][1]]; INDEX_2 i2 = INDEX_2::Sort (pi1, pi2); between.Set (i2, el[onp+j]); } } bool thinlayers = 0; for (ElementIndex ei = 0; ei < mesh.GetNE(); ei++) if (mesh[ei].GetType() == PRISM || mesh[ei].GetType() == PRISM12) thinlayers = 1; int 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; geo.PointBetweenEdge(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, mesh.Point(el[0]).GetLayer(), EDGEPOINT); between.Set (i2, el[2]); } el.SetCurved(true); } // refine surface elements for (SurfaceElementIndex sei = 0; sei < mesh.GetNSE(); sei++) { const Element2d & el = mesh[sei]; int onp = 0; Element2d newel(TRIG); 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 (int j = 0; j < onp; j++) newel[j] = el[j]; int nnp = newel.GetNP(); for (int j = 0; j < nnp-onp; j++) { PointIndex pi1 = newel[betw[j][0]]; PointIndex 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; geo.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, mesh.Point(pi1).GetLayer(), SURFACEPOINT); between.Set (i2, newel[onp+j]); } } mesh[sei] = newel; } // int i, j; // refine volume elements // for (int i = 1; i <= mesh.GetNE(); i++) for (ElementIndex ei : mesh.VolumeElements().Range()) { const Element & el = mesh.VolumeElement(ei); int onp = 0; Element newel(TET); 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 }, }; static int betw_prism15[9][3] = { { 0, 1, 6 }, { 0, 2, 7 }, { 1, 2, 8 }, { 0, 3, 9 }, { 1, 4, 10 }, { 2, 5, 11 }, { 3, 4, 12 }, { 3, 5, 13 }, { 4, 5, 14 } }; static int betw_pyramid[8][3] = { { 0, 1, 5 }, { 3, 2, 6 }, { 3, 0, 7 }, { 1, 2, 8 }, { 0, 4, 9 }, { 1, 4, 10 }, { 2, 4, 11 }, { 3, 4, 12 } }; static int betw_hex[12][3] = { { 0, 1, 8 }, { 2, 3, 9 }, { 3, 0, 10 }, { 1, 2, 11 }, { 4, 5, 12 }, { 6, 7, 13 }, { 7, 4, 14 }, { 5, 6, 15 }, { 0, 4, 16 }, { 1, 5, 17 }, { 2, 6, 18 }, { 3, 7, 19 }, }; 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; } case PRISM15: { betw = betw_prism15; newel.SetType(PRISM15); onp = 6; break; } case PYRAMID: case PYRAMID13: { betw = betw_pyramid; newel.SetType(PYRAMID13); onp = 5; break; } case HEX: case HEX20: { betw = betw_hex; newel.SetType (HEX20); onp = 8; break; } default: PrintSysError ("MakeSecondOrder, illegal vol type ", int(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())), mesh.Point(i2.I1()).GetLayer(), INNERPOINT); between.Set (i2, newel.PNum(onp+1+j)); } } mesh.VolumeElement (ei) = 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++) { idmap_type identmap; mesh.GetIdentifications().GetMap (i, identmap); for (INDEX_2_HASHTABLE::Iterator it = between.Begin(); it != between.End(); it++) { PointIndices<2> i2; PointIndex newpi; between.GetData (it, i2, newpi); PointIndices<2> oi2(identmap[i2[0]], identmap[i2[1]]); oi2.Sort(); if (between.Used (oi2)) { PointIndex 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::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 i, j; NgArray parents(np); for (int i = 1; i <= np; i++) parents.Elem(i) = INDEX_2(0,0); // for (int i = 1; i <= ne; i++) for (ElementIndex ei : mesh.VolumeElements().Range()) { const Element & el = mesh[ei]; 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, NgArray & parents) { // int i, j, k; // homotopy method int ne = mesh.GetNE(); int cnttrials = 100; int wrongels = 0; // for (int i = 1; i <= ne; i++) for (ElementIndex ei : mesh.VolumeElements().Range()) if (mesh.VolumeElement(ei).CalcJacobianBadness (mesh.Points()) > 1e10) { wrongels++; mesh.VolumeElement(ei).Flags().badel = 1; } else mesh.VolumeElement(ei).Flags().badel = 0; double facok = 0; double factry; BitArray illegalels(ne+1); illegalels.Clear(); if (wrongels) { cout << "WARNING: " << wrongels << " illegal element(s) found" << endl; int np = mesh.GetNP(); NgArray > should(np); NgArray > 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())); } TBitArray boundp(np); boundp.Clear(); /* for (int i = 1; i <= mesh.GetNSE(); i++) { const Element2d & sel = mesh.SurfaceElement(i); */ for (auto & sel : mesh.SurfaceElements()) for (int j = 1; j <= sel.GetNP(); j++) boundp.SetBit(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.SetBit(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; } */ } } ================================================ FILE: libsrc/meshing/smoothing2.5.cpp ================================================ #include #include "meshing.hpp" #include namespace netgen { void MeshOptimize2d :: ProjectBoundaryPoints(NgArray & surfaceindex, const NgArray* > & from, NgArray* > & dest) { for(int i=0; i= 0) { *dest[i] = *from[i]; geo.ProjectPoint(surfaceindex[i],*dest[i]); } } } void MeshOptimize2d :: ImproveVolumeMesh () { if (!faceindex) { PrintMessage (3, "Smoothing"); for (faceindex = 1; faceindex <= mesh.GetNFD(); faceindex++) { ImproveVolumeMesh (); 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 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); NgArray savepoints(mesh.GetNP()); NgArray 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 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(); TBitArray 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.SetBit (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; NgArray locelements(0); NgArray locrots(0); // for (PointIndex pi = mesh.Points().Begin(); pi < mesh.Points().End(); pi++) for (PointIndex pi : mesh.Points().Range()) { 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 = (geo.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(); } } ================================================ FILE: libsrc/meshing/smoothing2.cpp ================================================ #include #include "meshing.hpp" #include 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 Point<3> & p1, const Point<3> & p2, const Point<3> & p3, double metricweight, double h) { // badness = sqrt(3.0) / 12 * (\sum l_i^2) / area - 1 Vec<3> e12 = p2-p1; Vec<3> e13 = p3-p1; Vec<3> e23 = p3-p2; double cir_2 = e12.Length2() + e13.Length2() + e23.Length2(); double area = 0.5 * Cross (e12, e13).Length(); if (area <= 1e-24 * cir_2) return 1e10; double badness = c_trig * cir_2 / area - 1; if (metricweight > 0) { // add: metricweight * (area / h^2 + h^2 / area - 2) area *= 2; // optimum for (2 area) is h^2 double areahh = area / (h * h); badness += metricweight * (areahh + 1 / areahh - 2); } return badness; } double CalcTriangleBadnessGrad (const Point<3> & p1, const Point<3> & p2, const Point<3> & p3, Vec<3> & gradp1, double metricweight, double h) { // badness = sqrt(3.0) / 12 * (\sum l_i^2) / area - 1 Vec<3> e12 = p2-p1; Vec<3> e13 = p3-p1; Vec<3> e23 = p3-p2; double cir_2 = e12.Length2() + e13.Length2() + e23.Length2(); Vec<3> varea = Cross(e12, e13); double area = 0.5 * varea.Length(); Vec<3> dcir_2 = (-2) * (e12+e13); Vec<3> darea = (0.25/area) * Cross (p2-p3, varea); if (area <= 1e-24 * cir_2) { gradp1 = 0; return 1e10; } double badness = c_trig * cir_2 / area - 1; gradp1 = c_trig * (1.0/area * dcir_2 - cir_2 / (area*area) * darea); if (metricweight > 0) { // add: metricweight * (area / h^2 + h^2 / area - 2) area *= 2; // optimum for (2 area) is h^2 double areahh = area / (h * h); badness += metricweight * (areahh + 1 / areahh - 2); gradp1 += (2*metricweight * (1/(h*h) - (h*h)/(area*area))) * darea; } return badness; } double CalcTriangleBadness (const Point<3> & p1, const Point<3> & p2, const Point<3> & p3, const Vec<3> & n, double metricweight, double h) { Vec<3> v1 = p2-p1; Vec<3> v2 = p3-p1; Vec<3> e1 = v1; Vec<3> 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; NgArray locelements; NgArray locrots; NgArray lochs; NgArray > loc_pnts2, loc_pnts3; // static int locerr2; double locmetricweight; double loch; int surfi, surfi2; int uselocalh; public: Opti2dLocalData () { locmetricweight = 0; } }; class Opti2SurfaceMinFunction : public MinFunction { Opti2dLocalData & ld; const NetgenGeometry& geo; public: Opti2SurfaceMinFunction (const Mesh & amesh, Opti2dLocalData & ald) : ld(ald), geo(*amesh.GetGeometry()) { } ; virtual double Func (const Vector & x) const override { double badness = 0; auto n = geo.GetNormal(ld.surfi, ld.sp1, &ld.gi1); Point<3> pp1 = ld.sp1 + x(0) * ld.t1 + x(1) * ld.t2; for (int j = 0; j < ld.locelements.Size(); j++) { Vec<3> e1 = ld.loc_pnts2[j] - pp1; Vec<3> e2 = ld.loc_pnts3[j] - pp1; if (ld.uselocalh) ld.loch = ld.lochs[j]; if (Determinant(e1, e2, n) > 1e-8 * ld.loch * ld.loch) { badness += CalcTriangleBadness (pp1, ld.loc_pnts2[j], ld.loc_pnts3[j], ld.locmetricweight, ld.loch); } else { badness += 1e8; } } return badness; } virtual double FuncGrad (const Vector & x, Vector & g) const override { Vec<3> vgrad; Point<3> pp1; vgrad = 0; double badness = 0; pp1 = ld.sp1 + x(0) * ld.t1 + x(1) * ld.t2; for (int j = 0; j < ld.locelements.Size(); j++) { Vec<3> e1 = ld.loc_pnts2[j] - pp1; Vec<3> e2 = ld.loc_pnts3[j] - pp1; if (ld.uselocalh) ld.loch = ld.lochs[j]; if (Determinant(e1, e2, ld.normal) > 1e-8 * ld.loch * ld.loch) { Vec<3> hgrad; badness += CalcTriangleBadnessGrad (pp1, ld.loc_pnts2[j], ld.loc_pnts3[j], hgrad, ld.locmetricweight, ld.loch); vgrad += hgrad; } else { badness += 1e8; } } g(0) = ld.t1 * vgrad; g(1) = ld.t2 * vgrad; return badness; } virtual double FuncDeriv (const Vector & x, const Vector & dir, double & deriv) const override { deriv = 0; double badness = 0; Point<3> pp1 = ld.sp1 + x(0) * ld.t1 + x(1) * ld.t2; Vec<3> dir3d = dir(0) * ld.t1 + dir(1) * ld.t2; for (int j = 0; j < ld.locelements.Size(); j++) { Vec<3> e1 = ld.loc_pnts2[j] - pp1; Vec<3> e2 = ld.loc_pnts3[j] - pp1; if (ld.uselocalh) ld.loch = ld.lochs[j]; if (Determinant(e1, e2, ld.normal) > 1e-8 * ld.loch * ld.loch) { Vec<3> hgrad; badness += CalcTriangleBadnessGrad (pp1, ld.loc_pnts2[j], ld.loc_pnts3[j], hgrad, ld.locmetricweight, ld.loch); deriv += dir3d * hgrad; } else { badness += 1e8; } } // cout << "deriv = " << deriv << " =?= "; return badness; /* static int timer = NgProfiler::CreateTimer ("opti2surface - deriv"); NgProfiler::RegionTimer reg (timer); double eps = 1e-6; Vector xr(2), xl(2); xr = x; xl = x; for (int i = 0; i < 2; i++) { xr(i) = x(i) + eps * dir(i); xl(i) = x(i) - eps * dir(i); } deriv = (Func (xr) - Func(xl) ) / (2*eps); cout << deriv << endl; return Func(x); */ } virtual double XXFuncGrad (const Vector & x, Vector & g) const; virtual double XXFuncDeriv (const Vector & x, const Vector & dir, double & deriv) const; }; /* double Opti2SurfaceMinFunction :: Func (const Vector & x) const { static int timer = NgProfiler::CreateTimer ("opti2surface - func"); NgProfiler::RegionTimer reg (timer); Vector g(x.Size()); return FuncGrad (x, g); } */ double Opti2SurfaceMinFunction :: XXFuncGrad (const Vector & x, Vector & grad) const { // static int timer = NgProfiler::CreateTimer ("opti2surface - funcgrad"); // NgProfiler::RegionTimer reg (timer); Vec<3> vgrad; Point<3> pp1; vgrad = 0; double badness = 0; auto n = geo.GetNormal(ld.surfi, ld.sp1, &ld.gi1); 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++) { double g1x, g1y, hbadness; Vec<3> e1 = ld.loc_pnts2[j] - pp1; Vec<3> e2 = ld.loc_pnts3[j] - 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 :: XXFuncDeriv (const Vector & x, const Vector & dir, double & deriv) const { // static int timer = NgProfiler::CreateTimer ("opti2surface - funcderiv"); // NgProfiler::RegionTimer reg (timer); Vec<3> vgrad; Point<3> pp1; vgrad = 0; double badness = 0; auto n = geo.GetNormal(ld.surfi, ld.sp1, &ld.gi1); pp1 = ld.sp1 + x(0) * ld.t1 + x(1) * ld.t2; for (int j = 0; j < ld.locelements.Size(); j++) { double g1x, g1y, hbadness; /* 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; */ Vec<3> e1 = ld.loc_pnts2[j] - pp1; Vec<3> e2 = ld.loc_pnts3[j] - 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; const NetgenGeometry& geo; public: Opti2EdgeMinFunction (const Mesh & amesh, Opti2dLocalData & ald) : mesh(amesh), ld(ald), geo(*amesh.GetGeometry()) { } ; virtual double FuncGrad (const Vector & x, Vector & g) const override; virtual double Func (const Vector & x) const override; }; 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> 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; geo.ProjectPointEdge(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; } auto n1 = geo.GetNormal(ld.surfi, pp1); auto n2 = geo.GetNormal(ld.surfi2, pp1); v1 = Cross (n1, n2); v1.Normalize(); grad(0) = (vgrad * v1) * (ld.t1 * v1); return badness; } class Opti2SurfaceMinFunctionJacobian : public MinFunction { const Mesh & mesh; Opti2dLocalData & ld; const NetgenGeometry& geo; public: Opti2SurfaceMinFunctionJacobian (const Mesh & amesh, Opti2dLocalData & ald) : mesh(amesh), ld(ald), geo(*amesh.GetGeometry()) { } ; virtual double FuncGrad (const Vector & x, Vector & g) const override; virtual double FuncDeriv (const Vector & x, const Vector & dir, double & deriv) const override; virtual double Func (const Vector & x) const override; }; 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> vgrad; Point<3> pp1; Vec<2> g1, vdir; double badness, hbad, hderiv; vgrad = 0; badness = 0; // auto n = geo.GetNormal(ld.surfi, ld.sp1, &ld.gi1); pp1 = ld.sp1 + x(0) * ld.t1 + x(1) * ld.t2; // meshthis -> ProjectPoint (surfi, pp1); // meshthis -> GetNormalVector (surfi, pp1, n); static NgArray> pts2d; // better: use hashtable 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) = { x(0), x(1) }; for (int k = 1; k <= 2; k++) { if (k == 1) vdir = {1., 0.}; else vdir = {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> vgrad; Point<3> pp1; Vec<2> g1, vdir; double badness, hbad, hderiv; vgrad = 0; badness = 0; // pp1 = sp1; // pp1.Add2 (x.Get(1), t1, x.Get(2), t2); pp1 = ld.sp1 + x(0) * ld.t1 + x(1) * ld.t2; static NgArray> 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 = { dir(0), dir(1) }; hbad = bel. CalcJacobianBadnessDirDeriv (pts2d, lpi, vdir, hderiv); deriv += hderiv; badness += hbad; } return badness; } void MeshOptimize2d :: ImproveMesh (const MeshingParameters & mp) { static Timer timer("MeshSmoothing 2D"); RegionTimer reg (timer); PrintMessage (3, "Smoothing"); CheckMeshApproximation (mesh); int ncolors; Array colors; bool mixed = false; // auto elementsonpoint = mesh.CreatePoint2SurfaceElementTable( faceindex ); auto elementsonpoint = mesh.CreateCompressedPoint2SurfaceElementTable( faceindex ); NgArray savepoints(mesh.GetNP()); Table color_table; if(faceindex) { Array seia; mesh.GetSurfaceElementsOfFace (faceindex, seia); for (auto sei : seia) if (mesh[sei].GetNP() != 3) { mixed = true; break; } Array compress(mesh.GetNP()); NgArray icompress; for (int i = 0; i < seia.Size(); i++) { const Element2d & el = mesh[seia[i]]; for (int j = 0; j < el.GetNP(); j++) compress[el[j]] = -1; } for (int i = 0; i < seia.Size(); i++) { const Element2d & el = mesh[seia[i]]; for (int j = 0; j < el.GetNP(); j++) if (compress[el[j]] == -1) { compress[el[j]] = icompress.Size(); icompress.Append(el[j]); } } const auto & getDofs = [&] (int i) { return elementsonpoint[icompress[i]]; }; colors.SetSize(icompress.Size()); ncolors = ngcore::ComputeColoring( colors, mesh.GetNSE(), getDofs ); TableCreator creator(ncolors); for ( ; !creator.Done(); creator++) ParallelForRange( Range(colors), [&](auto myrange) { for(auto i : myrange) creator.Add(colors[i], icompress[i]); }); color_table = creator.MoveTable(); } else { for (auto & se : mesh.SurfaceElements()) if (se.GetNP() != 3) { for(auto pi : se.PNums()) if(mesh[pi].Type() == SURFACEPOINT) { mixed = true; break; } if(mixed) break; } const auto & getDofs = [&] (int i) { return elementsonpoint[i+PointIndex::BASE]; }; colors.SetSize(mesh.GetNP()); ncolors = ngcore::ComputeColoring( colors, mesh.GetNSE(), getDofs ); TableCreator creator(ncolors); for ( ; !creator.Done(); creator++) ParallelForRange( Range(colors), [&](auto myrange) { for(auto i : myrange) creator.Add(colors[i], PointIndex(i+PointIndex::BASE)); }); color_table = creator.MoveTable(); } /* int i, j, k; Vector xedge(1); 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) { Vec3d n1, n2; 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)); } } */ // NgProfiler::StopTimer (timer1); /* for (PointIndex pi = PointIndex::BASE; pi < mesh.GetNP()+PointIndex::BASE; pi++) if (mesh[pi].Type() == SURFACEPOINT) */ static Timer tloop("MeshSmooting 2D - loop"); tloop.Start(); for (auto icolor : Range(color_table)) { if (multithread.terminate) break; ParallelForRange( Range(color_table[icolor].Size()), [&](auto myrange) { Opti2dLocalData ld; ld.uselocalh = mp.uselocalh; ld.loch = mp.maxh; ld.locmetricweight = metricweight; ld.meshthis = this; Opti2SurfaceMinFunction surfminf(mesh, ld); Opti2SurfaceMinFunctionJacobian surfminfj(mesh, ld); MinFunction & minfunc = mixed ? static_cast(surfminfj) : surfminf; OptiParameters par; par.maxit_linsearch = 8; par.maxit_bfgs = 5; for (auto i : myrange) { PointIndex pi = color_table[icolor][i]; if (mesh[pi].Type() == SURFACEPOINT) { if (multithread.terminate) return; 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); ld.loc_pnts2.SetSize (0); ld.loc_pnts3.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); ld.loc_pnts2.Append (mesh[bel.PNumMod(k + 1)]); ld.loc_pnts3.Append (mesh[bel.PNumMod(k + 2)]); break; } if (ld.uselocalh) { Point3d pmid = Center (mesh[bel[0]], mesh[bel[1]], mesh[bel[2]]); ld.lochs.Append (mesh.GetH(pmid)); } } ld.normal = geo.GetNormal(ld.surfi, ld.sp1, &ld.gi1); ld.t1 = ld.normal.GetNormal (); ld.t2 = Cross (ld.normal, ld.t1); if(mixed) { // save points, and project to tangential plane (only for optimization with Opti2SurfaceMinFunctionJacobian in mixed element meshes) 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; } } } Vector x(2); x = 0; par.typx = 0.3*ld.lochs[0]; // NgProfiler::StartTimer (timer2); BFGS (x, minfunc, par, 1e-6); // NgProfiler::StopTimer (timer2); auto origp = mesh[pi]; int loci = 1; double fact = 1; int moveisok = 0; if(mixed) { // 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]); PointGeomInfo ngi; ngi = ld.gi1; moveisok = geo.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] = origp; } } } } }, mixed ? 1 : ngcore::TasksPerThread(4)); // mixed element smoothing not parallel yet } tloop.Stop(); CheckMeshApproximation (mesh); mesh.SetNextTimeStamp(); } } ================================================ FILE: libsrc/meshing/smoothing3.cpp ================================================ #include #include "meshing.hpp" #ifdef SOLIDGEOM #include #endif #include #include #include namespace netgen { using namespace ngcore; double MinFunctionSum :: Func (const Vector & x) const { double retval = 0; for(int i=0; iFunc(x); return retval; } void MinFunctionSum :: Grad (const Vector & x, Vector & g) const { g = 0.; VectorMem<3> gi; for(int i=0; iGrad(x,gi); for(int j=0; j gi; for(int i=0; iFuncGrad(x,gi); for(int j=0; jFuncDeriv(x,dir,derivi); deriv += derivi; } return retval; } double MinFunctionSum :: GradStopping (const Vector & x) const { double minfs(0), mini; for(int i=0; iGradStopping(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 NgArray> & 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[PointIndex (el.I1())], points[PointIndex (el.I3())], points[PointIndex (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 NgArray & faces; DenseMatrix m; double h; public: CheapPointFunction1 (Mesh::T_POINTS & apoints, const NgArray & 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 NgArray & 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[PointIndex(faces.Get(i).I1())]; const Point3d & p2 = points[PointIndex(faces.Get(i).I2())]; const Point3d & p3 = points[PointIndex(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 Array & elements; Table &elementsonpoint; bool own_elementsonpoint; const MeshingParameters & mp; PointIndex actpind; double h; public: PointFunction (Mesh & mesh, const MeshingParameters & amp); PointFunction (const PointFunction & pf); virtual ~PointFunction () { if(own_elementsonpoint) delete &elementsonpoint; } virtual void SetPointIndex (PointIndex aactpind); void SetLocalH (double ah) { h = ah; } double GetLocalH () const { return h; } const Table & GetPointToElementTable() { return elementsonpoint; }; 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 (const PointFunction & pf) : points(pf.points), elements(pf.elements), elementsonpoint(pf.elementsonpoint), own_elementsonpoint(false), mp(pf.mp) { } PointFunction :: PointFunction (Mesh & mesh, const MeshingParameters & amp) : points(mesh.Points()), elements(mesh.VolumeElements()), elementsonpoint(* new Table()), own_elementsonpoint(true), mp(amp) { static Timer tim("PointFunction - build elementsonpoint table"); RegionTimer reg(tim); Array non_tet_points(points.Size()); non_tet_points = false; // Don't optimize if point is adjacent to a non-tet element ParallelForRange(elements.Range(), [&] (auto myrange) { for(auto ei : myrange) { const auto & el = elements[ei]; if(el.NP()!=4) for(auto pi : el.PNums()) non_tet_points[pi] = true; } }); elementsonpoint = ngcore::CreateSortedTable( elements.Range(), [&](auto & table, ElementIndex ei) { const auto & el = elements[ei]; if(el.NP()!=4 || (mp.only3D_domain_nr && mp.only3D_domain_nr != el.GetIndex()) ) return; for (PointIndex pi : el.PNums()) if(!non_tet_points[pi]) table.Add (pi, ei); }, points.Size()); } 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 (auto ei : elementsonpoint[actpind]) { const Element & el = elements[ei]; 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 (auto ei : elementsonpoint[actpind]) { const Element & el = elements[ei]; 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 (auto ei : elementsonpoint[actpind]) { const Element & el = elements[ei]; 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 NgArray faces; for (auto ei : elementsonpoint[actpind]) { const Element & el = elements[ei]; for (int k = 1; k <= 4; k++) if (el.PNum(k) == actpind) { Element2d face(TRIG); 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 & mesh, 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 & mesh, const MeshingParameters & amp) : PointFunction (mesh, amp) { ; } void CheapPointFunction :: SetPointIndex (PointIndex aactpind) { actpind = aactpind; int ne = elementsonpoint[actpind].Size(); int i, j; PointIndex 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 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 NgArray & elements; // TABLE elementsonpoint; // PointIndex actpind; // public: // JacobianPointFunction (Mesh::T_POINTS & apoints, // const NgArray & 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 Array & aelements) : points(apoints), elements(aelements), elementsonpoint(apoints.Size()) { for (int i = 0; i < elements.Size(); i++) for (int j = 1; j <= elements[i].NP(); j++) elementsonpoint.Add1 (elements[i].PNum(j), i+1); onplane = false; } void JacobianPointFunction :: SetPointIndex (PointIndex aactpind) { actpind = aactpind; } double JacobianPointFunction :: Func (const Vector & v) const { double badness = 0; Point<3> hp = points[actpind]; points[actpind] = hp + Vec<3> (v(0), v(1), v(2)); if(onplane) points[actpind] -= (v(0)*nv(0)+v(1)*nv(1)+v(2)*nv(2)) * nv; for (auto eli : elementsonpoint[actpind]) badness += elements[eli].CalcJacobianBadness (points); points[actpind] = hp; return badness; } double JacobianPointFunction :: FuncGrad (const Vector & x, Vector & g) const { int k; int lpi; double badness = 0;//, hbad; Point<3> hp = points[actpind]; points[actpind] = hp + Vec<3> (x(0), x(1), x(2)); if(onplane) points[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 (auto ei : elementsonpoint[actpind]) { const Element & el = elements[ei]; 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[ei]. 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[actpind] = hp; return badness; } double JacobianPointFunction :: FuncDeriv (const Vector & x, const Vector & dir, double & deriv) const { int k; int lpi; double badness = 0; Point<3> hp = points[actpind]; points[actpind] = Point<3> (hp + Vec3d (x(0), x(1), x(2))); if(onplane) points[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 (auto ei : elementsonpoint[actpind]) { const Element & el = elements[ei]; 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[ei]. CalcJacobianBadnessDirDeriv (points, lpi, vdir, hderiv); deriv += hderiv; } points[actpind] = hp; return badness; } #ifdef SOLIDGEOMxxxx void Mesh :: ImproveMesh (const CSG eometry & 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 = "Optimize Volume: Smooth Mesh"; TABLE 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), points.Get(i).GetLayer()); pf->SetLocalH (lh); 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) { static Timer t("Mesh::ImproveMesh"); RegionTimer reg(t); static Timer tcoloring("coloring"); static Timer tcalcbadmax("Calc badmax"); static Timer topt("optimize"); static Timer trange("range"); static Timer tloch("loch"); BuildBoundaryEdges(false); (*testout) << "Improve Mesh" << "\n"; PrintMessage (3, "ImproveMesh"); // int np = GetNP(); int ne = GetNE(); PointFunction pf_glob(*this, mp); auto & elementsonpoint = pf_glob.GetPointToElementTable(); const auto & getDofs = [&] (int i) { return elementsonpoint[i += PointIndex::BASE]; }; Array colors(points.Size()); tcoloring.Start(); int ncolors = ngcore::ComputeColoring( colors, ne, getDofs ); auto color_table = CreateTable( points.Size(), [&] ( auto & table, int i ) { PointIndex pi = i+static_cast(PointIndex::BASE); table.Add(colors[i], pi); }, ncolors); tcoloring.Stop(); if (goal == OPT_QUALITY) { double bad1 = CalcTotalBad (mp); (*testout) << "Total badness = " << bad1 << endl; PrintMessage (5, "Total badness = ", bad1); } (*testout) << setprecision(8); Array pointh (points.Size()); if(HasLocalHFunction()) { RegionTimer rt(tloch); ParallelForRange(points.Range(), [&] (auto myrange) { for(auto pi : myrange) pointh[pi] = GetH(pi); }); } else { pointh = 0; for (Element & el : VolumeElements()) { double h = pow(el.Volume(points),1./3.); for (PointIndex pi : el.PNums()) if (h > pointh[pi]) pointh[pi] = h; } } const char * savetask = multithread.task; multithread.task = "Optimize Volume: Smooth Mesh"; topt.Start(); for (auto icolor : Range(ncolors)) { if (multithread.terminate) throw NgException ("Meshing stopped"); ParallelForRange( color_table[icolor].Range(), [&](auto myrange) { RegionTracer reg(ngcore::TaskManager::GetThreadId(), trange, myrange.Size()); Vector x(3); PointFunction pf{pf_glob}; Opti3FreeMinFunction freeminf(pf); OptiParameters par; par.maxit_linsearch = 20; par.maxit_bfgs = 20; for (auto i : myrange) { PointIndex pi = color_table[icolor][i]; if ( (*this)[pi].Type() == INNERPOINT ) { double lh = pointh[pi]; pf.SetLocalH (lh); par.typx = lh; freeminf.SetPoint (points[pi]); pf.SetPointIndex (pi); x = 0; int pok; pok = freeminf.Func (x) < 1e10; if (!pok) { pok = pf.MovePointToInner (); freeminf.SetPoint (points[pi]); pf.SetPointIndex (pi); } if (pok) { //*testout << "start BFGS, pok" << endl; BFGS (x, freeminf, par); //*testout << "BFGS complete, pok" << endl; points[pi](0) += x(0); points[pi](1) += x(1); points[pi](2) += x(2); } } } }, 4*ngcore::TaskManager::GetNumThreads()); } topt.Stop(); multithread.task = savetask; if (goal == OPT_QUALITY) { double bad1 = CalcTotalBad (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 TBitArray * 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; TBitArray badnodes(np); badnodes.Clear(); for (int i = 1; i <= ne; i++) { const Element & el = VolumeElement(i); double bad = el.CalcJacobianBadness (Points()); if (bad > 1) for (int j = 1; j <= el.GetNP(); j++) badnodes.SetBit (el.PNum(j)); } Array pointh (points.Size()); if(HasLocalHFunction()) { // for(i = 1; i<=points.Size(); i++) for (PointIndex pi : points.Range()) pointh[pi] = GetH(pi); } else { pointh = 0; for (int i=0; i pointh[el.PNum(j)]) pointh[el.PNum(j)] = h; } } const char * savetask = multithread.task; multithread.task = "Optimize Volume: Smooth Mesh Jacobian"; // for (PointIndex pi = points.Begin(); i < points.End(); pi++) for (PointIndex pi : points.Range()) { if ((*this)[pi].Type() != INNERPOINT) continue; if(usepoint && !usepoint->Test(pi)) continue; //(*testout) << "improvejac, p = " << i << endl; if (goal == OPT_WORSTCASE && !badnodes.Test(pi)) continue; // (*testout) << "smooth p " << i << endl; /* if (multithread.terminate) break; */ if (multithread.terminate) throw NgException ("Meshing stopped"); multithread.percent = 100.0 * pi / points.Size(); if (points.Size() < 1000) PrintDot (); else if (pi % 10 == 0) PrintDot ('+'); double lh = pointh[pi]; par.typx = lh; pf.SetPointIndex (pi); 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[pi](0) += x(0); points[pi](1) += x(1); points[pi](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 TBitArray & usepoint, const NgArray< Vec<3>* > & nv, OPTIMIZEGOAL goal, const NgArray< idmap_type* > * 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); NgArray< idmap_type* > locidmaps; const NgArray< idmap_type* > * used_idmaps; if(idmaps) used_idmaps = idmaps; else { used_idmaps = &locidmaps; for(int i=1; i<=GetIdentifications().GetMaxNr(); i++) { if(GetIdentifications().GetType(i) == Identifications::PERIODIC) { locidmaps.Append(new idmap_type); 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; TBitArray badnodes(np); badnodes.Clear(); for (int i = 1; i <= ne; i++) { const Element & el = VolumeElement(i); double bad = el.CalcJacobianBadness (Points()); if (bad > 1) for (int j = 1; j <= el.GetNP(); j++) badnodes.SetBit (el.PNum(j)); } NgArray pointh (points.Size()); if(HasLocalHFunction()) { // for(i=1; i<=points.Size(); i++) for (PointIndex pi : points.Range()) pointh[pi] = GetH(pi); } else { pointh = 0; for(int i=0; i pointh[el.PNum(j)]) pointh[el.PNum(j)] = h; } } const char * savetask = multithread.task; multithread.task = "Optimize Volume: Smooth Mesh Jacobian"; // for (PointIndex pi = points.Begin(); pi <= points.End(); pi++) for (PointIndex pi : points.Range()) if ( usepoint.Test(pi) ) { //(*testout) << "improvejac, p = " << i << endl; if (goal == OPT_WORSTCASE && !badnodes.Test(pi)) continue; // (*testout) << "smooth p " << i << endl; /* if (multithread.terminate) break; */ if (multithread.terminate) throw NgException ("Meshing stopped"); multithread.percent = 100.0 * pi / points.Size(); if (points.Size() < 1000) PrintDot (); else if (pi % 10 == 0) PrintDot ('+'); double lh = pointh[pi];//GetH(points.Get(i)); par.typx = lh; pf.SetPointIndex (pi); constexpr PointIndex state0(PointIndex::INVALID); constexpr PointIndex statem1 = state0-1; PointIndex brother = statem1; if(usesum) { for(int j=0; brother == statem1 && jSize(); j++) { if(pi < (*used_idmaps)[j]->Size() + IndexBASE()) { brother = (*(*used_idmaps)[j])[pi]; if(brother == pi || brother == state0) brother = statem1; } } // if(brother >= pi) if(brother-pi >= 0) { pf2ptr->SetPointIndex(brother); pf2ptr->SetNV(*nv[brother-1]); } } // if(usesum && brother < pi) if(usesum && (brother-pi < 0)) continue; //pf.UnSetNV(); x = 0; //(*testout) << "before " << pf.Func(x); pf.SetNV(*nv[pi-1]); x = 0; int pok = (brother == statem1) ? (pf.Func (x) < 1e10) : (pf_sum.Func (x) < 1e10); if (pok) { if(brother == statem1) BFGS (x, pf, par); else BFGS (x, pf_sum, par); for(int j=0; j<3; j++) points[pi](j) += x(j);// - scal*nv[i-1].X(j); if(brother != statem1) for(int j=0; j<3; j++) points[brother](j) += x(j);// - scal*nv[brother-1].X(j); } else { cout << "el not ok" << endl; (*testout) << "el not ok" << endl << " func " << ((brother == statem1) ? pf.Func(x) : pf_sum.Func (x)) << endl; if(brother != statem1) (*testout) << " func1 " << pf.Func(x) << endl << " func2 " << pf2ptr->Func(x) << endl; } } PrintDot ('\n'); delete pf2ptr; for(int i=0; i // for tAVX namespace netgen { using namespace std; class 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 facetnr, 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 */, int facetnr, double /* lam1 */, double /* lam2 */, double * /* values */) { return false; } virtual bool GetSurfValue (int selnr, int facetnr, const double xref[], const double x[], const double dxdxref[], double * values) { return GetSurfValue (selnr, facetnr, xref[0], xref[1], values); } virtual bool GetMultiSurfValue (int selnr, int facetnr, 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, facetnr, &xref[i*sxref], &x[i*sx], &dxdxref[i*sdxdxref], &values[i*svalues]); return res; } virtual bool GetMultiSurfValue (size_t selnr, size_t facetnr, size_t npts, const SIMD * xref, const SIMD * x, const SIMD * dxdxref, SIMD * values) { cerr << "GetMultiSurfVaue not overloaded for SIMD" << endl; return false; } virtual bool GetSegmentValue (int segnr, double xref, double * values) { return false; } virtual int GetNumMultiDimComponents () { return 1; } virtual void SetMultiDimComponent (int mc) { if (mc >= GetNumMultiDimComponents()) mc = GetNumMultiDimComponents()-1; if (mc < 0) mc = 0; multidimcomponent = mc; } }; class DLL_HEADER MouseEventHandler { public: virtual void DblClick (int elnr, double x, double y, double z) = 0; }; class DLL_HEADER UserVisualizationObject { public: virtual ~UserVisualizationObject() { ; } virtual void Draw () = 0; }; } #endif ================================================ FILE: libsrc/meshing/specials.cpp ================================================ #include #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."); NgArray 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; TBitArray 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.SetBit(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.SetBit (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(); TBitArray 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 (PointIndex i (1); i <= locked.Size(); i++) for (PointIndex i : locked.Range()) if (locked.Test(i)) { mesh.AddLockedPoint (i); } NgArray 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; } } } ================================================ FILE: libsrc/meshing/specials.hpp ================================================ #ifndef FILE_SPECIALS #define FILE_SPECIALS /* Very special implementations .. */ namespace netgen { /// DLL_HEADER extern void CutOffAndCombine (Mesh & mesh, const Mesh & othermesh); DLL_HEADER extern void HelmholtzMesh (Mesh & mesh); } // namespace netgen #endif ================================================ FILE: libsrc/meshing/surfacegeom.cpp ================================================ /* *************************************************************************/ /* File: surfacegeom.cpp */ /* Author: Michael Neunteufel */ /* Date: Jun. 2020 */ /* *************************************************************************/ #include namespace netgen { SurfaceGeometry :: SurfaceGeometry() { //identity func = [](Point<2> p) { return Vec<3>(p[0],p[1],0.0); }; } SurfaceGeometry :: SurfaceGeometry(function(Point<2>)> _func) : func(_func) { ; } SurfaceGeometry :: SurfaceGeometry(const SurfaceGeometry& geom) : func(geom.func), eps(geom.eps) { ; } void SurfaceGeometry :: CalcHesse(double u, double v, Vec<3>& f_uu, Vec<3>& f_vv, Vec<3>& f_uv) const { Point<2> p = Point<2>(u,v); double pr = p[0]+eps; double pl = p[0]-eps; double prr = p[0]+2*eps; double pll = p[0]-2*eps; auto dr = GetTangentVectors( pr, v ); auto dl = GetTangentVectors( pl, v ); auto drr = GetTangentVectors( prr, v ); auto dll = GetTangentVectors( pll, v ); f_uu = (1.0/(12.0*eps)) * (8.0*dr[0]-8.0*dl[0]-drr[0]+dll[0]); f_uv = (1.0/(12.0*eps)) * (8.0*dr[1]-8.0*dl[1]-drr[1]+dll[1]); pr = p[1]+eps; pl = p[1]-eps; prr = p[1]+2*eps; pll = p[1]-2*eps; GetTangentVectors(u, pr, dr); GetTangentVectors(u, pl, dl); GetTangentVectors(u, prr, drr); GetTangentVectors(u, pll, dll); f_vv = (1.0/(12.0*eps)) * (8.0*dr[1]-8.0*dl[1]-drr[1]+dll[1]); } Array> SurfaceGeometry :: GetTangentVectors(double u, double v) const { Array> tang(2); Point<2> pru = Point<2>(u+eps,v); Point<2> plu = Point<2>(u-eps,v); Point<2> prru = Point<2>(u+2*eps,v); Point<2> pllu = Point<2>(u-2*eps,v); Point<2> prv = Point<2>(u,v+eps); Point<2> plv = Point<2>(u,v-eps); Point<2> prrv = Point<2>(u,v+2*eps); Point<2> pllv = Point<2>(u,v-2*eps); tang[0] = 1/(12.0*eps)*( 8.0*func(pru) - 8.0*func(plu) - func(prru) + func(pllu) ); tang[1] = 1/(12.0*eps)*( 8.0*func(prv) - 8.0*func(plv) - func(prrv) + func(pllv) ); return tang; } void SurfaceGeometry :: GetTangentVectors(double u, double v, Array>& tang) const { Point<2> pru = Point<2>(u+eps,v); Point<2> plu = Point<2>(u-eps,v); Point<2> prru = Point<2>(u+2*eps,v); Point<2> pllu = Point<2>(u-2*eps,v); Point<2> prv = Point<2>(u,v+eps); Point<2> plv = Point<2>(u,v-eps); Point<2> prrv = Point<2>(u,v+2*eps); Point<2> pllv = Point<2>(u,v-2*eps); tang[0] = 1/(12.0*eps)*( 8.0*func(pru) - 8.0*func(plu) - func(prru) + func(pllu) ); tang[1] = 1/(12.0*eps)*( 8.0*func(prv) - 8.0*func(plv) - func(prrv) + func(pllv) ); } Vec<3> SurfaceGeometry :: GetNormal(int surfind, const Point<3> & p, const PointGeomInfo* gi) const { Array> tang = GetTangentVectors(gi->u, gi->v); auto normal = Cross(tang[0], tang[1]); normal.Normalize(); return normal; } PointGeomInfo SurfaceGeometry :: ProjectPoint(int surfind, Point<3> & p) const { throw Exception("In SurfaceGeometry::ProjectPoint"); } void SurfaceGeometry :: ProjectPointEdge (int surfind, int surfind2, Point<3> & p, EdgePointGeomInfo* gi) const { if (gi == nullptr) throw Exception("In SurfaceGeometry::ProjectPointEdge: gi is nullptr"); throw Exception("In SurfaceGeometry::ProjectPointEdge: not implemented"); } bool SurfaceGeometry :: ProjectPointGI (int surfind, Point<3> & p, PointGeomInfo & gi) const { Array> tangs(2); Vec<3> diff, f_uu, f_vv, f_uv; Vec<2> r, dx; double norm_r, energy=0.0, new_energy=0.0, alpha=2.0,u=0.0,v=0.0,maxerr=1e-16; Mat<2,2> mat, inv; int num=0, maxit=25; double damping=0.5; //Solve minimization problem // argmin_(u,v) 0.5*\| f(u,v)-p\|^2 //via Neton's method: // F(u,v) = ( (f(u,v)-p)*f_u(u,v), (f(u,v)-p)*f_v(u,v))^T = (0,0)^T //Stiffness matrix // F'(u,v) = ( f_u*f_u + (f-p)*f_uu, f_v*f_u + (f-p)*f_uv, f_v*f_u + (f-p)*f_uv, f_v*f_v + (f-p)*f_vv ) do { num++; GetTangentVectors(gi.u, gi.v,tangs); diff = func(Point<2>(gi.u, gi.v)) - Vec<3>(p); energy = diff.Length2(); r = Vec<2>( diff*tangs[0], diff*tangs[1] ); norm_r = r.Length2(); CalcHesse(gi.u, gi.v, f_uu, f_vv, f_uv); mat(0,0) = tangs[0]*tangs[0] + diff*f_uu; mat(1,0) = mat(0,1) = tangs[0]*tangs[1]+diff*f_uv; mat(1,1) = tangs[1]*tangs[1]+diff*f_vv; CalcInverse(mat,inv); dx = inv*r; //Linesearch alpha = 2.0; do { alpha /= 2.0; u = gi.u - min(1.0,alpha*damping*num)*dx[0]; v = gi.v - min(1.0,alpha*damping*num)*dx[1]; diff = func(Point<2>(u, v)) - Vec<3>(p); new_energy = diff.Length2(); } while (alpha > 1e-10 && new_energy > energy+1e-14); if (alpha <= 1e-10) throw Exception("In SurfaceGeometry::ProjectPointGI: Linesearch min alpha reached!"); gi.u = u; gi.v = v; } while ( norm_r > maxerr && num < maxit); //Stay in reference domain [0,1]^2 if (gi.u < 0 || gi.u > 1 || gi.v < 0 || gi.v > 1) { cout << "Warning: Projected point outside [0,1]^2: u=" << gi.u << ",v=" << gi.v <<". Setting back." << endl; gi.u = min(max(gi.u,0.0),1.0); gi.v = min(max(gi.v,0.0),1.0); } p = Point<3>(func(Point<2>(gi.u,gi.v))); if (num == maxit) { //cout << "In SurfaceGeometry::ProjectPointGI: Newton did not converge" << endl; throw Exception("In SurfaceGeometry::ProjectPointGI: Newton did not converge"); } return true; } bool SurfaceGeometry :: CalcPointGeomInfo(int surfind, PointGeomInfo& gi, const Point<3> & p3) const { throw Exception("In SurfaceGeometry::CalcPointGeomInfo: not implemented"); return false; } void SurfaceGeometry :: PointBetweenEdge(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 { newgi.u = ap1.u+secpoint*(ap2.u-ap1.u); newgi.v = ap1.v+secpoint*(ap2.v-ap1.v); newgi.edgenr = ap1.edgenr; newgi.body = -1; newgi.dist = -1.0; newp = Point<3>(func(Point<2>(newgi.u, newgi.v))); } void CheckForBBBPnt(const Array>& bbbpts, const Point<3>& pnt, Array& found, Array& indbbbpts, const Array& pids) { for (int k = 0; k < bbbpts.Size(); k++) { auto diff = pnt - bbbpts[k]; if(diff.Length2() < 1e-14) { found[k] = true; indbbbpts[k] = pids[pids.Size()-1]; } } } void CheckForSingularity(const Array>& hppoints, const Point<3>& pnt, const Array& hpptsfac, shared_ptr & mesh, const Array& pids) { for (int k = 0; k < hppoints.Size(); k++) { auto diff = pnt - hppoints[k]; if(diff.Length2() < 1e-14) { (*mesh)[pids[pids.Size()-1]].Singularity(hpptsfac[k]); } } } void SurfaceGeometry :: 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 { newgi.u = gi1.u+secpoint*(gi2.u-gi1.u); newgi.v = gi1.v+secpoint*(gi2.v-gi1.v); newgi.trignum = -1; newp = Point<3>(func(Point<2>(newgi.u, newgi.v))); //newp = p1+secpoint*(p2-p1); //ProjectPointGI(surfi, newp, newgi); } int SurfaceGeometry :: GenerateStructuredMesh(shared_ptr & mesh, bool quads, int nx, int ny, bool flip_triangles, const Array>& bbbpts, const Array& bbbnames, const Array>& hppoints, const Array& hpptsfac, const Array& hpbnd, const Array& hpbndfac, Array layer_thickness[4], bool layer_quad) { mesh->SetDimension(3); Array found(bbbpts.Size()); found = false; Array indbbbpts(bbbpts.Size()); int numx = nx; int numy = ny; size_t total_layer_el[4] = {layer_thickness[0].Size(), layer_thickness[1].Size(), layer_thickness[2].Size(), layer_thickness[3].Size()}; double interior_x = 1.0; double interior_y = 1.0; for(double scale : layer_thickness[0]) interior_x -= scale; for(double scale : layer_thickness[2]) interior_x -= scale; for(double scale : layer_thickness[1]) interior_y -= scale; for(double scale : layer_thickness[3]) interior_y -= scale; auto AddPoint = [&] (double offsetx, double offsety, Array & pids, Array & pgis) { PointGeomInfo pgi; pgi.trignum = -1; pgi.u = offsetx; pgi.v = offsety; Point<3> pnt = Point<3>(func(Point<2>(pgi.u,pgi.v))); pids.Append(mesh->AddPoint(pnt)); pgis.Append(pgi); CheckForBBBPnt(bbbpts, pnt, found, indbbbpts, pids); CheckForSingularity(hppoints, pnt, hpptsfac, mesh, pids); }; auto InternalLoop = [&] (double offsety, Array & pids, Array & pgis) { int j = 0; double offsetx = 0.0; for(int l=0; l < layer_thickness[0].Size(); l++,j++) { AddPoint(offsetx+layer_thickness[0][l]*double(j-l), offsety, pids, pgis); offsetx += layer_thickness[0][l]; } for(;j <= nx-total_layer_el[2]; j++) AddPoint(offsetx + interior_x*double(j-total_layer_el[0])/(nx-total_layer_el[0]-total_layer_el[2]), offsety, pids, pgis); offsetx += interior_x; int startj = j; for(int l=0; l < layer_thickness[2].Size(); l++, j++) { AddPoint(offsetx+layer_thickness[2][layer_thickness[2].Size()-1-l]*double(j-startj-l+1), offsety, pids, pgis); offsetx += layer_thickness[2][layer_thickness[2].Size()-1-l]; } }; Array pids; Array pgis; int i = 0; double offsety = 0.0; for(int k=0; k < layer_thickness[1].Size(); k++,i++) { InternalLoop(offsety, pids, pgis); offsety += layer_thickness[1][k]; } for(; i <= ny-total_layer_el[3]; i++) { InternalLoop(offsety, pids, pgis); offsety += interior_y/(ny-total_layer_el[1]-total_layer_el[3]); } offsety -= interior_y/(ny-total_layer_el[1]-total_layer_el[3]); for(int k=0; k < layer_thickness[3].Size(); k++,i++) { offsety += layer_thickness[3][layer_thickness[3].Size()-1-k]; InternalLoop(offsety, pids, pgis); } for (bool f : found) if (!f) throw Exception("In SurfaceGeometry :: GenerateMesh: bbbpts not resolved in mesh."); FaceDescriptor fd; fd.SetSurfNr(1); fd.SetDomainIn(1); fd.SetDomainOut(0); fd.SetBCProperty(1); mesh->AddFaceDescriptor(fd); for(int i=0; i < numy; i++) { for(int j=0; j < numx; j++) { int base = i * (numx+1) + j; if (quads || (layer_quad && i < total_layer_el[1]) || (layer_quad && i > numy-1-total_layer_el[3]) || (layer_quad && j < total_layer_el[0]) || (layer_quad && j > numx-1-total_layer_el[2]) ) { int pnum[4] = {base,base+1,base+numx+2,base+numx+1}; Element2d el = Element2d(QUAD); for (int i = 0; i < 4; i++) { el[i] = pids[pnum[i]]; el.GeomInfoPi(i+1) = pgis[pnum[i]]; } el.SetIndex(1); mesh->AddSurfaceElement(el); } else { Array pnum1(3); Array pnum2(3); if (flip_triangles) { pnum1[0] = base; pnum1[1] = base+1; pnum1[2] = base+numx+2; pnum2[0] = base; pnum2[1] = base+numx+2; pnum2[2] = base+numx+1; } else { pnum1[0] = base; pnum1[1] = base+1; pnum1[2] = base+numx+1; pnum2[0] = base+1; pnum2[1] = base+numx+2; pnum2[2] = base+numx+1; } Element2d el = Element2d(TRIG); for (int i = 0; i < 3; i++) { el[i] = pids[pnum1[i]]; el.GeomInfoPi(i+1) = pgis[pnum1[i]]; } el.SetIndex(1); mesh->AddSurfaceElement(el); for (int i = 0; i < 3; i++) { el[i] = pids[pnum2[i]]; el.GeomInfoPi(i+1) = pgis[pnum2[i]]; } mesh->AddSurfaceElement(el); } } } Segment seg; seg.si = 1; seg.edgenr = 1; seg.epgeominfo[0].edgenr = 0; seg.epgeominfo[1].edgenr = 0; //for hp refinement seg.singedge_left = 0; seg.singedge_right = 0; for (size_t i=0; i < hpbnd.Size(); i++) { if (hpbnd[i] == "bottom") { seg.singedge_left = hpbndfac[i]; seg.singedge_right = hpbndfac[i]; } } // needed for codim2 in 3d seg.edgenr = 1; for(int i=0; i < numx; i++) { seg[0] = pids[i]; seg[1] = pids[i+1]; seg.geominfo[0] = pgis[i]; seg.geominfo[1] = pgis[i+1]; seg.epgeominfo[0].u = pgis[i].u; seg.epgeominfo[0].v = pgis[i].v; seg.epgeominfo[0].edgenr = seg.edgenr; seg.epgeominfo[1].u = pgis[i+1].u; seg.epgeominfo[1].v = pgis[i+1].v; seg.epgeominfo[1].edgenr = seg.edgenr; mesh->AddSegment(seg); } seg.si = 2; seg.edgenr = 2; seg.singedge_left = 0; seg.singedge_right = 0; for (size_t i=0; i < hpbnd.Size(); i++) { if (hpbnd[i] == "right") { seg.singedge_left = hpbndfac[i]; seg.singedge_right = hpbndfac[i]; } } for(int i=0; iAddSegment(seg); } seg.si = 3; seg.edgenr = 3; seg.singedge_left = 0; seg.singedge_right = 0; for (size_t i=0; i < hpbnd.Size(); i++) { if (hpbnd[i] == "top") { seg.singedge_left = hpbndfac[i]; seg.singedge_right = hpbndfac[i]; } } for(int i=0; iAddSegment(seg); } seg.si = 4; seg.edgenr = 4; seg.singedge_left = 0; seg.singedge_right = 0; for (size_t i=0; i < hpbnd.Size(); i++) { if (hpbnd[i] == "left") { seg.singedge_left = hpbndfac[i]; seg.singedge_right = hpbndfac[i]; } } for(int i=0; iAddSegment(seg); } mesh->SetCD2Name(1, "bottom"); mesh->SetCD2Name(2, "right"); mesh->SetCD2Name(3, "top"); mesh->SetCD2Name(4, "left"); for (int i = 0; i < bbbpts.Size(); i++) { Element0d el; el.pnum = indbbbpts[i]; el.index = i+1; mesh->pointelements.Append(el); mesh->SetCD3Name(i+1, bbbnames[i]); } mesh->Compress(); mesh->UpdateTopology(); return 0; } }; ================================================ FILE: libsrc/meshing/surfacegeom.hpp ================================================ #ifndef FILE_SURFACEGEOM #define FILE_SURFACEGEOM /* *************************************************************************/ /* File: surfacegeom.hpp */ /* Author: Michael Neunteufel */ /* Date: Jun. 2020 */ /* *************************************************************************/ #include namespace netgen { class DLL_HEADER SurfaceGeometry : public NetgenGeometry { function(Point<2>)> func; double eps=1e-4; private: void CalcHesse(double u, double v, Vec<3>& f_uu, Vec<3>& f_vv, Vec<3>& f_uv) const; public: SurfaceGeometry(); SurfaceGeometry(function(Point<2>)> func); SurfaceGeometry(const SurfaceGeometry& geom); SurfaceGeometry& operator =(const SurfaceGeometry& geom) { func = geom.func; eps = geom.eps; return *this; } Array> GetTangentVectors(double u, double v) const; void GetTangentVectors(double u, double v, Array>& tang) const; virtual Vec<3> GetNormal(int surfind, const Point<3> & p, const PointGeomInfo* gi) const override; virtual PointGeomInfo ProjectPoint(int surfind, Point<3> & p) const override; virtual void ProjectPointEdge (int surfind, int surfind2, Point<3> & p, EdgePointGeomInfo* gi = nullptr) const override; virtual bool ProjectPointGI (int surfind, Point<3> & p, PointGeomInfo & gi) const override; virtual bool CalcPointGeomInfo(int surfind, PointGeomInfo& gi, const Point<3> & p3) const override; virtual void PointBetweenEdge(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 override; 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 override; int GenerateStructuredMesh(shared_ptr & mesh, bool quads, int nx, int ny, bool flip_triangles, const Array>& bbbpts, const Array& bbbnames, const Array>& hppoints, const Array& hpptsfac, const Array& hpbnd, const Array& hpbndfac, Array layer_thickness[4], bool layer_quad); }; } #endif //SURFACEGEOM ================================================ FILE: libsrc/meshing/topology.cpp ================================================ #include #include "meshing.hpp" namespace netgen { using ngcore::ParallelForRange; using ngcore::ParallelFor; using ngcore::TasksPerThread; /* template void QuickSortRec (NgFlatArray 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 void QuickSort (NgFlatArray data) { if (data.Size() > 1) QuickSortRec (data, 0, data.Size()-1); } */ MeshTopology :: MeshTopology (const Mesh & amesh) : mesh(&amesh) { buildedges = static_buildedges; buildfaces = static_buildfaces; buildvertex2element = static_buildvertex2element; timestamp = -1; } MeshTopology :: ~MeshTopology () { ; } bool MeshTopology :: NeedsUpdate() const { return (timestamp <= mesh->GetTimeStamp()); } void MeshTopology :: EnableTable (string name, bool set) { if (name == "edges") SetBuildEdges(set); else if (name == "faces") SetBuildFaces(set); else if (name == "parentedges") SetBuildParentEdges(set); else if (name == "parentfaces") SetBuildParentFaces(set); else throw Exception ("nothing known about table "+name +"\n" "known are 'edges', 'faces', 'parentedges', 'parentfaces'"); } bool MeshTopology :: static_buildedges = true; bool MeshTopology :: static_buildfaces = true; bool MeshTopology :: static_buildvertex2element = true; void MeshTopology :: EnableTableStatic (string name, bool set) { if (name == "edges") static_buildedges = set; else if (name == "faces") static_buildfaces = set; else if (name == "vertex2element") static_buildvertex2element = set; else throw Exception ("nothing known about table "+name +"\n" "known are 'edges', 'faces', 'vertex2element'"); } template void LoopOverEdges (const Mesh & mesh, MeshTopology & top, PointIndex v, FUNC func) { for (ElementIndex elnr : top.GetVertexElements(v)) { const Element & el = mesh[elnr]; auto eledges = MeshTopology::GetEdges (el.GetType()); for (int k = 0; k < eledges.Size(); k++) { PointIndices<2> edge(el[eledges[k][0]], el[eledges[k][1]]); bool edgedir = edge[0] > edge[1]; if (edgedir) swap (edge[0], edge[1]); if (edge[0] != v) continue; func (edge, elnr, k, 3); } } for (SurfaceElementIndex elnr : top.GetVertexSurfaceElements(v)) { const Element2d & el = mesh[elnr]; auto eledges = MeshTopology::GetEdges (el.GetType()); for (int k = 0; k < eledges.Size(); k++) { PointIndices<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() != v) continue; func (edge, elnr, k, 2); } } for (SegmentIndex elnr : top.GetVertexSegments(v)) { const Segment & el = mesh[elnr]; PointIndices<2> edge(el[0], el[1]); int edgedir = (edge.I1() > edge.I2()); if (edgedir) swap (edge.I1(), edge.I2()); edge.Sort(); if (edge.I1() != v) continue; func (edge, elnr, 0, 1); } } template void LoopOverFaces (const Mesh & mesh, MeshTopology & top, PointIndex v, FUNC func) { for (ElementIndex elnr : top.GetVertexElements(v)) { const Element & el = mesh[elnr]; int nelfaces = MeshTopology::GetNFaces (el.GetType()); const ELEMENT_FACE * elfaces = MeshTopology::GetFaces0 (el.GetType()); for (int j = 0; j < nelfaces; j++) if (elfaces[j][3] < 0) { // triangle PointIndices<4> face(el[elfaces[j][0]], el[elfaces[j][1]], el[elfaces[j][2]], PointIndex(PointIndex::INVALID)); [[maybe_unused]] int 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; func (face, elnr, j, true); } /* if (pass == 1) { if (!vert2face.Used (face)) { nfa++; vert2face.Set (face, nfa); INDEX_4 hface(face.I1(),face.I2(),face.I3(),0); face2vert.Append (hface); } } else { int facenum = vert2face.Get(face); faces[elnr][j].fnr = facenum-1; faces[elnr][j].forient = facedir; } */ else { // quad // int facenum; PointIndices<4> face4(el[elfaces[j][0]], el[elfaces[j][1]], el[elfaces[j][2]], el[elfaces[j][3]]); // int 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()); } if (face4.I1() != v) continue; func(face4, elnr, j, true); /* INDEX_3 face(face4.I1(), face4.I2(), face4.I3()); if (vert2face.Used (face)) { facenum = vert2face.Get(face); } else { if (pass == 2) cout << "hier in pass 2" << endl; nfa++; vert2face.Set (face, nfa); facenum = nfa; INDEX_4 hface(face4.I1(),face4.I2(),face4.I3(),face4.I4()); face2vert.Append (hface); } faces[elnr][j].fnr = facenum-1; faces[elnr][j].forient = facedir; } */ } } for (SurfaceElementIndex elnr : top.GetVertexSurfaceElements(v)) { const Element2d & el = mesh[elnr]; const ELEMENT_FACE * elfaces = MeshTopology::GetFaces1 (el.GetType()); if (elfaces[0][3] == 0) { // triangle // int facenum; // int facedir; PointIndices<4> face(el.PNum(elfaces[0][0]), el.PNum(elfaces[0][1]), el.PNum(elfaces[0][2]), PointIndex(PointIndex::INVALID)); // facedir = 0; if (face[0] > face[1]) { swap (face[0], face[1]); // facedir += 1; } if (face[1] > face[2]) { swap (face[1], face[2]); // facedir += 2; } if (face.I1() > face[1]) { swap (face.I1(), face[1]); // facedir += 4; } if (face.I1() != v) continue; func(face, elnr, 0, false); /* 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[elnr].fnr = facenum-1; surffaces[elnr].forient = facedir; */ } else { // quad // int facenum; // int facedir; PointIndices<4> 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()); } if (face4.I1() != v) continue; func(face4, elnr, 0, false); /* INDEX_3 face(face4.I1(), face4.I2(), face4.I3()); if (vert2face.Used (face)) facenum = vert2face.Get(face); else { nfa++; vert2face.Set (face, nfa); facenum = nfa; INDEX_4 hface(face4.I1(),face4.I2(),face4.I3(),face4.I4()); face2vert.Append (hface); } surffaces[elnr].fnr = facenum-1; surffaces[elnr].forient = facedir; } */ } } } void MeshTopology :: Update (NgTaskManager tm_unused, NgTracer tracer) { static Timer timer("Topology::Update"); static Timer timer_tables("Build vertex to element table"); RegionTimer reg (timer); #ifdef PARALLEL // ParallelMeshTopology & paralleltop = mesh.GetParallelTopology(); #endif auto id = this->mesh->GetCommunicator().Rank(); auto ntasks = this->mesh->GetCommunicator().Size(); 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(); 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; (*tracer) ("Topology::Update setup tables", false); NgArray cnt(nv); /* generate: vertex to element vertex to surface element vertex to segment */ if (buildvertex2element) { timer_tables.Start(); vert2element = mesh->CreatePoint2ElementTable(); vert2surfelement = mesh->CreatePoint2SurfaceElementTable(0); vert2segment = ngcore::CreateSortedTable( mesh->LineSegments().Range(), [&](auto & table, SegmentIndex segi) { const Segment & seg = (*mesh)[segi]; table.Add (seg[0], segi); table.Add (seg[1], segi); }, np); vert2pointelement = ngcore::CreateSortedTable( mesh->pointelements.Range(), [&](auto & table, int pei) { const Element0d & pointel = mesh->pointelements[pei]; table.Add(pointel.pnum, pei); }, np); timer_tables.Stop(); } (*tracer) ("Topology::Update setup tables", true); if (buildedges) { static Timer timer1("topology::buildedges"); 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].nr = -1; for (int i = 0; i < nse; i++) for (int j = 0; j < 4; j++) surfedges[i][j].nr = -1; */ ParallelFor (ne, [this](auto i) { for (auto & e : edges[i]) e = -1; }); ParallelFor (nse, [this](auto i) { for (auto & e : surfedges[i]) e = -1; }); // keep existing edges cnt = 0; for (int i = 0; i < edge2vert.Size(); i++) cnt[edge2vert[i][0]]++; TABLE vert2edge (cnt); for (int i = 0; i < edge2vert.Size(); i++) vert2edge.AddSave (edge2vert[i][0], i); // ensure all coarse grid and intermediate level edges cnt = 0; // for (int i = mesh->mlbetweennodes.Begin(); i < mesh->mlbetweennodes.End(); i++) for (int i : mesh->mlbetweennodes.Range()) { PointIndices<2> parents = Sort (mesh->mlbetweennodes[i]); if (parents[0].IsValid()) cnt[parents[0]]++; } TABLE vert2vertcoarse (cnt); // for (int i = mesh->mlbetweennodes.Begin(); i < mesh->mlbetweennodes.End(); i++) for (int i : mesh->mlbetweennodes.Range()) { PointIndices<2> parents = Sort (mesh->mlbetweennodes[i]); if (parents[0].IsValid()) vert2vertcoarse.AddSave (parents[0], parents[1]); } int max_edge_on_vertex = 0; for (int i = PointIndex::BASE; i < nv+PointIndex::BASE; i++) { int onv = vert2edge[i].Size() + vert2vertcoarse[i].Size() + 4*(vert2element)[i].Size() + 2*(vert2surfelement)[i].Size() + (vert2segment)[i].Size(); max_edge_on_vertex = max (onv, max_edge_on_vertex); } // count edges associated with vertices cnt = 0; ParallelForRange (mesh->GetNV(), // Points().Size(), [&] (IntRange r) { auto begin = r.First(); auto end = r.Next(); // INDEX_CLOSED_HASHTABLE v2eht(2*max_edge_on_vertex+10); ngcore::ClosedHashTable v2eht(2*max_edge_on_vertex+10); for (PointIndex v = begin+IndexBASE(); v < end+IndexBASE(); v++) { v2eht.DeleteData(); for (int ednr : vert2edge[v]) { int v2 = edge2vert[ednr][1]; v2eht.Set (v2, ednr); } size_t usedold = v2eht.UsedElements(); for (int v2 : vert2vertcoarse[v]) v2eht.Set (v2, 33); // some value LoopOverEdges (*mesh, *this, v, [&] (INDEX_2 edge, int elnr, int loc_edge, int element_dim) { v2eht.Set (edge[1], 33); // something }); cnt[v] = v2eht.UsedElements()-usedold; } }, TasksPerThread(4) ); // accumulate number of edges int ned = edge2vert.Size(); for (size_t v : cnt.Range()) { auto hv = cnt[v]; cnt[v] = ned; ned += hv; } edge2vert.SetSize(ned); edge2segment.SetSize(ned); edge2segment = -1; // INDEX_CLOSED_HASHTABLE v2eht(2*max_edge_on_vertex+10); // NgArray vertex2; // for (PointIndex v = IndexBASE(); v < nv+IndexBASE(); v++) ParallelForRange (mesh->GetNV(), // Points().Size(), [&] (IntRange r) { auto begin = r.First(); auto end = r.Next(); // INDEX_CLOSED_HASHTABLE v2eht(2*max_edge_on_vertex+10); ngcore::ClosedHashTable v2eht(2*max_edge_on_vertex+10); Array vertex2; for (PointIndex v = begin+IndexBASE(); v < end+IndexBASE(); v++) { int ned = cnt[v]; v2eht.DeleteData(); vertex2.SetSize0 (); for (int ednr : vert2edge[v]) { int v2 = edge2vert[ednr][1]; v2eht.Set (v2, ednr); } for (int v2 : vert2vertcoarse[v]) if (!v2eht.Used(v2)) { v2eht.Set (v2, 33); // some value vertex2.Append (v2); } LoopOverEdges (*mesh, *this, v, [&](INDEX_2 edge, int elnr, int loc_edge, int element_dim) { size_t pos; if (v2eht.PositionCreate(edge[1], pos)) { vertex2.Append (edge[1]); v2eht.SetData (pos, 33); } /* if (!v2eht.Used(edge.I2())) { vertex2.Append (edge.I2()); v2eht.Set (edge.I2(), 33); } */ }); QuickSort (vertex2); /* for (int j = 0; j < vertex2.Size(); j++) { v2eht.Set (vertex2[j], ned); edge2vert[ned] = { v, vertex2[j] }; ned++; } */ for (auto v2 : vertex2) { v2eht.Set (v2, ned); edge2vert[ned] = { v, v2 }; ned++; } LoopOverEdges (*mesh, *this, v, [&](INDEX_2 edge, int elnr, int loc_edge, int element_dim) { int edgenum = v2eht.Get(edge[1]); switch (element_dim) { case 3: edges[elnr][loc_edge] = edgenum; break; case 2: surfedges[elnr][loc_edge] = edgenum; break; case 1: segedges[elnr] = edgenum; edge2segment[edgenum] = elnr; break; } }); } }, TasksPerThread(4) ); if (build_parent_edges) { static Timer t("build_hierarchy"); RegionTimer reg(t); cnt = 0; for (auto verts : edge2vert) cnt[verts[0]]++; TABLE vert2edge (cnt); for (auto i : edge2vert.Range()) vert2edge.AddSave (edge2vert[i][0], i); // build edge hierarchy: parent_edges.SetSize (ned); parent_edges = { -1, { -1, -1, -1 } }; for (size_t i = 0; i < ned; i++) { auto verts = edge2vert[i]; // 2 vertices of edge if (verts[0] >= mesh->mlbetweennodes.Size()+IndexBASE() || verts[1] >= mesh->mlbetweennodes.Size()+IndexBASE()) continue; auto pa0 = mesh->mlbetweennodes[verts[0]]; // two parent vertices of v0 auto pa1 = mesh->mlbetweennodes[verts[1]]; // two parent vertices of v1 // both vertices are on coarsest mesh if (!pa0[0].IsValid() && !pa1[0].IsValid()) continue; int issplitedge = 0; if (pa0[0] == verts[1] || pa0[1] == verts[1]) issplitedge = 1; if (pa1[0] == verts[0] || pa1[1] == verts[0]) issplitedge = 2; if (issplitedge) { // cout << "split edge " << endl; // edge is obtained by splitting one edge into two parts: auto paedge = issplitedge == 1 ? pa0 : pa1; if (paedge[0] > paedge[1]) Swap (paedge[0], paedge[1]); for (int ednr : vert2edge[paedge[0]]) if (auto cverts = edge2vert[ednr]; cverts[1] == paedge[1]) { int orient = (paedge[0] == verts[0] || paedge[1] == verts[1]) ? 1 : 0; parent_edges[i] = { orient, { ednr, -1, -1 } }; } } else { bool bisect_edge = false; // edge is splitting edge in middle of triangle: for (int j = 1; j <= 2; j++) { IVec<2,PointIndex> paedge1, paedge2, paedge3; int orient_inner = 0; if (j == 1) { paedge1 = IVec<2> (pa0[0], verts[1]); paedge2 = IVec<2> (pa0[1], verts[1]); paedge3 = IVec<2> (pa0[0], pa0[1]); orient_inner = 0; } else { paedge1 = IVec<2> (pa1[0], verts[0]); paedge2 = IVec<2> (pa1[1], verts[0]); paedge3 = IVec<2> (pa1[0], pa1[1]); orient_inner = 1; } if (paedge1[0] > paedge1[1]) Swap (paedge1[0], paedge1[1]); if (paedge2[0] > paedge2[1]) Swap (paedge2[0], paedge2[1]); if (paedge3[0] > paedge3[1]) Swap (paedge3[0], paedge3[1]); // if first vertex number is -1, then don't try to find entry in node2edge hash table if ( !paedge1[0].IsValid() || !paedge2[0].IsValid() ) continue; int paedgenr1=-1, paedgenr2=-1, paedgenr3=-1, orient1 = 0, orient2 = 0; for (int ednr : vert2edge[paedge1[0]]) if (auto cverts = edge2vert[ednr]; cverts[1] == paedge1[1]) { paedgenr1 = ednr; orient1 = (paedge1[0] == verts[0] || paedge1[1] == verts[1]) ? 1 : 0; } for (int ednr : vert2edge[paedge2[0]]) if (auto cverts = edge2vert[ednr]; cverts[1] == paedge2[1]) { paedgenr2 = ednr; orient2 = (paedge2[0] == verts[0] || paedge2[1] == verts[1]) ? 1 : 0; } for (int ednr : vert2edge[paedge3[0]]) if (auto cverts = edge2vert[ednr]; cverts[1] == paedge3[1]) paedgenr3 = ednr; if (paedgenr1 != -1 && paedgenr2 != -1){ bisect_edge = true; parent_edges[i] = { orient1+2*orient2+4*orient_inner, { paedgenr1, paedgenr2, paedgenr3 } }; } } if (!bisect_edge) // not a bisect edge (then a red edge) { IVec<2,PointIndex> paedge1, paedge2, paedge3; int orient1 = 0, orient2 = 0, orient3=0; // int orient_inner = 0; paedge1 = IVec<2,PointIndex> (pa0[0], pa0[1]); paedge2 = IVec<2,PointIndex> (pa1[0], pa1[1]); // find common vertex and the third pa edge if (pa0[0]==pa1[0]){// 00 //orient1 = 0; orient2 = 1; if (pa0[1] (pa0[1], pa1[1]); }else{ //orient3 = 0; paedge3 = IVec<2,PointIndex> (pa1[1], pa0[1]); } } else if (pa0[0]==pa1[1]){//01 //orient1 = 0; //orient2 = 0; if (pa0[1] (pa0[1], pa1[0]); }else{ //orient3 = 0; paedge3 = IVec<2,PointIndex> (pa1[0], pa0[1]); } } else if (pa0[1]==pa1[0]){//10 orient1 = 1; orient2 = 1; if (pa0[0] (pa0[0], pa1[1]); }else{ //orient3 = 0; paedge3 = IVec<2,PointIndex> (pa1[1], pa0[0]); } } else if (pa0[1]==pa1[1]){//11 orient1 = 1; //orient2 = 0; if (pa0[0] (pa0[0], pa1[0]); }else{ //orient3 = 0; paedge3 = IVec<2,PointIndex> (pa1[0], pa0[0]); } } int paedgenr1=-1, paedgenr2=-1, paedgenr3=-1; for (int ednr : vert2edge[paedge1[0]]) if (auto cverts = edge2vert[ednr]; cverts[1] == paedge1[1]) paedgenr1 = ednr; for (int ednr : vert2edge[paedge2[0]]) if (auto cverts = edge2vert[ednr]; cverts[1] == paedge2[1]) paedgenr2 = ednr; for (int ednr : vert2edge[paedge3[0]]) if (auto cverts = edge2vert[ednr]; cverts[1] == paedge3[1]) paedgenr3 = ednr; parent_edges[i] = { 8+orient1+2*orient2+4*orient3, { paedgenr1, paedgenr2, paedgenr3 } }; //cout <<8+orient1+2*orient2+4*orient3 <<":"< paedge1, paedge2; if (j == 1) { paedge1 = IVec<2> (pa1[0], pa2[0]); paedge2 = IVec<2> (pa1[1], pa2[1]); } else { paedge1 = IVec<2> (pa1[0], pa2[1]); paedge2 = IVec<2> (pa1[1], pa2[0]); } int paedgenr1 = 0, paedgenr2 = 0; int orient1 = 1, orient2 = 1; if (paedge1[0] > paedge1[1]) { Swap (paedge1[0], paedge1[1]); orient1 = 0; } if (paedge2[0] > paedge2[1]) { Swap (paedge2[0], paedge2[1]); orient2 = 0; } if ( paedge1[0] == -1 || paedge2[0] == -1 ) continue; if (node2edge.Used (paedge1) && node2edge.Used (paedge2)) { paedgenr1 = node2edge.Get (paedge1); paedgenr2 = node2edge.Get (paedge2); parentedges[i][0] = 2 * paedgenr1 + orient1; parentedges[i][1] = 2 * paedgenr2 + orient2; } } } if (parentedges[i][0] == -1) { // triangle split into quad+trig (from anisotropic pyramids) for (int j = 0; j < 2; j++) for (int k = 0; k < 2; k++) { IVec<2> paedge (pa1[1-j], pa2[1-k]); int orientpa = 1; if (paedge[0] > paedge[1]) { Swap (paedge[0], paedge[1]); orientpa = 0; } if (pa1[j] == pa2[k] && node2edge.Used(paedge)) { int paedgenr = node2edge.Get (paedge); parentedges[i][0] = 2 * paedgenr + orientpa; } } } */ } } /* for (int i : Range(parent_edges)) { auto [info, nrs] = parent_edges[i]; cout << "edge " << i << " has " << info << ", nrs = " << nrs[0] << " " << nrs[1] << endl; } */ } } // edge hashtable:: needed for getting parent faces ngcore::ClosedHashTable, int> v2e(nv); if (build_parent_faces) for (auto i : Range(edge2vert)) { auto edge = edge2vert[i]; IVec<2> e2(edge[0], edge[1]); e2.Sort(); v2e[e2] = i; } // generate faces if (buildfaces) { static Timer timer2("topology::buildfaces"); // static int timer2a = NgProfiler::CreateTimer ("topology::buildfacesa"); // static int timer2b = NgProfiler::CreateTimer ("topology::buildfacesb"); // static int timer2b1 = NgProfiler::CreateTimer ("topology::buildfacesb1"); // static int timer2c = NgProfiler::CreateTimer ("topology::buildfacesc"); RegionTimer reg2 (timer2); if (id == 0) PrintMessage (5, "Update faces "); // NgProfiler::StartTimer (timer2a); faces.SetSize(ne); surffaces.SetSize(nse); cnt = 0; for (int i = 0; i < face2vert.Size(); i++) cnt[face2vert[i][0]]++; TABLE vert2oldface(cnt); for (int i = 0; i < face2vert.Size(); i++) vert2oldface.AddSave (face2vert[i][0], i); // find all potential intermediate faces Array> intermediate_faces; if (build_parent_faces) { for (ElementIndex ei = 0; ei < ne; ei++) for (int i = 0; i < 4; i++) { Element2d face; // cout << "element: " << (*mesh)[ei].PNums() << endl; (*mesh)[ei].GetFace(i+1, face); // cout << "face " << face.PNums() << endl; IVec<3,PointIndex> f3 = { face[0], face[1], face[2] }; for (int j = 0; j < 3; j++) { PointIndex v = f3[j]; if (v >= mesh->mlbetweennodes.Size()+IndexBASE()) continue; auto pa = mesh->mlbetweennodes[v]; for (int k = 0; k < 2; k++) if (f3.Contains(pa[k])) { PointIndex v0 = pa[k]; // also in face PointIndex v1 = pa[1-k]; PointIndex v2 = f3[0]-v+f3[1]-v0+f3[2]; // if there is an edge connecting v1 and v2, accept // the new face IVec<2> parentedge(v1, v2); parentedge.Sort(); if (v2e.Used(parentedge)){ IVec<3> cf3 = { v0, v1, v2 }; cf3.Sort(); // cout << "intermediate: " << cf3 << " of " << f3 << endl; intermediate_faces.Append (cf3); } } } } for (SurfaceElementIndex sei = 0; sei < nse; sei++) { const Element2d & sel = (*mesh)[sei]; IVec<3,PointIndex> f3 = { sel[0], sel[1], sel[2] }; for (int j = 0; j < 3; j++) { PointIndex v = f3[j]; if (v >= mesh->mlbetweennodes.Size()+IndexBASE()) continue; auto pa = mesh->mlbetweennodes[v]; for (int k = 0; k < 2; k++) if (f3.Contains(pa[k])) { PointIndex v0 = pa[k]; // also in face PointIndex v1 = pa[1-k]; PointIndex v2 = f3[0]-v+f3[1]-v0+f3[2]; // if there is an edge connecting v1 and v2, accept // the new face IVec<2> parentedge(v1, v2); parentedge.Sort(); if (v2e.Used(parentedge)){ IVec<3> cf3 = { v0, v1, v2 }; cf3.Sort(); // cout << "intermediate: " << cf3 << " of " << f3 << endl; intermediate_faces.Append (cf3); } } } } } cnt = 0; for (int i = 0; i < intermediate_faces.Size(); i++) cnt[intermediate_faces[i][0]]++; TABLE vert2intermediate(cnt); for (int i = 0; i < intermediate_faces.Size(); i++) vert2intermediate.AddSave (intermediate_faces[i][0], i); // cout << "vert2intermediate = " << endl << vert2intermediate << endl; for (int elnr = 0; elnr < ne; elnr++) for (int j = 0; j < 6; j++) faces[elnr][j] = -1; int max_face_on_vertex = 0; for (PointIndex i = IndexBASE(); i < nv+IndexBASE(); i++) { int onv = vert2oldface[i].Size() + vert2element[i].Size() + vert2surfelement[i].Size(); max_face_on_vertex = max (onv, max_face_on_vertex); } // NgProfiler::StopTimer (timer2a); // NgProfiler::StartTimer (timer2b); // INDEX_3_CLOSED_HASHTABLE vert2face(2*max_face_on_vertex+10); int oldnfa = face2vert.Size(); // count faces associated with vertices cnt = 0; // for (auto v : mesh.Points().Range()) // NgProfiler::StartTimer (timer2b1); ParallelForRange (mesh->GetNV(), // Points().Size(), [&] (IntRange r) { // auto begin = r.First(); // auto end = r.Next(); // INDEX_3_CLOSED_HASHTABLE vert2face(2*max_face_on_vertex+10); NgClosedHashTable vert2face(2*max_face_on_vertex+10); // for (PointIndex v = begin+PointIndex::BASE; // v < end+PointIndex::BASE; v++) for (PointIndex v : r+PointIndex::BASE) { vert2face.DeleteData(); for (int j = 0; j < vert2oldface[v].Size(); j++) { int fnr = vert2oldface[v][j]; INDEX_3 face (face2vert[fnr][0], face2vert[fnr][1], face2vert[fnr][2]); vert2face.Set (face, 33); // something } int cnti = 0; for (int j = 0; j < vert2intermediate[v].Size(); j++) { int fnr = vert2intermediate[v][j]; INDEX_3 face (intermediate_faces[fnr][0], intermediate_faces[fnr][1], intermediate_faces[fnr][2]); face.Sort(); if (!vert2face.Used(face)) { cnti++; vert2face.Set (face, 33); // something } } LoopOverFaces (*mesh, *this, v, [&] (INDEX_4 i4, int elnr, int j, bool volume) { INDEX_3 face(i4[0], i4[1], i4[2]); if (!vert2face.Used (face)) { cnti++; vert2face.Set (face, 33); // something } }); cnt[v] = cnti; } }, TasksPerThread(4) ); // NgProfiler::StopTimer (timer2b1); // accumulate number of faces int nfa = oldnfa; // for (auto v : Range(mesh->GetNV())) // Points().Range()) // for (size_t v = 0; v < mesh->GetNV(); v++) for (auto v : cnt.Range()) { auto hv = cnt[v]; cnt[v] = nfa; nfa += hv; } face2vert.SetSize(nfa); ParallelForRange (mesh->GetNV(), [&] (IntRange r) { // auto begin = r.First(); // auto end = r.Next(); // INDEX_3_CLOSED_HASHTABLE vert2face(2*max_face_on_vertex+10); NgClosedHashTable vert2face(2*max_face_on_vertex+10); /* for (PointIndex v = begin+PointIndex::BASE; v < end+PointIndex::BASE; v++) */ for (PointIndex v : r+PointIndex::BASE) { int first_fa = cnt[v]; int nfa = first_fa; vert2face.DeleteData(); for (int j = 0; j < vert2oldface[v].Size(); j++) { int fnr = vert2oldface[v][j]; INDEX_3 face (face2vert[fnr][0], face2vert[fnr][1], face2vert[fnr][2]); vert2face.Set (face, fnr); } for (int j = 0; j < vert2intermediate[v].Size(); j++) { int fnr = vert2intermediate[v][j]; INDEX_3 face (intermediate_faces[fnr][0], intermediate_faces[fnr][1], intermediate_faces[fnr][2]); face.Sort(); /* if (!vert2face.Used(face)) { face2vert[nfa] = { face[0], face[1], face[2], 0 }; // i4; vert2face.Set (face, nfa); nfa++; } */ size_t pos; if (vert2face.PositionCreate(face, pos)) { face2vert[nfa] = { face[0], face[1], face[2], PointIndex::BASE-1 }; // i4; vert2face.SetData (pos, face, nfa); nfa++; } } LoopOverFaces (*mesh, *this, v, [&] (INDEX_4 i4, int elnr, int j, bool volume) { INDEX_3 face(i4.I1(), i4.I2(), i4.I3()); /* if (!vert2face.Used (face)) { face2vert[nfa] = { i4[0], i4[1], i4[2], i4[3] }; // i4; vert2face.Set (face, nfa); nfa++; } */ size_t pos; if (vert2face.PositionCreate(face, pos)) { face2vert[nfa] = { i4[0], i4[1], i4[2], i4[3] }; // i4; vert2face.SetData (pos, face, nfa); nfa++; } }); QuickSort (face2vert.Range(first_fa, nfa)); for (int j = first_fa; j < nfa; j++) { if (face2vert[j][0] == v) { INDEX_3 face (face2vert[j][0], face2vert[j][1], face2vert[j][2]); vert2face.Set (face, j); } else break; } LoopOverFaces (*mesh, *this, v, [&] (INDEX_4 i4, int elnr, int j, bool volume) { INDEX_3 face(i4.I1(), i4.I2(), i4.I3()); int facenum = vert2face.Get(face); if (volume) faces[elnr][j] = facenum; else surffaces[elnr] = facenum; }); } }, TasksPerThread(4) ); // *testout << "face2vert = " << endl << face2vert << endl; // NgProfiler::StopTimer (timer2b); // NgProfiler::StartTimer (timer2c); face2surfel.SetSize (nfa); face2surfel = SurfaceElementIndex::INVALID; for (SurfaceElementIndex sei = 0; sei < nse; sei++) face2surfel[GetFace(sei)] = sei; /* 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); // surf2volelement = INDEX_2(0,0); surf2volelement = { ElementIndex::INVALID, ElementIndex::INVALID }; (*tracer) ("Topology::Update build surf2vol", false); // for (int i = 0; i < ne; i++) ParallelFor (ne, [this](auto i) { for (int j = 0; j < 6; j++) { // int fnum = (faces.Get(i)[j]+7) / 8; int fnum = faces[i][j]; if (fnum >= 0 && face2surfel[fnum].IsValid()) { SurfaceElementIndex sel = face2surfel[fnum]; surf2volelement[sel][1] = surf2volelement[sel][0]; surf2volelement[sel][0] = i; // +1; } }}); (*tracer) ("Topology::Update build surf2vol", true); face2vert.SetAllocSize (face2vert.Size()); // face table complete #ifdef PARALLEL // (*testout) << " RESET Paralleltop" << endl; // paralleltop.Reset (); #endif (*tracer) ("Topology::Update count face_els", false); NgArray face_els(nfa), face_surfels(nfa); face_els = 0; face_surfels = 0; ParallelForRange (ne, [&] (IntRange r) { /* NgArray hfaces; for (ElementIndex ei : r) { GetElementFaces (ei+1, hfaces); for (auto f : hfaces) AsAtomic(face_els[f-1])++; } */ for (ElementIndex ei : r) for (auto f : GetFaces(ei)) AsAtomic(face_els[f])++; }, TasksPerThread(4)); /* for (int i = 1; i <= nse; i++) face_surfels[GetSurfaceElementFace1 (i)-1]++; */ for (auto sei : Range(mesh->SurfaceElements())) face_surfels[GetFace(sei)]++; (*tracer) ("Topology::Update count face_els", true); 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 ) { continue; // if ( !paralleltop.DoCoarseUpdate() ) continue; } else #endif { (*testout) << "illegal face : " << i << ", cnt = " << face_els[i]+face_surfels[i] << endl; (*testout) << "points = " << face2vert[i][0] << "," << face2vert[i][1] << "," << face2vert[i][2] << "," << face2vert[i][3] << endl; (*testout) << "pos = "; for (int j = 0; j < 4; j++) if (face2vert[i][j].IsValid()) (*testout) << (*mesh)[(PointIndex)face2vert[i][j]] << " "; (*testout) << endl; FlatArray vertels = GetVertexElements (face2vert[i][0]); for (int k = 0; k < vertels.Size(); k++) { int elfaces[10], orient[10]; int nf = GetElementFaces (vertels[k]+1, 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)[vertels[k]].GetHpElnr()]; (*testout) << "coarse eleme = " << hpref_el.coarse_elnr << endl; } } } } } } if (cnt_err && ntasks == 1) cout << IM(5) << cnt_err << " elements are not matching !!!" << endl; } // NgProfiler::StopTimer (timer2c); if (build_parent_faces) { // tets only if (id == 0) PrintMessage (5, "build face hierarchy"); // cout << "f2v = " << face2vert << endl; ngcore::ClosedHashTable, int> v2f(nv); for (auto i : Range(face2vert)) { auto face = face2vert[i]; IVec<3> f3(face[0], face[1], face[2]); f3.Sort(); v2f[f3] = i; } // cout << "v2f:" << endl << v2f << endl; parent_faces.SetSize (nfa); parent_faces = { -1, { -1, -1, -1, -1 } }; for (auto i : Range(nfa)) { IVec<3,PointIndex> f3(face2vert[i][0], face2vert[i][1], face2vert[i][2]); // face on coarses level ? bool all_vert_coarse = true; for (int k = 0; k < 3; k++) { PointIndex vb = f3[k]; if (vb >= mesh->mlbetweennodes.Size()+IndexBASE()) continue; auto parents = mesh->mlbetweennodes[vb]; if (parents[0] >= IndexBASE()) all_vert_coarse = false; } if (all_vert_coarse) continue; // find a vertex, such that one of its parent is a trig vertex bool issplit = false; for (int k = 0; k < 3; k++) { PointIndex vb = f3[k]; // assume vb as the new bisect vert if (vb >= mesh->mlbetweennodes.Size()+IndexBASE()) continue; auto parents = mesh->mlbetweennodes[vb]; // is face part of one parent face (boundary-face) ? for (int j = 0; j < 2; j++) { if (f3.Contains(parents[j])) { PointIndex v0 = parents[j]; PointIndex v1 = parents[1-j]; // the third one, on the tip PointIndex v2 = f3[0]-v0+f3[1]-vb+f3[2]; // if there is an edge connecting v1 and v2, accept // the new face IVec<2> parentedge(v1, v2); parentedge.Sort(); if (v2e.Used(parentedge)){ IVec<3> parentverts(v0, v1, v2); parentverts.Sort(); int classnr = 0; if (v2 > vb) { Swap (v2, vb); classnr += 1; } if (v0 > v1) { Swap (v0, v1); classnr += 2; } if (v1 > v2) { Swap (v1, v2); classnr += 4; } if (v0 > v1) { Swap (v0, v1); classnr += 8; } if (v2f.Used(parentverts)) { int pafacenr = v2f[parentverts]; // cout << "parent-face = " << pafacenr << endl; parent_faces[i] = { classnr, { pafacenr, -1, -1, -1 } }; } else { cout << "missing parent face: " << parentverts << endl; } issplit=true; break; } } } } /* // is face a new face (bisect-face) ? if (!issplit) for (int k = 0; k < 3; k++) { PointIndex vb = f3[k]; // assume vb as the new bisect vert if (vb >= mesh->mlbetweennodes.Size()+PointIndex::BASE) continue; auto parents = mesh->mlbetweennodes[vb]; PointIndex v0 = parents[0]; PointIndex v1 = parents[1]; PointIndex v2 = f3[(k+1)%3]; PointIndex v3 = f3[(k+2)%3]; IVec<3> parentedge1(v0, v2); parentedge1.Sort(); IVec<3> parentedge2(v0, v3); parentedge2.Sort(); IVec<3> parentedge3(v1, v2); parentedge3.Sort(); IVec<3> parentedge4(v1, v3); parentedge4.Sort(); // if edges [v0,v2], [v0, v3], [v1,v2], [v1,v3] exists // then vb is the bisecting edge if (v2e.Used(parentedge1) && v2e.Used(parentedge2) && v2e.Used(parentedge3) && v2e.Used(parentedge4) ){ int classnr; if (k==2){// vb is the largest vert: 6 cases // by default v0 < v1, v2 < v3 if (v1 < v2) classnr = 0; else if (v1 < v3 && v0 < v2) classnr = 1; else if (v0 < v2) classnr = 2; else if (v1 < v3) classnr = 3; else if (v0 < v3) classnr = 4; else classnr = 5; }else if (k==1){// vb is the second largest vert: 3 cases // by default v0 < v1, v3 < v2 if (v1 < v3) classnr = 6; else if (v0 < v3) classnr = 7; else classnr = 8; }else {// vb is the third largest vert: 1 case // by default v0 < v1 < vb < v2 < v3 classnr=9; } IVec<3> parentverts1(v0, v2, v3); parentverts1.Sort(); IVec<3> parentverts2(v1, v2, v3); parentverts2.Sort(); IVec<3> parentverts3(v0, v1, v2); parentverts3.Sort(); IVec<3> parentverts4(v0, v1, v3); parentverts4.Sort(); int pafacenr1=-1, pafacenr2=-1, pafacenr3=-1, pafacenr4=-1; if (v2f.Used(parentverts1)) { pafacenr1 = v2f[parentverts1]; // cout << "parent-face1 = " << pafacenr1<< endl ; } if (v2f.Used(parentverts2)) { pafacenr2 = v2f[parentverts2]; // cout << "parent-face2 = " << pafacenr2<< endl ; } if (v2f.Used(parentverts3)) { pafacenr3 = v2f[parentverts3]; // cout << "parent-face3 = " << pafacenr3<< endl ; } if (v2f.Used(parentverts4)) { pafacenr4 = v2f[parentverts4]; // cout << "parent-face4 = " << pafacenr4<< endl ; } if (k == 0 || k == 2) parent_faces[i] = { classnr, { pafacenr2, pafacenr1, pafacenr4, pafacenr3} }; else parent_faces[i] = { classnr, { pafacenr2, pafacenr1, pafacenr3, pafacenr4} }; break; } } */ // is face a new face (bisect-face) ? if (!issplit) for (int k = 0; k < 3; k++) { PointIndex vb = f3[k]; // assume vb as the new bisect vert if (vb >= mesh->mlbetweennodes.Size()+IndexBASE()) continue; auto parents = mesh->mlbetweennodes[vb]; PointIndex v0 = parents[0]; PointIndex v1 = parents[1]; PointIndex v2 = f3[(k+1)%3]; PointIndex v3 = f3[(k+2)%3]; IVec<2> parentedge1(v0, v2); parentedge1.Sort(); IVec<2> parentedge2(v0, v3); parentedge2.Sort(); IVec<2> parentedge3(v1, v2); parentedge3.Sort(); IVec<2> parentedge4(v1, v3); parentedge4.Sort(); // if edges [v0,v2], [v0, v3], [v1,v2], [v1,v3] exists // then vb is the bisecting edge if (v2e.Used(parentedge1) && v2e.Used(parentedge2) && v2e.Used(parentedge3) && v2e.Used(parentedge4)) { int verts[5] = { v0, v1, v2, v3, vb }; /* cout << "verts5: "; for (int j = 0; j < 5; j++) cout << verts[j] << " "; */ // classify permutation of verts int classnr = 0; for (int j = 0; j < 4; j++) { int maxk = 0; for (int k = 0; k < 5-j; k++) if (verts[k] > verts[maxk]) maxk = k; // compress for (int k = maxk; k < 4-j; k++) verts[k] = verts[k+1]; classnr = maxk + (5-j) * classnr; } // cout << "classnr = " << classnr << endl; IVec<3> parentverts1(v1, v2, v3); parentverts1.Sort(); IVec<3> parentverts2(v0, v2, v3); parentverts2.Sort(); IVec<3> parentverts3(v0, v1, v3); parentverts3.Sort(); IVec<3> parentverts4(v0, v1, v2); parentverts4.Sort(); if (!v2f.Used(parentverts1) || !v2f.Used(parentverts2) || !v2f.Used(parentverts3) || !v2f.Used(parentverts4)) { cout << "all edges are used, but not faces ????" << endl; continue; } int pafacenr1 = v2f[parentverts1]; int pafacenr2 = v2f[parentverts2]; int pafacenr3 = v2f[parentverts3]; int pafacenr4 = v2f[parentverts4]; parent_faces[i] = { classnr, { pafacenr1, pafacenr2, pafacenr3, pafacenr4} }; break; } } auto [info, nrs] = parent_faces[i]; if (nrs[0] == -1){ // hacking for tet red refinements PointIndex v0 = f3[0]; auto pa0 = mesh->mlbetweennodes[v0]; auto pa1 = mesh->mlbetweennodes[f3[1]]; auto pa2 = mesh->mlbetweennodes[f3[2]]; // v0 is a coarse vertex ==> f3 is a boundary face if (v0==pa1[0] || v0==pa1[1]){ if (pa1[0]==v0){// type 0: bottom left corner IVec<3> parentverts(v0, pa1[1], pa2[1]); int pafacenr = v2f[parentverts]; parent_faces[i] = { 16, { pafacenr, -1, -1, -1} }; //cout << "f "< parentverts(pa1[0], v0, pa2[1]); int pafacenr = v2f[parentverts]; parent_faces[i] = { 17, { pafacenr, -1, -1, -1} }; //cout << "f "< parentverts(pa1[0], pa2[0], v0); int pafacenr = v2f[parentverts]; parent_faces[i] = { 18, { pafacenr, -1, -1, -1} }; //cout << "f "< parentverts(pa0[0], pa0[1], pa1[1]); int pafacenr = v2f[parentverts]; parent_faces[i] = { 19, { pafacenr, -1, -1, -1} }; //cout << "f "< & eledges) const { int ned = GetNEdges (mesh->VolumeElement(elnr).GetType()); ElementIndex ei = IndexBASE() +(elnr-1); eledges.SetSize (ned); for (int i = 0; i < ned; i++) // eledges[i] = edges.Get(elnr)[i]+1; eledges[i] = edges[ei][i]+1; } void MeshTopology :: GetElementFaces (int elnr, NgArray & elfaces) const { int nfa = GetNFaces (mesh->VolumeElement(elnr).GetType()); ElementIndex ei = IndexBASE() +(elnr-1); elfaces.SetSize (nfa); for (auto i : Range(nfa)) // elfaces[i] = faces.Get(elnr)[i]+1; elfaces[i] = faces[ei][i]+1; } void MeshTopology :: GetElementFaces (int elnr, NgArray & elfaces, bool withorientation) const { ElementIndex ei = IndexBASE() +(elnr-1); int nfa = GetNFaces (mesh->VolumeElement(ei).GetType()); elfaces.SetSize (nfa); for (auto i : Range(nfa)) // elfaces[i] = faces.Get(elnr)[i]+1; elfaces[i] = faces[ei][i]+1; if(withorientation) { for(auto & face : elfaces) { auto v = face2vert[face-1]; if(v[3].IsValid()) cerr << "GetElementFaces with orientation currently not supported for quads" << endl; int classnr = 0; if (v[0] > v[1]) { classnr++; } if (v[1] > v[2]) { classnr++; } if (v[2] > v[0]) { classnr++; } if(classnr==1) face = -face; } } } void MeshTopology :: GetElementEdgeOrientations (int elnr, NgArray & eorient) const { ElementIndex ei = IndexBASE() +(elnr-1); int ned = GetNEdges (mesh->VolumeElement(ei).GetType()); eorient.SetSize (ned); for (int i = 1; i <= ned; i++) // eorient.Elem(i) = (edges.Get(elnr)[i-1] > 0) ? 1 : -1; // eorient.Elem(i) = (edges.Get(elnr)[i-1].orient) ? -1 : 1; eorient.Elem(i) = GetElementEdgeOrientation (elnr, i-1) ? -1 : 1; } void MeshTopology :: GetElementFaceOrientations (int elnr, NgArray & forient) const { ElementIndex ei = IndexBASE() +(elnr-1); int nfa = GetNFaces (mesh->VolumeElement(ei).GetType()); forient.SetSize (nfa); for (int i = 1; i <= nfa; i++) // forient.Elem(i) = faces.Get(elnr)[i-1].forient; // forient.Elem(i) = (faces.Get(elnr)[i-1]-1) % 8; forient.Elem(i) = GetElementFaceOrientation(elnr, i-1); } int MeshTopology :: GetElementEdges (int elnr, int * eledges, int * orient) const { // int ned = GetNEdges (mesh.VolumeElement(elnr).GetType()); ElementIndex ei = IndexBASE() +(elnr-1); 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; */ // if (edges.Get(elnr)[i] == -1) return i; // eledges[i] = edges[ei].Get(elnr)[i]+1; if (edges[ei][i] == -1) return i; eledges[i] = edges[ei][i]+1; // orient[i] = edges.Get(elnr)[i].orient ? -1 : 1; orient[i] = GetElementEdgeOrientation(elnr, i) ? -1 : 1; } } else { for (int i = 0; i < 12; i++) { // if (!edges.Get(elnr)[i]) return i; // eledges[i] = abs (edges.Get(elnr)[i]); // if (edges.Get(elnr)[i] == -1) return i; //eledges[i] = edges.Get(elnr)[i]+1; if (edges[ei][i] == -1) return i; eledges[i] = edges[ei][i]+1; } } 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 { ElementIndex ei = IndexBASE() +(elnr-1); // 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; */ // if (faces.Get(elnr)[i] == -1) return i; // elfaces[i] = faces.Get(elnr)[i]+1; if (faces[ei][i] == -1) return i; elfaces[i] = faces[ei][i]+1; // orient[i] = faces.Get(elnr)[i].forient; orient[i] = GetElementFaceOrientation (elnr, i); } } else { for (int i = 0; i < 6; i++) { // if (!faces.Get(elnr)[i]) return i; // elfaces[i] = (faces.Get(elnr)[i]-1) / 8 + 1; // if (faces.Get(elnr)[i] == -1) return i; // elfaces[i] = faces.Get(elnr)[i]+1; if (faces[ei][i] == -1) return i; elfaces[i] = faces[ei][i]+1; } } return 6; } void MeshTopology :: GetSurfaceElementEdges (int elnr, NgArray & eledges) const { int ned = GetNEdges (mesh->SurfaceElement(elnr).GetType()); SurfaceElementIndex sei = IndexBASE() +(elnr-1); eledges.SetSize (ned); for (int i = 0; i < ned; i++) // eledges[i] = surfedges.Get(elnr)[i]+1; eledges[i] = surfedges[sei][i]+1; } void MeshTopology :: GetEdges (SurfaceElementIndex elnr, NgArray & eledges) const { int ned = GetNEdges ( (*mesh)[elnr].GetType()); eledges.SetSize (ned); for (int i = 0; i < ned; i++) eledges[i] = surfedges[elnr][i]; } /* FlatArray MeshTopology :: GetEdges (SurfaceElementIndex elnr) const { return FlatArray(GetNEdges ( (*mesh)[elnr].GetType()), &surfedges[elnr][0]); } FlatArray MeshTopology :: GetEdges (ElementIndex elnr) const { return FlatArray(GetNEdges ( (*mesh)[elnr].GetType()), &edges[elnr][0]); } FlatArray MeshTopology :: GetFaces (ElementIndex elnr) const { return FlatArray(GetNFaces ( (*mesh)[elnr].GetType()), &faces[elnr][0]); } */ /* int MeshTopology :: GetSurfaceElementFace (int elnr) const { return surffaces[elnr-1]+1; } int MeshTopology :: GetFace (SurfaceElementIndex elnr) const { return surffaces[elnr].fnr; } */ void MeshTopology :: GetSurfaceElementEdgeOrientations (int elnr, NgArray & eorient) const { int ned = GetNEdges (mesh->SurfaceElement(elnr).GetType()); eorient.SetSize (ned); for (int i = 0; i < ned; i++) // eorient[i] = (surfedges.Get(elnr)[i] > 0) ? 1 : -1; // eorient[i] = (surfedges.Get(elnr)[i].orient) ? -1 : 1; eorient[i] = GetSurfaceElementEdgeOrientation(elnr, i) ? -1 : 1; } int MeshTopology :: GetSurfaceElementFaceOrientation (int elnr) const { // return (surffaces.Get(elnr)-1) % 8; // return surffaces.Get(elnr).forient; return GetSurfaceElementFaceOrientation2(elnr); } int MeshTopology :: GetSurfaceElementEdges (int elnr, int * eledges, int * orient) const { SurfaceElementIndex sei = IndexBASE() +(elnr-1); 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; */ // if (surfedges.Get(elnr)[i] == -1) return i; // eledges[i] = surfedges.Get(elnr)[i]+1; if (surfedges[sei][i] == -1) return i; eledges[i] = surfedges[sei][i]+1; // orient[i] = (surfedges.Get(elnr)[i].orient) ? -1 : 1; // orient[i] = GetSurfaceElementEdgeOrientation(elnr, i) ? -1 : 1; orient[i] = 1; } } else { for (i = 0; i < 4; i++) { /* if (!surfedges.Get(elnr)[i]) return i; eledges[i] = abs (surfedges.Get(elnr)[i]); */ // if (surfedges.Get(elnr)[i] == -1) return i; // eledges[i] = surfedges.Get(elnr)[i]+1; if (surfedges[sei][i] == -1) return i; eledges[i] = surfedges[sei][i]+1; } } return 4; } else { /* eledges[0] = abs (segedges.Get(elnr)); if (orient) orient[0] = segedges.Get(elnr) > 0 ? 1 : -1; */ eledges[0] = segedges[elnr-1]+1; if (orient) // orient[0] = segedges.Get(elnr).orient ? -1 : 1; // orient[0] = GetSegmentEdgeOrientation(elnr) ? -1 : 1; orient[0] = 1; } return 1; } int MeshTopology :: GetElementEdgeOrientation (int elnr, int locedgenr) const { ElementIndex ei = IndexBASE() +(elnr-1); const Element & el = mesh->VolumeElement (ei); const ELEMENT_EDGE * eledges = MeshTopology::GetEdges0 (el.GetType()); int k = locedgenr; INDEX_2 edge(el[eledges[k][0]], el[eledges[k][1]]); int edgedir = (edge.I1() > edge.I2()); return edgedir; } int MeshTopology :: GetElementFaceOrientation (int elnr, int locfacenr) const { ElementIndex ei = IndexBASE() +(elnr-1); const Element & el = mesh->VolumeElement (ei); const ELEMENT_FACE * elfaces = MeshTopology::GetFaces0 (el.GetType()); int j = locfacenr; if (elfaces[j][3] < 0) { // triangle INDEX_4 face(el[elfaces[j][0]], el[elfaces[j][1]], el[elfaces[j][2]], PointIndex::BASE-1 ); int 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; } return facedir; } else { // quad // int facenum; INDEX_4 face4(el[elfaces[j][0]], el[elfaces[j][1]], el[elfaces[j][2]], el[elfaces[j][3]]); int 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()); } return facedir; } } int MeshTopology :: GetSurfaceElementEdgeOrientation (int elnr, int locedgenr) const { const Element2d & el = mesh->SurfaceElement (elnr); const ELEMENT_EDGE * eledges = MeshTopology::GetEdges0 (el.GetType()); int k = locedgenr; INDEX_2 edge(el[eledges[k][0]], el[eledges[k][1]]); int edgedir = (edge.I1() > edge.I2()); return edgedir; } int MeshTopology :: GetSurfaceElementFaceOrientation2 (int elnr) const { const Element2d & el = mesh->SurfaceElement (elnr); const ELEMENT_FACE * elfaces = MeshTopology::GetFaces0 (el.GetType()); int j = 0; if (elfaces[j][3] < 0) { // triangle INDEX_4 face(el[elfaces[j][0]], el[elfaces[j][1]], el[elfaces[j][2]], PointIndex(PointIndex::INVALID)); int 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; } return facedir; } else { // quad // int facenum; INDEX_4 face4(el[elfaces[j][0]], el[elfaces[j][1]], el[elfaces[j][2]], el[elfaces[j][3]]); int 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()); } return facedir; } } void MeshTopology :: GetSegmentEdge (int segnr, int & enr, int & orient) const { enr = segedges[segnr-1]+1; orient = GetSegmentEdgeOrientation(segnr); } int MeshTopology :: GetSegmentEdgeOrientation (int elnr) const { const Segment & el = mesh->LineSegment (elnr); const ELEMENT_EDGE * eledges = MeshTopology::GetEdges0 (el.GetType()); int k = 0; INDEX_2 edge(el[eledges[k][0]], el[eledges[k][1]]); int edgedir = (edge.I1() > edge.I2()); return edgedir; } void MeshTopology :: GetFaceVertices (int fnr, NgArray & vertices) const { vertices.SetSize(4); for (int i = 0; i < 4; i++) vertices[i] = face2vert[fnr-1][i]; if (vertices[3]+1==PointIndex::BASE) vertices.SetSize(3); } void MeshTopology :: GetFaceVertices (int fnr, int * vertices) const { for (int i = 0; i <= 3; i++) vertices[i] = face2vert[fnr-1][i]; } void MeshTopology :: GetEdgeVertices (int ednr, int & v1, int & v2) const { // cout << "id = " << id << "getedgevertices, ednr = " << ednr << ", ned = " << edge2vert.Size() << "&v1 = " << &v1 << endl; if (ednr < 1 || ednr > edge2vert.Size()) cerr << "illegal edge nr: " << ednr << ", numedges = " << edge2vert.Size() << " id = " << id << endl; v1 = edge2vert[ednr-1][0]; v2 = edge2vert[ednr-1][1]; } void MeshTopology :: GetEdgeVertices (int ednr, PointIndex & v1, PointIndex & v2) const { v1 = edge2vert[ednr-1][0]; v2 = edge2vert[ednr-1][1]; } void MeshTopology :: GetFaceEdges (int fnr, NgArray & fedges, bool withorientation) const { // NgArrayMem pi(4); // NgArrayMem eledges; fedges.SetSize (0); // GetFaceVertices(fnr, pi); auto pi = GetFaceVertices(fnr-1); // Sort Edges according to global vertex numbers // e1 = fmax, f2 // e2 = fmax, f1 // e3 = op e1(f2,f3) // e4 = op e2(f1,f3) /* NgArrayMem fp; fp[0] = pi[0]; for(int k=1;kfp[0]) swap(fp[k],fp[0]); fp[1] = fp[0]+ */ // GetVertexElements (pi[0], els); FlatArray 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)[els[i]]; int nref_faces = GetNFaces (el.GetType()); const ELEMENT_FACE * ref_faces = GetFaces1 (el.GetType()); int nfa_ref_edges = GetNEdges (GetFaceType0(fnr-1)); int cntv = 0,fa=-1; for(int m=0;m0;j++) for(int k=0;k=0) { const ELEMENT_EDGE * fa_ref_edges = GetEdges1 (GetFaceType0(fnr-1)); fedges.SetSize(nfa_ref_edges); // GetElementEdges (els[i]+1, eledges); auto eledges = GetEdges (els[i]); for (int j = 0; j < eledges.Size(); j++) { // int vi1, vi2; // GetEdgeVertices (eledges[j]+1, vi1, vi2); auto [vi1, vi2] = GetEdgeVertices(eledges[j]); 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 & elements) const { if (vert2element.Size()) elements = vert2element[vnr]; } void MeshTopology :: GetVertexSurfaceElements( int vnr, Array & elements ) const { if (vert2surfelement.Size()) elements = vert2surfelement[vnr]; } int MeshTopology :: GetVerticesEdge ( PointIndex v1, PointIndex v2 ) const { /* if (vert2element.Size() > 0) { auto elements_v1 = GetVertexElements ( v1 ); // int edv1, edv2; for ( int i = 0; i < elements_v1.Size(); i++ ) { // GetElementEdges( elements_v1[i]+1, elementedges ); auto elementedges = GetEdges(ElementIndex(elements_v1[i])); for ( int ed = 0; ed < elementedges.Size(); ed ++) { // GetEdgeVertices( elementedges[ed]+1, edv1, edv2 ); auto [edv1,edv2] = GetEdgeVertices (elementedges[ed]); if ( ( edv1 == v1 && edv2 == v2 ) || ( edv1 == v2 && edv2 == v1 ) ) return elementedges[ed]; } } } */ if (vert2element.Size() > 0) for (auto ei : GetVertexElements ( v1 )) for (auto ed : GetEdges(ei)) { auto [edv1,edv2] = GetEdgeVertices (ed); if ( ( edv1 == v1 && edv2 == v2 ) || ( edv1 == v2 && edv2 == v1 ) ) return ed; } if (vert2surfelement.Size() > 0) for (auto sei : GetVertexSurfaceElements ( v1 )) for (auto ed : GetEdges(sei)) { auto [edv1,edv2] = GetEdgeVertices (ed); if ( ( edv1 == v1 && edv2 == v2 ) || ( edv1 == v2 && edv2 == v1 ) ) return ed; } return -1; } void MeshTopology :: GetSegmentVolumeElements ( int segnr, NgArray & volels ) const { /* int v1, v2; // GetEdgeVertices ( GetSegmentEdge (segnr), v1, v2 ); GetEdgeVertices ( GetEdge (segnr-1)+1, v1, v2 ); */ auto [v1,v2] = GetEdgeVertices ( GetEdge (segnr-1) ); auto volels1 = GetVertexElements ( v1 ); auto volels2 = GetVertexElements ( v2 ); volels.SetSize(0); for ( auto volel1 : volels1 ) if ( volels2.Contains( volel1 ) ) volels.Append ( volel1 ); } void MeshTopology :: GetSegmentSurfaceElements (int segnr, NgArray & els) const { // int v1, v2; // GetEdgeVertices ( GetSegmentEdge (segnr), v1, v2 ); // GetEdgeVertices ( GetEdge (segnr-1)+1, v1, v2 ); auto [v1,v2] = GetEdgeVertices ( GetEdge (segnr-1) ); auto els1 = GetVertexSurfaceElements ( v1 ); auto els2 = GetVertexSurfaceElements ( v2 ); els.SetSize(0); for ( auto el1 : els1 ) if ( els2.Contains( el1 ) ) els.Append ( el1 ); } } ================================================ FILE: libsrc/meshing/topology.hpp ================================================ #ifndef TOPOLOGY #define TOPOLOGY /**************************************************************************/ /* File: topology.hh */ /* Author: Joachim Schoeberl */ /* Date: 27. Apr. 01 */ /**************************************************************************/ /* Mesh topology (Elements, Faces, Edges, Vertices */ #include "meshtype.hpp" namespace netgen { // typedef int T_EDGE; // typedef int T_FACE; class EdgeIndex : public Index { public: using Index::Index; }; class FaceIndex : public Index { public: using Index::Index; }; typedef EdgeIndex T_EDGE; typedef FaceIndex T_FACE; class MeshTopology { const Mesh * mesh; bool buildvertex2element; bool buildedges; bool buildfaces; bool build_parent_edges = false; // may be changed to default = false bool build_parent_faces = false; // may be changed to default = false static bool static_buildedges, static_buildfaces, static_buildvertex2element; Array> edge2vert; Array> face2vert; Array, ElementIndex> edges; Array, ElementIndex> faces; Array, SurfaceElementIndex> surfedges; Array segedges; Array surffaces; // Array surf2volelement; Array, SurfaceElementIndex> surf2volelement; Array face2surfel; Array edge2segment; Table vert2element; Table vert2surfelement; Table vert2segment; Table vert2pointelement; int timestamp; public: MeshTopology () = default; MeshTopology (MeshTopology && top) = default; DLL_HEADER MeshTopology (const Mesh & amesh); DLL_HEADER ~MeshTopology (); MeshTopology & operator= (MeshTopology && top) = default; void SetBuildVertex2Element (bool bv2e) { buildvertex2element = bv2e; } void SetBuildEdges (bool be) { buildedges = be; } void SetBuildFaces (bool bf) { buildfaces = bf; } void SetBuildParentEdges (bool bh) { build_parent_edges = bh; } void SetBuildParentFaces (bool bh) { build_parent_faces = bh; } DLL_HEADER void EnableTable (string name, bool set); static void EnableTableStatic (string name, bool set); bool HasEdges () const { return buildedges; } bool HasFaces () const { return buildfaces; } bool HasParentEdges () const { return build_parent_edges; } bool HasParentFaces () const { return build_parent_faces; } void Update(NgTaskManager tm = &DummyTaskManager, NgTracer tracer = &DummyTracer); bool NeedsUpdate() const; size_t GetNEdges () const { return edge2vert.Size(); } size_t GetNFaces () const { return face2vert.Size(); } static inline short int GetNVertices (ELEMENT_TYPE et); static inline short int GetNPoints (ELEMENT_TYPE et); static inline short int GetNEdges (ELEMENT_TYPE et); static inline short int GetNFaces (ELEMENT_TYPE et); DLL_HEADER 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 FlatArray GetEdges (ELEMENT_TYPE et); inline static const ELEMENT_FACE * GetFaces1 (ELEMENT_TYPE et); inline static const ELEMENT_FACE * GetFaces0 (ELEMENT_TYPE et); [[deprecated("use GetEdge(SegmentIndex) instead")]] EdgeIndex GetSegmentEdge (int segnr) const { return segedges[segnr-1]+1; } EdgeIndex GetEdge (SegmentIndex segnr) const { return segedges[segnr]; } [[deprecated("use GetEdge(SegmentIndex) instead")]] void GetSegmentEdge (int segnr, int & enr, int & orient) const; [[deprecated("use GetEdges (ElementIndex) -> FlatArray")]] void GetElementEdges (int elnr, NgArray & edges) const; [[deprecated("use GetFaces (ElementIndex) -> FlatArray")]] void GetElementFaces (int elnr, NgArray & faces) const; void GetElementFaces (int elnr, NgArray & faces, bool withorientation) const; // definition in meshclass.hpp inline FlatArray GetEdges (ElementIndex elnr) const; inline FlatArray GetFaces (ElementIndex elnr) const; // [[deprecated("use GetElementEdge instead")]] void GetElementEdgeOrientations (int elnr, NgArray & eorient) const; // [[deprecated("use GetElementEdge instead")]] void GetElementFaceOrientations (int elnr, NgArray & forient) const; [[deprecated("use GetEdges (ElementIndex) -> FlatArray")]] int GetElementEdges (int elnr, int * edges, int * orient) const; // [[deprecated("use GetFaces (ElementIndex) -> FlatArray")]] int GetElementFaces (int elnr, int * faces, int * orient) const; // [[deprecated("use GetElementEdge instead")]] int GetElementEdgeOrientation (int elnr, int locedgenr) const; // old style // [[deprecated("use GetElementEdge instead")]] int GetElementFaceOrientation (int elnr, int locfacenr) const; // old style // [[deprecated("use GetElementEdge instead")]] int GetSurfaceElementEdgeOrientation (int elnr, int locedgenr) const; // old style // [[deprecated("use GetElementEdge instead")]] int GetSurfaceElementFaceOrientation2 (int elnr) const; // old style // [[deprecated("use GetElementEdge instead")]] int GetSegmentEdgeOrientation (int elnr) const; // old style DLL_HEADER void GetFaceVertices (int fnr, NgArray & vertices) const; DLL_HEADER void GetFaceVertices (int fnr, int * vertices) const; auto GetFaceVertices (int fnr) const { return FlatArray (face2vert[fnr][3].IsValid() ? 4 : 3, &face2vert[fnr][0]); } [[deprecated("use GetEdgeVertices -> tupe(v0,v1) instead")]] DLL_HEADER void GetEdgeVertices (int enr, int & v1, int & v2) const; [[deprecated("use GetEdgeVertices -> tupe(v0,v1) instead")]] DLL_HEADER void GetEdgeVertices (int enr, PointIndex & v1, PointIndex & v2) const; auto GetEdgeVertices (int enr) const { return std::array{edge2vert[enr][0], edge2vert[enr][1]}; } auto GetEdgeVerticesPtr (int enr) const { return &edge2vert[enr][0]; } auto GetFaceVerticesPtr (int fnr) const { return &face2vert[fnr][0]; } DLL_HEADER void GetFaceEdges (int fnr, NgArray & edges, bool withorientation = false) const; // ELEMENT_TYPE GetFaceType (int fnr) const // { return (!face2vert[fnr-1][3].IsValid()) ? TRIG : QUAD; } ELEMENT_TYPE GetFaceType0 (SurfaceElementIndex fnr) const { return (!face2vert[fnr][3].IsValid()) ? TRIG : QUAD; } [[deprecated("use GetEdges (SurfaceElementIndex) -> FlatArray")]] void GetSurfaceElementEdges (int elnr, NgArray & edges) const; [[deprecated("use GetFace(SurfaceElementIndex")]] int GetSurfaceElementFace1 (int elnr) const { return surffaces[elnr-1]+1; } [[deprecated("orientation is outdated")]] void GetSurfaceElementEdgeOrientations (int elnr, NgArray & eorient) const; // [[deprecated("orientation is outdated")]] int GetSurfaceElementFaceOrientation (int elnr) const; [[deprecated("use GetEdge -> FlatArray instead")]] void GetEdges (SurfaceElementIndex elnr, NgArray & edges) const; inline FlatArray GetEdges (SurfaceElementIndex elnr) const; // { return FlatArray(GetNEdges ( (*mesh)[elnr].GetType()), &surfedges[elnr][0]); } int GetFace (SurfaceElementIndex elnr) const { return surffaces[elnr]; } int GetSurfaceElementEdges (int elnr, int * edges, int * orient) const; int GetNSurfedges() const {return surfedges.Size();} [[deprecated("use GetEdges(ElementIndex) instead")]] const EdgeIndex * GetElementEdgesPtr (int elnr) const { return &edges[IndexBASE()+elnr][0]; } const EdgeIndex * GetSurfaceElementEdgesPtr (int selnr) const { return &surfedges[selnr][0]; } const EdgeIndex * GetSegmentElementEdgesPtr (int selnr) const { return &segedges[selnr]; } const FaceIndex * GetElementFacesPtr (int elnr) const { return &faces[IndexBASE()+elnr][0]; } const FaceIndex * GetSurfaceElementFacesPtr (int selnr) const { return &surffaces[selnr]; } void GetSurface2VolumeElement (int selnr, int & elnr1, int & elnr2) const { elnr1 = surf2volelement[SurfaceElementIndex::Base() + selnr-1][0]+1 - ElementIndex::Base(); elnr2 = surf2volelement[SurfaceElementIndex::Base() + selnr-1][1]+1 - ElementIndex::Base(); } std::array GetSurface2VolumeElement (SurfaceElementIndex sei) { return surf2volelement[sei]; } [[deprecated("use GetSurfaceEleement -> SurfaceElementIndex")]] int GetFace2SurfaceElement1 (int fnr) const { return face2surfel[fnr-1]+1 - SurfaceElementIndex::Base(); } SurfaceElementIndex GetFace2SurfaceElement (int fnr) const { return face2surfel[fnr]; } SegmentIndex GetSegmentOfEdge(int edgenr) const { return edge2segment[edgenr-1]; } [[deprecated("use GetVertexElements -> FlatArray instead")]] void GetVertexElements (int vnr, Array & elements) const; FlatArray GetVertexElements (PointIndex vnr) const { return vert2element[vnr]; } [[deprecated("use GetVertexSurfaceElements -> FlatArray instead")]] void GetVertexSurfaceElements( int vnr, Array& elements ) const; const auto & GetVertexSurfaceElements( ) const { return vert2surfelement; } FlatArray GetVertexSurfaceElements(PointIndex vnr) const { return vert2surfelement[vnr]; } FlatArray GetVertexSegments (PointIndex vnr) const { return vert2segment[vnr]; } FlatArray GetVertexPointElements (PointIndex vnr) const { return vert2pointelement[vnr]; } DLL_HEADER int GetVerticesEdge ( PointIndex v1, PointIndex v2) const; void GetSegmentVolumeElements ( int segnr, NgArray & els ) const; void GetSegmentSurfaceElements ( int segnr, NgArray & els ) const; // Call this before Update() to discard old edges void ClearEdges() { edge2vert.SetSize0(); } private: Array>> parent_edges; void BuildParentEdges (); Array>> parent_faces; void BuildParentFaces (); public: auto GetParentEdges (int enr) const { return parent_edges[enr]; } auto GetParentFaces (int fnr) const { return parent_faces[fnr]; } }; inline short 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: case PYRAMID13: return 5; case PRISM: case PRISM12: case PRISM15: return 6; case HEX7: return 7; case HEX: case HEX20: return 8; // default: // cerr << "Ng_ME_GetNVertices, illegal element type " << et << endl; } return 0; } inline short 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: return 4; case QUAD8: return 8; case TET: return 4; case TET10: return 10; case PYRAMID: return 5; case PYRAMID13: return 13; case PRISM: return 6; case PRISM12: return 12; case PRISM15: return 15; case HEX7: return 7; case HEX: return 8; case HEX20: return 20; // default: // cerr << "Ng_ME_GetNVertices, illegal element type " << et << endl; } return -99; } inline short int MeshTopology :: GetNEdges (ELEMENT_TYPE et) { // __assume(et >= SEGMENT && et <= PYRAMID13); 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: case PYRAMID13: return 8; case PRISM: case PRISM12: case PRISM15: return 9; case HEX7: return 11; case HEX: case HEX20: return 12; // default: // cerr << "Ng_ME_GetNEdges, illegal element type " << et << endl; } return 0; } inline short int MeshTopology :: GetNFaces (ELEMENT_TYPE et) { // __assume(et >= SEGMENT && et <= PYRAMID13); 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: case PYRAMID13: return 5; case PRISM: case PRISM12: case PRISM15: return 5; case HEX: case HEX20: case HEX7: return 6; default: return 0; // default: // cerr << "Ng_ME_GetNVertices, illegal element type " << et << endl; } } const ELEMENT_EDGE * MeshTopology :: GetEdges1 (ELEMENT_TYPE et) { static ELEMENT_EDGE segm_edges[1] = { { 1, 2 }}; static ELEMENT_EDGE trig_edges[3] = { { 3, 1 }, { 2, 3 }, { 1, 2 }}; static ELEMENT_EDGE quad_edges[4] = { { 1, 2 }, { 3, 4 }, { 4, 1 }, { 2, 3 }}; static ELEMENT_EDGE tet_edges[6] = { { 4, 1 }, { 4, 2 }, { 4, 3 }, { 1, 2 }, { 1, 3 }, { 2, 3 }}; static ELEMENT_EDGE prism_edges[9] = { { 3, 1 }, { 1, 2 }, { 3, 2 }, { 6, 4 }, { 4, 5 }, { 6, 5 }, { 3, 6 }, { 1, 4 }, { 2, 5 }}; static ELEMENT_EDGE pyramid_edges[8] = { { 1, 2 }, { 2, 3 }, { 1, 4 }, { 4, 3 }, { 1, 5 }, { 2, 5 }, { 3, 5 }, { 4, 5 }}; static ELEMENT_EDGE hex7_edges[11] = { { 1, 2 }, { 3, 4 }, { 4, 1 }, { 2, 3 }, { 5, 6 }, { 7, 5 }, { 6, 7 }, { 1, 5 }, { 2, 6 }, { 3, 7 }, { 4, 7 }, }; static ELEMENT_EDGE hex_edges[12] = { { 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: case PYRAMID13: return pyramid_edges; case PRISM: case PRISM12: case PRISM15: return prism_edges; case HEX7: return hex7_edges; case HEX: case HEX20: return hex_edges; // default: // cerr << "Ng_ME_GetEdges, illegal element type " << et << endl; } return 0; } const ELEMENT_EDGE * MeshTopology :: GetEdges0 (ELEMENT_TYPE et) { static ELEMENT_EDGE segm_edges[1] = { { 0, 1 }}; static ELEMENT_EDGE trig_edges[3] = { { 2, 0 }, { 1, 2 }, { 0, 1 }}; static ELEMENT_EDGE quad_edges[4] = { { 0, 1 }, { 2, 3 }, { 3, 0 }, { 1, 2 }}; static ELEMENT_EDGE tet_edges[6] = { { 3, 0 }, { 3, 1 }, { 3, 2 }, { 0, 1 }, { 0, 2 }, { 1, 2 }}; static ELEMENT_EDGE prism_edges[9] = { { 2, 0 }, { 0, 1 }, { 2, 1 }, { 5, 3 }, { 3, 4 }, { 5, 4 }, { 2, 5 }, { 0, 3 }, { 1, 4 }}; static ELEMENT_EDGE pyramid_edges[8] = { { 0, 1 }, { 1, 2 }, { 0, 3 }, { 3, 2 }, { 0, 4 }, { 1, 4 }, { 2, 4 }, { 3, 4 }}; static ELEMENT_EDGE hex7_edges[11] = { { 0, 1 }, { 2, 3 }, { 3, 0 }, { 1, 2 }, { 4, 5 }, { 6, 4 }, { 5, 6 }, { 0, 4 }, { 1, 5 }, { 2, 6 }, { 3, 6 }, }; static ELEMENT_EDGE hex_edges[12] = { { 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: case PYRAMID13: return pyramid_edges; case PRISM: case PRISM12: case PRISM15: return prism_edges; case HEX7: return hex7_edges; case HEX: case HEX20: return hex_edges; // default: // cerr << "Ng_ME_GetEdges, illegal element type " << et << endl; } return 0; } FlatArray MeshTopology :: GetEdges (ELEMENT_TYPE et) { static ELEMENT_EDGE segm_edges[1] = { { 0, 1 }}; static ELEMENT_EDGE trig_edges[3] = { { 2, 0 }, { 1, 2 }, { 0, 1 }}; static ELEMENT_EDGE quad_edges[4] = { { 0, 1 }, { 2, 3 }, { 3, 0 }, { 1, 2 }}; static ELEMENT_EDGE tet_edges[6] = { { 3, 0 }, { 3, 1 }, { 3, 2 }, { 0, 1 }, { 0, 2 }, { 1, 2 }}; static ELEMENT_EDGE prism_edges[9] = { { 2, 0 }, { 0, 1 }, { 2, 1 }, { 5, 3 }, { 3, 4 }, { 5, 4 }, { 2, 5 }, { 0, 3 }, { 1, 4 }}; static ELEMENT_EDGE pyramid_edges[8] = { { 0, 1 }, { 1, 2 }, { 0, 3 }, { 3, 2 }, { 0, 4 }, { 1, 4 }, { 2, 4 }, { 3, 4 }}; static ELEMENT_EDGE hex7_edges[11] = { { 0, 1 }, { 2, 3 }, { 3, 0 }, { 1, 2 }, { 4, 5 }, { 6, 4 }, { 5, 6 }, { 0, 4 }, { 1, 5 }, { 2, 6 }, { 3, 6 }, }; static ELEMENT_EDGE hex_edges[12] = { { 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 { 1, segm_edges }; case TRIG: case TRIG6: return { 3, trig_edges }; case QUAD: case QUAD6: case QUAD8: return { 4, quad_edges }; case TET: case TET10: return { 6, tet_edges }; case PYRAMID: case PYRAMID13: return { 8, pyramid_edges }; case PRISM: case PRISM12: case PRISM15: return { 9, prism_edges }; case HEX7: return { 11, hex7_edges }; case HEX: case HEX20: return { 12, hex_edges }; // default: // cerr << "Ng_ME_GetEdges, illegal element type " << et << endl; } return { 0, nullptr }; } inline const ELEMENT_FACE * MeshTopology :: GetFaces1 (ELEMENT_TYPE et) { static const ELEMENT_FACE trig_faces[1] = { { 1, 2, 3, 0 } }; static const ELEMENT_FACE quad_faces[1] = { { 1, 2, 3, 4 } }; static const ELEMENT_FACE tet_faces[4] = { { 4, 2, 3, 0 }, { 4, 3, 1, 0 }, { 4, 1, 2, 0 }, { 1, 3, 2, 0 } }; static const ELEMENT_FACE prism_faces[5] = { { 1, 3, 2, 0 }, { 4, 5, 6, 0 }, { 3, 1, 4, 6 }, { 1, 2, 5, 4 }, { 2, 3, 6, 5 } }; static const ELEMENT_FACE pyramid_faces[5] = { { 1, 2, 5, 0 }, { 2, 3, 5, 0 }, { 3, 4, 5, 0 }, { 4, 1, 5, 0 }, { 1, 4, 3, 2 } }; static const ELEMENT_FACE hex7_faces[6] = { { 1, 4, 3, 2 }, { 5, 6, 7, 0 }, { 1, 2, 6, 5 }, { 2, 3, 7, 6 }, { 3, 4, 7, 0 }, { 4, 1, 5, 7 } }; static const ELEMENT_FACE hex_faces[6] = { { 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: case PRISM15: return prism_faces; case PYRAMID: case PYRAMID13: return pyramid_faces; case SEGMENT: case SEGMENT3: case HEX7: return hex7_faces; case HEX: case HEX20: return hex_faces; // default: // cerr << "Ng_ME_GetVertices, illegal element type " << et << endl; } return 0; } inline const ELEMENT_FACE * MeshTopology :: GetFaces0 (ELEMENT_TYPE et) { static const ELEMENT_FACE trig_faces[1] = { { 0, 1, 2, -1 } }; static const ELEMENT_FACE quad_faces[1] = { { 0, 1, 2, 3 } }; static const ELEMENT_FACE tet_faces[4] = { { 3, 1, 2, -1 }, { 3, 2, 0, -1 }, { 3, 0, 1, -1 }, { 0, 2, 1, -1 } }; static const ELEMENT_FACE prism_faces[5] = { { 0, 2, 1, -1 }, { 3, 4, 5, -1 }, { 2, 0, 3, 5 }, { 0, 1, 4, 3 }, { 1, 2, 5, 4 } }; static const ELEMENT_FACE pyramid_faces[5] = { { 0, 1, 4, -1 }, { 1, 2, 4, -1 }, { 2, 3, 4, -1 }, { 3, 0, 4, -1 }, { 0, 3, 2, 1 } }; static const ELEMENT_FACE hex7_faces[6] = { { 0, 3, 2, 1 }, { 4, 5, 6, -1}, { 0, 1, 5, 4 }, { 1, 2, 6, 5 }, { 2, 3, 6, -1}, { 3, 0, 4, 6 } }; static const ELEMENT_FACE hex_faces[6] = { { 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: case PRISM15: return prism_faces; case PYRAMID: case PYRAMID13: return pyramid_faces; case SEGMENT: case SEGMENT3: case HEX7: return hex7_faces; case HEX: case HEX20: return hex_faces; // default: // cerr << "Ng_ME_GetVertices, illegal element type " << et << endl; } return 0; } } #endif ================================================ FILE: libsrc/meshing/validate.cpp ================================================ #include #include "meshing.hpp" namespace netgen { void GetPureBadness(Mesh & mesh, NgArray & pure_badness, const TBitArray & isnewpoint) { //const int ne = mesh.GetNE(); const int np = mesh.GetNP(); pure_badness.SetSize(np+PointIndex::BASE+1); pure_badness = -1; NgArray< Point<3>* > backup(np); for(int i=0; i(mesh.Point(i+1)); if(isnewpoint.Test(i+IndexBASE()) && mesh.mlbetweennodes[i+IndexBASE()][0].IsValid()) { mesh.Point(i+1) = Center(mesh.Point(mesh.mlbetweennodes[i+IndexBASE()][0]), mesh.Point(mesh.mlbetweennodes[i+IndexBASE()][1])); } } for (ElementIndex i = 0; i < mesh.GetNE(); i++) { double bad = mesh[i].CalcJacobianBadness (mesh.Points()); for(int j=0; j 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 & bad_elements, const NgArray & pure_badness, double max_worsening, const bool uselocalworsening, NgArray * 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 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, TBitArray & working_points, const Mesh & mesh, const NgArray & bad_elements, const int width) { working_elements.Clear(); working_points.Clear(); for(int i=0; i & bad_elements, const TBitArray & isnewpoint, const Refinement & refinement, const NgArray & pure_badness, double max_worsening, const bool uselocalworsening, const NgArray< idmap_type* > & 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"); NgArray* > should(np); NgArray* > can(np); NgArray* > nv(np); for(int i=0; i; should[i] = new Point<3>; can[i] = new Point<3>; } TBitArray isboundarypoint(np),isedgepoint(np); isboundarypoint.Clear(); isedgepoint.Clear(); for(int i = 1; i <= mesh.GetNSeg(); i++) { const Segment & seg = mesh.LineSegment(i); isedgepoint.SetBit(seg[0]); isedgepoint.SetBit(seg[1]); } NgArray surfaceindex(np); surfaceindex = -1; /* for (int i = 1; i <= mesh.GetNSE(); i++) { const Element2d & sel = mesh.SurfaceElement(i); */ for (auto & sel : mesh.SurfaceElements()) for (int j = 1; j <= sel.GetNP(); j++) if(!isedgepoint.Test(sel.PNum(j))) { isboundarypoint.SetBit(sel.PNum(j)); surfaceindex[sel.PNum(j) - IndexBASE()] = 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 TBitArray working_elements(ne+1); TBitArray 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()); TBitArray isworkingboundary(np); for(int i=1; i<=np; i++) if(working_points.Test(i) && isboundarypoint.Test(i)) isworkingboundary.SetBit(i); else isworkingboundary.Clear(i); for(int i=0; i(); i < IndexBASE()+np; i++) { if(isnewpoint.Test(i) && //working_points.Test(i+PointIndex::BASE) && mesh.mlbetweennodes[i][0].IsValid()) *can[i-IndexBASE()] = Center(*can[mesh.mlbetweennodes[i][0]-IndexBASE()], *can[mesh.mlbetweennodes[i][1]-IndexBASE()]); else *can[i-IndexBASE()] = mesh[i]; } 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; auto geo = mesh.GetGeometry(); if(!geo) { 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(0,0,0); /* for (int i = 1; i <= mesh.GetNSE(); i++) { const Element2d & sel = mesh.SurfaceElement(i); */ for (auto & sel : mesh.SurfaceElements()) { 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) - IndexBASE()] += auxvec; } for(int i=0; iNormalize(); 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(geo) for(int i=0; i= 0) { *should[i] = *can[i]; geo->ProjectPoint(surfaceindex[i],*should[i]); } } } 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(mesh, dummymp, OPT_QUALITY); for(int i=0; iProjectBoundaryPoints(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 & pure_badness, const TBitArray & isnewpoint); double Validate(const Mesh & mesh, NgArray & bad_elements, const NgArray & pure_badness, double max_worsening, const bool uselocalworsening, NgArray * quality_loss = NULL); void RepairBisection(Mesh & mesh, NgArray & bad_elements, const TBitArray & isnewpoint, const Refinement & refinement, const NgArray & pure_badness, double max_worsening, const bool uselocalworsening, const NgArray< idmap_type* > & idmaps); } #endif // VALIDATE_HPP ================================================ FILE: libsrc/meshing/visual_interface.cpp ================================================ #include "visual_interface.hpp" #include "../include/nginterface.h" void (*Ptr_Ng_ClearSolutionData) () = nullptr; void (*Ptr_Ng_InitSolutionData) (Ng_SolutionData*) = nullptr; void (*Ptr_Ng_SetSolutionData) (Ng_SolutionData*) = nullptr; void (*Ptr_Ng_Redraw) (bool blocking) = nullptr; void Ng_ClearSolutionData () { if(Ptr_Ng_ClearSolutionData) Ptr_Ng_ClearSolutionData(); } void Ng_InitSolutionData (Ng_SolutionData * soldata) { if(Ptr_Ng_InitSolutionData) Ptr_Ng_InitSolutionData(soldata); } void Ng_SetSolutionData (Ng_SolutionData * soldata) { if(Ptr_Ng_SetSolutionData) Ptr_Ng_SetSolutionData(soldata); } void Ng_Redraw (bool blocking) { if(Ptr_Ng_Redraw) Ptr_Ng_Redraw(blocking); } namespace netgen { void (*Ptr_Ng_Tcl_SetResult)(Tcl_Interp *interp, char *result, Tcl_FreeProc *freeProc) = nullptr; void (*Ptr_Ng_Tcl_CreateCommand)(Tcl_Interp *interp, const char *cmdName, Tcl_CmdProc *proc) = nullptr; void (*Ptr_Render)(bool) = nullptr; void (*Ptr_UpdateVisSurfaceMeshData)(int, shared_ptr>>, shared_ptr>, shared_ptr>> ) = nullptr; } // namespace netgen ================================================ FILE: libsrc/meshing/visual_interface.hpp ================================================ #ifndef VISUAL_INTERFACE_HPP_INCLUDED #define VISUAL_INTERFACE_HPP_INCLUDED #include #include #include struct Ng_SolutionData; // Function pointers for visualization purposed, all set to nullptr by default and initialized correctly when the GUI library is loaded DLL_HEADER extern void (*Ptr_Ng_ClearSolutionData) (); DLL_HEADER extern void (*Ptr_Ng_InitSolutionData) (Ng_SolutionData * soldata); DLL_HEADER extern void (*Ptr_Ng_SetSolutionData) (Ng_SolutionData * soldata); DLL_HEADER extern void (*Ptr_Ng_Redraw) (bool blocking); // Tcl wrapper functions struct Tcl_Interp; typedef int (Tcl_CmdProc) (void * clientData, Tcl_Interp *interp, int argc, const char *argv[]); typedef void (Tcl_FreeProc) (char *blockPtr); namespace netgen { /* inline constexpr int NG_TCL_VOLATILE = 1; inline constexpr int NG_TCL_STATIC = 0; inline constexpr int NG_TCL_DYNAMIC = 3; */ #define NG_TCL_VOLATILE ((Tcl_FreeProc *) 1) #define NG_TCL_STATIC ((Tcl_FreeProc *) 0) #define NG_TCL_DYNAMIC ((Tcl_FreeProc *) 3) inline constexpr int NG_TCL_OK = 0; inline constexpr int NG_TCL_ERROR = 1; inline constexpr int NG_TCL_RETURN = 2; inline constexpr int NG_TCL_BREAK = 3; inline constexpr int NG_TCL_CONTINUE = 4; DLL_HEADER extern void (*Ptr_Ng_Tcl_SetResult)(Tcl_Interp *interp, char *result, Tcl_FreeProc *freeProc); DLL_HEADER extern void (*Ptr_Ng_Tcl_CreateCommand)(Tcl_Interp *interp, const char *cmdName, Tcl_CmdProc *proc); DLL_HEADER extern void (*Ptr_Render)(bool); DLL_HEADER extern void (*Ptr_UpdateVisSurfaceMeshData)(int, shared_ptr>>, shared_ptr>, shared_ptr>> ); inline void Render(bool blocking = false) { if(Ptr_Render) Ptr_Render(blocking); } inline void UpdateVisSurfaceMeshData(int oldnl, shared_ptr>> locpointsptr = nullptr, shared_ptr> loclinesptr = nullptr, shared_ptr>> plainpointsptr = nullptr ) { if(Ptr_UpdateVisSurfaceMeshData) Ptr_UpdateVisSurfaceMeshData(oldnl, locpointsptr, loclinesptr, plainpointsptr); } inline void Ng_Tcl_SetResult(Tcl_Interp *interp, char *result, Tcl_FreeProc *freeProc) { if(Ptr_Ng_Tcl_SetResult) Ptr_Ng_Tcl_SetResult(interp, result, freeProc); } inline void Ng_Tcl_CreateCommand(Tcl_Interp *interp, const char *cmdName, Tcl_CmdProc *proc) { if(Ptr_Ng_Tcl_CreateCommand) Ptr_Ng_Tcl_CreateCommand(interp, cmdName, proc); } } #endif // VISUAL_INTERFACE_HPP_INCLUDED ================================================ FILE: libsrc/occ/CMakeLists.txt ================================================ target_sources(nglib PRIVATE Partition_Inter2d.cxx Partition_Inter3d.cxx Partition_Loop.cxx Partition_Loop2d.cxx Partition_Loop3d.cxx Partition_Spliter.cxx occgenmesh.cpp occgeom.cpp occmeshsurf.cpp python_occ.cpp python_occ_basic.cpp python_occ_shapes.cpp occ_face.cpp occ_edge.cpp occ_vertex.cpp occ_utils.cpp cross_section.cpp ) if(USE_GUI) target_sources(nggui PRIVATE vsocc.cpp occpkg.cpp) endif(USE_GUI) install(FILES occgeom.hpp occmeshsurf.hpp vsocc.hpp occ_utils.hpp occ_vertex.hpp occ_edge.hpp occ_face.hpp occ_solid.hpp DESTINATION ${NG_INSTALL_DIR_INCLUDE}/occ COMPONENT netgen_devel ) ================================================ FILE: libsrc/occ/Partition_Inter2d.cxx ================================================ #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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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 instead 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: these 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 analytically find vertices that E1 and E2 must pass through 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 having parameter on // closest to or . is True if // found vertex is closer to . 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 //======================================================================= 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 // (encountered 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 . 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 ================================================ FILE: libsrc/occ/Partition_Inter2d.hxx ================================================ // 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 _Standard_Version_HeaderFile #include #endif #if OCC_VERSION_HEX < 0x070000 #ifndef _Handle_BRepAlgo_AsDes_HeaderFile #include #endif #else #include #include #endif #ifndef _Standard_Real_HeaderFile #include #endif #ifndef _Standard_Boolean_HeaderFile #include #endif class BRepAlgo_AsDes; class TopoDS_Face; #if OCC_VERSION_HEX < 0x070000 class TopTools_MapOfShape; class TopTools_ListOfShape; #endif class TopoDS_Vertex; class TopoDS_Edge; #ifndef _Standard_HeaderFile #include #endif #ifndef _Standard_Macro_HeaderFile #include #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 ================================================ FILE: libsrc/occ/Partition_Inter2d.ixx ================================================ // 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 #include "Partition_Inter2d.jxx" ================================================ FILE: libsrc/occ/Partition_Inter2d.jxx ================================================ // 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 // netgen headers #ifndef _BRepAlgo_AsDes_HeaderFile #include #endif #ifndef _TopoDS_Face_HeaderFile #include #endif #ifndef _TopTools_MapOfShape_HeaderFile #include #endif #ifndef _TopoDS_Vertex_HeaderFile #include #endif #ifndef _TopTools_ListOfShape_HeaderFile #include #endif #ifndef _TopoDS_Edge_HeaderFile #include #endif #ifndef _Partition_Inter2d_HeaderFile #include "Partition_Inter2d.hxx" #endif ================================================ FILE: libsrc/occ/Partition_Inter3d.cxx ================================================ #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 #include "Partition_Inter2d.hxx" #include "Partition_Inter3d.ixx" #include "utilities.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef DEB #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //======================================================================= //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)::DownCast(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 sphere, pcurve is out of domain by V though S is // UPeriodic, sometimes it is in domain but nonetheless 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 don't 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 (" CANNOT 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 ================================================ FILE: libsrc/occ/Partition_Inter3d.hxx ================================================ // 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 _Standard_Version_HeaderFile #include #endif #if OCC_VERSION_HEX < 0x070000 #ifndef _Handle_BRepAlgo_AsDes_HeaderFile #include #endif #else #include #include #endif #ifndef _TopTools_DataMapOfShapeListOfShape_HeaderFile #include #endif #ifndef _TopTools_MapOfShape_HeaderFile #include #endif #ifndef _TopTools_DataMapOfShapeShape_HeaderFile #include #endif #ifndef _Standard_Boolean_HeaderFile #include #endif #if OCC_VERSION_HEX < 0x070000 class TopTools_ListOfShape; class TopTools_DataMapOfShapeShape; class TopTools_MapOfShape; #endif class BRepAlgo_AsDes; class TopoDS_Face; class TopoDS_Shape; class TopoDS_Vertex; class TopoDS_Edge; #ifndef _Standard_HeaderFile #include #endif #ifndef _Standard_Macro_HeaderFile #include #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 ================================================ FILE: libsrc/occ/Partition_Inter3d.ixx ================================================ // 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" ================================================ FILE: libsrc/occ/Partition_Inter3d.jxx ================================================ // 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 #endif #ifndef _TopTools_ListOfShape_HeaderFile #include #endif #ifndef _TopTools_DataMapOfShapeShape_HeaderFile #include #endif #ifndef _TopoDS_Face_HeaderFile #include #endif #ifndef _TopTools_MapOfShape_HeaderFile #include #endif #ifndef _TopoDS_Shape_HeaderFile #include #endif #ifndef _TopoDS_Vertex_HeaderFile #include #endif #ifndef _TopoDS_Edge_HeaderFile #include #endif #ifndef _Partition_Inter3d_HeaderFile #include "Partition_Inter3d.hxx" #endif ================================================ FILE: libsrc/occ/Partition_Loop.cxx ================================================ #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 #include #include "Partition_Loop.ixx" #include "utilities.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static char* name = new char[100]; // static int nbe = 0; #ifdef WIN32 #define M_PI 3.14159265358979323846 #endif //======================================================================= //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 connected by the vertex in the list . // Is erased of the list. If is too in the list // 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 edge difference 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 = - M_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 = 0.0; 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 ================================================ FILE: libsrc/occ/Partition_Loop.hxx ================================================ // 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 #endif #ifndef _TopTools_ListOfShape_HeaderFile #include #endif #ifndef _TopTools_DataMapOfShapeListOfShape_HeaderFile #include #endif #ifndef _Standard_Version_HeaderFile #include #endif class TopoDS_Face; class TopoDS_Edge; #if OCC_VERSION_HEX < 0x070000 class TopTools_ListOfShape; #endif #ifndef _Standard_HeaderFile #include #endif #ifndef _Standard_Macro_HeaderFile #include #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 ================================================ FILE: libsrc/occ/Partition_Loop.ixx ================================================ // 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" ================================================ FILE: libsrc/occ/Partition_Loop.jxx ================================================ // 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 #endif #ifndef _TopoDS_Edge_HeaderFile #include #endif #ifndef _TopTools_ListOfShape_HeaderFile #include #endif #ifndef _TopTools_DataMapOfShapeShape_HeaderFile #include #endif #ifndef _Partition_Loop_HeaderFile #include "Partition_Loop.hxx" #endif ================================================ FILE: libsrc/occ/Partition_Loop2d.cxx ================================================ #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 #include "Partition_Loop2d.ixx" #include "utilities.h" #include #include #include #include #include // #include // V6.3 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // V6.5 #include #include #include #include #include #include #include #include #include #include #include #include #include //======================================================================= //function : Partition_Loop2d //purpose : //======================================================================= Partition_Loop2d::Partition_Loop2d() { } //======================================================================= //function : Init //purpose : Init with the set of edges must have // pcurves on . //======================================================================= 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 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 until 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 the edge connected with by // the vertex . // is removed from the list. If is in // 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 edge difference 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 * M_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 (M_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 all edges reachable from //======================================================================= 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 with and // select an edge with its parameter closest to found one. // Return new degenerated edge trimming 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 with edges bound to its vertex in // and store intersection parameter on in // as well as the edges them-self in . // Bind to vertex of in //======================================================================= 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() ); // V6.3 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 double 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 , 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 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 to 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. // serves to find original edge by new // one.
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 ================================================ FILE: libsrc/occ/Partition_Loop2d.hxx ================================================ // 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 #endif #ifndef _TopAbs_Orientation_HeaderFile #include #endif #ifndef _TopTools_ListOfShape_HeaderFile #include #endif #ifndef _TopTools_MapOfShape_HeaderFile #include #endif #ifndef _Standard_Version_HeaderFile #include #endif class TopoDS_Face; class TopoDS_Edge; #if OCC_VERSION_HEX < 0x070000 class TopTools_ListOfShape; #endif class BRepAlgo_Image; #ifndef _Standard_HeaderFile #include #endif #ifndef _Standard_Macro_HeaderFile #include #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 ================================================ FILE: libsrc/occ/Partition_Loop2d.ixx ================================================ // GEOM PARTITION : partition algorithm // // Copyright (C) 2003 CEA/DEN, EDF R&D // // // // File : Partition_Loop2d.ixx // Module : GEOM #include "Partition_Loop2d.jxx" ================================================ FILE: libsrc/occ/Partition_Loop2d.jxx ================================================ // GEOM PARTITION : partition algorithm // // Copyright (C) 2003 CEA/DEN, EDF R&D // // // // File : Partition_Loop2d.jxx // Module : GEOM #ifndef _TopoDS_Face_HeaderFile #include #endif #ifndef _TopoDS_Edge_HeaderFile #include #endif #ifndef _TopTools_ListOfShape_HeaderFile #include #endif #ifndef _BRepAlgo_Image_HeaderFile #include #endif #ifndef _Partition_Loop2d_HeaderFile #include "Partition_Loop2d.hxx" #endif ================================================ FILE: libsrc/occ/Partition_Loop3d.cxx ================================================ #ifdef OCCGEOMETRY // GEOM PARTITION : partition algorithm // // Copyright (C) 2003 CEA/DEN, EDF R&D // // // // File : Partition_Loop3d.cxx // Module : GEOM //using namespace std; #include #include "Partition_Loop3d.ixx" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //======================================================================= //function : Partition_Loop3d //purpose : //======================================================================= Partition_Loop3d::Partition_Loop3d() { } //======================================================================= //function : AddConstFaces //purpose : Add faces of 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 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. // 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 is inside by edge . // if , compute : 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 ================================================ FILE: libsrc/occ/Partition_Loop3d.hxx ================================================ // 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 #endif #ifndef _TopTools_IndexedDataMapOfShapeListOfShape_HeaderFile #include #endif #ifndef _Standard_Boolean_HeaderFile #include #endif #ifndef _Standard_Real_HeaderFile #include #endif #ifndef _Standard_Version_HeaderFile #include #endif #if OCC_VERSION_HEX < 0x070000 #else #include #include #endif class TopoDS_Shape; #if OCC_VERSION_HEX < 0x070000 class TopTools_ListOfShape; class TopTools_MapOfOrientedShape; #endif class TopoDS_Edge; class TopoDS_Face; class gp_Vec; #ifndef _Standard_HeaderFile #include #endif #ifndef _Standard_Macro_HeaderFile #include #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 ================================================ FILE: libsrc/occ/Partition_Loop3d.ixx ================================================ // GEOM PARTITION : partition algorithm // // Copyright (C) 2003 CEA/DEN, EDF R&D // // // // File : Partition_Loop3d.ixx // Module : GEOM #include "Partition_Loop3d.jxx" ================================================ FILE: libsrc/occ/Partition_Loop3d.jxx ================================================ // GEOM PARTITION : partition algorithm // // Copyright (C) 2003 CEA/DEN, EDF R&D // // // // File : Partition_Loop3d.jxx // Module : GEOM #ifndef _TopoDS_Shape_HeaderFile #include #endif #ifndef _TopTools_ListOfShape_HeaderFile #include #endif #ifndef _TopTools_MapOfOrientedShape_HeaderFile #include #endif #ifndef _TopoDS_Edge_HeaderFile #include #endif #ifndef _TopoDS_Face_HeaderFile #include #endif #ifndef _gp_Vec_HeaderFile #include #endif #ifndef _Partition_Loop3d_HeaderFile #include "Partition_Loop3d.hxx" #endif ================================================ FILE: libsrc/occ/Partition_Spliter.cxx ================================================ #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 #include "Partition_Inter2d.hxx" #include "Partition_Inter3d.hxx" #include "Partition_Loop2d.hxx" #include "Partition_Loop3d.hxx" #include "Partition_Spliter.ixx" #include "utilities.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef DEB //# define PART_PERF #endif #ifdef PART_PERF # include #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 . // is an object shape. // makes avoid faces that do not form a // closed shell // 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 unsplit 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 common 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 equal only if they have same vertices. // ==True makes consider same edges as equal // Put in 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 (; iValue( 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 unsplit 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 SEQUENCE 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 (" CANNOT 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 result //======================================================================= 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 result //======================================================================= 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 encountered 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 is a tool shape. Prepare tool // faces of 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 edges 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 ================================================ FILE: libsrc/occ/Partition_Spliter.hxx ================================================ // 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 _Standard_Version_HeaderFile #include #endif #ifndef _TopAbs_ShapeEnum_HeaderFile #include #endif #ifndef _TopoDS_Compound_HeaderFile #include #endif #ifndef _BRep_Builder_HeaderFile #include #endif #ifndef _TopTools_ListOfShape_HeaderFile #include #endif #ifndef _TopTools_MapOfShape_HeaderFile #include #endif #ifndef _TopTools_DataMapOfShapeShape_HeaderFile #include #endif #if OCC_VERSION_HEX < 0x070000 #ifndef _Handle_BRepAlgo_AsDes_HeaderFile #include #endif #else #include #include #endif #ifndef _BRepAlgo_Image_HeaderFile #include #endif #ifndef _Partition_Inter3d_HeaderFile #include "Partition_Inter3d.hxx" #endif #ifndef _TopTools_MapOfOrientedShape_HeaderFile #include #endif #ifndef _Standard_Boolean_HeaderFile #include #endif class BRepAlgo_AsDes; class TopoDS_Shape; #if OCC_VERSION_HEX < 0x070000 class TopTools_ListOfShape; #endif class TopoDS_Edge; #ifndef _Standard_HeaderFile #include #endif #ifndef _Standard_Macro_HeaderFile #include #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 ================================================ FILE: libsrc/occ/Partition_Spliter.ixx ================================================ // 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" ================================================ FILE: libsrc/occ/Partition_Spliter.jxx ================================================ // 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 #endif #ifndef _TopoDS_Shape_HeaderFile #include #endif #ifndef _TopTools_ListOfShape_HeaderFile #include #endif #ifndef _TopoDS_Edge_HeaderFile #include #endif #ifndef _Partition_Spliter_HeaderFile #include "Partition_Spliter.hxx" #endif ================================================ FILE: libsrc/occ/cross_section.cpp ================================================ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "core/array.hpp" #include "occ_utils.hpp" #include "occgeom.hpp" namespace netgen { TopoDS_Face MakePlaneFaceCoveringShape (const TopoDS_Shape& shape, const gp_Pln& pln, double rel_margin = 0.05, double abs_margin = 0.0) { Bnd_Box b; BRepBndLib::Add(shape, b); b.SetGap(0.0); Standard_Real xmin, ymin, zmin, xmax, ymax, zmax; b.Get(xmin, ymin, zmin, xmax, ymax, zmax); gp_Trsf w2l; w2l.SetTransformation(pln.Position()); auto upd = [&] (double x, double y, double z, double& umin, double& umax, double& vmin, double& vmax) { gp_Pnt p(x, y, z); p.Transform(w2l); umin = std::min(umin, p.X()); umax = std::max(umax, p.X()); vmin = std::min(vmin, p.Y()); vmax = std::max(vmax, p.Y()); }; double umin = std::numeric_limits::infinity(); double umax = -std::numeric_limits::infinity(); double vmin = std::numeric_limits::infinity(); double vmax = -std::numeric_limits::infinity(); upd(xmin, ymin, zmin, umin, umax, vmin, vmax); upd(xmin, ymin, zmax, umin, umax, vmin, vmax); upd(xmin, ymax, zmin, umin, umax, vmin, vmax); upd(xmin, ymax, zmax, umin, umax, vmin, vmax); upd(xmax, ymin, zmin, umin, umax, vmin, vmax); upd(xmax, ymin, zmax, umin, umax, vmin, vmax); upd(xmax, ymax, zmin, umin, umax, vmin, vmax); upd(xmax, ymax, zmax, umin, umax, vmin, vmax); double du = umax - umin; double dv = vmax - vmin; double pad = std::max(abs_margin, rel_margin * std::max(du, dv)); umin -= pad; umax += pad; vmin -= pad; vmax += pad; double eps = std::max(Precision::Confusion(), 1e-9); if (umax - umin < eps) { umin -= 1.0; umax += 1.0; } if (vmax - vmin < eps) { vmin -= 1.0; vmax += 1.0; } return BRepBuilderAPI_MakeFace(pln, umin, umax, vmin, vmax).Face(); } TopoDS_Shape CrossSection (const TopoDS_Shape& shape, const gp_Ax3& axes) { gp_Pln pln(axes); TopoDS_Face planeFace = MakePlaneFaceCoveringShape(shape, axes); auto bb = GetBoundingBox(shape); auto diam = bb.Diam(); // Heal / unify the input // - especially if shape comes from STEP/IGES ShapeFix_Shape fix(shape); fix.Perform(); TopoDS_Shape fixed = fix.Shape(); BRepAlgoAPI_Splitter splitter; splitter.SetNonDestructive(true); splitter.SetFuzzyValue(1e-7 * diam); TopTools_ListOfShape args; args.Append(shape); TopTools_ListOfShape tools; tools.Append(planeFace); splitter.SetArguments(args); splitter.SetTools(tools); splitter.Build(); if (!splitter.IsDone()) return TopoDS_Shape(); // for each input face/edge propagate properties to generated sub-shapes for (auto typ : {TopAbs_FACE, TopAbs_EDGE}) for (TopExp_Explorer e(shape, typ); e.More(); e.Next()) { if (!OCCGeometry::HaveProperties(e.Current())) continue; auto prop = OCCGeometry::GetProperties(e.Current()); for (auto mods : splitter.Generated(e.Current())) OCCGeometry::GetProperties(mods).Merge(prop); } // for each input solid, find the cut faces and propagate properties for (auto solid : GetSolids(shape)) { if (!OCCGeometry::HaveProperties(solid)) continue; auto prop = OCCGeometry::GetProperties(solid); for (auto mods : splitter.Modified(solid)) { if (mods.ShapeType() != TopAbs_SOLID) continue; for (TopExp_Explorer ef(mods, TopAbs_FACE); ef.More(); ef.Next()) OCCGeometry::GetProperties(ef.Current()).Merge(prop); } } TopoDS_Shape res = splitter.Shape(); const gp_Ax1 ax = axes.Axis(); const gp_Dir n = ax.Direction(); const gp_Pnt p0 = axes.Location(); Array out_shapes; for (auto f : GetFaces(res)) { Handle(Geom_Surface) s = BRep_Tool::Surface(TopoDS::Face(f)); Handle(Geom_Plane) gp = Handle(Geom_Plane)::DownCast(s); if (gp.IsNull()) continue; // Check coplanarity (orientation can flip) gp_Pln fpln = gp->Pln(); auto my_n = fpln.Position().Axis().Direction(); if (!my_n.IsParallel(n, 1e-10)) continue; // Check distance of face plane to our plane Standard_Real dist = fpln.Distance(p0); if (dist > 1e-7 * diam) continue; if (my_n.Dot(n) > 0) f.Reverse(); out_shapes.Append(f); } BRepBuilderAPI_Sewing sew(1e-7 * diam); for (auto s : out_shapes) sew.Add(TopoDS::Face(s)); sew.Perform(); for (auto s : out_shapes) PropagateProperties(sew, s); auto out = sew.SewedShape(); gp_Ax3 xy(gp::XOY()); gp_Trsf T; T.SetTransformation(axes, xy); BRepBuilderAPI_Transform btransf(out, T, Standard_True); PropagateProperties(btransf, out); return btransf.Shape(); } } // namespace netgen ================================================ FILE: libsrc/occ/occ_edge.cpp ================================================ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" #include #include #include #pragma clang diagnostic pop #include "occ_edge.hpp" #include "occgeom.hpp" namespace netgen { OCCEdge::OCCEdge(TopoDS_Shape edge_, GeometryVertex & start_, GeometryVertex & end_) : GeometryEdge(start_, end_), edge(TopoDS::Edge(edge_)) { curve = BRep_Tool::Curve(edge, s0, s1); BRepGProp::LinearProperties(edge, props); auto verts = GetVertices(edge); if(verts.size() != 2) throw Exception("OCC edge does not have 2 vertices"); if(start != end) { // swap start/end if necessary double d00 = Dist(GetPoint(0), start->GetPoint()); double d01 = Dist(GetPoint(0), end->GetPoint()); if(d01 < d00) swap(start, end); } } double OCCEdge::GetLength() const { return props.Mass(); } Point<3> OCCEdge::GetCenter() const { return occ2ng( props.CentreOfMass() ); } Point<3> OCCEdge::GetPoint(double t) const { return occ2ng( curve->Value(s0+t*(s1-s0)) ); } double OCCEdge::CalcStep(double t, double sag) const { throw Exception(ToString("not implemented") + __FILE__ + ":" + ToString(__LINE__)); } void OCCEdge::ProjectPoint(Point<3>& p, EdgePointGeomInfo* gi) const { auto pnt = ng2occ(p); // extend the projection parameter range, else projection might fail // for an endpoint // see discussion here: https://forum.ngsolve.org/t/how-to-apply-occidentification-correctly/2555 // I do not see a better way using occ tolerances? double eps = 1e-7 * (s1-s0); GeomAPI_ProjectPointOnCurve proj(pnt, curve, s0-eps, s1+eps); pnt = proj.NearestPoint(); if(gi) gi->dist = (proj.LowerDistanceParameter() - s0)/(s1-s0); p = occ2ng(pnt); } Vec<3> OCCEdge::GetTangent(double t) const { t = s0 + t*(s1-s0); gp_Pnt p; gp_Vec v; curve->D1(t, p, v); return occ2ng(v) * (s1-s0); } } ================================================ FILE: libsrc/occ/occ_edge.hpp ================================================ #ifndef FILE_OCC_EDGE_INCLUDED #define FILE_OCC_EDGE_INCLUDED // #pragma clang diagnostic push // #pragma clang diagnostic ignored "-Wdeprecated-declarations" #include #include #include #include #include #include // #pragma clang diagnostic pop #include "occ_vertex.hpp" #include "meshing.hpp" namespace netgen { class OCCEdge : public GeometryEdge { public: TopoDS_Edge edge; Handle(Geom_Curve) curve; double s0, s1; GProp_GProps props; public: OCCEdge(TopoDS_Shape edge_, GeometryVertex & start_, GeometryVertex & end_); auto Shape() const { return edge; } double GetLength() const override; Point<3> GetCenter() const override; Point<3> GetPoint(double t) const override; double CalcStep(double t, double sag) const override; void ProjectPoint(Point<3>& p, EdgePointGeomInfo* gi) const override; Vec<3> GetTangent(double t) const override; bool IsDegenerated(double) const override { return BRep_Tool::Degenerated(edge); } }; } #endif // FILE_OCCEDGE_INCLUDED ================================================ FILE: libsrc/occ/occ_face.cpp ================================================ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" #include #include #include #include #pragma clang diagnostic pop #include "occ_edge.hpp" #include "occ_face.hpp" #include "occgeom.hpp" namespace netgen { OCCFace::OCCFace(TopoDS_Shape dshape) : face(TopoDS::Face(dshape)) { BRepGProp::SurfaceProperties (dshape, props); bbox = ::netgen::GetBoundingBox(face); surface = BRep_Tool::Surface(face); shape_analysis = new ShapeAnalysis_Surface( surface ); tolerance = BRep_Tool::Tolerance( face ); } size_t OCCFace::GetNBoundaries() const { return 0; } Point<3> OCCFace::GetCenter() const { return occ2ng( props.CentreOfMass() ); } Array OCCFace::GetBoundary(const Mesh& mesh) const { auto & geom = dynamic_cast(*mesh.GetGeometry()); auto n_edges = geom.GetNEdges(); constexpr int UNUSED = 0; constexpr int FORWARD = 1; constexpr int REVERSED = 2; constexpr int BOTH = 3; Array edge_orientation(n_edges); edge_orientation = UNUSED; Array curve_on_face[BOTH]; curve_on_face[FORWARD].SetSize(n_edges); curve_on_face[REVERSED].SetSize(n_edges); Array edge_on_face[BOTH]; edge_on_face[FORWARD].SetSize(n_edges); edge_on_face[REVERSED].SetSize(n_edges); // In case the face is INTERNAL, we need to orient it to FORWARD to get proper orientation for the edges // (relative to the face) otherwise, all edges are also INTERNAL auto oriented_face = TopoDS_Face(face); if(oriented_face.Orientation() == TopAbs_INTERNAL) oriented_face.Orientation(TopAbs_FORWARD); for(auto edge_ : GetEdges(oriented_face)) { auto edge = TopoDS::Edge(edge_); auto edgenr = geom.GetEdge(edge).nr; auto & orientation = edge_orientation[edgenr]; double s0, s1; auto cof = BRep_Tool::CurveOnSurface (edge, oriented_face, s0, s1); if(edge.Orientation() == TopAbs_FORWARD || edge.Orientation() == TopAbs_INTERNAL) { curve_on_face[FORWARD][edgenr] = cof; orientation += FORWARD; edge_on_face[FORWARD][edgenr] = edge; } if(edge.Orientation() == TopAbs_REVERSED) { curve_on_face[REVERSED][edgenr] = cof; orientation += REVERSED; edge_on_face[REVERSED][edgenr] = edge; } if(edge.Orientation() == TopAbs_INTERNAL) { // add reversed edge auto r_edge = TopoDS::Edge(edge.Reversed()); auto cof = BRep_Tool::CurveOnSurface (r_edge, oriented_face, s0, s1); curve_on_face[REVERSED][edgenr] = cof; orientation += REVERSED; edge_on_face[REVERSED][edgenr] = r_edge; } if(orientation > BOTH) throw Exception("have edge more than twice in face " + ToString(nr) + " " + properties.GetName() + ", orientation: " + ToString(orientation)); } Array boundary; for (auto seg : mesh.LineSegments()) { auto edgenr = seg.epgeominfo[0].edgenr; auto orientation = edge_orientation[edgenr]; if(orientation == UNUSED) continue; for(const auto ORIENTATION : {FORWARD, REVERSED}) { if((orientation & ORIENTATION) == 0) continue; // auto cof = curve_on_face[ORIENTATION][edgenr]; auto edge = edge_on_face[ORIENTATION][edgenr]; double s0, s1; auto cof = BRep_Tool::CurveOnSurface (edge, face, s0, s1); double s[2] = { seg.epgeominfo[0].dist, seg.epgeominfo[1].dist }; // dist is in [0,1], map parametrization to [s0, s1] s[0] = s0 + s[0]*(s1-s0); s[1] = s0 + s[1]*(s1-s0); // fixes normal-vector roundoff problem when endpoint is cone-tip double delta = s[1]-s[0]; s[0] += 1e-10*delta; s[1] -= 1e-10*delta; for(auto i : Range(2)) { // take uv from CurveOnSurface as start value but project again for better accuracy // (cof->Value yields wrong values (outside of surface) for complicated faces auto uv = cof->Value(s[i]); PointGeomInfo gi; gi.u = uv.X(); gi.v = uv.Y(); Point<3> pproject = mesh[seg[i]]; ProjectPointGI(pproject, gi); seg.epgeominfo[i].u = gi.u; seg.epgeominfo[i].v = gi.v; } bool do_swap = ORIENTATION == REVERSED; if(seg.epgeominfo[1].dist < seg.epgeominfo[0].dist) do_swap = !do_swap; if(do_swap) { 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); } boundary.Append(seg); } } return boundary; } PointGeomInfo OCCFace::Project(Point<3>& p) const { auto suval = shape_analysis->ValueOfUV(ng2occ(p), tolerance); double u,v; suval.Coord(u, v); p = occ2ng(surface->Value( u, v )); PointGeomInfo gi; gi.trignum = nr+1; gi.u = u; gi.v = v; return gi; } bool OCCFace::ProjectPointGI(Point<3>& p_, PointGeomInfo& gi) const { /* static Timer t("OCCFace::ProjectPointGI"); RegionTimer rt(t); // *testout << "input, uv = " << gi.u << ", " << gi.v << endl; auto suval = shape_analysis->NextValueOfUV({gi.u, gi.v}, ng2occ(p_), tolerance); gi.trignum = nr+1; suval.Coord(gi.u, gi.v); // *testout << "result, uv = " << gi.u << ", " << gi.v << endl; p_ = occ2ng(surface->Value( gi.u, gi.v )); return true; */ // Old code: do newton iterations manually double u = gi.u; double v = gi.v; auto p = ng2occ(p_); auto 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; p_ = occ2ng(x); gi.u = u; gi.v = v; return true; } Point<3> OCCFace::GetPoint(const PointGeomInfo& gi) const { return occ2ng(surface->Value( gi.u, gi.v )); } void OCCFace::CalcEdgePointGI(const GeometryEdge& edge, double t, EdgePointGeomInfo& egi) const { throw Exception(ToString("not implemented") + __FILE__ + ":" + ToString(__LINE__)); } Box<3> OCCFace::GetBoundingBox() const { return bbox; } double OCCFace::GetCurvature(const PointGeomInfo& gi) const { BRepAdaptor_Surface sf(face, Standard_True); BRepLProp_SLProps prop2(sf, 2, 1e-5); prop2.SetParameters (gi.u, gi.v); return max(fabs(prop2.MinCurvature()), fabs(prop2.MaxCurvature())); } void OCCFace::RestrictH(Mesh& mesh, const MeshingParameters& mparam) const { throw Exception(ToString("not implemented") + __FILE__ + ":" + ToString(__LINE__)); } Vec<3> OCCFace::GetNormal(const Point<3>& p, const PointGeomInfo* gi) const { PointGeomInfo gi_; if(gi==nullptr) { auto p_ = p; gi_ = Project(p_); gi = &gi_; } gp_Pnt pnt; gp_Vec du, dv; surface->D1(gi->u,gi->v,pnt,du,dv); auto n = Cross (occ2ng(du), occ2ng(dv)); n.Normalize(); if (face.Orientation() == TopAbs_REVERSED) n *= -1; return n; } } ================================================ FILE: libsrc/occ/occ_face.hpp ================================================ #ifndef FILE_OCC_FACE_INCLUDED #define FILE_OCC_FACE_INCLUDED // #pragma clang diagnostic push // #pragma clang diagnostic ignored "-Wdeprecated-declarations" #include #include #include #include // #pragma clang diagnostic pop #include "occ_vertex.hpp" #include "meshing.hpp" namespace netgen { class OCCFace : public GeometryFace { TopoDS_Face face; GProp_GProps props; Box<3> bbox; Handle( Geom_Surface ) surface; Handle( ShapeAnalysis_Surface ) shape_analysis; double tolerance; public: OCCFace(TopoDS_Shape dshape); const TopoDS_Face Shape() const { return face; } Point<3> GetCenter() const override; virtual size_t GetNBoundaries() const override; virtual Array GetBoundary(const Mesh& mesh) const override; virtual PointGeomInfo Project(Point<3>& p) const override; virtual bool ProjectPointGI(Point<3>& p, PointGeomInfo& gi) const override; virtual Point<3> GetPoint(const PointGeomInfo& gi) const override; virtual void CalcEdgePointGI(const GeometryEdge& edge, double t, EdgePointGeomInfo& egi) const override; virtual Box<3> GetBoundingBox() const override; virtual double GetCurvature(const PointGeomInfo& gi) const override; virtual void RestrictH(Mesh& mesh, const MeshingParameters& mparam) const override; virtual Vec<3> GetNormal(const Point<3>& p, const PointGeomInfo* gi = nullptr) const override; }; } #endif // FILE_OCC_FACE_INCLUDED ================================================ FILE: libsrc/occ/occ_solid.hpp ================================================ #ifndef FILE_OCC_SOLID_INCLUDED #define FILE_OCC_SOLID_INCLUDED #include #include #include "meshing.hpp" namespace netgen { class OCCSolid : public GeometrySolid { TopoDS_Solid solid; public: OCCSolid(TopoDS_Shape dshape) : solid(TopoDS::Solid(dshape)) { } TopoDS_Solid& GetShape() { return solid; } }; } #endif // FILE_OCC_SOLID_INCLUDED ================================================ FILE: libsrc/occ/occ_utils.cpp ================================================ #include #include #include #include #include #include "occ_utils.hpp" #include "occgeom.hpp" namespace netgen { Point<3> occ2ng (const TopoDS_Shape& shape) { if(shape.ShapeType() != TopAbs_VERTEX) throw Exception("Try to convert non vertex to point!"); return occ2ng( BRep_Tool::Pnt(TopoDS::Vertex(shape)) ); } Transformation<3> occ2ng (const gp_Trsf & occ_trafo) { Transformation<3> trafo; auto v = occ_trafo.TranslationPart(); auto m = occ_trafo.VectorialPart(); auto & tv = trafo.GetVector(); auto & tm = trafo.GetMatrix(); for(auto i : Range(3)) { tv[i] = v.Coord(i+1); for(auto k : Range(3)) tm(i,k) = m(i+1,k+1); } return trafo; } Transformation<3> occ2ng (const gp_GTrsf & occ_trafo) { Transformation<3> trafo; auto v = occ_trafo.TranslationPart(); auto m = occ_trafo.VectorialPart(); auto & tv = trafo.GetVector(); auto & tm = trafo.GetMatrix(); for(auto i : Range(3)) { tv[i] = v.Coord(i+1); for(auto k : Range(3)) tm(i,k) = m(i+1,k+1); } return trafo; } Box<3> GetBoundingBox( const TopoDS_Shape & shape ) { Bnd_Box bb; #if OCC_VERSION_HEX < 0x070000 BRepBndLib::Add (shape, bb); #else BRepBndLib::Add (shape, bb, true); #endif return {occ2ng(bb.CornerMin()), occ2ng(bb.CornerMax())}; } Standard_Integer BuildTriangulation( const TopoDS_Shape & shape ) { BRepTools::Clean (shape); // double deflection = 0.01; // https://dev.opencascade.org/doc/overview/html/occt_user_guides__mesh.html // from Standard_Boolean meshing_imeshtools_parameters() IMeshTools_Parameters aMeshParams; aMeshParams.Deflection = 0.01; aMeshParams.Angle = 0.5; aMeshParams.Relative = Standard_True; aMeshParams.InParallel = Standard_True; aMeshParams.MinSize = Precision::Confusion(); aMeshParams.InternalVerticesMode = Standard_True; aMeshParams.ControlSurfaceDeflection = Standard_True; BRepMesh_IncrementalMesh aMesher (shape, aMeshParams); return aMesher.GetStatusFlags(); } } ================================================ FILE: libsrc/occ/occ_utils.hpp ================================================ #ifndef FILE_OCC_UTILS_INCLUDED #define FILE_OCC_UTILS_INCLUDED #include // #pragma clang diagnostic push // #pragma clang diagnostic ignored "-Wdeprecated-declarations" #include #include #include #include #include #include #include #include #include #include #define NETGEN_OCC_VERSION_AT_LEAST(MAJOR, MINOR) \ ((OCC_VERSION_MAJOR > MAJOR) || \ ((OCC_VERSION_MAJOR == MAJOR) && (OCC_VERSION_MINOR >= MINOR))) #define NETGEN_OCC_VERSION_AT_LEAST_MAJOR(MAJOR) \ (NETGEN_OCC_VERSION_AT_LEAST(MAJOR, 0)) // #pragma clang diagnostic pop #include "meshing.hpp" #if NETGEN_OCC_VERSION_AT_LEAST(7, 4) #define OCC_HAVE_DUMP_JSON #endif namespace netgen { inline Point<3> occ2ng (const gp_Pnt & p) { return Point<3> (p.X(), p.Y(), p.Z()); } inline Point<2> occ2ng (const gp_Pnt2d & p) { return Point<2> (p.X(), p.Y()); } inline Vec<3> occ2ng (const gp_Vec & v) { return Vec<3> (v.X(), v.Y(), v.Z()); } DLL_HEADER Point<3> occ2ng (const TopoDS_Shape & s); inline Point<3> occ2ng (const TopoDS_Vertex & v) { return occ2ng (BRep_Tool::Pnt (v)); } DLL_HEADER Transformation<3> occ2ng (const gp_Trsf & t); DLL_HEADER Transformation<3> occ2ng (const gp_GTrsf & t); inline Transformation<3> occ2ng (const variant & t) { if(auto t1 = get_if(&t)) return occ2ng(*t1); return occ2ng(get(t)); } inline gp_Pnt ng2occ (const Point<3> & p) { return gp_Pnt(p(0), p(1), p(2)); } inline void CheckValidPropertyType(const TopoDS_Shape & shape) { switch (shape.ShapeType()) { case TopAbs_SOLID: case TopAbs_FACE: case TopAbs_EDGE: case TopAbs_VERTEX: break; default: throw Exception("Cannot query properties of compound shapes - setting properties sets property on all highest dimension subshape type"); } } DLL_HEADER Box<3> GetBoundingBox( const TopoDS_Shape & shape ); struct OCCIdentification { TopoDS_Shape from; TopoDS_Shape to; optional> trafo = nullopt; string name; Identifications::ID_TYPE type; bool opposite_direction = false; }; Standard_Integer BuildTriangulation( const TopoDS_Shape & shape ); class MyExplorer { class Iterator { TopExp_Explorer exp; public: Iterator (TopoDS_Shape ashape, TopAbs_ShapeEnum atoFind, TopAbs_ShapeEnum atoAvoid) : exp(ashape, atoFind, atoAvoid) { } auto operator*() { return exp.Current(); } Iterator & operator++() { exp.Next(); return *this; } bool operator!= (nullptr_t nu) { return exp.More(); } }; public: TopoDS_Shape shape; TopAbs_ShapeEnum toFind; TopAbs_ShapeEnum toAvoid; MyExplorer (TopoDS_Shape ashape, TopAbs_ShapeEnum atoFind, TopAbs_ShapeEnum atoAvoid = TopAbs_SHAPE) : shape(ashape), toFind(atoFind), toAvoid(atoAvoid) { ; } Iterator begin() { return Iterator(shape, toFind, toAvoid); } auto end() { return nullptr; } }; inline auto Explore (TopoDS_Shape shape, TopAbs_ShapeEnum toFind, TopAbs_ShapeEnum toAvoid = TopAbs_SHAPE) { return MyExplorer (shape, toFind, toAvoid); } class IndexMapIterator { class Iterator { const TopTools_IndexedMapOfShape & indmap; int i; public: Iterator (const TopTools_IndexedMapOfShape & aindmap, int ai) : indmap(aindmap), i(ai) { ; } auto operator*() { return tuple(i, indmap(i)); } Iterator & operator++() { i++; return *this; } bool operator!= (const Iterator & i2) { return i != i2.i; } }; public: const TopTools_IndexedMapOfShape & indmap; IndexMapIterator (const TopTools_IndexedMapOfShape & aindmap) : indmap(aindmap) { } Iterator begin() { return Iterator(indmap, 1); } Iterator end() { return Iterator(indmap, indmap.Extent()+1); } }; inline auto Enumerate (const TopTools_IndexedMapOfShape & indmap) { return IndexMapIterator(indmap); } class ListOfShapes : public std::vector { public: DLL_HEADER TopoDS_Shape Max(gp_Vec dir); DLL_HEADER TopoDS_Shape Nearest(gp_Pnt pnt); DLL_HEADER ListOfShapes SubShapes(TopAbs_ShapeEnum type) const; ListOfShapes Solids() const { return SubShapes(TopAbs_SOLID); } ListOfShapes Shells() const { return SubShapes(TopAbs_SHELL); } ListOfShapes Faces() const { return SubShapes(TopAbs_FACE); } ListOfShapes Wires() const { return SubShapes(TopAbs_WIRE); } ListOfShapes Edges() const { return SubShapes(TopAbs_EDGE); } ListOfShapes Vertices() const { return SubShapes(TopAbs_VERTEX); } ListOfShapes operator*(const ListOfShapes& other) const { ListOfShapes common; for(const auto& shape : (*this)) for(const auto& shape_o : other) if(shape.IsSame(shape_o)) common.push_back(shape); return common; } ListOfShapes GetHighestDimShapes() const { for (auto type : {TopAbs_SOLID, TopAbs_FACE, TopAbs_EDGE, TopAbs_VERTEX}) { auto ret = SubShapes(type); if (ret.size() > 0) return ret; } return ListOfShapes(); } }; inline ListOfShapes GetSolids(const TopoDS_Shape & shape) { ListOfShapes sub; for (TopExp_Explorer e(shape, TopAbs_SOLID); e.More(); e.Next()) sub.push_back(e.Current()); return sub; } inline ListOfShapes GetShells(const TopoDS_Shape & shape) { ListOfShapes sub; for (TopExp_Explorer e(shape, TopAbs_SHELL); e.More(); e.Next()) sub.push_back(e.Current()); return sub; } inline ListOfShapes GetFaces(const TopoDS_Shape & shape) { ListOfShapes sub; for (TopExp_Explorer e(shape, TopAbs_FACE); e.More(); e.Next()) sub.push_back(e.Current()); return sub; } inline ListOfShapes GetWires(const TopoDS_Shape & shape) { ListOfShapes sub; for (TopExp_Explorer e(shape, TopAbs_WIRE); e.More(); e.Next()) sub.push_back(e.Current()); return sub; } inline ListOfShapes GetEdges(const TopoDS_Shape & shape) { ListOfShapes sub; for (TopExp_Explorer e(shape, TopAbs_EDGE); e.More(); e.Next()) sub.push_back(e.Current()); return sub; } inline ListOfShapes GetVertices(const TopoDS_Shape & shape) { ListOfShapes sub; for (TopExp_Explorer e(shape, TopAbs_VERTEX); e.More(); e.Next()) sub.push_back(e.Current()); return sub; } inline ListOfShapes GetHighestDimShapes(const TopoDS_Shape & shape) { auto ret = GetSolids(shape); if(ret.size() > 0) return ret; ret = GetFaces(shape); if(ret.size() > 0) return ret; ret = GetEdges(shape); if(ret.size() > 0) return ret; ret = GetVertices(shape); if(ret.size() > 0) return ret; return ListOfShapes(); } class DirectionalInterval { public: gp_Vec dir; double minval = -1e99; double maxval = 1e99; bool openmin = false, openmax = false; DirectionalInterval (gp_Vec adir) : dir(adir) { ; } DirectionalInterval (const DirectionalInterval & i2) = default; DirectionalInterval operator< (double val) const { DirectionalInterval i2 = *this; i2.maxval = val; i2.openmax = true; return i2; } DirectionalInterval operator> (double val) const { DirectionalInterval i2 = *this; i2.minval = val; i2.openmin = true; return i2; } DirectionalInterval operator<= (double val) const { DirectionalInterval i2 = *this; i2.maxval = val; i2.openmax = false; return i2; } DirectionalInterval operator>= (double val) const { DirectionalInterval i2 = *this; i2.minval = val; i2.openmin = false; return i2; } DirectionalInterval Intersect (const DirectionalInterval & i2) { DirectionalInterval res = *this; res.minval = max(res.minval, i2.minval); res.maxval = min(res.maxval, i2.maxval); return res; } bool Contains (gp_Pnt p, double eps = 1e-8) { // cout << "Contains point " << p.X() << "," << p.Y() << "," << p.Z() << " ? " << endl; double val = dir.X()*p.X() + dir.Y()*p.Y() + dir.Z() * p.Z(); // cout << "minval = " << minval << ", val = " << val << " maxval = " << maxval << endl; if (openmin) { if (val < minval+eps) return false; } else { if (val < minval-eps) return false; } if (openmax) { if (val > maxval-eps) return false; } else { if (val > maxval+eps) return false; } return true; } }; inline auto Properties (TopoDS_Shape shape) { GProp_GProps props; double tol; switch (shape.ShapeType()) { case TopAbs_SOLID: case TopAbs_COMPOUND: case TopAbs_COMPSOLID: tol = 1e-2 * BRep_Tool::MaxTolerance(shape, TopAbs_FACE); BRepGProp::VolumeProperties (shape, props, tol); break; case TopAbs_FACE: case TopAbs_SHELL: tol = 1e-2 * BRep_Tool::MaxTolerance(shape, TopAbs_FACE); BRepGProp::SurfaceProperties (shape, props, tol); break; case TopAbs_WIRE: case TopAbs_EDGE: tol = 1e-2 * BRep_Tool::MaxTolerance(shape, TopAbs_EDGE); BRepGProp::LinearProperties(shape, props, tol); break; default: BRepGProp::LinearProperties(shape, props); } return props; } inline gp_Pnt Center (TopoDS_Shape shape) { return Properties(shape).CentreOfMass(); } inline double Mass (TopoDS_Shape shape) { return Properties(shape).Mass(); } } #endif // FILE_OCC_UTILS_INCLUDED ================================================ FILE: libsrc/occ/occ_vertex.cpp ================================================ #include #include #include "occ_vertex.hpp" namespace netgen { OCCVertex::OCCVertex( TopoDS_Shape s ) : vertex(TopoDS::Vertex(s)) { p = occ2ng(vertex); } Point<3> OCCVertex::GetPoint() const { return p; } } ================================================ FILE: libsrc/occ/occ_vertex.hpp ================================================ #ifndef FILE_OCC_VERTEX_INCLUDED #define FILE_OCC_VERTEX_INCLUDED // #pragma clang diagnostic push // #pragma clang diagnostic ignored "-Wdeprecated-declarations" #include #include // #pragma clang diagnostic pop #include "meshing.hpp" #include "occ_utils.hpp" namespace netgen { class OCCVertex : public GeometryVertex { TopoDS_Vertex vertex; Point<3> p; public: OCCVertex( ) = default; OCCVertex( TopoDS_Shape s ); ~OCCVertex() {} Point<3> GetPoint() const override; }; } #endif // FILE_OCC_VERTEX_INCLUDED ================================================ FILE: libsrc/occ/occconstruction.cpp ================================================ #ifdef OCCGEOMETRY #include #include #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 #include #include #include // #include #include #include #include #include #include #include //#include #include #include 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 ================================================ FILE: libsrc/occ/occgenmesh.cpp ================================================ #ifdef OCCGEOMETRY #include #include #include "occgeom.hpp" #include "occ_face.hpp" #include "occmeshsurf.hpp" #include #include #include #include #include #include #include #include #include #include #include namespace netgen { #define TCL_OK 0 #define TCL_ERROR 1 #define DIVIDEEDGESECTIONS 10000 // better solution to come soon #define IGNORECURVELENGTH 0 #define VSMALL 1e-10 DLL_HEADER bool merge_solids = false; // 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 ComputeH (double kappa, const MeshingParameters & mparam) { kappa *= mparam.curvaturesafety; /* double hret; if (mparam.maxh * kappa < 1) hret = mparam.maxh; else hret = 1 / (kappa + VSMALL); if (mparam.maxh < hret) hret = mparam.maxh; return hret; */ // return min(mparam.maxh, 1/kappa); return (mparam.maxh*kappa < 1) ? mparam.maxh : 1/kappa; } void RestrictHTriangle (gp_Pnt2d & par0, gp_Pnt2d & par1, gp_Pnt2d & par2, BRepLProp_SLProps * prop, BRepLProp_SLProps * prop2, Mesh & mesh, int depth, double h, int layer, const MeshingParameters & mparam) { 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; prop2->SetParameters (parmid.X(), parmid.Y()); if (!prop2->IsCurvatureDefined()) { (*testout) << "curvature not defined!" << endl; return; } curvature = max(fabs(prop2->MinCurvature()), fabs(prop2->MaxCurvature())); prop2->SetParameters (par0.X(), par0.Y()); if (!prop2->IsCurvatureDefined()) { (*testout) << "curvature not defined!" << endl; return; } curvature = max(curvature,max(fabs(prop2->MinCurvature()), fabs(prop2->MaxCurvature()))); prop2->SetParameters (par1.X(), par1.Y()); if (!prop2->IsCurvatureDefined()) { (*testout) << "curvature not defined!" << endl; return; } curvature = max(curvature,max(fabs(prop2->MinCurvature()), fabs(prop2->MaxCurvature()))); prop2->SetParameters (par2.X(), par2.Y()); if (!prop2->IsCurvatureDefined()) { (*testout) << "curvature not defined!" << endl; return; } curvature = max(curvature,max(fabs(prop2->MinCurvature()), fabs(prop2->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, mparam); 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, prop2, mesh, depth+1, h, layer, mparam); RestrictHTriangle(pm, par0, par1, prop, prop2, mesh, depth+1, h, layer, mparam); } 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, prop2, mesh, depth+1, h, layer, mparam); RestrictHTriangle(pm, par0, par1, prop, prop2, mesh, depth+1, h, layer, mparam); } 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, prop2, mesh, depth+1, h, layer, mparam); RestrictHTriangle(pm, par2, par0, prop, prop2, mesh, depth+1, h, layer, mparam); } } 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, layer); p3d = Point3d(pnt0.X(), pnt0.Y(), pnt0.Z()); mesh.RestrictLocalH (p3d, h, layer); p3d = Point3d(pnt1.X(), pnt1.Y(), pnt1.Z()); mesh.RestrictLocalH (p3d, h, layer); p3d = Point3d(pnt2.X(), pnt2.Y(), pnt2.Z()); mesh.RestrictLocalH (p3d, h, layer); //(*testout) << "p = " << p3d << ", h = " << h << ", maxside = " << maxside << endl; } } bool OCCMeshFace (const OCCGeometry & geom, Mesh & mesh, FlatArray glob2loc, const MeshingParameters & mparam, int nr, int projecttype, bool delete_on_failure) { auto k = nr+1; if(1==0 && !geom.fvispar[k-1].IsDrawable()) { (*testout) << "ignoring face " << k << endl; cout << "ignoring face " << k << endl; return true; } // if(master_faces[k]!=k) // continue; (*testout) << "mesh face " << k << endl; multithread.percent = 100 * k / (mesh.GetNFD() + VSMALL); geom.facemeshstatus[k-1] = -1; // FaceDescriptor & fd = mesh.GetFaceDescriptor(k); auto face = TopoDS::Face(geom.fmap(k)); const auto& occface = dynamic_cast(geom.GetFace(k-1)); int oldnf = mesh.GetNSE(); Box<3> bb = geom.GetBoundingBox(); // int projecttype = PLANESPACE; // int projecttype = PARAMETERSPACE; static Timer tinit("init"); tinit.Start(); Meshing2OCCSurfaces meshing(geom, face, bb, projecttype, mparam); tinit.Stop(); static Timer tprint("print"); tprint.Start(); if (meshing.GetProjectionType() == PLANESPACE) PrintMessage (2, "Face ", k, " / ", geom.GetNFaces(), " (plane space projection)"); else PrintMessage (2, "Face ", k, " / ", geom.GetNFaces(), " (parameter space projection)"); tprint.Stop(); // Meshing2OCCSurfaces meshing(f2, bb); // meshing.SetStartTime (starttime); //(*testout) << "Face " << k << endl << endl; auto segments = geom.GetFace(k-1).GetBoundary(mesh); if (meshing.GetProjectionType() == PLANESPACE) { static Timer t("MeshSurface: Find edges and points - Physical"); RegionTimer r(t); int cntp = 0; glob2loc = 0; for (Segment & seg : segments) // if (seg.si == k) for (int j = 0; j < 2; j++) { PointIndex pi = seg[j]; if (glob2loc[pi] == 0) { meshing.AddPoint (mesh.Point(pi), pi); cntp++; glob2loc[pi] = cntp; } } for(const auto& vert : geom.GetFaceVertices(geom.GetFace(k-1))) { PointIndex pi = vert->nr + IndexBASE(); if(glob2loc[pi] == 0) { auto gi = occface.Project(mesh[pi]); MultiPointGeomInfo mgi; mgi.AddPointGeomInfo(gi); meshing.AddPoint(mesh[pi], pi, &mgi); cntp++; glob2loc[pi] = cntp; } } /* for (int i = 1; i <= mesh.GetNSeg(); i++) { Segment & seg = mesh.LineSegment(i); */ // for (Segment & seg : mesh.LineSegments()) for (Segment & seg : segments) //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; //if(orientation & 1) meshing.AddBoundaryElement (glob2loc[seg[0]], glob2loc[seg[1]], gi0, gi1); } } else { static Timer t("MeshSurface: Find edges and points - Parameter"); RegionTimer r(t); Array gis(2*segments.Size()); gis.SetSize (0); glob2loc = 0; // int cntpt = 0; Box<2> uv_box(Box<2>::EMPTY_BOX); for(auto & seg : segments) for(auto i : Range(2)) uv_box.Add( {seg.epgeominfo[i].u, seg.epgeominfo[i].v } ); BoxTree<2> uv_tree(uv_box); double tol = 1e99; for(auto& seg : segments) { Point<2> p1 = { seg.epgeominfo[0].u, seg.epgeominfo[0].v }; Point<2> p2 = { seg.epgeominfo[1].u, seg.epgeominfo[1].v }; tol = min2(tol, Dist(p1, p2)); } uv_tree.SetTolerance(0.9 * tol); Array found_points; for(auto & seg : segments) { PointGeomInfo gi[2]; gi[0].trignum = gi[1].trignum = k; gi[0].u = seg.epgeominfo[0].u; gi[0].v = seg.epgeominfo[0].v; gi[1].u = seg.epgeominfo[1].u; gi[1].v = seg.epgeominfo[1].v; int locpnum[2] = {0, 0}; for (int j = 0; j < 2; j++) { Point<2> uv = {gi[j].u, gi[j].v}; uv_tree.GetIntersecting(uv, uv, found_points); bool found = false; for(auto& fp : found_points) { if(meshing.GetGlobalIndex(fp - 1) == seg[j]) { locpnum[j] = fp; found = true; } } if(!found) { PointIndex pi = seg[j]; locpnum[j] = meshing.AddPoint (mesh.Point(pi), pi) + 1; glob2loc[pi] = locpnum[j]; gis.Append (gi[j]); uv_tree.Insert(uv, locpnum[j]); } } meshing.AddBoundaryElement (locpnum[0], locpnum[1], gi[0], gi[1]); } for(const auto& vert : geom.GetFaceVertices(geom.GetFace(k-1))) { PointIndex pi = vert->nr + IndexBASE(); if(glob2loc[pi] == 0) { auto gi = occface.Project(mesh[pi]); MultiPointGeomInfo mgi; mgi.AddPointGeomInfo(gi); glob2loc[pi] = meshing.AddPoint(mesh[pi], pi, &mgi) + 1; gis.Append(gi); Point<2> uv = { gi.u, gi.v }; uv_tree.Insert(uv, glob2loc[pi]); } } } // Philippose - 15/01/2009 auto& props = occface.properties; double maxh = min2(geom.face_maxh[k-1], props.maxh); //double maxh = mparam.maxh; // int noldpoints = mesh->GetNP(); int noldsurfel = mesh.GetNSE(); int layer = props.layer; static Timer tsurfprop("surfprop"); tsurfprop.Start(); GProp_GProps sprops; BRepGProp::SurfaceProperties(TopoDS::Face(geom.fmap(k)),sprops); tsurfprop.Stop(); meshing.SetMaxArea(2.*sprops.Mass()); MESHING2_RESULT res; // TODO: check overlap not correctly working here MeshingParameters mparam_without_overlap = mparam; mparam_without_overlap.checkoverlap = false; try { static Timer t("GenerateMesh"); RegionTimer reg(t); res = meshing.GenerateMesh (mesh, mparam_without_overlap, maxh, k, layer); } catch (SingularMatrixException) { // (*myerr) << "Singular Matrix" << endl; res = MESHING2_GIVEUP; } catch (UVBoundsException) { // (*myerr) << "UV bounds exceeded" << endl; res = MESHING2_GIVEUP; } static Timer t1("rest of loop"); RegionTimer reg1(t1); bool meshing_failed = res != MESHING2_OK; if(meshing_failed && delete_on_failure) { for (SurfaceElementIndex sei = noldsurfel; sei < mesh.GetNSE(); sei++) mesh.Delete(sei); mesh.Compress(); } for (SurfaceElementIndex sei = oldnf; sei < mesh.GetNSE(); sei++) mesh[sei].SetIndex (k); auto n_illegal_trigs = mesh.FindIllegalTrigs(); PrintMessage (3, n_illegal_trigs, " illegal triangles"); return meshing_failed; } void OCCSetLocalMeshSize(const OCCGeometry & geom, Mesh & mesh, const MeshingParameters & mparam, const OCCParameters& occparam) { static Timer t1("OCCSetLocalMeshSize"); RegionTimer regt(t1); mesh.SetGlobalH (mparam.maxh); mesh.SetMinimalH (mparam.minh); NgArray maxhdom; maxhdom.SetSize (geom.NrSolids()); maxhdom = mparam.maxh; int maxlayer = 1; for(auto dom : Range(geom.GetNSolids())) { auto & props = geom.GetSolid(dom).properties; maxhdom[dom] = min2(maxhdom[dom], props.maxh); maxlayer = max2(maxlayer, props.layer); } for(auto & f : geom.Faces()) maxlayer = max2(maxlayer, f->properties.layer); for(auto & e : geom.Edges()) maxlayer = max2(maxlayer, e->properties.layer); mesh.SetMaxHDomain (maxhdom); Box<3> bb = geom.GetBoundingBox(); bb.Increase (bb.Diam()/10); if (mparam.uselocalh) { const char * savetask = multithread.task; multithread.percent = 0; for(auto layer : Range(1, maxlayer+1)) mesh.SetLocalH (bb.PMin(), bb.PMax(), mparam.grading, layer); for(auto& v : geom.Vertices()) { auto& props = v->properties; if(props.maxh < 1e99) mesh.GetLocalH(props.layer)->SetH(v->GetPoint(), props.maxh); } int nedges = geom.emap.Extent(); double mincurvelength = IGNORECURVELENGTH; double maxedgelen = 0; double minedgelen = 1e99; if(occparam.resthminedgelenenable) { mincurvelength = occparam.resthminedgelen; if(mincurvelength < IGNORECURVELENGTH) mincurvelength = IGNORECURVELENGTH; } 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; double len = Mass(e); if (len < mincurvelength) { (*testout) << "ignored" << endl; continue; } bool is_identified_edge = false; // TODO: change to use hash value const auto& gedge = geom.GetEdge(e); auto& v0 = gedge.GetStartVertex(); auto& v1 = gedge.GetEndVertex(); for(auto & ident : v0.identifications) { auto other = ident.from == &v0 ? ident.to : ident.from; if(other->nr == v1.nr && ident.type == Identifications::CLOSESURFACES) { is_identified_edge = true; break; } } if(is_identified_edge) continue; double localh = len/mparam.segmentsperedge; double s0, s1; Handle(Geom_Curve) c = BRep_Tool::Curve(e, s0, s1); const auto & props = gedge.properties; localh = min2(localh, props.maxh); maxedgelen = max (maxedgelen, len); minedgelen = min (minedgelen, len); int maxj = max((int) ceil(len/localh)*2, 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, props.layer); } } 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); auto layer = geom.GetEdge(edge).properties.layer; for (int j = 1; j <= nsections; j++) { double s = s0 + j/(double) nsections * (s1-s0); prop.SetParameter (s); double curvature = 0; if(prop.IsTangentDefined()) 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), mparam), layer); } } multithread.task = "Setting local mesh size (face curvature)"; // setting face curvature int nfaces = geom.fmap.Extent(); BuildTriangulation(geom.shape); 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()) { if (geom.shape.Infinite()) throw Exception("Cannot generate mesh for an infinite geometry"); else throw Exception("OCC-Triangulation could not be built"); } BRepAdaptor_Surface sf(face, Standard_True); // one prop for evaluating and one for derivatives BRepLProp_SLProps prop(sf, 0, 1e-5); BRepLProp_SLProps prop2(sf, 2, 1e-5); auto layer = geom.GetFace(face).properties.layer; 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); // fix for OCC7.6.0-dev int n = triangulation->Triangle(j)(k); p[k-1] = triangulation->Node(n).Transformed(loc); par[k-1] = triangulation->UVNode(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, &prop2, mesh, 0, 0, layer, mparam); //cout << "\rFace " << i << " pos12 ntriangles " << ntriangles << flush; } } // setting close edges if (mparam.closeedgefac.has_value()) { multithread.task = "Setting local mesh size (close edges)"; int sections = 100; NgArray lines(sections*nedges); /* BoxTree<3> * searchtree = new BoxTree<3> (bb.PMin(), bb.PMax()); */ BoxTree<3> searchtree(bb.PMin(), bb.PMax()); int nlines = 0; Array edgenumber; for (int i = 1; i <= nedges && !multithread.terminate; i++) { TopoDS_Edge edge = TopoDS::Edge (geom.emap(i)); int layer = geom.GetEdge(edge).properties.layer; 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()); lines[nlines].layer = layer; Box3d box; box.SetPoint (Point3d(lines[nlines].p0)); box.AddPoint (Point3d(lines[nlines].p1)); searchtree.Insert (box.PMin(), box.PMax(), nlines+1); nlines++; edgenumber.Append(i); s_start = s; d0 = d1; } } } NgArray linenums; auto is_identified_edge = [&](int e0, int e1) { const auto& edge0 = geom.GetEdge(e0-1); const auto& edge1 = geom.GetEdge(e1-1); if(edge0.primary == edge1.primary) return true; Array v0 = { &edge0.GetStartVertex(), &edge0.GetEndVertex() }; Array v1 = { &edge1.GetStartVertex(), &edge1.GetEndVertex() }; for(auto i : Range(2)) for(auto j : Range(2)) if(v0[i]->primary == v1[j]->primary) return true; return false; }; 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(), line.layer), mesh.GetH(box.PMax(), line.layer)); 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.layer != lines[num].layer) continue; if( is_identified_edge(edgenumber[i], edgenumber[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 /= (*mparam.closeedgefac + VSMALL); if (mindist < 1e-3 * bb.Diam()) { (*testout) << "extremely small local h: " << mindist << " --> setting to " << 1e-3 * bb.Diam() << endl; (*testout) << "somewhere near " << line.p0 << " - " << line.p1 << endl; mindist = 1e-3 * bb.Diam(); } mesh.RestrictLocalHLine(line.p0, line.p1, mindist, line.layer); } } for (auto mspnt : mparam.meshsize_points) mesh.RestrictLocalH(mspnt.pnt, mspnt.h, mspnt.layer); multithread.task = savetask; } mesh.LoadLocalMeshSize (mparam.meshsizefilename); } } #endif ================================================ FILE: libsrc/occ/occgeom.cpp ================================================ #ifdef OCCGEOMETRY #include #include #include #include #include "occ_vertex.hpp" #include "occ_edge.hpp" #include "occ_face.hpp" #include "occ_solid.hpp" #include "occgeom.hpp" #include "Partition_Spliter.hxx" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if OCC_VERSION_HEX < 0x070000 // pass #elif OCC_VERSION_HEX < 0x070200 #include #include #else #include #endif namespace netgen { void LoadOCCInto(OCCGeometry* occgeo, const filesystem::path & filename); void PrintContents (OCCGeometry * geom); // Utility function to apply builder and propagate properties template static TopoDS_Shape Apply(T & builder, TopoDS_Shape & shape) { auto newshape = builder->Apply(shape); PropagateProperties(*builder, newshape); return newshape; }; TopTools_IndexedMapOfShape OCCGeometry::global_shape_property_indices; std::vector OCCGeometry::global_shape_properties; TopTools_IndexedMapOfShape OCCGeometry::global_identification_indices; std::vector> OCCGeometry::global_identifications; TopoDS_Shape ListOfShapes::Max(gp_Vec dir) { double maxval = -1e99; TopoDS_Shape maxshape; for (auto shape : *this) { GProp_GProps props; gp_Pnt center; switch (shape.ShapeType()) { case TopAbs_VERTEX: center = BRep_Tool::Pnt (TopoDS::Vertex(shape)); break; case TopAbs_FACE: BRepGProp::SurfaceProperties (shape, props); center = props.CentreOfMass(); break; default: BRepGProp::LinearProperties(shape, props); center = props.CentreOfMass(); } double val = center.X()*dir.X() + center.Y()*dir.Y() + center.Z() * dir.Z(); if (val > maxval) { maxval = val; maxshape = shape; } } return maxshape; } TopoDS_Shape ListOfShapes::Nearest(gp_Pnt pnt) { double mindist = 1e99; TopoDS_Shape nearestshape; auto vertex = BRepBuilderAPI_MakeVertex (pnt).Vertex(); for (auto shape : *this) { double dist = BRepExtrema_DistShapeShape(shape, vertex).Value(); if (dist < mindist) { nearestshape = shape; mindist = dist; } } return nearestshape; } ListOfShapes ListOfShapes::SubShapes(TopAbs_ShapeEnum type) const { TopTools_MapOfShape check_unique; ListOfShapes sub; for(const auto& shape : *this) for(TopExp_Explorer e(shape, type); e.More(); e.Next()) if(const auto& s = e.Current(); !check_unique.Contains(s)) { check_unique.Add(s); sub.push_back(s); } return sub; } OCCGeometry::OCCGeometry(const TopoDS_Shape& _shape, int aoccdim, bool copy) { if(copy) { auto filename = GetTempFilename(); step_utils::WriteSTEP(_shape, filename); LoadOCCInto(this, filename); dimension = aoccdim; filesystem::remove(filename); } else { shape = _shape; changed = 1; dimension = aoccdim; BuildFMap(); CalcBoundingBox(); PrintContents (this); } } const GeometryShape & OCCGeometry :: GetShape(const TopoDS_Shape & shape) const { switch (shape.ShapeType()) { case TopAbs_VERTEX: return GetVertex(shape); case TopAbs_EDGE: return GetEdge(shape); case TopAbs_FACE: return GetFace(shape); default: throw Exception("unknown shape type"); } } const GeometryVertex & OCCGeometry :: GetVertex(const TopoDS_Shape & shape) const { return *vertices[vmap.FindIndex(shape)-1]; } const GeometryEdge & OCCGeometry :: GetEdge(const TopoDS_Shape & shape) const { return *edges[emap.FindIndex(shape)-1]; } const GeometryFace & OCCGeometry :: GetFace(const TopoDS_Shape & shape) const { return *faces[fmap.FindIndex(shape)-1]; } const GeometrySolid & OCCGeometry :: GetSolid(const TopoDS_Shape & shape) const { return *solids[somap.FindIndex(shape)-1]; } string STEP_GetEntityName(const TopoDS_Shape & theShape, STEPCAFControl_Reader * aReader) { const Handle(XSControl_WorkSession)& theSession = aReader->Reader().WS(); const Handle(XSControl_TransferReader)& aTransferReader = theSession->TransferReader(); Handle(Standard_Transient) anEntity = aTransferReader->EntityFromShapeResult(theShape, 1); if (anEntity.IsNull()) // as just mapped anEntity = aTransferReader->EntityFromShapeResult (theShape,-1); if (anEntity.IsNull()) // as anything anEntity = aTransferReader->EntityFromShapeResult (theShape,4); if (anEntity.IsNull()) { cout<<"Warning: cannot get entity from shape" <Name()->ToCString();; auto bReprItem = Handle(StepBasic_ProductDefinitionRelationship)::DownCast(anEntity); if (!bReprItem.IsNull()) return bReprItem->Description()->ToCString(); cout<<"Warning: unknown entity type " << anEntity->DynamicType() << endl; return "none"; } void OCCGeometry :: Analyse(Mesh& mesh, const MeshingParameters& mparam) const { OCCSetLocalMeshSize(*this, mesh, mparam, occparam); } bool OCCGeometry :: MeshFace(Mesh& mesh, const MeshingParameters& mparam, int nr, FlatArray glob2loc) const { MeshingParameters local_mp = mparam; auto face = TopoDS::Face(fmap(nr+1)); if(auto quad_dominated = OCCGeometry::GetProperties(face).quad_dominated; quad_dominated.has_value()) local_mp.quad = *quad_dominated; bool failed = OCCMeshFace(*this, mesh, glob2loc, local_mp, nr, PARAMETERSPACE, true); if(failed) failed = OCCMeshFace(*this, mesh, glob2loc, local_mp, nr, PLANESPACE, false); if(failed) { facemeshstatus[nr] = -1; PrintError ("Problem in Surface mesh generation"); } else { facemeshstatus[nr] = 1; } return failed; } 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 << IM(3) << "Highest entry in topology hierarchy: " << endl; if (count) cout << IM(3) << count << " composite solid(s)" << endl; else if (geom->somap.Extent()) cout << IM(3) << geom->somap.Extent() << " solid(s)" << endl; else if (geom->shmap.Extent()) cout << IM(3) << geom->shmap.Extent() << " shells(s)" << endl; else if (geom->fmap.Extent()) cout << IM(3) << geom->fmap.Extent() << " face(s)" << endl; else if (geom->wmap.Extent()) cout << IM(3) << geom->wmap.Extent() << " wire(s)" << endl; else if (geom->emap.Extent()) cout << IM(3) << geom->emap.Extent() << " edge(s)" << endl; else if (geom->vmap.Extent()) cout << IM(3) << geom->vmap.Extent() << " vertices(s)" << endl; else cout << IM(3) << "no entities" << endl; } void OCCGeometry :: GlueGeometry() { PrintMessage(1, "OCC Glue Geometry"); /* // BRep_Builder builder; TopoDS_Shape my_fuse; int cnt = 0; for (TopExp_Explorer exp_solid(shape, TopAbs_SOLID); exp_solid.More(); exp_solid.Next()) { cout << "cnt = " << cnt << endl; if (cnt == 0) my_fuse = exp_solid.Current(); else // my_fuse = BRepAlgoAPI_Fuse (my_fuse, exp_solid.Current()); my_fuse = QANewModTopOpe_Glue::QANewModTopOpe_Glue(my_fuse, exp_solid.Current()); cnt++; } cout << "remove" << endl; // for (int i = 1; i <= somap.Size(); i++) // builder.Remove (shape, somap(i)); cout << "now add" << endl; // builder.Add (shape, my_fuse); shape = my_fuse; cout << "build fmap" << endl; BuildFMap(); */ // from // https://www.opencascade.com/doc/occt-7.4.0/overview/html/occt_user_guides__boolean_operations.html BOPAlgo_Builder aBuilder; // Setting arguments TopTools_ListOfShape aLSObjects; for (TopExp_Explorer exp_solid(shape, TopAbs_SOLID); exp_solid.More(); exp_solid.Next()) aLSObjects.Append (exp_solid.Current()); aBuilder.SetArguments(aLSObjects); // Setting options for GF // Set parallel processing mode (default is false) // Standard_Boolean bRunParallel = Standard_True; // aBuilder.SetRunParallel(bRunParallel); // Set Fuzzy value (default is Precision::Confusion()) // Standard_Real aFuzzyValue = 1.e-5; // aBuilder.SetFuzzyValue(aFuzzyValue); // Set safe processing mode (default is false) // Standard_Boolean bSafeMode = Standard_True; // aBuilder.SetNonDestructive(bSafeMode); // Set Gluing mode for coinciding arguments (default is off) // BOPAlgo_GlueEnum aGlue = BOPAlgo_GlueShift; // aBuilder.SetGlue(aGlue); // Disabling/Enabling the check for inverted solids (default is true) // Standard Boolean bCheckInverted = Standard_False; // aBuilder.SetCheckInverted(bCheckInverted); // Set OBB usage (default is false) // Standard_Boolean bUseOBB = Standard_True; // aBuilder.SetUseOBB(buseobb); // Perform the operation aBuilder.Perform(); // Check for the errors #if OCC_VERSION_HEX >= 0x070200 if (aBuilder.HasErrors()) { cout << "builder has errors" << endl; return; } // Check for the warnings if (aBuilder.HasWarnings()) { // treatment of the warnings ; } #endif PropagateProperties(aBuilder, shape); // result of the operation shape = aBuilder.Shape(); BuildFMap(); } 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; Apply(rebuild, 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); } shape = Apply(rebuild, 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; Apply(rebuild, shape); for (exp0.Init (shape, TopAbs_FACE); exp0.More(); exp0.Next()) { TopoDS_Face face = TopoDS::Face (exp0.Current()); auto props = GetProperties(face); 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)" <Status(ShapeExtend_DONE2)) cout << "(orientation of wires fixed)" <Status(ShapeExtend_DONE3)) cout << "(missing seam added)" <Status(ShapeExtend_DONE4)) cout << "(small area wire removed)" <Status(ShapeExtend_DONE5)) cout << "(natural bounds added)" <Face(); rebuild->Replace(face, newface); } // Set the original properties of the face to the newly created // face (after the healing process) // GetProperties(face); } shape = Apply(rebuild, shape); } { Handle(ShapeBuild_ReShape) rebuild = new ShapeBuild_ReShape; Apply(rebuild, 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); } shape = Apply(rebuild, shape); } if (fixsmalledges) { cout << endl << "- fixing small edges" << endl; Handle(ShapeFix_Wire) sfw; Handle(ShapeBuild_ReShape) rebuild = new ShapeBuild_ReShape; Apply(rebuild, 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); } //delete sfw; sfw = NULL; } } shape = Apply(rebuild, shape); { BuildFMap(); Handle(ShapeBuild_ReShape) rebuild = new ShapeBuild_ReShape; Apply(rebuild, 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); } } } shape = Apply(rebuild, shape); //delete rebuild; rebuild = NULL; } { Handle(ShapeBuild_ReShape) rebuild = new ShapeBuild_ReShape; Apply(rebuild, 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); } shape = Apply(rebuild, shape); } Handle(ShapeFix_Wireframe) sfwf = new ShapeFix_Wireframe; sfwf->SetPrecision(tolerance); sfwf->Load (shape); sfwf->ModeDropSmallEdges() = Standard_True; 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; } { 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; } auto newshape = sfwf->Shape(); PropagateProperties(*sfwf->Context(), newshape); shape = newshape; //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(); auto newshape = sffsm -> FixShape(); PropagateProperties(*sffsm->Context(), newshape); shape = newshape; //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(); PropagateProperties(sewedObj, shape); 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); } shape = Apply(rebuild, 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); 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 << "Total surface area : " << newsurfacecont << " (" << surfacecont << ")" << endl; cout << endl; } // For 2d geometries, make sure all faces have a normal vector with positive z-component void OCCGeometry :: FixFaceOrientation() { if(dimension!=2) return; bool needs_fix = false; Handle(ShapeBuild_ReShape) rebuild = new ShapeBuild_ReShape; for (auto face : GetFaces(shape)) { auto occface = OCCFace(face); auto normal = occface.GetNormal(occ2ng(GetVertices(face)[0])); if(normal[2] < 0) { needs_fix = true; // Need do copy the face, otherwise replace is ignored BRepBuilderAPI_Copy copy(face); auto newface = copy.Shape().Reversed(); PropagateProperties(copy, face); rebuild->Replace(face, newface); } } if(needs_fix ) shape = Apply(rebuild, shape); } void OCCGeometry :: BuildFMap() { somap.Clear(); shmap.Clear(); fmap.Clear(); wmap.Clear(); emap.Clear(); vmap.Clear(); TopExp_Explorer exp0, exp1, exp2, exp3, exp4, exp5; // Check face orientation in 2d geometries FixFaceOrientation(); 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 (auto face : MyExplorer(shape, TopAbs_FACE, TopAbs_SHELL)) if (!fmap.Contains(face)) { fmap.Add (face); for (auto wire : MyExplorer(face, TopAbs_WIRE)) if (!wmap.Contains(wire)) { wmap.Add (wire); for (auto edge : MyExplorer(wire, TopAbs_EDGE)) if (!emap.Contains(edge)) { emap.Add (edge); for (auto vertex : MyExplorer(edge, TopAbs_VERTEX)) if (!vmap.Contains(vertex)) 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); } } } */ std::map> free_edges_in_solid; for(auto i1 : Range(1, somap.Extent()+1)) { auto s = somap(i1); for (auto edge : MyExplorer(s, TopAbs_EDGE, TopAbs_WIRE)) if (!emap.Contains(edge)) { free_edges_in_solid[i1].Append(emap.Add (edge)); for (auto vertex : MyExplorer(edge, TopAbs_VERTEX)) if (!vmap.Contains(vertex)) vmap.Add (vertex); } } for (auto edge : MyExplorer(shape, TopAbs_EDGE, TopAbs_WIRE)) if (!emap.Contains(edge)) { emap.Add (edge); for (auto vertex : MyExplorer(edge, TopAbs_VERTEX)) if (!vmap.Contains(vertex)) 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); } */ for (auto vertex : MyExplorer(shape, TopAbs_VERTEX, TopAbs_EDGE)) if (!vmap.Contains(vertex)) 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 = 1e99; // 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; NetgenGeometry::Clear(); // Add shapes for(auto i1 : Range(1, vmap.Extent()+1)) { auto v = vmap(i1); auto occ_vertex = make_unique(TopoDS::Vertex(v)); occ_vertex->nr = vertices.Size(); if(HaveProperties(v)) occ_vertex->properties = GetProperties(v); vertices.Append(std::move(occ_vertex)); } for(auto i1 : Range(1, emap.Extent()+1)) { auto e = emap(i1); auto edge = TopoDS::Edge(e); auto verts = GetVertices(e); if(verts.size() == 0) continue; auto occ_edge = make_unique(edge, GetVertex(verts[0]), GetVertex(verts[1]) ); if(HaveProperties(edge)) occ_edge->properties = GetProperties(e); edges.Append(std::move(occ_edge)); } for(auto i1 : Range(1, fmap.Extent()+1)) { auto f = fmap(i1); auto k = faces.Size(); auto occ_face = make_unique(f); for(auto e : GetEdges(f)) occ_face->edges.Append( &GetEdge(e) ); if(HaveProperties(f)) occ_face->properties = GetProperties(f); faces.Append(std::move(occ_face)); if(dimension==2) for(auto e : GetEdges(f)) { auto & edge = GetEdge(e); if(e.Orientation() == TopAbs_REVERSED) edge.domout = k; else edge.domin = k; } } for(auto i1 : Range(1, somap.Extent()+1)) { auto s = somap(i1); int k = solids.Size(); auto occ_solid = make_unique(s); if(HaveProperties(s)) occ_solid->properties = GetProperties(s); for(auto f : GetFaces(s)) { auto & face = static_cast(GetFace(f)); face.properties.maxh = min2(face.properties.maxh, occ_solid->properties.maxh); if(face.domin==-1) face.domin = k; else face.domout = k; if(face.Shape().Orientation() == TopAbs_INTERNAL) face.domout = k; } if(free_edges_in_solid.count(i1)) for(auto ei : free_edges_in_solid[i1]) { auto & edge = GetEdge(emap(ei)); edge.properties.maxh = min(edge.properties.maxh, occ_solid->properties.maxh); edge.domin = k; edge.domout = k; occ_solid->free_edges.Append(&GetEdge(emap(ei))); } solids.Append(std::move(occ_solid)); } // Propagate maxh to children for(auto& face : faces) for(auto& edge : face->edges) edge->properties.maxh = min2(edge->properties.maxh, face->properties.maxh); // Add identifications auto add_identifications = [&](auto & shapes, auto & shape_map) { for(auto i1 : Range(1, shape_map.Extent()+1)) { auto shape = shape_map(i1); if(HaveIdentifications(shape)) for(auto & ident : GetIdentifications(shape)) { if(!shape_map.Contains(ident.from) || !shape_map.Contains(ident.to)) continue; ShapeIdentification si{ &GetShape(ident.from), &GetShape(ident.to), ident.trafo, ident.type, ident.name }; shapes[i1-1]->identifications.Append(si); } } }; add_identifications( vertices, vmap ); add_identifications( edges, emap ); add_identifications( faces, fmap ); bounding_box = ::netgen::GetBoundingBox( shape ); ProcessIdentifications(); } 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); TopoDS_Shape newshape = rebuild->Apply(shape, TopAbs_SHAPE, 1); shape = newshape; } cout << " done" << endl; } else cout << " not possible" << endl; } Array OCCGeometry :: GetFaceVertices(const GeometryFace& face) const { Array verts; const auto& occface = dynamic_cast(face); for(auto& vert : GetVertices(occface.Shape())) verts.Append(&GetVertex(vert)); return verts; } void OCCGeometry :: BuildVisualizationMesh (double deflection) { // cout << IM(5) << "Preparing visualization (deflection = " << deflection << ") ... " << flush; BuildTriangulation(shape); // cout << IM(5) << "done" << endl; } void OCCGeometry :: CalcBoundingBox () { boundingbox = ::netgen::GetBoundingBox(shape); (*testout) << "Bounding Box = [" << boundingbox.PMin() << " - " << boundingbox.PMax() << "]" << endl; SetCenter(); } // 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; // } void LoadOCCInto(OCCGeometry* occgeo, const filesystem::path & filename) { static Timer timer_all("LoadOCC"); RegionTimer rtall(timer_all); static Timer timer_readfile("LoadOCC-ReadFile"); static Timer timer_transfer("LoadOCC-Transfer"); static Timer timer_getnames("LoadOCC-get names"); // 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); timer_readfile.Start(); STEPCAFControl_Reader reader; // Enable transfer of colours reader.SetColorMode(Standard_True); reader.SetNameMode(Standard_True); Standard_Integer stat = reader.ReadFile(filename.string().c_str()); timer_readfile.Stop(); timer_transfer.Start(); if(stat != IFSelect_RetDone) { throw NgException("Couldn't load OCC geometry"); } reader.Transfer(step_doc); timer_transfer.Stop(); // Read in the shape(s) and the colours present in the STEP File auto step_shape_contents = XCAFDoc_DocumentTool::ShapeTool(step_doc->Main()); TDF_LabelSequence step_shapes; step_shape_contents->GetShapes(step_shapes); // For the STEP File Reader in OCC, the 1st Shape contains the entire // compound geometry as one shape auto main_shape = step_shape_contents->GetShape(step_shapes.Value(1)); step_utils::LoadProperties(main_shape, reader, step_doc); occgeo->shape = main_shape; occgeo->changed = 1; occgeo->BuildFMap(); occgeo->CalcBoundingBox(); PrintContents (occgeo); } // 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 filesystem::path & 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(filename.string().c_str()); if(stat != IFSelect_RetDone) { throw NgException("Couldn't load occ"); } // Enable transfer of colours reader.SetColorMode(Standard_True); reader.SetNameMode(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 compound shape // using the "OneShape" member auto shape = reader.OneShape(); auto shapeTool = XCAFDoc_DocumentTool::ShapeTool(iges_doc->Main()); // load colors for (auto typ : {TopAbs_SOLID, TopAbs_FACE, TopAbs_EDGE }) for (TopExp_Explorer e(shape, typ); e.More(); e.Next()) { TDF_Label label; shapeTool->Search(e.Current(), label); if(label.IsNull()) continue; XCAFPrs_IndexedDataMapOfShapeStyle set; TopLoc_Location loc; XCAFPrs::CollectStyleSettings(label, loc, set); XCAFPrs_Style aStyle; set.FindFromKey(e.Current(), aStyle); auto & prop = OCCGeometry::GetProperties(e.Current()); if(aStyle.IsSetColorSurf()) prop.col = step_utils::ReadColor(aStyle.GetColorSurfRGBA()); } // load names auto workSession = reader.WS(); auto model = workSession->Model(); auto transProc = workSession->TransferReader()->TransientProcess(); Standard_Integer nb = model->NbEntities(); for (Standard_Integer i = 1; i <= nb; i++) { Handle(Standard_Transient) entity = model->Value(i); auto item = Handle(StepRepr_RepresentationItem)::DownCast(entity); if(item.IsNull()) continue; TopoDS_Shape shape = TransferBRep::ShapeResult(transProc->Find(item)); string name = item->Name()->ToCString(); if (!transProc->IsBound(item)) continue; OCCGeometry::GetProperties(shape).name = name; } occgeo->shape = shape; 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 filesystem::path & filename) { OCCGeometry * occgeo; occgeo = new OCCGeometry; LoadOCCInto(occgeo, filename); return occgeo; } OCCGeometry *LoadOCC_BREP (const filesystem::path & filename) { OCCGeometry * occgeo; occgeo = new OCCGeometry; BRep_Builder aBuilder; Standard_Boolean result = BRepTools::Read(occgeo->shape, filename.string().c_str(), aBuilder); if(!result) { result = BinTools::Read(occgeo->shape, filename.string().c_str()); if (!result) { delete occgeo; throw Exception("Could not read BREP file " + filename.string()); } } occgeo->changed = 1; occgeo->BuildFMap(); occgeo->CalcBoundingBox(); PrintContents (occgeo); return occgeo; } void OCCGeometry :: Save (const filesystem::path & filename) const { string ext = ToLower(filename.extension()); auto s_filename = filename.string(); auto c_filename = s_filename.c_str(); if (ext == ".igs") { IGESControl_Writer writer("millimeters", 1); writer.AddShape (shape); writer.Write (c_filename); } else if (ext == ".stp") { step_utils::WriteSTEP(*this, filename); } else if (ext == ".stl") { StlAPI_Writer writer; writer.ASCIIMode() = Standard_True; writer.Write (shape, c_filename); } else if (ext == ".stlb") { StlAPI_Writer writer; writer.ASCIIMode() = Standard_False; writer.Write (shape, c_filename); } throw NgException ("Unknown target format: " + filename); } void OCCGeometry :: SaveToMeshFile (ostream & ost) const { auto ss = make_shared(); TextOutArchive out(ss); NetgenGeometry *geo = const_cast(this); out & geo; ost << "TextOutArchive" << endl; ost << ss->str().size() << endl; ost << ss->str(); } void OCCGeometry :: DoArchive(Archive& ar) { constexpr int current_format_version = 0; int format_version = current_format_version; auto netgen_version = GetLibraryVersion("netgen"); ar & netgen_version & format_version; if(ar.Output()) { std::stringstream ss; #if OCC_VERSION_HEX < 0x070600 BRepTools::Write(shape, ss); #else BRepTools::Write(shape, ss, false, false, TopTools_FormatVersion_VERSION_1); #endif ar << ss.str(); } else { if(format_version>current_format_version) throw Exception("Loading OCCGeometry from archive: unknown format version " + ToString(format_version) + ", written by netgen version " + ToString(netgen_version)); std::string str; ar & str; stringstream ss(str); BRep_Builder builder; BRepTools::Read(shape, ss, builder); } TopTools_IndexedMapOfShape shape_map; Array shape_list; ar & dimension; auto types = Array{ TopAbs_SOLID, TopAbs_FACE, TopAbs_EDGE }; if(ar.GetVersion("netgen") >= "v6.2.2406-22") types.Append(TopAbs_VERTEX); for (auto typ : types) for (TopExp_Explorer e(shape, typ); e.More(); e.Next()) { auto ds = e.Current(); if(shape_map.FindIndex(ds) == 0) { shape_map.Add(ds); shape_list.Append(ds); } } for (auto s : shape_list) { bool has_properties = HaveProperties(s); ar & has_properties; if(has_properties) ar & GetProperties(s); bool has_identifications = HaveIdentifications(s); ar & has_identifications; if(has_identifications) { int n_idents; std::vector used_idents; if(ar.Output()) { // only use identifications that are used within the geometry for(auto& id : GetIdentifications(s)) { if(shape_map.Contains(id.from) && shape_map.Contains(id.to)) used_idents.push_back(id); } n_idents = used_idents.size(); } auto & idents = ar.Output() ? used_idents : GetIdentifications(s); ar & n_idents; idents.resize(n_idents); for(auto i : Range(n_idents)) { auto & id = idents[i]; int id_from, id_to; if(ar.Output()) { id_from = shape_map.FindIndex(id.from)-1; id_to = shape_map.FindIndex(id.to)-1; } ar & id_from & id_to; // trafo is now optional -> special treatment necessary for backward compatibility if(ar.Output() || netgen_version >= "v6.2.2403-34-g571cbbe4") ar & id.trafo; else { auto trafo = Transformation<3>(); ar & trafo; id.trafo = trafo; } ar & id.name; if(ar.Input()) { id.from = shape_list[id_from]; id.to = shape_list[id_to]; } } } } if(ar.Input()) { changed = 1; BuildFMap(); CalcBoundingBox(); } } const char * shapesname[] = {" ", "CompSolids", "Solids", "Shells", "Faces", "Wires", "Edges", "Vertices"}; const char * shapename[] = {" ", "CompSolid", "Solid", "Shell", "Face", "Wire", "Edge", "Vertex"}; const char * orientationstring[] = {"+", "-", "i", "e"}; 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 handled" << 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(HaveProperties(e.Current())) { const auto& props = GetProperties(e.Current()); if(props.name || props.maxh < 1e99) str << " - "; if(props.name) str << props.GetName(); if(props.maxh < 1e99) str << " maxh(" << props.maxh << ")"; } 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 stretched 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; NgArray edgeLengths; NgArray 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; } bool IsMappedShape(const Transformation<3> & trafo, const TopoDS_Shape & me, const TopoDS_Shape & you) { if(me.ShapeType() != you.ShapeType()) return false; Bnd_Box bbox; BRepBndLib::Add(me, bbox); BRepBndLib::Add(you, bbox); BoxTree<3> tree( occ2ng(bbox.CornerMin()), occ2ng(bbox.CornerMax()) ); Point<3> c_me = occ2ng(Center(me)); Point<3> c_you = occ2ng(Center(you)); if(tree.GetTolerance() < Dist(trafo(c_me), c_you)) return false; TopTools_IndexedMapOfShape vmap; std::vector> verts; auto verts_me = GetVertices(me); auto verts_you = GetVertices(you); if(verts_me.size() != verts_you.size()) return false; for (auto i : Range(verts_me.size())) { auto s = verts_me[i]; if(vmap.FindIndex(s) > 0) continue; auto p = trafo(occ2ng(s)); tree.Insert( p, i ); vmap.Add(s); verts.push_back(nullopt); } for (auto vert : verts_you) { auto s = vert; auto p = occ2ng(s); bool vert_mapped = false; tree.GetFirstIntersecting( p, p, [&](size_t i ) { vmap.Add(verts_me[i]); verts[vmap.FindIndex(verts_me[i])-1] = s; vert_mapped = true; return true; }); if(!vert_mapped) return false; } return true; } void Identify(const TopoDS_Shape & me, const TopoDS_Shape & you, string name, Identifications::ID_TYPE type, std::optional> opt_trafo) { Transformation<3> trafo; if(opt_trafo) { trafo = occ2ng(*opt_trafo); } else { auto v = occ2ng(Center(you)) - occ2ng(Center(me)); trafo = Transformation<3>(v); } ListOfShapes list_me, list_you; list_me.push_back(me); list_you.push_back(you); Identify(list_me, list_you, name, type, trafo); } void Identify(const ListOfShapes & me, const ListOfShapes & you, string name, Identifications::ID_TYPE type, Transformation<3> trafo) { ListOfShapes id_me; ListOfShapes id_you; if(auto faces_me = me.Faces(); faces_me.size()>0) { id_me = faces_me; id_you = you.Faces(); } else if(auto edges_me = me.Edges(); edges_me.size()>0) { id_me = edges_me; id_you = you.Edges(); } else { id_me = me.Vertices(); id_you = you.Vertices(); } for(auto shape_me : id_me) for(auto shape_you : id_you) { if(!IsMappedShape(trafo, shape_me, shape_you)) continue; OCCGeometry::GetIdentifications(shape_me).push_back (OCCIdentification { shape_me, shape_you, trafo, name, type }); } } void OCCParameters :: Print(ostream & ost) const { ost << "OCC Parameters:" << endl << "minimum edge length: " << resthminedgelenenable << ", min len = " << resthminedgelen << endl; } DLL_HEADER extern OCCParameters occparam; OCCParameters occparam; // int OCCGeometry :: GenerateMesh (shared_ptr & mesh, MeshingParameters & mparam) // { // return OCCGenerateMesh (*this, mesh, mparam, occparam); // } static RegisterClassForArchive regnggeo; namespace step_utils { void LoadProperties(const TopoDS_Shape & shape, const STEPCAFControl_Reader & reader, const Handle(TDocStd_Document) step_doc) { static Timer t("step_utils::LoadProperties"); RegionTimer rt(t); auto workSession = reader.Reader().WS(); auto model = workSession->Model(); auto transferReader = workSession->TransferReader(); auto transProc = transferReader->TransientProcess(); auto shapeTool = XCAFDoc_DocumentTool::ShapeTool(step_doc->Main()); // load colors for (auto typ : { TopAbs_SOLID, TopAbs_FACE, TopAbs_EDGE }) for (TopExp_Explorer e(shape, typ); e.More(); e.Next()) { TDF_Label label; shapeTool->Search(e.Current(), label); if(label.IsNull()) continue; XCAFPrs_IndexedDataMapOfShapeStyle set; TopLoc_Location loc; XCAFPrs::CollectStyleSettings(label, loc, set); XCAFPrs_Style aStyle; set.FindFromKey(e.Current(), aStyle); if(aStyle.IsSetColorSurf()) { for(TopExp_Explorer e2(e.Current(), TopAbs_FACE); e2.More(); e2.Next()) { auto & prop = OCCGeometry::GetProperties(e2.Current()); prop.col = step_utils::ReadColor(aStyle.GetColorSurfRGBA()); } } if(aStyle.IsSetColorCurv()) { for(TopExp_Explorer e2(e.Current(), TopAbs_EDGE); e2.More(); e2.Next()) { auto & prop = OCCGeometry::GetProperties(e2.Current()); prop.col = step_utils::ReadColor(aStyle.GetColorSurfRGBA()); } } } // load names Standard_Integer nb = model->NbEntities(); for (Standard_Integer i = 1; i <= nb; i++) { Handle(Standard_Transient) entity = model->Value(i); auto item = Handle(StepRepr_RepresentationItem)::DownCast(entity); if(item.IsNull()) continue; TopoDS_Shape shape = TransferBRep::ShapeResult(transProc->Find(item)); string name = item->Name()->ToCString(); if (!transProc->IsBound(item) || name == "") continue; // we only allow names on SOLIDS, FACES, EDGES, VERTICES. // if name is given on a compound, assume it should be on all subshapes // of highest dimension for(auto & s : GetHighestDimShapes(shape)) OCCGeometry::GetProperties(s).name = name; } // load custom data (maxh etc.) for (Standard_Integer i = 1; i <= nb; i++) { Handle(Standard_Transient) entity = model->Value(i); auto item = Handle(StepRepr_CompoundRepresentationItem)::DownCast(entity); if(item.IsNull()) continue; auto shape_item = item->ItemElementValue(1); TopoDS_Shape shape = TransferBRep::ShapeResult(transProc->Find(shape_item)); string name = item->Name()->ToCString(); if(name == "netgen_geometry_identification") ReadIdentifications(item, transProc); if(name != "netgen_geometry_properties") continue; auto & prop = OCCGeometry::GetProperties(shape); auto nprops = item->NbItemElement(); for(auto i : Range(2, nprops+1)) { auto prop_item = item->ItemElementValue(i); string prop_name = prop_item->Name()->ToCString(); if(prop_name=="maxh") prop.maxh = Handle(StepRepr_ValueRepresentationItem)::DownCast(prop_item) ->ValueComponentMember()->Real(); if(prop_name=="hpref") prop.hpref = Handle(StepRepr_ValueRepresentationItem)::DownCast(prop_item) ->ValueComponentMember()->Real(); } } } void WriteProperties(const Handle(Interface_InterfaceModel) model, const Handle(Transfer_FinderProcess) finder, const TopoDS_Shape & shape) { static const ShapeProperties default_props; Handle(StepRepr_RepresentationItem) item = STEPConstruct::FindEntity(finder, shape); if(!item) return; auto prop = OCCGeometry::GetProperties(shape); if(auto n = prop.name) item->SetName(MakeName(*n)); Array props; props.Append(item); if(auto maxh = prop.maxh; maxh != default_props.maxh) props.Append( MakeReal(maxh, "maxh") ); if(auto hpref = prop.hpref; hpref != default_props.hpref) props.Append( MakeReal(hpref, "hpref") ); if(props.Size()>1) { for(auto & item : props.Range(1, props.Size())) model->AddEntity(item); auto compound = MakeCompound(props, "netgen_geometry_properties"); model->AddEntity(compound); } WriteIdentifications(model, shape, finder); } void WriteIdentifications(const Handle(Interface_InterfaceModel) model, const TopoDS_Shape & shape, const Handle(Transfer_FinderProcess) finder) { Handle(StepRepr_RepresentationItem) item = STEPConstruct::FindEntity(finder, shape); if(!OCCGeometry::HaveIdentifications(shape)) return; auto & identifications = OCCGeometry::GetIdentifications(shape); if(identifications.size()==0) return; // auto n = identifications.size(); Array ident_items; ident_items.Append(item); for(auto & ident : identifications) { const auto& to = STEPConstruct::FindEntity(finder, ident.from == shape ? ident.to : ident.from); if(to.IsNull()) continue; Array items; items.Append(MakeReal(ident.from == shape ? 1 : 0)); items.Append(to); Transformation<3> trafo; if(ident.trafo) trafo = *ident.trafo; auto & m = trafo.GetMatrix(); for(auto i : Range(9)) items.Append(MakeReal(m(i))); auto & v = trafo.GetVector(); for(auto i : Range(3)) items.Append(MakeReal(v(i))); items.Append(MakeInt(ident.type)); for(auto & item : items.Range(0, items.Size())) model->AddEntity(item); ident_items.Append(MakeCompound(items, ident.name)); } for(auto & item : ident_items.Range(1, ident_items.Size())) model->AddEntity(item); auto comp = MakeCompound(ident_items, "netgen_geometry_identification"); model->AddEntity(comp); } void ReadIdentifications(Handle(StepRepr_RepresentationItem) item, Handle(Transfer_TransientProcess) transProc) { auto idents = Handle(StepRepr_CompoundRepresentationItem)::DownCast(item); auto n = idents->NbItemElement(); std::vector result; auto shape_origin = TransferBRep::ShapeResult(transProc->Find(idents->ItemElementValue(1))); for(auto i : Range(2,n+1)) { auto id_item = Handle(StepRepr_CompoundRepresentationItem)::DownCast(idents->ItemElementValue(i)); OCCIdentification ident; ident.name = id_item->Name()->ToCString(); auto is_from = ReadReal(id_item->ItemElementValue(1)); if(is_from) { ident.from = shape_origin; ident.to = TransferBRep::ShapeResult(transProc->Find(id_item->ItemElementValue(2))); } else { ident.from = TransferBRep::ShapeResult( transProc->Find(id_item->ItemElementValue(2))); ident.to = shape_origin; } Transformation<3> trafo; auto & m = trafo.GetMatrix(); for(auto i : Range(9)) m(i) = ReadReal(id_item->ItemElementValue(3+i)); auto & v = trafo.GetVector(); for(auto i : Range(3)) v(i) = ReadReal(id_item->ItemElementValue(12+i)); if(FlatVector(9, &trafo.GetMatrix()(0,0)).L2Norm() != .0 && trafo.GetVector().Length2() != .0) ident.trafo = trafo; ident.type = Identifications::ID_TYPE(ReadInt(id_item->ItemElementValue(15))); result.push_back(ident); } OCCGeometry::GetIdentifications(shape_origin) = result; } void WriteSTEP(const TopoDS_Shape & shape, const filesystem::path & filename) { Interface_Static::SetCVal("write.step.schema", "AP242IS"); Interface_Static::SetIVal("write.step.assembly",1); Handle(XCAFApp_Application) app = XCAFApp_Application::GetApplication(); Handle(TDocStd_Document) doc; app->NewDocument("STEP-XCAF", doc); Handle(XCAFDoc_ShapeTool) shapetool = XCAFDoc_DocumentTool::ShapeTool(doc->Main()); Handle(XCAFDoc_ColorTool) colortool = XCAFDoc_DocumentTool::ColorTool(doc->Main()); TDF_Label label = shapetool->NewShape(); shapetool->SetShape(label, shape); Handle(XSControl_WorkSession) session = new XSControl_WorkSession; STEPCAFControl_Writer writer(session); const Handle(Interface_InterfaceModel) model = session->Model(); // Set colors (BEFORE transferring shape into step data structures) for (auto typ : { TopAbs_SOLID, TopAbs_FACE, TopAbs_EDGE }) for (TopExp_Explorer e(shape, typ); e.More(); e.Next()) { auto prop = OCCGeometry::GetProperties(e.Current()); if(auto col = prop.col) colortool->SetColor(e.Current(), step_utils::MakeColor(*col), XCAFDoc_ColorGen); } // Transfer shape into step data structures -> now we can manipulate/add step representation items writer.Transfer(doc, STEPControl_AsIs); // Write all other properties auto finder = session->TransferWriter()->FinderProcess(); for (auto typ : { TopAbs_SOLID, TopAbs_FACE, TopAbs_EDGE }) for (TopExp_Explorer e(shape, typ); e.More(); e.Next()) WriteProperties(model, finder, e.Current()); writer.Write(filename.string().c_str()); } } // namespace step_utils } #endif ================================================ FILE: libsrc/occ/occgeom.hpp ================================================ #ifndef FILE_OCCGEOM #define FILE_OCCGEOM /* *************************************************************************/ /* File: occgeom.hpp */ /* Author: Robert Gaisbauer */ /* Date: 26. May 03 */ /* *************************************************************************/ #ifdef OCCGEOMETRY #include #include #include "occ_utils.hpp" #include "occmeshsurf.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if OCC_VERSION_MAJOR>=7 && OCC_VERSION_MINOR>=4 #define OCC_HAVE_HISTORY #endif namespace netgen { // 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 bool IsMappedShape(const Transformation<3> & trafo, const TopoDS_Shape & me, const TopoDS_Shape & you); 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; int layer = 1; double Dist (Line l); double Length () { return (p1-p0).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 DLL_HEADER OCCParameters { public: /// Factor for meshing close edges, moved to meshingparameters // double resthcloseedgefac = 2.; /// Enable / Disable detection of close edges // int resthcloseedgeenable = true; /// Minimum edge length to be used for dividing edges to mesh points // double resthminedgelen = 0.001; double resthminedgelen = 1e-4; /// Enable / Disable use of the minimum edge length (by default use 1e-4) int resthminedgelenenable = false; /*! Dump all the OpenCascade specific meshing parameters to console */ void Print (ostream & ost) const; }; class DLL_HEADER OCCGeometry : public NetgenGeometry { Point<3> center; OCCParameters occparam; public: static TopTools_IndexedMapOfShape global_shape_property_indices; static std::vector global_shape_properties; static TopTools_IndexedMapOfShape global_identification_indices; static std::vector> global_identifications; static ShapeProperties& GetProperties(const TopoDS_Shape& shape) { try { CheckValidPropertyType(shape); } catch(Exception& e) { cerr << "WARNING: " << e.what() << endl; } auto index = OCCGeometry::global_shape_property_indices.FindIndex(shape); if(index > 0) return OCCGeometry::global_shape_properties [index-1]; OCCGeometry::global_shape_property_indices.Add(shape); OCCGeometry::global_shape_properties.push_back({}); return OCCGeometry::global_shape_properties.back(); } static bool HaveProperties(const TopoDS_Shape& shape) { return OCCGeometry::global_shape_property_indices.FindIndex(shape) > 0; } static std::vector& GetIdentifications(const TopoDS_Shape& shape) { auto index = OCCGeometry::global_identification_indices.FindIndex(shape); if(index > 0) return OCCGeometry::global_identifications[index-1]; OCCGeometry::global_identification_indices.Add(shape); OCCGeometry::global_identifications.push_back({}); return OCCGeometry::global_identifications.back(); } static bool HaveIdentifications(const TopoDS_Shape& shape) { return OCCGeometry::global_identification_indices.FindIndex(shape) > 0; } TopoDS_Shape shape; TopTools_IndexedMapOfShape fmap, emap, vmap, somap, shmap, wmap; NgArray fsingular, esingular, vsingular; Box<3> boundingbox; mutable int changed; mutable NgArray facemeshstatus; // Philippose - 15/01/2009 // Maximum mesh size for a given face // (Used to explicitly define mesh size limits on individual faces) NgArray face_maxh; // Philippose - 14/01/2010 // Boolean array to detect whether a face has been explicitly modified // by the user or not NgArray 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) NgArray face_sel_status; NgArray 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(); } OCCGeometry(const TopoDS_Shape& _shape, int aoccdim = 3, bool copy = false); Mesh::GEOM_TYPE GetGeomType() const override { return Mesh::GEOM_OCC; } void SetDimension(int dim) { dimension = dim; BuildFMap(); } void SetOCCParameters(const OCCParameters& par) { occparam = par; } using NetgenGeometry::GetVertex; using NetgenGeometry::GetEdge; using NetgenGeometry::GetFace; using NetgenGeometry::GetSolid; GeometryShape & GetShape(const TopoDS_Shape & shape) { return const_cast(as_const(*this).GetShape(shape)); } GeometryVertex & GetVertex(const TopoDS_Shape & shape) { return const_cast(as_const(*this).GetVertex(shape)); } GeometryEdge & GetEdge(const TopoDS_Shape & shape) { return const_cast(as_const(*this).GetEdge(shape)); } GeometryFace & GetFace(const TopoDS_Shape & shape) { return const_cast(as_const(*this).GetFace(shape)); } GeometrySolid & GetSolid(const TopoDS_Shape & shape) { return const_cast(as_const(*this).GetSolid(shape)); } const GeometryShape & GetShape(const TopoDS_Shape & shape) const; const GeometryVertex & GetVertex(const TopoDS_Shape & shape) const; const GeometryEdge & GetEdge(const TopoDS_Shape & shape) const; const GeometryFace & GetFace(const TopoDS_Shape & shape) const; const GeometrySolid & GetSolid(const TopoDS_Shape & shape) const; void Analyse(Mesh& mesh, const MeshingParameters& mparam) const override; bool MeshFace(Mesh& mesh, const MeshingParameters& mparam, int nr, FlatArray glob2loc) const override; // void OptimizeSurface(Mesh& mesh, const MeshingParameters& mparam) const override {} void Save (const filesystem::path & filename) const override; void SaveToMeshFile (ostream & /* ost */) const override; void DoArchive(Archive& ar) override; void BuildFMap(); auto GetShape() const { return shape; } Box<3> GetBoundingBox() const { return boundingbox; } int NrSolids() const { return somap.Extent(); } // Philippose - 17/01/2009 // Total number of faces in the geometry int NrFaces() const { return fmap.Extent(); } void SetCenter() { center = boundingbox.Center(); } Point<3> Center() const { return center; } 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(); Array GetFaceVertices(const GeometryFace& face) const override; void FixFaceOrientation(); void HealGeometry(); void GlueGeometry(); // 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, const MeshingParameters & mparam) { 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; } } } void SetFaceMaxH(size_t facenr, double faceh) { if(facenr >= fmap.Extent()) throw RangeException("OCCGeometry faces", facenr, 0, fmap.Extent()); face_maxh[facenr] = faceh; face_maxh_modified[facenr] = true; } // 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() { for(int 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); private: //bool FastProject (int surfi, Point<3> & ap, double& u, double& v) const; }; DLL_HEADER void Identify(const ListOfShapes & me, const ListOfShapes & you, string name, Identifications::ID_TYPE type, Transformation<3> trafo); DLL_HEADER void Identify(const TopoDS_Shape & me, const TopoDS_Shape & you, string name, Identifications::ID_TYPE type, std::optional> opt_trafo); void PrintContents (OCCGeometry * geom); DLL_HEADER OCCGeometry * LoadOCC_IGES (const filesystem::path & filename); DLL_HEADER OCCGeometry * LoadOCC_STEP (const filesystem::path & filename); DLL_HEADER OCCGeometry * LoadOCC_BREP (const filesystem::path & filename); // 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....!!) DLL_HEADER extern void OCCSetLocalMeshSize(const OCCGeometry & geom, Mesh & mesh, const MeshingParameters & mparam, const OCCParameters& occparam); DLL_HEADER extern bool OCCMeshFace (const OCCGeometry & geom, Mesh & mesh, FlatArray glob2loc, const MeshingParameters & mparam, int nr, int projecttype, bool delete_on_failure); inline auto GetModified(BRepBuilderAPI_MakeShape & builder, TopoDS_Shape shape) { return builder.Modified(shape); } inline auto GetModified(BRepTools_History & history, TopoDS_Shape shape) { return history.Modified(shape); } inline auto GetModified(BOPAlgo_BuilderShape & builder, TopoDS_Shape shape) { return builder.Modified(shape); } inline ArrayMem GetModified(BRepBuilderAPI_Sewing& builder, TopoDS_Shape shape) { return {builder.Modified(shape)}; } inline auto GetModified(BRepTools_ReShape& reshape, TopoDS_Shape shape) { auto history = reshape.History(); return history->Modified(shape); } template void PropagateIdentifications (TBuilder & builder, TopoDS_Shape shape, std::optional> trafo = nullopt) { TopTools_IndexedMapOfShape mod_indices; Array modifications; TopTools_MapOfShape shape_handled; Transformation<3> trafo_inv; if(trafo) trafo_inv = trafo->CalcInverse(); for (auto typ : { TopAbs_SOLID, TopAbs_FACE, TopAbs_EDGE, TopAbs_VERTEX }) for (TopExp_Explorer e(shape, typ); e.More(); e.Next()) { auto s = e.Current(); mod_indices.Add(s); modifications.Append(TopTools_IndexedMapOfShape()); modifications.Last().Add(s); } for (auto typ : { TopAbs_SOLID, TopAbs_FACE, TopAbs_EDGE, TopAbs_VERTEX }) for (TopExp_Explorer e(shape, typ); e.More(); e.Next()) { auto s = e.Current(); for (auto mods : GetModified(builder, s)) { auto index = mod_indices.FindIndex(s)-1; modifications[index].Add(mods); } } for (auto typ : { TopAbs_SOLID, TopAbs_FACE, TopAbs_EDGE, TopAbs_VERTEX }) for (TopExp_Explorer e(shape, typ); e.More(); e.Next()) { auto s = e.Current(); if(shape_handled.Contains(s)) continue; shape_handled.Add(s); if(!OCCGeometry::HaveIdentifications(s)) continue; auto& identifications = OCCGeometry::GetIdentifications(s); // auto& shape_mapped = modifications[mod_indices.FindIndex(s)-1]; for(auto ident : identifications) { auto i1 = mod_indices.FindIndex(ident.to); auto i2 = mod_indices.FindIndex(ident.from); if(i1 == 0 || i2 == 0) // not in geometry continue; auto& mods_to = modifications[i1-1]; auto& mods_from = modifications[i2-1]; if(mods_to.Extent()==1 && mods_from.Extent() ==1) continue; auto from = ident.from; auto to = ident.to; for(auto it = mods_from.cbegin(); it != mods_from.cend(); it++) for(auto it2 = mods_to.cbegin(); it2 != mods_to.cend(); it2++) { auto& from_mapped = it.Iterator().Value(); auto& to_mapped = it2.Iterator().Value(); if(from.IsSame(from_mapped) && to.IsSame(to_mapped)) continue; if(!ident.trafo) continue; Transformation<3> trafo_mapped = *ident.trafo; if(trafo) { Transformation<3> trafo_temp; trafo_temp.Combine(*ident.trafo, trafo_inv); trafo_mapped.Combine(*trafo, trafo_temp); } if(!IsMappedShape(trafo_mapped, from_mapped, to_mapped)) continue; OCCIdentification id_new = ident; id_new.to = to_mapped; id_new.from = from_mapped; id_new.trafo = trafo_mapped; auto id_owner = from.IsSame(s) ? from_mapped : to_mapped; OCCGeometry::GetIdentifications(id_owner).push_back(id_new); } } } } template void PropagateProperties (TBuilder & builder, TopoDS_Shape shape, std::optional> trafo = nullopt) { bool have_identifications = false; for (auto typ : { TopAbs_SOLID, TopAbs_FACE, TopAbs_EDGE, TopAbs_VERTEX }) for (TopExp_Explorer e(shape, typ); e.More(); e.Next()) { auto s = e.Current(); have_identifications |= OCCGeometry::HaveIdentifications(s); if(!OCCGeometry::HaveProperties(s)) continue; auto prop = OCCGeometry::GetProperties(s); for (auto mods : GetModified(builder, s)) OCCGeometry::GetProperties(mods).Merge(prop); } if(have_identifications) PropagateIdentifications(builder, shape, trafo); } namespace step_utils { inline Handle(TCollection_HAsciiString) MakeName (string s) { return new TCollection_HAsciiString(s.c_str()); }; inline Handle(StepRepr_RepresentationItem) MakeInt (int n, string name = "") { Handle(StepRepr_IntegerRepresentationItem) int_obj = new StepRepr_IntegerRepresentationItem; int_obj->Init(MakeName(name), n); return int_obj; } inline int ReadInt (Handle(StepRepr_RepresentationItem) item) { return Handle(StepRepr_IntegerRepresentationItem)::DownCast(item)->Value(); } inline Handle(StepRepr_RepresentationItem) MakeReal (double val, string name = "") { Handle(StepBasic_MeasureValueMember) value_member = new StepBasic_MeasureValueMember; value_member->SetReal(val); Handle(StepRepr_ValueRepresentationItem) value_repr = new StepRepr_ValueRepresentationItem; value_repr->Init(MakeName(name), value_member); return value_repr; } inline double ReadReal (Handle(StepRepr_RepresentationItem) item) { return Handle(StepRepr_ValueRepresentationItem)::DownCast(item) ->ValueComponentMember()->Real(); } inline Handle(StepRepr_RepresentationItem) MakeCompound( FlatArray items, string name = "" ) { Handle(StepRepr_HArray1OfRepresentationItem) array_repr = new StepRepr_HArray1OfRepresentationItem(1,items.Size()); for(auto i : Range(items)) array_repr->SetValue(i+1, items[i]); Handle(StepRepr_CompoundRepresentationItem) comp = new StepRepr_CompoundRepresentationItem; comp->Init( MakeName(name), array_repr ); return comp; } void WriteIdentifications(const Handle(Interface_InterfaceModel) model, const TopoDS_Shape & shape, const Handle(Transfer_FinderProcess) finder); void ReadIdentifications(Handle(StepRepr_RepresentationItem) item, Handle(Transfer_TransientProcess) transProc); inline Quantity_ColorRGBA MakeColor(const Vec<4> & c) { return Quantity_ColorRGBA (c[0], c[1], c[2], c[3]); } inline Vec<4> ReadColor (const Quantity_ColorRGBA & c) { auto rgb = c.GetRGB(); return {rgb.Red(), rgb.Green(), rgb.Blue(), c.Alpha()}; } void LoadProperties(const TopoDS_Shape & shape, const STEPCAFControl_Reader & reader, const Handle(TDocStd_Document) step_doc); void WriteProperties(const Handle(Interface_InterfaceModel) model, const Handle(Transfer_FinderProcess) finder, const TopoDS_Shape & shape); void WriteSTEP(const TopoDS_Shape & shape, const filesystem::path & filename); inline void WriteSTEP(const OCCGeometry & geo, const filesystem::path & filename) { WriteSTEP(geo.GetShape(), filename); } // deep copy, also ensures consistent shape ordering (face numbers etc.) TopoDS_Shape WriteAndRead(const TopoDS_Shape shape); } // namespace step_utils } #endif #endif ================================================ FILE: libsrc/occ/occmeshsurf.cpp ================================================ #ifdef OCCGEOMETRY #include #include #include "occgeom.hpp" #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" #include #include #pragma clang diagnostic pop #include "occmeshsurf.hpp" namespace netgen { bool glob_testout(false); void OCCSurface :: GetNormalVector (const Point<3> & p, const PointGeomInfo & geominfo, Vec<3> & n) const { GeomLProp_SLProps lprop(occface,geominfo.u,geominfo.v,1,1e-8); if (lprop.IsNormalDefined()) { n = occ2ng(lprop.Normal()); } else { gp_Pnt pnt; gp_Vec du, dv; double setu=geominfo.u,setv=geominfo.v; 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(); */ n += occ2ng(lprop.Normal()); } 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(); */ n += occ2ng(lprop.Normal()); } 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(); */ n += occ2ng(lprop.Normal()); } 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(); */ n += occ2ng(lprop.Normal()); } setv = geominfo.v; n.Normalize(); } 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 = -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); // static Timer t("occ-defintangplane calculations"); // RegionTimer reg(t); Mat<3,2> D1_; 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(); auto D1T_ = Trans(D1_); auto D1TD1_ = D1T_*D1_; if (Det (D1TD1_) == 0) throw SingularMatrixException(); Mat<2,2> DDTinv_; CalcInverse (D1TD1_, DDTinv_); Mat<3,2> Y_; 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); } auto A_ = DDTinv_ * D1T_ * Y_; Mat<2,2> Ainv_; if (Det(A_) == 0) throw SingularMatrixException(); CalcInverse (A_, Ainv_); Vec<2> temp_ = Ainv_ * (psp2-psp1); double r_ = temp_.Length(); Mat<2,2> R_; R_(0,0) = temp_(0)/r_; R_(1,0) = temp_(1)/r_; R_(0,1) = -R_(1,0); R_(1,1) = R_(0,0); A_ = A_ * R_; Ainv_ = Trans(R_) * Ainv_; Amat = A_; Amatinv = Ainv_; // temp = Amatinv * (psp2-psp1); #ifdef OLD 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); // cout << " =?= inv = " << DDTinv << endl; 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); // cout << "=?= R = " << R << endl; 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); } // cout << "=?= Ainv = " << endl << Ainv << endl; temp = Amatinv * (psp2-psp1); cout << " =?= Amatinv = " << Amatinv << endl; #endif }; } void OCCSurface :: ToPlane (const Point<3> & p3d, const PointGeomInfo & geominfo, Point<2> & pplane, double h, int & zone) const { // static Timer t("ToPlane"); RegionTimer reg(t); 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) { // static Timer t("FromPlane"); RegionTimer reg(t); 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; p3d = occ2ng(occface->Value (gi.u, gi.v)); }; } void OCCSurface :: Project (Point<3> & ap, PointGeomInfo & gi) { static Timer t("OccSurface::Project"); RegionTimer reg(t); static Timer tanal("OccSurface::Project analysis"); static Timer ttol("OccSurface::Project approximation"); static Timer t2("OccSurface::Project actual"); // try Newton's method ... gp_Pnt p = ng2occ(ap); double u = gi.u; double v = gi.v; #ifdef OLD // was a problem for pheres: got u-v parameters outside range of definition gp_Pnt x = occface->Value (u,v); if (p.SquareDistance(x) <= sqr(PROJECTION_TOLERANCE)) return; gp_Vec du, dv; occface->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) break; 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; occface->D1(u,v,x,du,dv); if (xold.SquareDistance(x) < sqr(PROJECTION_TOLERANCE)) { ap = Point<3> (x.X(), x.Y(), x.Z()); gi.u = u; gi.v = v; return; } } while (count < 20); #endif // Newton did not converge, use OCC projection // static int cnt = 0; // if (cnt++ % 1000 == 0) cout << "********************************************** OCCSurfce :: Project, cnt = " << cnt << endl; gp_Pnt pnt = p; // (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; // JS : shouldn't we move these 2 lines to the constructor ? // tanal.Start(); Handle( ShapeAnalysis_Surface ) su = new ShapeAnalysis_Surface( occface ); // ShapeAnalysis_Surface su( occface ); // tanal.Stop(); ttol.Start(); auto toltool = BRep_Tool::Tolerance( topods_face ); ttol.Stop(); // gp_Pnt2d suval = su->ValueOfUV ( pnt, toltool); t2.Start(); gp_Pnt2d suval = su->NextValueOfUV (gp_Pnt2d(u,v), pnt, toltool); t2.Stop(); 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; ap = occ2ng(pnt); // Point<3> (pnt.X(), pnt.Y(), pnt.Z()); } Meshing2OCCSurfaces :: Meshing2OCCSurfaces (const NetgenGeometry& geo, const TopoDS_Shape & asurf, const Box<3> & abb, int aprojecttype, const MeshingParameters & mparam) : Meshing2(geo, mparam, Box<3>(abb.PMin(), abb.PMax())), surface(TopoDS::Face(asurf), aprojecttype) { ; } void Meshing2OCCSurfaces :: DefineTransformation (const Point<3> & p1, const Point<3> & p2, const PointGeomInfo * geominfo1, const PointGeomInfo * geominfo2) { ((OCCSurface&)surface).DefineTangentialPlane (p1, *geominfo1, p2, *geominfo2); } void Meshing2OCCSurfaces :: TransformToPlain (const Point<3>& locpoint, const MultiPointGeomInfo & geominfo, Point<2> & planepoint, double h, int & zone) { surface.ToPlane (locpoint, geominfo.GetPGI(1), planepoint, h, zone); } int Meshing2OCCSurfaces :: TransformFromPlain (const Point<2> & planepoint, Point<3> & locpoint, PointGeomInfo & gi, double h) { surface.FromPlane (planepoint, locpoint, gi, h); return 0; } double Meshing2OCCSurfaces :: CalcLocalH (const Point<3> & p, double gh) const { return gh; } /* 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; } */ } #endif ================================================ FILE: libsrc/occ/occmeshsurf.hpp ================================================ #ifdef OCCGEOMETRY #ifndef FILE_OCCMESHSURF #define FILE_OCCMESHSURF #include "occgeom.hpp" #include "mydefs.hpp" #include #include #include #include #include #include #define PARAMETERSPACE -1 #define PLANESPACE 1 namespace netgen { class OCCGeometry; class SingularMatrixException {}; class UVBoundsException {}; class OCCSurface { public: TopoDS_Face topods_face; Handle(Geom_Surface) occface; TopAbs_Orientation orient; int projecttype; ShapeAnalysis_Surface su; Standard_Real toltool; 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)), su( occface ), toltool(BRep_Tool::Tolerance(topods_face)) { static Timer t("occurface ctor"); RegionTimer r(t); 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; // su = ShapeAnalysis_Surface( occface ); /* 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 NetgenGeometry& geo, const TopoDS_Shape & asurf, const Box<3> & aboundingbox, int aprojecttype, const MeshingParameters & mparam); /// int GetProjectionType () { return surface.projecttype; } protected: /// void DefineTransformation (const Point<3> & p1, const Point<3> & p2, const PointGeomInfo * geominfo1, const PointGeomInfo * geominfo2) override; /// void TransformToPlain (const Point<3> & locpoint, const MultiPointGeomInfo & geominfo, Point<2> & plainpoint, double h, int & zone) override; /// int TransformFromPlain (const Point<2> & plainpoint, Point<3> & locpoint, PointGeomInfo & gi, double h) override; /// double CalcLocalH (const Point<3> & p, double gh) const override; }; class OCCGeometry; } // namespace netgen #endif #endif ================================================ FILE: libsrc/occ/occpkg.cpp ================================================ #ifdef OCCGEOMETRY #include #include #include #include #include #include #include #include #include "../meshing/bcfunctions.hpp" #include "vsocc.hpp" #include #include // __declspec(dllimport) void AutoColourBcProps(Mesh & mesh, const char *bccolourfile); // __declspec(dllimport) void GetFaceColours(Mesh & mesh, NgArray & face_colours); // __declspec(dllimport) bool ColourMatch(Vec3d col1, Vec3d col2, double eps = 2.5e-05); extern "C" int Ng_occ_Init (Tcl_Interp * interp); namespace netgen { extern DLL_HEADER shared_ptr ng_geometry; extern DLL_HEADER shared_ptr mesh; extern DLL_HEADER MeshingParameters mparam; extern DLL_HEADER OCCParameters occparam; 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 (const filesystem::path & filename) const; virtual VisualScene * GetVisualScene (const NetgenGeometry * geom) const; virtual void SetParameters (Tcl_Interp * interp) { // occparam.resthminedgelen = // atof (Tcl_GetVar (interp, "::stloptions.resthminedgelen", 0)); // occparam.resthminedgelenenable = // atoi (Tcl_GetVar (interp, "::stloptions.resthminedgelenenable", 0)); if(auto geo = dynamic_pointer_cast(ng_geometry); geo) geo->SetOCCParameters(occparam); } }; int Ng_SetOCCVisParameters (ClientData clientData, Tcl_Interp * interp, int argc, tcl_const char *argv[]) { #ifdef OCCGEOMETRY int showvolume; OCCGeometry * occgeometry = dynamic_cast (ng_geometry.get()); showvolume = atoi (Tcl_GetVar (interp, "::occoptions.showvolumenr", 0)); if (occgeometry) if (showvolume != vispar.occshowvolumenr) { if (showvolume < 0 || showvolume > occgeometry->NrSolids()) { char buf[20]; snprintf (buf, size(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 (ng_geometry.get()); // 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 (ng_geometry.get()); 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 (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); auto txt = str.str(); char* cstr = (char*) txt.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 (ng_geometry.get()); 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, mparam); } } 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, mparam); } 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, mparam); } } if (strcmp (argv[1], "getsurfms") == 0) { int facenr = atoi (argv[2]); if (occgeometry && facenr >= 1 && facenr <= occgeometry->NrFaces()) { snprintf (buf, size(buf), "%5.2f", occgeometry->GetFaceMaxH(facenr)); } else { snprintf (buf, size(buf), "%5.2f", mparam.maxh); } Tcl_SetResult (interp, buf, TCL_STATIC); } if (strcmp (argv[1], "getactive") == 0) { snprintf (buf, size(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) snprintf (buf, size(buf), "%d", occgeometry->NrFaces()); else snprintf (buf, size(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) { 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; NgArray> face_colours; GetFaceColours(*mesh, face_colours); for(int i = 0; i < face_colours.Size();i++) { outVar << "{ " << face_colours[i][0] << " " << face_colours[i][1] << " " << face_colours[i][2] << " } "; } tcl_const char * valuevar = argv[2]; Tcl_SetVar (interp, valuevar, (char*)outVar.str().c_str(), 0); } if(strcmp(argv[1], "showalso") == 0) { NgArray> face_colours; GetFaceColours(*mesh,face_colours); int colourind = atoi (argv[2]); for(int i = 1; i <= mesh->GetNFD(); i++) { Array 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) { NgArray> face_colours; GetFaceColours(*mesh,face_colours); int colourind = atoi (argv[2]); for(int i = 1; i <= mesh->GetNFD(); i++) { Array 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) { NgArray> face_colours; GetFaceColours(*mesh,face_colours); int colourind = atoi (argv[2]); for(int i = 1; i <= mesh->GetNFD(); i++) { Array 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) { NgArray> face_colours; GetFaceColours(*mesh,face_colours); int colourind = atoi (argv[2]); for(int i = 1; i <= mesh->GetNFD(); i++) { Array 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); } */ for (auto & el : mesh->SurfaceElements()) el.Visible(1); mesh->SetNextTimeStamp(); } if(strcmp(argv[1], "hideall") == 0) { /* for(int i = 1; i <= mesh->GetNSE(); i++) { mesh->SurfaceElement(i).Visible(0); } */ for (auto & el : mesh->SurfaceElements()) el.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) { 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 (const filesystem::path & filename) const { string ext = ToLower(filename.extension()); if (ext == ".iges" || ext == ".igs") { PrintMessage (1, "Load IGES geometry file ", filename); OCCGeometry * occgeometry = LoadOCC_IGES (filename); return occgeometry; } else if (ext == ".stp" || ext == ".step") { PrintMessage (1, "Load STEP geometry file ", filename); OCCGeometry * occgeometry = LoadOCC_STEP (filename); return occgeometry; } else if (ext == ".brep") { PrintMessage (1, "Load BREP geometry file ", filename); OCCGeometry * occgeometry = LoadOCC_BREP (filename); return occgeometry; } return NULL; } static VisualSceneOCCGeometry vsoccgeom; VisualScene * OCCGeometryRegister :: GetVisualScene (const NetgenGeometry * geom) const { OCCGeometry * geometry = dynamic_cast (ng_geometry.get()); 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 ================================================ FILE: libsrc/occ/python_occ.cpp ================================================ #ifdef NG_PYTHON #ifdef OCCGEOMETRY #include #include #include #include #include #include "occgeom.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace netgen; namespace netgen { extern std::shared_ptr ng_geometry; extern std::shared_ptr mesh; } static string occparameter_description = R"delimiter( OCC Specific Meshing Parameters ------------------------------- closeedgefac: Optional[float] = 2. Factor for meshing close edges, if None it is disabled. minedgelen: Optional[float] = 0.001 Minimum edge length to be used for dividing edges to mesh points. If None this is disabled. )delimiter"; void CreateOCCParametersFromKwargs(OCCParameters& occparam, py::dict kwargs) { if(kwargs.contains("minedgelen")) { auto val = kwargs.attr("pop")("minedgelen"); if(val.is_none()) occparam.resthminedgelenenable = false; else { occparam.resthminedgelen = py::cast(val); occparam.resthminedgelenenable = true; } } } extern py::object CastShape(const TopoDS_Shape & s); DLL_HEADER void ExportNgOCCBasic(py::module &m); DLL_HEADER void ExportNgOCCShapes(py::module &m); DLL_HEADER void ExportNgOCC(py::module &m) { m.attr("occ_version") = OCC_VERSION_COMPLETE; // suppress info messages from occ (like statistics on Transfer) Message_Gravity aGravity = Message_Alarm; for (Message_SequenceOfPrinters::Iterator aPrinterIter (Message::DefaultMessenger()->Printers()); aPrinterIter.More(); aPrinterIter.Next()) { aPrinterIter.Value()->SetTraceLevel (aGravity); } ExportNgOCCBasic(m); ExportNgOCCShapes(m); static py::exception exc(m, "OCCException"); py::register_exception_translator([](std::exception_ptr p) { try { if(p) std::rethrow_exception(p); } catch (const Standard_Failure& e) { #if (PYBIND11_VERSION_MAJOR == 2 && PYBIND11_VERSION_MINOR < 12) exc((string(e.DynamicType()->Name()) + ": " + e.GetMessageString()).c_str()); #else py::set_error(PyExc_RuntimeError, (string(e.DynamicType()->Name()) + ": " + e.GetMessageString()).c_str()); #endif } }); py::class_, NetgenGeometry> (m, "OCCGeometry", R"raw_string(Use LoadOCCGeometry to load the geometry from a *.step file.)raw_string") /* .def(py::init(), py::arg("shape"), "Create Netgen OCCGeometry from existing TopoDS_Shape") */ .def(py::init([] (const TopoDS_Shape& shape, int occdim, bool copy) { auto geo = make_shared (shape, occdim, copy); // ng_geometry = geo; // geo->BuildFMap(); // geo->CalcBoundingBox(); return geo; }), py::arg("shape"), py::arg("dim")=3, py::arg("copy")=false, "Create Netgen OCCGeometry from existing TopoDS_Shape") .def(py::init([] (const std::vector shapes) { BOPAlgo_Builder builder; for (auto & s : shapes) builder.AddArgument(s); builder.Perform(); for(auto& s : shapes) PropagateProperties(builder, s); auto geo = make_shared (builder.Shape()); ng_geometry = geo; // geo->BuildFMap(); // geo->CalcBoundingBox(); return geo; }), py::arg("shape"), "Create Netgen OCCGeometry from existing TopoDS_Shape") .def(py::init([] (const string& filename, int dim) { shared_ptr geo; if(EndsWith(filename, ".step") || EndsWith(filename, ".stp")) geo.reset(LoadOCC_STEP(filename)); else if(EndsWith(filename, ".brep")) geo.reset(LoadOCC_BREP(filename)); else if(EndsWith(filename, ".iges")) geo.reset(LoadOCC_IGES(filename)); else throw Exception("Cannot load file " + filename + "\nValid formats are: step, stp, brep, iges"); if(dim<3) geo->SetDimension(dim); ng_geometry = geo; return geo; }), py::arg("filename"), py::arg("dim")=3, "Load OCC geometry from step, brep or iges file") .def(NGSPickle()) .def("Glue", &OCCGeometry::GlueGeometry) .def("Heal",[](OCCGeometry & self, double tolerance, bool fixsmalledges, bool fixspotstripfaces, bool sewfaces, bool makesolids, bool splitpartitions) { self.tolerance = tolerance; self.fixsmalledges = fixsmalledges; self.fixspotstripfaces = fixspotstripfaces; self.sewfaces = sewfaces; self.makesolids = makesolids; self.splitpartitions = splitpartitions; self.HealGeometry(); self.BuildFMap(); },py::arg("tolerance")=1e-3, py::arg("fixsmalledges")=true, py::arg("fixspotstripfaces")=true, py::arg("sewfaces")=true, py::arg("makesolids")=true, py::arg("splitpartitions")=false,R"raw_string(Heal the OCCGeometry.)raw_string",py::call_guard()) .def("SetFaceMeshsize", [](OCCGeometry& self, size_t fnr, double meshsize) { self.SetFaceMaxH(fnr, meshsize); }, "Set maximum meshsize for face fnr. Face numbers are 0 based.") .def("Draw", [](shared_ptr geo) { ng_geometry = geo; }) .def_property_readonly("solids", [](shared_ptr geo) { ListOfShapes solids; for (int i = 1; i <= geo->somap.Extent(); i++) solids.push_back(geo->somap(i)); return solids; }, "Get solids in order that they will be in the mesh") .def_property_readonly("faces", [](shared_ptr geo) { ListOfShapes faces; for (int i = 1; i <= geo->fmap.Extent(); i++) faces.push_back(geo->fmap(i)); return faces; }, "Get faces in order that they will be in the mesh") .def_property_readonly("edges", [](shared_ptr geo) { ListOfShapes edges; for (int i = 1; i <= geo->emap.Extent(); i++) edges.push_back(geo->emap(i)); return edges; }, "Get edges in order that they will be in the mesh") .def_property_readonly("vertices", [](shared_ptr geo) { ListOfShapes vertices; for (int i = 1; i <= geo->vmap.Extent(); i++) vertices.push_back(geo->vmap(i)); return vertices; }, "Get vertices in order that they will be in the mesh") .def("_visualizationData", [] (shared_ptr occ_geo) { std::vector vertices; std::vector indices; std::vector edges; std::vector edge_indices; std::vector normals; std::vector min = {std::numeric_limits::max(), std::numeric_limits::max(), std::numeric_limits::max()}; std::vector max = {std::numeric_limits::lowest(), std::numeric_limits::lowest(), std::numeric_limits::lowest()}; std::vector face_colors; std::vector edge_colors; auto box = occ_geo->GetBoundingBox(); for(int i = 0; i < 3; i++) { min[i] = box.PMin()[i]; max[i] = box.PMax()[i]; } occ_geo->BuildVisualizationMesh(0.01); gp_Pnt2d uv; gp_Pnt pnt; gp_Vec n; gp_Pnt p[3]; for(int edge_index = 1; edge_index <= occ_geo->emap.Extent(); edge_index++) { auto edge = TopoDS::Edge(occ_geo->emap(edge_index)); if(OCCGeometry::HaveProperties(edge)) { const auto& props = OCCGeometry::GetProperties(edge); if(props.col) edge_colors.insert(edge_colors.end(), {float((*props.col)[0]), float((*props.col)[1]), float((*props.col)[2]), float((*props.col)[3])}); else edge_colors.insert(edge_colors.end(),{0.f,0.f,0.f,1.f}); } else { edge_colors.insert(edge_colors.end(),{0.f,0.f,0.f,1.f}); } Handle(Poly_PolygonOnTriangulation) poly; Handle(Poly_Triangulation) T; TopLoc_Location loc; BRep_Tool::PolygonOnTriangulation(edge, poly, T, loc); if(poly.IsNull()) { cout << IM(2) << "No polygon on triangulation for edge " << edge_index << endl; BRepAdaptor_Curve adapt_crv = BRepAdaptor_Curve(edge); GCPnts_TangentialDeflection discretizer; discretizer.Initialize(adapt_crv, 0.09, 0.01); if (discretizer.NbPoints() > 1) { for (int j = 1; j <= discretizer.NbPoints()-1; ++j) { gp_Pnt p_0 = discretizer.Value(j); gp_Pnt p_1 = discretizer.Value(j+1); edges.insert(edges.end(), {float(p_0.X()), float(p_0.Y()), float(p_0.Z()), float(p_1.X()), float(p_1.Y()), float(p_1.Z())}); edge_indices.push_back(uint32_t(edge_index-1)); } } } else { int nbnodes = poly -> NbNodes(); for (int j = 1; j < nbnodes; j++) { auto p0 = occ2ng((T -> Node(poly->Nodes()(j))).Transformed(loc)); auto p1 = occ2ng((T -> Node(poly->Nodes()(j+1))).Transformed(loc)); for(auto k : Range(3)) edges.push_back(p0[k]); for(auto k : Range(3)) edges.push_back(p1[k]); edge_indices.push_back(uint32_t(edge_index-1)); box.Add(p0); box.Add(p1); } } } for (int i = 1; i <= occ_geo->fmap.Extent(); i++) { auto face = TopoDS::Face(occ_geo->fmap(i)); if (OCCGeometry::HaveProperties(face)) { const auto& props = OCCGeometry::GetProperties(face); if(props.col) face_colors.insert(face_colors.end(), {float((*props.col)[0]), float((*props.col)[1]), float((*props.col)[2]), float((*props.col)[3])}); else { face_colors.insert(face_colors.end(),{0.7,0.7,0.7,1.}); } } else { face_colors.insert(face_colors.end(),{0.7,0.7,0.7,1.}); } auto surf = BRep_Tool::Surface(face); TopLoc_Location loc; 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; indices.reserve(indices.size() + triangulation->NbTriangles()); vertices.reserve(vertices.size() + triangulation->NbTriangles()*3*3); normals.reserve(normals.size() + triangulation->NbTriangles()*3*3); for (int j = 1; j < triangulation->NbTriangles()+1; j++) { auto triangle = triangulation->Triangle(j); for (int k = 1; k < 4; k++) p[k-1] = triangulation->Node(triangle(k)).Transformed(loc); indices.push_back(uint32_t(i-1)); for (int k = 1; k < 4; k++) { vertices.insert(vertices.end(),{ float(p[k-1].X()), float(p[k-1].Y()), float(p[k-1].Z())}); uv = triangulation->UVNode(triangle(k)); prop.SetParameters(uv.X(), uv.Y()); if (prop.IsNormalDefined()) n = prop.Normal(); else { gp_Vec a(p[0], p[1]); gp_Vec b(p[0], p[2]); n = b^a; } if (face.Orientation() == TopAbs_REVERSED) n*= -1; normals.insert(normals.end(),{float(n.X()), float(n.Y()), float(n.Z())}); } } } py::gil_scoped_acquire ac; py::dict res; py::list snames; res["vertices"] = MoveToNumpy(vertices); res["edges"] = MoveToNumpy(edges); res["edge_indices"] = MoveToNumpy(edge_indices); res["edge_colors"] = MoveToNumpy(edge_colors); res["indices"] = MoveToNumpy(indices); res["normals"] = MoveToNumpy(normals); res["face_colors"] = MoveToNumpy(face_colors); res["min"] = MoveToNumpy(min); res["max"] = MoveToNumpy(max); return res; }, py::call_guard()) .def("GenerateMesh", [](shared_ptr geo, MeshingParameters* pars, NgMPI_Comm comm, shared_ptr mesh, py::kwargs kwargs) { MeshingParameters mp; OCCParameters occparam; if(pars) { auto mp_kwargs = CreateDictFromFlags(pars->geometrySpecificParameters); CreateOCCParametersFromKwargs(occparam, mp_kwargs); mp = *pars; } CreateOCCParametersFromKwargs(occparam, kwargs); CreateMPfromKwargs(mp, kwargs); py::gil_scoped_release gil_release; geo->SetOCCParameters(occparam); if(!mesh) mesh = make_shared(); mesh->SetCommunicator(comm); mesh->SetGeometry(geo); if (comm.Rank()==0) { SetGlobalMesh(mesh); auto result = geo->GenerateMesh(mesh, mp); if(result != 0) { netgen::mesh = mesh; // keep mesh for debugging throw Exception("Meshing failed!"); } ng_geometry = geo; if (comm.Size() > 1) mesh->Distribute(); } else { mesh->SendRecvMesh(); } return mesh; }, py::arg("mp") = nullptr, py::arg("comm")=NgMPI_Comm{}, py::arg("mesh")=nullptr, (meshingparameter_description + occparameter_description).c_str()) .def_property_readonly("shape", [](const OCCGeometry & self) { return self.GetShape(); }) ; m.def("LoadOCCGeometry",[] (filesystem::path filename) { cout << "WARNING: LoadOCCGeometry is deprecated! Just use the OCCGeometry(filename) constructor. It is able to read brep and iges files as well!" << endl; ifstream ist(filename); OCCGeometry * instance = new OCCGeometry(); instance = LoadOCC_STEP(filename.c_str()); ng_geometry = shared_ptr(instance, NOOP_Deleter); return ng_geometry; },py::call_guard()); m.def("TestXCAF", [] (TopoDS_Shape shape) { /*static*/ Handle(XCAFApp_Application) app = XCAFApp_Application::GetApplication(); cout << endl << endl << endl; cout << "app = " << *reinterpret_cast(&app) << endl; Handle(TDocStd_Document) doc; cout << "nbdocs = " << app->NbDocuments() << endl; if(app->NbDocuments() > 0) { app->GetDocument(1,doc); // app->Close(doc); } else app->NewDocument ("STEP-XCAF",doc); Handle(XCAFDoc_ShapeTool) shape_tool = XCAFDoc_DocumentTool::ShapeTool(doc->Main()); Handle(XCAFDoc_MaterialTool) material_tool = XCAFDoc_DocumentTool::MaterialTool(doc->Main()); // Handle(XCAFDoc_VisMaterialTool) vismaterial_tool = XCAFDoc_DocumentTool::VisMaterialTool(doc->Main()); // TDF_LabelSequence doc_shapes; // shape_tool->GetShapes(doc_shapes); // cout << "shape tool nbentities: " << doc_shapes.Size() << endl; TDF_Label label = shape_tool -> FindShape(shape); cout << "shape label = " << endl << label << endl; if (label.IsNull()) return; cout << "nbattr = " << label.NbAttributes() << endl; if (!label.IsNull()) { Handle(TDF_Attribute) attribute; cout << "create guid" << endl; // Standard_GUID guid("c4ef4200-568f-11d1-8940-080009dc3333"); Standard_GUID guid("2a96b608-ec8b-11d0-bee7-080009dc3333"); cout << "have guid" << endl; cout << "find attrib " << label.FindAttribute(guid, attribute) << endl; cout << "attrib = " << attribute << endl; cout << "tag = " << label.Tag() << endl; cout << "father.tag = " << label.Father().Tag() << endl; cout << "Data = " << label.Data() << endl; cout << "nbchild = " << label.NbChildren() << endl; for (auto i : Range(label.NbChildren())) { TDF_Label child = label.FindChild(i+1); cout << "child[" << i << "] = " << child << endl; cout << "find attrib " << child.FindAttribute(guid, attribute) << endl; cout << "attrib = " << attribute << endl; } // cout << "findshape = " << shape_tool -> FindShape(shape) << endl; cout << "IsMaterial = " << material_tool->IsMaterial(label) << endl; // cout << "IsVisMaterial = " << vismaterial_tool->IsMaterial(label) << endl; } }, py::arg("shape")=TopoDS_Shape()); } PYBIND11_MODULE(libNgOCC, m) { ExportNgOCC(m); } #endif // OCCGEOMETRY #endif // NG_PYTHON ================================================ FILE: libsrc/occ/python_occ_basic.cpp ================================================ #ifdef NG_PYTHON #ifdef OCCGEOMETRY #include #include #include #include #include "occgeom.hpp" #include #include #include #include #include #include #include #include using namespace netgen; DLL_HEADER void ExportNgOCCBasic(py::module &m) { py::class_(m, "gp_Pnt", "3d OCC point") .def(py::init([] (py::tuple pnt) { if (py::len(pnt) != 3) throw std::length_error("need 3-tuple to create gp_Pnt"); return gp_Pnt(py::cast(pnt[0]), py::cast(pnt[1]), py::cast(pnt[2])); })) .def(py::init([] (double x, double y, double z) { return gp_Pnt(x, y, z); }), py::arg("x"), py::arg("y"), py::arg("z")) .def_property("x", [](gp_Pnt&p) { return p.X(); }, [](gp_Pnt&p,double x) { p.SetX(x); }) .def_property("y", [](gp_Pnt&p) { return p.Y(); }, [](gp_Pnt&p,double y) { p.SetY(y); }) .def_property("z", [](gp_Pnt&p) { return p.Z(); }, [](gp_Pnt&p,double z) { p.SetZ(z); }) .def("__str__", [] (const gp_Pnt & p) { stringstream str; str << "(" << p.X() << ", " << p.Y() << ", " << p.Z() << ")"; return str.str(); }) .def("__repr__", [] (const gp_Pnt & p) { stringstream str; str << "(" << p.X() << ", " << p.Y() << ", " << p.Z() << ")"; return str.str(); }) .def("__sub__", [](gp_Pnt p1, gp_Pnt p2) { return gp_Vec(p2, p1); }) .def("__add__", [](gp_Pnt p, gp_Vec v) { return p.Translated(v); }) // gp_Pnt(p.X()+v.X(), p.Y()+v.Y(), p.Z()+v.Z()); }) .def("__sub__", [](gp_Pnt p, gp_Vec v) { return p.Translated(-v); }) // gp_Pnt(p.X()-v.X(), p.Y()-v.Y(), p.Z()-v.Z()); }) .def("__getitem__", [](const gp_Pnt& p, int index) { if(index == 0) return p.X(); if(index == 1) return p.Y(); if(index == 2) return p.Z(); throw std::out_of_range("Point index must be in range [0,3)!"); }) ; py::class_(m, "gp_Vec", "3d OCC vector") .def(py::init([] (py::tuple vec) { return gp_Vec(py::cast(vec[0]), py::cast(vec[1]), py::cast(vec[2])); })) .def(py::init([] (double x, double y, double z) { return gp_Vec(x, y, z); }), py::arg("x"), py::arg("y"), py::arg("z")) .def(py::init([](gp_Dir d) { return gp_Vec(d); })) .def_property("x", [](gp_Vec&p) { return p.X(); }, [](gp_Vec&p,double x) { p.SetX(x); }) .def_property("y", [](gp_Vec&p) { return p.Y(); }, [](gp_Vec&p,double y) { p.SetY(y); }) .def_property("z", [](gp_Vec&p) { return p.Z(); }, [](gp_Vec&p,double z) { p.SetZ(z); }) .def("Norm", [](const gp_Vec& v) { return v.Magnitude(); }) .def("__str__", [] (const gp_Vec & p) { stringstream str; str << "(" << p.X() << ", " << p.Y() << ", " << p.Z() << ")"; return str.str(); }) .def("__repr__", [] (const gp_Vec & p) { stringstream str; str << "(" << p.X() << ", " << p.Y() << ", " << p.Z() << ")"; return str.str(); }) .def("__add__", [](gp_Vec v1, gp_Vec v2) { return v1+v2; }) .def("__sub__", [](gp_Vec v1, gp_Vec v2) { return v1-v2; }) .def("__rmul__", [](gp_Vec v, double s) { return s*v; }) .def("__mul__", [](gp_Vec v1, gp_Vec v2) { return v1*v2; }) .def("__neg__", [](gp_Vec v) { return -v; }) .def("__xor__", [](gp_Vec v1, gp_Vec v2) { return v1^v2; }) .def("__lt__", [](gp_Vec v, double val) { cout << IM(6) << "vec, lt v - " << netgen::occ2ng(v) << ", val = " << val << endl; return DirectionalInterval(v) < val; }) .def("__gt__", [](gp_Vec v, double val) { cout << IM(6) << "vec, gt v - " << netgen::occ2ng(v) << ", val = " << val << endl; return DirectionalInterval(v) > val; }) .def("__le__", [](gp_Vec v, double val) { return DirectionalInterval(v) <= val; }) .def("__ge__", [](gp_Vec v, double val) { return DirectionalInterval(v) >= val; }) ; py::class_(m, "gp_Dir", "3d OCC direction") .def(py::init([] (py::tuple dir) { return gp_Dir(py::cast(dir[0]), py::cast(dir[1]), py::cast(dir[2])); })) .def(py::init([] (double x, double y, double z) { return gp_Dir(x, y, z); }), py::arg("x"), py::arg("y"), py::arg("z")) .def(py::init()) .def("__str__", [] (const gp_Dir & p) { stringstream str; str << "(" << p.X() << ", " << p.Y() << ", " << p.Z() << ")"; return str.str(); }) .def("__getitem__", [](const gp_Dir& d, int index) { if(index == 0) return d.X(); if(index == 1) return d.Y(); if(index == 2) return d.Z(); throw std::out_of_range("Direction index must be in range [0,3)!"); }) ; py::class_(m, "gp_Mat", "3d OCC matrix") .def("__getitem__", [](const gp_Mat& mat, tuple index) { return mat.Row(get<0>(index)+1).Coord(get<1>(index)+1); }) ; py::class_(m, "Axis", "an OCC axis in 3d") .def(py::init([](gp_Pnt p, gp_Dir d) { return gp_Ax1(p,d); }), py::arg("p"), py::arg("d")) ; py::class_(m, "gp_Ax2") .def(py::init([](gp_Pnt p, gp_Dir d) { return gp_Ax2(p,d); })) .def(py::init([](const gp_Ax3 & ax3) { return gp_Ax2(ax3.Ax2()); })) ; py::class_(m, "Axes", "an OCC coordinate system in 3d") .def(py::init([](gp_Pnt p, gp_Dir N, gp_Dir Vx) { return gp_Ax3(p,N, Vx); }), py::arg("p")=gp_Pnt(0,0,0), py::arg("n")=gp_Vec(0,0,1), py::arg("h")=gp_Vec(1,0,0)) .def(py::init([](gp_Ax1 ax1) { return gp_Ax3(ax1.Location(), ax1.Direction()); }), py::arg("axis")) .def(py::init()) .def_property("p", [](gp_Ax3 & ax) { return ax.Location(); }, [](gp_Ax3&ax, gp_Pnt p) { ax.SetLocation(p); }) ; py::class_(m, "gp_Pnt2d", "2d OCC point") .def(py::init([] (std::tuple pnt) { return gp_Pnt2d(get<0>(pnt), get<1>(pnt)); })) .def(py::init([] (double x, double y) { return gp_Pnt2d(x, y); }), py::arg("x"), py::arg("y")) .def_property("x", [](gp_Pnt2d&p) { return p.X(); }, [](gp_Pnt2d&p,double x) { p.SetX(x); }) .def_property("y", [](gp_Pnt2d&p) { return p.Y(); }, [](gp_Pnt2d&p,double y) { p.SetY(y); }) .def("__str__", [] (const gp_Pnt2d & p) { stringstream str; str << "(" << p.X() << ", " << p.Y() << ")"; return str.str(); }) .def("__repr__", [] (const gp_Pnt2d & p) { stringstream str; str << "(" << p.X() << ", " << p.Y() << ")"; return str.str(); }) .def("__sub__", [](gp_Pnt2d p1, gp_Pnt2d p2) { return gp_Vec2d(p1.X()-p2.X(), p1.Y()-p2.Y()); }) .def("__add__", [](gp_Pnt2d p, gp_Vec2d v) { return p.Translated(v); }) .def("__sub__", [](gp_Pnt2d p, gp_Vec2d v) { return p.Translated(-v); }) ; py::class_(m, "gp_Vec2d", "2d OCC vector") .def(py::init([] (py::tuple vec) { if (py::len(vec) != 2) throw Exception("need 2-tuple to create gp_Vec2d"); return gp_Vec2d(py::cast(vec[0]), py::cast(vec[1])); })) .def(py::init([] (double x, double y) { return gp_Vec2d(x, y); }), py::arg("x"), py::arg("y")) .def_property("x", [](gp_Vec2d&p) { return p.X(); }, [](gp_Vec2d&p,double x) { p.SetX(x); }) .def_property("y", [](gp_Vec2d&p) { return p.Y(); }, [](gp_Vec2d&p,double y) { p.SetY(y); }) .def("__str__", [] (const gp_Vec & p) { stringstream str; str << "(" << p.X() << ", " << p.Y() << ")"; return str.str(); }) .def("__repr__", [] (const gp_Vec & p) { stringstream str; str << "(" << p.X() << ", " << p.Y() << ")"; return str.str(); }) .def("__add__", [](gp_Vec2d v1, gp_Vec2d v2) { return v1+v2; }) .def("__sub__", [](gp_Vec2d v1, gp_Vec2d v2) { return v1-v2; }) .def("__rmul__", [](gp_Vec2d v, double s) { return s*v; }) .def("__neg__", [](gp_Vec2d v) { return -v; }) .def("__xor__", [](gp_Vec2d v1, gp_Vec2d v2) { return v1^v2; }) ; py::class_(m, "gp_Dir2d", "2d OCC direction") .def(py::init([] (py::tuple dir) { if (py::len(dir) != 2) throw Exception("need 2-tuple to create gp_Dir2d"); return gp_Dir2d(py::cast(dir[0]), py::cast(dir[1])); })) .def(py::init([] (double x, double y) { return gp_Dir2d(x, y); }), py::arg("x"), py::arg("y")) ; m.def("Pnt", [](double x, double y) { return gp_Pnt2d(x,y); }, py::arg("x"), py::arg("y"), "create 2d OCC point"); m.def("Pnt", [](double x, double y, double z) { return gp_Pnt(x,y,z); }, py::arg("x"), py::arg("y"), py::arg("z"), "create 3d OCC point"); m.def("Pnt", [](std::vector p) { if (p.size() == 2) return py::cast(gp_Pnt2d(p[0], p[1])); if (p.size() == 3) return py::cast(gp_Pnt(p[0], p[1], p[2])); throw Exception("OCC-Points only in 2D or 3D"); }, py::arg("p"), "create 2d or 3d OCC point"); m.def("Vec", [](double x, double y) { return gp_Vec2d(x,y); }, py::arg("x"), py::arg("y"), "create 2d OCC point"); m.def("Vec", [](double x, double y, double z) { return gp_Vec(x,y,z); }, py::arg("x"), py::arg("y"), py::arg("z"), "create 3d OCC point"); m.def("Vec", [](std::vector p) { if (p.size() == 2) return py::cast(gp_Vec2d(p[0], p[1])); if (p.size() == 3) return py::cast(gp_Vec(p[0], p[1], p[2])); throw Exception("OCC-Vecs only in 2D or 3D"); }, py::arg("v"), "create 2d or 3d OCC vector"); m.def("Dir", [](double x, double y) { return gp_Dir2d(x,y); }, py::arg("x"), py::arg("y"), "create 2d OCC direction"); m.def("Dir", [](double x, double y, double z) { return gp_Dir(x,y,z); }, py::arg("x"), py::arg("y"), py::arg("z"), "create 3d OCC direction"); m.def("Dir", [](std::vector p) { if (p.size() == 2) return py::cast(gp_Dir2d(p[0], p[1])); if (p.size() == 3) return py::cast(gp_Dir(p[0], p[1], p[2])); throw Exception("OCC-Dirs only in 2D or 3D"); }, py::arg("d"), "create 2d or 3d OCC direction"); py::class_(m, "gp_Ax2d", "2d OCC coordinate system") .def(py::init([](gp_Pnt2d p, gp_Dir2d d) { return gp_Ax2d(p,d); }), py::arg("p")=gp_Pnt2d(0,0), py::arg("d")=gp_Dir2d(1,0)) ; py::class_(m, "gp_GTrsf") .def(py::init([](const std::vector& mat, const std::vector& vec) { if(mat.size() != 9) throw Exception("Need 9 matrix values for construction of gp_GTrsf"); if(vec.size() != 3) throw Exception("Need 3 vector values for construction of gp_GTrsf"); gp_GTrsf trafo; trafo.SetVectorialPart({ mat[0], mat[1], mat[2], mat[3], mat[4], mat[5], mat[6], mat[7], mat[8] }); trafo.SetTranslationPart( { vec[0], vec[1], vec[2] }); return trafo; }), py::arg("mat"), py::arg("vec") = std::vector{ 0., 0., 0. }) .def("__call__", [] (gp_GTrsf & trafo, const TopoDS_Shape & shape) { BRepBuilderAPI_GTransform builder(shape, trafo, true); PropagateProperties(builder, shape, occ2ng(trafo)); return builder.Shape(); }) ; py::class_(m, "gp_Trsf") .def(py::init<>()) .def("SetMirror", [] (gp_Trsf & trafo, const gp_Ax1 & ax) { trafo.SetMirror(ax); return trafo; }) .def("Inverted", &gp_Trsf::Inverted) .def_static("Translation", [] (const gp_Vec & v) { gp_Trsf trafo; trafo.SetTranslation(v); return trafo; }) .def_static("Scale", [] (const gp_Pnt & p, double s) { gp_Trsf trafo; trafo.SetScale(p,s); return trafo; }) .def_static("Mirror", [] (const gp_Ax1 & ax) { gp_Trsf trafo; trafo.SetMirror(ax); return trafo; }) .def_static("Rotation", [] (const gp_Ax1 & ax, double ang) { gp_Trsf trafo; trafo.SetRotation(ax, ang*M_PI/180); return trafo; }) .def_static("Rotation", [] (const gp_Pnt & p, const gp_Dir & d, double ang) { gp_Trsf trafo; trafo.SetRotation(gp_Ax1(p,d), ang*M_PI/180); return trafo; }) .def_static("Transformation", [] (const gp_Ax3 & ax) { gp_Trsf trafo; trafo.SetTransformation(ax); return trafo; }) .def_static("Transformation", [] (const gp_Ax3 & from, const gp_Ax3 to) { gp_Trsf trafo; trafo.SetTransformation(from, to); return trafo; }) .def(py::self * py::self) .def("__call__", [] (gp_Trsf & trafo, const TopoDS_Shape & shape) { BRepBuilderAPI_Transform builder(shape, trafo, true); PropagateProperties(builder, shape, occ2ng(trafo)); return builder.Shape(); }) .def("__str__", [](gp_Trsf & trafo) { stringstream str; gp_XYZ xyz = trafo.TranslationPart(); str << xyz.X() << ", " << xyz.Y() << ", " << xyz.Z(); return str.str(); }) ; py::class_(m, "TopLoc_Location") .def(py::init()) .def("Transformation", [](const TopLoc_Location & loc) { return loc.Transformation(); }) ; py::class_ (m, "DirectionalInterval") .def("__str__", [](DirectionalInterval self) { stringstream str; str << "(" << self.minval << ", " << self.maxval << ")"; return str.str(); }) .def("__lt__", [](DirectionalInterval i, double val) { cout << "directionalinterval, lt, imin/max = " << i.minval << " / " << i.maxval << endl; return i < val; }) .def("__gt__", [](DirectionalInterval i, double val) { cout << "directionalinterval, gt, imin/max = " << i.minval << " / " << i.maxval << endl; return i > val; }) .def("__and__", [](DirectionalInterval self, DirectionalInterval other) { cout << "and of intervals" << endl; return self.Intersect(other); }) ; py::implicitly_convertible(); py::implicitly_convertible(); py::implicitly_convertible(); py::implicitly_convertible(); py::implicitly_convertible(); py::implicitly_convertible(); py::implicitly_convertible(); py::implicitly_convertible(); py::implicitly_convertible(); py::implicitly_convertible(); py::implicitly_convertible(); m.attr("X") = py::cast(gp_Vec(1,0,0)); m.attr("Y") = py::cast(gp_Vec(0,1,0)); m.attr("Z") = py::cast(gp_Vec(0,0,1)); } #endif // OCCGEOMETRY #endif // NG_PYTHON ================================================ FILE: libsrc/occ/python_occ_shapes.cpp ================================================ #include #ifdef NG_PYTHON #ifdef OCCGEOMETRY #include #include #include #include #include #include "occgeom.hpp" #include "occ_utils.hpp" #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" #if NETGEN_OCC_VERSION_AT_LEAST(7, 6) #include #endif // NETGEN_OCC_VERSION_AT_LEAST(7, 6) #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #pragma clang diagnostic pop using namespace netgen; void ExtractEdgeData( const TopoDS_Edge & edge, int index, std::vector * p, Box<3> & box ) { if (BRep_Tool::Degenerated(edge)) return; Handle(Poly_PolygonOnTriangulation) poly; Handle(Poly_Triangulation) T; TopLoc_Location loc; BRep_Tool::PolygonOnTriangulation(edge, poly, T, loc); if (poly.IsNull()) { cout << IM(2) << "no edge mesh, do my own sampling" << endl; double s0, s1; Handle(Geom_Curve) c = BRep_Tool::Curve(edge, s0, s1); constexpr int num = 100; for (int i = 0; i < num; i++) { auto p0 = occ2ng(c->Value (s0 + i*(s1-s0)/num)); auto p1 = occ2ng(c->Value (s0 + (i+1)*(s1-s0)/num)); for(auto k : Range(3)) { p[0].push_back(p0[k]); p[1].push_back(p1[k]); } p[0].push_back(index); p[1].push_back(index); box.Add(p0); box.Add(p1); } return; } int nbnodes = poly -> NbNodes(); for (int j = 1; j < nbnodes; j++) { auto p0 = occ2ng((T -> Node(poly->Nodes()(j))).Transformed(loc)); auto p1 = occ2ng((T -> Node(poly->Nodes()(j+1))).Transformed(loc)); for(auto k : Range(3)) { p[0].push_back(p0[k]); p[1].push_back(p1[k]); } p[0].push_back(index); p[1].push_back(index); box.Add(p0); box.Add(p1); } } void ExtractFaceData( const TopoDS_Face & face, int index, std::vector * p, std::vector * n, Box<3> & box ) { TopLoc_Location loc; Handle(Poly_Triangulation) triangulation = BRep_Tool::Triangulation (face, loc); Handle(Geom_Surface) surf = BRep_Tool::Surface (face); BRepAdaptor_Surface sf(face, Standard_False); BRepLProp_SLProps prop(sf, 1, 1e-5); bool flip = TopAbs_REVERSED == face.Orientation(); if (triangulation.IsNull()) { cout << "pls build face triangulation before" << endl; return; } int ntriangles = triangulation -> NbTriangles(); for (int j = 1; j <= ntriangles; j++) { Poly_Triangle triangle = triangulation -> Triangle(j); std::array,3> pts; std::array,3> normals; for (int k = 0; k < 3; k++) pts[k] = occ2ng( (triangulation -> Node(triangle(k+1))).Transformed(loc) ); for (int k = 0; k < 3; k++) { auto uv = triangulation -> UVNode(triangle(k+1)); prop.SetParameters (uv.X(), uv.Y()); if (prop.IsNormalDefined()) normals[k] = occ2ng (prop.Normal()); else normals[k] = Cross(pts[1]-pts[0], pts[2]-pts[0]); } if(flip) { Swap(pts[1], pts[2]); Swap(normals[1], normals[2]); for (int k = 0; k < 3; k++) normals[k] = -normals[k]; } for (int k = 0; k < 3; k++) { box.Add(pts[k]); for (int d = 0; d < 3; d++) { p[k].push_back( pts[k][d] ); n[k].push_back( normals[k][d] ); } p[k].push_back( index ); } } } py::object CastShape(const TopoDS_Shape & s) { switch (s.ShapeType()) { case TopAbs_VERTEX: return py::cast(TopoDS::Vertex(s)); case TopAbs_FACE: return py::cast(TopoDS::Face(s)); case TopAbs_EDGE: return py::cast(TopoDS::Edge(s)); case TopAbs_WIRE: return py::cast(TopoDS::Wire(s)); case TopAbs_COMPOUND: case TopAbs_COMPSOLID: case TopAbs_SOLID: case TopAbs_SHELL: case TopAbs_SHAPE: return py::cast(s); } throw Exception("Invalid Shape type"); }; namespace netgen { TopoDS_Shape CrossSection(const TopoDS_Shape & shape, const gp_Ax3 & axis); } class WorkPlane : public enable_shared_from_this { gp_Ax3 axes; gp_Ax2d localpos; gp_Pnt2d startpnt; TopoDS_Vertex lastvertex, startvertex; Handle(Geom_Surface) surf; // Geom_Plane surf; BRepBuilderAPI_MakeWire wire_builder; std::vector wires; public: WorkPlane (const gp_Ax3 & _axes, const gp_Ax2d _localpos = gp_Ax2d()) : axes(_axes), localpos(_localpos) // , surf(_axis) { // surf = GC_MakePlane (gp_Ax1(axis.Location(), axis.Direction())); surf = new Geom_Plane(axes); } auto Finish() { if (!startvertex.IsNull()) { wires.push_back (wire_builder.Wire()); wire_builder = BRepBuilderAPI_MakeWire(); startvertex.Nullify(); } return shared_from_this(); } auto StartPnt() const { return startpnt; } auto CurrentLocation() const { return localpos.Location(); } auto CurrentDirection() const { return gp_Vec2d(localpos.Direction()); } auto MoveTo (double h, double v) { startpnt = gp_Pnt2d(h,v); localpos.SetLocation(startpnt); startvertex.Nullify(); return shared_from_this(); } auto Move(double len) { gp_Dir2d dir = localpos.Direction(); gp_Pnt2d oldp = localpos.Location(); auto newp = oldp.Translated(len*dir); return MoveTo(newp.X(), newp.Y()); } auto Direction (double h, double v) { localpos.SetDirection(gp_Dir2d(h,v)); return shared_from_this(); } auto LineTo (double h, double v, optional name = nullopt) { gp_Pnt2d old2d = localpos.Location(); gp_Pnt oldp = axes.Location() . Translated(old2d.X() * axes.XDirection() + old2d.Y() * axes.YDirection()); // localpos.Translate (gp_Vec2d(h,v)); localpos.SetLocation (gp_Pnt2d(h,v)); gp_Pnt2d new2d = localpos.Location(); gp_Pnt newp = axes.Location() . Translated(new2d.X() * axes.XDirection() + new2d.Y() * axes.YDirection()); if (new2d.Distance(old2d) < 1e-10) return shared_from_this(); bool closing = new2d.Distance(startpnt) < 1e-10; cout << IM(6) << "lineto, oldp = " << occ2ng(oldp) << endl; cout << IM(6) << "lineto, newp = " << occ2ng(newp) << endl; gp_Pnt pfromsurf = surf->Value(new2d.X(), new2d.Y()); cout << IM(6) << "p from plane = " << occ2ng(pfromsurf) << endl; Handle(Geom_TrimmedCurve) curve = GC_MakeSegment(oldp, newp); if (startvertex.IsNull()) startvertex = lastvertex = BRepBuilderAPI_MakeVertex(oldp); auto endv = closing ? startvertex : BRepBuilderAPI_MakeVertex(newp); // liefert noch Fehler bei close auto edge = BRepBuilderAPI_MakeEdge(curve, lastvertex, endv).Edge(); lastvertex = endv; // auto edge = BRepBuilderAPI_MakeEdge(curve).Edge(); if (name) OCCGeometry::GetProperties(edge).name = name; wire_builder.Add(edge); if (closing) Finish(); return shared_from_this(); } auto Line(double h, double v, optional name = nullopt) { gp_Pnt2d oldp = localpos.Location(); oldp.Translate(gp_Vec2d(h,v)); return LineTo (oldp.X(), oldp.Y(), name); } auto Line(double len, optional name = nullopt) { gp_Dir2d dir = localpos.Direction(); cout << IM(6) << "dir = " << dir.X() << ", " << dir.Y() << endl; gp_Pnt2d oldp = localpos.Location(); oldp.Translate(len*dir); return LineTo (oldp.X(), oldp.Y(), name); } auto Rotate (double angle) { localpos.Rotate(localpos.Location(), angle*M_PI/180); return shared_from_this(); } auto Spline(const std::vector &points, bool periodic, double tol, const std::map &tangents, bool start_from_localpos, std::optional name) { gp_Pnt2d P1 = start_from_localpos ? localpos.Location() : points.front(); gp_Pnt P13d = surf->Value(P1.X(), P1.Y()); gp_Pnt2d PLast = points.back(); gp_Pnt PLast3d = surf->Value(PLast.X(), PLast.Y()); Handle(TColgp_HArray1OfPnt2d) allpoints; if (start_from_localpos) { if (points.front().Distance(P1) <= tol) throw Exception("First item of given list of points is too close to current position (distance <= tol)."); allpoints = new TColgp_HArray1OfPnt2d(1, points.size() + 1); allpoints->SetValue(1, P1); for (int i = 0; i < points.size(); i++) allpoints->SetValue(i + 2, points[i]); } else { allpoints = new TColgp_HArray1OfPnt2d(1, points.size()); for (int i = 0; i < points.size(); i++) allpoints->SetValue(i + 1, points[i]); } Geom2dAPI_Interpolate builder(allpoints, periodic, tol); if (tangents.size() > 0) { const gp_Vec2d dummy_vec = tangents.begin()->second; TColgp_Array1OfVec2d tangent_vecs(1, allpoints->Length()); Handle(TColStd_HArray1OfBoolean) tangent_flags = new TColStd_HArray1OfBoolean(1, allpoints->Length()); for (int i : Range(allpoints->Length())) { if (tangents.count(i) > 0) { tangent_vecs.SetValue(i+1, tangents.at(i)); tangent_flags->SetValue(i+1, true); } else { tangent_vecs.SetValue(i+1, dummy_vec); tangent_flags->SetValue(i+1, false); } } builder.Load(tangent_vecs, tangent_flags); } builder.Perform(); auto curve2d = builder.Curve(); const bool closing = periodic || PLast.Distance(startpnt) < 1e-10; if (startvertex.IsNull()) startvertex = lastvertex = BRepBuilderAPI_MakeVertex(P13d).Vertex(); auto endv = closing ? startvertex : BRepBuilderAPI_MakeVertex(PLast3d).Vertex(); //create 3d edge from 2d curve using surf auto edge = BRepBuilderAPI_MakeEdge(curve2d, surf, lastvertex, endv).Edge(); lastvertex = endv; BRepLib::BuildCurves3d(edge); wire_builder.Add(edge); if(name.has_value()) OCCGeometry::GetProperties(edge).name = name; // update localpos localpos.SetLocation(PLast); //compute angle of rotation //compute tangent t2 in PLast const auto dir = localpos.Direction(); gp_Vec2d t = gp_Vec2d(dir.X(), dir.Y()); gp_Vec2d t2 = curve2d->DN(curve2d->LastParameter(), 1); double angle = t.Angle(t2); //angle \in [-pi,pi] //update localpos.Direction() Rotate(angle*180/M_PI); if (closing) Finish(); return shared_from_this(); } auto ArcTo (double h, double v, const gp_Vec2d t, optional name=nullopt, optional maxh=nullopt) { gp_Pnt2d P1 = localpos.Location(); //check input if(P1.X() == h && P1.Y() == v) throw Exception("points P1 and P2 must not be congruent"); localpos.SetLocation (gp_Pnt2d(h,v)); gp_Pnt2d P2 = localpos.Location(); cout << IM(6) << "ArcTo:" << endl; cout << IM(6) << "P1 = (" << P1.X() <<", " << P1.Y() << ")"< -M_PI/2 && angletp12n < M_PI/2) P3 = gp_Pnt2d(M.X() + r * p12n.X() , M.Y() + r * p12n.Y()); else P3 = gp_Pnt2d(M.X() - r * p12n.X() , M.Y() - r * p12n.Y()); cout << IM(6) << "r = " << r <=0) dirn = gp_Dir2d(-dir.Y(),dir.X()); else dirn = gp_Dir2d(dir.Y(),-dir.X()); gp_Pnt2d oldp = localpos.Location(); oldp.Translate(radius*dirn); cout << IM(6) << "M = (" << oldp.X() << ", " << oldp.Y() << ")" << endl; dirn.Rotate(newAngle-M_PI); oldp.Translate(radius*dirn); //compute tangent vector in P1 gp_Vec2d t = gp_Vec2d(dir.X(),dir.Y()); cout << IM(6) << "t = (" << t.X() << ", " << t.Y() << ")" << endl; //add arc return ArcTo (oldp.X(), oldp.Y(), t, name, maxh); } auto Rectangle (double l, double w, optional name) { Line (l, name); Rotate (90); Line(w, name); Rotate (90); Line (l, name); Rotate (90); Line(w, name); Rotate (90); return shared_from_this(); } auto RectangleCentered (double l, double w, optional name) { Move(-l/2); Rotate(-90); Move(w/2); Rotate(90); Rectangle(l,w, name); Rotate(-90); Move(-w/2); Rotate(90); Move(l/2); return shared_from_this(); } auto Circle(double x, double y, double r) { /* MoveTo(x+r, y); Direction (0, 1); Arc(r, 180); Arc(r, 180); // wires.push_back (wire_builder.Wire()); // wire_builder = BRepBuilderAPI_MakeWire(); return shared_from_this(); */ gp_Pnt2d p(x,y); Handle(Geom2d_Circle) circ_curve = GCE2d_MakeCircle(p, r).Value(); auto edge = BRepBuilderAPI_MakeEdge(circ_curve, surf).Edge(); BRepLib::BuildCurves3d(edge); wire_builder.Add(edge); wires.push_back (wire_builder.Wire()); wire_builder = BRepBuilderAPI_MakeWire(); return shared_from_this(); } auto Ellipse(double major, double minor) { Handle(Geom2d_Ellipse) ell_curve = GCE2d_MakeEllipse(localpos, major, minor).Value(); auto edge = BRepBuilderAPI_MakeEdge(ell_curve, surf).Edge(); BRepLib::BuildCurves3d(edge); wire_builder.Add(edge); wires.push_back (wire_builder.Wire()); wire_builder = BRepBuilderAPI_MakeWire(); return shared_from_this(); } auto NameVertex (string name) { if (!lastvertex.IsNull()) OCCGeometry::GetProperties(lastvertex).name = name; return shared_from_this(); } auto Circle (double r) { gp_Pnt2d pos = localpos.Location(); return Circle (pos.X(), pos.Y(), r); } shared_ptr Close (optional name = nullopt) { if (startpnt.Distance(localpos.Location()) > 1e-10) { LineTo (startpnt.X(), startpnt.Y(), name); return shared_from_this(); } if (!startvertex.IsNull()) Finish(); return shared_from_this(); } auto Reverse() { wires.back().Reverse(); return shared_from_this(); } auto Offset(double d) { Finish(); TopoDS_Wire wire = wires.back(); wires.pop_back(); // handle wires containing a single edge correctly, see // https://dev.opencascade.org/content/brepoffsetapimakeoffset-open-topodswire BRepBuilderAPI_MakeFace makeFace{gp_Pln{axes}}; makeFace.Add(wire); BRepOffsetAPI_MakeOffset builder(makeFace.Face()); builder.Perform(d); auto shape = builder.Shape(); wires.push_back (TopoDS::Wire(shape)); return shared_from_this(); } optional Last() { return wires.empty() ? optional{} : optional{wires.back()}; } TopoDS_Face Face() { BRepBuilderAPI_MakeFace builder(surf, 1e-8); for (auto w : wires) builder.Add(w); wires.clear(); return builder.Face(); } auto Wires() { ListOfShapes ws; for (auto w : wires) ws.push_back(w); return ws; } }; DLL_HEADER void ExportNgOCCShapes(py::module &m) { py::enum_(m, "TopAbs_ShapeEnum", "Enumeration of all supported TopoDS_Shapes") .value("COMPOUND", TopAbs_COMPOUND) .value("COMPSOLID", TopAbs_COMPSOLID) .value("SOLID", TopAbs_SOLID) .value("SHELL", TopAbs_SHELL) .value("FACE", TopAbs_FACE) .value("WIRE", TopAbs_WIRE) .value("EDGE", TopAbs_EDGE) .value("VERTEX", TopAbs_VERTEX) .value("SHAPE", TopAbs_SHAPE) .export_values() ; m.def("ResetGlobalShapeProperties", [] () { OCCGeometry::global_shape_properties.clear(); OCCGeometry::global_shape_property_indices.Clear(); }, "Clear cached OpenCascade shape property metadata stored by Netgen."); struct SwigTypeInfo { const char* name; // SWIG's type name string // Other fields... }; struct SwigPyObject{ PyObject_HEAD void *ptr; SwigTypeInfo* ty; // SWIG type information int own; // ownership flag }; m.def("From_PyOCC", [](py::object shape) { py::object py_this = shape.attr("this"); PyObject* obj = py_this.ptr(); SwigPyObject* swig_obj = reinterpret_cast(obj); if (!swig_obj->ptr || !swig_obj->ty || !swig_obj->ty->name) { throw std::runtime_error("SWIG object does not contain a valid pointer"); } if(strcmp(swig_obj->ty->name, "_p_TopoDS_Shape") != 0) throw std::runtime_error("Does not contain TopoDS_Shape from pyocc!"); return py::cast(static_cast(swig_obj->ptr)); }, py::return_value_policy::reference, py::keep_alive<0,1>(), "Convert a PyOCC SWIG-wrapped TopoDS_Shape into a Netgen TopoDS_Shape view without copying."); py::class_ (m, "TopoDS_Shape") .def("__str__", [] (const TopoDS_Shape & shape) { stringstream str; #ifdef OCC_HAVE_DUMP_JSON shape.DumpJson(str); #endif // OCC_HAVE_DUMP_JSON return str.str(); }) .def("GenerateMesh", [](TopoDS_Shape & shape, MeshingParameters* pars, int dim, bool ngs_mesh, py::kwargs kwargs) { auto geo = py::cast(make_shared(shape, dim)); auto mesh = geo.attr("GenerateMesh")(**kwargs); if(!ngs_mesh) return mesh; try { auto ngsolve = py::module::import("ngsolve"); return ngsolve.attr("Mesh")(mesh); } catch (py::import_error &) { throw Exception("ngsolve module not found, cannot convert to ngsolve mesh, you can use 'ngs_mesh=False' to return a Netgen mesh instead"); } }, py::arg("mp")=nullptr, py::arg("dim")=3, py::arg("ngs_mesh")=true, "Generate a mesh for the shape. Returns an NGSolve mesh if ngs_mesh=True, " "otherwise a Netgen mesh. Extra keyword arguments are forwarded to OCCGeometry.GenerateMesh.") .def("ShapeType", [] (const TopoDS_Shape & shape) { throw Exception ("use 'shape.type' instead of 'shape.ShapeType()'"); }, "deprecated, use 'shape.type' instead") .def_property_readonly("type", [](const TopoDS_Shape & shape) { return shape.ShapeType(); }, "returns type of shape, i.e. 'EDGE', 'FACE', ...") .def("SubShapes", [] (const TopoDS_Shape & shape, TopAbs_ShapeEnum & type) { ListOfShapes sub; for (TopExp_Explorer e(shape, type); e.More(); e.Next()) sub.push_back(e.Current()); return sub; }, py::arg("type"), "returns list of sub-shapes of type 'type'") .def_property_readonly("solids", GetSolids, "returns all sub-shapes of type 'SOLID'") .def_property_readonly("shells", GetShells, "returns all sub-shapes of type 'SHELL'") .def_property_readonly("faces", GetFaces, "returns all sub-shapes of type 'FACE'") .def_property_readonly("edges", GetEdges, "returns all sub-shapes of type 'EDGE'") .def_property_readonly("wires", GetWires, "returns all sub-shapes of type 'WIRE'") .def_property_readonly("vertices", GetVertices, "returns all sub-shapes of type 'VERTEX'") .def_property_readonly("bounding_box", [] ( const TopoDS_Shape &shape ) { auto box = GetBoundingBox(shape); return py::make_tuple( ng2occ(box.PMin()), ng2occ(box.PMax()) ); }, "returns bounding box (pmin, pmax)") .def("LimitTolerance", [](TopoDS_Shape& self, double tmin, double tmax, TopAbs_ShapeEnum type) { ShapeFix_ShapeTolerance fix; fix.LimitTolerance(self, tmin, tmax, type); }, py::arg("tmin"), py::arg("tmax")=0., py::arg("type")=TopAbs_SHAPE, "limit tolerance of shape to range [tmin, tmax]") .def("SetTolerance", [](TopoDS_Shape& self, double tol, TopAbs_ShapeEnum stype) { ShapeFix_ShapeTolerance fix; fix.SetTolerance(self, tol, stype); }, py::arg("tol"), py::arg("stype")=TopAbs_SHAPE, "set (enforce) tolerance of shape to 't'") .def("Properties", [] (const TopoDS_Shape & shape) { auto props = Properties(shape); return tuple( py::cast(props.Mass()), py::cast(props.CentreOfMass()) ); }, "returns tuple of shape properties, currently ('mass', 'center'") .def_property_readonly("center", [](const TopoDS_Shape & shape) { return Center(shape); }, "returns center of gravity of shape") .def_property_readonly("mass", [](const TopoDS_Shape & shape) { return Mass(shape); }, "returns mass of shape, what is length, face, or volume") .def_property_readonly("inertia", [](const TopoDS_Shape & shape) { return Properties(shape).MatrixOfInertia(); }, "returns matrix of inertia of shape") .def("Move", [](const TopoDS_Shape & shape, const gp_Vec v) { // which one to choose ? // version 1: Transoformation gp_Trsf trafo; trafo.SetTranslation(v); BRepBuilderAPI_Transform builder(shape, trafo, true); PropagateProperties(builder, shape, occ2ng(trafo)); return CastShape(builder.Shape()); // version 2: change location // ... }, py::arg("v"), "copy shape, and translate copy by vector 'v'") .def("Rotate", [](const TopoDS_Shape & shape, const gp_Ax1 ax, double ang) { gp_Trsf trafo; trafo.SetRotation(ax, ang*M_PI/180); BRepBuilderAPI_Transform builder(shape, trafo, true); PropagateProperties(builder, shape, occ2ng(trafo)); return builder.Shape(); }, py::arg("axis"), py::arg("ang"), "copy shape, and rotet copy by 'ang' degrees around 'axis'") .def("Mirror", [] (const TopoDS_Shape & shape, const gp_Ax3 & ax) { gp_Trsf trafo; trafo.SetMirror(ax.Ax2()); BRepBuilderAPI_Transform builder(shape, trafo, true); PropagateProperties(builder, shape, occ2ng(trafo)); return builder.Shape(); }, py::arg("axes"), "copy shape, and mirror over XY - plane defined by 'axes'") .def("Mirror", [] (const TopoDS_Shape & shape, const gp_Ax1 & ax) { gp_Trsf trafo; trafo.SetMirror(ax); BRepBuilderAPI_Transform builder(shape, trafo, true); PropagateProperties(builder, shape, occ2ng(trafo)); return builder.Shape(); }, py::arg("axes"), "copy shape, and rotate by 180 deg around axis 'axis'") .def("Scale", [](const TopoDS_Shape & shape, const gp_Pnt p, double s) { gp_Trsf trafo; trafo.SetScale(p, s); BRepBuilderAPI_Transform builder(shape, trafo, true); PropagateProperties(builder, shape, occ2ng(trafo)); return builder.Shape(); }, py::arg("p"), py::arg("s"), "copy shape, and scale copy by factor 's'") .def("WriteStep", [](const TopoDS_Shape & shape, string & filename) { step_utils::WriteSTEP(shape, filename); } , py::arg("filename"), "export shape in STEP - format") .def("WriteBrep", [](const TopoDS_Shape & shape, const string& filename, bool withTriangles, bool withNormals, optional version, bool binary) { if(binary) { #if NETGEN_OCC_VERSION_AT_LEAST(7, 6) BinTools_FormatVersion v = version ? BinTools_FormatVersion(*version) : BinTools_FormatVersion_CURRENT; BinTools::Write(shape, filename.c_str(), withTriangles, withNormals, v); # else // NETGEN_OCC_VERSION_AT_LEAST(7, 6) throw Exception("Binary BREP export not supported in this version of OpenCascade"); #endif // NETGEN_OCC_VERSION_AT_LEAST(7, 6) } else { #if NETGEN_OCC_VERSION_AT_LEAST(7, 6) TopTools_FormatVersion v = version ? (TopTools_FormatVersion)(*version) : TopTools_FormatVersion_CURRENT; BRepTools::Write(shape, filename.c_str(), withTriangles, withNormals, v); #else // OCC_VERSION_MAJOR>=7 && OCC_VERSION_MINOR>=6 BRepTools::Write(shape, filename.c_str()); #endif // OCC_VERSION_MAJOR>=7 && OCC_VERSION_MINOR>=6 } }, py::arg("filename"), py::arg("withTriangles")=true, py::arg("withNormals")=false, py::arg("version")=py::none(), py::arg("binary")=false, "export shape in BREP - format") .def("bc", [](const TopoDS_Shape & shape, const string & name) { for (TopExp_Explorer e(shape, TopAbs_FACE); e.More(); e.Next()) OCCGeometry::GetProperties(e.Current()).name = name; return shape; }, py::arg("name"), "sets 'name' property for all faces of shape") .def("mat", [](const TopoDS_Shape & shape, const string & name) { for (TopExp_Explorer e(shape, TopAbs_SOLID); e.More(); e.Next()) OCCGeometry::GetProperties(e.Current()).name = name; return shape; }, py::arg("name"), "sets 'name' property to all solids of shape") .def_property("name", [](const TopoDS_Shape & self) -> optional { CheckValidPropertyType(self); if (auto name = OCCGeometry::GetProperties(self).name) return *name; else return nullopt; }, [](const TopoDS_Shape & self, optional name) { for (auto & s : GetHighestDimShapes(self)) OCCGeometry::GetProperties(s).name = name; }, "'name' of shape") .def_property("maxh", [](const TopoDS_Shape& self) { CheckValidPropertyType(self); return OCCGeometry::GetProperties(self).maxh; }, [](TopoDS_Shape& self, double val) { for(auto & s : GetHighestDimShapes(self)) OCCGeometry::GetProperties(s).maxh = val; }, "maximal mesh-size for shape") .def_property("hpref", [](const TopoDS_Shape& self) { CheckValidPropertyType(self); return OCCGeometry::GetProperties(self).hpref; }, [](TopoDS_Shape& self, double val) { for(auto & s : GetHighestDimShapes(self)) OCCGeometry::GetProperties(s).hpref = val; }, "number of refinement levels for geometric refinement") .def_property("col", [](const TopoDS_Shape & self) -> py::object { CheckValidPropertyType(self); if(!OCCGeometry::HaveProperties(self) || !OCCGeometry::GetProperties(self).col) return py::none(); auto col = *OCCGeometry::GetProperties(self).col; return py::cast(std::vector({ col(0), col(1), col(2), col(3) })); }, [](const TopoDS_Shape & self, std::optional> c) { if(c.has_value()) { Vec<4> col((*c)[0], (*c)[1], (*c)[2], 1.0); if(c->size() == 4) col[3] = (*c)[3]; for(auto & s : GetHighestDimShapes(self)) OCCGeometry::GetProperties(s).col = col; } else for(auto & s : GetHighestDimShapes(self)) OCCGeometry::GetProperties(s).col = nullopt; }, "color of shape as RGB or RGBA - tuple") .def_property("layer", [](const TopoDS_Shape& self) { if (!OCCGeometry::HaveProperties(self)) return 1; return OCCGeometry::GetProperties(self).layer; }, [](const TopoDS_Shape& self, int layer) { OCCGeometry::GetProperties(self).layer = layer; for(auto & s : GetHighestDimShapes(self)) OCCGeometry::GetProperties(s).layer = layer; }, "layer of shape") .def("UnifySameDomain", [](const TopoDS_Shape& shape, bool edges, bool faces, bool concatBSplines) { ShapeUpgrade_UnifySameDomain unify(shape, edges, faces, concatBSplines); unify.Build(); Handle(BRepTools_History) history = unify.History (); for (auto typ : { TopAbs_SOLID, TopAbs_FACE, TopAbs_EDGE }) for (TopExp_Explorer e(shape, typ); e.More(); e.Next()) { auto prop = OCCGeometry::GetProperties(e.Current()); for (auto mods : history->Modified(e.Current())) OCCGeometry::GetProperties(mods).Merge(prop); } return unify.Shape(); }, py::arg("unifyEdges")=true, py::arg("unifyFaces")=true, py::arg("concatBSplines")=true, "Unify edges and/or faces that lie on the same geometric domain " "(ShapeUpgrade_UnifySameDomain) and propagate shape properties.") .def_property("location", [](const TopoDS_Shape & shape) { return shape.Location(); }, [](TopoDS_Shape & shape, const TopLoc_Location & loc) { shape.Location(loc); }, "Location of shape") .def("Located", [](const TopoDS_Shape & shape, const TopLoc_Location & loc) { return shape.Located(loc); }, py::arg("loc"), "copy shape and sets location of copy") .def("__add__", [] (const TopoDS_Shape & shape1, const TopoDS_Shape & shape2) { BRepAlgoAPI_Fuse builder(shape1, shape2); PropagateProperties (builder, shape1); PropagateProperties (builder, shape2); /* #ifdef OCC_HAVE_HISTORY Handle(BRepTools_History) history = builder.History (); for (auto typ : { TopAbs_SOLID, TopAbs_FACE, TopAbs_EDGE }) for (auto & s : { shape1, shape2 }) for (TopExp_Explorer e(s, typ); e.More(); e.Next()) { auto prop = OCCGeometry::GetProperties(e.Current()); for (auto mods : history->Modified(e.Current())) OCCGeometry::GetProperties(mods).Merge(prop); } #endif */ auto fused = builder.Shape(); // make one face when fusing in 2D // from https://gitlab.onelab.info/gmsh/gmsh/-/issues/627 // int cntsolid = 0; // for (TopExp_Explorer e(shape1, TopAbs_SOLID); e.More(); e.Next()) // cntsolid++; // for (TopExp_Explorer e(shape2, TopAbs_SOLID); e.More(); e.Next()) // cntsolid++; // if (cntsolid == 0) // { ShapeUpgrade_UnifySameDomain unify(fused, true, true, true); unify.Build(); // #ifdef OCC_HAVE_HISTORY Handle(BRepTools_History) history = unify.History (); for (auto typ : { TopAbs_SOLID, TopAbs_FACE, TopAbs_EDGE }) for (TopExp_Explorer e(fused, typ); e.More(); e.Next()) { auto prop = OCCGeometry::GetProperties(e.Current()); for (auto mods : history->Modified(e.Current())) OCCGeometry::GetProperties(mods).Merge(prop); } // #endif // PropagateProperties (unify, fused); return unify.Shape(); // } // else // return fused; }, "fuses shapes") .def("__radd__", [] (const TopoDS_Shape & shape, int i) // for sum([shapes]) { return shape; }, "needed for Sum([shapes])") .def("__mul__", [] (const TopoDS_Shape & shape1, const TopoDS_Shape & shape2) { BRepAlgoAPI_Common builder(shape1, shape2); /* #ifdef OCC_HAVE_HISTORY Handle(BRepTools_History) history = builder.History (); for (auto typ : { TopAbs_SOLID, TopAbs_FACE, TopAbs_EDGE }) for (auto & s : { shape1, shape2 }) for (TopExp_Explorer e(s, typ); e.More(); e.Next()) { auto prop = OCCGeometry::GetProperties(e.Current()); for (auto mods : history->Modified(e.Current())) OCCGeometry::GetProperties(mods).Merge(prop); } #endif // OCC_HAVE_HISTORY */ PropagateProperties (builder, shape1); PropagateProperties (builder, shape2); return builder.Shape(); }, "common of shapes") .def("__sub__", [] (const TopoDS_Shape & shape1, const TopoDS_Shape & shape2) { BRepAlgoAPI_Cut builder(shape1, shape2); /* #ifdef OCC_HAVE_HISTORY Handle(BRepTools_History) history = builder.History (); for (auto typ : { TopAbs_SOLID, TopAbs_FACE, TopAbs_EDGE }) for (auto & s : { shape1, shape2 }) for (TopExp_Explorer e(s, typ); e.More(); e.Next()) { auto prop = OCCGeometry::GetProperties(e.Current()); for (auto mods : history->Modified(e.Current())) OCCGeometry::GetProperties(mods).Merge(prop); } #endif // OCC_HAVE_HISTORY */ PropagateProperties (builder, shape1); PropagateProperties (builder, shape2); return builder.Shape(); }, "cut of shapes") .def("__eq__", [] (const TopoDS_Shape& shape1, const TopoDS_Shape& shape2) { return shape1.IsSame(shape2); }) .def("__hash__", [] (const TopoDS_Shape& shape) { OCCGeometry::GetProperties(shape); // make sure it is in global properties return OCCGeometry::global_shape_property_indices.FindIndex(shape); }) .def("Reversed", [](const TopoDS_Shape & shape) { return CastShape(shape.Reversed()); }, "Return a copy with the orientation reversed (TopoDS_Shape::Reversed).") .def("Extrude", [](const TopoDS_Shape & shape, double h, optional dir, bool identify, Identifications::ID_TYPE idtype, string idname) { for (TopExp_Explorer e(shape, TopAbs_FACE); e.More(); e.Next()) { Handle(Geom_Surface) surf = BRep_Tool::Surface (TopoDS::Face(e.Current())); gp_Vec edir; if(dir.has_value()) edir = *dir; else { gp_Vec du, dv; gp_Pnt p; surf->D1 (0,0,p,du,dv); edir = du^dv; } BRepPrimAPI_MakePrism builder(shape, h*edir, false); for (auto typ : { TopAbs_SOLID, TopAbs_FACE, TopAbs_EDGE, TopAbs_VERTEX }) for (TopExp_Explorer e(shape, typ); e.More(); e.Next()) { auto prop = OCCGeometry::GetProperties(e.Current()); for (auto mods : builder.Generated(e.Current())) OCCGeometry::GetProperties(mods).Merge(prop); } if(identify) { Transformation<3> trsf(h * occ2ng(edir)); Identify(GetFaces(shape), GetFaces(builder.LastShape()), idname, idtype, trsf); } return builder.Shape(); } if (!dir.has_value()) throw Exception("shape does not contain a face to determine extrusion direction, please provide 'dir' argument"); gp_Vec edir = h * (*dir); BRepPrimAPI_MakePrism builder(shape, edir, false); for (auto typ : { TopAbs_SOLID, TopAbs_FACE, TopAbs_EDGE, TopAbs_VERTEX }) for (TopExp_Explorer e(shape, typ); e.More(); e.Next()) { auto prop = OCCGeometry::GetProperties(e.Current()); for (auto mods : builder.Generated(e.Current())) OCCGeometry::GetProperties(mods).Merge(prop); } return builder.Shape(); }, py::arg("h"), py::arg("dir")=nullopt, py::arg("identify")=false, py::arg("idtype")=Identifications::CLOSESURFACES, py::arg("idname") = "extrusion", "extrude shape to thickness 'h', shape must contain a plane surface, optionally give an extrusion direction") .def("Extrude", [] (const TopoDS_Shape & face, gp_Vec vec) { BRepPrimAPI_MakePrism builder(face, vec); for (auto typ : { TopAbs_SOLID, TopAbs_FACE, TopAbs_EDGE, TopAbs_VERTEX }) for (TopExp_Explorer e(face, typ); e.More(); e.Next()) { auto prop = OCCGeometry::GetProperties(e.Current()); for (auto mods : builder.Generated(e.Current())) OCCGeometry::GetProperties(mods).Merge(prop); } return builder.Shape(); }, py::arg("v"), "extrude shape by vector 'v'") .def("Revolve", [](const TopoDS_Shape & shape, const gp_Ax1 &A, const double D) { // for (TopExp_Explorer e(shape, TopAbs_FACE); e.More(); e.Next()) { // return BRepPrimAPI_MakeRevol (shape, A, D*M_PI/180).Shape(); BRepPrimAPI_MakeRevol builder(shape, A, D*M_PI/180, true); for (auto typ : { TopAbs_FACE, TopAbs_EDGE, TopAbs_VERTEX}) for (TopExp_Explorer e(shape, typ); e.More(); e.Next()) { auto prop = OCCGeometry::GetProperties(e.Current()); for (auto mods : builder.Generated(e.Current())) OCCGeometry::GetProperties(mods).Merge(prop); } return builder.Shape(); } // throw Exception("no face found for revolve"); }, py::arg("axis"), py::arg("ang"), "revolve shape around 'axis' by 'ang' degrees") .def("CrossSection", &CrossSection, py::arg("plane_axes"), "Create cross section of shape with plane defined by 'plane_axes' and transfer properties to dim-1 entities") .def("MakeFillet", [](const TopoDS_Shape& shape, const std::vector>& fillets) -> TopoDS_Shape { if (shape.ShapeType() == TopAbs_FACE) { BRepFilletAPI_MakeFillet2d mkFillet2d(TopoDS::Face(shape)); for (auto [v, r] : fillets) mkFillet2d.AddFillet(TopoDS::Vertex(v), r); mkFillet2d.Build(); // TODO: CL I think we shouldn't do this here but, double check // PropagateProperties (mkFillet2d, shape); return mkFillet2d.Shape(); } BRepFilletAPI_MakeFillet mkFillet(shape); for (auto [e, r] : fillets) mkFillet.Add(r, TopoDS::Edge(e)); mkFillet.Build(); PropagateProperties (mkFillet, shape); for (auto [e, r] : fillets) for (auto gen : mkFillet.Generated(e)) OCCGeometry::GetProperties(gen).name = "fillet"; return mkFillet.Shape(); }, py::arg("fillets"), "make fillets for shapes of radius 'r'") .def("MakeFillet", [](const TopoDS_Shape & shape, std::vector edges, double r) -> TopoDS_Shape { if(shape.ShapeType() == TopAbs_FACE) { BRepFilletAPI_MakeFillet2d mkFillet(TopoDS::Face(shape)); for (auto e : edges) mkFillet.AddFillet (TopoDS::Vertex(e), r); mkFillet.Build(); // TODO: CL I think we shouldn't do this here but, double check // PropagateProperties (mkFillet, shape); return mkFillet.Shape(); } BRepFilletAPI_MakeFillet mkFillet(shape); for (auto e : edges) mkFillet.Add (r, TopoDS::Edge(e)); mkFillet.Build(); PropagateProperties (mkFillet, shape); for (auto e : edges) for (auto gen : mkFillet.Generated(e)) OCCGeometry::GetProperties(gen).name = "fillet"; return mkFillet.Shape(); }, py::arg("edges"), py::arg("r"), "make fillets for edges 'edges' of radius 'r'") .def("MakeChamfer", [](const TopoDS_Shape & shape, std::vector edges, double d) { #if OCC_VERSION_MAJOR>=7 && OCC_VERSION_MINOR>=4 BRepFilletAPI_MakeChamfer mkChamfer(shape); for (auto e : edges) mkChamfer.Add (d, TopoDS::Edge(e)); mkChamfer.Build(); PropagateProperties (mkChamfer, shape); for (auto e : edges) for (auto gen : mkChamfer.Generated(e)) OCCGeometry::GetProperties(gen).name = "chamfer"; return mkChamfer.Shape(); #else throw Exception("MakeChamfer not available for occ-version < 7.4"); #endif }, py::arg("edges"), py::arg("d"), "make symmetric chamfer for edges 'edges' of distrance 'd'") .def("MakeThickSolid", [](const TopoDS_Shape & body, std::vector facestoremove, double offset, double tol, bool intersection, string joinT, bool removeIntEdges) { TopTools_ListOfShape faces; for (auto f : facestoremove) faces.Append(f); BRepOffsetAPI_MakeThickSolid maker; GeomAbs_JoinType joinType; if(joinT == "arc") joinType = GeomAbs_Arc; else if(joinT == "intersection") joinType = GeomAbs_Intersection; else throw Exception("Only joinTypes 'arc' and 'intersection' exist!"); maker.MakeThickSolidByJoin(body, faces, offset, tol, BRepOffset_Skin, intersection, false, joinType, removeIntEdges); return maker.Shape(); }, py::arg("facestoremove"), py::arg("offset"), py::arg("tol"), py::arg("intersection") = false,py::arg("joinType")="arc", py::arg("removeIntersectingEdges") = false, "makes shell-like solid from faces") .def("Offset", [](const TopoDS_Shape & shape, double offset, double tol, bool intersection, string joinT, bool removeIntEdges, optional identification_name) { BRepOffsetAPI_MakeOffsetShape maker; GeomAbs_JoinType joinType; if(joinT == "arc") joinType = GeomAbs_Arc; else if(joinT == "intersection") joinType = GeomAbs_Intersection; else if(joinT == "tangent") joinType = GeomAbs_Tangent; else throw Exception("Only joinTypes 'arc', 'intersection' and 'tangent' exist!"); maker.PerformByJoin(shape, offset, tol, BRepOffset_Skin, intersection, false, joinType, removeIntEdges); // PropagateProperties (maker, shape); for (auto typ : { TopAbs_FACE, TopAbs_EDGE, TopAbs_VERTEX }) for (TopExp_Explorer e(shape, typ); e.More(); e.Next()) { auto s = e.Current(); auto prop = OCCGeometry::GetProperties(s); for (auto mods : maker.Generated(s)) { if(OCCGeometry::HaveProperties(s)) { auto & new_props = OCCGeometry::GetProperties(mods); new_props.Merge(prop); if (prop.name) new_props.name = string("offset_")+(*prop.name); } if(identification_name) { OCCIdentification ident; ident.from = s; ident.to = mods; ident.name = *identification_name; ident.type = Identifications::CLOSESURFACES; OCCGeometry::GetIdentifications(s).push_back(ident); } } } return maker.Shape(); }, py::arg("offset"), py::arg("tol"), py::arg("intersection") = false,py::arg("joinType")="arc", py::arg("removeIntersectingEdges") = false, py::arg("identification_name") = nullopt, "makes shell-like solid from faces") .def("MakeTriangulation", [](const TopoDS_Shape & shape) { BuildTriangulation(shape); }, "Ensure all faces of the shape have an OpenCascade triangulation " "(typically via BRepMesh). Useful before querying Poly_Triangulation " "or exporting to viewers. See https://dev.opencascade.org/doc/refman/html/class_b_rep_mesh___incremental_mesh.html") .def("Identify", py::overload_cast>>(&Identify), py::arg("other"), py::arg("name"), py::arg("type")=Identifications::PERIODIC, py::arg("trafo")=nullopt, "Identify shapes for periodic meshing") .def("Distance", [](const TopoDS_Shape& self, const TopoDS_Shape& other) { return BRepExtrema_DistShapeShape(self, other).Value(); }, "Compute the minimum distance between two shapes using " "BRepExtrema_DistShapeShape. See https://dev.opencascade.org/doc/refman/html/class_b_rep_extrema___dist_shape_shape.html") .def("Triangulation", [](const TopoDS_Shape & shape) { // extracted from vsocc.cpp TopoDS_Face face; try { face = TopoDS::Face(shape); } catch (Standard_Failure & e) { e.Print (cout); throw NgException ("Triangulation: shape is not a face"); } Handle(Geom_Surface) surf = BRep_Tool::Surface (face); TopLoc_Location loc; Handle(Poly_Triangulation) triangulation = BRep_Tool::Triangulation (face, loc); if (triangulation.IsNull()) { BuildTriangulation(shape); triangulation = BRep_Tool::Triangulation (face, loc); } // throw Exception("Don't have a triangulation, call 'MakeTriangulation' first"); int ntriangles = triangulation -> NbTriangles(); Array< std::array,3> > triangles; for (int j = 1; j <= ntriangles; j++) { Poly_Triangle triangle = triangulation -> Triangle(j); std::array,3> pts; for (int k = 0; k < 3; k++) pts[k] = occ2ng( (triangulation -> Node(triangle(k+1))).Transformed(loc) ); triangles.Append ( pts ); } // return MoveToNumpyArray(triangles); return triangles; }, "Extract the face triangulation (Poly_Triangulation) from OpenCascade. If missing, builds it first, then returns the triangle vertex coordinates.") .def("_webgui_data", [](const TopoDS_Shape & shape) { [[maybe_unused]] auto status = BuildTriangulation(shape); // cout << "status = " << aStatus << endl; std::vector p[3]; std::vector n[3]; py::list names, colors, solid_names; std::vector> solid_face_map; int index = 0; Box<3> box(Box<3>::EMPTY_BOX); TopTools_IndexedMapOfShape fmap; for (TopExp_Explorer e(shape, TopAbs_FACE); e.More(); e.Next()) { TopoDS_Face face = TopoDS::Face(e.Current()); if(fmap.Contains(face)) continue; // Handle(TopoDS_Face) face = e.Current(); fmap.Add(face); ExtractFaceData(face, index, p, n, box); ShapeProperties props; if(OCCGeometry::HaveProperties(face)) props = OCCGeometry::GetProperties(face); auto c = props.GetColor(); colors.append(py::make_tuple(c[0], c[1], c[2], c[3])); names.append(props.GetName()); index++; } for(auto& solid : GetSolids(shape)) { std::vector faces; for(auto& face : GetFaces(solid)) faces.push_back(fmap.FindIndex(face)-1); solid_face_map.push_back(std::move(faces)); auto& props = OCCGeometry::GetProperties(solid); if(props.name) solid_names.append(*props.name); else solid_names.append(""); } std::vector edge_p[2]; py::list edge_names, edge_colors; index = 0; for (TopExp_Explorer e(shape, TopAbs_EDGE); e.More(); e.Next()) { TopoDS_Edge edge = TopoDS::Edge(e.Current()); ExtractEdgeData(edge, index, edge_p, box); auto & props = OCCGeometry::GetProperties(edge); if(props.col) { auto & c = *props.col; edge_colors.append(py::make_tuple(c[0], c[1], c[2])); } else edge_colors.append(py::make_tuple(0.0, 0.0, 0.0)); if(props.name) { edge_names.append(*props.name); } else edge_names.append(""); index++; } auto center = box.Center(); py::list mesh_center; mesh_center.append(center[0]); mesh_center.append(center[1]); mesh_center.append(center[2]); py::dict data; data["ngsolve_version"] = "Netgen x.x"; // TODO data["mesh_dim"] = 3; // TODO data["mesh_center"] = mesh_center; data["mesh_radius"] = box.Diam()/2; data["order2d"] = 1; data["order3d"] = 0; data["draw_vol"] = false; data["draw_surf"] = true; data["funcdim"] = 0; data["have_normals"] = true; data["show_wireframe"] = true; data["show_mesh"] = true; data["Bezier_points"] = py::list{}; py::list points; points.append(p[0]); points.append(p[1]); points.append(p[2]); points.append(n[0]); points.append(n[1]); points.append(n[2]); data["Bezier_trig_points"] = points; data["funcmin"] = 0; data["funcmax"] = 1; data["mesh_regions_2d"] = index; data["autoscale"] = false; data["colors"] = colors; data["names"] = names; data["solid_names"] = solid_names; py::list edges; edges.append(edge_p[0]); edges.append(edge_p[1]); data["edges"] = edges; data["edge_names"] = edge_names; data["edge_colors"] = edge_colors; data["solid_face_map"] = solid_face_map; return data; }, "Return triangulated face/edge data and metadata for web visualization.") ; py::class_ (m, "Vertex") .def(py::init([] (const TopoDS_Shape & shape) { return TopoDS::Vertex(shape); }), "Create a vertex from a TopoDS_Shape (must be a vertex).") .def(py::init([] (const gp_Pnt & p) { return BRepBuilderAPI_MakeVertex (p).Vertex(); }), "Create a vertex at the given point.") .def_property_readonly("p", [] (const TopoDS_Vertex & v) -> gp_Pnt { return BRep_Tool::Pnt (v); }, "coordinates of vertex") ; py::class_ (m, "Edge") .def(py::init([] (const TopoDS_Shape & shape) { return TopoDS::Edge(shape); }), "Create an edge from a TopoDS_Shape (must be an edge).") .def(py::init([] (Handle(Geom2d_Curve) curve2d, TopoDS_Face face) { auto edge = BRepBuilderAPI_MakeEdge(curve2d, BRep_Tool::Surface (face)).Edge(); BRepLib::BuildCurves3d(edge); return edge; }), "Construct an edge from a 2D parametric curve on a face by lifting it to the face's surface.") .def(py::init([] (const TopoDS_Vertex & v1, const TopoDS_Vertex & v2) { return BRepBuilderAPI_MakeEdge(v1, v2).Edge(); }), "Create a straight edge between two vertices.") .def("Value", [](const TopoDS_Edge & e, double s) { double s0, s1; auto curve = BRep_Tool::Curve(e, s0, s1); return curve->Value(s); }, py::arg("s"), "evaluate curve for parameters 's'") .def("Tangent", [](const TopoDS_Edge & e, double s) { gp_Pnt p; gp_Vec v; double s0, s1; auto curve = BRep_Tool::Curve(e, s0, s1); curve->D1(s, p, v); return v; }, py::arg("s"), "tangent vector to curve at parameter 's'") .def_property_readonly("start", [](const TopoDS_Edge & e) { double s0, s1; auto curve = BRep_Tool::Curve(e, s0, s1); return curve->Value(s0); }, "start-point of curve") .def_property_readonly("end", [](const TopoDS_Edge & e) { double s0, s1; auto curve = BRep_Tool::Curve(e, s0, s1); return curve->Value(s1); }, "end-point of curve") .def_property_readonly("start_tangent", [](const TopoDS_Edge & e) { double s0, s1; auto curve = BRep_Tool::Curve(e, s0, s1); gp_Pnt p; gp_Vec v; curve->D1(s0, p, v); return v; }, "tangent at start-point") .def_property_readonly("end_tangent", [](const TopoDS_Edge & e) { double s0, s1; auto curve = BRep_Tool::Curve(e, s0, s1); gp_Pnt p; gp_Vec v; curve->D1(s1, p, v); return v; }, "tangent at end-point") .def_property_readonly("parameter_interval", [](const TopoDS_Edge & e) { double s0, s1; auto curve = BRep_Tool::Curve(e, s0, s1); return tuple(s0, s1); }, "parameter interval of curve") .def_property("partition", [](TopoDS_Shape & self) -> optional> { if (OCCGeometry::HaveProperties(self)) return OCCGeometry::GetProperties(self).partition; return nullopt; }, [](TopoDS_Shape &self, py::array_t val) { Array partition(val.size()); for(auto i : Range(partition)) partition[i] = val.at(i); OCCGeometry::GetProperties(self).partition = std::move(partition); }, "Optional edge partition parameters for meshing (array of curve parameters).") .def("Split", [](const TopoDS_Edge& self, py::args args) { ListOfShapes new_edges; double s0, s1; auto curve = BRep_Tool::Curve(self, s0, s1); double tstart, t, dist; TopoDS_Vertex vstart, vend; vstart = TopExp::FirstVertex(self); IntTools_Context context; tstart = s0; for(auto arg : args) { if(py::isinstance(arg)) t = s0 + py::cast(arg) * (s1-s0); else { auto p = py::cast(arg); auto result = context.ComputePE(p, 0., self, t, dist); if(result != 0) throw Exception("Error in finding splitting points on edge!"); } auto p = curve->Value(t); vend = BRepBuilderAPI_MakeVertex(p); auto newE = TopoDS::Edge(self.EmptyCopied()); BOPTools_AlgoTools::MakeSplitEdge(self, vstart, tstart, vend, t, newE); new_edges.push_back(newE); vstart = vend; tstart = t; } auto newE = TopoDS::Edge(self.EmptyCopied()); t = s1; vend = TopExp::LastVertex(self); BOPTools_AlgoTools::MakeSplitEdge(self, vstart, tstart, vend, t, newE); new_edges.push_back(newE); return new_edges; }, "Splits edge at given parameters. Parameters can either be floating values in (0,1), then edge parametrization is used. Or it can be points, then the projection of these points are used for splitting the edge.") .def("Extend", [](const TopoDS_Edge & edge, gp_Pnt pnt, int continuity, bool after) { double s0, s1; auto curve = BRep_Tool::Curve(edge, s0, s1); if (continuity < 0 || continuity > 2) throw Exception("continuity must be 0, 1 or 2"); auto bounded_curve = opencascade::handle::DownCast(curve); GeomLib::ExtendCurveToPoint(bounded_curve, pnt, continuity, after); return BRepBuilderAPI_MakeEdge(bounded_curve).Edge(); }, py::arg("point"), py::arg("continuity") = 1, py::arg("after") = true, "Extend the edge's underlying curve to a target point with G0/G1/G2 continuity.") ; py::class_ (m, "Wire") .def(py::init([](const TopoDS_Edge & edge) { BRepBuilderAPI_MakeWire builder; builder.Add(edge); return builder.Wire(); }), "Create a wire from a single edge.") .def(py::init([](std::vector edges) { BRepBuilderAPI_MakeWire builder; try { for (auto s : edges) switch (s.ShapeType()) { case TopAbs_EDGE: builder.Add(TopoDS::Edge(s)); break; case TopAbs_WIRE: builder.Add(TopoDS::Wire(s)); break; default: throw Exception("can make wire only from edges and wires"); } return builder.Wire(); } catch (Standard_Failure & e) { stringstream errstr; e.Print(errstr); throw NgException("error in wire builder: "+errstr.str()); } }), "Create a wire from a list of edges and/or wires.") .def("Offset", [](const TopoDS_Wire & wire, const TopoDS_Face & face, double dist, string joinT, bool openresult) { GeomAbs_JoinType joinType; if(joinT == "arc") joinType = GeomAbs_Arc; else if(joinT == "intersection") joinType = GeomAbs_Intersection; else if(joinT == "tangent") joinType = GeomAbs_Tangent; else throw Exception("Only joinTypes 'arc', 'tangent', and 'intersection' exist!"); BRepOffsetAPI_MakeOffset builder(face, joinType, openresult); builder.AddWire(wire); builder.Perform(dist); auto shape = builder.Shape(); return shape; }, "Offset a wire on a supporting face by distance 'dist' with a chosen join type: " "'arc' rounds corners with circular arcs, 'tangent' blends with tangent continuity, " "and 'intersection' keeps sharp corners by intersecting offset segments.") ; py::class_ (m, "Face") .def(py::init([](TopoDS_Wire wire) { return BRepBuilderAPI_MakeFace(wire).Face(); }), py::arg("w"), "Create a planar face bounded by a wire.") .def(py::init([](const TopoDS_Face & face, const TopoDS_Wire & wire) { return BRepBuilderAPI_MakeFace(BRep_Tool::Surface (face), wire).Face(); }), py::arg("f"), py::arg("w"), "Create a face on the surface of another face, bounded by a wire.") .def(py::init([](const TopoDS_Face & face, std::vector wires) { auto surf = BRep_Tool::Surface (face); BRepBuilderAPI_MakeFace builder(surf, 1e-8); for (auto w : wires) builder.Add(w); return builder.Face(); }), py::arg("f"), py::arg("w"), "Create a face on a reference surface and add one or more bounding wires.") .def(py::init([] (const TopoDS_Shape & shape) { return TopoDS::Face(shape); }), "Create a face from a TopoDS_Shape (must be a face).") .def_property("quad_dominated", [](const TopoDS_Face& self) -> optional { return OCCGeometry::GetProperties(self).quad_dominated; }, [](TopoDS_Face& self, optional quad_dominated) { OCCGeometry::GetProperties(self).quad_dominated = quad_dominated; }, "Hint that the face should be meshed with quad-dominated elements.") .def_property_readonly("surf", [] (TopoDS_Face face) -> Handle(Geom_Surface) { Handle(Geom_Surface) surf = BRep_Tool::Surface (face); return surf; }, "Return the underlying OpenCascade surface of the face.") .def("WorkPlane",[] (const TopoDS_Face & face) { Handle(Geom_Surface) surf = BRep_Tool::Surface (face); gp_Vec du, dv; gp_Pnt p; surf->D1 (0,0,p,du,dv); auto ax = gp_Ax3(p, du^dv, du); return make_shared (ax); }, "Create a 2D work plane aligned with the face's surface at (u,v)=(0,0), using the surface normal as the plane normal.") .def("ProjectWire", [](const TopoDS_Face& face, const TopoDS_Wire& wire) { BRepAlgo_NormalProjection builder(face); builder.Add(wire); builder.Build(); return builder.Projection(); }, "Project a wire onto a face along the local surface normals " "using BRepAlgo_NormalProjection. See https://dev.opencascade.org/doc/refman/html/class_b_rep_algo___normal_projection.html") .def("Extend", [](const TopoDS_Face & face, double length, int continuity, bool inU, bool after) { if (continuity < 0 || continuity > 2) throw Exception("continuity must be 0, 1 or 2"); auto surf = BRep_Tool::Surface (face); auto bounded_surface = opencascade::handle::DownCast(surf); GeomLib::ExtendSurfByLength(bounded_surface, length, continuity, inU, after); return BRepBuilderAPI_MakeFace(bounded_surface, 1e-7).Face(); }, py::arg("length"), py::arg("continuity") = 1, py::arg("u_direction") = true, py::arg("after") = true, "Extend a bounded face in U or V by a given length with a requested continuity " "using GeomLib::ExtendSurfByLength. See https://dev.opencascade.org/doc/refman/html/class_geom_lib.html") ; py::class_ (m, "Solid") .def(py::init([](const TopoDS_Shape& faces) { BRep_Builder builder; TopoDS_Shell shell; builder.MakeShell(shell); for(auto& face : GetFaces(faces)) builder.Add(shell, face); TopoDS_Solid solid; builder.MakeSolid(solid); builder.Add(solid, shell); return solid; }), "Create solid from shell. Shell must consist of topologically closed faces (share vertices and edges).") ; py::class_ (m, "Compound") .def(py::init([](std::vector shapes, bool separate_layers) { BRep_Builder builder; TopoDS_Compound comp; builder.MakeCompound(comp); for(auto i : Range(shapes.size())) { builder.Add(comp, shapes[i]); if(separate_layers) { for(auto & s : GetSolids(shapes[i])) OCCGeometry::GetProperties(s).layer = i+1; for(auto & s : GetFaces(shapes[i])) OCCGeometry::GetProperties(s).layer = i+1; for(auto & s : GetEdges(shapes[i])) OCCGeometry::GetProperties(s).layer = i+1; for(auto & s : GetVertices(shapes[i])) OCCGeometry::GetProperties(s).layer = i+1; } } return comp; }), py::arg("shapes"), py::arg("separate_layers")=false, "Create a compound from a list of shapes. If separate_layers is true, assigns layer indices per input shape.") ; py::class_ (m, "Geom_Surface") .def("Value", [] (const Handle(Geom_Surface) & surf, double u, double v) { return surf->Value(u, v); }, "Evaluate the surface point at parameters (u, v).") .def("D1", [] (const Handle(Geom_Surface) & surf, double u, double v) { gp_Vec du, dv; gp_Pnt p; surf->D1 (u,v,p,du,dv); return tuple(p,du,dv); }, "Evaluate point and first derivatives (du, dv) at parameters (u, v).") .def("Normal", [] (const Handle(Geom_Surface) & surf, double u, double v) { GeomLProp_SLProps lprop(surf,u,v,1,1e-8); if (lprop.IsNormalDefined()) return lprop.Normal(); throw Exception("normal not defined"); }, "Compute the surface normal at parameters (u, v) if defined.") ; py::implicitly_convertible(); py::implicitly_convertible(); m.def("MakePolygon", [](std::vector verts) { BRepBuilderAPI_MakePolygon builder; for(auto& v : verts) builder.Add(v); return builder.Wire(); }, py::arg("verts"), "Create a polygonal wire by connecting vertices in order."); class ListOfShapesIterator { TopoDS_Shape * ptr; public: ListOfShapesIterator (TopoDS_Shape * aptr) : ptr(aptr) { } ListOfShapesIterator operator++ () { return ListOfShapesIterator(++ptr); } auto operator*() const { return CastShape(*ptr); } bool operator!=(ListOfShapesIterator it2) const { return ptr != it2.ptr; } bool operator==(ListOfShapesIterator it2) const { return ptr == it2.ptr; } }; py::class_ (m, "ListOfShapes") .def(py::init>(), "Create a list of shapes from a Python list.") .def("__iter__", [](ListOfShapes &s) { return py::make_iterator(ListOfShapesIterator(&*s.begin()), ListOfShapesIterator(&*s.end())); }, py::keep_alive<0, 1>() /* Essential: keep object alive while iterator exists */, "Iterate over shapes in the list.") .def("__getitem__", [](const ListOfShapes & list, size_t i) { return CastShape(list.at(i)); }, "Return the i-th shape from the list.") .def("__getitem__", [](const ListOfShapes & self, py::slice inds) { size_t start, step, n, stop; if (!inds.compute(self.size(), &start, &stop, &step, &n)) throw py::error_already_set(); ListOfShapes sub; sub.reserve(n); for (size_t i = 0; i < n; i++) sub.push_back (self[start+i*step]); return sub; }, "Return a sub-list of shapes using Python slice semantics.") .def("__add__", [](const ListOfShapes & l1, const ListOfShapes & l2) { ListOfShapes l = l1; for (auto s : l2) l.push_back(s); return l; }, "Concatenate two ListOfShapes instances.") .def("__add__", [](const ListOfShapes & l1, py::list l2) { ListOfShapes l = l1; for (auto s : l2) l.push_back(py::cast(s)); return l; }, "Concatenate a ListOfShapes with a Python list of shapes.") .def("__len__", [](const ListOfShapes & self) { return self.size(); }, "Return the number of shapes in the list.") .def("__getitem__",[](const ListOfShapes & self, string name) { ListOfShapes selected; std::regex pattern(name); for (auto s : self) if (auto sname = OCCGeometry::GetProperties(s).name) if (std::regex_match(*sname, pattern)) selected.push_back(s); return selected; }, "returns list of all shapes named 'name'") .def("__getitem__",[](const ListOfShapes & self, DirectionalInterval interval) { ListOfShapes selected; for (auto s : self) if (interval.Contains(Center(s), GetBoundingBox(s).Diam() * 1e-7)) selected.push_back(s); return selected; }, "Return shapes whose centers lie inside the given directional interval.") .def_property_readonly("solids", &ListOfShapes::Solids, "Return only solid sub-shapes.") .def_property_readonly("shells", &ListOfShapes::Shells, "Return only shell sub-shapes.") .def_property_readonly("faces", &ListOfShapes::Faces, "Return only face sub-shapes.") .def_property_readonly("wires", &ListOfShapes::Wires, "Return only wire sub-shapes.") .def_property_readonly("edges", &ListOfShapes::Edges, "Return only edge sub-shapes.") .def_property_readonly("vertices", &ListOfShapes::Vertices, "Return only vertex sub-shapes.") .def(py::self * py::self) .def("Sorted",[](ListOfShapes self, gp_Vec dir) { TopTools_IndexedMapOfShape indices; std::vector sortval; for (auto shape : self) { if(indices.FindIndex(shape) > 0) continue; GProp_GProps props; gp_Pnt center; switch (shape.ShapeType()) { case TopAbs_VERTEX: center = BRep_Tool::Pnt (TopoDS::Vertex(shape)); break; case TopAbs_FACE: BRepGProp::SurfaceProperties (shape, props); center = props.CentreOfMass(); break; default: BRepGProp::LinearProperties(shape, props); center = props.CentreOfMass(); } double val = center.X()*dir.X() + center.Y()*dir.Y() + center.Z() * dir.Z(); indices.Add(shape); sortval.push_back(val); } std::sort (std::begin(self), std::end(self), [&](const TopoDS_Shape& a, const TopoDS_Shape& b) { return sortval[indices.FindIndex(a)-1] < sortval[indices.FindIndex(b)-1]; }); return self; }, py::arg("dir"), "returns list of shapes, where center of gravity is sorted in direction of 'dir'") .def("Max", [] (ListOfShapes & shapes, gp_Vec dir) { return CastShape(shapes.Max(dir)); }, py::arg("dir"), "returns shape where center of gravity is maximal in the direction 'dir'") .def("Min", [] (ListOfShapes & shapes, gp_Vec dir) { return CastShape(shapes.Max(-dir)); }, py::arg("dir"), "returns shape where center of gravity is minimal in the direction 'dir'") .def("Nearest", [] (ListOfShapes & shapes, gp_Pnt pnt) { return CastShape(shapes.Nearest(pnt)); }, py::arg("p"), "returns shape nearest to point 'p'") .def("Nearest", [] (ListOfShapes & shapes, gp_Pnt2d pnt) { return CastShape(shapes.Nearest( { pnt.X(), pnt.Y(), 0 })); }, py::arg("p"), "returns shape nearest to point 'p'") .def_property("name", [](ListOfShapes& shapes) { throw Exception("Cannot get property of ListOfShapes, get the property from individual shapes!"); }, [](ListOfShapes& shapes, optional name) { for(auto& shape : shapes) { OCCGeometry::GetProperties(shape).name = name; } }, "set name for all elements of list") .def_property("col", [](ListOfShapes& shapes) { throw Exception("Cannot get property of ListOfShapes, get the property from individual shapes!"); }, [](ListOfShapes& shapes, std::vector c) { Vec<4> col(c[0], c[1], c[2], 1.0); if(c.size() == 4) col[3] = c[3]; for(auto& shape : shapes) OCCGeometry::GetProperties(shape).col = col; }, "set col for all elements of list") .def_property("maxh", [](ListOfShapes& shapes) { throw Exception("Cannot get property of ListOfShapes, get the property from individual shapes!"); }, [](ListOfShapes& shapes, double maxh) { for(auto & s : shapes) OCCGeometry::GetProperties(s).maxh = maxh; }, "set maxh for all elements of list") .def_property("hpref", [](ListOfShapes& shapes) { throw Exception("Cannot get property of ListOfShapes, get the property from individual shapes!"); }, [](ListOfShapes& shapes, double hpref) { for(auto& shape : shapes) OCCGeometry::GetProperties(shape).hpref = hpref; }, "set hpref for all elements of list") .def_property("quad_dominated", [](ListOfShapes& shapes) { throw Exception("Cannot get property of ListOfShapes, get the property from individual shapes!"); }, [](ListOfShapes& shapes, optional quad_dominated) { for(auto& shape : shapes) OCCGeometry::GetProperties(shape).quad_dominated = quad_dominated; }, "Set the quad-dominated meshing hint for all shapes in the list.") .def("Identify", [](const ListOfShapes& me, const ListOfShapes& other, string name, Identifications::ID_TYPE type, std::variant trafo) { Identify(me, other, name, type, occ2ng(trafo)); }, py::arg("other"), py::arg("name"), py::arg("type")=Identifications::PERIODIC, py::arg("trafo"), "Identify shapes for periodic meshing") ; py::class_ (m, "Geom2d_Curve") .def("Trim", [](Handle(Geom2d_Curve) curve, double u1, double u2) -> Handle(Geom2d_Curve) { return new Geom2d_TrimmedCurve (curve, u1, u2); }, "Return a trimmed 2D curve on the parameter interval [u1, u2].") .def("Value", [](Handle(Geom2d_Curve) curve, double s) { return curve->Value(s); }, "Evaluate the 2D curve at parameter s.") .def_property_readonly("start", [](Handle(Geom2d_Curve) curve) { return curve->Value(curve->FirstParameter()); }, "Start point of the curve in parameter space.") .def_property_readonly("end", [](Handle(Geom2d_Curve) curve) { return curve->Value(curve->LastParameter()); }, "End point of the curve in parameter space.") .def("Edge", [](Handle(Geom2d_Curve) curve) { // static Geom_Plane surf{gp_Ax3()}; // crashes in nbconvert ??? static auto surf = Handle(Geom_Plane)(new Geom_Plane{gp_Ax3()}); auto edge = BRepBuilderAPI_MakeEdge(curve, surf).Edge(); BRepLib::BuildCurves3d(edge); return edge; }, "Lift the 2D curve to the default plane and return a 3D edge.") .def("Wire", [](Handle(Geom2d_Curve) curve) { // static Geom_Plane surf{gp_Ax3()}; // crashes in nbconvert ??? static auto surf = Handle(Geom_Plane)(new Geom_Plane{gp_Ax3()}); auto edge = BRepBuilderAPI_MakeEdge(curve, surf).Edge(); BRepLib::BuildCurves3d(edge); return BRepBuilderAPI_MakeWire(edge).Wire(); }, "Create a wire from the lifted 2D curve on the default plane.") .def("Face", [](Handle(Geom2d_Curve) curve) { // static Geom_Plane surf{gp_Ax3()}; // crashes in nbconvert ??? static auto surf = Handle(Geom_Plane)(new Geom_Plane{gp_Ax3()}); auto edge = BRepBuilderAPI_MakeEdge(curve, surf).Edge(); BRepLib::BuildCurves3d(edge); auto wire = BRepBuilderAPI_MakeWire(edge).Wire(); return BRepBuilderAPI_MakeFace(wire).Face(); }, "Create a planar face bounded by the lifted 2D curve.") ; py::enum_(m, "ShapeContinuity", "Wrapper for OCC enum GeomAbs_Shape") .value("C0", GeomAbs_Shape::GeomAbs_C0) .value("C1", GeomAbs_Shape::GeomAbs_C1) .value("C2", GeomAbs_Shape::GeomAbs_C2) .value("C3", GeomAbs_Shape::GeomAbs_C3) .value("CN", GeomAbs_Shape::GeomAbs_CN) .value("G1", GeomAbs_Shape::GeomAbs_G1) .value("G2", GeomAbs_Shape::GeomAbs_G2); py::enum_(m, "ApproxParamType", "Wrapper for Approx_ParametrizationType") .value("Centripetal", Approx_ParametrizationType::Approx_Centripetal) .value("ChordLength", Approx_ParametrizationType::Approx_ChordLength) .value("IsoParametric", Approx_ParametrizationType::Approx_IsoParametric); m.def("HalfSpace", [] (gp_Pnt p, gp_Vec n) { gp_Pln plane(p, n); BRepBuilderAPI_MakeFace bface(plane); auto face = bface.Face(); auto refpnt = p.Translated(-n); BRepPrimAPI_MakeHalfSpace builder(face, refpnt); return builder.Shape(); }, py::arg("p"), py::arg("n"), "Create a half-space bounded by a plane through point p with normal n."); m.def("Sphere", [] (gp_Pnt cc, double r) { return BRepPrimAPI_MakeSphere (cc, r).Solid(); }, py::arg("c"), py::arg("r"), "Create a sphere with center c and radius r."); m.def("Ellipsoid", [] (gp_Ax3 ax, double r1, double r2, optional hr3) { auto sp = BRepPrimAPI_MakeSphere (gp_Pnt(0,0,0), 1).Solid(); gp_GTrsf gtrafo; double r3 = hr3.value_or(r2); gtrafo.SetVectorialPart({ r2, 0, 0, 0, r3, 0, 0, 0, r1 }); gtrafo.SetTranslationPart( { 0.0, 0.0, 0.0 } ); BRepBuilderAPI_GTransform gbuilder(sp, gtrafo, true); PropagateProperties(gbuilder, sp, occ2ng(gtrafo)); auto gsp = gbuilder.Shape(); gp_Trsf trafo; trafo.SetTransformation(ax, gp_Ax3()); BRepBuilderAPI_Transform builder(gsp, trafo, true); PropagateProperties(builder, gsp, occ2ng(trafo)); return builder.Shape(); }, py::arg("axes"), py::arg("r1"), py::arg("r2"), py::arg("r3")=std::nullopt, "Create an ellipsoid aligned with axes, with radii r1, r2, and optional r3 (defaults to r2)."); m.def("Cylinder", [] (gp_Pnt cpnt, gp_Dir cdir, double r, double h, optional bot, optional top, optional mantle) { auto builder = BRepPrimAPI_MakeCylinder (gp_Ax2(cpnt, cdir), r, h); if(mantle) OCCGeometry::GetProperties(builder.Face()).name = *mantle; auto pyshape = py::cast(builder.Solid()); gp_Vec v = cdir; if(bot) pyshape.attr("faces").attr("Min")(v).attr("name") = *bot; if(top) pyshape.attr("faces").attr("Max")(v).attr("name") = *top; return pyshape; }, py::arg("p"), py::arg("d"), py::arg("r"), py::arg("h"), py::arg("bottom") = nullopt, py::arg("top") = nullopt, py::arg("mantle") = nullopt, "Create a cylinder at base point p with axis direction d, radius r, and height h. Optional face names: bottom/top/mantle."); m.def("Cylinder", [] (gp_Ax2 ax, double r, double h) { return BRepPrimAPI_MakeCylinder (ax, r, h).Solid(); }, py::arg("axis"), py::arg("r"), py::arg("h"), "Create a cylinder defined by axis, radius, and height."); m.def("Cone", [] (gp_Ax2 ax, double r1, double r2, double h, double angle) { return BRepPrimAPI_MakeCone (ax, r1, r2, h, angle).Solid(); }, py::arg("axis"), py::arg("r1"), py::arg("r2"), py::arg("h"), py::arg("angle"), "Create a cone defined by axis, bottom radius r1, top radius r2, height h, and semi-angle."); m.def("Box", [] (gp_Pnt cp1, gp_Pnt cp2) { return BRepPrimAPI_MakeBox (cp1, cp2).Solid(); }, py::arg("p1"), py::arg("p2"), "Create a box defined by two opposite corner points p1 and p2."); m.def("Prism", [] (const TopoDS_Shape & face, gp_Vec vec) { return BRepPrimAPI_MakePrism (face, vec, true).Shape(); }, py::arg("face"), py::arg("v"), "Extrude a face (or shape) along the vector v to create a prism."); m.def("Revolve", [] (const TopoDS_Shape & face,const gp_Ax1 &A, const double D) { //convert angle from deg to rad return BRepPrimAPI_MakeRevol (face, A, D*M_PI/180, true).Shape(); }, "Revolve a shape around an axis by an angle in degrees."); m.def("Pipe", [] (const TopoDS_Wire & spine, const TopoDS_Shape & profile, optional> twist, optional auxspine) { if (twist) { // auto [pnt, angle] = *twist; /* cyl = Cylinder((0,0,0), Z, r=1, h=1).faces[0] heli = Edge(Segment((0,0), (2*math.pi, 1)), cyl) auxspine = Wire( [heli] ) Handle(Geom_Surface) cyl = new Geom_CylindricalSurface (gp_Ax3(pnt, gp_Vec(0,0,1)), 1); auto edge = BRepBuilderAPI_MakeEdge(curve2d, cyl).Edge(); BRepLib::BuildCurves3d(edge); */ throw Exception("twist not implemented"); } if (auxspine) { BRepOffsetAPI_MakePipeShell builder(spine); builder.SetMode (*auxspine, Standard_True); for (TopExp_Explorer e(profile, TopAbs_WIRE); e.More(); e.Next()) builder.Add (TopoDS::Wire(e.Current())); builder.Build(); builder.MakeSolid(); return builder.Shape(); } return BRepOffsetAPI_MakePipe (spine, profile).Shape(); }, py::arg("spine"), py::arg("profile"), py::arg("twist")=nullopt, py::arg("auxspine")=nullopt, "Create a pipe by sweeping a profile along a spine wire. " "If auxspine is provided, uses a pipe shell with the auxiliary spine for orientation."); m.def("PipeShell", [] (const TopoDS_Wire & spine, variant> profile, std::optional auxspine) { try { BRepOffsetAPI_MakePipeShell builder(spine); if(auxspine) builder.SetMode (*auxspine, Standard_True); if(std::holds_alternative(profile)) builder.Add (std::get(profile)); else { for(auto s : std::get>(profile)) builder.Add(s); } return builder.Shape(); } catch (Standard_Failure & e) { stringstream errstr; e.Print(errstr); throw NgException("cannot create PipeShell: "+errstr.str()); } }, py::arg("spine"), py::arg("profile"), py::arg("auxspine")=nullopt, "Create a pipe shell by sweeping one or more profiles along a spine wire. " "Optionally uses an auxiliary spine to control orientation."); // Handle(Geom2d_Ellipse) anEllipse1 = new Geom2d_Ellipse(anAx2d, aMajor, aMinor); m.def("Ellipse", [] (const gp_Ax2d & ax, double major, double minor) -> Handle(Geom2d_Curve) { return Handle(Geom2d_Ellipse) (GCE2d_MakeEllipse(ax, major, minor)); }, py::arg("axes"), py::arg("major"), py::arg("minor"), "Create a 2D ellipse curve defined by axes and major/minor radii."); m.def("Segment", [](gp_Pnt2d p1, gp_Pnt2d p2) -> Handle(Geom2d_Curve) { return Handle(Geom2d_TrimmedCurve)(GCE2d_MakeSegment(p1, p2)); /* Handle(Geom2d_TrimmedCurve) curve = GCE2d_MakeSegment(p1, p2); return curve; */ }, py::arg("p1"), py::arg("p2"), "Create a 2D line segment curve from p1 to p2."); m.def("Circle", [](gp_Pnt2d p1, double r) -> Handle(Geom2d_Curve) { return Handle(Geom2d_Circle)(GCE2d_MakeCircle(p1, r)); /* Handle(Geom2d_Circle) curve = GCE2d_MakeCircle(p1, r); return curve; */ }, py::arg("c"), py::arg("r"), "Create a 2D circle curve with center c and radius r."); m.def("SplineApproximation", [](const std::vector &points, Approx_ParametrizationType approx_type, int deg_min, int deg_max, GeomAbs_Shape continuity, double tol) -> Handle(Geom2d_Curve) { TColgp_Array1OfPnt2d hpoints(0, 0); hpoints.Resize(0, points.size() - 1, true); for (int i = 0; i < points.size(); i++) hpoints.SetValue(i, points[i]); Geom2dAPI_PointsToBSpline builder(hpoints, approx_type, deg_min, deg_max, continuity, tol); return Handle(Geom2d_BSplineCurve)(builder.Curve()); }, py::arg("points"), py::arg("approx_type") = Approx_ParametrizationType::Approx_ChordLength, py::arg("deg_min") = 3, py::arg("deg_max") = 8, py::arg("continuity") = GeomAbs_Shape::GeomAbs_C2, py::arg("tol")=1e-8, R"delimiter( Generate a piecewise continuous spline-curve approximating a list of points in 2d. Parameters ---------- points : List|Tuple[gp_Pnt2d] List (or tuple) of gp_Pnt. approx_type : ApproxParamType Assumption on location of parameters wrt points. deg_min : int Minimum polynomial degree of splines deg_max : int Maximum polynomial degree of splines continuity : ShapeContinuity Continuity requirement on the approximating surface tol : float Tolerance for the distance from individual points to the approximating curve. )delimiter"); m.def("SplineInterpolation", [](const std::vector &points, bool periodic, double tol, const std::map &tangents) -> Handle(Geom2d_Curve) { Handle(TColgp_HArray1OfPnt2d) hpoints = new TColgp_HArray1OfPnt2d(1, points.size()); for (int i = 0; i < points.size(); i++) hpoints->SetValue(i+1, points[i]); Geom2dAPI_Interpolate builder(hpoints, periodic, tol); if (tangents.size() > 0) { const gp_Vec2d dummy_vec = tangents.begin()->second; TColgp_Array1OfVec2d tangent_vecs(1, points.size()); Handle(TColStd_HArray1OfBoolean) tangent_flags = new TColStd_HArray1OfBoolean(1, points.size()); for (int i : Range(points.size())) { if (tangents.count(i) > 0) { tangent_vecs.SetValue(i+1, tangents.at(i)); tangent_flags->SetValue(i+1, true); } else{ tangent_vecs.SetValue(i+1, dummy_vec); tangent_flags->SetValue(i+1, false); } } builder.Load(tangent_vecs, tangent_flags); } builder.Perform(); return Handle(Geom2d_BSplineCurve)(builder.Curve()); }, py::arg("points"), py::arg("periodic")=false, py::arg("tol")=1e-8, py::arg("tangents")=std::map{}, R"delimiter( Generate a piecewise continuous spline-curve interpolating a list of points in 2d. Parameters ---------- points : List|Tuple[gp_Pnt2d] List (or tuple) of gp_Pnt2d. periodic : bool Whether the result should be periodic tol : float Tolerance for the distance between points. tangents : Dict[int, gp_Vec2d] Tangent vectors for the points indicated by the key value (0-based). )delimiter"); m.def("Sew", [] (const std::vector & faces, double tol, bool non_manifold) -> TopoDS_Shape { if(faces.size() == 1) return faces[0]; BRepBuilderAPI_Sewing sewer(tol); sewer.SetNonManifoldMode(non_manifold); for (auto & s : faces) sewer.Add(s); sewer.Perform(); for (auto & s : faces) PropagateProperties (sewer, s); auto sewn = sewer.SewedShape(); return sewn; }, py::arg("faces"), py::arg("tolerance")=1e-6, py::arg("non_manifold")=false, R"doc( Stitch a list of faces into one or more connected shells. Parameters ---------- faces : list[TopoDS_Shape] Faces or other shapes to sew together. tolerance : float, default=1e-6 Geometric tolerance for merging edges and vertices. non_manifold : bool, default=False If True, allows edges shared by more than two faces (may produce multiple shells). If False, creates only manifold shells suitable for solids. Returns ------- TopoDS_Shape The sewed shape containing one or more shells. )doc"); m.def("Glue", [] (const std::vector shapes) -> TopoDS_Shape { if(shapes.size() == 1) return shapes[0]; BOPAlgo_Builder builder; for (auto & s : shapes) { bool has_solid = false; for (TopExp_Explorer e(s, TopAbs_SOLID); e.More(); e.Next()) { builder.AddArgument(e.Current()); has_solid = true; } if (has_solid) continue; bool has_face = false; for (TopExp_Explorer e(s, TopAbs_FACE); e.More(); e.Next()) { builder.AddArgument(e.Current()); has_face = true; } if (has_face) continue; bool has_edge = false; for (TopExp_Explorer e(s, TopAbs_EDGE); e.More(); e.Next()) { builder.AddArgument(e.Current()); has_edge = true; } if (has_edge) continue; for (TopExp_Explorer e(s, TopAbs_VERTEX); e.More(); e.Next()) { builder.AddArgument(e.Current()); } } builder.Perform(); /* #ifdef OCC_HAVE_HISTORY Handle(BRepTools_History) history = builder.History (); for (auto typ : { TopAbs_SOLID, TopAbs_FACE, TopAbs_EDGE }) for (auto & s : shapes) for (TopExp_Explorer e(s, typ); e.More(); e.Next()) { auto prop = OCCGeometry::GetProperties(e.Current()); for (auto mods : history->Modified(e.Current())) OCCGeometry::GetProperties(mods).Merge(prop); } #endif // OCC_HAVE_HISTORY */ for (auto & s : shapes) PropagateProperties (builder, s); return builder.Shape(); }, py::arg("shapes"), "glue together shapes of list"); m.def("Glue", [] (TopoDS_Shape shape) -> TopoDS_Shape { BOPAlgo_Builder builder; for (TopExp_Explorer e(shape, TopAbs_SOLID); e.More(); e.Next()) builder.AddArgument(e.Current()); builder.Perform(); if (builder.HasErrors()) builder.DumpErrors(cout); if (builder.HasWarnings()) builder.DumpWarnings(cout); /* #ifdef OCC_HAVE_HISTORY Handle(BRepTools_History) history = builder.History (); for (TopExp_Explorer e(shape, TopAbs_SOLID); e.More(); e.Next()) { auto prop = OCCGeometry::GetProperties(e.Current()); for (auto mods : history->Modified(e.Current())) OCCGeometry::GetProperties(mods).Merge(prop); } #endif // OCC_HAVE_HISTORY */ PropagateProperties (builder, shape); return builder.Shape(); }, py::arg("shape"), "glue together shapes from shape, typically a compound"); m.def("Fuse", [](const vector& shapes) -> TopoDS_Shape { auto s = shapes[0]; for(auto i : Range(size_t(1), shapes.size())) { BRepAlgoAPI_Fuse builder(s, shapes[i]); PropagateProperties(builder, s); PropagateProperties(builder, shapes[i]); s = builder.Shape(); } return s; }, "Fuse a list of shapes sequentially (pairwise) using BRepAlgoAPI_Fuse."); // py::class_ (m, "Geom_TrimmedCurve") // ; m.def("Segment", [](gp_Pnt p1, gp_Pnt p2) { Handle(Geom_TrimmedCurve) curve = GC_MakeSegment(p1, p2); return BRepBuilderAPI_MakeEdge(curve).Edge(); }, py::arg("p1"), py::arg("p2"), "Create a straight edge between two points."); m.def("Circle", [](gp_Pnt c, gp_Dir n, double r) { Handle(Geom_Circle) curve = GC_MakeCircle (c, n, r); return BRepBuilderAPI_MakeEdge(curve).Edge(); }, py::arg("center"), py::arg("normal"), py::arg("radius"), "Create a circular edge defined by center, normal, and radius."); m.def("ArcOfCircle", [](gp_Pnt p1, gp_Pnt p2, gp_Pnt p3) { Handle(Geom_TrimmedCurve) curve = GC_MakeArcOfCircle(p1, p2, p3); return BRepBuilderAPI_MakeEdge(curve).Edge(); }, py::arg("p1"), py::arg("p2"), py::arg("p3"), "Create a circular arc from p1 through p2 to p3."); m.def("ArcOfCircle", [](gp_Pnt p1, gp_Vec v, gp_Pnt p2) { Handle(Geom_TrimmedCurve) curve = GC_MakeArcOfCircle(p1, v, p2); return BRepBuilderAPI_MakeEdge(curve).Edge(); }, py::arg("p1"), py::arg("v"), py::arg("p2"), "Create a circular arc from p1 to p2 with tangent vector v at p1."); m.def("BSplineCurve", [](std::vector vpoles, int degree) { // not yet working ???? TColgp_Array1OfPnt poles(0, vpoles.size()-1); TColStd_Array1OfReal knots(0, vpoles.size()+degree); TColStd_Array1OfInteger mult(0, vpoles.size()+degree); // int cnt = 0; for (int i = 0; i < vpoles.size(); i++) { poles.SetValue(i, vpoles[i]); knots.SetValue(i, i); mult.SetValue(i,1); } for (int i = vpoles.size(); i < vpoles.size()+degree+1; i++) { knots.SetValue(i, i); mult.SetValue(i, 1); } Handle(Geom_Curve) curve = new Geom_BSplineCurve(poles, knots, mult, degree); return BRepBuilderAPI_MakeEdge(curve).Edge(); }, py::arg("poles"), py::arg("degree"), "Create a B-spline edge from control points and degree (experimental)."); m.def("BezierCurve", [](std::vector vpoles) { TColgp_Array1OfPnt poles(0, vpoles.size()-1); for (int i = 0; i < vpoles.size(); i++) poles.SetValue(i, vpoles[i]); Handle(Geom_Curve) curve = new Geom_BezierCurve(poles); return BRepBuilderAPI_MakeEdge(curve).Edge(); }, py::arg("points"), "Create a Bezier curve from control points."); m.def("BezierSurface", [](py::array_t nppoles, optional> npweights, double tol) { if(nppoles.ndim() != 3) throw std::length_error("`poles` array must have dimension 3."); if(nppoles.shape(2) != 3) throw std::length_error("The third dimension must have size 3."); if(npweights && npweights->ndim() != 2) throw std::length_error("`weights` array must have dimension 2."); auto deg_u = nppoles.shape(0) - 1; auto deg_v = nppoles.shape(1) - 1; TColgp_Array2OfPnt poles(1, deg_u + 1, 1, deg_v + 1); TColStd_Array2OfReal weights(1, deg_u + 1, 1, deg_v + 1); for(int i = 0; i < nppoles.shape(0); ++i) for(int j = 0; j < nppoles.shape(1); ++j) { poles.SetValue(i + 1, j + 1, gp_Pnt(nppoles.at(i, j, 0), nppoles.at(i, j, 1), nppoles.at(i, j, 2))); if(npweights) weights.SetValue(i + 1, j + 1, npweights->at(i, j)); else weights.SetValue(i + 1, j + 1, 1.0); } Handle(Geom_Surface) surface = new Geom_BezierSurface(poles, weights); return BRepBuilderAPI_MakeFace(surface, tol).Face(); }, py::arg("poles"), py::arg("weights")=std::nullopt, py::arg("tol")=1e-7, "Creates a rational Bezier surface with the set of poles and the set of weights. The weights are defaulted to all being 1. If all the weights are identical the surface is considered as non rational. Raises ConstructionError if the number of poles in any direction is greater than MaxDegree + 1 or lower than 2 or CurvePoles and CurveWeights have not the same length or one weight value is lower or equal to Resolution. Returns an occ face with the given tolerance."); m.def("SplineApproximation", [](const std::vector &points, Approx_ParametrizationType approx_type, int deg_min, int deg_max, GeomAbs_Shape continuity, double tol) { TColgp_Array1OfPnt hpoints(0, 0); hpoints.Resize(0, points.size() - 1, true); for (int i = 0; i < points.size(); i++) hpoints.SetValue(i, points[i]); GeomAPI_PointsToBSpline builder(hpoints, approx_type, deg_min, deg_max, continuity, tol); return BRepBuilderAPI_MakeEdge(builder.Curve()).Edge(); }, py::arg("points"), py::arg("approx_type") = Approx_ParametrizationType::Approx_ChordLength, py::arg("deg_min") = 3, py::arg("deg_max") = 8, py::arg("continuity") = GeomAbs_Shape::GeomAbs_C2, py::arg("tol")=1e-8, R"delimiter( Generate a piecewise continuous spline-curve approximating a list of points in 3d. Parameters ---------- points : List[gp_Pnt] or Tuple[gp_Pnt] List (or tuple) of gp_Pnt. approx_type : ApproxParamType Assumption on location of parameters wrt points. deg_min : int Minimum polynomial degree of splines deg_max : int Maximum polynomial degree of splines continuity : ShapeContinuity Continuity requirement on the approximating surface tol : float Tolerance for the distance from individual points to the approximating curve. )delimiter"); m.def("SplineInterpolation", [](const std::vector &points, bool periodic, double tol, const std::map &tangents) { Handle(TColgp_HArray1OfPnt) hpoints = new TColgp_HArray1OfPnt(1, points.size()); for (int i = 0; i < points.size(); i++) hpoints->SetValue(i+1, points[i]); GeomAPI_Interpolate builder(hpoints, periodic, tol); if (tangents.size() > 0) { const gp_Vec dummy_vec = tangents.begin()->second; TColgp_Array1OfVec tangent_vecs(1, points.size()); Handle(TColStd_HArray1OfBoolean) tangent_flags = new TColStd_HArray1OfBoolean(1, points.size()); for (int i : Range(points.size())) { if (tangents.count(i) > 0) { tangent_vecs.SetValue(i+1, tangents.at(i)); tangent_flags->SetValue(i+1, true); } else{ tangent_vecs.SetValue(i+1, dummy_vec); tangent_flags->SetValue(i+1, false); } } builder.Load(tangent_vecs, tangent_flags); } builder.Perform(); return BRepBuilderAPI_MakeEdge(builder.Curve()).Edge(); }, py::arg("points"), py::arg("periodic")=false, py::arg("tol")=1e-8, py::arg("tangents")=std::map{}, R"delimiter( Generate a piecewise continuous spline-curve interpolating a list of points in 3d. Parameters ---------- points : List|Tuple[gp_Pnt] List (or tuple) of gp_Pnt periodic : bool Whether the result should be periodic tol : float Tolerance for the distance between points. tangents : Dict[int, gp_Vec] Tangent vectors for the points indicated by the key value (0-based). )delimiter"); m.def("SplineSurfaceApproximation", [](py::array_t pnt_array, Approx_ParametrizationType approx_type, int deg_min, int deg_max, GeomAbs_Shape continuity, double tol, bool periodic, double degen_tol) { if (pnt_array.ndim() != 3) throw Exception("`points` array must have dimension 3."); if (pnt_array.shape(2) != 3) throw Exception("The third dimension must have size 3."); auto array = py::extract>(pnt_array)(); TColgp_Array2OfPnt points(1, pnt_array.shape(0), 1, pnt_array.shape(1)); auto pnts_unchecked = pnt_array.unchecked<3>(); for (int i = 0; i < pnt_array.shape(0); ++i) for (int j = 0; j < pnt_array.shape(1); ++j) points.SetValue(i+1, j+1, gp_Pnt(pnts_unchecked(i, j, 0), pnts_unchecked(i, j, 1), pnts_unchecked(i, j, 2))); GeomAPI_PointsToBSplineSurface builder; #if OCC_VERSION_MAJOR>=7 && OCC_VERSION_MINOR>=4 builder.Init(points, approx_type, deg_min, deg_max, continuity, tol, periodic); #else if(periodic) throw Exception("periodic not supported"); builder.Init(points, approx_type, deg_min, deg_max, continuity, tol); #endif return BRepBuilderAPI_MakeFace(builder.Surface(), tol).Face(); }, py::arg("points"), py::arg("approx_type") = Approx_ParametrizationType::Approx_ChordLength, py::arg("deg_min") = 3, py::arg("deg_max") = 8, py::arg("continuity") = GeomAbs_Shape::GeomAbs_C2, py::arg("tol") = 1e-3, py::arg("periodic") = false, py::arg("degen_tol") = 1e-8, R"delimiter( Generate a piecewise continuous spline-surface approximating an array of points. Parameters ---------- points : np.ndarray Array of points coordinates. The first dimension corresponds to the first surface coordinate point index, the second dimension to the second surface coordinate point index. The third dimension refers to physical coordinates. Such an array can be generated with code like:: px, py = np.meshgrid(*[np.linspace(0, 1, N)]*2) points = np.array([[(px[i,j], py[i,j], px[i,j]*py[i,j]**2) for j in range(N)] for i in range(N)]) approx_type : ApproxParamType Assumption on location of parameters wrt points. deg_min : int Minimum polynomial degree of splines deg_max : int Maximum polynomial degree of splines continuity : ShapeContinuity Continuity requirement on the approximating surface tol : float Tolerance for the distance from individual points to the approximating surface. periodic : bool Whether the result should be periodic in the first surface parameter degen_tol : double Tolerance for resolution of degenerate edges )delimiter"); m.def("SplineSurfaceInterpolation", []( py::array_t pnt_array, Approx_ParametrizationType approx_type, bool periodic, double degen_tol) { if (pnt_array.ndim() != 3) throw Exception("`points` array must have dimension 3."); if (pnt_array.shape(2) != 3) throw Exception("The third dimension must have size 3."); auto array = py::extract>(pnt_array)(); TColgp_Array2OfPnt points(1, pnt_array.shape(0), 1, pnt_array.shape(1)); auto pnts_unchecked = pnt_array.unchecked<3>(); for (int i = 0; i < pnt_array.shape(0); ++i) for (int j = 0; j < pnt_array.shape(1); ++j) points.SetValue(i+1, j+1, gp_Pnt(pnts_unchecked(i, j, 0), pnts_unchecked(i, j, 1), pnts_unchecked(i, j, 2))); GeomAPI_PointsToBSplineSurface builder; #if OCC_VERSION_MAJOR>=7 && OCC_VERSION_MINOR>=4 builder.Interpolate(points, approx_type, periodic); #else if(periodic) throw Exception("periodic not supported"); builder.Interpolate(points, approx_type); #endif return BRepBuilderAPI_MakeFace(builder.Surface(), degen_tol).Face(); }, py::arg("points"), py::arg("approx_type") = Approx_ParametrizationType::Approx_ChordLength, py::arg("periodic") = false, py::arg("degen_tol") = 1e-8, R"delimiter( Generate a piecewise continuous spline-surface interpolating an array of points. Parameters ---------- points : np.ndarray Array of points coordinates. The first dimension corresponds to the first surface coordinate point index, the second dimension to the second surface coordinate point index. The third dimension refers to physical coordinates. Such an array can be generated with code like:: px, py = np.meshgrid(*[np.linspace(0, 1, N)]*2) points = np.array([[(px[i,j], py[i,j], px[i,j]*py[i,j]**2) for j in range(N)] for i in range(N)]) approx_type : ApproxParamType Assumption on location of parameters wrt points. periodic : bool Whether the result should be periodic in the first surface parameter degen_tol : double Tolerance for resolution of degenerate edges )delimiter"); m.def("MakeFillet", [](TopoDS_Shape shape, std::vector edges, double r) { throw Exception("call 'shape.MakeFilled'"); BRepFilletAPI_MakeFillet mkFillet(shape); for (auto e : edges) mkFillet.Add (r, TopoDS::Edge(e)); return mkFillet.Shape(); }, "deprecated, use 'shape.MakeFillet'"); m.def("MakeThickSolid", [](TopoDS_Shape body, std::vector facestoremove, double offset, double tol) { throw Exception("call 'shape.MakeThickSolid'"); TopTools_ListOfShape faces; for (auto f : facestoremove) faces.Append(f); BRepOffsetAPI_MakeThickSolid maker; maker.MakeThickSolidByJoin(body, faces, offset, tol); return maker.Shape(); }, "deprecated, use 'shape.MakeThickSolid'"); m.def("ThruSections", [](std::vector wires, bool solid) { BRepOffsetAPI_ThruSections aTool(solid); // Standard_True); for (auto shape : wires) aTool.AddWire(TopoDS::Wire(shape)); aTool.CheckCompatibility(Standard_False); return aTool.Shape(); }, py::arg("wires"), py::arg("solid")=true, "Building a loft. This is a shell or solid passing through a set of sections (wires). " "First and last sections may be vertices. See https://dev.opencascade.org/doc/refman/html/class_b_rep_offset_a_p_i___thru_sections.html#details"); m.def("ConnectEdgesToWires", [](const vector& edges, double tol, bool shared) { Handle(TopTools_HSequenceOfShape) sedges = new TopTools_HSequenceOfShape; Handle(TopTools_HSequenceOfShape) swires = new TopTools_HSequenceOfShape; for(auto& e : edges) sedges->Append(e); ShapeAnalysis_FreeBounds::ConnectEdgesToWires(sedges, tol, shared, swires); vector wires; for(auto& w : *swires) wires.push_back(TopoDS::Wire(w)); return wires; }, py::arg("edges"), py::arg("tol")=1e-8, py::arg("shared")=true, "Connect edges into one or more wires using ShapeAnalysis_FreeBounds::ConnectEdgesToWires."); py::class_> (m, "WorkPlane") .def(py::init(), py::arg("axes")=gp_Ax3(), py::arg("pos")=gp_Ax2d()) .def_property_readonly("cur_loc", &WorkPlane::CurrentLocation) .def_property_readonly("cur_dir", &WorkPlane::CurrentDirection) .def_property_readonly("start_pnt", &WorkPlane::StartPnt) .def("MoveTo", &WorkPlane::MoveTo, py::arg("h"), py::arg("v"), "moveto (h,v), and start new wire") .def("Move", &WorkPlane::Move, py::arg("l"), "move 'l' from current position and direction, start new wire") .def("Direction", &WorkPlane::Direction, py::arg("dirh"), py::arg("dirv"), "reset direction to (dirh, dirv)") // .def("LineTo", &WorkPlane::LineTo) .def("LineTo", [](WorkPlane&wp, double x, double y, optional name) { return wp.LineTo(x, y, name); }, py::arg("h"), py::arg("v"), py::arg("name")=nullopt, "draw line to position (h,v)") .def("ArcTo", &WorkPlane::ArcTo, py::arg("h"), py::arg("v"), py::arg("t"), py::arg("name")=nullopt, py::arg("maxh")=nullopt) .def("Arc", &WorkPlane::Arc, py::arg("r"), py::arg("ang"), py::arg("name")=nullopt, py::arg("maxh")=nullopt, "draw arc tangential to current pos/dir, of radius 'r' and angle 'ang', draw to the left/right if ang is positive/negative") .def("Rotate", &WorkPlane::Rotate, py::arg("ang"), "rotate current direction by 'ang' degrees") .def("Line", [](WorkPlane&wp,double l, optional name) { return wp.Line(l, name); }, py::arg("l"), py::arg("name")=nullopt) .def("Line", [](WorkPlane&wp,double h,double v, optional name) { return wp.Line(h,v,name); }, py::arg("dx"), py::arg("dy"), py::arg("name")=nullopt) .def("Spline", &WorkPlane::Spline, py::arg("points"), py::arg("periodic")=false, py::arg("tol")=1e-8, py::arg("tangents")=std::map{}, py::arg("start_from_localpos")=true, py::arg("name")=nullopt, "draw spline (default: starting from current position, which is implicitly added to given list of points), tangents can be specified for each point (0 refers to starting point)") .def("Rectangle", &WorkPlane::Rectangle, py::arg("l"), py::arg("w"), py::arg("name")=nullopt, "draw rectangle, with current position as corner, use current direction") .def("RectangleC", &WorkPlane::RectangleCentered, py::arg("l"), py::arg("w"), py::arg("name")=nullopt, "draw rectangle, with current position as center, use current direction") .def("Circle", [](WorkPlane&wp, double x, double y, double r) { return wp.Circle(x,y,r); }, py::arg("h"), py::arg("v"), py::arg("r"), "draw circle with center (h,v) and radius 'r'") .def("Circle", [](WorkPlane&wp, double r) { return wp.Circle(r); }, py::arg("r"), "draw circle with center in current position") .def("Ellipse", [](WorkPlane& wp, double major, double minor) { return wp.Ellipse(major, minor); }, py::arg("major"), py::arg("minor"), "draw ellipse with current position as center") .def("NameVertex", &WorkPlane::NameVertex, py::arg("name"), "name vertex at current position") .def("Offset", &WorkPlane::Offset, py::arg("d"), "replace current wire by offset curve of distance 'd'") .def("Reverse", &WorkPlane::Reverse, "revert orientation of current wire") .def("Close", &WorkPlane::Close, py::arg("name")=nullopt, "draw line to start point of wire, and finish wire") .def("Finish", &WorkPlane::Finish, "finish current wire without closing") .def("Last", &WorkPlane::Last, "(deprecated) returns current wire") .def("Wire", &WorkPlane::Last, "returns current wire") .def("Face", &WorkPlane::Face, "generate and return face of all wires, resets list of wires") .def("Wires", &WorkPlane::Wires, "returns all wires") ; } #endif // OCCGEOMETRY #endif // NG_PYTHON ================================================ FILE: libsrc/occ/utilities.h ================================================ // 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 information if _DEBUG_ is defined --- */ #ifndef UTILITIES_H #define UTILITIES_H #include #include #include // #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__<<"] : "<putMessage(*SLog<<"---PYSCRIPT--- "<putMessage(\ *SLog<<__FILE__<<" ["<< __LINE__<<"] : "\ << "COMPILED with " << COMPILER \ << ", " << __DATE__ \ << " at " << __TIME__ <putMessage( MYTRACE <putMessage( MYTRACE << #var << "=" << var < #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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; } glDisable(GL_TEXTURE_2D); glClearColor(backcolor, backcolor, backcolor, 1.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); SetLight(); glPushMatrix(); glMultMatrixd (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, 0, 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; } } } // 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++) { /* #if OCC_VERSION_MAJOR>=7 && OCC_VERSION_MINOR>=5 gp_Pnt p = T -> Node(aEdgePoly->Nodes()(j)).Transformed(aEdgeLoc); #else gp_Pnt p = T -> Nodes()(aEdgePoly->Nodes()(j)).Transformed(aEdgeLoc); #endif */ gp_Pnt p = T -> Node(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++) { /* #if OCC_VERSION_MAJOR>=7 && OCC_VERSION_MINOR>=5 gp_Pnt p = T -> Node(aEdgePoly->Node(j)).Transformed(aEdgeLoc); #else gp_Pnt p = (T -> Nodes())(aEdgePoly->Nodes()(j)).Transformed(aEdgeLoc); #endif */ gp_Pnt p = T -> Node(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()) { auto c = OCCGeometry::GetProperties(face).col.value_or(Vec<4>(0,1,0,1) ); for(auto j : Range(4)) mat_col[j] = c[j]; } 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++) { /* #if OCC_VERSION_MAJOR>=7 && OCC_VERSION_MINOR>=5 Poly_Triangle triangle = triangulation -> Triangle(j); #else Poly_Triangle triangle = triangulation -> Triangles()(j); #endif */ Poly_Triangle triangle = triangulation -> Triangle(j); gp_Pnt p[3]; for (int k = 1; k <= 3; k++) p[k-1] = (triangulation -> Node(triangle(k))).Transformed(loc); for (int k = 1; k <= 3; k++) { #if OCC_VERSION_MAJOR>=7 && OCC_VERSION_MINOR>=5 uv = triangulation -> UVNode(triangle(k)); #else uv = triangulation -> UVNodes()(triangle(k)); #endif 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 (); if(zoomall) CalcTransformationMatrices(); } 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(); glMultMatrixd (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.clipping.enable) { 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 ================================================ FILE: libsrc/occ/vsocc.hpp ================================================ #ifndef FILE_VSOCC #define FILE_VSOCC /**************************************************************************/ /* File: vsocc.hpp */ /* Author: Joachim Schoeberl */ /* Date: 05. Jan. 2011 */ /**************************************************************************/ namespace netgen { class VisualSceneOCCGeometry : public VisualScene { NgArray trilists; NgArray 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 ================================================ FILE: libsrc/stlgeom/CMakeLists.txt ================================================ target_sources(nglib PRIVATE meshstlsurface.cpp stlgeom.cpp stlgeomchart.cpp stlgeommesh.cpp stlline.cpp stltool.cpp stltopology.cpp python_stl.cpp ) if(USE_GUI) target_sources(nggui PRIVATE vsstl.cpp stlpkg.cpp) endif(USE_GUI) install(FILES meshstlsurface.hpp stlgeom.hpp stlline.hpp stltool.hpp stltopology.hpp vsstl.hpp DESTINATION ${NG_INSTALL_DIR_INCLUDE}/stlgeom COMPONENT netgen_devel ) ================================================ FILE: libsrc/stlgeom/meshstlsurface.cpp ================================================ #include #include #include #include #include #include "stlgeom.hpp" namespace netgen { static void STLFindEdges (STLGeometry & geom, Mesh & mesh, const MeshingParameters& mparam, const STLParameters& stlparam) { double h = mparam.maxh; // mark edge points: //int ngp = geom.GetNP(); geom.RestrictLocalH(mesh, h, stlparam, mparam); PushStatusF("Mesh Lines"); NgArray meshlines; NgArray meshpoints; PrintMessage(3,"Mesh Lines"); /* cout << geom.GetNLines() << " lines" << endl; double totnp = 0; for (int i = 1; i <= geom.GetNLines(); i++) totnp += geom.GetLine(i)->NP(); cout << "avg np per line " << totnp/geom.GetNLines() << endl; */ for (int i = 1; i <= geom.GetNLines(); i++) { meshlines.Append(geom.GetLine(i)->Mesh(geom.GetPoints(), meshpoints, h, mesh)); SetThreadPercent(100.0 * (double)i/(double)geom.GetNLines()); } geom.meshpoints.SetSize(0); //testing geom.meshlines.SetSize(0); //testing for (int i = 1; i <= meshpoints.Size(); i++) { geom.meshpoints.Append(meshpoints.Get(i)); //testing mesh.AddPoint(meshpoints.Get(i)); } //(++++++++++++++testing for (int i = 1; i <= geom.GetNLines(); i++) { geom.meshlines.Append(meshlines.Get(i)); } //++++++++++++++testing) PrintMessage(7,"feed with edges"); for (int i = 1; i <= meshlines.Size(); i++) { STLLine* line = meshlines.Get(i); (*testout) << "store line " << i << endl; for (int 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 + PointIndex::BASE-1; seg[1] = p2 + PointIndex::BASE-1; 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); if(trig2 != 0) { Segment seg2; seg2[0] = p2 + PointIndex::BASE-1;; seg2[1] = p1 + PointIndex::BASE-1;; 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); } } } PopStatus(); } void STLSurfaceMeshing1 (STLGeometry & geom, class Mesh & mesh, const MeshingParameters& mparam, int retrynr, const STLParameters& stlparam); int STLSurfaceMeshing (STLGeometry & geom, class Mesh & mesh, const MeshingParameters& mparam, const STLParameters& stlparam) { PrintFnStart("Do Surface Meshing"); geom.PrepareSurfaceMeshing(); if (mesh.GetNSeg() == 0) STLFindEdges (geom, mesh, mparam, stlparam); int nopen; int outercnt = 20; for (int 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, mparam, trialcnt, stlparam); mesh.FindOpenSegments(); nopen = mesh.GetNOpenSegments(); auto n_illegal_trigs = mesh.FindIllegalTrigs(); PrintMessage (3, n_illegal_trigs, " illegal triangles"); if (nopen) { geom.ClearMarkedSegs(); for (int i = 1; i <= nopen; i++) { const Segment & seg = mesh.GetOpenSegment (i); geom.AddMarkedSeg(mesh.Point(seg[0]),mesh.Point(seg[1])); } geom.InitMarkedTrigs(); for (int 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); } MeshOptimize2d optmesh(mesh); optmesh.SetFaceIndex (0); optmesh.SetImproveEdges (0); optmesh.SetMetricWeight (0); mesh.CalcSurfacesOfNode(); optmesh.EdgeSwapping (0); optmesh.ImproveMesh (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 openseght (nopen+1); for (int 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 newpht(100); int nsegold = mesh.GetNSeg(); for (int 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 elements (intersecting..) PrintMessage(5,"check overlapping"); // mesh.FindOpenElements(); // would leed to locked points mesh.CheckOverlappingBoundary(); // if(mesh.CheckOverlappingBoundary()) ; // return MESHING3_BADSURFACEMESH; geom.InitMarkedTrigs(); for (int 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"); } NgArray refpts; NgArray refh; // was commented: for (SurfaceElementIndex sei = 0; sei < mesh.GetNSE(); sei++) if (mesh[sei].BadElement()) { for (int j = 1; j <= 3; j++) { refpts.Append (mesh.Point (mesh[sei].PNum(j))); refh.Append (mesh.GetH (refpts.Last()) / 2); } mesh.Delete(sei); } // delete wrong oriented element for (SurfaceElementIndex sei = 0; sei < mesh.GetNSE(); sei++) { const Element2d & el = mesh[sei]; if (el.IsDeleted()) continue; if (!el.PNum(1).IsValid()) 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[sei].PNum(1))); refh.Append (mesh.GetH (refpts.Last()) / 2); mesh.Delete(sei); } } // end comments for (int i = 1; i <= refpts.Size(); i++) mesh.RestrictLocalH (refpts.Get(i), refh.Get(i)); mesh.RemoveOneLayerSurfaceElements(); // Open edge-segments will be refined ! INDEX_2_HASHTABLE openseght (nopen+1); for (int 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 (); int nsegold = mesh.GetNSeg(); INDEX_2_HASHTABLE newpht(100); for (int 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]))); } } mesh.Compress(); mesh.FindOpenSegments (); nopen = mesh.GetNOpenSegments(); /* if (!nopen) { // mesh is still ok void STLSurfaceOptimization (STLGeometry & geom, class Mesh & mesh, MeshingParameters & mparam) } */ } } while (nopen); if(mesh.CheckOverlappingBoundary()) return MESHING3_BADSURFACEMESH; mesh.Compress(); mesh.CalcSurfacesOfNode(); return MESHING3_OK; } void STLSurfaceMeshing1 (STLGeometry & geom, Mesh & mesh, const MeshingParameters& mparam, int retrynr, const STLParameters& stlparam) { static int timer1 = NgProfiler::CreateTimer ("STL surface meshing1"); static int timer1a = NgProfiler::CreateTimer ("STL surface meshing1a"); static int timer1b = NgProfiler::CreateTimer ("STL surface meshing1b"); static int timer1c = NgProfiler::CreateTimer ("STL surface meshing1c"); static int timer1d = NgProfiler::CreateTimer ("STL surface meshing1d"); double h = mparam.maxh; mesh.FindOpenSegments(); NgArray spiralps(0); spiralps.SetSize(0); for (int i = 1; i <= geom.GetNP(); i++) if (geom.GetSpiralPoint(i)) spiralps.Append(i); PrintMessage(7,"NO spiralpoints = ", spiralps.Size()); //int spfound; /* NgArray meshsp(mesh.GetNP()); meshsp = 0; for (int i = 1; i <= mesh.GetNP(); i++) for (int j = 1; j <= spiralps.Size(); j++) if (Dist2(geom.GetPoint(spiralps.Get(j)), mesh.Point(i)) < 1e-20) meshsp.Elem(i) = spiralps.Get(j); NgArray imeshsp; for (int i = 1; i <= meshsp.Size(); i++) if (meshsp.Elem(i)) imeshsp.Append(i); */ NgArray imeshsp; NgArray ispiral_point; for (int i = 1; i <= mesh.GetNP(); i++) { for (int j = 1; j <= spiralps.Size(); j++) if (Dist2(geom.GetPoint(spiralps.Get(j)), mesh.Point(i)) < 1e-20) { imeshsp.Append(i); ispiral_point.Append(spiralps.Get(j)); break; } } double starttime = GetTime (); mesh.SurfaceArea().ReCalc(); // int oldnp = mesh.GetNP(); NgArray compress(mesh.GetNP()); compress = 0; NgArray icompress; NgArray opensegsperface(mesh.GetNFD()); opensegsperface = 0; for (int i = 1; i <= mesh.GetNOpenSegments(); i++) opensegsperface[mesh.GetOpenSegment(i).si]++; TABLE opensegments(mesh.GetNFD()); for (int i = 1; i <= mesh.GetNOpenSegments(); i++) { const Segment & seg = mesh.GetOpenSegment (i); if (seg.si < 1 || seg.si > mesh.GetNFD()) cerr << "segment index " << seg.si << " out of range [1, " << mesh.GetNFD() << "]" << endl; opensegments.Add (seg.si, i); } for (int fnr = 1; fnr <= mesh.GetNFD(); fnr++) { if (!opensegsperface[fnr]) continue; if (multithread.terminate) return; NgProfiler::StartTimer (timer1); NgProfiler::StartTimer (timer1a); PrintMessage(5,"Meshing surface ", fnr, "/", mesh.GetNFD()); MeshingSTLSurface meshing (geom, mparam); meshing.SetStartTime (starttime); // compress = 0; icompress.SetSize(0); int cntused = 0; for (int i = 0; i < imeshsp.Size(); i++) { compress[imeshsp[i]] = ++cntused; icompress.Append(imeshsp[i]); } NgProfiler::StopTimer (timer1a); NgProfiler::StartTimer (timer1b); /* for (int i = 1; i <= mesh.GetNOpenSegments(); i++) { const Segment & seg = mesh.GetOpenSegment (i); if (seg.si == fnr) for (int j = 0; j < 2; j++) if (compress[seg[j]] == 0) { compress[seg[j]] = ++cntused; icompress.Append(seg[j]); } } */ NgFlatArray segs = opensegments[fnr]; for (int hi = 0; hi < segs.Size(); hi++) { int i = segs[hi]; const Segment & seg = mesh.GetOpenSegment (i); for (int j = 0; j < 2; j++) if (compress[seg[j]] == 0) { compress[seg[j]] = ++cntused; icompress.Append(seg[j]); } } NgProfiler::StopTimer (timer1b); NgProfiler::StartTimer (timer1c); for (int hi = 0; hi < icompress.Size(); hi++) { PointIndex pi = icompress[hi]; /* // int sppointnum = meshsp.Get(i); int sppointnum = 0; if (hi < ispiral_point.Size()) sppointnum = ispiral_point[hi]; if (sppointnum) { */ if (hi < ispiral_point.Size()) { int sppointnum = ispiral_point[hi]; MultiPointGeomInfo mgi; int ntrigs = geom.NOTrigsPerPoint(sppointnum); for (int 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); meshing.AddPoint (mesh[pi], pi, &mgi); } else meshing.AddPoint (mesh[pi], pi); } NgProfiler::StopTimer (timer1c); NgProfiler::StartTimer (timer1d); /* for (int i = 1; i <= mesh.GetNOpenSegments(); i++) { const Segment & seg = mesh.GetOpenSegment (i); if (seg.si == fnr) meshing.AddBoundaryElement (compress[seg[0]], compress[seg[1]], seg.geominfo[0], seg.geominfo[1]); } */ // NgFlatArray segs = opensegments[fnr]; for (int hi = 0; hi < segs.Size(); hi++) { int i = segs[hi]; const Segment & seg = mesh.GetOpenSegment (i); meshing.AddBoundaryElement (compress[seg[0]], compress[seg[1]], seg.geominfo[0], seg.geominfo[1]); } NgProfiler::StopTimer (timer1d); NgProfiler::StopTimer (timer1); PrintMessage(3,"start meshing, trialcnt = ", retrynr); meshing.GenerateMesh (mesh, mparam, h, fnr); for (int i = 0; i < icompress.Size(); i++) compress[icompress[i]] = 0; mparam.Render(); } // NgProfiler::Print(stdout); mesh.CalcSurfacesOfNode(); } void STLSurfaceOptimization (STLGeometry & geom, Mesh & mesh, const MeshingParameters & mparam) { PrintFnStart("optimize STL Surface"); MeshOptimize2d optmesh(mesh); optmesh.SetFaceIndex (0); optmesh.SetImproveEdges (0); optmesh.SetMetricWeight (mparam.elsizeweight); PrintMessage(5,"optimize string = ", mparam.optimize2d, " elsizew = ", mparam.elsizeweight); for (int i = 1; i <= mparam.optsteps2d; i++) for (size_t j = 1; j <= mparam.optimize2d.length(); j++) { if (multithread.terminate) break; //(*testout) << "optimize, before, step = " << meshparam.optimize2d[j-1] << mesh.Point (3679) << endl; mesh.CalcSurfacesOfNode(); switch (mparam.optimize2d[j-1]) { case 's': { optmesh.EdgeSwapping(0); break; } case 'S': { optmesh.EdgeSwapping(1); break; } case 'm': { optmesh.ImproveMesh(mparam); break; } case 'c': { optmesh.CombineImprove(); break; } } // while(mesh.CheckOverlappingBoundary()) // { // for(const auto & el : mesh.SurfaceElements()) // { // if(el.BadElement()) // { // cout << "Restrict localh at el nr " << el << endl; // for(const auto& p : el.PNums()) // { // const auto& pnt = mesh[p]; // mesh.RestrictLocalH(pnt, 0.5*mesh.GetH(pnt)); // } // } // } // optmesh.SplitImprove(); // } //(*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(ageom, mp, ageom.GetBoundingBox()), geom(ageom) { ; } void MeshingSTLSurface :: DefineTransformation (const Point<3> & p1, const Point<3> & p2, const PointGeomInfo * geominfo, const PointGeomInfo * geominfo2) { transformationtrig = geominfo[0].trignum; geom.DefineTangentialPlane(p1, p2, transformationtrig); } void MeshingSTLSurface :: TransformToPlain (const Point<3> & locpoint, const MultiPointGeomInfo & gi, Point<2> & plainpoint, double h, int & zone) { int trigs[10000]; if (gi.GetNPGI() >= 9999) { PrintError("In Transform to plane: increase size of trigs!!!"); } for (int i = 1; i <= gi.GetNPGI(); i++) trigs[i-1] = gi.GetPGI(i).trignum; trigs[gi.GetNPGI()] = 0; // int trig = gi.trignum; // (*testout) << "locpoint = " << locpoint; geom.ToPlane (locpoint, trigs, plainpoint, h, zone, 1); // 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) { for (int 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) { int lineendtrig = gi.trignum; return geom.TrigIsInOC (lineendtrig, geom.meshchart); // Vec3d baselinenormal = geom.meshtrignv; // Vec3d linenormal = geom.GetTriangleNormal (lineendtrig); // return ( (baselinenormal * linenormal) > cos (30 * (M_PI/180)) ); } void MeshingSTLSurface :: GetChartBoundary (NgArray> & points, NgArray> & points3d, NgArray & lines, double h) const { points.SetSize (0); points3d.SetSize (0); lines.SetSize (0); geom.GetMeshChartBoundary (points, points3d, lines, h); } int MeshingSTLSurface :: TransformFromPlain (const Point<2> & plainpoint, Point<3> & 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 Point<3> & p, double gh) const { return gh; } double MeshingSTLSurface :: Area () const { return geom.Area(); } } ================================================ FILE: libsrc/stlgeom/meshstlsurface.hpp ================================================ #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: /// void DefineTransformation (const Point<3> & p1, const Point<3> & p2, const PointGeomInfo * geominfo1, const PointGeomInfo * geominfo2) override; /// void TransformToPlain (const Point<3> & locpoint, const MultiPointGeomInfo & geominfo, Point<2> & plainpoint, double h, int & zone) override; /// int TransformFromPlain (const Point<2>& plainpoint, Point<3> & locpoint, PointGeomInfo & gi, double h) override; /// int BelongsToActiveChart (const Point3d & p, const PointGeomInfo & gi) override; /// int ComputePointGeomInfo (const Point3d & p, PointGeomInfo & gi) override; /// int ChooseChartPointGeomInfo (const MultiPointGeomInfo & mpgi, PointGeomInfo & pgi) override; /// int IsLineVertexOnChart (const Point3d & p1, const Point3d & p2, int endpoint, const PointGeomInfo & gi) override; void GetChartBoundary (NgArray> & points, NgArray> & poitns3d, NgArray & lines, double h) const override; /// double CalcLocalH (const Point<3> & p, double gh) const override; /// double Area () const override; }; #endif ================================================ FILE: libsrc/stlgeom/python_stl.cpp ================================================ #ifdef NG_PYTHON #include <../general/ngpython.hpp> #include #include #include "../meshing/python_mesh.hpp" using namespace netgen; namespace netgen { extern shared_ptr mesh; extern shared_ptr ng_geometry; } static string stlparameter_description = R"delimiter( STL Specific Meshing Parameters ------------------------------- yangle: float = 30. Angle for edge detection contyangle: float = 20. Edges continue if angle > contyangle edgecornerangle: float = 60. Angle of geometry edge at which the mesher should set a point. closeedgefac: Optional[float] = 1. Factor for meshing close edges, if None it is disabled. minedgelen: Optional[float] = 0.001 Minimum edge length to be used for dividing edges to mesh points. If None this is disabled. )delimiter"; void CreateSTLParametersFromKwargs(STLParameters& stlparam, py::dict kwargs) { if(kwargs.contains("yangle")) stlparam.yangle = py::cast(kwargs.attr("pop")("yangle")); if(kwargs.contains("contyangle")) stlparam.contyangle = py::cast(kwargs.attr("pop")("contyangle")); if(kwargs.contains("edgecornerangle")) stlparam.edgecornerangle = py::cast(kwargs.attr("pop")("edgecornerangle")); if(kwargs.contains("chartangle")) stlparam.chartangle = py::cast(kwargs.attr("pop")("chartangle")); if(kwargs.contains("outerchartangle")) stlparam.outerchartangle = py::cast(kwargs.attr("pop")("outerchartangle")); if(kwargs.contains("usesearchtree")) stlparam.usesearchtree = py::cast(kwargs.attr("pop")("usesearchtree")); if(kwargs.contains("atlasfac")) { auto val = kwargs.attr("pop")("resthatlasfac"); if(val.is_none()) stlparam.resthatlasenable = false; else { stlparam.resthatlasenable = true; stlparam.resthatlasfac = py::cast(val); } } if(kwargs.contains("atlasminh")) stlparam.atlasminh = py::cast(kwargs.attr("pop")("atlasminh")); if(kwargs.contains("surfcurvfac")) { auto val = kwargs.attr("pop")("surfcurvfac"); if(val.is_none()) stlparam.resthsurfcurvenable = false; else { stlparam.resthsurfcurvenable = true; stlparam.resthsurfcurvfac = py::cast(val); } } if(kwargs.contains("chartdistfac")) { auto val = kwargs.attr("pop")("chartdistfac"); if(val.is_none()) stlparam.resthchartdistenable = false; else { stlparam.resthchartdistenable = true; stlparam.resthchartdistfac = py::cast(val); } } if(kwargs.contains("edgeanglefac")) { auto val = kwargs.attr("pop")("edgeanglefac"); if(val.is_none()) stlparam.resthedgeangleenable = false; else { stlparam.resthedgeangleenable = true; stlparam.resthedgeanglefac = py::cast(val); } } if(kwargs.contains("surfmeshcurvfac")) { auto val = kwargs.attr("pop")("surfmeshcurvfac"); if(val.is_none()) stlparam.resthsurfmeshcurvenable = false; else { stlparam.resthsurfmeshcurvenable = true; stlparam.resthsurfmeshcurvfac = py::cast(val); } } if(kwargs.contains("linelengthfac")) { auto val = kwargs.attr("pop")("linelengthfac"); if(val.is_none()) stlparam.resthlinelengthenable = false; else { stlparam.resthlinelengthenable = true; stlparam.resthlinelengthfac = py::cast(val); } } if(kwargs.contains("recalc_h_opt")) stlparam.recalc_h_opt = py::cast(kwargs.attr("pop")("recalc_h_opt")); } NGCORE_API_EXPORT void ExportSTL(py::module & m) { py::class_, NetgenGeometry> (m,"STLGeometry") .def(py::init<>()) .def(py::init<>([](const string& filename, bool surface) { ifstream ist(filename); return shared_ptr(STLGeometry::Load(ist, surface)); }), py::arg("filename"), py::arg("surface")=false, py::call_guard()) .def(NGSPickle()) .def("_visualizationData", [](shared_ptr stl_geo) { std::vector vertices; std::vector trigs; std::vector normals; std::vector min = {std::numeric_limits::max(), std::numeric_limits::max(), std::numeric_limits::max()}; std::vector max = {std::numeric_limits::lowest(), std::numeric_limits::lowest(), std::numeric_limits::lowest()}; std::vector surfnames; surfnames.push_back("stl"); vertices.reserve(stl_geo->GetNT()*3*3); trigs.reserve(stl_geo->GetNT()*4); normals.reserve(stl_geo->GetNT()*3*3); size_t ii = 0; for(int i = 0; i < stl_geo->GetNT(); i++) { auto& trig = stl_geo->GetTriangle(i+1); for(int k = 0; k < 3; k++) { trigs.push_back(ii++); auto& pnt = stl_geo->GetPoint(trig[k]); for (int l = 0; l < 3; l++) { float val = pnt[l]; vertices.push_back(val); min[l] = min2(min[l], val); max[l] = max2(max[l], val); normals.push_back(trig.Normal()[l]); } } trigs.push_back(0); } py::gil_scoped_acquire ac; py::dict res; py::list snames; for(auto name : surfnames) snames.append(py::cast(name)); res["vertices"] = MoveToNumpy(vertices); res["triangles"] = MoveToNumpy(trigs); res["normals"] = MoveToNumpy(normals); res["surfnames"] = snames; res["min"] = MoveToNumpy(min); res["max"] = MoveToNumpy(max); return res; }, py::call_guard()) .def("GenerateMesh", [] (shared_ptr geo, MeshingParameters* pars, shared_ptr mesh, py::kwargs kwargs) { MeshingParameters mp; STLParameters stlparam; if(pars) { auto mp_flags = pars->geometrySpecificParameters; auto mp_kwargs = CreateDictFromFlags(mp_flags); CreateSTLParametersFromKwargs(stlparam, mp_kwargs); mp = *pars; } CreateSTLParametersFromKwargs(stlparam, kwargs); CreateMPfromKwargs(mp, kwargs); // this will throw if any kwargs are not passed py::gil_scoped_release gil_release; if(!mesh) { mesh = make_shared(); } mesh->SetGeometry(geo); ng_geometry = geo; SetGlobalMesh(mesh); auto result = STLMeshingDummy(geo.get(), mesh, mp, stlparam); if(result != 0) { netgen::mesh = mesh; throw Exception("Meshing failed!"); } return mesh; }, py::arg("mp") = nullptr, py::arg("mesh") = nullptr, (meshingparameter_description + stlparameter_description).c_str()) .def("Draw", FunctionPointer ([] (shared_ptr self) { ng_geometry = self; }) ) .def("GetVicinity", [] (shared_ptr self, int node, int size, string type) { NgArray vic; int trig=-1; if(type == "trig") trig = node; if(type == "point") trig = self->TrigPerPoint(node, 1); self->GetVicinity(trig, size, vic); auto geo = make_shared(); NgArray trigs; for(auto i : Range(vic.Size())) { int trigi = vic[i]; STLReadTriangle t; Vec<3> normal = self->GetTriangle(trigi).Normal(); Point<3> pts[3]; auto trig = self->GetTriangle(trigi); for(auto pi : Range(3)) pts[pi] = self->GetPoint(trig[pi]); trigs.Append(STLReadTriangle(pts, normal)); } geo->SetSurfaceSTL(true); geo->InitSTLGeometry(trigs); return geo; }, py::arg("node"), py::arg("size"), py::arg("node_type") = "trig") .def("SmoothDirtyTrigs", [] (shared_ptr self, py::kwargs kwargs) { STLParameters stlparam; CreateSTLParametersFromKwargs(stlparam, kwargs); self->SmoothDirtyTrigs(stlparam); }) .def("GetDirtyTrigs", [] (shared_ptr self, py::kwargs kwargs) { STLParameters stlparam; CreateSTLParametersFromKwargs(stlparam, kwargs); self->MarkDirtyTrigs(stlparam); py::list dirty; for(auto i : Range(self->GetNT())) if(self->IsMarkedTrig(i+1)) dirty.append(i); }) .def("MovePointToMiddle", [] (shared_ptr self, int node, int count) { auto trignr = self->TrigPerPoint(node, 1); auto trig = self->GetTriangle(trignr); int point_in_trig = -1; for(auto i : Range(3)) if(trig[i] == node) point_in_trig = i; if(point_in_trig == -1) throw Exception("Point not found in triangle"); self->SetSelectTrig(trignr); self->SetNodeOfSelTrig(point_in_trig); for([[maybe_unused]] auto i : Range(count)) self->MoveSelectedPointToMiddle(); }) .def("Save", &STLGeometry::Save) ; m.def("LoadSTLGeometry", [] (const string & filename) { cout << "WARNING: LoadSTLGeometry is deprecated, use the STLGeometry(filename) constructor instead!" << endl; ifstream ist(filename); return shared_ptr(STLGeometry::Load(ist)); },py::call_guard()); } PYBIND11_MODULE(libstl, m) { ExportSTL(m); } #endif ================================================ FILE: libsrc/stlgeom/stlgeom.cpp ================================================ #include #include #include "stlgeom.hpp" namespace netgen { //globalen searchtree fuer gesamte geometry aktivieren int geomsearchtreeon = 0; int usechartnormal = 1; //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ void STLMeshing (STLGeometry & geom, Mesh & mesh, const MeshingParameters& mparam, const STLParameters& stlpar) { geom.Clear(); geom.BuildEdges(stlpar); geom.MakeAtlas(mesh, mparam, stlpar); if (multithread.terminate) { return; } geom.CalcFaceNums(); geom.AddFaceEdges(); geom.LinkEdges(stlpar); 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 = make_unique(*this); externaledges.SetSize(0); Clear(); meshchart = 0; // initialize all ?? JS if (geomsearchtreeon) searchtree = new BoxTree<3> (GetBoundingBox().PMin() - Vec3d(1,1,1), GetBoundingBox().PMax() + Vec3d(1,1,1)); else searchtree = NULL; status = STL_GOOD; statustext = "Good Geometry"; smoothedges = NULL; area = -1; } STLGeometry :: ~STLGeometry() { // for (auto p : atlas) delete p; // delete edgedata; } void STLGeometry :: Save (const filesystem::path & filename) const { string ext = ToLower(filename.extension()); if (ext == ".stl") { STLTopology::Save (filename); return; } else if (ext == ".stlb") { SaveBinary (filename,"Binary STL Geometry"); return; } else if (ext == ".stle") { SaveSTLE (filename); return; } throw Exception ("Unknown target format: " + filename.string()); } DLL_HEADER extern STLParameters stlparam; int STLGeometry :: GenerateMesh (shared_ptr & mesh, MeshingParameters & mparam) { STLParameters stlpar = stlparam; return STLMeshingDummy (this, mesh, mparam, stlpar); } Vec<3> STLGeometry :: GetNormal(int surfind, const Point<3> & p, const PointGeomInfo* gi) const { if(!gi) throw Exception("STLGeometry::GetNormal without PointGeomInfo called"); return GetChart(GetChartNr(gi->trignum)).GetNormal(); } bool STLGeometry :: CalcPointGeomInfo(int /*surfind*/, PointGeomInfo& gi, const Point<3> & p3) const { Point<3> hp = p3; SelectChartOfTriangle(gi.trignum); gi.trignum = Project (hp); if (gi.trignum) return true; return false; } bool STLGeometry :: ProjectPointGI (int surfind, Point<3> & p, PointGeomInfo & gi) const { static std::mutex mutex_project_whole_surface; int meshchart = GetChartNr(gi.trignum); const STLChart& chart = GetChart(meshchart); int trignum = chart.ProjectNormal(p); if(trignum==0) { // non-thread-safe implementation std::lock_guard guard(mutex_project_whole_surface); PrintMessage(7,"project failed"); SelectChartOfTriangle (gi.trignum); // needed because ProjectOnWholeSurface uses meshchartnv (the normal vector of selected chart) trignum = ProjectOnWholeSurface(p); if(trignum==0) { PrintMessage(7, "project on whole surface failed"); return false; } } return true; } PointGeomInfo STLGeometry :: ProjectPoint (INDEX surfind, Point<3> & p) const { throw Exception("ProjectPoint without PointGeomInfo not implemented"); } void STLGeometry :: 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; auto ngi1 = gi1; auto ngi2 = gi2; // SelectChartOfTriangle (gi1.trignum); int tn1 = ProjectPointGI (surfi, np1, ngi1); // SelectChartOfTriangle (gi2.trignum); int tn2 = ProjectPointGI (surfi, np2, ngi2); newgi.trignum = tn1; //urspruengliche version newp = np1; //urspruengliche version if (!newgi.trignum) { newgi.trignum = tn2; newp = np2; } if (!newgi.trignum) newgi.trignum = gi1.trignum; } else { // (*testout) << "WARNING: PointBetween got geominfo = 0" << endl; newp = p1+secpoint*(p2-p1); newgi.trignum = 0; } } void STLGeometry :: PointBetweenEdge (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 = GetLine (gi1.edgenr)->GetPointInDist (GetPoints(), newgi.dist, hi); // (*testout) << "newp = " << newp << endl; } 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(const STLParameters& stlparam) { 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; STLPointId 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(const STLParameters& stlparam) { multithread.terminate = 0; // UseExternalEdges(); BuildEdges(stlparam); DenseMatrix m(3), hm(3); Vector rhs(3), sol(3), hv(3), hv2(3); Vec<3> ri; double wnb = stldoctor.smoothnormalsweight; // neighbour 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; STLPointId 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: NgArray 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()) { NgArray 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)); edges.Append(e); return edges.Size(); } 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; NgArray 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; NgArray > 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 NgArray >& eps) { int i; int ne = eps.Size()/2; NgArray epsi; Box<3> bb = GetBoundingBox(); bb.Increase(1); Point3dTree ptree (bb.PMin(), bb.PMax()); NgArray 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]; NgArray importpoints; NgArray importlines; NgArray 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()); NgArray 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 filesystem::path & filename) { StoreEdgeData(); PrintFnStart("Load edges from file '", filename, "'"); ifstream fin(filename); edgedata->Read(fin); // calcedgedataanglesnew = 1; } void STLGeometry :: SaveEdgeData(const filesystem::path & filename) { PrintFnStart("save edges to file '", filename, "'"); ofstream fout(filename); 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(const STLParameters& stlparam) { // if (!trigsconverted) {return;} ClearEdges(); meshlines.SetSize(0); FindEdgesFromAngles(stlparam); } 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[k-1] = trias[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() , " (=", int(GetTriangle(GetSelectTrig()).PNum(GetNodeOfSelTrig())), ")"); if (AtlasMade() && GetSelectTrig() >= 1 && GetSelectTrig() <= GetNT()) { PrintMessage(1," chartnum=", int(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 ", int(GetChartNr(st))); } void STLGeometry :: ShowSelectedTrigCoords() { int st = GetSelectTrig(); /* //testing!!!! NgArray trigs; GetSortedTrianglesAroundPoint(GetTriangle(st).PNum(GetNodeOfSelTrig()),st,trigs); */ if (st >= 1 && st <= GetNT()) { PrintMessage(1, "coordinates of selected trig ", st, ":"); PrintMessage(1, " p1 = ", int(GetTriangle(st).PNum(1)), " = ", Point3d (GetPoint(GetTriangle(st).PNum(1)))); PrintMessage(1, " p2 = ", int(GetTriangle(st).PNum(2)), " = ", Point3d (GetPoint(GetTriangle(st).PNum(2)))); PrintMessage(1, " p3 = ", int(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 ", int(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, NgArray& vic) { if (starttrig == 0 || starttrig > GetNT()) {return;} NgArray 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; NgArray list1; list1.SetSize(0); NgArray 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; NgArray list1; list1.SetSize(0); NgArray 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(const STLParameters& stlparam) { 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; STLPointId 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(const STLParameters& stlparam) { //double revertedangle = stldoctor.smoothangle/180.*M_PI; double fact = stldoctor.dirtytrigfact; MarkRevertedTrigs(stlparam); 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(stlparam); } void STLGeometry :: MarkRevertedTrigs(const STLParameters& stlparam) { int i,j; if (edgesperpoint.Size() != GetNP()) {BuildEdges(stlparam);} PrintFnStart("mark reverted trigs"); InitMarkedTrigs(); int found; double revertedangle = stldoctor.smoothangle/180.*M_PI; int cnt = 0; STLPointId 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(const STLParameters& stlparam) { PrintFnStart("smooth dirty trigs"); MarkDirtyTrigs(stlparam); int i,j; int changed = 1; STLPointId 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(stlparam); 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() { if (area >= 0) return area; area = 0; for (int i = 1; i <= GetNT(); i++) area += GetTriangle(i).Area(points); return area; } 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 NgArray & 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()); NgArray 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() { PrintMessageCR(3,"Check overlapping geometry ..."); Box<3> geombox = GetBoundingBox(); Point<3> pmin = geombox.PMin(); Point<3> pmax = geombox.PMax(); BoxTree<3> setree(pmin, pmax); int oltrigs = 0; markedtrigs.SetSize(GetNT()); for (int i = 1; i <= GetNT(); i++) SetMarkedTrig(i, 0); for (int 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); } { mutex inters_mutex; ParallelFor( 1, GetNT()+1, [&] (int first, int next) { NgArray inters; for (int i=first; i tpmin = tri.box.PMin(); Point<3> tpmax = tri.box.PMax(); setree.GetIntersecting (tpmin, tpmax, inters); for (int 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 (int 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])) { lock_guard guard(inters_mutex); { oltrigs++; PrintMessage(5,"Intersecting Triangles: trig ",i," with ",inters.Get(j),"!"); SetMarkedTrig(i, 1); SetMarkedTrig(inters.Get(j), 1); } } } } }); } PrintMessage(3,"Check overlapping geometry ... ", oltrigs, " triangles overlap"); 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); NgArray 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()); NgArray 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(const STLParameters& stlparam) { //PrintFnStart("build edges"); edges.SetSize(0); meshlines.SetSize(0); FindEdgesFromAngles(stlparam); } void STLGeometry :: UseExternalEdges() { for (int 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"); STLPointId np1, np2; int ecnt = 0; edgedata->SetSize(GetNT()/2*3); for (int 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() { PrintMessageCR (5,"calc edge data angles ... "); for (int i = 1; i <= GetNTE(); i++) { STLTopEdge & edge = GetTopEdge (i); double cosang = edge.TrigNum(2) == 0 ? 1. : GetTriangle(edge.TrigNum(1)).Normal() * GetTriangle(edge.TrigNum(2)).Normal(); edge.SetCosAngle (cosang); } for (int 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); */ } PrintMessage (5,"calc edge data angles ... done"); } void STLGeometry :: FindEdgesFromAngles(const STLParameters& stlparam) { // 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;} for (int i = 1; i <= edgedata->Size(); i++) { STLTopEdge & sed = edgedata->Elem(i); if(sed.TrigNum(2) == 0) sed.SetStatus(ED_CONFIRMED); 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; [[maybe_unused]] int its = 0; while (changed && stlparam.contyangle < stlparam.yangle) { its++; //(*mycout) << "." << flush; changed = 0; for (int 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 (int 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 for (int 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 NgArray edgecnt; NgArray chartindex; edgecnt.SetSize(GetNOFaces()); chartindex.SetSize(GetNOFaces()); for (int i = 1; i <= GetNOFaces(); i++) { edgecnt.Elem(i) = 0; chartindex.Elem(i) = 0; } for (int i = 1; i <= GetNT(); i++) { int fn = GetTriangle(i).GetFaceNum(); if (!chartindex.Get(fn)) {chartindex.Elem(fn) = GetChartNr(i);} for (int j = 1; j <= 3; j++) { edgecnt.Elem(fn) += GetNEPP(GetTriangle(i).PNum(j)); } } for (int i = 1; i <= GetNOFaces(); i++) { if (!edgecnt.Get(i)) {PrintMessage(5,"Face", i, " has no edge!");} } int changed = 0; STLPointId ap1, ap2; for (int i = 1; i <= GetNOFaces(); i++) { if (!edgecnt.Get(i)) { const STLChart& c = GetChart(chartindex.Get(i)); // bool foundone = false; int longest_ap1 = -1, longest_ap2 = -1; double maxlen = -1; for (int j = 1; j <= c.GetNChartT(); j++) { const STLTriangle& t1 = GetTriangle(c.GetChartTrig1(j)); for (int k = 1; k <= 3; k++) { int nt = NeighbourTrig(c.GetChartTrig1(j),k); if (GetChartNr(nt) != chartindex.Get(i)) { t1.GetNeighbourPoints(GetTriangle(nt),ap1,ap2); // AddEdge(ap1,ap2); double len = Dist(GetPoint(ap1), GetPoint(ap2)); if (len > maxlen) { maxlen = len; longest_ap1 = ap1; longest_ap2 = ap2; } changed = 1; } } } if (maxlen > 0) AddEdge(longest_ap1,longest_ap2); } } if (changed) BuildEdgesPerPoint(); } void STLGeometry :: LinkEdges(const STLParameters& stlparam) { 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 NgArray 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 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; NgArray 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 NgArray todolist; NgArray 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 NgArray todolist; NgArray nextlist; facecnt++; markedtrigs1++; GetTriangle(starttrig).SetFaceNum(facecnt); todolist.Append(starttrig); STLPointId 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 (GetNE()/10 + 1); // Jack: Ok ? // UseExternalEdges(); PushStatusF("Build Smooth Edges"); int nt = GetNT(); Vec3d ng1, ng2; for (int 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 (int j = 1; j <= NONeighbourTrigs(i); j++) { int nbt = NeighbourTrig (i, j); ng2 = GetTriangle(nbt).GeomNormal(points); ng2 /= (ng2.Length() + 1e-24); STLPointId 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(); } bool STLGeometry :: IsSmoothEdge (int pi1, int pi2) const { if (!smoothedges) return false; INDEX_2 i2(pi1, pi2); i2.Sort(); return smoothedges->Used (i2); } /* //function is not used now int IsInArray(int n, const NgArray& ia) { int i; for (i = 1; i <= ia.Size(); i++) { if (ia.Get(i) == n) {return 1;} } return 0; } */ void STLGeometry :: AddConeAndSpiralEdges(const STLParameters& stlparam) { 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 STLPointId np1, np2; int cnt = 0; for (ChartId i = 1; i <= GetNOCharts(); i++) { STLChart& chart = GetChart(i); for (int j = 1; j <= chart.GetNChartT(); j++) { STLTrigId t = chart.GetChartTrig1(j); const STLTriangle& tt = GetTriangle(t); for (int k = 1; k <= NONeighbourTrigs(t); k++) { STLTrigId 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=", int(i), ", trig=", int(t), ", p1=", int(np1), ", p2=", int(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 trigsaroundp; NgArray chartpointchecked(GetNP()); //gets number of chart, if in this chart already checked chartpointchecked = 0; int onoc, notonoc, tpp, pn; STLPointId ap1, ap2; int tn1, tn2, l, problem; if (!stldoctor.conecheck) {PrintWarning("++++++++++++ \ncone checking deactivated by user!!!!!\n+++++++++++++++"); return ;} PushStatus("Find Critical Points"); int addedges = 0; for (ChartId i = 1; i <= GetNOCharts(); i++) { SetThreadPercent((double)i/(double)GetNOCharts()*100.); if (multithread.terminate) {PopStatus();return;} STLChart& chart = GetChart(i); for (int j = 1; j <= chart.GetNChartT(); j++) { STLTrigId t = chart.GetChartTrig1(j); const STLTriangle& tt = GetTriangle(t); for (int k = 1; k <= 3; k++) { pn = tt.PNum(k); if (chartpointchecked.Get(pn) == i) {continue;} int checkpoint = 0; for (int 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 (int l = 2; l <= trigsaroundp.Size()-1; l++) { tn1 = trigsaroundp[l-2]; tn2 = trigsaroundp[l-1]; 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 (int l = 2; l <= trigsaroundp.Size()-1; l++) { tn1 = trigsaroundp[l-2]; tn2 = trigsaroundp[l-1]; 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 (int l = trigsaroundp.Size()-1; l >= 2; l--) { tn1 = trigsaroundp[l]; tn2 = trigsaroundp[l-1]; 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 (int l = trigsaroundp.Size()-1; l >= 2; l--) { tn1 = trigsaroundp[l]; tn2 = trigsaroundp[l-1]; 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 (ChartId i = 1; i <= GetNOCharts(); i++) { STLChart& chart = GetChart(i); for (int j = 1; j <= chart.GetNChartT(); j++) { STLTrigId t = chart.GetChartTrig1(j); const STLTriangle& tt = GetTriangle(t); for (int k = 1; k <= 3; k++) { pn = tt.PNum(k); if (GetNEPP(pn) == 2) { onoc = 0; notonoc = 0; for (int 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[l-2]). GetNeighbourPoints(GetTriangle(trigsaroundp[l-1]), ap1, ap2); if (IsEdge(ap1,ap2)) {here = (here+1)%2;} if (!here && TrigIsInOC(trigsaroundp[l-1],i)) {thereOC = 1;} if (!here && !TrigIsInOC(trigsaroundp[l-1],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(STLPointId p, STLTrigId starttrig, Array& trigs) { STLTrigId acttrig = starttrig; trigs.SetAllocSize(trigsperpoint.EntrySize(p)); trigs.SetSize(0); trigs.Append(acttrig); int locindex1(0), locindex2(0); //(*mycout) << "trigs around point " << p << endl; int end = 0; while (!end) { const STLTriangle& at = GetTriangle(acttrig); for (int i = 1; i <= trigsperpoint.EntrySize(p); i++) { STLTrigId t = trigsperpoint.Get(p,i); const STLTriangle& nt = GetTriangle(t); if (at.IsNeighbourFrom(nt)) { STLPointId ap1, ap2; at.GetNeighbourPoints(nt, ap1, ap2); if (ap2 == p) {Swap(ap1,ap2);} if (ap1 != p) {PrintSysError("In GetSortedTrianglesAroundPoint!!!");} for (int 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); } } void STLGeometry :: WriteChartToFile( ChartId chartnumber, filesystem::path filename ) { PrintMessage(1,"write chart ", int(chartnumber), " to ", filename); Array trignums; if (chartnumber >= 1 && chartnumber <= GetNOCharts()) { const STLChart& chart = GetChart(chartnumber); for (int j = 1; j <= chart.GetNChartT(); j++) trignums.Append(chart.GetChartTrig1(j)); for (int j = 1; j <= chart.GetNOuterT(); j++) trignums.Append(chart.GetOuterTrig1(j)); QuickSort(trignums); STLGeometry geo; NgArray readtrigs; const auto & first_trig = GetTriangle(chart.GetChartTrig1(1)); auto normal = first_trig.Normal(); Box<3> box{Box<3>::EMPTY_BOX}; for(auto j : trignums) { const auto& trig = GetTriangle(j); Point<3> pts[3]; for(auto k : Range(3)) { pts[k] = GetPoint(trig[k]); box.Add(pts[k]); } // Vec3d normal = Cross( pts[1]-pts[0], pts[2]-pts[0] ); readtrigs.Append(STLReadTriangle(pts, trig.Normal())); } auto dist = box.PMax() - box.PMin(); auto extra_point = GetPoint(first_trig[0]) - dist.Length()*normal; NgArray acttrigs(GetNT()); acttrigs = -1; for (int j = 1; j <= chart.GetNT(); j++) acttrigs.Elem(chart.GetTrig1(j)) = chartnumber; for (int j = 1; j <= chart.GetNT(); j++) { auto t = chart.GetTrig1(j); const auto & tt = GetTriangle(t); for (int k = 1; k <= 3; k++) { int nt = NeighbourTrig(t,k); if (acttrigs.Get(nt) != chartnumber) { STLPointId np1, np2; tt.GetNeighbourPoints(GetTriangle(nt),np1,np2); Point<3> pts[3]; pts[0] = GetPoint(np2); pts[1] = GetPoint(np1); pts[2] = extra_point; Vec3d normal = -Cross( pts[2]-pts[0], pts[1]-pts[0] ); readtrigs.Append(STLReadTriangle(pts, normal)); } } } geo.InitSTLGeometry(readtrigs); geo.Save(filename); } } class STLGeometryRegister : public GeometryRegister { public: virtual NetgenGeometry * Load (const filesystem::path & filename) const; }; NetgenGeometry * STLGeometryRegister :: Load (const filesystem::path & filename) const { string ext = ToLower(filename.extension()); if (ext == ".stl") { PrintMessage (1, "Load STL geometry file ", filename); ifstream infile(filename); STLGeometry * hgeom = STLGeometry :: Load (infile); hgeom -> edgesfound = 0; return hgeom; } else if (ext == ".stlb") { PrintMessage (1, "Load STL binary geometry file ", filename); ifstream infile(filename); STLGeometry * hgeom = STLGeometry :: LoadBinary (infile); hgeom -> edgesfound = 0; return hgeom; } else if (ext == ".nao") { PrintMessage (1, "Load naomi (F. Kickinger) geometry file ", filename); ifstream infile(filename); STLGeometry * hgeom = STLGeometry :: LoadNaomi (infile); hgeom -> edgesfound = 0; return hgeom; } return NULL; } class STLInit { public: STLInit() { GeometryRegister().Append (new STLGeometryRegister); } }; STLInit stlinit; static RegisterClassForArchive> stlgeo; } ================================================ FILE: libsrc/stlgeom/stlgeom.hpp ================================================ #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 #include "stltopology.hpp" #include "stltool.hpp" #include "stlline.hpp" namespace netgen { /* inline int IsInArray(int n, const NgArray& ia) { return ia.Contains(n); } inline bool AddIfNotExists(NgArray& list, int x) { if (list.Contains(x)) return false; list.Append(x); return true; } */ // extern DLL_HEADER MeshingParameters mparam; class STLEdgeDataList { NgArray 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, NgArray& line); void BuildClusterWithEdge(int ep1, int ep2, NgArray& line); int GetNEPPStat(int p, int status) const; int GetNConfCandEPP(int p) const; }; class DLL_HEADER STLGeometry : public NetgenGeometry, public STLTopology { // edges to be meshed: NgArray edges; //edges per point TABLE edgesperpoint; // line: a connection of edges NgArray lines; NgArray lineendpoints; //per geometrypoint, 1 = is endpoint; 0 = no endpoint, NgArray normals; //normals belong to points! NgArray externaledges; int undoexternaledges; NgArray storedexternaledges; unique_ptr edgedata; // STLEdgeDataList edgedata_store; int calcedgedataanglesnew; int edgedatastored; int facecnt; //meshpoint is only set, if an edge is at this point!!! NgArray vicinity; //is one, if a triangle belongs to vicinity (eg. of selecttrig) NgArray markedtrigs; //is one, if a triangle belongs to marked triangles (calcdirtystrigs) NgArray markedsegs; //every pointpair is a segment!!! NgArray selectedmultiedge; //spiralpoints: NgArray spiralpoints; // Array, ChartId> atlas; //marks all already charted trigs with chartnumber Array chartmark; //outerchartspertrig, ascending sorted TABLE outerchartspertrig; //for meshing and project: NgArray meshcharttrigs; //per trig: 1=belong to chart, 0 not mutable int meshchart; NgArray ha_points; // help array, np long, filled with 0 // sharp geometric edges not declared as edges // (not considered for spiral check) INDEX_2_HASHTABLE * smoothedges; //transformation: mutable 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; NgArray meshlines; NgArray meshpoints; double area; public: STLGeometry(); virtual ~STLGeometry(); void DoArchive(Archive& ar) override { STLTopology::DoArchive(ar); } void Clear(); virtual void Save (const filesystem::path & filename) const override; bool CalcPointGeomInfo(int surfind, PointGeomInfo& gi, const Point<3> & p3) const override; PointGeomInfo ProjectPoint(INDEX surfind, Point<3> & p) const override; bool ProjectPointGI (int surfind, Point<3> & p, PointGeomInfo & gi) const override; Vec<3> GetNormal(int surfind, const Point<3> & p, const PointGeomInfo* gi = nullptr) const override; 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 override; void PointBetweenEdge(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 override; void STLInfo(double* data); //stldoctor: void SmoothNormals(const STLParameters& stlparam); void MarkNonSmoothNormals(const STLParameters& stlparam); 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 NgArray& SelectedMultiEdge() {return selectedmultiedge;} twoint GetNearestSelectedDefinedEdge(); void BuildSelectedMultiEdge(twoint ep); void BuildSelectedEdge(twoint ep); void BuildSelectedCluster(twoint ep); void ImportEdges(); void AddEdges(const NgArray >& eps); void ExportEdges(); void LoadEdgeData(const filesystem::path & file); void SaveEdgeData(const filesystem::path & 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(const STLParameters& stlparam); 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, NgArray& vic); int Vicinity(int trig) const; void InitMarkedTrigs(); void MarkDirtyTrigs(const STLParameters& stlparam); void SmoothDirtyTrigs(const STLParameters& stlparam); void GeomSmoothRevertedTrigs(const STLParameters& stlparam); void MarkRevertedTrigs(const STLParameters& stlparam); 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) { normals.Append(n); return normals.Size(); } 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) { edges.Append(v); return edges.Size(); } 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 NgArray & readtrigs) override; virtual void TopologyChanged() override; //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(const STLParameters& stlparam); void BuildEdgesPerPoint(); void UseExternalEdges(); void FindEdgesFromAngles(const STLParameters& stlparam); void CalcFaceNums(); int GetNOBodys(); int GetNOFaces() {return facecnt;} void LinkEdges(const STLParameters& stlparam); void AddConeAndSpiralEdges(const STLParameters& stlparam); 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& outercharttrigs, NgArray& chartpointchecked, NgArray& dirtytrigs); void ClearSpiralPoints(); void SetSpiralPoint(int pn) {spiralpoints.Elem(pn) = 1;}; int GetSpiralPoint(int pn) const {return spiralpoints.Get(pn);}; void GetSortedTrianglesAroundPoint(STLPointId p, STLTrigId starttrig, Array& trigs); // smooth edges: sharp geometric edges not declared as edges void BuildSmoothEdges (); bool IsSmoothEdge (int pi1, int pi2) const; //make charts with regions of a max. angle void MakeAtlas(class Mesh & mesh, const MeshingParameters& mparam, const STLParameters& stlparam); //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 ChartId GetChartNr(STLTrigId i) const; ChartId GetMarker(STLTrigId i) const { return chartmark[i]; } void SetMarker(STLTrigId nr, ChartId m); size_t GetNOCharts() const { return atlas.Size(); } //get a chart from atlas const STLChart& GetChart(ChartId nr) const { return *atlas[nr];}; STLChart & GetChart(ChartId nr) { return *atlas[nr];}; int AtlasMade() const; void GetInnerChartLimes(NgArray& limes, ChartId chartnum); //FOR MESHING int GetMeshChartNr () { return meshchart; } void GetMeshChartBoundary (NgArray> & points, NgArray> & points3d, NgArray & 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) const; // 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) { lines.Append(line); return lines.Size(); } 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, const STLParameters& stlparam, const MeshingParameters& mparam); void RestrictLocalHCurv(class Mesh & mesh, double gh, const STLParameters& stlparam); void RestrictHChartDistOneChart(ChartId chartnum, NgArray& acttrigs, class Mesh & mesh, double gh, double fact, double minh, const STLParameters& stlparam); friend class MeshingSTLSurface; int GenerateMesh (shared_ptr & mesh, MeshingParameters & mparam) override; // Add additional Point to chart to close the surface and write the resulting stl to a file void WriteChartToFile( ChartId chartnumber, filesystem::path filename="chart.slb" ); }; #include "meshstlsurface.hpp" extern int STLMeshingDummy (STLGeometry* stlgeometry, shared_ptr & mesh, const MeshingParameters & mparam, const STLParameters& stlpar); } #endif ================================================ FILE: libsrc/stlgeom/stlgeomchart.cpp ================================================ //20.11.1999 third part of stlgeom.cc, functions with chart and atlas #include #include #include #include #include #include "stlgeom.hpp" namespace netgen { int chartdebug = 0; void STLGeometry :: MakeAtlas(Mesh & mesh, const MeshingParameters& mparam, const STLParameters& stlparam) { static Timer t("makeatlas"); RegionTimer reg(t); static Timer tinner("find innner chart"); static Timer touter("find outer chart"); // int timer1 = NgProfiler::CreateTimer ("makeatlas"); /* int timerb = NgProfiler::CreateTimer ("makeatlas - begin"); int timere = NgProfiler::CreateTimer ("makeatlas - end"); int timere1 = NgProfiler::CreateTimer ("makeatlas - end1"); int timere2 = NgProfiler::CreateTimer ("makeatlas - end2"); int timer2 = NgProfiler::CreateTimer ("makeatlas - part 2"); int timer3 = NgProfiler::CreateTimer ("makeatlas - part 3"); int timer4 = NgProfiler::CreateTimer ("makeatlas - part 4"); int timer4a = NgProfiler::CreateTimer ("makeatlas - part 4a"); int timer4b = NgProfiler::CreateTimer ("makeatlas - part 4b"); int timer4c = NgProfiler::CreateTimer ("makeatlas - part 4c"); int timer4d = NgProfiler::CreateTimer ("makeatlas - part 4d"); int timer4e = NgProfiler::CreateTimer ("makeatlas - part 4e"); int timer5 = NgProfiler::CreateTimer ("makeatlas - part 5"); int timer5a = NgProfiler::CreateTimer ("makeatlas - part 5a"); int timer5b = NgProfiler::CreateTimer ("makeatlas - part 5b"); int timer5cs = NgProfiler::CreateTimer ("makeatlas - part 5cs"); int timer5cl = NgProfiler::CreateTimer ("makeatlas - part 5cl"); */ PushStatusF("Make Atlas"); double h = mparam.maxh; double atlasminh = 5e-3 * Dist (boundingbox.PMin(), boundingbox.PMax()); PrintMessage(5, "atlasminh = ", atlasminh); //speedup for make atlas if (GetNT() > 50000) mesh.SetGlobalH(min2 (0.05*Dist (boundingbox.PMin(), boundingbox.PMax()), mparam.maxh)); atlas.SetSize(0); ClearSpiralPoints(); BuildSmoothEdges(); // NgProfiler::StartTimer (timer1); 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 outermark(GetNT()); //marks all trigs form actual outer region Array outertested(GetNT()); //marks tested trigs for outer region Array pointstochart(GetNP()); //point in chart becomes chartnum Array innerpointstochart(GetNP()); //point in chart becomes chartnum Array chartpoints; //point in chart becomes chartnum Array innerchartpoints; Array> innerchartpts; NgArray dirtycharttrigs; NgArray chartdistacttrigs (GetNT()); //outercharttrigs chartdistacttrigs = 0; STLBoundary chartbound(this); //knows the actual chart boundary //int chartboundarydivisions = 10; markedsegs.SetSize(0); //for testing!!! NgArray chartpointchecked(GetNP()); //for dirty-chart-trigs chartmark.SetSize(GetNT()); innerpointstochart = ChartId::INVALID; pointstochart = ChartId::INVALID; chartpointchecked = ChartId::INVALID; double eps = 1e-12 * Dist (boundingbox.PMin(), boundingbox.PMax()); int spiralcheckon = stldoctor.spiralcheck; if (!spiralcheckon) {PrintWarning("++++++++++++\nspiral deactivated by user!!!!\n+++++++++++++++"); } chartmark = ChartId::INVALID; outermark = ChartId::INVALID; outertested = ChartId::INVALID; double atlasarea = Area(); double workedarea = 0; double showinc = 100.*5000./(double)GetNT(); double nextshow = 0; STLTrigId lastunmarked = 1; PrintMessage(5,"one dot per 5000 triangles: "); size_t markedtrigcnt = 0; while (markedtrigcnt < GetNT()) { if (multithread.terminate) { PopStatus(); return; } // NgProfiler::StartTimer (timerb); if (workedarea / atlasarea*100. >= nextshow) {PrintDot(); nextshow+=showinc;} SetThreadPercent(100.0 * workedarea / atlasarea); atlas.Append (make_unique (this, stlparam)); STLChart & chart = *atlas.Last(); //find unmarked trig STLTrigId prelastunmarked = lastunmarked; bool found = false; for (STLTrigId j = lastunmarked; j <= GetNT(); j++) if (!GetMarker(j)) { found = true; lastunmarked = j; break; } chartpoints.SetSize(0); innerchartpoints.SetSize(0); innerchartpts.SetSize(0); chartbound.Clear(); chartbound.SetChart(&chart); if (!found) throw Exception("Make Atlas, no starttrig found"); //find surrounding trigs // int starttrig = j; STLTrigId starttrig = lastunmarked; Point<3> startp = GetPoint(GetTriangle(starttrig)[0]); bool accepted; ChartId chartnum = GetNOCharts(); Vec<3> sn = GetTriangle(starttrig).Normal(); chart.SetNormal (startp, sn); // *testout << "first trig " << starttrig << ", n = " << sn << endl; SetMarker(starttrig, chartnum); markedtrigcnt++; chart.AddChartTrig(starttrig); chartbound.AddTriangle(GetTriangle(starttrig)); workedarea += GetTriangle(starttrig).Area(points); for (int i = 0; i < 3; i++) { STLPointId pi = GetTriangle(starttrig)[i]; innerpointstochart[pi] = chartnum; pointstochart[pi] = chartnum; chartpoints.Append(pi); innerchartpoints.Append(pi); } bool changed = true; int oldstartic = 1; int oldstartic2; // NgProfiler::StopTimer (timerb); // NgProfiler::StartTimer (timer2); tinner.Start(); while (changed) { changed = false; oldstartic2 = oldstartic; oldstartic = chart.GetNT(); // for (ic = oldstartic2; ic <= chart->GetNT(); ic++) for (int ic = oldstartic2; ic <= oldstartic; ic++) { STLTrigId i = chart.GetTrig1(ic); if (GetMarker(i) == chartnum) { for (int j = 1; j <= NONeighbourTrigs(i); j++) { STLTrigId nt = NeighbourTrig(i,j); // *testout << "check trig " << nt << endl; STLPointId np1, np2; GetTriangle(i).GetNeighbourPoints(GetTriangle(nt),np1,np2); if (GetMarker(nt) == 0 && !IsEdge(np1,np2)) { Vec<3> n2 = GetTriangle(nt).Normal(); // *testout << "acos = " << 180/M_PI*acos (n2*sn) << endl; if ( (n2 * sn) >= coschartangle ) { // *testout << "good angle " << endl; accepted = true; /* //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; } } } } } */ //find overlapping charts exacter (fast, too): for (int k = 1; k <= NONeighbourTrigs(nt); k++) { int nnt = NeighbourTrig(nt,k); if (GetMarker(nnt) != chartnum) { STLPointId nnp1, nnp2; GetTriangle(nt).GetNeighbourPoints(GetTriangle(nnt),nnp1,nnp2); accepted = chartbound.TestSeg(GetPoint(nnp1), GetPoint(nnp2), sn,sinchartangle,1 /*chartboundarydivisions*/ ,points, eps); // if (!accepted) *testout << "not acc due to testseg" << endl; Vec<3> n3 = GetTriangle(nnt).Normal(); if ( (n3 * sn) >= coschartangle && IsSmoothEdge (nnp1, nnp2) ) accepted = true; } if (!accepted) break; } /* // new check 2019-09-22 if (accepted) { auto & trig = GetTriangle(nt); Point<3> p0 = GetPoint(trig[0]); Point<3> p1 = GetPoint(trig[1]); Point<3> p2 = GetPoint(trig[2]); Point<3> p01 = Center(p0,p1); Point<3> p02 = Center(p0,p2); Point<3> p12 = Center(p1,p2); Point<3> p012 = Center(p0,p1,p2); p01 += 1e-5 * (p012-p01); p02 += 1e-5 * (p012-p02); p12 += 1e-5 * (p012-p12); bool test1 = chartbound.TestSegChartNV(p01,p012,sn); bool test2 = chartbound.TestSegChartNV(p02,p012,sn); bool test3 = chartbound.TestSegChartNV(p12,p012,sn); if (!test1 || !test2 || !test3) { cout << "more stringent" << endl; accepted = false; } } */ if (accepted) { // *testout << "trig accepted" << endl; SetMarker(nt, chartnum); changed = true; markedtrigcnt++; workedarea += GetTriangle(nt).Area(points); chart.AddChartTrig(nt); chartbound.AddTriangle(GetTriangle(nt)); for (int k = 1; k <= 3; k++) { STLPointId pi = GetTriangle(nt).PNum(k); if (innerpointstochart[pi] != chartnum) { innerpointstochart[pi] = chartnum; pointstochart[pi] = chartnum; chartpoints.Append(pi); innerchartpoints.Append(pi); } } } } } } } } } tinner.Stop(); innerchartpts.SetSize(innerchartpoints.Size()); for (size_t i = 0; i < innerchartpoints.Size(); i++) innerchartpts[i] = GetPoint(innerchartpoints[i]); // NgProfiler::StopTimer (timer2); // NgProfiler::StartTimer (timer3); //find outertrigs // chartbound.Clear(); // warum, ic-bound auf edge macht Probleme js ??? touter.Start(); outermark[starttrig] = chartnum; //chart->AddOuterTrig(starttrig); changed = true; oldstartic = 1; while (changed) { changed = false; oldstartic2 = oldstartic; oldstartic = chart.GetNT(); for (int ic = oldstartic2; ic <= oldstartic; ic++) { STLTrigId i = chart.GetTrig1(ic); if (outermark[i] != chartnum) continue; for (int j = 1; j <= NONeighbourTrigs(i); j++) { STLTrigId nt = NeighbourTrig(i,j); if (outermark[nt] == chartnum) continue; const STLTriangle & ntrig = GetTriangle(nt); STLPointId np1, np2; GetTriangle(i).GetNeighbourPoints(GetTriangle(nt),np1,np2); if (IsEdge (np1, np2)) continue; /* if (outertested.Get(nt) == chartnum) continue; */ outertested[nt] = chartnum; Vec<3> n2 = GetTriangle(nt).Normal(); //abfragen, ob noch im tolerierten Winkel if ( (n2 * sn) >= cosouterchartangle ) { accepted = true; // NgProfiler::StartTimer (timer4); bool isdirtytrig = false; Vec<3> gn = GetTriangle(nt).GeomNormal(points); double gnlen = gn.Length(); if (n2 * gn <= cosouterchartanglehalf * gnlen) isdirtytrig = true; //zurueckweisen, falls eine Spiralartige outerchart entsteht //find overlapping charts exacter: //do not check dirty trigs! // NgProfiler::StartTimer (timer4a); if (spiralcheckon && !isdirtytrig) for (int k = 1; k <= NONeighbourTrigs(nt); k++) { // NgProfiler::StartTimer (timer4b); STLTrigId nnt = NeighbourTrig(nt,k); if (outermark[nnt] != chartnum) { // NgProfiler::StartTimer (timer4c); STLPointId nnp1, nnp2; GetTriangle(nt).GetNeighbourPoints(GetTriangle(nnt),nnp1,nnp2); // NgProfiler::StopTimer (timer4c); // NgProfiler::StartTimer (timer4d); accepted = chartbound.TestSeg(GetPoint(nnp1),GetPoint(nnp2), sn,sinouterchartangle, 0 /*chartboundarydivisions*/ ,points, eps); // NgProfiler::StopTimer (timer4d); // NgProfiler::StartTimer (timer4e); Vec<3> n3 = GetTriangle(nnt).Normal(); if ( (n3 * sn) >= cosouterchartangle && IsSmoothEdge (nnp1, nnp2) ) accepted = true; // NgProfiler::StopTimer (timer4e); } // NgProfiler::StopTimer (timer4b); if (!accepted) break; } // NgProfiler::StopTimer (timer4a); // NgProfiler::StopTimer (timer4); // NgProfiler::RegionTimer reg5(timer5); // outer chart is only small environment of // inner chart: if (accepted) { // NgProfiler::StartTimer (timer5a); accepted = false; for (int k = 1; k <= 3; k++) if (innerpointstochart[ntrig.PNum(k)] == chartnum) { accepted = true; break; } // NgProfiler::StopTimer (timer5a); // int timer5csl = (innerchartpts.Size() < 100) ? timer5cs : timer5cl; // NgProfiler::StartTimer (timer5csl); if (!accepted) for (int k = 1; k <= 3; k++) { Point<3> pt = GetPoint(ntrig.PNum(k)); double h2 = sqr(mesh.GetH(pt)); /* for (int l = 1; l <= innerchartpoints.Size(); l++) { double tdist = Dist2(pt, GetPoint (innerchartpoints.Get(l))); if (tdist < 4 * h2) { accepted = 1; break; } } */ for (int l = 0; l < innerchartpts.Size(); l++) { double tdist = Dist2(pt, innerchartpts[l]); if (tdist < 4 * h2) { accepted = true; break; } } if (accepted) break; } // NgProfiler::StopTimer (timer5csl); } // NgProfiler::StartTimer (timer5b); if (accepted) { changed = true; outermark[nt] = chartnum; if (GetMarker(nt) != chartnum) { chartbound.AddTriangle(GetTriangle(nt)); chart.AddOuterTrig(nt); for (int k = 1; k <= 3; k++) { if (pointstochart[GetTriangle(nt).PNum(k)] != chartnum) { pointstochart[GetTriangle(nt).PNum(k)] = chartnum; chartpoints.Append(GetTriangle(nt).PNum(k)); } } } } // NgProfiler::StopTimer (timer5b); } } } } touter.Stop(); // NgProfiler::StopTimer (timer3); // NgProfiler::StartTimer (timere); // NgProfiler::StartTimer (timere1); //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 (int k = 1; k <= dirtycharttrigs.Size(); k++) { STLTrigId tn = chart.GetChartTrig1(dirtycharttrigs.Get(k)); outermark[tn] = 0; //not necessary, for later use SetMarker(tn, 0); markedtrigcnt--; workedarea -= GetTriangle(tn).Area(points); } chart.MoveToOuterChart(dirtycharttrigs); lastunmarked = 1; lastunmarked = prelastunmarked; } chartbound.DeleteSearchTree(); // NgProfiler::StopTimer (timere1); // NgProfiler::StartTimer (timere2); // cout << "key" << endl; // char key; // cin >> key; //calculate an estimate meshsize, not to produce too large outercharts, with factor 2 larger! RestrictHChartDistOneChart(chartnum, chartdistacttrigs, mesh, h, 0.5, atlasminh, stlparam); // NgProfiler::Print(stdout); // NgProfiler::StopTimer (timere2); // NgProfiler::StopTimer (timere); } // NgProfiler::StopTimer (timer1); // NgProfiler::Print(stdout); PrintMessage(5,""); PrintMessage(5,"NO charts=", atlas.Size()); int cnttrias = 0; outerchartspertrig.SetSize(GetNT()); // for (int i = 1; i <= atlas.Size(); i++) for (ChartId i : atlas.Range()) { for (int j = 1; j <= GetChart(i).GetNT(); j++) { STLTrigId tn = GetChart(i).GetTrig1(j); AddOCPT(tn,i); } cnttrias += GetChart(i).GetNT(); } PrintMessage(5, "NO outer chart trias=", cnttrias); //sort outerchartspertrig for (int i = 1; i <= GetNT(); i++) { for (int k = 1; k < GetNOCPT(i); k++) for (int j = 1; j < GetNOCPT(i); j++) { int 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(stlparam); PrintMessage(5,"Make Atlas finished"); for (auto & chart : atlas) chart->BuildInnerSearchTree(); 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; } ChartId STLGeometry :: GetChartNr(STLTrigId i) const { if (i > chartmark.Size()) { PrintSysError("GetChartNr(", int(i), ") not possible!!!"); i = 1; } return chartmark[i]; } /* int STLGeometry :: GetMarker(int i) const { return chartmark.Get(i); } */ void STLGeometry :: SetMarker(STLTrigId nr, ChartId m) { chartmark[nr] = m; } int STLGeometry :: AtlasMade() const { return chartmark.Size() != 0; } /* //return 1 if not exists int AddIfNotExists(NgArray& 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(NgArray& limes, ChartId chartnum) { STLPointId np1, np2; limes.SetSize(0); STLChart& chart = GetChart(chartnum); for (int j = 1; j <= chart.GetNChartT(); j++) { STLTrigId t = chart.GetChartTrig1(j); const STLTriangle& tt = GetTriangle(t); for (int k = 1; k <= NONeighbourTrigs(t); k++) { STLTrigId 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& outercharttrigs, NgArray& chartpointchecked, NgArray& dirtytrigs) { dirtytrigs.SetSize(0); // int cnt = 0; for (int j = 1; j <= chart.GetNChartT(); j++) { STLTrigId t = chart.GetChartTrig1(j); const STLTriangle& tt = GetTriangle(t); for (int k = 1; k <= NONeighbourTrigs(t); k++) { STLTrigId nt = NeighbourTrig(t,k); if (GetChartNr(nt) != chartnum && outercharttrigs[nt] != chartnum) { STLPointId np1, np2; tt.GetNeighbourPoints(GetTriangle(nt),np1,np2); if (!IsEdge(np1,np2)) { dirtytrigs.Append(j); //local numbers!!! // cnt++; break; //only once per trig!!! } } } } // cnt = 0; STLPointId ap1, ap2, pn; Array trigsaroundp; for (int j = chart.GetNChartT(); j >= 1; j--) { STLTrigId t = chart.GetChartTrig1(j); const STLTriangle& tt = GetTriangle(t); for (int k = 1; k <= 3; k++) { pn = tt.PNum(k); //if (chartpointchecked.Get(pn) == chartnum) //{continue;} int checkpoint = 0; for (int n = 1; n <= trigsperpoint.EntrySize(pn); n++) { if (trigsperpoint.Get(pn,n) != t && //ueberfluessig??? GetChartNr(trigsperpoint.Get(pn,n)) != chartnum && outercharttrigs[trigsperpoint.Get(pn,n)] != chartnum) {checkpoint = 1;}; } if (checkpoint) { chartpointchecked.Elem(pn) = chartnum; GetSortedTrianglesAroundPoint(pn,t,trigsaroundp); trigsaroundp.Append(t); //ring bool problem = false; //forward: for (int l = 2; l <= trigsaroundp.Size()-1; l++) { STLTrigId tn1 = trigsaroundp[l-2]; STLTrigId tn2 = trigsaroundp[l-1]; 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[tn2] != chartnum) {problem = true;} } //backwards: for (int l = trigsaroundp.Size()-1; l >= 2; l--) { STLTrigId tn1 = trigsaroundp[l]; STLTrigId tn2 = trigsaroundp[l-1]; 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[tn2] != chartnum) {problem = true;} } // if (problem && !IsInArray(j,dirtytrigs)) if (problem && !dirtytrigs.Contains(j)) { dirtytrigs.Append(j); // cnt++; break; //only once per triangle } } } } } } ================================================ FILE: libsrc/stlgeom/stlgeommesh.cpp ================================================ //20.11.1999 second part of stlgeom.cc, mainly mesh functions #include #include #include #include #include #include "stlgeom.hpp" namespace netgen { int EdgeUsed(int p1, int p2, NgArray& edges, INDEX_2_HASHTABLE& 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 edgepoints; TABLE edgepointdists; TABLE edgepointorigines; TABLE edgepointoriginps; NgArray edgetrigs; NgArray edgepointnums; NgArray edgetriglocinds; int size = 3*GetNT(); INDEX_2_HASHTABLE 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); NgArray edgelist1; NgArray 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!");} NgArray 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()); meshcharttrigs = 0; } void STLGeometry::GetMeshChartBoundary (NgArray> & apoints, NgArray> & points3d, NgArray & alines, double h) { twoint seg, newseg; int zone; Point<2> p2; const STLChart& chart = GetChart(meshchart); for (int i = 1; i <= chart.GetNOLimit(); i++) { seg = chart.GetOLimit(i); INDEX_2 i2; for (int 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 (int 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) const { meshchart = GetChartNr(trignum); meshtrignv = GetTriangle(trignum).Normal(); } void STLGeometry :: SelectChartOfPoint (const Point<3> & p) { int i, ii; NgArray 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 { NgArray trigsinbox; if (!geomsearchtreeon) { //alter chart-tree Box<3> box(locpoint, locpoint); box.Increase (range); chart.GetTrianglesInBox (box.PMin(), box.PMax(), trigsinbox); } else { NgArray 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) { Vec<3> p1p = h * plainpoint[0] * ex + h * plainpoint[1] * 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 j; int fi = 0; // int cnt = 0; int different = 0; // const double lamtol = 1e-6; const STLChart& chart = GetChart(meshchart); STLTrigId trig = chart.ProjectNormal(p3d); return trig; // cout << "new, trig = " << trig << endl; // #define MOVEDTOCHART #ifdef MOVEDTOCHART 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++) { STLTrigId i = chart.GetTrig1(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; } #endif // cout << "oldtrig = " << fi << endl; // 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.GetTrig1(i)).GetNearestPoint(points, p); if (dist < nearest) { pf = p; nearest = dist; ft = chart.GetTrig1(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, const STLParameters& stlparam) { 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; STLPointId 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) { NgArray 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, const STLParameters& stlparam, const MeshingParameters& mparam) { //bei jedem Dreieck alle Nachbardreiecke vergleichen, und, fallskein Kante dazwischen, //die Meshsize auf ein bestimmtes Mass limitieren int i,j; STLPointId 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"); NgArray 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 (mparam.closeedgefac.has_value()) { PushStatusF("Restrict H due to close edges"); //geht nicht für spiralen!!!!!!!!!!!!!!!!!! double disttohfact = sqr(10.0 / *mparam.closeedgefac); int k,l; double h1, h2, dist; int rc = 0; Point3d p3p1; double mindist = 1E50; PrintMessage(7,"build search tree..."); BoxTree<3> * lsearchtree = new BoxTree<3> (GetBoundingBox().PMin() - Vec3d(1,1,1), GetBoundingBox().PMax() + Vec3d(1,1,1)); NgArray pmins(GetNLines()); NgArray 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(); } NgArray 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 NgArray acttrigs(GetNT()); //outercharttrigs acttrigs = 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., stlparam); } PopStatus(); // NgProfiler::Print(stdout); } 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(ChartId chartnum, NgArray& acttrigs, class Mesh & mesh, double gh, double fact, double minh, const STLParameters& stlparam) { static int timer1 = NgProfiler::CreateTimer ("restrictH OneChart 1"); static int timer2 = NgProfiler::CreateTimer ("restrictH OneChart 2"); static int timer3 = NgProfiler::CreateTimer ("restrictH OneChart 3"); static int timer3a = NgProfiler::CreateTimer ("restrictH OneChart 3a"); static int timer3b = NgProfiler::CreateTimer ("restrictH OneChart 3b"); NgProfiler::StartTimer (timer1); double limessafety = stlparam.resthchartdistfac*fact; // original: 2 double localh; // mincalch = 1E10; //maxcalch = -1E10; NgArray limes1; NgArray limes2; NgArray plimes1; NgArray plimes2; NgArray plimes1trigs; //check from which trig the points come NgArray plimes2trigs; NgArray plimes1origin; //either the original pointnumber or zero, if new point int divisions = 10; STLPointId 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(chartnum); chart.ClearOLimit(); chart.ClearILimit(); for (int j = 1; j <= chart.GetNChartT(); j++) { int t = chart.GetChartTrig1(j); tt = GetTriangle(t); for (int k = 1; k <= NONeighbourTrigs(t); k++) { int nt = NeighbourTrig(t,k); if (GetChartNr(nt) != chartnum) { tt.GetNeighbourPoints(GetTriangle(nt),np1,np2); if (!IsEdge(np1,np2) && !GetSpiralPoint(np1) && !GetSpiralPoint(np2)) { Point3d p3p1 = GetPoint(np1); Point3d p3p2 = GetPoint(np2); // if (AddIfNotExists(limes1,np1)) if (!limes1.Contains(np1)) { limes1.Append(np1); plimes1.Append(p3p1); plimes1trigs.Append(t); plimes1origin.Append(np1); } // if (AddIfNotExists(limes1,np2)) if (!limes1.Contains(np2)) { limes1.Append(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); } } } } } NgProfiler::StopTimer (timer1); NgProfiler::StartTimer (timer2); for (int j = 1; j <= chart.GetNT(); j++) acttrigs.Elem(chart.GetTrig1(j)) = chartnum; for (int j = 1; j <= chart.GetNOuterT(); j++) { int t = chart.GetOuterTrig1(j); tt = GetTriangle(t); for (int k = 1; k <= 3; k++) { int nt = NeighbourTrig(t,k); if (acttrigs.Get(nt) != chartnum) { tt.GetNeighbourPoints(GetTriangle(nt),np1,np2); if (!IsEdge(np1,np2)) { Point3d p3p1 = GetPoint(np1); Point3d p3p2 = GetPoint(np2); // if (AddIfNotExists(limes2,np1)) {plimes2.Append(p3p1); plimes2trigs.Append(t);} // if (AddIfNotExists(limes2,np2)) {plimes2.Append(p3p2); plimes2trigs.Append(t);} if (!limes2.Contains(np1)) { limes2.Append(np1); plimes2.Append(p3p1); plimes2trigs.Append(t); } if (!limes2.Contains(np2)) { limes2.Append(np2); plimes2.Append(p3p2); plimes2trigs.Append(t); } chart.AddOLimit(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.); plimes2.Append(Point3d(p3p1.X()*f1+p3p2.X()*f2, p3p1.Y()*f1+p3p2.Y()*f2, p3p1.Z()*f1+p3p2.Z()*f2)); plimes2trigs.Append(t); } } } } } NgProfiler::StopTimer (timer2); NgProfiler::StartTimer (timer3); double chartmindist = 1E50; if (plimes2.Size()) { NgProfiler::StartTimer (timer3a); Box3d bbox; bbox.SetPoint (plimes2.Get(1)); for (int j = 2; j <= plimes2.Size(); j++) bbox.AddPoint (plimes2.Get(j)); Point3dTree stree(bbox.PMin(), bbox.PMax()); for (int j = 1; j <= plimes2.Size(); j++) stree.Insert (plimes2.Get(j), j); NgArray foundpts; NgProfiler::StopTimer (timer3a); NgProfiler::StartTimer (timer3b); for (int j = 1; j <= plimes1.Size(); j++) { double mindist = 1E50; 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++) { int k = foundpts.Get(kk); double 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;} } } NgProfiler::StopTimer (timer3b); } NgProfiler::StopTimer (timer3); } int STLMeshingDummy (STLGeometry* stlgeometry, shared_ptr & mesh, const MeshingParameters & mparam, const STLParameters& stlparam) { if (mparam.perfstepsstart > mparam.perfstepsend) return 0; multithread.terminate = 0; int success = 1; //int trialcntouter = 0; if (mparam.perfstepsstart <= MESHCONST_MESHEDGES) { if (mesh) mesh -> DeleteMesh(); else mesh = make_shared(); 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); if (mparam.uselocalh) for (auto mspnt : mparam.meshsize_points) mesh->RestrictLocalH(mspnt.pnt, mspnt.h); success = 0; //mesh->DeleteMesh(); STLMeshing (*stlgeometry, *mesh, mparam, stlparam); stlgeometry->edgesfound = 1; stlgeometry->surfacemeshed = 0; stlgeometry->surfaceoptimized = 0; stlgeometry->volumemeshed = 0; } if (multithread.terminate) return 0; if (mparam.perfstepsstart <= MESHCONST_MESHSURFACE && mparam.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, mparam, stlparam); 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 (mparam.perfstepsstart <= MESHCONST_OPTSURFACE && mparam.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); MeshingParameters mpar = mparam; mpar.optimize2d = "cmsmSm"; STLSurfaceOptimization (*stlgeometry, *mesh, mpar); #ifdef STAT_STREAM (*statout) << GetTime() << " & "; #endif mpar.Render(); } stlgeometry->surfaceoptimized = 1; } if (multithread.terminate) return 0; if(stlgeometry->IsSurfaceSTL()) return 0; if (mparam.perfstepsstart <= MESHCONST_MESHVOLUME && mparam.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 (mparam.perfstepsstart <= MESHCONST_OPTVOLUME && mparam.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 mparam.Render(); } } return 0; } } ================================================ FILE: libsrc/stlgeom/stlline.cpp ================================================ #include #include #include #include #include #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, NgArray& 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, NgArray& 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 NgArray& 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, NgArray& line) { int status = Get(GetEdgeNum(ep1,ep2)).GetStatus(); int p(0), en; int j, i, k; int oldend; int newend = 1; STLPointId pnew; int 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,STLPointId>& ap, int nr) const { return Dist(ap[PNum(nr)],ap[PNum(nr+1)]); } double STLLine :: GetLength(const Array,STLPointId>& ap) const { double len = 0; for (int i = 2; i <= pts.Size(); i++) len += (ap[pts.Get(i)] - ap[pts.Get(i-1)]).Length(); return len; } void STLLine :: GetBoundingBox (const Array,STLPointId> & ap, Box<3> & box) const { box.Set (ap[pts[0]]); for (int i = 1; i < pts.Size(); i++) box.Add (ap[pts[i]]); } Point<3> STLLine :: GetPointInDist(const Array,STLPointId>& ap, double dist, int& index) const { if (dist <= 0) { index = 1; return ap[StartP()]; } double len = 0; int i; for (i = 1; i < pts.Size(); i++) { double seglen = Dist (ap[pts.Get(i)], ap[pts.Get(i+1)]); if (len + seglen > dist) { index = i; double relval = (dist - len) / (seglen + 1e-16); Vec3d v (ap[pts.Get(i)], ap[pts.Get(i+1)]); return ap[pts.Get(i)] + relval * v; } len += seglen; } index = pts.Size() - 1; return ap[EndP()]; } /* double stlgh; double GetH(const Point3d& p, double x) { return stlgh;//+0.5)*(x+0.5); } */ STLLine* STLLine :: Mesh(const Array,STLPointId>& ap, NgArray& mp, double ghi, class Mesh& mesh) const { static int timer1a = NgProfiler::CreateTimer ("mesh stl-line 1a"); static int timer1b = NgProfiler::CreateTimer ("mesh stl-line 1b"); static int timer2 = NgProfiler::CreateTimer ("mesh stl-line 2"); static int timer3 = NgProfiler::CreateTimer ("mesh stl-line 3"); NgProfiler::StartTimer (timer1a); 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; Box<3> bbox; GetBoundingBox (ap, bbox); double diam = bbox.Diam(); double minh = mesh.LocalHFunction().GetMinH (bbox.PMin(), bbox.PMax()); double maxseglen = 0; for (int i = 1; i <= GetNS(); i++) maxseglen = max2 (maxseglen, GetSegLen (ap, i)); int nph = 10+int(maxseglen / minh); //anzahl der integralauswertungen pro segment NgArray inthi(GetNS()*nph); NgArray curvelen(GetNS()*nph); NgProfiler::StopTimer (timer1a); NgProfiler::StartTimer (timer1b); for (int i = 1; i <= GetNS(); i++) { //double seglen = GetSegLen(ap,i); for (int 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; int j = 1; p = ap[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); NgProfiler::StopTimer (timer1b); NgProfiler::StartTimer (timer2); inthl = 0; //restart each meshseg for (int i = 1; i <= inthlint; i++) { while (inthl < 1.000000001 && j <= inthi.Size()) { inthl += inthi.Get(j)/fact; dist += curvelen.Get(j); j++; } //went too 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++; } NgProfiler::StopTimer (timer2); NgProfiler::StartTimer (timer3); p = ap[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; */ NgProfiler::StopTimer (timer3); return line; } } ================================================ FILE: libsrc/stlgeom/stlline.hpp ================================================ #ifndef FILE_STLLINE #define FILE_STLLINE /**************************************************************************/ /* File: stlline.hh */ /* Author: Joachim Schoeberl */ /* Author2: Johannes Gerstmayr */ /* Date: 20. Nov. 99 */ /**************************************************************************/ namespace netgen { 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 hashtab; NgArray edgedata; TABLE 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, NgArray& 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; NgArray pts; NgArray lefttrigs; NgArray righttrigs; NgArray 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,STLPointId>& 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,STLPointId> & 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,STLPointId>& 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,STLPointId>& ap, double dist, int& index) const; //return a meshed polyline STLLine* Mesh(const Array,STLPointId>& ap, NgArray& mp, double ghi, class Mesh& mesh) const; void DoSplit() {split = 1;} int ShouldSplit() const {return split;} }; } // namespace netgen #endif ================================================ FILE: libsrc/stlgeom/stlpkg.cpp ================================================ #include #include #include #include #include #include #include #include #include "vsstl.hpp" extern "C" int Ng_STL_Init (Tcl_Interp * interp); namespace netgen { DLL_HEADER extern shared_ptr ng_geometry; DLL_HEADER extern shared_ptr mesh; DLL_HEADER extern MeshingParameters mparam; DLL_HEADER extern STLParameters stlparam; static VisualSceneSTLGeometry vsstlgeom; static VisualSceneSTLMeshing vsstlmeshing; char * err_needsstlgeometry = (char*) "This operation needs an STL geometry"; class STLGeometryVisRegister : public GeometryRegister { public: virtual NetgenGeometry * Load (const filesystem::path & filename) const { return NULL; } 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.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[]) { STLGeometryVisRegister 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 (ng_geometry.get()); 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(stlparam); } else if (strcmp (argv[1], "smoothdirtytrigs") == 0) { stlgeometry->SmoothDirtyTrigs(stlparam); } else if (strcmp (argv[1], "smoothrevertedtrigs") == 0) { stlgeometry->GeomSmoothRevertedTrigs(stlparam); } 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(stlparam); } else if (strcmp (argv[1], "marknonsmoothnormals") == 0) { stlgeometry->MarkNonSmoothNormals(stlparam); } 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(stlparam); } 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(); } else if (strcmp (argv[1], "writechart") == 0) { int st = stlgeometry->GetSelectTrig(); if (st >= 1 && st <= stlgeometry->GetNT() && stlgeometry->AtlasMade()) { auto chartnumber = stlgeometry->GetChartNr(st); stlgeometry->WriteChartToFile(chartnumber, "chart.stlb"); } } } return TCL_OK; } 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 (ng_geometry.get()); 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) { snprintf (buf, size(buf), "%d", stlgeometry->Topology_Ok()); Tcl_SetResult (interp, buf, TCL_STATIC); } if (strcmp (argv[1], "orientation_ok") == 0) { snprintf (buf, size(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; } snprintf (buf, size(buf), "%i", (int)data[0]); Tcl_SetVar (interp, argv[1], buf, 0); snprintf (buf, size(buf), "%5.3g", data[1]); Tcl_SetVar (interp, argv[2], buf, 0); snprintf (buf, size(buf), "%5.3g", data[2]); Tcl_SetVar (interp, argv[3], buf, 0); snprintf (buf, size(buf), "%5.3g", data[3]); Tcl_SetVar (interp, argv[4], buf, 0); snprintf (buf, size(buf), "%5.3g", data[4]); Tcl_SetVar (interp, argv[5], buf, 0); snprintf (buf, size(buf), "%5.3g", data[5]); Tcl_SetVar (interp, argv[6], buf, 0); snprintf (buf, size(buf), "%5.3g", data[6]); Tcl_SetVar (interp, argv[7], buf, 0); snprintf (buf, size(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 (auto loader : GeometryRegister()) loader -> SetParameters (interp); Ng_SetMeshingParameters (clientData, interp, argc, argv); STLGeometry * stlgeometry = dynamic_cast (ng_geometry.get()); if (mesh && stlgeometry) { mesh -> SetLocalH (stlgeometry->GetBoundingBox().PMin() - Vec3d(10, 10, 10), stlgeometry->GetBoundingBox().PMax() + Vec3d(10, 10, 10), mparam.grading); stlgeometry -> RestrictLocalH(*mesh, mparam.maxh, stlparam, mparam); if (stlparam.resthsurfmeshcurvenable) mesh -> CalcLocalHFromSurfaceCurvature (mparam.grading, stlparam.resthsurfmeshcurvfac); } return TCL_OK; } VisualScene * STLGeometryVisRegister :: GetVisualScene (const NetgenGeometry * geom) const { const STLGeometry * geometry = dynamic_cast (geom); if (geometry) { vsstlmeshing.SetGeometry (const_cast (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 STLGeometryVisRegister); 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; } ================================================ FILE: libsrc/stlgeom/stltool.cpp ================================================ #include #include #include #include #include #include "stlgeom.hpp" namespace netgen { //add a point into a pointlist, return pointnumber int AddPointIfNotExists(NgArray& ap, const Point3d& p, double eps) { double eps2 = sqr(eps); for (int i = 1; i <= ap.Size(); i++) if (Dist2(ap.Get(i),p) <= eps2 ) return i; ap.Append(p); return ap.Size(); } //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 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]; for (int 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); for (int j = 0; j < ilen; j++) ios << buf[j]; } void FIOReadDouble(istream& ios, double& i) { const int ilen = sizeof(double); char buf[ilen]; for (int 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); for (int 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); for (int j = 0; j < ilen; j++) ios << buf[j]; } void FIOReadString(istream& ios, char* str, int len) { for (int j = 0; j < len; j++) ios.get(str[j]); } //read string and add terminating 0 void FIOReadStringE(istream& ios, char* str, int len) { for (int j = 0; j < len; j++) ios.get(str[j]); str[len] = 0; } void FIOWriteString(ostream& ios, char* str, int len) { for (int 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 STLPointId * 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!!! for(int i = 0; i <= 2; i++) for(int 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!!! for(int i = 0; i <= 2; i++) for(int 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, STLPointId & p1, STLPointId & p2) const { for(int i = 1; i <= 3; i++) for(int 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, STLPointId & p1, STLPointId & p2, STLPointId & po) const { for(int i = 1; i <= 3; i++) for(int 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,STLPointId>& ap) const { const Point<3> & p1 = ap[PNum(1)]; const Point<3> & p2 = ap[PNum(2)]; const Point<3> & p3 = ap[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,STLPointId>& ap) const { return 0.5 * Cross(ap[PNum(2)]-ap[PNum(1)], ap[PNum(3)]-ap[PNum(1)]).Length(); } double STLTriangle :: MinHeight(const Array,STLPointId>& 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,STLPointId>& ap) const { return max3(Dist(ap[PNum(1)],ap[PNum(2)]), Dist(ap[PNum(2)],ap[PNum(3)]), Dist(ap[PNum(3)],ap[PNum(1)])); } void STLTriangle :: ProjectInPlain(const Array,STLPointId>& ap, const Vec<3> & n, Point<3> & pp) const { const Point<3> & p1 = ap[PNum(1)]; const Point<3> & p2 = ap[PNum(2)]; const Point<3> & p3 = ap[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,STLPointId>& ap, const Vec<3> & nproj, Point<3> & pp, Vec<3> & lam) const { const Point<3> & p1 = ap[PNum(1)]; const Point<3> & p2 = ap[PNum(2)]; const Point<3> & p3 = ap[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,STLPointId>& ap, Point<3> & pp) const { const Point<3> & p1 = ap[PNum(1)]; const Point<3> & p2 = ap[PNum(2)]; const Point<3> & p3 = ap[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; } bool STLTriangle :: PointInside(const Array,STLPointId> & ap, const Point<3> & pp) const { const Point<3> & p1 = ap[PNum(1)]; const Point<3> & p2 = ap[PNum(2)]; const Point<3> & p3 = ap[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,STLPointId>& 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[PNum(j)], ap[PNumMod(j+1)], p); if (dist < nearest) { nearest = dist; pf = p; } } p3d = pf; return nearest; } } bool STLTriangle :: HasEdge(STLPointId p1, STLPointId p2) const { for (int i = 1; i <= 3; i++) if (p1 == PNum(i) && p2 == PNumMod(i+1)) return true; return false; } 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 (STLPointId p1, STLPointId 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, const STLParameters& astlparam) : geometry(ageometry), stlparam(astlparam) { // charttrigs = new NgArray (0,0); // outertrigs = new NgArray (0,0); // ilimit = new NgArray (0,0); // olimit = new NgArray (0,0); geometry = ageometry; if ( stlparam.usesearchtree == 1) { Box<3> box = geometry->GetBoundingBox(); box.Increase (0.2*box.Diam()+1e-12); searchtree = new BoxTree<3,STLTrigId> (box); /* searchtree = new BoxTree<3> (geometry->GetBoundingBox().PMin() - Vec3d(1,1,1), geometry->GetBoundingBox().PMax() + Vec3d(1,1,1)); */ } else searchtree = NULL; } STLChart :: ~STLChart() { delete searchtree; } void STLChart :: AddChartTrig(STLTrigId i) { // static int timer = NgProfiler::CreateTimer ("STLChart::AddChartTrig"); // NgProfiler::RegionTimer reg(timer); charttrigs.Append(i); const STLTriangle & trig = geometry->GetTriangle(i); const Point<3> & p1 = geometry->GetPoint (trig.PNum(1)); const Point<3> & p2 = geometry->GetPoint (trig.PNum(2)); const Point<3> & p3 = geometry->GetPoint (trig.PNum(3)); /* Point3d pmin(p1), pmax(p1); pmin.SetToMin (p2); pmin.SetToMin (p3); pmax.SetToMax (p2); pmax.SetToMax (p3); */ /* Box<3> box(p1); box.Add(p2); box.Add(p3); */ Box<3> box(p1,p2,p3); if (!geomsearchtreeon && (stlparam.usesearchtree == 1)) // {searchtree->Insert (pmin, pmax, i);} { searchtree->Insert (box, i); } } void STLChart :: AddOuterTrig(STLTrigId i) { // static int timer = NgProfiler::CreateTimer ("STLChart::AddOuterTrig"); // NgProfiler::RegionTimer reg(timer); 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);} } bool STLChart :: IsInWholeChart(int nr) const { return charttrigs.Contains(nr) || outertrigs.Contains(nr); } void STLChart :: GetTrianglesInBox (const Point3d & pmin, const Point3d & pmax, NgArray & trias) const { if (geomsearchtreeon) {PrintMessage(5,"geomsearchtreeon is set!!!");} if (searchtree) searchtree -> GetIntersecting (pmin, pmax, trias); else { Box<3> box1(pmin, pmax); box1.Increase (1e-2*box1.Diam()); trias.SetSize(0); int nt = GetNT(); for (int i = 1; i <= nt; i++) { STLTrigId trignum = GetTrig1(i); const STLTriangle & trig = geometry->GetTriangle(trignum); Box<3> box2(geometry->GetPoint (trig.PNum(1)), geometry->GetPoint (trig.PNum(2)), geometry->GetPoint (trig.PNum(3))); if (box1.Intersect (box2)) trias.Append (trignum); } } } //trigs may contain the same triangle double void STLChart :: MoveToOuterChart(const NgArray& trigs) { if (!trigs.Size()) return; for (int i = 1; i <= trigs.Size(); i++) { if (charttrigs[trigs.Get(i)-1] != -1) AddOuterTrig(charttrigs[trigs.Get(i)-1]); charttrigs[trigs.Get(i)-1] = -1; } DelChartTrigs(trigs); } //trigs may contain the same triangle double void STLChart :: DelChartTrigs(const NgArray& trigs) { if (!trigs.Size()) return; for (int i = 1; i <= trigs.Size(); i++) charttrigs[trigs.Get(i)-1] = -1; int cnt = 0; for (int i = 1; i <= charttrigs.Size(); i++) { if (charttrigs[i-1] == -1) cnt++; if (cnt != 0 && i < charttrigs.Size()) charttrigs[i-cnt] = charttrigs[i]; } int 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 BoxTree<3,STLTrigId> (geometry->GetBoundingBox().PMin() - Vec3d(1,1,1), geometry->GetBoundingBox().PMax() + Vec3d(1,1,1)); for (int 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); } void STLChart :: BuildInnerSearchTree() { Box<2> chart_bbox(Box<2>::EMPTY_BOX); for (STLTrigId trigid : charttrigs) { for (STLPointId pi : (*geometry)[trigid].PNums()) { Point<3> p = (*geometry)[pi]; Point<2> p2d = Project2d(p); chart_bbox.Add(p2d); } } chart_bbox.Increase (1e-2*chart_bbox.Diam()); inner_searchtree = make_unique> (chart_bbox); for (STLTrigId trigid : charttrigs) { Box<2> bbox(Box<2>::EMPTY_BOX); for (STLPointId pi : (*geometry)[trigid].PNums()) { Point<3> p = (*geometry)[pi]; Point<2> p2d = Project2d(p); bbox.Add(p2d); } inner_searchtree->Insert (bbox, trigid); } } STLTrigId STLChart :: ProjectNormal (Point<3> & p3d) const { int nt = GetNT(); double lamtol = 1e-6; QuadraticFunction3d quadfun(p3d, GetNormal()); int starttrig = 1; if (inner_searchtree) { starttrig = GetNChartT()+1; Point<2> p2d = Project2d (p3d); bool inside = false; STLTrigId trignum; inner_searchtree->GetFirstIntersecting(p2d, p2d, [&](auto i) { auto & trig = geometry->GetTriangle(i); const Point<3> & c = trig.center; if (quadfun.Eval(c) > sqr (trig.rad)) return false; Point<3> p = p3d; Vec<3> lam; int err = trig.ProjectInPlain(geometry->GetPoints(), GetNormal(), p, lam); inside = (err == 0 && lam(0) > -lamtol && lam(1) > -lamtol && (1-lam(0)-lam(1)) > -lamtol); if (inside) { trignum=i; p3d = p; return true; } return false; }); if(inside) return trignum; } for (int j = starttrig; j <= nt; j++) { STLTrigId i = GetTrig1(j); auto & trig = geometry->GetTriangle(i); const Point<3> & c = trig.center; if (quadfun.Eval(c) > sqr (trig.rad)) continue; Point<3> p = p3d; Vec<3> lam; int err = trig.ProjectInPlain(geometry->GetPoints(), GetNormal(), p, lam); bool inside = (err == 0 && lam(0) > -lamtol && lam(1) > -lamtol && (1-lam(0)-lam(1)) > -lamtol); if (inside) { p3d = p; return i; } } return 0; } /* 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 NgArray > & 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) : geometry(ageometry) { ; } /* void STLBoundary :: AddOrDelSegment(const STLBoundarySeg & seg) { bool found = false; for (int i = 1; i <= boundary.Size(); i++) { if (found) { boundary.Elem(i-1) = boundary.Get(i); } if (boundary.Get(i) == seg) { found = true; } } if (!found) { boundary.Append(seg); } else { boundary.SetSize(boundary.Size()-1); } } */ void STLBoundary ::AddTriangle(const STLTriangle & t) { // static Timer timer("STLBoundary::AddTriangle"); RegionTimer reg(timer); // static int timer_old = NgProfiler::CreateTimer ("STLChart::AddTriangle_old"); // static int timer_new = NgProfiler::CreateTimer ("STLChart::AddTriangle_new"); // NgProfiler::StartTimer (timer_old); #ifdef ADDTRIGOLD 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); /* int newnr; if (freelist.Size()) { newnr = freelist.Last(); freelist.DeleteLast(); boundary[newnr] = seg1; } else { boundary.Append(seg1); newnr = boundary.Size(); } // cout << "tree add el " << boundary.Size() << endl; if (searchtree) { // cout << "add " << boundary.Size() << endl; searchtree->Insert (seg1.BoundingBox(), newnr); } */ } if (!found2) { seg2.Swap(); boundary.Append(seg2); /* int newnr; if (freelist.Size()) { newnr = freelist.Last(); freelist.DeleteLast(); boundary[newnr] = seg2; } else { boundary.Append(seg2); newnr = boundary.Size(); } // boundary.Append(seg2); // cout << "tree add el " << boundary.Size() << endl; if (searchtree) { // cout << "add " << boundary.Size() << endl; searchtree->Insert (seg2.BoundingBox(), newnr); } */ } if (!found3) { seg3.Swap(); boundary.Append(seg3); /* int newnr; if (freelist.Size()) { newnr = freelist.Last(); freelist.DeleteLast(); boundary[newnr] = seg3; } else { boundary.Append(seg3); newnr = boundary.Size(); } // cout << "tree add el " << boundary.Size() << endl; if (searchtree) { // cout << "add " << boundary.Size() << endl; searchtree->Insert (seg3.BoundingBox(), newnr); } */ } #endif // NgProfiler::StopTimer (timer_old); // NgProfiler::StartTimer (timer_new); INDEX_2 segs[3]; segs[0] = INDEX_2(t[0], t[1]); segs[1] = INDEX_2(t[1], t[2]); segs[2] = INDEX_2(t[2], t[0]); if(!searchtree) BuildSearchTree(); for (auto seg : segs) { STLBoundarySeg bseg(seg[0], seg[1], geometry->GetPoints(), chart); bseg.SetSmoothEdge (geometry->IsSmoothEdge (seg[0],seg[1])); INDEX_2 op(seg[1], seg[0]); if (boundary_ht.Used(op)) { boundary_ht.Delete(op); if (searchtree) searchtree->DeleteElement(op); } else { boundary_ht[seg] = bseg; if (searchtree) searchtree->Insert (bseg.BoundingBox(), seg); } } } bool STLBoundary :: TestSeg(const Point<3>& p1, const Point<3> & p2, const Vec<3> & sn, double sinchartangle, int divisions, Array,STLPointId>& points, double eps) { if (usechartnormal) return TestSegChartNV (p1, p2, sn); #ifdef NONE // for statistics { int i; static NgArray 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 tested segments: " << cntsegs << endl; for (i = 1; i <= cntclass.Size(); i++) { (*testout) << int (exp (i * log(2.0))) << " bnd segs: " << cntclass.Get(i) << endl; } */ } } #endif int i,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); */ for(auto [i2, seg] : boundary_ht) { 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) if (false) 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); } void STLBoundary :: BuildSearchTree() { Box<2> box2d(Box<2>::EMPTY_BOX); Box<3> box3d = geometry->GetBoundingBox(); for (size_t i = 0; i < 8; i++) box2d.Add ( chart->Project2d (box3d.GetPointNr(i))); searchtree = make_unique> (box2d); // searchtree = nullptr; } void STLBoundary :: DeleteSearchTree() { searchtree = nullptr; } // checks, whether 2d projection intersects bool STLBoundary :: TestSegChartNV(const Point3d & p1, const Point3d& p2, const Vec3d& sn) { // static int timerquick = NgProfiler::CreateTimer ("TestSegChartNV-searchtree"); // static Timer timer("TestSegChartNV"); RegionTimer reg(timer); Point<2> p2d1 = chart->Project2d (p1); Point<2> p2d2 = chart->Project2d (p2); Box<2> box2d; box2d.Set (p2d1); box2d.Add (p2d2); Line2d l1 (p2d1, p2d2); double eps = 1e-6; auto hasIntersection = [&] (auto i2) NETGEN_LAMBDA_INLINE { const STLBoundarySeg & seg = boundary_ht[i2]; if (seg.IsSmoothEdge()) return false; if (!box2d.Intersect (seg.BoundingBox())) return false; const Point<2> & sp1 = seg.P2D1(); const Point<2> & sp2 = seg.P2D2(); Line2d l2 (sp1, sp2); double lam1, lam2; int err = CrossPointBarycentric (l1, l2, lam1, lam2, eps); bool in1 = (lam1 > eps) && (lam1 < 1-eps); bool on1 = (lam1 > -eps) && (lam1 < 1 + eps); bool in2 = (lam2 > eps) && (lam2 < 1-eps); bool on2 = (lam2 > -eps) && (lam2 < 1 + eps); if(!err && ((on1 && in2) || (on2 && in1))) return true; return false; }; if (searchtree) { bool has_intersection = false; searchtree -> GetFirstIntersecting (box2d.PMin(), box2d.PMax(), [&] (auto i2) NETGEN_LAMBDA_INLINE { has_intersection = hasIntersection(i2); return has_intersection; }); return !has_intersection; } else { for(auto [i2, seg] : boundary_ht) if(hasIntersection(i2)) return false; return true; } } 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; } DLL_HEADER extern STLParameters stlparam; STLParameters stlparam; } ================================================ FILE: libsrc/stlgeom/stltool.hpp ================================================ #ifndef FILE_STLTOOL #define FILE_STLTOOL //#include "gprim/gprim.hh" /**************************************************************************/ /* File: stlgeom.hh */ /* Author: Joachim Schoeberl */ /* Author2: Johannes Gerstmayr */ /* Date: 20. Nov. 99 */ /**************************************************************************/ namespace netgen { // use one normal vector for whole chart extern int usechartnormal; extern int chartdebug; extern int geomsearchtreeon; extern int AddPointIfNotExists(NgArray& 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 NgArray * ArrayINTPTR; class STLGeometry; class STLParameters; // typedef int ChartId class ChartId { int i; public: class t_invalid { public: constexpr t_invalid() = default; }; static constexpr t_invalid INVALID{}; ChartId() { } constexpr ChartId(t_invalid inv) : i(0) { ; } constexpr ChartId(int ai) : i(ai) { } operator int() const { return i; } ChartId operator++ (int) { ChartId hi(*this); i++; return hi; } ChartId & operator++ () { i++; return *this; } }; } namespace ngcore { template<> constexpr netgen::ChartId IndexBASE () { return netgen::ChartId(1); } } namespace netgen { class STLChart { private: STLGeometry * geometry; Array charttrigs; // trigs which only belong to this chart Array outertrigs; // trigs which belong to other charts BoxTree<3,STLTrigId> * searchtree; // ADT containing outer trigs NgArray olimit; //outer limit of outer chart NgArray ilimit; //outer limit of inner chart const STLParameters& stlparam; public: STLChart(STLGeometry * ageometry, const STLParameters& astlparam); ~STLChart(); void AddChartTrig(STLTrigId i); void AddOuterTrig(STLTrigId i); bool IsInWholeChart(int nr) const; STLTrigId GetChartTrig1(int i) const {return charttrigs[i-1];} STLTrigId GetOuterTrig1(int i) const {return outertrigs[i-1];} //get all trigs: STLTrigId GetTrig1(int i) const { if (i <= charttrigs.Size()) {return charttrigs[i-1];} else {return outertrigs[i-charttrigs.Size()-1];} } size_t GetNChartT() const {return charttrigs.Size();} size_t GetNOuterT() const {return outertrigs.Size();} size_t GetNT() const {return charttrigs.Size()+outertrigs.Size(); } void GetTrianglesInBox (const Point3d & pmin, const Point3d & pmax, NgArray & 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);} size_t GetNOLimit() const {return olimit.Size();} size_t 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 NgArray& trigs); void DelChartTrigs(const NgArray& trigs); // define local coordinate system, JS: private: Vec<3> normal; Point<3> pref; Vec<3> t1, t2; unique_ptr> inner_searchtree; 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 { Vec<3> v = p3d-pref; return Point<2> (t1 * v, t2 * v); } void BuildInnerSearchTree(); STLTrigId ProjectNormal (Point<3> & p) const; }; class STLBoundarySeg { Point<3> p1, p2, center; Point<2> p2d1, p2d2; Box<2> boundingbox; double rad; STLPointId i1, i2; bool smoothedge; public: STLBoundarySeg () { ; } STLBoundarySeg (STLPointId ai1, STLPointId ai2, const Array,STLPointId> & points, const STLChart * chart) : p1(points[ai1]), p2(points[ai2]), i1(ai1), i2(ai2) { center = ::netgen::Center (p1, p2); rad = Dist (p1, center); p2d1 = chart->Project2d (p1); p2d2 = chart->Project2d (p2); boundingbox.Set (p2d1); boundingbox.Add (p2d2); } int operator== (const STLBoundarySeg & s2) const { return i1 == s2.i1 && i2 == s2.i2; } void Swap (); STLPointId I1() const { return i1; } STLPointId 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 (bool se) { smoothedge = se; } bool IsSmoothEdge () const { return smoothedge; } friend class STLBoundary; }; class STLBoundary { private: STLGeometry * geometry; const STLChart * chart; // NgArray boundary; NgClosedHashTable boundary_ht; unique_ptr> searchtree; public: STLBoundary(STLGeometry * ageometry); ~STLBoundary() {} void Clear() { /* boundary.SetSize(0); */ boundary_ht = NgClosedHashTable(); } 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_ht.UsedElements();}; // const STLBoundarySeg & GetSegment(int i) {return boundary.Get(i);} void BuildSearchTree(); void DeleteSearchTree(); bool TestSeg(const Point<3> & p1, const Point<3> & p2, const Vec<3> & sn, double sinchartangle, int divisions, Array,STLPointId>& points, double eps); bool 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; }; DLL_HEADER extern STLDoctorParams stldoctor; // TODO change enable flag to optional parameters class DLL_HEADER STLParameters { public: /// angle for edge detection double yangle = 30.; double contyangle = 20.; //edges continued with contyangle /// angle of geometry edge at which the mesher should set a point double edgecornerangle = 60.; /// angle inside on chart double chartangle = 15.; /// angle for overlapping parts of char double outerchartangle = 70.; /// 0 .. no, 1 .. local, (2 .. global) int usesearchtree = 0; /// double resthatlasfac = 2.; bool resthatlasenable = true; double atlasminh = 0.1; double resthsurfcurvfac = 2.; bool resthsurfcurvenable = false; double resthchartdistfac = 1.2; bool resthchartdistenable = true; // double resthcloseedgefac = 1.; // bool resthcloseedgeenable = true; double resthedgeanglefac = 1.; bool resthedgeangleenable = false; double resthsurfmeshcurvfac = 1.; bool resthsurfmeshcurvenable = false; double resthlinelengthfac = 0.5; bool resthlinelengthenable = true; /// bool recalc_h_opt = true; /// STLParameters(); /// void Print (ostream & ost) const; }; inline ostream & operator<< (ostream & ost, const STLParameters & stlparam) { stlparam.Print (ost); return ost; } void STLMeshing (STLGeometry & geom, Mesh & mesh, const MeshingParameters& mparam, const STLParameters& stlpar); int STLSurfaceMeshing (STLGeometry & geom, Mesh & mesh, const MeshingParameters& mparam, const STLParameters& stlpar); void STLSurfaceOptimization (STLGeometry & geom, Mesh & mesh, const MeshingParameters & mparam); } // namespace netgen #endif ================================================ FILE: libsrc/stlgeom/stltopology.cpp ================================================ #include #include #include #include #include #include #include "stlgeom.hpp" #include #include namespace netgen { STLTopology :: STLTopology() : trias(), topedges(), points(), ht_topedges(NULL), trigsperpoint(), neighbourtrigs() { ; } STLTopology :: ~STLTopology() { ; } STLGeometry * STLTopology :: LoadBinary (istream & ist) { STLGeometry * geom = new STLGeometry(); NgArray 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; char spaces[nospaces+1]; for (int cntface = 0; cntface < nofacets; cntface++) { if (cntface % 10000 == 0) // { PrintDot(); } PrintMessageCR (3, cntface, " triangles loaded\r"); float f; FIOReadFloat(ist,f); normal(0) = f; FIOReadFloat(ist,f); normal(1) = f; FIOReadFloat(ist,f); normal(2) = f; for (int 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); } PrintMessage (3, nofacets, " triangles loaded\r"); geom->InitSTLGeometry(readtrigs); return geom; } void STLTopology :: SaveBinary (const filesystem::path & 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 filesystem::path & 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(); NgArray 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; NgArray > readpoints; ist >> buf; if (strcmp (buf, "NODES") == 0) { ist >> novertex; PrintMessage(5,"number 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 filesystem::path & 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(); snprintf(buf1, size(buf1), "%1.9g",n.X()); snprintf(buf2, size(buf2), "%1.9g",n.Y()); snprintf(buf3, size(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)); snprintf(buf1, size(buf1), "%1.9g",p.X()); snprintf(buf2, size(buf2), "%1.9g",p.Y()); snprintf(buf3, size(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, bool surface) { // Check if the file starts with "solid". If not, the file is binary { // binary header is 80 bytes, so don't load more than that constexpr int buflen = 80; char buf[buflen+1]; FIOReadStringE(ist,buf,buflen); // ignore whitespaces at start of line int istart; for (istart=0; istart binary file if (strncmp(buf+istart, "solid", 5) != 0) return LoadBinary(ist); // Check if there is a non-printable character in first 80 bytes for (auto i : Range(istart, buflen)) if(std::isprint(buf[i])==0 && std::isspace(buf[i])==0) return LoadBinary(ist); } STLGeometry * geom = new STLGeometry(); NgArray readtrigs; char buf[100]; Point<3> pts[3]; Vec<3> normal; [[maybe_unused]] int cntface = 0; int vertex = 0; bool badnormals = false; ist >> buf; // skip first line while (ist.good()) { ist >> buf; int n = strlen (buf); for (int 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 = Cross (pts[1]-pts[0], pts[2]-pts[0]); hnormal.Normalize(); if (normal * hnormal < 0.5) badnormals = true; } 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 (readtrigs.Size() % 100000 == 0) PrintMessageCR (3, readtrigs.Size(), " triangles loaded\r"); } else { cout << "Skipping flat triangle " << "l1 = " << Dist(pts[0], pts[1]) << ", l2 = " << Dist(pts[0], pts[2]) << ", l3 = " << Dist(pts[2], pts[1]) << endl; } } } } PrintMessage (3, readtrigs.Size(), " triangles loaded"); if (badnormals) { PrintWarning("File has normal vectors which differ extremely from geometry->correct with stldoctor!!!"); } geom->surface = surface; geom->InitSTLGeometry(readtrigs); return geom; } void STLTopology :: InitSTLGeometry(const NgArray & readtrigs) { // 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 (int i = 0; i < readtrigs.Size(); i++) for (int 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()); NgArray pintersect; pointtol = boundingbox.Diam() * stldoctor.geom_tol_fact; PrintMessage(5,"point tolerance = ", pointtol); PrintMessageCR(5,"identify points ..."); for(int i = 0; i < readtrigs.Size(); i++) { const STLReadTriangle & t = readtrigs[i]; STLTriangle st; st.SetNormal (t.Normal()); for (int 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); } if (Dist(p, points[foundpos]) > 1e-10) cout << "identify close points: " << p << " " << points[foundpos] << ", dist = " << Dist(p, points[foundpos]) << endl; st[k] = foundpos; } if ( (st[0] == st[1]) || (st[0] == st[2]) || (st[1] == st[2]) ) { PrintError("STL Triangle degenerated"); } else { AddTriangle(st); } } PrintMessage(5,"identify points ... done"); 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); NgArray 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"); PrintMessage(5,"build topology ..."); // build up topology tables int nt = GetNT(); INDEX_2_HASHTABLE * oldedges = ht_topedges; ht_topedges = new INDEX_2_HASHTABLE (GetNP()+1); topedges.SetSize(0); for (int i = 1; i <= nt; i++) { STLTriangle & trig = GetTriangle(i); for (int 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 (int k = 1; k <= 3; k++) if (othertrig.EdgeNum(k) == enr) othertrig.NBTrigNum(k) = i; } else { topedges.Append (STLTopEdge (pi1, pi2, i, 0)); enr = topedges.Size(); ht_topedges->Set (i2, enr); trig.EdgeNum(j) = enr; } } } PrintMessage(5,"topology built, checking"); topology_ok = 1; int ne = GetNTE(); for (int i = 1; i <= nt; i++) GetTriangle(i).flags.toperror = 0; for (int i = 1; i <= nt; i++) for (int 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; } } if(!surface) for (int 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 (int i = 1; i <= nt; i++) { const STLTriangle & t = GetTriangle (i); for (int j = 1; j <= 3; j++) { if(t.NBTrigNum(j) != 0) { 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 (int i = 1; i <= GetNT(); i++) for (int 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 (int i = 1; i <= ne; i++) for (int 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 (STLTrigId ti = 0; ti < GetNT(); ti++) for (STLTrigId ti : Range(trias)) { STLTriangle & trig = trias[ti]; for (int k = 0; k < 3; k++) { STLPointId pi = trig[k]; // - STLBASE; STLPointId pi2 = trig[(k+1)%3]; // - STLBASE; STLPointId 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 (int j = 0; j < trigsperpoint[pi].Size(); j++) { STLTrigId ti2 = trigsperpoint[pi][j]; // - STLBASE; const STLTriangle & trig2 = trias[ti2]; if (ti == ti2) continue; bool hasboth = 0; for (int l = 0; l < 3; l++) if (trig2[l] /* - STLBASE */ == pi2) { hasboth = 1; break; } if (!hasboth) continue; STLPointId pi4(0); for (int 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 (int i = 1; i <= GetNT(); i++) for (int k = 1; k <= 3; k++) if(GetTriangle(i).NBTrigNum(k) != 0) 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 (int i = 1; i <= GetNT(); i++) { SetThreadPercent((double)i/(double)GetNT()*100.); if (multithread.terminate) { PopStatus(); return; } for (int k = 1; k <= 3; k++) { for (int 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," = ",int(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, NgArray & 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 { STLPointId p1, p2; STLPointId psearch = GetTriangle(trig).PNum(edgenum); for (int 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()) { NgArray oriented; oriented.SetSize(GetNT()); int i; for (i = 1; i <= oriented.Size(); i++) { oriented.Elem(i) = 0; } oriented.Elem(starttrig) = 1; int k; NgArray list1; list1.SetSize(0); NgArray 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!"); } } static RegisterClassForArchive stltop; } ================================================ FILE: libsrc/stlgeom/stltopology.hpp ================================================ #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,... */ namespace netgen { class STLGeometry; // #define STLBASE 1 class STLPointId { int i; public: STLPointId () { ; } constexpr STLPointId (int ai) : i(ai) { ; } STLPointId & operator= (const STLPointId & ai) { i = ai.i; return *this; } STLPointId & operator= (int ai) { i = ai; return *this; } constexpr operator int () const { return i; } STLPointId operator++ (int) { return STLPointId(i++); } STLPointId operator-- (int) { return STLPointId(i--); } STLPointId & operator++ () { ++i; return *this; } STLPointId & operator-- () { --i; return *this; } void DoArchive(Archive& ar) { ar & i; } }; class STLTrigId { int i; public: STLTrigId () { ; } constexpr STLTrigId (int ai) : i(ai) { ; } STLTrigId & operator= (const STLTrigId & ai) { i = ai.i; return *this; } STLTrigId & operator= (int ai) { i = ai; return *this; } constexpr operator int () const { return i; } STLTrigId operator++ (int) { return STLTrigId(i++); } STLTrigId operator-- (int) { return STLTrigId(i--); } STLTrigId & operator++ () { ++i; return *this; } STLTrigId & operator-- () { --i; return *this; } int operator- (STLTrigId i2) const { return i-i2.i; } }; inline void SetInvalid (STLTrigId & id) { id = 0; } inline bool IsInvalid (STLTrigId & id) { return id == 0; } } namespace ngcore { template<> constexpr netgen::STLPointId IndexBASE () { return netgen::STLPointId(1); } template<> constexpr netgen::STLTrigId IndexBASE () { return netgen::STLTrigId(1); } } namespace netgen { // 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 STLPointId 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 STLPointId * apts); STLTriangle () { pts[0]=0;pts[1]=0;pts[2]=0; nbtrigs[0][0] = nbtrigs[0][1] = nbtrigs[0][2] = 0.; nbtrigs[1][0] = nbtrigs[1][1] = nbtrigs[1][2] = 0.; } void DoArchive(Archive& ar) { ar.Do(&topedges[0],3); ar.Do(&nbtrigs[0][0], 6); // ar.Do(&pts[0],3); ar & pts[0] & pts[1] & pts[2]; ar.Do(&domains[0],2); size_t i = flags.toperror; ar & normal & box & center & rad & facenum & i; flags.toperror = i; } STLPointId operator[] (int i) const { return pts[i]; } STLPointId & 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: STLPointId PNum(int i) const { return pts[(i-1)]; } STLPointId & PNum(int i) { return pts[(i-1)]; } STLPointId PNumMod(int i) const { return pts[(i-1)%3]; } STLPointId & PNumMod(int i) { return pts[(i-1)%3]; } FlatArray PNums() const { return { 3, pts }; } 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, STLPointId & p1, STLPointId & p2) const; int GetNeighbourPointsAndOpposite(const STLTriangle& t, STLPointId & p1, STLPointId & p2, STLPointId & po) const; // NON-normalized geometry - normal vector Vec<3> GeomNormal(const Array,STLPointId>& 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, STLPointId>& ap, const Vec<3> & n, Point<3> & pp) const; //project with the triangle's normal vector in plane void ProjectInPlain(const Array, STLPointId> & 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,STLPointId>& ap, const Vec<3> & nproj, Point<3> & pp, Vec<3> & lam) const; bool PointInside(const Array,STLPointId>& ap, const Point<3> & pp) const; //get nearest point on triangle and distance to it double GetNearestPoint(const Array,STLPointId>& ap, Point<3> & p3d) const; double Area(const Array,STLPointId>& ap) const; double MinHeight(const Array,STLPointId>& ap) const; double MaxLength(const Array,STLPointId>& ap) const; //max length of a side of triangle int GetFaceNum() {return facenum;} void SetFaceNum(int i) {facenum = i;} bool HasEdge(STLPointId p1, STLPointId p2) const; }; /** Topology Edge: Useful unside a face. A edges sharing more than 2 faces: trigs are undefined */ class STLTopEdge { STLPointId pts[2]; int trigs[2]; double cosangle; int status; // excluded, confirmed, candidate, undefined public: STLTopEdge (); STLTopEdge (STLPointId p1, STLPointId p2, int trig1, int trig2); STLPointId operator[] (int i) const { return pts[i]; } STLPointId & operator[] (int i) { return pts[i]; } STLPointId PNum(int i) const { return pts[(i-1)]; } STLPointId & PNum(int i) { return pts[(i-1)]; } STLPointId PNumMod(int i) const { return pts[(i-1)%2]; } STLPointId & 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 trias; NgArray topedges; Array, STLPointId> points; bool surface = false; // mapping of sorted pair of points to topedge INDEX_2_HASHTABLE * ht_topedges; // mapping of node to trigs TABLE()> trigsperpoint; // mapping of node to edges TABLE topedgesperpoint; // searchtree for trigs and points BoxTree<3> * 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); DLL_HEADER static STLGeometry * Load (istream & ist, bool surface=false); static STLGeometry * LoadBinary (istream & ist); void Save (const filesystem::path & filename) const; void SaveBinary (const filesystem::path & filename, const char* aname) const; void SaveSTLE (const filesystem::path & filename) const; // stores trigs and edges bool IsSurfaceSTL() const { return surface; } void SetSurfaceSTL( bool surface_ ) { surface = surface_; } virtual void DoArchive(Archive& ar) { ar & trias & points & boundingbox & pointtol; if(ar.Input()) FindNeighbourTrigs(); } virtual void InitSTLGeometry (const NgArray & readtrigs); virtual void TopologyChanged() {}; //do some things, if topology changed! /// Generate topology tables void FindNeighbourTrigs(); void GetTrianglesInBox (const Box<3> & box, NgArray & trias) const; int GetNP() const { return points.Size(); } int AddPoint(const Point<3> & p) { points.Append(p); return points.Size(); } const Point<3> & GetPoint(STLPointId nr) const { return points[nr]; } // .Get(nr); } int GetPointNum (const Point<3> & p); void SetPoint(STLPointId nr, const Point<3> & p) { points[nr] = p; } // { points.Elem(nr) = p; } auto & GetPoints() const { return points; } const Point<3> & operator[] (STLPointId i) const { return points[i]; } Point<3> & operator[] (STLPointId i) { return points[i]; } int GetNT() const { return trias.Size(); } void AddTriangle(const STLTriangle& t); const STLTriangle & GetTriangle (STLTrigId nr) const { return trias[nr]; } // .Get(nr); } STLTriangle & GetTriangle (STLTrigId nr) { return trias[nr]; } // .Elem(nr); } const STLTriangle & operator[] (STLTrigId i) const { return trias[i]; } STLTriangle & operator[] (STLTrigId 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); } DLL_HEADER 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; } DLL_HEADER void InvertTrig (int trig); DLL_HEADER void DeleteTrig (int trig); DLL_HEADER void OrientAfterTrig (int trig); // Table will be constructed, if topology is not ok /// neighbourtrigs for surfacetrigs TABLE neighbourtrigs; /// get nr-th neighbour Triangle for triangle trig int NONeighbourTrigs(STLTrigId trig) const { return neighbourtrigs.EntrySize(int(trig)); } STLTrigId NeighbourTrig(STLTrigId trig, int nr) const { return neighbourtrigs.Get(int(trig),nr); } int NeighbourTrigSorted(int trig, int nr) const; void AddNeighbourTrig(STLTrigId i, STLTrigId nt) { neighbourtrigs.Add1(int(i), nt); } int GetLeftTrig (int p1, int p2) const; int GetRightTrig (int p1, int p2) const; const Box<3> & GetBoundingBox () const { return boundingbox; } }; } // namespace netgen #endif ================================================ FILE: libsrc/stlgeom/vsstl.cpp ================================================ #include #include #include #include #include #include #include "vsstl.hpp" namespace netgen { /* //mmm #include "stlgeom/modeller.hpp" */ /* *********************** Draw STL Geometry **************** */ DLL_HEADER extern shared_ptr mesh; // #include "../../ngtcltk/mvdraw.hpp" VisualSceneSTLMeshing :: VisualSceneSTLMeshing () : VisualScene() { selecttrig = 0; nodeofseltrig = 1; } 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(); glMultMatrixd (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); NgArray 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 NgArray& 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.GetChartTrig1(j)); const Vec3d & n = stlgeometry->GetTriangle(chart.GetChartTrig1(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.GetOuterTrig1(j)); const Vec3d & n = stlgeometry->GetTriangle(chart.GetOuterTrig1(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(); glMultMatrixd (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(); glMultMatrixd (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 (); } } #ifdef NG_PYTHON #include <../general/ngpython.hpp> #include NGCORE_API_EXPORT void ExportSTLVis(py::module &m) { using namespace netgen; py::class_> (m, "VisualSceneSTLGeometry") .def("Draw", &VisualSceneSTLGeometry::DrawScene) ; m.def("SetBackGroundColor", &VisualSceneSTLGeometry::SetBackGroundColor); m.def("VS", [](STLGeometry & geom) { auto vs = make_shared(); vs->SetGeometry(&geom); return vs; }); } PYBIND11_MODULE(libstlvis, m) { ExportSTLVis(m); } #endif ================================================ FILE: libsrc/stlgeom/vsstl.hpp ================================================ #ifndef FILE_VSSTL #define FILE_VSSTL /**************************************************************************/ /* File: vsstl.hpp */ /* Author: Joachim Schoeberl */ /* Date: 05. Jan. 2011 */ /**************************************************************************/ namespace netgen { class NGGUI_API VisualSceneSTLGeometry : public VisualScene { NgArray 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 NGGUI_API VisualSceneSTLMeshing : public VisualScene { NgArray trilists; int selecttrig, nodeofseltrig; class STLGeometry * stlgeometry; public: VisualSceneSTLMeshing (); virtual ~VisualSceneSTLMeshing (); void SetGeometry (class STLGeometry * astlgeometry) { stlgeometry = astlgeometry; stlgeometry->SetSelectTrig(selecttrig); stlgeometry->SetNodeOfSelTrig(nodeofseltrig); } virtual void BuildScene (int zoomall = 0); virtual void DrawScene (); virtual void MouseDblClick (int px, int py); int seltria; }; } #endif ================================================ FILE: libsrc/visualization/CMakeLists.txt ================================================ target_sources(nggui PRIVATE importsolution.cpp meshdoc.cpp mvdraw.cpp vsfieldlines.cpp vsmesh.cpp vssolution.cpp visualpkg.cpp ) target_link_libraries( nggui PUBLIC "$" ${OPENGL_LIBRARIES} nglib) install(FILES meshdoc.hpp mvdraw.hpp visual_api.hpp vispar.hpp visual.hpp vssolution.hpp DESTINATION ${NG_INSTALL_DIR_INCLUDE}/visualization COMPONENT netgen_devel ) ================================================ FILE: libsrc/visualization/importsolution.cpp ================================================ // // Read solution file // #include "visual_api.hpp" #include #include #include #include #include #include namespace netgen { DLL_HEADER extern shared_ptr mesh; NGGUI_API void ImportSolution2 (const char * filename) { ifstream inf (filename); char buf[100], name[1000]; int i, size, comps, order; bool iscomplex; std::string 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", mesh->GetNP())); // 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 (type == "element") { soldata.soltype = NG_SOLUTION_ELEMENT; soldata.draw_surface = 0; } if (type == "surfaceelement") { soldata.soltype = NG_SOLUTION_SURFACE_ELEMENT; soldata.draw_volume = 0; } if (type == "noncontinuous") soldata.soltype = NG_SOLUTION_NONCONTINUOUS; if (type == "surfacenoncontinuous") 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); */ } } ================================================ FILE: libsrc/visualization/meshdoc.cpp ================================================ #ifndef NOTCL #include #include // #include "incvis.hpp" #include #include namespace netgen { // #include "meshdoc.hpp" MeshDoctorParameters meshdoctor; DLL_HEADER extern shared_ptr mesh; 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(); glMultMatrixd (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-IndexBASE() >= 0 && selpoint-IndexBASE() < 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) { 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 (int i = 1; i <= mesh->GetNSE(); i++) { glLoadName (i); // copy to be thread-safe // Element2d el = mesh->SurfaceElement (i); Element2d el = (*mesh)[SurfaceElementIndex(i-1)]; int drawel = 1; for (int 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 (int 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 (int i = 1; i <= mesh->GetNSE(); i++) { Element2d el = (*mesh)[SurfaceElementIndex(i-1)]; int drawel = 1; for (int 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 (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]); if (edgedist[seg[0]] <= markedgedist && edgedist[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(); glMultMatrixd (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()) { SurfaceElementIndex sei(elnr-1); selpoint = (*mesh)[sei].PNum(locpi); selpoint2 = (*mesh)[sei].PNum(oldlocpi); cout << "selpts = " << selpoint << ", " << selpoint2 << endl; } UpdateTables(); } void VisualSceneMeshDoctor :: UpdateTables () { if (!mesh) return; edgedist.SetSize(mesh->GetNP()); int i, changed; edgedist = 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[selpoint] = 1; edgedist[selpoint2] = 1; } } do { changed = 0; for (i = 1; i <= mesh->GetNSeg(); i++) { const Segment & seg = mesh->LineSegment(i); int edist = min2 (edgedist[seg[0]], edgedist[seg[1]]); edist++; if (edgedist[seg[0]] > edist) { edgedist[seg[0]] = edist; changed = 1; } if (edgedist[seg[1]] > edist) { edgedist[seg[1]] = edist; changed = 1; } } } while (changed); } int VisualSceneMeshDoctor :: IsSegmentMarked (int segnr) const { const Segment & seg = mesh->LineSegment(segnr); return (edgedist[seg[0]] <= markedgedist && edgedist[seg[1]] <= markedgedist); } } #endif // NOTCL ================================================ FILE: libsrc/visualization/meshdoc.hpp ================================================ namespace netgen { class VisualSceneMeshDoctor : public VisualScene { int filledlist; int outlinelist; int edgelist; int selelement, locpi; PointIndex selpoint, selpoint2; // for edgemarking: Array edgedist; int markedgedist; public: NGGUI_API VisualSceneMeshDoctor (); NGGUI_API virtual ~VisualSceneMeshDoctor (); NGGUI_API virtual void BuildScene (int zoomall = 0); NGGUI_API virtual void DrawScene (); NGGUI_API virtual void MouseDblClick (int px, int py); NGGUI_API void SetMarkEdgeDist (int dist); NGGUI_API void ClickElement (int elnr); NGGUI_API void UpdateTables (); NGGUI_API int IsSegmentMarked (int segnr) const; }; class MeshDoctorParameters { public: int active; }; NGGUI_API extern MeshDoctorParameters meshdoctor; } ================================================ FILE: libsrc/visualization/mvdraw.cpp ================================================ #include #include #include #include // #include #ifndef WIN32 #define GLX_GLXEXT_LEGACY #include #include #include /* for XA_RGB_DEFAULT_MAP atom */ // #include // for parallel GL ??? #endif namespace netgen { NGGUI_API Point3d VisualScene :: center; NGGUI_API double VisualScene :: rad; NGGUI_API GLdouble VisualScene :: backcolor; NGGUI_API VisualScene visual_scene_cross; NGGUI_API VisualScene *visual_scene = &visual_scene_cross; /* #if TOGL_MAJOR_VERSION!=2 GLuint VisualScene :: fontbase = 0; #else Tcl_Obj * VisualScene :: fontbase = NULL; Togl * VisualScene :: globtogl; #endif */ void (*opengl_text_function)(const char * text) = NULL; int opengl_text_width = 0; void Set_OpenGLText_Callback ( void (*fun) (const char * text), int width ) { opengl_text_function = fun; opengl_text_width = width; } void MyOpenGLText (const char * text) { if (opengl_text_function) (*opengl_text_function) (text); // cout << "MyOpenGLText: " << text << endl; } int MyOpenGLTextWidth () { return opengl_text_width; } void MyOpenGLLines(FlatArray> points) { glBegin(GL_LINES); for (auto p : points) glVertex3dv(&p[0]); glEnd(); } // texture for color decoding // GLubyte * VisualScene :: colortexture = NULL; GLuint VisualScene :: coltexname = 1; int VisualScene :: ntexcols = -1; double VisualScene :: lookatmat[16]; double VisualScene :: transmat[16]; double VisualScene :: rotmat[16]; double VisualScene :: centermat[16]; double VisualScene :: transformationmat[16]; int VisualScene :: selface; int VisualScene :: selelement; PointIndex VisualScene :: selpoint; PointIndex VisualScene :: selpoint2; int VisualScene :: locpi; int VisualScene :: seledge; optional> VisualScene :: marker = nullopt; int VisualScene :: subdivision_timestamp = -1; int VisualScene :: subdivisions = 2; int VisualScene :: viewport[4]; VisualizationParameters :: VisualizationParameters() { lightamb = 0.3; lightdiff = 0.7; lightspec = 1; shininess = 50; transp = 0.3; locviewer = 0; showstltrias = 0; centerpoint = PointIndex::INVALID; 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() { ; } void VisualScene :: BuildScene (int zoomall) { center = Point3d (0,0,0); rad = 1; if(zoomall) 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); glGetDoublev (GL_MODELVIEW_MATRIX, lookatmat); glLoadIdentity(); glTranslatef(0.0f, 0.0f, -dist); glGetDoublev (GL_MODELVIEW_MATRIX, transmat); glLoadIdentity(); glGetDoublev (GL_MODELVIEW_MATRIX, rotmat); glScaled (1/rad, 1/rad, 1/rad); glTranslated (-center.X(), -center.Y(), -center.Z()); glGetDoublev (GL_MODELVIEW_MATRIX, centermat); glLoadIdentity(); glMultMatrixd (lookatmat); glMultMatrixd (transmat); glMultMatrixd (rotmat); glMultMatrixd (centermat); glGetDoublev (GL_MODELVIEW_MATRIX, transformationmat); glPopMatrix(); } void VisualScene :: ArbitraryRotation (const NgArray & alpha, const NgArray & vec) { glPushMatrix(); glLoadIdentity(); for(int i=0; i a(1); a[0] = alpha; NgArray 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); glGetDoublev (GL_MODELVIEW_MATRIX, rotmat); glLoadIdentity(); glMultMatrixd (lookatmat); glMultMatrixd (transmat); glMultMatrixd (rotmat); glMultMatrixd (centermat); glGetDoublev (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); glMultMatrixd (rotmat); glGetDoublev (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); glMultMatrixd (transmat); glGetDoublev (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); glMultMatrixd (transmat); glGetDoublev (GL_MODELVIEW_MATRIX, transmat); break; } } glLoadIdentity(); glMultMatrixd (lookatmat); glMultMatrixd (transmat); glMultMatrixd (rotmat); glMultMatrixd (centermat); glGetDoublev (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)); glMultMatrixd (centermat); glGetDoublev (GL_MODELVIEW_MATRIX, transformationmat); glPopMatrix(); } void VisualScene :: SetClippingPlane () { if (vispar.clipping.enable) { Vec3d n = vispar.clipping.normal; n /= (n.Length()+1e-10); clipplane[0] = n.X(); clipplane[1] = n.Y(); clipplane[2] = n.Z(); clipplane[3] = -(Vec3d(center) * n) + rad * vispar.clipping.dist; double clipplane2[4]; clipplane2[0] = n.X(); clipplane2[1] = n.Y(); clipplane2[2] = n.Z(); clipplane2[3] = -(Vec3d(center) * n) + rad * (vispar.clipping.dist + vispar.clipping.dist2); glClipPlane(GL_CLIP_PLANE0, clipplane2); 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, double alpha, int typ) { if (linear) ncols = 32; if (ntexcols != ncols) { ntexcols = ncols; ArrayMem colortexture; colortexture.SetSize(4*ncols); 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*alpha); } // glPixelStorei (GL_UNPACK_ALIGNMENT, 1); glTexImage1D (GL_TEXTURE_1D, 0, 4, ncols, 0, GL_RGBA, GL_UNSIGNED_BYTE, colortexture.Data()); glTexImage2D (GL_TEXTURE_2D, 0, 4, ncols, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, colortexture.Data()); 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, string format, string unit) { if (!vispar.drawcolorbar) return; CreateTexture (GetVSSolution().numtexturecols, linear, 1, 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 (auto i : Range(50)) { double x = minx + i*1.0/49*(maxx-minx); SetOpenGlColor (x, minx, maxx); glVertex3d (x, miny, -5); glVertex3d (x, maxy, -5); } glEnd(); glDisable (GL_TEXTURE_1D); glEnable (GL_COLOR_MATERIAL); GLfloat textcol[3] = { GLfloat(1 - backcolor), GLfloat(1 - backcolor), GLfloat(1 - backcolor) }; glColor3fv (textcol); glPushAttrib (GL_LIST_BIT); // glListBase (fontbase); constexpr size_t buf_size = 20; char buf[buf_size]; GLint viewport[4]; glGetIntegerv (GL_VIEWPORT, viewport); double char_width = 2.0*MyOpenGLTextWidth()/(viewport[3]); for (int i = 0; i <= 4; i++) { double val; if (logscale) val = minval * pow (maxval / minval, i / 4.0); else val = minval + i * (maxval-minval) / 4; snprintf (buf, buf_size, format.c_str(), val); auto n = strlen(buf); double x = minx + i * (maxx-minx) / 4; x -= 0.5*char_width * n; // center text glRasterPos3d (x, 0.7,-5); MyOpenGLText (buf); } if(unit != "") MyOpenGLText (unit.c_str()); glPopAttrib (); glEnable (GL_DEPTH_TEST); } void VisualScene :: DrawTitle (string title) { if(title=="") return; glDisable (GL_LIGHTING); glDisable (GL_DEPTH_TEST); glEnable (GL_COLOR_MATERIAL); GLfloat textcol[3] = { GLfloat(1 - backcolor), GLfloat(1 - backcolor), GLfloat(1 - backcolor) }; glColor3fv (textcol); glPushAttrib (GL_LIST_BIT); GLint viewport[4]; glGetIntegerv (GL_VIEWPORT, viewport); double char_width = 2.0*MyOpenGLTextWidth()/(viewport[3]); double x = -0.5*char_width * title.size(); // center text glRasterPos3d (x, 0.82,-5); MyOpenGLText (title.c_str()); 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); glMultMatrixd (rotmat); glEnable (GL_COLOR_MATERIAL); glDisable (GL_LIGHTING); glPolygonMode (GL_FRONT_AND_BACK, GL_LINE); GLfloat textcol[3] = { GLfloat(1 - backcolor), GLfloat(1 - backcolor), GLfloat(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); snprintf (buf, size(buf), "x"); // glCallLists (GLsizei(strlen (buf)), GL_UNSIGNED_BYTE, buf); MyOpenGLText (buf); glRasterPos3d (0.0f, len, 0.0f); snprintf (buf, size(buf), "y"); // glCallLists (GLsizei(strlen (buf)), GL_UNSIGNED_BYTE, buf); MyOpenGLText (buf); glRasterPos3d (0.0f, 0.0f, len); snprintf (buf, size(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 :: DrawMarker() { static constexpr GLubyte cross[] = { 0xc6, 0xee, 0x7c, 0x38, 0x7c, 0xee, 0xc6 }; if(!marker) return; glColor3d (0, 0, 1); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glDisable (GL_COLOR_MATERIAL); glDisable (GL_LIGHTING); glDisable (GL_CLIP_PLANE0); auto & p = *marker; glRasterPos3d (p[0], p[1], p[2]); glBitmap (7, 7, 3, 3, 0, 0, &cross[0]); } 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] = { GLfloat(1 - backcolor), GLfloat(1 - backcolor), GLfloat(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); } void VisualSceneSurfaceMeshing::MouseMove(int oldx, int oldy, int newx, int newy, char mode) { double fac = 0.001; if(mode == 'M') { shiftx += fac * (newx - oldx); shifty += fac * (oldy - newy); return; } else if(mode == 'Z') { scalex *= (1 - fac * (newy - oldy)); scaley *= (1 - fac * (newy - oldy)); return; } VisualScene::MouseMove(oldx, oldy, newx, newy, mode); } std::vector Snapshot( int w, int h ) { // save current settings GLint viewport[4]; glGetIntegerv (GL_VIEWPORT, viewport); glMatrixMode (GL_PROJECTION); glPushMatrix(); glLoadIdentity(); double pnear = 0.1; double pfar = 10; gluPerspective(20.0f, double(w) / h, pnear, pfar); glMatrixMode (GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); glViewport(0,0,w,h); GLuint fb = 0; glGenFramebuffers(1, &fb); glBindFramebuffer(GL_FRAMEBUFFER, fb); // create, reserve and attach color and depth renderbuffer GLuint rbs[2]; glGenRenderbuffers(2, rbs); glBindRenderbuffer(GL_RENDERBUFFER, rbs[0]); glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, w, h); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbs[0]); glBindRenderbuffer(GL_RENDERBUFFER, rbs[1]); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, w, h); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rbs[1]); // check if framebuffer status is complete if(int fbstatus; (fbstatus = glCheckFramebufferStatus(GL_FRAMEBUFFER)) != GL_FRAMEBUFFER_COMPLETE) cerr << "no frame buffer " << fbstatus << endl; visual_scene->DrawScene(); glFinish(); std::vector buffer(w*h*3); glPixelStorei(GL_UNPACK_ALIGNMENT,1); glPixelStorei(GL_PACK_ALIGNMENT,1); glReadPixels (0, 0, w, h, GL_RGB, GL_UNSIGNED_BYTE, &buffer[0]); glDeleteRenderbuffers(2, rbs); glDeleteFramebuffers(1, &fb); glBindFramebuffer(GL_FRAMEBUFFER, 0); // restore previous settings glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); glMatrixMode (GL_PROJECTION); glPopMatrix(); glMatrixMode (GL_MODELVIEW); glPopMatrix(); return buffer; } VisualSceneSurfaceMeshing :: VisualSceneSurfaceMeshing () : VisualScene() { ; } VisualSceneSurfaceMeshing :: ~VisualSceneSurfaceMeshing () { ; } void VisualSceneSurfaceMeshing :: DrawScene () { // int i, j, k; if(!locpointsptr) return; auto& locpoints = *locpointsptr; auto& loclines = *loclinesptr; auto& plainpoints = *plainpointsptr; 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(); glMultMatrixd (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 (int 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 (int 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); glBegin (GL_LINES); for (int 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) { const auto& p1 = plainpoints.Get(pi1); const auto& p2 = plainpoints.Get(pi2); glBegin (GL_LINES); glVertex3f (scalex * p1[0] + shiftx, scaley * p1[1] + shifty, -5); glVertex3f (scalex * p2[0] + shiftx, scaley * p2[1] + shifty, -5); glEnd(); } } glEnd (); glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_colp); glBegin (GL_POINTS); for (int i = 1; i <= plainpoints.Size(); i++) { const auto& p = plainpoints.Get(i); glVertex3f (scalex * p[0] + shiftx, scaley * p[1] + shifty, -5); } glEnd(); glDisable (GL_POLYGON_OFFSET_FILL); glPopMatrix(); DrawCoordinateCross (); DrawNetgenLogo (); glFinish(); } void VisualSceneSurfaceMeshing :: BuildScene (int zoomall) { } VisualSceneSurfaceMeshing vssurfacemeshing; void Impl_Render (bool blocking) { if (blocking && multithread.running) { multithread.redraw = 2; while (multithread.redraw == 2) ; } else multithread.redraw = 1; } void Impl_UpdateVisSurfaceMeshData(int oldnl, shared_ptr>> locpointsptr, shared_ptr> loclinesptr, shared_ptr>> plainpointsptr) { vssurfacemeshing.oldnl = oldnl; if(locpointsptr) vssurfacemeshing.locpointsptr = locpointsptr; if(loclinesptr) vssurfacemeshing.loclinesptr = loclinesptr; if(plainpointsptr) vssurfacemeshing.plainpointsptr = plainpointsptr; } static bool set_function_pointers = []() { Ptr_Render = Impl_Render; Ptr_UpdateVisSurfaceMeshData = Impl_UpdateVisSurfaceMeshData; return true; }(); #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); if( glXIsDirect ( dpy, ctx ) ) cout << "WARNING: direct rendering enabled; this might break mpi-parallel netgen (especially if X-forwarding is used! (to disable, change -indirect to true in ng/drawing.tcl)" << endl; /* 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); netgen::GetVSSolution().Broadcast (); } #endif } ================================================ FILE: libsrc/visualization/mvdraw.hpp ================================================ #ifndef FILE_MVDRAW #define FILE_MVDRAW #include "meshing/global.hpp" namespace netgen { class VisualScene { protected: static NGGUI_API Point3d center; static NGGUI_API double rad; static double lookatmat[16]; static double transmat[16]; static double rotmat[16]; static double centermat[16]; static NGGUI_API double transformationmat[16]; GLdouble clipplane[4]; int changeval; static NGGUI_API GLdouble backcolor; static int NGGUI_API selface; static int selelement; static PointIndex NGGUI_API selpoint; static PointIndex selpoint2; static int locpi; static int NGGUI_API seledge; static optional> marker; static int subdivision_timestamp; static int subdivisions; public: static int viewport[4]; static GLuint coltexname; static int ntexcols; int invcolor; public: NGGUI_API VisualScene (); NGGUI_API virtual ~VisualScene(); NGGUI_API virtual void BuildScene (int zoomall = 0); NGGUI_API virtual void DrawScene (); NGGUI_API void CalcTransformationMatrices(); NGGUI_API void StandardRotation (const char * dir); NGGUI_API void ArbitraryRotation (const NgArray & alpha, const NgArray & vec); NGGUI_API void ArbitraryRotation (const double alpha, const Vec3d & vec); NGGUI_API virtual void MouseMove(int oldx, int oldy, int newx, int newy, char mode); NGGUI_API void LookAt (const Point<3> & cam, const Point<3> & obj, const Point<3> & camup); NGGUI_API void SetClippingPlane (); NGGUI_API virtual void MouseDblClick (int px, int py); NGGUI_API void SetLight (); static void SetBackGroundColor (double col) { backcolor = col; } NGGUI_API void CreateTexture (int ncols, int linear, double alpha, int typ); NGGUI_API void DrawColorBar (double minval, double maxval, int logscale = 0, bool linear = 1, string format="%8.3e", string unit=""); NGGUI_API void DrawTitle (string title); NGGUI_API void DrawCoordinateCross (); NGGUI_API void DrawMarker(); NGGUI_API void DrawNetgenLogo (); NGGUI_API void SetOpenGlColor(double val, double valmin, double valmax, int logscale = 0); #ifdef PARALLELGL NGGUI_API void InitParallelGL (); NGGUI_API void Broadcast (); #endif }; NGGUI_API extern void MyOpenGLText (const char * text); NGGUI_API extern int MyOpenGLTextWidth (); NGGUI_API extern void Set_OpenGLText_Callback ( void (*fun) (const char * text), int width ); NGGUI_API extern VisualScene visual_scene_cross; NGGUI_API extern VisualScene *visual_scene; NGGUI_API extern void MyOpenGLLines (FlatArray> points); class VisualSceneSurfaceMeshing : public VisualScene { double scalex = 1., scaley = 1., shiftx = 0., shifty = 0.; public: shared_ptr>> locpointsptr; shared_ptr> loclinesptr; shared_ptr>> plainpointsptr; int oldnl; bool clearptr; VisualSceneSurfaceMeshing (); virtual ~VisualSceneSurfaceMeshing (); void BuildScene (int zoomall = 0) override; void DrawScene () override; NGGUI_API void MouseMove(int oldx, int oldy, int newx, int newy, char mode) override; }; NGGUI_API extern VisualSceneSurfaceMeshing vssurfacemeshing; struct VisualSelect { unsigned framebuffer = 0; unsigned render_buffers[2]; unsigned width = 0; unsigned height = 0; unsigned x = 0; unsigned y = 0; int list = 0; int list_timestamp = -1; double projmat[16]; double transformationmat[16]; // todo: set double clipplane[4]; // todo: set int viewport[4]; int selelement = -1; Point<3> center; // todo: set double rad = 0.0; // todo: set bool enable_clipping_plane = true; // todo: set bool Unproject(int px, int py, Point<3> &p) { auto hy = viewport[3] - py; float pz; glReadPixels (px, hy, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &pz); if(pz<1 && pz>0) gluUnProject(px, hy, pz, transformationmat, projmat, viewport, &p[0], &p[1], &p[2]); return pz<1 && pz>0; } ngcore::IVec<2> Project(Point<3> p) { Point<3> pwin; gluProject(p[0], p[1], p[2], transformationmat, projmat, viewport, &pwin[0], &pwin[1], &pwin[2]); return ngcore::IVec<2>(pwin[0]+0.5, viewport[3]-pwin[1]+0.5); } bool SelectSurfaceElement (shared_ptr mesh, int px, int py, Point<3> &p, bool select_on_clipping_plane); }; class VisualSceneMesh : public VisualScene { int filledlist = 0; int linelist = 0; int edgelist = 0; int pointnumberlist = 0; int tetlist = 0; int prismlist = 0; int pyramidlist = 0; int hexlist = 0; int badellist = 0; int identifiedlist = 0; int domainsurflist = 0; int vstimestamp = -1; int filledtimestamp = -1; int linetimestamp = -1; int edgetimestamp = -1; // int pointnumbertimestamp = -1; int tettimestamp = -1; int prismtimestamp = -1; int pyramidtimestamp = -1; int hextimestamp = -1; // int badeltimestamp = -1; // int identifiedtimestamp = -1; // int domainsurftimestamp = -1; struct { unsigned texture = -1; int width = 0; int height = 0; int size = 0; } colors; VisualSelect select; #ifdef PARALLELGL NgArray par_linelists; NgArray par_filledlists; #endif MouseEventHandler * user_me_handler; NgLock *lock; // int selface, selelement; // int selpoint, selpoint2, locpi; // int seledge; double minh, maxh; // for meshsize coloring mutable shared_ptr mesh; public: NGGUI_API VisualSceneMesh (); NGGUI_API virtual ~VisualSceneMesh (); NGGUI_API virtual void BuildScene (int zoomall = 0); NGGUI_API virtual void DrawScene (); NGGUI_API virtual void MouseDblClick (int px, int py); NGGUI_API void SetMesh (shared_ptr m) { mesh = m; } NGGUI_API shared_ptr GetMesh () const { return mesh; } void SetMouseEventHandler (MouseEventHandler * handler) { user_me_handler = handler; } NGGUI_API int SelectedFace () const { return selface; } NGGUI_API void SetSelectedFace (int asf); // { selface = asf; selecttimestamp = GetTimeStamp(); } NGGUI_API int SelectedEdge () const { return seledge; } NGGUI_API int SelectedElement () const { return selelement; } NGGUI_API int SelectedPoint () const { return selpoint; } void BuildFilledList (bool select); void BuildColorTexture(); void SelectCenter(int zoomall); // private: void BuildLineList(); void BuildEdgeList(); void BuildPointNumberList(); void BuildTetList(const BitArray & shownode); void BuildPrismList(const BitArray & shownode); void BuildPyramidList(const BitArray & shownode); void BuildHexList(const BitArray & shownode); void BuildBadelList(); void BuildIdentifiedList(); void BuildDomainSurfList(); bool SelectSurfaceElement (int px, int py, Point<3> &p, bool select_on_clipping_plane); bool Unproject(int px, int py, Point<3> &p); ngcore::IVec<2> Project(Point<3> p); }; NGGUI_API extern VisualSceneMesh vsmesh; class NGGUI_API 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 double * transformationmat, const Point3d & center, const double rad, const int displaylist, int & selelement, int & selface, int & seledge, PointIndex & selpoint, PointIndex & selpoint2, int & locpi); void RenderSurfaceElements (shared_ptr mesh, int subdivisions, std::function face_init, std::function sel_init ); NGGUI_API std::vector Snapshot( int w, int h ); } #endif ================================================ FILE: libsrc/visualization/vispar.hpp ================================================ #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; */ class Clipping { public: Vec3d normal; double dist; double dist2; int enable; int timestamp; bool operator== (Clipping & clip2) { return (normal == clip2.normal) && (dist == clip2.dist) && // (dist2 == clip2.dist2) && (enable == clip2.enable); } }; Clipping clipping; 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 drawsurfaceelementnumbers; int drawsegmentnumbers; 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; PointIndex 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(); }; NGGUI_API extern VisualizationParameters vispar; } #endif ================================================ FILE: libsrc/visualization/visual.hpp ================================================ #ifndef FILE_VISUAL #define FILE_VISUAL /* *************************************************************************/ /* File: visual.hpp */ /* Author: Joachim Schoeberl */ /* Date: 02. Dec. 01 */ /* *************************************************************************/ /* Visualization */ #include "visual_api.hpp" #include "../include/incopengl.hpp" #include "../meshing/visual_interface.hpp" #include "../meshing/soldata.hpp" #include "vispar.hpp" #include "mvdraw.hpp" #include #include "vssolution.hpp" #include "meshdoc.hpp" #endif ================================================ FILE: libsrc/visualization/visual_api.hpp ================================================ #ifndef VISUAL_API_HPP_INCLUDED #define VISUAL_API_HPP_INCLUDED #ifdef nggui_EXPORTS #define NGGUI_API NGCORE_API_EXPORT #else #define NGGUI_API NGCORE_API_IMPORT #endif #endif // VISUAL_API_HPP_INCLUDED ================================================ FILE: libsrc/visualization/visualpkg.cpp ================================================ #include // #include #include #include #include #include #include // #include #include #include namespace netgen { /* */ int Ng_Vis_Set (ClientData clientData, Tcl_Interp * interp, int argc, tcl_const char *argv[]) { auto & vssolution = netgen::GetVSSolution(); 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.c_str()) == size_t(pointpos-1)) && (strncmp (vssolution.soldata[i]->name.c_str(), scalname, pointpos-1) == 0) ) { vssolution.SetScalfunction(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] = ':'; snprintf (newscalname+pointpos, sizeof(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.c_str(), vecname) == 0) vssolution.SetVecfunction(i); if (strcmp (vssolution.soldata[i]->name.c_str(), fieldlines_vecname) == 0) vssolution.fieldlines_vecfunction = i; } 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 available 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; auto & vssolution = netgen::GetVSSolution(); 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.c_str(), argv[2]) == 0) { cout << "found soldata " << i << endl; } } if (strcmp (argv[1], "getnfieldnames") == 0) { snprintf (buf, size(buf), "%d", vssolution.GetNSolData()); } if (strcmp (argv[1], "getfieldname") == 0) { snprintf (buf, size(buf), "%s", vssolution.GetSolData(atoi(argv[2])-1)->name.c_str()); } if (strcmp (argv[1], "iscomplex") == 0) { snprintf (buf, size(buf), "%d", vssolution.GetSolData(atoi(argv[2])-1)->iscomplex); } if (strcmp (argv[1], "getfieldcomponents") == 0) { snprintf (buf, size(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.c_str()); 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) { snprintf (buf, size(buf), "1"); } if (strcmp (argv[1], "getdimension") == 0) { auto mesh = vssolution.GetMesh(); snprintf (buf, size(buf), "%d", mesh->GetDimension()); } } Tcl_SetResult (interp, buf, TCL_STATIC); return TCL_OK; } VisualSceneMeshDoctor vsmeshdoc; DLL_HEADER extern shared_ptr 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; } 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; } } ================================================ FILE: libsrc/visualization/vsfieldlines.cpp ================================================ #ifndef NOTCL #include #include #include #include #include #include #include #include namespace netgen { // extern shared_ptr mesh; void VisualSceneSolution :: BuildFieldLinesFromBox(Array> & startpoints) { shared_ptr mesh = GetMesh(); if (!mesh) return; 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++) { Point<3> 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> & startpoints) { shared_ptr mesh = GetMesh(); if (!mesh) return; for (int i = 1; i <= startpoints.Size(); i++) { double s = double (rand()) / RAND_MAX; Point<3> 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> & startpoints) { shared_ptr mesh = GetMesh(); if (!mesh) return; 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][0]; (*infile) >> startpoints[numpoints][1]; (*infile) >> startpoints[numpoints][2]; numpoints++; } else if (keyword == "line" || keyword == "box") { for(int i=0; i<6; i++) (*infile) >> fieldlines_startarea_parameter[i]; (*infile) >> iparam; Array> auxpoints(iparam); if (keyword == "box") BuildFieldLinesFromBox(auxpoints); else if (keyword == "line") BuildFieldLinesFromLine(auxpoints); for(int i=0; i> & startpoints) { shared_ptr mesh = GetMesh(); if (!mesh) return; Array 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; iPoint(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)[elements_2d[i]]; int numtri = (elem.GetNV() == 3) ? 1 : 2; for(int tri = 0; startpointsp < startpoints.Size() && triPoint(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 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 () { shared_ptr mesh = GetMesh(); if (!mesh) return; 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; double phaser=1.0; double phasei=0.0; std::function &)> eval_func = [&](int elnr, const double * lami, Vec<3> & vec) { double values[6] = {0., 0., 0., 0., 0., 0.}; bool drawelem; auto mesh = GetMesh(); if (mesh->GetDimension()==3) drawelem = GetValues (vsol, elnr, lami[0], lami[1], lami[2], values); else drawelem = GetSurfValues (vsol, elnr, -1, lami[0], lami[1], values); Vec3d v; RealVec3d (values, v, vsol->iscomplex, phaser, phasei); vec = v; return drawelem; }; FieldLineCalc linecalc(*mesh, eval_func, 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> 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; phaser = cos(phi); phasei = sin(phi); linecalc.GenerateFieldLines(startpoints,num_fieldlines / num_fieldlineslists+1); auto & pstart = linecalc.GetPStart(); auto & pend = linecalc.GetPEnd(); auto & values = linecalc.GetValues(); auto nlines = values.Size(); glNewList(fieldlineslist+ln, GL_COMPILE); SetTextureMode (usetexture); for(auto i : Range(nlines)) { SetOpenGlColor (values[i]); DrawCylinder (pstart[i], pend[i], fieldlines_relthickness); } glEndList (); } } } #endif // NOTCL ================================================ FILE: libsrc/visualization/vsmesh.cpp ================================================ #include #include #include #include "../meshing/global.hpp" // #include #ifdef STLGEOM #include #endif // #include #include namespace netgen { // extern shared_ptr mesh; extern NetgenGeometry * ng_geometry; VisualSceneMesh vsmesh; VisualSceneMesh :: VisualSceneMesh () : VisualScene() { selface = -1; selelement = -1; locpi = -2; selpoint = PointIndex::INVALID; selpoint2 = PointIndex::INVALID; seledge = -1; minh = 0.0; maxh = 0.0; user_me_handler = NULL; mesh = nullptr; } VisualSceneMesh :: ~VisualSceneMesh () { ; } void VisualSceneMesh :: DrawScene () { try { shared_ptr mesh = GetMesh(); if (!mesh) { VisualScene::DrawScene(); return; } lock = NULL; static int timer = NgProfiler::CreateTimer ("VSMesh::DrawScene"); NgProfiler::RegionTimer reg (timer); BuildScene(); glEnable(GL_DEPTH_TEST); 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(); glMultMatrixd (transformationmat); GLdouble projmat[16]; // brauchen wir das ? glGetDoublev (GL_PROJECTION_MATRIX, projmat); glEnable (GL_BLEND); glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 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) { 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); BitArray shownode(mesh->GetNP()+1); if (vispar.clipping.enable) { shownode.Clear(); for (PointIndex pi : mesh->Points().Range()) { Point<3> p = (*mesh)[pi]; double val = p[0] * clipplane[0] + p[1] * clipplane[1] + p[2] * clipplane[2] + clipplane[3]; if (val > 0) shownode.SetBit (pi); } } else shownode.Set(); if (vispar.drawprisms) { BuildPrismList (shownode); glCallList (prismlist); } if (vispar.drawpyramids) { BuildPyramidList (shownode); glCallList (pyramidlist); } if (vispar.drawhexes) { BuildHexList (shownode); glCallList (hexlist); } if (vispar.drawtets) { BuildTetList (shownode); 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); glDisable(GL_BLEND); if (vispar.drawoutline) { glPolygonOffset (1, 1); glEnable (GL_POLYGON_OFFSET_LINE); BuildLineList (); #ifdef PARALLELGL if (ntasks > 1 && vispar.drawtetsdomain > 0 && vispar.drawtetsdomain < ntasks) 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.drawsegmentnumbers || vispar.drawsurfaceelementnumbers || vispar.drawelementnumbers) glCallList (pointnumberlist); glPopName(); if (vispar.drawedges) { BuildEdgeList(); glCallList (edgelist); } DrawMarker(); glDisable(GL_CLIP_PLANE0); glPopMatrix(); if (vispar.colormeshsize) DrawColorBar (minh, maxh, 1); DrawCoordinateCross (); DrawNetgenLogo (); if (lock) { lock -> UnLock(); delete lock; lock = NULL; } glFinish(); } catch (const bad_weak_ptr & e) { // cout << "don't have a mesh to visualize" << endl; VisualScene::DrawScene(); } } void VisualSceneMesh :: SelectCenter (int zoomall) { shared_ptr mesh = GetMesh(); Point3d pmin, pmax; mesh->GetBox (pmin, pmax, -1); // works in NGSolve, mesh view if (mesh->GetDimension() == 2) mesh->GetBox (pmin, pmax); else // otherwise strange zooms during 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-IndexBASE() >= 1 && zoomall==2) center = mesh->Point (selpoint); else if (marker && zoomall==2) center = *marker; else if (vispar.centerpoint-IndexBASE() >= 0 && zoomall==2) center = mesh->Point (vispar.centerpoint); else center = Center (pmin, pmax); double oldrad = rad; rad = 0.5 * Dist (pmin, pmax); if(rad == 0) rad = 1e-6; if (rad > 1.2 * oldrad || mesh->GetMajorTimeStamp() > vstimestamp || zoomall) { CalcTransformationMatrices(); } glEnable (GL_NORMALIZE); } void VisualSceneMesh :: BuildScene (int zoomall) { auto mesh = GetGlobalMesh(); if (!mesh) { PrintMessage (3, "vsmesh::buildscene: don't have a mesh to visualize"); VisualScene::BuildScene (zoomall); return; } if (!lock) { lock = new NgLock (mesh->Mutex()); lock -> Lock(); } static int timer = NgProfiler::CreateTimer ("VSMesh::BuildScene"); NgProfiler::RegionTimer reg (timer); NgArray faces; int meshtimestamp = mesh->GetTimeStamp(); if (meshtimestamp > vstimestamp || zoomall) SelectCenter(zoomall); 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.drawsegmentnumbers || vispar.drawsurfaceelementnumbers || vispar.drawelementnumbers) { // glEnable (GL_COLOR_MATERIAL); GLfloat textcol[3] = { float(1-backcolor), float(1-backcolor), float(1-backcolor) }; glColor3fv (textcol); glNormal3d (0, 0, 1); glPushAttrib (GL_LIST_BIT); // glListBase (fontbase); char buf[30]; if (vispar.drawpointnumbers) for (PointIndex pi : mesh->Points().Range()) { const Point3d & p = mesh->Point(pi); glRasterPos3d (p.X(), p.Y(), p.Z()); snprintf (buf, size(buf), "%d", int(pi)); // 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()); snprintf (buf, size(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); auto [v1,v2] = top.GetEdgeVertices(i-1); 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()); snprintf (buf, size(buf), "%d", i); // glCallLists (strlen (buf), GL_UNSIGNED_BYTE, buf); MyOpenGLText (buf); } } if (vispar.drawsegmentnumbers) { for (auto si : Range(mesh->LineSegments())) { const auto& seg = (*mesh)[si]; Point<3> c = Center((*mesh)[seg[0]], (*mesh)[seg[1]]); glRasterPos3d (c[0], c[1], c[2]); snprintf (buf, size(buf), "%d", int(si)); MyOpenGLText (buf); } } if (vispar.drawfacenumbers) { const MeshTopology & top = mesh->GetTopology(); NgArray 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.Size() == 3) { 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()); snprintf (buf, size(buf), "%d", i); // glCallLists (strlen (buf), GL_UNSIGNED_BYTE, buf); MyOpenGLText (buf); } } if (vispar.drawsurfaceelementnumbers) { for (auto sei : Range(mesh->SurfaceElements())) { const auto & sel = (*mesh)[sei]; Point<3> c; if(sel.GetNV() == 3) c = Center((*mesh)[sel[0]], (*mesh)[sel[1]], (*mesh)[sel[2]]); else c = Center((*mesh)[sel[0]], (*mesh)[sel[1]], (*mesh)[sel[2]], (*mesh)[sel[3]]); glRasterPos3d (c[0], c[1], c[2]); snprintf (buf, size(buf), "%d", int(sei)); MyOpenGLText (buf); } } if (vispar.drawelementnumbers) { NgArray v; // for (int i = 1; i <= mesh->GetNE(); i++) for (ElementIndex ei : Range(mesh->VolumeElements())) { // const ELEMENTTYPE & eltype = mesh->ElementType(i); NgArray pnums; Point3d p; const Element & el = mesh->VolumeElement (ei); if ( ! el.PNum(5)) // eltype == TET ) { pnums.SetSize(4); for( int j = 0; j < pnums.Size(); j++) pnums[j] = mesh->VolumeElement(ei).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(ei).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(ei).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(ei).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()); snprintf (buf, size(buf), "%d", ei-IndexBASE(ei)); // 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++) for (ElementIndex ei : Range(mesh->VolumeElements())) { if (mesh->VolumeElement(ei).Flags().badel || mesh->VolumeElement(ei).Flags().illegal || (ei-IndexBASE(ei) == vispar.drawelement)) { // copy to be thread-safe Element el = mesh->VolumeElement (ei); 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 (ElementIndex ei : mesh->VolumeElements().Range()) { if ((*mesh)[ei].Flags().badel) { // copy to be thread-safe Element el = (*mesh)[ei]; 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 (ElementIndex ei : Range(mesh->VolumeElements())) { Element el = mesh->VolumeElement (ei); int hascp = 0; for (int j = 1; j <= el.GetNP(); j++) if (el.PNum(j) == vispar.centerpoint) hascp = 1; if (hascp) { (*testout) << "draw el " << ei << " : "; 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 (SurfaceElementIndex sei : mesh->SurfaceElements().Range()) { Element2d el = (*mesh)[sei]; // copy to be thread-safe if (!el.BadElement()) continue; if (el.IsDeleted()) continue; bool drawel = true; for (int j = 1; j <= el.GetNP(); j++) if (!el.PNum(j).IsValid()) drawel = false; 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); glEnable (GL_COLOR_MATERIAL); glDisable (GL_LIGHTING); if (mesh -> HasIdentifications() ) { { auto & idpts = mesh->GetIdentifications().GetIdentifiedPoints(); for (auto [hash, val] : idpts) { auto [hash_pts, hash_nr] = hash; auto [pi1, pi2] = hash_pts; // val = pts[2]; Point<3> p1 = mesh->Point(pi1); Point<3> p2 = mesh->Point(pi2); Point<3> c = Center(p1, p2); if (vispar.shrink < 1) { p1 = c + vispar.shrink * (p1 - c); p2 = c + vispar.shrink * (p2 - c); } glColor3fv (identifiedcol); glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, identifiedcol); glBegin (GL_LINES); glVertex3dv(p1); glVertex3dv(p2); glEnd(); } } } glDisable (GL_COLOR_MATERIAL); glEnable (GL_LIGHTING); glEndList (); } if (lock) { lock -> UnLock(); delete lock; lock = NULL; } vstimestamp = meshtimestamp; } void VisualSceneMesh :: BuildColorTexture () { shared_ptr mesh = GetMesh(); if(colors.texture == -1) glGenTextures(1, &colors.texture); // build color texture glBindTexture(GL_TEXTURE_2D, colors.texture); Array data; for(auto fdi : Range(1, mesh->GetNFD()+1)) { auto c = mesh->GetFaceDescriptor(fdi).SurfColour(); ArrayMem cf{float(c[0]), float(c[1]), float(c[2]), float(c[3])}; if(fdi==selface) cf = {1.0f, 0.0f, 0.0f, 1.0f}; data.Append(cf); } int n = data.Size()/4; colors.width = max2(1,min2(n, 1024)); colors.height = (n+colors.width-1)/colors.width; for([[maybe_unused]] auto i: Range(n, colors.width*colors.height)) data.Append({0.0f, 0.0f, 0.0f, 0.0f}); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, colors.width, colors.height, 0, GL_RGBA, GL_FLOAT, data.Data()); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); } void RenderSurfaceElements (shared_ptr mesh, int subdivisions, std::function face_init, std::function sel_init ) { CurvedElements & curv = mesh->GetCurvedElements(); int hoplotn = 1 << subdivisions; Array seia; for (int faceindex = 1; faceindex <= mesh->GetNFD(); faceindex++) { if(!face_init(faceindex-1)) continue; mesh->GetSurfaceElementsOfFace (faceindex, seia); static Point<3> xa[129]; static Vec<3> na[129]; 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 (!sel_init(sei)) continue; switch (el.GetType()) { case TRIG: { if (curv.IsHighOrder()) // && curv.IsSurfaceElementCurved(sei)) { if (hoplotn > 128) hoplotn = 128; 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++) 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())); } } } } void VisualSceneMesh :: BuildFilledList (bool build_select) { shared_ptr mesh = GetMesh(); static int timer = NgProfiler::CreateTimer ("Mesh::BuildFilledList"); NgProfiler::RegionTimer reg (timer); auto & list = build_select ? select.list : filledlist; auto & timestamp = build_select ? select.list_timestamp : filledtimestamp; if (list && timestamp > max(mesh->GetTimeStamp(), subdivision_timestamp)) return; #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 (list) glDeleteLists (list, 1); list = glGenLists (1); glNewList (list, GL_COMPILE); for ( int dest = 1; dest < ntasks; dest++ ) glCallList (par_filledlists[dest]); glEndList(); timestamp = NextTimeStamp(); return; } #endif if (!lock) { lock = new NgLock (mesh->Mutex()); lock -> Lock(); } timestamp = NextTimeStamp(); if(!build_select && !vispar.colormeshsize) BuildColorTexture(); if (list) glDeleteLists (list, 1); list = glGenLists (1); glNewList (list, GL_COMPILE); glBindTexture(GL_TEXTURE_2D, colors.texture); #ifdef STLGEOM STLGeometry * stlgeometry = dynamic_cast (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 if (build_select) { glDisable(GL_TEXTURE_1D); glDisable(GL_TEXTURE_2D); glDisable(GL_FOG); glDisable(GL_LIGHTING); glDisable (GL_COLOR_MATERIAL); } else { glDisable(GL_TEXTURE_1D); glEnable(GL_TEXTURE_2D); glEnable (GL_COLOR_MATERIAL); glBindTexture(GL_TEXTURE_2D, colors.texture); } // GLfloat matcol[] = { 0, 1, 0, 1 }; // GLfloat matcolsel[] = { 1, 0, 0, 1 }; GLint rendermode; glGetIntegerv (GL_RENDER_MODE, &rendermode); auto face_init = [&](int i) { if(!build_select && !vispar.colormeshsize) { float x = (0.5+i%colors.width)/colors.width; float y = (0.5+i/colors.width)/colors.height; glTexCoord2f(x,y); } return true; }; CurvedElements & curv = mesh->GetCurvedElements(); auto sel_init = [&](SurfaceElementIndex sei) { if (build_select) { GLushort r,g,b; r = (sei+1) % (1<<16); g = (sei+1) >> 16; b = 0; glColor3us(r,g,b); } if (vispar.colormeshsize) { auto & el = (*mesh)[sei]; if(el.GetType() == TRIG && !curv.IsHighOrder()) { if (vispar.colormeshsize) SetOpenGlColor (locms(el[0]-1), minh, maxh, 0); } } return true; }; RenderSurfaceElements(mesh, subdivisions, face_init, sel_init); glLoadName (0); glBindTexture(GL_TEXTURE_2D, 0); glEndList (); #ifdef PARALLELGL glFinish(); if (id > 0) MyMPI_Send (list, 0, MPI_TAG_VIS); #endif if(lock) { lock->UnLock(); delete lock; lock = NULL; } } void VisualSceneMesh :: BuildLineList() { shared_ptr mesh = GetMesh(); if (linetimestamp > max(mesh->GetTimeStamp (), subdivision_timestamp)) return; 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 (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 << 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() { shared_ptr mesh = GetMesh(); if (!lock) { lock = new NgLock (mesh->Mutex()); lock -> Lock(); } if (edgetimestamp > max(mesh->GetTimeStamp(), subdivision_timestamp) && vispar.drawtetsdomain == 0 && 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); /* #ifdef PARALLEL if (ntasks > 1 && vispar.drawtetsdomain && // (vispar.drawtetsdomain != seg.GetPartition())) continue; (vispar.drawtetsdomain != mesh->seg_partition[i-1]) continue; #endif */ 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 << 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(const BitArray & shownode) { shared_ptr mesh = GetMesh(); if (tettimestamp > mesh->GetTimeStamp () && tettimestamp > vispar.clipping.timestamp ) 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); NgArray faces; 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 } */ }; CurvedElements & curv = mesh->GetCurvedElements(); if (!curv.IsHighOrder()) glShadeModel (GL_FLAT); else glShadeModel (GL_SMOOTH); int hoplotn = max (2, 1 << subdivisions); for (ElementIndex ei = 0; ei < mesh->GetNE(); ei++) { if (vispar.drawtetsdomain > 0) { /* int tetid = vispar.drawmetispartition ? (*mesh)[ei].GetPartition() : (*mesh)[ei].GetIndex(); */ int tetid = (*mesh)[ei].GetIndex(); if (vispar.drawtetsdomain != tetid) continue; } const Element & el = (*mesh)[ei]; if ((el.GetType() == TET || el.GetType() == TET10) && !el.IsDeleted()) { bool visible = true; for (auto pi: el.PNums()) if (!shownode[pi]) visible = false; if(!visible) continue; int ind = el.GetIndex() % 4; // if (vispar.drawmetispartition && el.GetPartition()!=-1) // ind = el.GetPartition() % 4; 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(); NgArray > ploc ( (order+1)*(order+1) ); NgArray > 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; // Philippose - 16/02/2010 // Add Mesh size based coloring of // meshes also for the volume elements if(vispar.colormeshsize) { glBegin (GL_TRIANGLE_STRIP); 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]); glEnd(); } else // Do not color mesh based on mesh size { GLubyte ind[4][3] = { { 0,1,2 }, { 3,1,0 }, { 1,3,2 }, { 2,3,0 } }; glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(3, GL_DOUBLE, 0, &pts[0](0)); for (int j = 0; j < 4; j++) { glNormal3dv (Cross (pts[ind[j][1]]-pts[ind[j][0]], pts[ind[j][2]]-pts[ind[j][0]])); glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_BYTE, &ind[j][0]); } glDisableClientState(GL_VERTEX_ARRAY); /* glBegin (GL_TRIANGLE_STRIP); 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(const BitArray & shownode) { shared_ptr mesh = GetMesh(); if (prismtimestamp > mesh->GetTimeStamp () && prismtimestamp > vispar.clipping.timestamp ) 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); NgArray faces; glDisable (GL_COLOR_MATERIAL); 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()) { bool visible = true; for (auto pi: el.PNums()) if (!shownode[pi]) visible = false; if(!visible) continue; 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 = 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 << 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(const BitArray & shownode) { shared_ptr mesh = GetMesh(); if (hextimestamp > mesh->GetTimeStamp () && hextimestamp > vispar.clipping.timestamp ) 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); glDisable (GL_COLOR_MATERIAL); glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, hexcol); NgArray 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()) { bool visible = true; for (auto pi: el.PNums()) if (!shownode[pi]) visible = false; if(!visible) continue; 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 = 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(); } } } static float hex7col[] = { 1.0f, 0.65f, 0.0f, 1.0f }; glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, hex7col); for (ElementIndex ei = 0; ei < mesh->GetNE(); ei++) { const Element & el = (*mesh)[ei]; if (el.GetType() == HEX7 && !el.IsDeleted()) { /* CurvedElements & curv = mesh->GetCurvedElements(); if (curv.IsHighOrder()) { const ELEMENT_FACE * faces = MeshTopology :: GetFaces1 (HEX); const Point3d * vertices = MeshTopology :: GetVertices (HEX); Point<3> grid[11][11]; Point<3> fpts[4]; int order = 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 <= 7; j++) { Point3d p = mesh->Point(el.PNum(j)); c.X() += p.X(); c.Y() += p.Y(); c.Z() += p.Z(); } c.X() /= 7; c.Y() /= 7; c.Z() /= 7; } 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(const BitArray & shownode) { shared_ptr mesh = GetMesh(); if (pyramidtimestamp > mesh->GetTimeStamp () && pyramidtimestamp > vispar.clipping.timestamp ) 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 }; glDisable (GL_COLOR_MATERIAL); glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, pyramidcol); glLineWidth (1.0f); NgArray faces; for (ElementIndex ei = 0; ei < mesh->GetNE(); ei++) { const Element & el = (*mesh)[ei]; if ((el.GetType() == PYRAMID || el.GetType() == PYRAMID13) && !el.IsDeleted()) { bool visible = true; for (auto pi: el.PNums()) if (!shownode[pi]) visible = false; if(!visible) continue; 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 = 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() { shared_ptr mesh = GetMesh(); 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 (); } bool VisualSelect :: SelectSurfaceElement (shared_ptr mesh, int px, int py, Point<3> &p, bool select_on_clipping_plane) { selelement = -1; // marker = nullopt; if(px != x || py != y) { x = px; y = py; } glGetIntegerv (GL_VIEWPORT, viewport); // GLenum err; if(framebuffer == 0 || viewport[2] != width || viewport[3] != height) { width = viewport[2]; height = viewport[3]; if(framebuffer != 0) { glDeleteRenderbuffers(2, render_buffers); glDeleteFramebuffers(1, &framebuffer); } glGenFramebuffers(1, &framebuffer); glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); // create, reserve and attach color and depth renderbuffer glGenRenderbuffers(2, render_buffers); glBindRenderbuffer(GL_RENDERBUFFER, render_buffers[0]); glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB16, width, height); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, render_buffers[0]); glBindRenderbuffer(GL_RENDERBUFFER, render_buffers[1]); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, render_buffers[1]); // check if framebuffer status is complete if(int fbstatus; (fbstatus = glCheckFramebufferStatus(GL_FRAMEBUFFER)) != GL_FRAMEBUFFER_COMPLETE) cerr << "no frame buffer " << fbstatus << endl; } glFlush(); glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); glEnable(GL_DEPTH_TEST); glClearColor(0, 0, 0, 1.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode (GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); glMultMatrixd (transformationmat); glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); auto hy = viewport[3] - py; if (enable_clipping_plane) { glClipPlane(GL_CLIP_PLANE0, clipplane); glEnable(GL_CLIP_PLANE0); 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; if(select_on_clipping_plane) { glColor3us(0,0,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 (list); glFinish(); glGetDoublev (GL_PROJECTION_MATRIX, projmat); auto found = Unproject(px, py, p); if(found) { // marker = p; GLushort numbers[3]; glReadPixels (px, hy, 1, 1, GL_RGB, GL_UNSIGNED_SHORT, numbers); selelement = numbers[0] + numbers[1]*(1<<16); } glBindFramebuffer(GL_FRAMEBUFFER, 0); glPopMatrix(); return found; } bool VisualSceneMesh :: Unproject(int px, int py, Point<3> &p) { return select.Unproject(px, py, p); } ngcore::IVec<2> VisualSceneMesh :: Project(Point<3> p) { Point<3> pwin; gluProject(p[0], p[1], p[2], transformationmat, select.projmat, select.viewport, &pwin[0], &pwin[1], &pwin[2]); return ngcore::IVec<2>(pwin[0]+0.5, select.viewport[3]-pwin[1]+0.5); } bool VisualSceneMesh :: SelectSurfaceElement(int px, int py, Point<3> &p, bool select_on_clipping_plane) { BuildFilledList(true); memcpy(select.transformationmat, transformationmat, sizeof(transformationmat)); memcpy(select.clipplane, clipplane, sizeof(clipplane)); select.center = center; select.rad = rad; select.enable_clipping_plane = vispar.clipping.enable; bool found = select.SelectSurfaceElement(GetMesh(), px, py, p, select_on_clipping_plane); selelement = select.selelement; return found; } void VisualSceneMesh :: MouseDblClick (int px, int py) { Point<3> p; bool found_point = SelectSurfaceElement(px, py, p, false); if(selelement>0) { const Element2d & sel = GetMesh()->SurfaceElement(selelement); SetSelectedFace(sel.GetIndex()); auto pi_nearest = sel[0]; double min_dist = 1e99; for(auto pi : sel.PNums()) if(Dist2(GetMesh()->Point(pi), p) < min_dist) { min_dist = Dist2(GetMesh()->Point(pi), p); pi_nearest = pi; } auto p_win = Project(GetMesh()->Point(pi_nearest)); if(abs(p_win[0]-px) < 5 && abs(p_win[1]-py) < 5) { marker = GetMesh()->Point(pi_nearest); selpoint = pi_nearest; cout << "select point " << pi_nearest << " at " << *marker << endl; } else { marker = p; cout << endl << "select element " << selelement << " on face " << sel.GetIndex(); // output face name auto mesh = GetMesh(); string name; if(mesh->GetDimension() == 3) name = mesh->GetFaceDescriptor(sel.GetIndex()).GetBCName(); else name = mesh->GetMaterial(sel.GetIndex()); if(name != "") cout << " with name " << name; cout << endl; if(mesh->GetDimension() == 3) { auto & fd = mesh->GetFaceDescriptor(sel.GetIndex()); auto domin = fd.DomainIn(); auto domout = fd.DomainOut(); string name_in = domin >0 ? mesh->GetMaterial(domin) : ""; string name_out = domout >0 ? mesh->GetMaterial(domout) : ""; cout << "\tadjacent domains " << domin << ": " << name_in << ", " << domout << ": " << name_out << endl; } cout << "\tpoint: " << p << endl;; cout << "\tnodes: "; for (int i = 1; i <= sel.GetNP(); i++) cout << sel.PNum(i) << " "; cout << endl; } } if(found_point && user_me_handler) { if (selelement != -1) user_me_handler -> DblClick (selelement-1, p[0], p[1], p[2]); } if(lock) { lock->UnLock(); delete lock; lock = NULL; } } void VisualSceneMesh :: SetSelectedFace (int asf) { if(selface != asf) { selface = asf; BuildColorTexture(); } } static bool dummy_init_var = [] () { on_set_global_mesh = [](shared_ptr mesh) { vsmesh.SetMesh(mesh); }; return true; }(); } #ifdef NG_PYTHON #include <../general/ngpython.hpp> #include "../include/nginterface.h" NGGUI_API void ExportMeshVis(py::module &m) { using namespace netgen; vispar.drawcolorbar = true; vispar.drawnetgenlogo = true; vispar.drawcoordinatecross = true; vispar.drawfilledtrigs = true; vispar.drawdomainsurf = true; vispar.drawhexes = true; vispar.drawtets = true; vispar.drawprisms = true; vispar.drawoutline = true; py::class_> (m, "VisualSceneMesh") .def("Draw", &VisualSceneMesh::DrawScene) ; m.def("VS", FunctionPointer ([](shared_ptr mesh) { auto vs = make_shared(); // vs->SetMesh(mesh); SetGlobalMesh (mesh); return vs; })); m.def("MouseMove", FunctionPointer ([](VisualSceneMesh &vsmesh, int oldx, int oldy, int newx, int newy, char mode) { vsmesh.MouseMove(oldx, oldy, newx, newy, mode); })); m.def("SelectFace", FunctionPointer ([] (int facenr) { vsmesh.SetSelectedFace(facenr); })); m.def("GetGlobalMesh", FunctionPointer ([] () { return vsmesh.GetMesh(); })); } // BOOST_PYTHON_MODULE(libvisual) // { // ExportMeshVis(); // } #endif ================================================ FILE: libsrc/visualization/vssolution.cpp ================================================ #include #include #include #include #include // #include #include #include namespace netgen { VisualSceneSolution & GetVSSolution() { static VisualSceneSolution vssolution; return vssolution; } // extern shared_ptr mesh; extern VisualSceneMesh vsmesh; VisualSceneSolution :: SolData :: SolData () : data{nullptr}, solclass{nullptr} { ; } VisualSceneSolution :: SolData :: ~SolData () { // delete [] name; delete data; delete solclass; } VisualSceneSolution :: VisualSceneSolution () : VisualScene() { // cout << "init VisualSceneSolution" << endl; surfellist = 0; linelist = 0; element1dlist = 0; clipplanelist_scal = 0; clipplanelist_vec = 0; isolinelist = 0; clipplane_isolinelist = 0; surface_vector_list = 0; isosurface_list = 0; select_sel_list = 0; numtexturecols = 8; 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 () { // cout << "exit VisualSceneSolution" << endl; ClearSolutionData(); } /* void VisualSceneSolution :: SetMesh (shared_ptr amesh) { wp_mesh = amesh; } */ void VisualSceneSolution :: AddSolutionData (SolData * sd) { shared_ptr mesh = GetMesh(); NgLock meshlock1 (mesh->MajorMutex(), 1); int funcnr = -1; for (int i = 0; i < soldata.Size(); i++) { // if (strcmp (soldata[i]->name, sd->name) == 0) if (soldata[i]->name == sd->name) { 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) { shared_ptr mesh = GetMesh(); 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 handled" << 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 = IndexBASE(); pi < mesh->GetNP()+IndexBASE(); 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] - IndexBASE(); 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 = IndexBASE(); pi < mesh->GetNP()+IndexBASE(); 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] - IndexBASE(); 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 }; NgFlatArray 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 () { try { shared_ptr mesh = GetMesh(); 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 (GetVSSolution().numtexturecols, lineartexture, 0.5, GL_MODULATE); glClearColor(backcolor, backcolor, backcolor, 1); // glClearColor(backcolor, backcolor, backcolor, 0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); SetLight(); glPushMatrix(); glMultMatrixd (transformationmat); glMatrixMode (GL_MODELVIEW); glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); glPolygonOffset (1, 1); glEnable (GL_POLYGON_OFFSET_FILL); glEnable (GL_COLOR_MATERIAL); glDisable(GL_BLEND); 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 * netgen::GetVSSolution().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) { // Change for Martin: // orig: SetClippingPlane (); glCallList (surfellist); #ifdef USE_BUFFERS // static int timer = NgProfiler::CreateTimer ("Solution::drawing - DrawSurfaceElements VBO"); // NgProfiler::StartTimer(timer); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glDrawElements(GL_TRIANGLES, surfel_vbo_size, GL_UNSIGNED_INT, 0); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); // NgProfiler::StopTimer(timer); #endif /* // transparent test ... glColor4f (1, 0, 0, 0.1); glEnable (GL_COLOR_MATERIAL); glDepthFunc(GL_GREATER); glDepthMask(GL_FALSE); // glBlendFunc(GL_ONE_MINUS_DST_ALPHA,GL_DST_ALPHA); glBlendFunc(GL_ONE_MINUS_SRC_ALPHA,GL_SRC_ALPHA); glCallList (surfellist); glDisable(GL_BLEND); glDepthFunc(GL_LEQUAL); glDepthMask(GL_TRUE); glCallList (surfellist); // end test ... */ glCallList (surface_vector_list); glDisable(GL_CLIP_PLANE0); } if (showclipsolution) { if (clipsolution == 1) { // Martin // orig: glCallList (clipplanelist_scal); // transparent experiments // see http://wiki.delphigl.com/index.php/Blenden /* glColor4f (1, 1, 1, 0.5); glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); glEnable(GL_COLOR); glDepthFunc(GL_GREATER); glDepthMask(GL_FALSE); glCallList (clipplanelist_scal); glDepthFunc(GL_LEQUAL); glDepthMask(GL_TRUE); glCallList (clipplanelist_scal); glDisable(GL_BLEND); */ /* // latest transparent version ... glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); glEnable(GL_DEPTH_TEST); // CreateTexture (numtexturecols, lineartexture, 0.25, GL_MODULATE); // glCallList (clipplanelist_scal); glEnable(GL_BLEND); // glDisable(GL_DEPTH_TEST); // CreateTexture (numtexturecols, lineartexture, 0.25, GL_MODULATE); glCallList (clipplanelist_scal); // glDepthFunc(GL_LEQUAL); // glDepthMask(GL_TRUE); // glCallList (clipplanelist_scal); glEnable(GL_DEPTH_TEST); glDisable(GL_BLEND); */ // end test } if (clipsolution == 2) { // glDisable(GL_DEPTH_TEST); glCallList (clipplanelist_vec); // glEnable(GL_DEPTH_TEST); } } 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) { SetClippingPlane(); glCallList(pointcurvelist); glDisable(GL_CLIP_PLANE0); } 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.drawedges) { SetClippingPlane (); glCallList (element1dlist); } if (vispar.drawoutline && !numisolines) { SetClippingPlane (); glDepthMask(GL_FALSE); glCallList (linelist); glDepthMask(GL_TRUE); glDisable(GL_CLIP_PLANE0); } if (numisolines) { SetClippingPlane (); glCallList (isolinelist); glDisable(GL_CLIP_PLANE0); glCallList (clipplane_isolinelist); } // user visualization for (int i = 0; i < user_vis.Size(); i++) user_vis[i] -> Draw(); DrawMarker(); glPopMatrix(); glDisable(GL_CLIP_PLANE0); DrawColorBar (minval, maxval, logscale, lineartexture, number_format, unit); DrawTitle (title); if (vispar.drawcoordinatecross) DrawCoordinateCross (); DrawNetgenLogo (); glFinish(); // delete lock; // mem_lock.UnLock(); } catch (const bad_weak_ptr & e) { // cout << "don't have a mesh to visualize" << endl; VisualScene::DrawScene(); } } /* 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]; } } } */ Vec<3> VisualSceneSolution :: RealVec3d (const double * values, bool iscomplex, bool imag) { Vec<3> v; if (!iscomplex) { for (int j = 0; j < 3; j++) v(j) = values[j]; } else { if (!imag) { for (int j = 0; j < 3; j++) v(j) = values[2*j]; } else { for (int j = 0; j < 3; j++) v(j) = values[2*j+1]; } } return v; } 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) { try { shared_ptr mesh = GetMesh(); 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 = GetScalFunction(); SolData * vsol = GetVecFunction(); 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.clipping.timestamp > clipplanetimestamp || solutiontimestamp > surfeltimestamp) { GetMinMax (scalfunction, scalcomp, minval, maxval); } } if (mesh->GetTimeStamp() > surfeltimestamp || solutiontimestamp > surfeltimestamp || zoomall) { if (mesh->GetTimeStamp() > surfeltimestamp || zoomall) { // mesh has changed vsmesh.SelectCenter(zoomall); } DrawSurfaceElements(); surfeltimestamp = max2 (solutiontimestamp, mesh->GetTimeStamp()); } if (mesh->GetTimeStamp() > surfellinetimestamp || subdivision_timestamp > surfellinetimestamp || (solutiontimestamp > surfellinetimestamp) || zoomall) { DrawSurfaceElementLines(); surfellinetimestamp = max2 (solutiontimestamp, mesh->GetTimeStamp()); } if (vispar.drawedges) Draw1DElements(); 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.clipping.timestamp || clipplanetimestamp < solutiontimestamp) { // cout << "clipsolution = " << clipsolution << endl; if (vispar.clipping.enable && clipsolution == 2) { mesh->Mutex().unlock(); mesh->BuildElementSearchTree(3); mesh->Mutex().lock(); } if (vispar.clipping.enable && clipsolution == 1 && sol) DrawClipPlaneTrigs (); if (clipplanelist_vec) glDeleteLists (clipplanelist_vec, 1); clipplanelist_vec = glGenLists (1); glNewList (clipplanelist_vec, GL_COMPILE); if (vispar.clipping.enable && clipsolution == 2 && vsol) { SetTextureMode (usetexture); if (autoscale) GetMinMax (vecfunction, 0, minval, maxval); NgArray 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); v = RealVec3d (values, 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); SetTextureMode(0); // disable all textures for(int i=0; iGetNumPointCurves(); i++) { Box3d box; box.SetPoint(mesh->GetPointCurvePoint(i,0)); for(int j=1; jGetNumPointsOfPointCurve(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; jGetNumPointsOfPointCurve(i)-1; j++) { DrawCylinder(mesh->GetPointCurvePoint(i,j), mesh->GetPointCurvePoint(i,j+1), thick); } } glEndList(); } } if ( numisolines && (clipplanetimestamp < vispar.clipping.timestamp || 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(); auto sol_active = GetScalOrVecFunction(); if (sol) { glBegin (GL_LINES); for (SurfaceElementIndex sei = 0; sei < nse; sei++) { const Element2d & el = (*mesh)[sei]; if(!SurfaceElementActive(sol_active, *mesh, el)) continue; 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, -1, 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, -1, 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 = 0.0, vy = 0.0, vtwist = 0.0, 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, -1, 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, -1, 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.clipping.enable && clipsolution == 1 && sol) { clipplane_isolinelist = glGenLists (1); glNewList (clipplane_isolinelist, GL_COMPILE); NgArray cpt; NgArray pts; GetClippingPlaneTrigs (sol, cpt, pts); bool drawelem; glNormal3d (-clipplane[0], -clipplane[1], -clipplane[2]); glBegin (GL_LINES); 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, vali[0], vali[1], vali[2]); } glEnd(); glEndList (); } } clipplanetimestamp = max2 (vispar.clipping.timestamp, solutiontimestamp); } catch (const bad_weak_ptr & e) { PrintMessage (3, "vssolution::buildscene: don't have a mesh to visualize"); VisualScene::BuildScene (zoomall); } } void VisualSceneSolution :: Draw1DElements () { shared_ptr mesh = GetMesh(); if (element1dlist) glDeleteLists (element1dlist, 1); element1dlist = glGenLists (1); glNewList (element1dlist, GL_COMPILE); int npt = (1 << subdivisions) + 1; NgArray pref(npt), values(npt); NgArray > points(npt); const SolData * sol = NULL; if (scalfunction != -1) sol = soldata[scalfunction]; const SolData * vsol = NULL; if (deform && vecfunction != -1) vsol = soldata[vecfunction]; int ncomp = 0; if (sol) ncomp = sol->components; if (vsol) ncomp = vsol->components; NgArray mvalues(ncomp); for (int i = 0; i < npt; i++) pref[i] = double(i) / (npt-1); int meshdim = mesh->GetDimension(); for (SegmentIndex i = 0; i < mesh -> GetNSeg(); i++) { // mesh->GetCurvedElements(). // CalcMultiPointSegmentTransformation (&pref, i, &points, NULL); // const Segment & seg = mesh -> LineSegment(i); for (int j = 0; j < npt; j++) mesh->GetCurvedElements(). CalcSegmentTransformation (pref[j], i, points[j]); if (vsol) { for (int j = 0; j < npt; j++) { vsol->solclass->GetSegmentValue (i, pref[j], &mvalues[0]); // values[j] = ExtractValue (sol, scalcomp, &mvalues[0]); for (int k = 0; k < min(ncomp, 3); k++) points[j](k) += scaledeform * mvalues[k]; // points[j](0) += scaledeform * mvalues[0]; // points[j](1) += scaledeform * mvalues[1]; } } else if (sol && meshdim <= 2) { for (int j = 0; j < npt; j++) { sol->solclass->GetSegmentValue (i, pref[j], &mvalues[0]); values[j] = ExtractValue (sol, scalcomp, &mvalues[0]); points[j](meshdim) += scaledeform * values[j]; } } glBegin (GL_LINE_STRIP); for (int i = 0; i < npt; i++) glVertex3dv (points[i]); glEnd(); } glEndList (); } void VisualSceneSolution :: DrawSurfaceElements () { shared_ptr mesh = GetMesh(); static int timer = NgProfiler::CreateTimer ("Solution::DrawSurfaceElements"); /* static int timerstart = NgProfiler::CreateTimer ("Solution::DrawSurfaceElements start"); static int timerloops = NgProfiler::CreateTimer ("Solution::DrawSurfaceElements loops"); static int timerlist = NgProfiler::CreateTimer ("Solution::DrawSurfaceElements list"); static int timerbuffer = NgProfiler::CreateTimer ("Solution::DrawSurfaceElements buffer"); static int timer1 = NgProfiler::CreateTimer ("Solution::DrawSurfaceElements 1"); static int timer1a = NgProfiler::CreateTimer ("Solution::DrawSurfaceElements 1a"); static int timer1b = NgProfiler::CreateTimer ("Solution::DrawSurfaceElements 1b"); static int timer1c = NgProfiler::CreateTimer ("Solution::DrawSurfaceElements 1c"); static int timer2 = NgProfiler::CreateTimer ("Solution::DrawSurfaceElements 2"); static int timer2a = NgProfiler::CreateTimer ("Solution::DrawSurfaceElements 2a"); static int timer2b = NgProfiler::CreateTimer ("Solution::DrawSurfaceElements 2b"); */ 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, NG_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 // NgProfiler::StartTimer(timerstart); 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, 1.0f }; 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); NgArray > pref (npt); NgArray > points (npt); NgArray > dxdxis (npt); NgArray > nvs(npt); NgArray values(npt); NgArray mvalues(npt); int sol_comp = (sol && sol->draw_surface) ? sol->components : 0; NgArray> > simd_pref ( (npt+SIMD::Size()-1)/SIMD::Size() ); NgArray> > simd_points ( (npt+SIMD::Size()-1)/SIMD::Size() ); NgArray> > simd_dxdxis ( (npt+SIMD::Size()-1)/SIMD::Size() ); NgArray> > simd_nvs( (npt+SIMD::Size()-1)/SIMD::Size() ); NgArray> simd_values( (npt+SIMD::Size()-1)/SIMD::Size() * sol_comp); // NgArray> glob_pnts; // NgArray> glob_nvs; // NgArray glob_values; if (sol && sol->draw_surface) mvalues.SetSize (npt * sol->components); NgArray > valuesc(npt); #ifdef USE_BUFFERS if (has_surfel_vbo) glDeleteBuffers (4, &surfel_vbo[0]); glGenBuffers (4, &surfel_vbo[0]); has_surfel_vbo = true; glBindBuffer (GL_ARRAY_BUFFER, surfel_vbo[0]); glBufferData (GL_ARRAY_BUFFER, nse*npt*sizeof(Point<3,double>), NULL, GL_STATIC_DRAW); glVertexPointer(3, GL_DOUBLE, 0, 0); // glEnableClientState(GL_VERTEX_ARRAY); glBindBuffer (GL_ARRAY_BUFFER, surfel_vbo[1]); glBufferData (GL_ARRAY_BUFFER, nse*npt*sizeof(Vec<3,double>), NULL, GL_STATIC_DRAW); // glEnableClientState(GL_NORMAL_ARRAY); glNormalPointer(GL_DOUBLE, 0, 0); // glEnableClientState(GL_TEXTURE_COORD_ARRAY); glBindBuffer (GL_ARRAY_BUFFER, surfel_vbo[2]); glBufferData (GL_ARRAY_BUFFER, nse*npt*sizeof(double), NULL, GL_STATIC_DRAW); glTexCoordPointer(1, GL_DOUBLE, 0, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, surfel_vbo[3]); glBufferData(GL_ELEMENT_ARRAY_BUFFER, nse*npt*6*sizeof(int), NULL, GL_STATIC_DRAW); surfel_vbo_size = 0; #endif // NgProfiler::StopTimer(timerstart); auto sol_active = GetScalOrVecFunction(); for (SurfaceElementIndex sei = 0; sei < nse; sei++) { const Element2d & el = (*mesh)[sei]; if(!SurfaceElementActive(sol_active, *mesh, el)) continue; if ( el.GetType() == QUAD || el.GetType() == QUAD6 || el.GetType() == QUAD8 ) { 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]; mesh->GetCurvedElements(). CalcSurfaceTransformation (xref, sei, points[ii], dxdxis[ii]); nvs[ii] = Cross (dxdxis[ii].Col(0), dxdxis[ii].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; for (int j = 0; j < 3; j++) { dxdxis[ii](j,0) = vx(j) + y*vtwist(j); dxdxis[ii](j,1) = vy(j) + x*vtwist(j); } } 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, -1, pref[ii](0), pref[ii](1), scalcomp, valuesc[ii]); else for (int ii = 0; ii < npt; ii++) drawelem = GetSurfValue (sol, sei, -1, pref[ii](0), pref[ii](1), scalcomp, values[ii]); } */ if (sol && sol->draw_surface) { drawelem = GetMultiSurfValues (sol, sei, -1, 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, -1, 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 glColor4fv (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; // NgProfiler::StartTimer(timerloops); size_t base_pi = 0; 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); constexpr size_t simd_size = SIMD::Size(); size_t simd_npt = (npt+simd_size-1)/simd_size; for (size_t i = 0; i < simd_npt; i++) { simd_pref[i](0) = [&] (size_t j) { size_t ii = i*simd_size+j; return (ii < npt) ? pref[ii](0) : 0; }; simd_pref[i](1) = [&] (size_t j) { size_t ii = i*simd_size+j; return (ii < npt) ? pref[ii](1) : 0; }; } NgArray ind_reftrig; for (int iy = 0, ii = 0; iy < n; iy++,ii++) for (int ix = 0; ix < n-iy; ix++, ii++) { int nv = (ix+iy+1 < n) ? 6 : 3; int ind[] = { ii, ii+1, ii+n-iy+1, ii+n-iy+1, ii+1, ii+n-iy+2 }; for (int j = 0; j < nv; j++) ind_reftrig.Append (ind[j]); } NgArray glob_ind; glob_ind.SetSize(ind_reftrig.Size()); for(SurfaceElementIndex sei = 0; sei < nse; sei++) { const Element2d & el = (*mesh)[sei]; // if (el.GetIndex() <= 1) continue; if(!SurfaceElementActive(sol_active, *mesh, el)) continue; if ( el.GetType() == TRIG || el.GetType() == TRIG6 ) { // NgProfiler::StartTimer(timer1); #ifdef __AVX_try_it_out__ // NgProfiler::StartTimer(timer1a); bool curved = curv.IsSurfaceElementCurved(sei); if (curved) { mesh->GetCurvedElements(). CalcMultiPointSurfaceTransformation<3> (sei, simd_npt, &simd_pref[0](0), 2, &simd_points[0](0), 3, &simd_dxdxis[0](0,0), 6); for (size_t ii = 0; ii < simd_npt; ii++) simd_nvs[ii] = Cross (simd_dxdxis[ii].Col(0), simd_dxdxis[ii].Col(1)).Normalize(); } else { Point<3,SIMD> p1 = mesh->Point (el[0]); Point<3,SIMD> p2 = mesh->Point (el[1]); Point<3,SIMD> p3 = mesh->Point (el[2]); Vec<3,SIMD> vx = p1-p3; Vec<3,SIMD> vy = p2-p3; for (size_t ii = 0; ii < simd_npt; ii++) { simd_points[ii] = p3 + simd_pref[ii](0) * vx + simd_pref[ii](1) * vy; for (size_t j = 0; j < 3; j++) { simd_dxdxis[ii](j,0) = vx(j); simd_dxdxis[ii](j,1) = vy(j); } } Vec<3,SIMD> nv = Cross (vx, vy).Normalize(); for (size_t ii = 0; ii < simd_npt; ii++) simd_nvs[ii] = nv; } bool drawelem = false; if (sol && sol->draw_surface) { // NgProfiler::StopTimer(timer1a); // NgProfiler::StartTimer(timer1b); drawelem = sol->solclass->GetMultiSurfValue (sei, -1, simd_npt, &simd_pref[0](0).Data(), &simd_points[0](0).Data(), &simd_dxdxis[0](0).Data(), &simd_values[0].Data()); // NgProfiler::StopTimer(timer1b); // NgProfiler::StartTimer(timer1c); for (size_t j = 0; j < sol->components; j++) for (size_t i = 0; i < npt; i++) mvalues[i*sol->components+j] = ((double*)&simd_values[j*simd_npt])[i]; 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]); } for (size_t i = 0; i < npt; i++) { size_t ii = i/4; size_t r = i%4; for (int j = 0; j < 2; j++) pref[i](j) = simd_pref[ii](j)[r]; for (int j = 0; j < 3; j++) points[i](j) = simd_points[ii](j)[r]; for (int j = 0; j < 3; j++) nvs[i](j) = simd_nvs[ii](j)[r]; } if (deform) for (int ii = 0; ii < npt; ii++) points[ii] += GetSurfDeformation (sei, -1, pref[ii](0), pref[ii](1)); // NgProfiler::StopTimer(timer1c); #else bool curved = (*mesh)[sei].IsCurved(); 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, -1, 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, -1, pref[ii](0), pref[ii](1)); #endif // NgProfiler::StopTimer(timer1); int save_usetexture = usetexture; if (!drawelem) { usetexture = 0; SetTextureMode (usetexture); } // NgProfiler::StartTimer(timer2); #ifdef USE_BUFFERS if (drawelem && usetexture == 1 && !logscale) { glBindBuffer (GL_ARRAY_BUFFER, surfel_vbo[0]); glBufferSubData (GL_ARRAY_BUFFER, base_pi*sizeof(Point<3,double>), npt*sizeof(Point<3,double>), &points[0][0]); glBindBuffer (GL_ARRAY_BUFFER, surfel_vbo[1]); glBufferSubData (GL_ARRAY_BUFFER, base_pi*sizeof(Vec<3,double>), npt*sizeof(Vec<3,double>), &nvs[0][0]); glBindBuffer (GL_ARRAY_BUFFER, surfel_vbo[2]); glBufferSubData (GL_ARRAY_BUFFER, base_pi*sizeof(double), npt*sizeof(double), &values[0]); for (size_t i = 0; i < ind_reftrig.Size(); i++) glob_ind[i] = base_pi+ind_reftrig[i]; glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, surfel_vbo[3]); glBufferSubData (GL_ELEMENT_ARRAY_BUFFER, surfel_vbo_size*sizeof(int), ind_reftrig.Size()*sizeof(int), &glob_ind[0]); surfel_vbo_size += ind_reftrig.Size(); base_pi += npt; } else #endif 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 glColor4fv (col_grey); glNormal3dv (nvs[hi]); glVertex3dv (points[hi]); } glEnd(); } // NgProfiler::StopTimer(timer2); if (!drawelem && (usetexture != save_usetexture)) { usetexture = save_usetexture; SetTextureMode (usetexture); } } } // NgProfiler::StopTimer(timerloops); // NgProfiler::StartTimer(timerbuffer); // glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, surfel_vbo[3]); // glBufferData(GL_ELEMENT_ARRAY_BUFFER, glob_ind.Size()*sizeof(int), &glob_ind[0], GL_STATIC_DRAW); // surfel_vbo_size = glob_ind.Size(); // NgProfiler::StopTimer(timerbuffer); // glDrawElements(GL_TRIANGLES, surfel_vbo_size, GL_UNSIGNED_INT, 0); // glDrawElements(GL_TRIANGLES, glob_ind.Size(), GL_UNSIGNED_INT, &glob_ind[0]); // glDisableClientState(GL_VERTEX_ARRAY); // glDisableClientState(GL_NORMAL_ARRAY); // glDisableClientState(GL_TEXTURE_COORD_ARRAY); // glDeleteBuffers (1, &IndexVBOID); // glDeleteBuffers (4, &vboId[0]); // NgProfiler::StartTimer(timerlist); glEndList (); // NgProfiler::StopTimer(timerlist); #ifdef PARALLELGL glFinish(); if (id > 0) MyMPI_Send (surfellist, 0, NG_MPI_TAG_VIS); #endif } void VisualSceneSolution :: DrawSurfaceElementLines () { shared_ptr mesh = GetMesh(); #ifdef PARALLELGL if (id == 0 && ntasks > 1) { InitParallelGL(); par_surfellists.SetSize (ntasks); MyMPI_SendCmd ("redraw"); MyMPI_SendCmd ("solsurfellinelist"); for ( int dest = 1; dest < ntasks; dest++ ) MyMPI_Recv (par_surfellists[dest], dest, NG_MPI_TAG_VIS); if (linelist) glDeleteLists (linelist, 1); linelist = glGenLists (1); glNewList (linelist, GL_COMPILE); for ( int dest = 1; dest < ntasks; dest++ ) glCallList (par_surfellists[dest]); glEndList(); return; } #endif if (linelist) glDeleteLists (linelist, 1); linelist = glGenLists (1); glNewList (linelist, GL_COMPILE); glLineWidth (1.0f); int nse = mesh->GetNSE(); CurvedElements & curv = mesh->GetCurvedElements(); int n = 1 << subdivisions; NgArrayMem, 65> ptsloc(n+1); NgArrayMem, 65> ptsglob(n+1); double trigpts[3][2] = { { 0, 0 }, { 0, 1 }, { 1, 0} }; double trigvecs[3][2] = { { 1, 0 }, { 0, -1 }, { -1, 1} }; double quadpts[4][2] = { { 0, 0 }, { 1, 1 }, { 0, 1}, { 1, 0 } }; double quadvecs[4][2] = { { 1, 0 }, { -1, 0}, { 0, -1}, { 0, 1 } }; auto sol_active = GetScalOrVecFunction(); for (SurfaceElementIndex sei = 0; sei < nse; sei++) { Element2d & el = (*mesh)[sei]; if(!SurfaceElementActive(sol_active, *mesh, el)) continue; int nv = (el.GetType() == TRIG || el.GetType() == TRIG6) ? 3 : 4; 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); 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, k, ptsloc[ix](0), ptsloc[ix](1)); glVertex3dv (ptsglob[ix]); } glEnd (); } } glEndList (); #ifdef PARALLELGL glFinish(); if (id > 0) MyMPI_Send (linelist, 0, NG_MPI_TAG_VIS); #endif } void VisualSceneSolution :: DrawIsoSurface(const SolData * sol, const SolData * vsol, int comp) { shared_ptr mesh = GetMesh(); 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); NgArray > grid(n3); NgArray > locgrid(n3); NgArray > trans(n3); NgArray val1(n3*sol->components); NgArray > grads1(n3); NgArray compress(n3); MatrixFixWidth<3> pointmat(8); grads1 = 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; const Element & el = (*mesh)[ei]; if(!VolumeElementActive(sol, *mesh, el)) continue; ELEMENT_TYPE type = el.GetType(); if (type == HEX || type == PRISM || type == TET || type == PYRAMID) { 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 implemented 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; GetMultiValues( sol, ei, -1, n3, &locgrid[0](0), &locgrid[1](0)-&locgrid[0](0), &grid[0](0), &grid[1](0)-&grid[0](0), &trans[0](0), &trans[1](0)-&trans[0](0), &val1[0], sol->components); 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; val1[sol->components*i+comp-1] -= minval; // if (vsol) // GetValues (vsol, ei, &locgrid[i](0), &grid[i](0), &trans[i](0), &grads[i](0)); // grads[i] *= -1; if (val1[i*sol->components+comp-1] > 0) has_pos = 1; else has_neg = 1; // if (val[i] > 0) // has_pos = 1; // else // has_neg = 1; } if (!has_pos || !has_neg) continue; if (vsol) { GetMultiValues(vsol, ei, -1, n3, &locgrid[0](0), &locgrid[1](0)-&locgrid[0](0), &grid[0](0), &grid[1](0)-&grid[0](0), &trans[0](0), &trans[1](0)-&trans[0](0), &grads1[0](0), vsol->components); // for (int i = 0; i < cnt_valid; i++) // grads1[i*sol->components+comp-1] *= -1; for (int i = 0; i < cnt_valid; i++) grads1[i] *= -1; } 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]]; for (int j = 0; j < 4; j++) nodevali[j] = val1[sol->components*teti[j]+comp-1]; 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]]); normp[j] = grads1[teti[lpi1]] + (1-edgelam[j]) * (grads1[teti[lpi2]]-grads1[teti[lpi1]]); // normp[j] = grads1[sol->components*teti[lpi1]+comp-1] + (1-edgelam[j]) * (grads1[sol->components*teti[lpi2]+comp-1]-grads1[sol->components*teti[lpi1]+comp-1]); 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 NgArray< Point<3> > & lp, const Point<3> & pmin, const Point<3> & pmax, const int sei, const SolData * vsol, bool swap_lam) { shared_ptr mesh = GetMesh(); 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) { if(swap_lam) { Swap(lam1, lam2); lam1 = 1.0-lam1; lam2 = 1.0-lam2; } 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)); Point<2> xref(lam1, lam2); if (mesh->GetCurvedElements().IsHighOrder()) mesh->GetCurvedElements(). CalcSurfaceTransformation (xref, sei, cp); Vec<3> v; double values[6]; bool drawelem = GetSurfValues (vsol, sei, -1, 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 () { shared_ptr mesh = GetMesh(); 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(!SurfaceElementActive(vsol, *mesh, el)) continue; if (el.GetType() == TRIG || el.GetType() == TRIG6) { NgArray< 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) { NgArray < Point<3> > lp(3); lp[0] = mesh->Point(el[0]); lp[1] = mesh->Point(el[1]); lp[2] = mesh->Point(el[3]); DrawTrigSurfaceVectors(lp,pmin,pmax,sei,vsol); lp[0] = mesh->Point(el[2]); lp[1] = mesh->Point(el[1]); lp[2] = mesh->Point(el[3]); DrawTrigSurfaceVectors(lp,pmin,pmax,sei,vsol, true); /* 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, -1, 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 { shared_ptr mesh = GetMesh(); // static int timer1 = NgProfiler::CreateTimer ("getminmax, vol"); // static int timer2 = NgProfiler::CreateTimer ("getminmax, surf"); #ifdef PARALLELGL auto comm = mesh->GetCommunicator(); if (comm.Size() > 1) { if (id == 0) { MyMPI_SendCmd ("redraw"); MyMPI_SendCmd ("getminmax"); } MyMPI_Bcast (funcnr, mesh->GetCommunicator()); MyMPI_Bcast (comp, mesh->GetCommunicator()); } #endif // double val; // bool considerElem; bool hasit = false; #ifdef max #undef max #endif minv = numeric_limits::max(); maxv = -numeric_limits::max(); if ((ntasks == 1) || (id > 0)) if (funcnr != -1) { const SolData * sol = soldata[funcnr]; if (sol->draw_volume) { // NgProfiler::RegionTimer reg1 (timer1); int ne = mesh->GetNE(); mutex min_mutex; mutex max_mutex; ParallelFor(0, ne, [&] (int first, int next) { double minv_local = numeric_limits::max(); double maxv_local = -numeric_limits::max(); for (int i=first; i maxv_local) maxv_local = val; if (val < minv_local) minv_local = val; hasit = true; } } if(minv_local < minv) { lock_guard guard(min_mutex); if(minv_local < minv) minv = minv_local; } if(maxv_local > maxv) { lock_guard guard(max_mutex); if(maxv_local > maxv) maxv = maxv_local; } }); } if (sol->draw_surface) { // NgProfiler::RegionTimer reg2 (timer2); // int nse = mesh->GetNSE(); // for (int i = 0; i < nse; i++) auto sol_active = GetScalOrVecFunction(); for (SurfaceElementIndex i : mesh->SurfaceElements().Range()) { if(!SurfaceElementActive(sol_active, *mesh, (*mesh)[i])) continue; ELEMENT_TYPE type = (*mesh)[i].GetType(); double val; bool considerElem = (type == QUAD) ? GetSurfValue (sol, i, -1, 0.5, 0.5, comp, val) : GetSurfValue (sol, i, -1, 0.3333333, 0.3333333, comp, val); if (considerElem) { if (val > maxv) maxv = val; if (val < minv) minv = val; hasit = true; } } } } if (minv == maxv) maxv = minv+1e-6; if (!hasit) { minv = 0; maxv = 1; } #ifdef PARALLEL if ((ntasks > 1) && (id == 0)) { minv = 1e99; maxv = -1e99; } if (ntasks > 1) { double hmin, hmax; NG_MPI_Reduce (&minv, &hmin, 1, NG_MPI_DOUBLE, NG_MPI_MIN, 0, NG_MPI_COMM_WORLD); NG_MPI_Reduce (&maxv, &hmax, 1, NG_MPI_DOUBLE, NG_MPI_MAX, 0, NG_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 { shared_ptr mesh = GetMesh(); double lam1 = xref[0]; double lam2 = xref[1]; double lam3 = xref[2]; val = 0; bool ok = 0; if (comp == 0) { NgArrayMem 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: case PRISM15: { 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 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: case PRISM15: { 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: case PYRAMID13: { 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 { shared_ptr mesh = GetMesh(); val = 0; bool ok = 0; if (comp == 0) { NgArrayMem 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: { val = 0.0; 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 & val) const { shared_ptr mesh = GetMesh(); 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 (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 facetnr, 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, facetnr, 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, int facetnr, double lam1, double lam2, double * values) const { bool ok = false; switch (data->soltype) { case SOL_VIRTUALFUNCTION: { ok = data->solclass->GetSurfValue (selnr, facetnr, lam1, lam2, values); // ok = 1; // values[0] = 1.0; break; } default: { for (int i = 0; i < data->components; i++) ok = GetSurfValue (data, selnr, facetnr, lam1, lam2, i+1, values[i]); } } return ok; } bool VisualSceneSolution :: GetSurfValues (const SolData * data, SurfaceElementIndex selnr, int facetnr, 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, facetnr, xref, x, dxdxref, values); break; } default: { for (int i = 0; i < data->components; i++) ok = GetSurfValue (data, selnr, facetnr, xref[0], xref[1], i+1, values[i]); } } return ok; } bool VisualSceneSolution :: GetMultiSurfValues (const SolData * data, SurfaceElementIndex elnr, int facetnr, 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, facetnr, npt, xref, sxref, x, sx, dxdxref, sdxdxref, val, sval); else for (int i = 0; i < npt; i++) drawelem = GetSurfValues (data, elnr, facetnr, 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 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 VisualSceneSolution :: ExtractValueComplex (const SolData * data, int comp, double * values) const { if (!data->iscomplex) return values[comp-1]; else return complex (values[comp-1], values[comp]); } bool VisualSceneSolution :: GetSurfValueComplex (const SolData * data, SurfaceElementIndex selnr, int facetnr, double lam1, double lam2, int comp, complex & val) const { switch (data->soltype) { case SOL_VIRTUALFUNCTION: { NgArrayMem values(data->components); bool ok; ok = data->solclass->GetSurfValue (selnr, facetnr, lam1, lam2, &values[0]); if (ok) { if (!data->iscomplex) val = values[comp-1]; else val = complex (values[comp-1], values[comp]); } return ok; } default: cerr << "case not implemented 6565" << endl; } return 0; } bool VisualSceneSolution :: GetSurfValue (const SolData * data, SurfaceElementIndex selnr, int facetnr, double lam1, double lam2, int comp, double & val) const { bool ok; if (comp == 0) { val = 0; NgArrayMem values(data->components); ok = GetSurfValues (data, selnr, facetnr, lam1, lam2, &values[0]); val = ExtractValue (data, 0, &values[0]); return ok; } switch (data->soltype) { case SOL_VIRTUALFUNCTION: { NgArrayMem values(data->components); bool ok; ok = data->solclass->GetSurfValue (selnr, facetnr, 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: { shared_ptr mesh = GetMesh(); 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: case QUAD8: 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: { shared_ptr mesh = GetMesh(); 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: { shared_ptr mesh = GetMesh(); 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 implemented 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: { shared_ptr mesh = GetMesh(); val = (*mesh)[selnr].TestRefinementFlag(); return 1; } case SOL_ELEMENT_ORDER: { shared_ptr mesh = GetMesh(); val = (*mesh)[selnr].GetOrder(); return 1; } } return 0; } bool VisualSceneSolution :: GetSurfValue (const SolData * data, SurfaceElementIndex selnr, int facetnr, const double xref[], const double x[], const double dxdxref[], int comp, double & val) const { shared_ptr mesh = GetMesh(); double lam1 = xref[0], lam2 = xref[1]; bool ok; if (comp == 0) { val = 0; NgArrayMem values(data->components); ok = GetSurfValues (data, selnr, facetnr, xref, x, dxdxref, &values[0]); val = ExtractValue (data, 0, &values[0]); return ok; } switch (data->soltype) { case SOL_VIRTUALFUNCTION: { NgArrayMem 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, facetnr, 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: case QUAD8: 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 implemented 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, int facetnr, double lam1, double lam2) const { shared_ptr mesh = GetMesh(); Vec<3> def; if (deform && vecfunction != -1) { // GetSurfValues (soldata[vecfunction], elnr, facetnr, lam1, lam2, &def(0)); double values[6]; GetSurfValues (soldata[vecfunction], elnr, facetnr, lam1, lam2, values); def = RealVec3d (values, soldata[vecfunction]->iscomplex, imag_part); 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, facetnr, lam1, lam2, scalcomp, def(2)); def *= scaledeform; } else def = 0; return def; } void VisualSceneSolution :: GetPointDeformation (PointIndex pnum, Point<3> & p, SurfaceElementIndex elnr) const { shared_ptr mesh = GetMesh(); auto pnum_ = pnum-IndexBASE(); p = mesh->Point (pnum); 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) { 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 (SolData * sol, NgArray & trigs, NgArray & pts) { shared_ptr mesh = GetMesh(); // static int timer_vals = NgProfiler::CreateTimer ("ClipPlaneTrigs - vertex values"); static int timer1 = NgProfiler::CreateTimer ("ClipPlaneTrigs1"); // static int timer1a = NgProfiler::CreateTimer ("ClipPlaneTrigs1a"); // static int timer2 = NgProfiler::CreateTimer ("ClipPlaneTrigs2"); // static int timer3 = NgProfiler::CreateTimer ("ClipPlaneTrigs3"); // static int timer4 = NgProfiler::CreateTimer ("ClipPlaneTrigs4"); // static int timer4b = NgProfiler::CreateTimer ("ClipPlaneTrigs4b"); 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; // NgArray loctets; // NgArray loctetsloc; // NgArray > pointsloc; int n = 1 << subdivisions; int n3 = (n+1)*(n+1)*(n+1); NgArray > grid(n3); NgArray > locgrid(n3); NgArray > trans(n3); NgArray val(n3); NgArray locposval(n3); NgArray compress(n3); // NgProfiler::StartTimer (timer_vals); NgArray vertval(mesh->GetNP()); NgArray posval(mesh->GetNP()); // for (PointIndex pi = vertval.Begin(); pi < vertval.End(); pi++) for (PointIndex pi : vertval.Range()) { Point<3> vert = (*mesh)[pi]; vertval[pi] = vert(0) * clipplane[0] + vert(1) * clipplane[1] + vert(2) * clipplane[2] + clipplane[3]; posval[pi] = vertval[pi] > 0; } // NgProfiler::StopTimer (timer_vals); INDEX_2_CLOSED_HASHTABLE edges(8*n3); // point nr of edge for (ElementIndex ei = 0; ei < ne; ei++) { // NgProfiler::RegionTimer reg1a (timer1a); const Element & el = (*mesh)[ei]; if(!VolumeElementActive(sol, *mesh, el)) continue; int first_point_of_element = pts.Size(); 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 || type == PYRAMID13 || type == PRISM15 || type == HEX20 || type == HEX7) { int ii = 0; int cnt_valid = 0; // NgProfiler::StartTimer (timer2); if (!mesh->GetCurvedElements().IsElementHighOrder(ei)) { bool has_pos = 0, has_neg = 0; for (int i = 0; i < el.GetNP(); i++) if (posval[el[i]]) has_pos = 1; else has_neg = 1; if (!has_pos || !has_neg) { // NgProfiler::StopTimer (timer2); continue; } } 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++) { double x = double(ix)/n; double y = double(iy)/n; double z = double(iz)/n; Point<3> ploc; compress[ii] = ii; switch (type) { case PRISM: case PRISM12: case PRISM15: 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: case HEX20: ploc = Point<3> (double(ix) / n, double(iy) / n, double(iz) / n); break; case PYRAMID: case PYRAMID13: 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; case HEX7: { if (iz == n && iy==n) { y -= 1e-7, z -= 1e-7; } ploc = Point<3> (x * (1-y*z), y, z); // if (iz == n && iy==n) ploc = Point<3> (0,1-1e-8,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 && type != PRISM12 && type != PRISM15) cnt_valid = n3; locgrid.SetSize(cnt_valid); // NgProfiler::StopTimer (timer2); // NgProfiler::RegionTimer reg4(timer4); if (mesh->GetCurvedElements().IsHighOrder()) { // NgProfiler::RegionTimer reg4(timer4); mesh->GetCurvedElements(). CalcMultiPointElementTransformation (&locgrid, ei, &grid, 0); } else { // NgProfiler::RegionTimer reg4(timer4b); 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 = false, all_pos = true; 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]; locposval[i] = val[i] > 0; has_pos |= locposval[i]; all_pos &= locposval[i]; // if (val[i] > 0) has_pos = 1; else has_neg = 1; } // if (!has_pos || !has_neg) continue; if (!has_pos || all_pos) continue; edges.DeleteData(); 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]]; bool has_pos = false, all_pos = true; for (int j = 0; j < 8; j++) if (pi[j] != -1) { has_pos |= locposval[pi[j]]; all_pos &= locposval[pi[j]]; } if (!has_pos || all_pos) continue; 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 = true; for (int j = 0; j < 4; j++) is_valid &= (teti[j] != -1); if (!is_valid) continue; bool has_pos = false, all_pos = true; for (int j = 0; j < 4; j++) { has_pos |= locposval[teti[j]]; all_pos &= locposval[teti[j]]; } if (!has_pos || all_pos) 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) ) { 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; } int pi1 = edgei[ednr][0]; int pi2 = edgei[ednr][1]; int pnr = -1; INDEX_2 pair (teti[pi1], teti[pi2]); pair.Sort(); if (edges.Used(pair)) pnr = edges.Get(pair); else { ClipPlanePoint cppt; cppt.elnr = ei; edgelam[ednr] = nodevali[pi2] / (nodevali[pi2] - nodevali[pi1]); Point<3> gp1 = grid[teti[pi1]]; Point<3> gp2 = grid[teti[pi2]]; cppt.p = gp2 + edgelam[ednr] * (gp1-gp2); Point<3> p1 = locgrid[teti[pi1]]; Point<3> p2 = locgrid[teti[pi2]]; cppt.lami = p2 + edgelam[ednr] * (p1-p2); pts.Append (cppt); pnr = pts.Size()-1; edges.Set (pair, pnr); } 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) continue; // return; } } } void VisualSceneSolution :: GetClippingPlaneGrid (NgArray & pts) { shared_ptr mesh = GetMesh(); 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); 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 () { shared_ptr mesh = GetMesh(); #ifdef PARALLELGL if (id == 0 && ntasks > 1) { InitParallelGL(); NgArray parlists (ntasks); MyMPI_SendCmd ("redraw"); MyMPI_SendCmd ("clipplanetrigs"); for ( int dest = 1; dest < ntasks; dest++ ) MyMPI_Recv (parlists[dest], dest, NG_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); NgArray trigs; NgArray 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]; GetClippingPlaneTrigs (sol, trigs, points); if (sol -> draw_volume) { 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); NgArray vals(maxlpnr+1); NgArray > valsc(maxlpnr+1); NgArray elnrs(maxlpnr+1); NgArray trigok(maxlpnr+1); NgArray > locpoints(maxlpnr+1); NgArray > globpoints(maxlpnr+1); NgArray > jacobi(maxlpnr+1); NgArray mvalues( (maxlpnr+1) * sol->components); trigok = false; elnrs = -1; Point<3> p[3]; // double val[3]; // complex valc[3]; int lastelnr = -1; int nlp = -1; bool ok = false; for (int i = 0; i < trigs.Size(); i++) { const ClipPlaneTrig & trig = trigs[i]; if (trig.elnr != ElementIndex(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, -1, 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; ok = drawelem; 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 (mvalues[ii*sol->components + scalcomp-1], mvalues[ii*sol->components + scalcomp]); } 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 PARALLELGLGL glFinish(); if (id > 0) MyMPI_Send (clipplanelist_scal, 0, NG_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 (); } bool VisualSceneSolution :: SurfaceElementActive(const SolData *data, const Mesh & mesh, const Element2d & el) const { if(data == nullptr) return true; bool is_active = true; if (vispar.drawdomainsurf > 0) { if (mesh.GetDimension() == 3) { if (vispar.drawdomainsurf != mesh.GetFaceDescriptor(el.GetIndex()).DomainIn() && vispar.drawdomainsurf != mesh.GetFaceDescriptor(el.GetIndex()).DomainOut()) is_active = false; } else { if (el.GetIndex() != vispar.drawdomainsurf) is_active = false; } } if(data->draw_surfaces) { is_active = is_active && (*data->draw_surfaces)[el.GetIndex()-1]; } return is_active; } bool VisualSceneSolution :: VolumeElementActive(const SolData *data, const Mesh & mesh, const Element & el) const { bool is_active = true; if(data->draw_volumes) is_active = is_active && (*data->draw_volumes)[el.GetIndex()-1]; return is_active; } void VisualSceneSolution :: BuildSelectionList() { shared_ptr mesh = GetMesh(); if(select.list_timestamp == GetTimeStamp()) return; if(select.list) glDeleteLists(select.list, 1); select.list = glGenLists(1); glNewList(select.list, GL_COMPILE); SolData *sol = nullptr; if (scalfunction != -1) sol = soldata[scalfunction]; auto face_init = [](int i) {return true;}; auto sel_init = [&](SurfaceElementIndex sei) { if(!SurfaceElementActive(sol, *mesh, (*mesh)[sei])) return false; GLushort r,g,b; r = (sei+1) % (1<<16); g = (sei+1) >> 16; b = 0; glColor3us(r,g,b); return true; }; glDisable(GL_TEXTURE_1D); glDisable(GL_TEXTURE_2D); glDisable(GL_FOG); glDisable(GL_LIGHTING); glDisable (GL_COLOR_MATERIAL); RenderSurfaceElements(mesh, subdivisions, face_init, sel_init); glEndList(); } void VisualSceneSolution :: MouseDblClick (int px, int py) { BuildSelectionList(); auto mesh = GetMesh(); // auto dim = mesh->GetDimension(); marker = nullopt; auto formatComplex = [](double real, double imag) { return ToString(real) + (imag < 0 ? "" : "+") + ToString(imag) + "j"; }; auto printScalValue = [&formatComplex] (SolData & sol, int comp, double value, double imag=0., bool iscomplex=false) { cout << '\t'; if(sol.components>1) { if(comp==0) cout << "func(" << sol.name << ")"; else cout << sol.name << "["+ToString(comp)+"]"; } else cout << sol.name; cout << " = " << (iscomplex ? formatComplex(value, imag) : ToString(value)) << endl; }; auto printVecValue = [&formatComplex] (SolData & sol, FlatArray values) { if(sol.iscomplex) { cout << sol.name << " = ( " << formatComplex(values[0], values[1]); for(int i = 2; i < values.Size(); i+=2) cout << ", " << formatComplex(values[i], values[i+1]); cout << " )" << endl; } else { cout << sol.name << " = ( " << values[0]; for(int i = 1; i < values.Size(); i++) cout << ", " << values[i]; cout << " )" << endl; } }; Point<3> p; memcpy(select.transformationmat, transformationmat, sizeof(transformationmat)); memcpy(select.clipplane, clipplane, sizeof(clipplane)); select.center = center; select.rad = rad; select.enable_clipping_plane = vispar.clipping.enable; bool found_point = select.SelectSurfaceElement(GetMesh(), px, py, p, showclipsolution && clipsolution); selelement = select.selelement; if(!found_point) return; marker = p; // found point on clipping plane if(selelement==0) { GLint viewport[4]; GLdouble projection[16]; glGetDoublev(GL_PROJECTION_MATRIX, &projection[0]); glGetIntegerv(GL_VIEWPORT, &viewport[0]); Point<3> eye; gluUnProject( (viewport[2]-viewport[0])/2 , (viewport[3]-viewport[1])/2, 0.0, transformationmat, projection, viewport, &eye[0], &eye[1], &eye[2]); Vec<3> n{vispar.clipping.normal}; n.Normalize(); Vec<3> view = p-eye; // check if we look at the clipping plane from the right direction if(n*view > 1e-8) { double lami[3]; if(auto el3d = mesh->GetElementOfPoint( p, lami )) { cout << endl << "Selected point " << p << " on clipping plane" << endl; // marker = p; bool have_scal_func = scalfunction!=-1 && soldata[scalfunction]->draw_volume; // bool have_vec_func = vecfunction!=-1 && soldata[vecfunction]->draw_volume; if(have_scal_func) { auto & sol = *soldata[scalfunction]; double val; double imag = 0; int rcomponent = scalcomp; int comp = scalcomp; if(sol.iscomplex && rcomponent != 0) { rcomponent = 2 * ((rcomponent-1)/2) + 1; GetValue(&sol, el3d, lami[0], lami[1], lami[2], rcomponent+1, imag); comp = (scalcomp-1)/2 + 1; } GetValue(&sol, el3d, lami[0], lami[1], lami[2], rcomponent, val); printScalValue(sol, comp, val, imag, sol.iscomplex && comp > 0); } if(vecfunction!=-1 && soldata[vecfunction]->draw_volume) { auto & sol = *soldata[vecfunction]; ArrayMem values(sol.components); GetValues(&sol, el3d, lami[0], lami[1], lami[2], &values[0]); printVecValue(sol, values); } return; } } } double lami[3] = {0.0, 0.0, 0.0}; // Check if unprojected Point is close to surface element (eps of 1e-3 due to z-Buffer accuracy) bool found_2del = false; if(selelement>0 && mesh->PointContainedIn2DElement(p, lami, selelement-1, false && fabs(lami[2])<1e-3)) { // Found it, use coordinates of point projected to surface element mesh->GetCurvedElements().CalcSurfaceTransformation({1.0-lami[0]-lami[1], lami[0]}, selelement-1, p); found_2del = true; } cout << endl << "Selected point " << p << " on surface" << endl; if(!found_2del) return; bool have_scal_func = scalfunction!=-1 && soldata[scalfunction]->draw_surface; bool have_vec_func = vecfunction!=-1 && soldata[vecfunction]->draw_surface; if(have_scal_func) { auto & sol = *soldata[scalfunction]; double val; double imag = 0; int rcomponent = scalcomp; int comp = scalcomp; if(sol.iscomplex && rcomponent != 0) { rcomponent = 2 * ((rcomponent-1)/2) + 1; GetSurfValue(&sol, selelement-1, -1, 1.0-lami[0]-lami[1], lami[0], rcomponent+1, imag); comp = (scalcomp-1)/2 + 1; } GetSurfValue(&sol, selelement-1, -1, 1.0-lami[0]-lami[1], lami[0], rcomponent, val); printScalValue(sol, comp, val, imag, sol.iscomplex && comp > 0); } if(have_vec_func) { auto & sol = *soldata[vecfunction]; ArrayMem values(sol.components); GetSurfValues(&sol, selelement-1, -1, 1.0-lami[0]-lami[1], lami[0], &values[0]); printVecValue(sol, values); } } #ifdef PARALLELGL void VisualSceneSolution :: Broadcast () { NG_MPI_Datatype type; int blocklen[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1 }; NG_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, (char*)&deform - (char*)this, (char*)&scaledeform - (char*)this }; NG_MPI_Datatype types[] = { NG_MPI_INT, NG_MPI_INT, NG_MPI_INT, NG_MPI_INT, NG_MPI_INT, NG_MPI_INT, NG_MPI_INT, NG_MPI_INT, NG_MPI_DOUBLE, NG_MPI_DOUBLE, NG_MPI_INT, NG_MPI_INT, NG_MPI_INT, NG_MPI_DOUBLE, NG_MPI_INT, NG_MPI_INT, NG_MPI_DOUBLE }; NG_MPI_Type_create_struct (17, blocklen, displ, types, &type); NG_MPI_Type_commit ( &type ); NG_MPI_Bcast (this, 1, type, 0, NG_MPI_COMM_WORLD); NG_MPI_Type_free (&type); } #endif } #include "../include/nginterface.h" void Impl_Ng_ClearSolutionData () { #ifdef OPENGL // if (nodisplay) return; // netgen::vssolution.ClearSolutionData(); netgen::GetVSSolution().ClearSolutionData(); #endif } void Impl_Ng_InitSolutionData (Ng_SolutionData * soldata) { // soldata -> name = NULL; soldata -> data = NULL; soldata -> components = 1; soldata -> dist = 1; soldata -> order = 1; soldata -> iscomplex = 0; soldata -> draw_surface = 1; soldata -> draw_volume = 1; soldata -> draw_surfaces = nullptr; soldata -> draw_volumes = nullptr; soldata -> soltype = NG_SOLUTION_NODAL; soldata -> solclass = 0; } void Impl_Ng_SetSolutionData (Ng_SolutionData * soldata) { #ifdef OPENGL // if (nodisplay) return; // vssolution.ClearSolutionData (); netgen::VisualSceneSolution::SolData * vss = new netgen::VisualSceneSolution::SolData; // vss->name = new char[strlen (soldata->name)+1]; // strcpy (vss->name, soldata->name); vss->name = soldata->name; vss->title = soldata->title; vss->number_format = soldata->number_format; vss->unit = soldata->unit; vss->data = soldata->data; vss->components = soldata->components; vss->dist = soldata->dist; vss->order = soldata->order; vss->iscomplex = bool(soldata->iscomplex); vss->draw_surface = soldata->draw_surface; vss->draw_volume = soldata->draw_volume; vss->draw_surfaces = soldata->draw_surfaces; vss->draw_volumes = soldata->draw_volumes; vss->soltype = netgen::VisualSceneSolution::SolType (soldata->soltype); vss->solclass = soldata->solclass; // netgen::vssolution.AddSolutionData (vss); netgen::GetVSSolution().AddSolutionData (vss); #endif } void Impl_Ng_Redraw (bool blocking) { #ifdef OPENGL //netgen::vssolution.UpdateSolutionTimeStamp(); netgen::GetVSSolution().UpdateSolutionTimeStamp(); netgen::Render(blocking); #endif } #ifdef OPENGL #ifdef WIN32 void (*glBindBuffer) (GLenum a, GLuint b); void (*glDeleteBuffers) (GLsizei a, const GLuint *b); void (*glGenBuffers) (GLsizei a, GLuint *b); void (*glBufferData) (GLenum a, GLsizeiptr b, const GLvoid *c, GLenum d); void (*glBufferSubData) (GLenum a, GLintptr b, GLsizeiptr c, const GLvoid *d); GLenum (*glCheckFramebufferStatus) (GLenum target); void (*glBindFramebuffer) (GLenum target, GLuint framebuffer); void (*glBindRenderbuffer) (GLenum target, GLuint renderbuffer); void (*glDeleteFramebuffers) (GLsizei n, const GLuint *framebuffers); void (*glDeleteRenderbuffers) (GLsizei n, const GLuint *renderbuffers); void (*glGenFramebuffers) (GLsizei n, GLuint *framebuffers); void (*glGenRenderbuffers) (GLsizei n, GLuint *renderbuffers); void (*glRenderbufferStorage) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); void (*glFramebufferRenderbuffer) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); NGGUI_API void LoadOpenGLFunctionPointers() { #ifdef USE_BUFFERS glBindBuffer = (decltype(glBindBuffer)) wglGetProcAddress("glBindBuffer"); glBufferSubData = (decltype(glBufferSubData)) wglGetProcAddress("glBufferSubData"); glBufferData = (decltype(glBufferData)) wglGetProcAddress("glBufferData"); glDeleteBuffers = (decltype(glDeleteBuffers)) wglGetProcAddress("glDeleteBuffers"); glGenBuffers = (decltype(glGenBuffers)) wglGetProcAddress("glGenBuffers"); if(!glBindBuffer) throw std::runtime_error("Could not load OpenGL functions!"); #endif glCheckFramebufferStatus = (decltype(glCheckFramebufferStatus )) wglGetProcAddress("glCheckFramebufferStatus"); glBindFramebuffer = (decltype(glBindFramebuffer )) wglGetProcAddress("glBindFramebuffer"); glBindRenderbuffer = (decltype(glBindRenderbuffer )) wglGetProcAddress("glBindRenderbuffer"); glDeleteFramebuffers = (decltype(glDeleteFramebuffers )) wglGetProcAddress("glDeleteFramebuffers"); glDeleteRenderbuffers = (decltype(glDeleteRenderbuffers )) wglGetProcAddress("glDeleteRenderbuffers"); glGenFramebuffers = (decltype(glGenFramebuffers )) wglGetProcAddress("glGenFramebuffers"); glGenRenderbuffers = (decltype(glGenRenderbuffers )) wglGetProcAddress("glGenRenderbuffers"); glRenderbufferStorage = (decltype(glRenderbufferStorage )) wglGetProcAddress("glRenderbufferStorage"); glFramebufferRenderbuffer = (decltype(glFramebufferRenderbuffer )) wglGetProcAddress("glFramebufferRenderbuffer"); } #else // WIN32 NGGUI_API void LoadOpenGLFunctionPointers() { } #endif // WIN32 #endif // OPENGL // set function pointers static bool dummy_init = [](){ Ptr_Ng_ClearSolutionData = Impl_Ng_ClearSolutionData; Ptr_Ng_InitSolutionData = Impl_Ng_InitSolutionData; Ptr_Ng_SetSolutionData = Impl_Ng_SetSolutionData; Ptr_Ng_Redraw = Impl_Ng_Redraw; return true; }(); ================================================ FILE: libsrc/visualization/vssolution.hpp ================================================ #ifndef FILE_VSSOLUTION #define FILE_VSSOLUTION #include "visual_api.hpp" #include "mvdraw.hpp" typedef void * ClientData; struct Tcl_Interp; namespace netgen { NGGUI_API extern void ImportSolution (const char * filename); extern int Ng_Vis_Set (ClientData clientData, Tcl_Interp * interp, int argc, const char *argv[]); class NGGUI_API 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; }; #ifndef WIN32 // use OpenGL vertex buffers from OpenGL 2.x // not supported by some drivers on windows // try on your own responsibility #define USE_BUFFERS #endif #ifdef USE_BUFFERS bool has_surfel_vbo = false; GLuint surfel_vbo[4]; // size_t surfel_vbo_size; #endif int surfellist; int linelist; int element1dlist; int clipplanelist_scal; int clipplanelist_vec; int isolinelist; int clipplane_isolinelist; int surface_vector_list; // int cone_list; int isosurface_list; int select_sel_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; NgArray 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 timetimestamp; double minval, maxval; int scalfunction, vecfunction; string number_format = "%8.3e"; string unit = ""; string title = ""; NgLock *lock; VisualSelect select; #ifdef PARALLELGL NgArray par_linelists; NgArray par_surfellists; #endif NgArray user_vis; 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 (); string name; string number_format = "%8.3e"; string unit = ""; string title = ""; double * data; int components; int dist; int order; bool iscomplex; bool draw_volume; bool draw_surface; std::shared_ptr draw_volumes, draw_surfaces; SolType soltype; SolutionData * solclass; // internal variables: int size; }; NgArray soldata; int usetexture; // 0..no, 1..1D texture (standard), 2..2D-texture (complex) int clipsolution; // 0..no, 1..scal, 2..vec int scalcomp; int gridsize; double xoffset, yoffset; int autoscale, logscale; double mminval, mmaxval; int numisolines; 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> & startpoints); void BuildFieldLinesFromFace(Array> & startpoints); void BuildFieldLinesFromBox(Array> & startpoints); void BuildFieldLinesFromLine(Array> & startpoints); // weak_ptr wp_mesh; public: VisualSceneSolution (); virtual ~VisualSceneSolution (); virtual void BuildScene (int zoomall = 0); virtual void DrawScene (); void BuildSelectionList(); virtual void MouseDblClick (int px, int py); // void SetMesh (shared_ptr amesh); // shared_ptr GetMesh () { return shared_ptr(wp_mesh); } shared_ptr GetMesh () const { return GetGlobalMesh(); } 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 Vec<3> RealVec3d (const double * values, 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; void AddUserVisualizationObject (UserVisualizationObject * vis) { user_vis.Append (vis); } void DeleteUserVisualizationObject (UserVisualizationObject * vis) { int pos = user_vis.Pos(vis); if (pos >= 0) user_vis.Delete(pos); } private: void GetClippingPlaneTrigs (SolData * sol, NgArray & trigs, NgArray & pts); void GetClippingPlaneGrid (NgArray & 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); bool SurfaceElementActive(const SolData *data, const Mesh & mesh, const Element2d & sei) const; bool VolumeElementActive(const SolData *data, const Mesh & mesh, const Element & ei) const; // 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 & 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 facetnr, 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, int facetnr, double lam1, double lam2, int comp, double & val) const; bool GetSurfValue (const SolData * data, SurfaceElementIndex elnr, int facetnr, const double xref[], const double x[], const double dxdxref[], int comp, double & val) const; bool GetSurfValueComplex (const SolData * data, SurfaceElementIndex elnr, int facetnr, double lam1, double lam2, int comp, complex & val) const; bool GetSurfValues (const SolData * data, SurfaceElementIndex elnr, int facetnr, double lam1, double lam2, double * values) const; bool GetSurfValues (const SolData * data, SurfaceElementIndex elnr, int facetnr, const double xref[], const double x[], const double dxdxref[], double * values) const; bool GetMultiSurfValues (const SolData * data, SurfaceElementIndex elnr, int facetnr, 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 ExtractValueComplex (const SolData * data, int comp, double * values) const; Vec<3> GetDeformation (ElementIndex elnr, const Point<3> & p) const; Vec<3> GetSurfDeformation (SurfaceElementIndex selnr, int facetnr, double lam1, double lam2) const; void GetPointDeformation (PointIndex pnum, Point<3> & p, SurfaceElementIndex elnr = -1) const; public: /// draw elements (build lists) void DrawSurfaceElements (); void DrawSurfaceElementLines (); void Draw1DElements(); void DrawSurfaceVectors (); void DrawTrigSurfaceVectors(const NgArray< Point<3> > & lp, const Point<3> & pmin, const Point<3> & pmax, const int sei, const SolData * vsol, bool swap_lam=false); 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; friend int Ng_Vis_Set (ClientData clientData, Tcl_Interp * interp, int argc, const char *argv[]); void SetScalfunction( int i ) { scalfunction = i; title = soldata[i]->title; number_format = soldata[i]->number_format; unit = soldata[i]->unit; } void SetVecfunction( int i ) { vecfunction = i; title = soldata[i]->title; number_format = soldata[i]->number_format; unit = soldata[i]->unit; } SolData* GetScalFunction() const { return scalfunction == -1 ? nullptr : soldata[scalfunction]; } SolData* GetVecFunction() const { return vecfunction == -1 ? nullptr : soldata[vecfunction]; } SolData* GetScalOrVecFunction() const { auto sol = GetScalFunction(); return sol ? sol : GetVecFunction(); } #ifdef PARALLELGL void Broadcast (); #endif }; NGGUI_API VisualSceneSolution & GetVSSolution(); inline void AddUserVisualizationObject (UserVisualizationObject * vis) { GetVSSolution().AddUserVisualizationObject (vis); } inline void DeleteUserVisualizationObject (UserVisualizationObject * vis) { GetVSSolution().DeleteUserVisualizationObject (vis); } } #endif ================================================ FILE: mkinstalldirs ================================================ #! /bin/sh # mkinstalldirs --- make directory hierarchy # Author: Noah Friedman # Created: 1993-05-16 # Public domain errstatus=0 dirmode="" usage="\ Usage: mkinstalldirs [-h] [--help] [-m mode] dir ..." # process command line arguments while test $# -gt 0 ; do case $1 in -h | --help | --h*) # -h for help echo "$usage" 1>&2 exit 0 ;; -m) # -m PERM arg shift test $# -eq 0 && { echo "$usage" 1>&2; exit 1; } dirmode=$1 shift ;; --) # stop option processing shift break ;; -*) # unknown option echo "$usage" 1>&2 exit 1 ;; *) # first non-opt arg break ;; esac done for file do if test -d "$file"; then shift else break fi done case $# in 0) exit 0 ;; esac case $dirmode in '') if mkdir -p -- . 2>/dev/null; then echo "mkdir -p -- $*" exec mkdir -p -- "$@" fi ;; *) if mkdir -m "$dirmode" -p -- . 2>/dev/null; then echo "mkdir -m $dirmode -p -- $*" exec mkdir -m "$dirmode" -p -- "$@" fi ;; esac for file do set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'` shift pathcomp= for d do pathcomp="$pathcomp$d" case $pathcomp in -*) pathcomp=./$pathcomp ;; esac if test ! -d "$pathcomp"; then echo "mkdir $pathcomp" mkdir "$pathcomp" || lasterr=$? if test ! -d "$pathcomp"; then errstatus=$lasterr else if test ! -z "$dirmode"; then echo "chmod $dirmode $pathcomp" lasterr="" chmod "$dirmode" "$pathcomp" || lasterr=$? if test ! -z "$lasterr"; then errstatus=$lasterr fi fi fi fi pathcomp="$pathcomp/" done done exit $errstatus # Local Variables: # mode: shell-script # sh-indentation: 2 # End: # mkinstalldirs ends here ================================================ FILE: ng/CMakeLists.txt ================================================ if(USE_INTERNAL_TCL) add_definitions(-DINTERNAL_TCL_DEFAULT=1) else() add_definitions(-DINTERNAL_TCL_DEFAULT=0) endif() if(WIN32) # add icon and version info to netgen executable enable_language(RC) # Don't use ccache here due to incompatibility with the resource compiler set_directory_properties(PROPERTIES RULE_LAUNCH_COMPILE "") endif(WIN32) target_sources(nglib PRIVATE onetcl.cpp) if(USE_GUI) target_sources(nggui PRIVATE gui.cpp ngpkg.cpp demoview.cpp parallelfunc.cpp ngtcl.cpp ) if(NOT BUILD_FOR_CONDA) add_executable(netgen ngappinit.cpp) if(WIN32) target_sources(netgen PRIVATE ../windows/netgen.rc) endif(WIN32) target_link_libraries( netgen nglib nggui netgen_python netgen_gui) install(TARGETS netgen ${NG_INSTALL_DIR}) if(APPLE) set_target_properties(netgen PROPERTIES OUTPUT_NAME netgen) endif(APPLE) target_link_libraries( netgen ${Python3_LIBRARIES} ${TCL_LIBRARY} ${TK_LIBRARY}) endif(NOT BUILD_FOR_CONDA) install(TARGETS nggui ${NG_INSTALL_DIR}) endif(USE_GUI) if(USE_PYTHON) add_library(ngpy SHARED netgenpy.cpp) target_link_libraries( ngpy PUBLIC nglib PRIVATE "$" ) target_link_libraries( ngpy PRIVATE ${CMAKE_THREAD_LIBS_INIT} ${JPEG_LIBRARIES} ${MKL_LIBRARIES} ${ZLIB_LIBRARIES} occ_libs netgen_cgns ) if(EMSCRIPTEN) target_link_options(ngpy PUBLIC -sALLOW_MEMORY_GROWTH -sENVIRONMENT=web -sWASM_BIGINT -fwasm-exceptions) endif() if(APPLE) set_target_properties( ngpy PROPERTIES SUFFIX ".so") elseif(WIN32) set_target_properties( ngpy PROPERTIES SUFFIX ".pyd") set_target_properties( ngpy PROPERTIES OUTPUT_NAME "libngpy") endif() set_target_properties(ngpy PROPERTIES INSTALL_RPATH "${NG_RPATH_TOKEN}/../${NETGEN_PYTHON_RPATH}") install(TARGETS ngpy DESTINATION ${NG_INSTALL_DIR_PYTHON}/${NG_INSTALL_SUFFIX} COMPONENT netgen EXPORT netgen-targets) if(USE_GUI) add_library(ngguipy SHARED ngguipy.cpp) target_link_libraries( ngguipy PUBLIC nglib nggui PRIVATE "$" $) if(APPLE) set_target_properties( ngguipy PROPERTIES SUFFIX ".so") elseif(WIN32) set_target_properties( ngguipy PROPERTIES SUFFIX ".pyd") set_target_properties( ngguipy PROPERTIES OUTPUT_NAME "libngguipy") endif() set_target_properties(ngguipy PROPERTIES INSTALL_RPATH "${NG_RPATH_TOKEN}/../${NETGEN_PYTHON_RPATH}") install(TARGETS ngguipy DESTINATION ${NG_INSTALL_DIR_PYTHON}/${NG_INSTALL_SUFFIX} COMPONENT netgen EXPORT netgen-targets) endif(USE_GUI) endif(USE_PYTHON) if(USE_GUI) if(NOT USE_INTERNAL_TCL) install(FILES dialog.tcl menustat.tcl ngicon.tcl ng.tcl ngvisual.tcl sockets.tcl nghelp.tcl ngshell.tcl ngtesting.tcl parameters.tcl variables.tcl csgeom.tcl stlgeom.tcl occgeom.tcl acisgeom.tcl netgen.ocf drawing.tcl DESTINATION ${NG_INSTALL_DIR_BIN} COMPONENT netgen) endif() add_subdirectory(Togl2.1) endif(USE_GUI) ================================================ FILE: ng/Togl2.1/CMakeLists.txt ================================================ if(APPLE) set(CMAKE_C_COMPILER "/usr/bin/gcc") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -x objective-c") endif(APPLE) if(WIN32) set(TOGL_LIBRARY_TYPE SHARED) else(WIN32) set(TOGL_LIBRARY_TYPE STATIC) endif(WIN32) add_library(togl ${TOGL_LIBRARY_TYPE} togl.c toglProcAddr.c toglStubInit.c) target_link_libraries( togl PUBLIC $) target_compile_definitions(togl PRIVATE -DBUILD_togl=1 -DSTDC_HEADERS=1) if(WIN32) target_compile_definitions(togl PRIVATE -DUNICODE -D_UNICODE -DTOGL_USE_FONTS=0 -DSTDC_HEADER) else(WIN32) target_compile_options(togl PRIVATE -fomit-frame-pointer -Wno-implicit-int) target_compile_definitions(togl PRIVATE -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=0 -DHAVE_LIMITS_H=1 -DHAVE_SYS_PARAM_H=1 -DUSE_THREAD_ALLOC=1 -D_REENTRANT=1 -D_THREAD_SAFE=1 -DTCL_THREADS=1 -D_LARGEFILE64_SOURCE=1 -DTCL_WIDE_INT_IS_LONG=1) include_directories(BEFORE "${TCL_INCLUDE_PATH}/tcl-private/generic" "${TCL_INCLUDE_PATH}/tcl-private/unix") include_directories(BEFORE "${TK_INCLUDE_PATH}/tk-private/generic" "${TK_INCLUDE_PATH}/tk-private/unix" "${TK_INCLUDE_PATH}/tk-private") include_directories(BEFORE "${TCL_INCLUDE_PATH}/tk-private/generic/ttk") include_directories(BEFORE "${TK_INCLUDE_PATH}/../PrivateHeaders") include_directories(BEFORE "${TCL_INCLUDE_PATH}") include_directories(BEFORE "${TK_INCLUDE_PATH}") endif(WIN32) target_include_directories(togl PUBLIC ${OPENGL_INCLUDE_DIR}) target_link_libraries(togl PUBLIC ${OPENGL_LIBRARY}) set_target_properties(togl PROPERTIES POSITION_INDEPENDENT_CODE ON ) install(TARGETS togl DESTINATION ${NG_INSTALL_DIR} COMPONENT netgen) ================================================ FILE: ng/Togl2.1/LICENSE ================================================ This software is copyrighted by Brian Paul (brian@mesa3d.org), Benjamin Bederson (bederson@cs.umd.edu), and Greg Couch (gregcouch@users.sourceforge.net). The following terms apply to all files associated with the software unless explicitly disclaimed in individual files. The authors hereby grant permission to use, copy, modify, distribute, and license this software and its documentation for any purpose, provided that existing copyright notices are retained in all copies and that this notice is included verbatim in any distributions. No written agreement, license, or royalty fee is required for any of the authorized uses. Modifications to this software may be copyrighted by their authors and need not follow the licensing terms described here, provided that the new terms are clearly indicated on the first page of each file where they apply. IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. ================================================ FILE: ng/Togl2.1/Makefile.in ================================================ # Makefile.in -- # # This file is a Makefile for Sample TEA Extension. If it has the name # "Makefile.in" then it is a template for a Makefile; to generate the # actual Makefile, run "./configure", which is a configuration script # generated by the "autoconf" program (constructs like "@foo@" will get # replaced in the actual Makefile. # # Copyright (c) 1999 Scriptics Corporation. # Copyright (c) 2002-2005 ActiveState Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # # RCS: @(#) $Id: Makefile.in,v 1.26 2009/12/23 21:46:16 gregcouch Exp $ #======================================================================== # Add additional lines to handle any additional AC_SUBST cases that # have been added in a customized configure script. #======================================================================== #SAMPLE_NEW_VAR = @SAMPLE_NEW_VAR@ SHLIB_SUFFIX = @SHLIB_SUFFIX@ MATH_LIBS = @MATH_LIBS@ LIBGLU = @LIBGLU@ EXAMPLE_SRCS = double.c gears.c index.c overlay.c stereo.c texture.c pbuffer.c EXAMPLE_OBJS = $(EXAMPLE_SRCS:.c=.$(OBJEXT)) EXAMPLE_SHLIBS = $(EXAMPLE_SRCS:.c=$(SHLIB_SUFFIX)) #======================================================================== # Nothing of the variables below this line should need to be changed. # Please check the TARGETS section below to make sure the make targets # are correct. #======================================================================== #======================================================================== # The names of the source files is defined in the configure script. # The object files are used for linking into the final library. # This will be used when a dist target is added to the Makefile. # It is not important to specify the directory, as long as it is the # $(srcdir) or in the generic, win or unix subdirectory. #======================================================================== PKG_SOURCES = @PKG_SOURCES@ PKG_OBJECTS = @PKG_OBJECTS@ PKG_STUB_SOURCES = @PKG_STUB_SOURCES@ PKG_STUB_OBJECTS = @PKG_STUB_OBJECTS@ #======================================================================== # PKG_TCL_SOURCES identifies Tcl runtime files that are associated with # this package that need to be installed, if any. #======================================================================== PKG_TCL_SOURCES = @PKG_TCL_SOURCES@ #======================================================================== # This is a list of public header files to be installed, if any. #======================================================================== PKG_HEADERS = @PKG_HEADERS@ togl_ws.h #======================================================================== # "PKG_LIB_FILE" refers to the library (dynamic or static as per # configuration options) composed of the named objects. #======================================================================== PKG_LIB_FILE = @PKG_LIB_FILE@ PKG_STUB_LIB_FILE = @PKG_STUB_LIB_FILE@ pkglib_BINARIES = $(PKG_LIB_FILE) lib_BINARIES = $(PKG_STUB_LIB_FILE) BINARIES = $(pkglib_BINARIES) $(lib_BINARIES) SHELL = @SHELL@ srcdir = @srcdir@ prefix = @prefix@ exec_prefix = @exec_prefix@ bindir = @bindir@ libdir = @libdir@ includedir = @includedir@ datarootdir = @datarootdir@ datadir = @datadir@ mandir = @mandir@ DESTDIR = PKG_DIR = $(PACKAGE_NAME)$(PACKAGE_VERSION) pkgdatadir = $(datadir)/$(PKG_DIR) pkglibdir = $(libdir)/$(PKG_DIR) pkgincludedir = $(includedir)/$(PKG_DIR) top_builddir = . INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_VERSION = @PACKAGE_VERSION@ CC = @CC@ CFLAGS_DEFAULT = @CFLAGS_DEFAULT@ CFLAGS_WARNING = @CFLAGS_WARNING@ EXEEXT = @EXEEXT@ LDFLAGS_DEFAULT = @LDFLAGS_DEFAULT@ MAKE_LIB = @MAKE_LIB@ MAKE_SHARED_LIB = @MAKE_SHARED_LIB@ MAKE_STATIC_LIB = @MAKE_STATIC_LIB@ MAKE_STUB_LIB = @MAKE_STUB_LIB@ OBJEXT = @OBJEXT@ RANLIB = @RANLIB@ RANLIB_STUB = @RANLIB_STUB@ SHLIB_CFLAGS = @SHLIB_CFLAGS@ SHLIB_LD = @SHLIB_LD@ SHLIB_LD_LIBS = @SHLIB_LD_LIBS@ STLIB_LD = @STLIB_LD@ #TCL_DEFS = @TCL_DEFS@ TCL_BIN_DIR = @TCL_BIN_DIR@ TCL_SRC_DIR = @TCL_SRC_DIR@ #TK_BIN_DIR = @TK_BIN_DIR@ #TK_SRC_DIR = @TK_SRC_DIR@ # Not used, but retained for reference of what libs Tcl required #TCL_LIBS = @TCL_LIBS@ #======================================================================== # TCLLIBPATH seeds the auto_path in Tcl's init.tcl so we can test our # package without installing. The other environment variables allow us # to test against an uninstalled Tcl. Add special env vars that you # require for testing here (like TCLX_LIBRARY). #======================================================================== #EXTRA_PATH = $(top_builddir):$(TCL_BIN_DIR) EXTRA_PATH = $(top_builddir):$(TCL_BIN_DIR):$(TK_BIN_DIR) TCLLIBPATH = $(top_builddir) TCLSH_ENV = TCL_LIBRARY=`@CYGPATH@ $(TCL_SRC_DIR)/library` \ @LD_LIBRARY_PATH_VAR@="$(EXTRA_PATH):$(@LD_LIBRARY_PATH_VAR@)" \ PATH="$(EXTRA_PATH):$(PATH)" \ TCLLIBPATH="$(TCLLIBPATH)" # TK_LIBRARY=`@CYGPATH@ $(TK_SRC_DIR)/library` TCLSH_PROG = @TCLSH_PROG@ TCLSH = $(TCLSH_ENV) $(TCLSH_PROG) WISH_PROG = @WISH_PROG@ WISH = $(TCLSH_ENV) $(WISH_PROG) SHARED_BUILD = @SHARED_BUILD@ INCLUDES = -I. @PKG_INCLUDES@ @TCL_INCLUDES@ @TK_INCLUDES@ @TK_XINCLUDES@ PKG_CFLAGS = @PKG_CFLAGS@ # TCL_DEFS is not strictly need here, but if you remove it, then you # must make sure that configure.in checks for the necessary components # that your library may use. TCL_DEFS can actually be a problem if # you do not compile with a similar machine setup as the Tcl core was # compiled with. #DEFS = $(TCL_DEFS) @DEFS@ $(PKG_CFLAGS) DEFS = @DEFS@ -DAUTOSTEREOD=\"@AUTOSTEREOD@\" $(PKG_CFLAGS) CONFIG_CLEAN_FILES = Makefile pkgIndex.tcl togl_ws.h CLEANFILES = @CLEANFILES@ $(EXAMPLE_OBJS) $(EXAMPLE_SHLIBS) CPPFLAGS = @CPPFLAGS@ LIBS = @PKG_LIBS@ @LIBS@ AR = @AR@ CFLAGS = @CFLAGS@ COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) #======================================================================== # Start of user-definable TARGETS section #======================================================================== #======================================================================== # TEA TARGETS. Please note that the "libraries:" target refers to platform # independent files, and the "binaries:" target includes executable programs and # platform-dependent libraries. Modify these targets so that they install # the various pieces of your package. The make and install rules # for the BINARIES that you specified above have already been done. #======================================================================== all: binaries libraries doc #======================================================================== # The binaries target builds executable programs, Windows .dll's, unix # shared/static libraries, and any other platform-dependent files. # The list of targets to build for "binaries:" is specified at the top # of the Makefile, in the "BINARIES" variable. #======================================================================== binaries: $(BINARIES) libraries: #======================================================================== # Example section. These are examples because we don't want to install them. # And they're not tests because we currently have no automatic way to see # if they work. #======================================================================== examples: $(EXAMPLE_SHLIBS) double$(SHLIB_SUFFIX): double.$(OBJEXT) $(PKG_STUB_LIB_FILE) -match=`expr 'x$(PKG_OBJECTS)' : '.*togl.*'`; \ if [ $$match -eq 0 ]; then \ $(MAKE_SHARED_LIB) ; \ else \ $(MAKE) PKG_OBJECTS="double.$(OBJEXT) $(PKG_STUB_LIB_FILE)" $@ ; \ fi gears$(SHLIB_SUFFIX): gears.$(OBJEXT) $(PKG_STUB_LIB_FILE) -match=`expr 'x$(PKG_OBJECTS)' : '.*togl.*'`; \ if [ $$match -eq 0 ]; then \ $(MAKE_SHARED_LIB) ; \ else \ $(MAKE) PKG_OBJECTS="gears.$(OBJEXT) $(PKG_STUB_LIB_FILE)" $@ ; \ fi index$(SHLIB_SUFFIX): index.$(OBJEXT) $(PKG_STUB_LIB_FILE) -match=`expr 'x$(PKG_OBJECTS)' : '.*togl.*'`; \ if [ $$match -eq 0 ]; then \ $(MAKE_SHARED_LIB) ; \ else \ $(MAKE) PKG_OBJECTS="index.$(OBJEXT) $(PKG_STUB_LIB_FILE)" $@ ; \ fi overlay$(SHLIB_SUFFIX): overlay.$(OBJEXT) $(PKG_STUB_LIB_FILE) -match=`expr 'x$(PKG_OBJECTS)' : '.*togl.*'`; \ if [ $$match -eq 0 ]; then \ $(MAKE_SHARED_LIB) ; \ else \ $(MAKE) PKG_OBJECTS="overlay.$(OBJEXT) $(PKG_STUB_LIB_FILE)" $@ ; \ fi stereo$(SHLIB_SUFFIX): stereo.$(OBJEXT) $(PKG_STUB_LIB_FILE) -match=`expr 'x$(PKG_OBJECTS)' : '.*togl.*'`; \ if [ $$match -eq 0 ]; then \ $(MAKE_SHARED_LIB) ; \ else \ $(MAKE) PKG_OBJECTS="stereo.$(OBJEXT) $(PKG_STUB_LIB_FILE)" $@ ; \ fi texture$(SHLIB_SUFFIX): texture.$(OBJEXT) image.$(OBJEXT) $(PKG_STUB_LIB_FILE) -match=`expr 'x$(PKG_OBJECTS)' : '.*togl.*'`; \ if [ $$match -eq 0 ]; then \ $(MAKE_SHARED_LIB) ; \ else \ $(MAKE) PKG_OBJECTS="texture.$(OBJEXT) image.$(OBJEXT) $(PKG_STUB_LIB_FILE) $(LIBGLU)" $@ ; \ fi pbuffer$(SHLIB_SUFFIX): pbuffer.$(OBJEXT) $(PKG_STUB_LIB_FILE) -match=`expr 'x$(PKG_OBJECTS)' : '.*togl.*'`; \ if [ $$match -eq 0 ]; then \ $(MAKE_SHARED_LIB) ; \ else \ $(MAKE) PKG_OBJECTS="pbuffer.$(OBJEXT) $(PKG_STUB_LIB_FILE) $(LIBGLU)" $@ ; \ fi #======================================================================== # Stub section. #======================================================================== toglDecls.h toglStubInit.c: togl.decls $(TCLSH) `@CYGPATH@ $(TCL_SRC_DIR)/tools/genStubs.tcl` . togl.decls #======================================================================== # Your doc target should differentiate from doc builds (by the developer) # and doc installs (see install-doc), which just install the docs on the # end user machine when building from source. #======================================================================== doc: # @echo "If you have documentation to create, place the commands to" # @echo "build the docs in the 'doc:' target. For example:" # @echo " xml2nroff sample.xml > sample.n" # @echo " xml2html sample.xml > sample.html" install: all install-binaries install-libraries install-doc install-binaries: binaries install-lib-binaries install-bin-binaries #======================================================================== # This rule installs platform-independent files, such as header files. # The list=...; for p in $$list handles the empty list case x-platform. #======================================================================== install-libraries: libraries @mkdir -p $(DESTDIR)$(includedir) @echo "Installing header files in $(DESTDIR)$(includedir)" @list='$(PKG_HEADERS)'; for i in $$list; do \ echo "Installing $(srcdir)/$$i" ; \ $(INSTALL_DATA) $(srcdir)/$$i $(DESTDIR)$(includedir) ; \ done #======================================================================== # Install documentation. Unix manpages should go in the $(mandir) # directory. #======================================================================== install-doc: doc # @mkdir -p $(DESTDIR)$(mandir)/mann # @echo "Installing documentation in $(DESTDIR)$(mandir)" # @list='$(srcdir)/doc/*.n'; for i in $$list; do \ # echo "Installing $$i"; \ # rm -f $(DESTDIR)$(mandir)/mann/`basename $$i`; \ # $(INSTALL_DATA) $$i $(DESTDIR)$(mandir)/mann ; \ # done test: binaries libraries $(TCLSH) `@CYGPATH@ $(srcdir)/tests/all.tcl` $(TESTFLAGS) shell: binaries libraries @$(TCLSH) $(SCRIPT) gdb: $(TCLSH_ENV) gdb $(TCLSH_PROG) $(SCRIPT) depend: #======================================================================== # $(PKG_LIB_FILE) should be listed as part of the BINARIES variable # mentioned above. That will ensure that this target is built when you # run "make binaries". # # The $(PKG_OBJECTS) objects are created and linked into the final # library. In most cases these object files will correspond to the # source files above. #======================================================================== $(PKG_LIB_FILE): $(PKG_OBJECTS) -rm -f $(PKG_LIB_FILE) ${MAKE_LIB} $(RANLIB) $(PKG_LIB_FILE) $(PKG_STUB_LIB_FILE): $(PKG_STUB_OBJECTS) -rm -f $(PKG_STUB_LIB_FILE) ${MAKE_STUB_LIB} $(RANLIB_STUB) $(PKG_STUB_LIB_FILE) #======================================================================== # We need to enumerate the list of .c to .o lines here. # # In the following lines, $(srcdir) refers to the toplevel directory # containing your extension. If your sources are in a subdirectory, # you will have to modify the paths to reflect this: # # sample.$(OBJEXT): $(srcdir)/generic/sample.c # $(COMPILE) -c `@CYGPATH@ $(srcdir)/generic/sample.c` -o $@ # # Setting the VPATH variable to a list of paths will cause the makefile # to look into these paths when resolving .c to .obj dependencies. # As necessary, add $(srcdir):$(srcdir)/compat:.... #======================================================================== VPATH = $(srcdir):Xmu .c.@OBJEXT@: $(COMPILE) -c `@CYGPATH@ $<` -o $@ #======================================================================== # Distribution creation # You may need to tweak this target to make it work correctly. #======================================================================== COMPRESS = tar zcvf $(PKG_DIR)-src.tar.gz $(PKG_DIR) DIST_ROOT = /tmp/togl-dist DIST_DIR = $(DIST_ROOT)/$(PKG_DIR) BINPKG_DIR = $(PKG_DIR)-@TCL_VERSION@-$(subst Darwin,MacOSX,$(subst CYGWIN,Windows,$(shell uname -s | sed -e 's/[-_].*//'))) BINDIST_DIR = $(DIST_ROOT)/$(BINPKG_DIR) dist-clean: rm -rf $(DIST_DIR) $(DIST_ROOT)/$(PKG_DIR)* dist: dist-clean mkdir -p $(DIST_DIR) cp -p $(srcdir)/README* $(srcdir)/LICENSE* $(srcdir)/togl.decls \ $(srcdir)/*.py $(srcdir)/*.tcl \ $(srcdir)/aclocal.m4 $(srcdir)/configure $(srcdir)/*.in \ ben.rgb tree2.rgba \ $(DIST_DIR)/ chmod 664 $(DIST_DIR)/* chmod 775 $(DIST_DIR)/configure $(DIST_DIR)/configure.in for i in $(srcdir)/*.[ch]; do \ if [ -f $$i ]; then \ cp -p $$i $(DIST_DIR)/ ; \ fi; \ done cd $(DIST_DIR); rm -f $(CONFIG_CLEAN_FILES) mkdir $(DIST_DIR)/tclconfig cp $(srcdir)/tclconfig/install-sh $(srcdir)/tclconfig/tcl.m4 \ $(DIST_DIR)/tclconfig/ chmod 664 $(DIST_DIR)/tclconfig/tcl.m4 chmod +x $(DIST_DIR)/tclconfig/install-sh list='examples doc tests Xmu GL'; \ for p in $$list; do \ if test -d $(srcdir)/$$p ; then \ mkdir $(DIST_DIR)/$$p; \ cp -p $(srcdir)/$$p/*.* $(DIST_DIR)/$$p/; \ fi; \ done (cd $(DIST_ROOT); $(COMPRESS);) bindist-clean: rm -rf $(BINDIST_DIR) $(DIST_ROOT)/$(PKG_DIR)* bindist: all bindist-clean mkdir -p $(BINDIST_DIR) $(MAKE) prefix=$(BINDIST_DIR) exec_prefix=$(BINDIST_DIR) install $(INSTALL_DATA) README.bin $(BINDIST_DIR)/README.txt mkdir -p $(BINDIST_DIR)/doc @list='doc/*.html doc/*.js'; for i in $$list; do \ echo "Installing $$i"; \ rm -f $(BINDIST_DIR)/doc/`basename $$i`; \ $(INSTALL_DATA) $$i $(BINDIST_DIR)/doc ; \ done if [ @TOGL_WINDOWINGSYSTEM@ == TOGL_WGL ]; then \ (cd $(DIST_ROOT); zip -rDX9 $(BINPKG_DIR).zip $(BINPKG_DIR)); \ else \ (cd $(DIST_ROOT); tar zcvf $(BINPKG_DIR).tar.gz $(BINPKG_DIR)); \ fi #======================================================================== # End of user-definable section #======================================================================== #======================================================================== # Don't modify the file to clean here. Instead, set the "CLEANFILES" # variable in configure.in #======================================================================== clean: -test -z "$(BINARIES)" || rm -f $(BINARIES) -rm -f *.$(OBJEXT) core *.core -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean: clean -rm -f *.tab.c -rm -f $(CONFIG_CLEAN_FILES) -rm -f config.cache config.log config.status #======================================================================== # Install binary object libraries. On Windows this includes both .dll and # .lib files. Because the .lib files are not explicitly listed anywhere, # we need to deduce their existence from the .dll file of the same name. # Library files go into the lib directory. # In addition, this will generate the pkgIndex.tcl # file in the install location (assuming it can find a usable tclsh shell) # # You should not have to modify this target. #======================================================================== install-lib-binaries: binaries @mkdir -p $(DESTDIR)$(libdir) @list='$(lib_BINARIES)'; for p in $$list; do \ if test -f $$p; then \ echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(libdir)/$$p"; \ $(INSTALL_PROGRAM) $$p $(DESTDIR)$(libdir)/$$p; \ stub=`echo $$p|sed -e "s/.*\(stub\).*/\1/"`; \ if test "x$$stub" = "xstub"; then \ echo " $(RANLIB_STUB) $(DESTDIR)$(libdir)/$$p"; \ $(RANLIB_STUB) $(DESTDIR)$(libdir)/$$p; \ else \ echo " $(RANLIB) $(DESTDIR)$(libdir)/$$p"; \ $(RANLIB) $(DESTDIR)$(libdir)/$$p; \ fi; \ ext=`echo $$p|sed -e "s/.*\.//"`; \ if test "x$$ext" = "xdll"; then \ lib=`basename $$p|sed -e 's/.[^.]*$$//'`.lib; \ if test -f $$lib; then \ echo " $(INSTALL_DATA) $$lib $(DESTDIR)$(libdir)/$$lib"; \ $(INSTALL_DATA) $$lib $(DESTDIR)$(libdir)/$$lib; \ fi; \ fi; \ fi; \ done @mkdir -p $(DESTDIR)$(pkglibdir) @list='$(pkglib_BINARIES)'; for p in $$list; do \ if test -f $$p; then \ echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(pkglibdir)/$$p"; \ $(INSTALL_PROGRAM) $$p $(DESTDIR)$(pkglibdir)/$$p; \ stub=`echo $$p|sed -e "s/.*\(stub\).*/\1/"`; \ if test "x$$stub" = "xstub"; then \ echo " $(RANLIB_STUB) $(DESTDIR)$(pkglibdir)/$$p"; \ $(RANLIB_STUB) $(DESTDIR)$(pkglibdir)/$$p; \ else \ echo " $(RANLIB) $(DESTDIR)$(pkglibdir)/$$p"; \ $(RANLIB) $(DESTDIR)$(pkglibdir)/$$p; \ fi; \ ext=`echo $$p|sed -e "s/.*\.//"`; \ if test "x$$ext" = "xdll"; then \ lib=`basename $$p|sed -e 's/.[^.]*$$//'`.lib; \ if test -f $$lib; then \ echo " $(INSTALL_DATA) $$lib $(DESTDIR)$(pkglibdir)/$$lib"; \ $(INSTALL_DATA) $$lib $(DESTDIR)$(pkglibdir)/$$lib; \ fi; \ fi; \ fi; \ done @list='$(PKG_TCL_SOURCES)'; for p in $$list; do \ if test -f $(srcdir)/$$p; then \ destp=`basename $$p`; \ echo " Install $$destp $(DESTDIR)$(pkglibdir)/$$destp"; \ $(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(pkglibdir)/$$destp; \ fi; \ done @if test "x$(SHARED_BUILD)" = "x1"; then \ echo " Install pkgIndex.tcl $(DESTDIR)$(pkglibdir)"; \ $(INSTALL_DATA) pkgIndex.tcl $(DESTDIR)$(pkglibdir); \ echo " Install LICENSE $(DESTDIR)$(pkglibdir)"; \ $(INSTALL_DATA) LICENSE $(DESTDIR)$(pkglibdir); \ else \ echo " Install LICENSE.togl $(DESTDIR)$(libdir)"; \ $(INSTALL_DATA) LICENSE $(DESTDIR)$(libdir)/LICENSE.togl; \ fi #======================================================================== # Install binary executables (e.g. .exe files and dependent .dll files) # This is for files that must go in the bin directory (located next to # wish and tclsh), like dependent .dll files on Windows. # # You should not have to modify this target, except to define bin_BINARIES # above if necessary. #======================================================================== install-bin-binaries: binaries @mkdir -p $(DESTDIR)$(bindir) @list='$(bin_BINARIES)'; for p in $$list; do \ if test -f $$p; then \ echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/$$p"; \ $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/$$p; \ fi; \ done .SUFFIXES: .c .$(OBJEXT) Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status cd $(top_builddir) \ && CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status uninstall-binaries: list='$(pkglib_BINARIES)'; for p in $$list; do \ rm -f $(DESTDIR)$(pkglibdir)/$$p; \ done list='$(lib_BINARIES)'; for p in $$list; do \ rm -f $(DESTDIR)$(libdir)/$$p; \ done list='$(PKG_TCL_SOURCES)'; for p in $$list; do \ p=`basename $$p`; \ rm -f $(DESTDIR)$(pkglibdir)/$$p; \ done list='$(bin_BINARIES)'; for p in $$list; do \ rm -f $(DESTDIR)$(bindir)/$$p; \ done .PHONY: all binaries clean depend distclean doc install libraries test # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: # Additional dependencies togl.$(OBJEXT): toglFont.c toglAGL.c toglGLX.c toglWGL.c ================================================ FILE: ng/Togl2.1/README.stubs ================================================ This version of Togl is entirely free from dependencies on Tcl/Tk's internal functions. It uses the public stubs interface, witch means that the same binary works with any stubs-aware wish (i.e. version >= 8.1) It has been tested on Windows NT/2000 and Linux for several Tcl/Tk versions up to 8.4a3. I haven't been able to test the Mac port, it probably needs mending but I can't see why it shouldn't work in principle. Implementation wise, what differs from Togl 1.5 is that Togl_MakeWindowExist() is replaced by Togl_CreateWindow(), a function that gets registered in Tk as a callback for window creation. In Tk/Tk 8.4a3, there is a new public API call Tk_SetClassProcs() to register this callback, but for earlier versions of Tk one needs to do this using some pointer magic. There is a run-time check to determine which method to use, hence the same binary runs on all versions of Wish from 8.1 and up. For this to work you need to compile against the headers from Tcl/Tk 8.4a3 or later, or the binary will only work for Tcl/Tk 8.1-8.4a2. The tk8.4a3 public headers (tk8.4a3.h + tkDecls.h) are included for convenience, and they are used if the flag -DUSE_LOCAL_TK_H is specified. Jonas Beskow, December 2001 ================================================ FILE: ng/Togl2.1/Togl.py ================================================ """ Tkinter support for the Togl 2.X Tk OpenGL widget. Copyright (C) 2006-2007 Greg Couch See the LICENSE file for copyright details. """ __all__ = ['Togl', 'NORMAL', 'OVERLAY'] import Tkinter import weakref, atexit # Overlay constants NORMAL = 1 OVERLAY = 2 class Togl(Tkinter.Widget): """Tk OpenGL Widget""" _instances = weakref.WeakKeyDictionary() def __init__(self, master=None, cnf={}, **kw): """Return new Togl widget""" if master is None: master = Tkinter._default_root master.tk.call('package', 'require', 'Togl', '2.0') try: Tkinter.Widget.__init__(self, master, "togl", cnf, kw) except: Tkinter.Widget.destroy(self) raise Togl._instances[self] = True def _cbsubst(self, *args): """callback command argument substitution""" if len(args) != 1: return args return (self._nametowidget(args[0]),) def _options(self, cnf, kw = None): """Internal function.""" if kw: cnf = Tkinter._cnfmerge((cnf, kw)) else: cnf = Tkinter._cnfmerge(cnf) res = () for k, v in cnf.items(): if v is not None: if k[-1] == '_': k = k[:-1] if callable(v): if k.endswith('command'): v = self._register(v, self._cbsubst) else: v = self._register(v) res = res + ('-'+k, v) return res # cget, configure are inherited def extensions(self): """Return list of supported OpenGL extensions""" return self.tk.call(self._w, 'extensions') def postredisplay(self): """Cause the displaycommand callback to be called the next time the event loop is idle.""" self.tk.call(self._w, 'postredisplay') def render(self): """Call the displaycommand callback immediately.""" self.tk.call(self._w, 'render') def swapbuffers(self): """If single-buffred, just flush OpenGL command buffer. If double-buffered, swap front and back buffers. (So this is appropriate to call after every frame is drawn.)""" self.tk.call(self._w, 'swapbuffers') def makecurrent(self): """Make widget the current OpenGL context""" self.tk.call(self._w, 'makecurrent') def takephoto(self, imageName): """Copy current contents of widget into the given photo image """ self.tk.call(self._w, 'takephoto', imageName) def loadbitmapfont(self, name): return self.tk.call(self._w, 'loadbitmapfont', name) def unloadbitmapfont(self, fontbase): self.tk.call(self._w, 'unloadbitmapfont', fontbase) def uselayer(self, layer): self.tk.call(self._w, 'uselayer', layer) def showoverlay(self): self.tk.call(self._w, 'showoverlay') def hideoverlay(self): self.tk.call(self._w, 'hideoverlay') def postredisplayoverlay(self): self.tk.call(self._w, 'postredisplayoverlay') def renderoverlay(self): self.tk.call(self._w, 'renderoverlay') def existsoverlay(self): return self.tk.call(self._w, 'existsoverlay') def ismappedoverlay(self): return self.tk.call(self._w, 'ismappedoverlay') def getoverlaytransparentvalue(self): return self.tk.call(self._w, 'getoverlaytransparentvalue') def destroy(self): del Togl._instances[self] Tkinter.Widget.destroy(self) def _cleanup(): # destroy OpenGL contexts early, so destroycommand's don't # try to make any OpenGL calls during exit. for t in Togl._instances.keys(): try: t.destroy() except Tkinter.TclError: pass atexit.register(_cleanup) ================================================ FILE: ng/Togl2.1/Xmu/CmapAlloc.c ================================================ /* $XConsortium: CmapAlloc.c,v 1.9 94/04/17 20:15:52 rws Exp $ */ /* Copyright (c) 1989, 1994 X Consortium Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Except as contained in this notice, the name of the X Consortium shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from the X Consortium. */ /* * Author: Donna Converse, MIT X Consortium */ #include #include #include #include #define lowbit(x) ((x) & (~(x) + 1)) static int default_allocation(); static void best_allocation(); static void gray_allocation(); static int icbrt(); static int icbrt_with_bits(); static int icbrt_with_guess(); /* To determine the best allocation of reds, greens, and blues in a * standard colormap, use XmuGetColormapAllocation. * vinfo specifies visual information for a chosen visual * property specifies one of the standard colormap property names * red_max returns maximum red value * green_max returns maximum green value * blue_max returns maximum blue value * * XmuGetColormapAllocation returns 0 on failure, non-zero on success. * It is assumed that the visual is appropriate for the colormap property. */ Status XmuGetColormapAllocation(vinfo, property, red_max, green_max, blue_max) XVisualInfo *vinfo; Atom property; unsigned long *red_max, *green_max, *blue_max; { Status status = 1; if (vinfo->colormap_size <= 2) return 0; switch (property) { case XA_RGB_DEFAULT_MAP: status = default_allocation(vinfo, red_max, green_max, blue_max); break; case XA_RGB_BEST_MAP: best_allocation(vinfo, red_max, green_max, blue_max); break; case XA_RGB_GRAY_MAP: gray_allocation(vinfo->colormap_size, red_max, green_max, blue_max); break; case XA_RGB_RED_MAP: *red_max = vinfo->colormap_size - 1; *green_max = *blue_max = 0; break; case XA_RGB_GREEN_MAP: *green_max = vinfo->colormap_size - 1; *red_max = *blue_max = 0; break; case XA_RGB_BLUE_MAP: *blue_max = vinfo->colormap_size - 1; *red_max = *green_max = 0; break; default: status = 0; } return status; } /****************************************************************************/ /* Determine the appropriate color allocations of a gray scale. * * Keith Packard, MIT X Consortium */ static void gray_allocation(n, red_max, green_max, blue_max) int n; /* the number of cells of the gray scale */ unsigned long *red_max, *green_max, *blue_max; { *red_max = (n * 30) / 100; *green_max = (n * 59) / 100; *blue_max = (n * 11) / 100; *green_max += ((n - 1) - (*red_max + *green_max + *blue_max)); } /****************************************************************************/ /* Determine an appropriate color allocation for the RGB_DEFAULT_MAP. * If a map has less than a minimum number of definable entries, we do not * produce an allocation for an RGB_DEFAULT_MAP. * * For 16 planes, the default colormap will have 27 each RGB; for 12 planes, * 12 each. For 8 planes, let n = the number of colormap entries, which may * be 256 or 254. Then, maximum red value = floor(cube_root(n - 125)) - 1. * Maximum green and maximum blue values are identical to maximum red. * This leaves at least 125 cells which clients can allocate. * * Return 0 if an allocation has been determined, non-zero otherwise. */ static int default_allocation(vinfo, red, green, blue) XVisualInfo *vinfo; unsigned long *red, *green, *blue; { int ngrays; /* number of gray cells */ switch (vinfo->class) { case PseudoColor: if (vinfo->colormap_size > 65000) /* intended for displays with 16 planes */ *red = *green = *blue = (unsigned long) 27; else if (vinfo->colormap_size > 4000) /* intended for displays with 12 planes */ *red = *green = *blue = (unsigned long) 12; else if (vinfo->colormap_size < 250) return 0; else /* intended for displays with 8 planes */ *red = *green = *blue = (unsigned long) (icbrt(vinfo->colormap_size - 125) - 1); break; case DirectColor: if (vinfo->colormap_size < 10) return 0; *red = *green = *blue = vinfo->colormap_size / 2 - 1; break; case TrueColor: *red = vinfo->red_mask / lowbit(vinfo->red_mask); *green = vinfo->green_mask / lowbit(vinfo->green_mask); *blue = vinfo->blue_mask / lowbit(vinfo->blue_mask); break; case GrayScale: if (vinfo->colormap_size > 65000) ngrays = 4096; else if (vinfo->colormap_size > 4000) ngrays = 512; else if (vinfo->colormap_size < 250) return 0; else ngrays = 12; gray_allocation(ngrays, red, green, blue); break; default: return 0; } return 1; } /****************************************************************************/ /* Determine an appropriate color allocation for the RGB_BEST_MAP. * * For a DirectColor or TrueColor visual, the allocation is determined * by the red_mask, green_mask, and blue_mask members of the visual info. * * Otherwise, if the colormap size is an integral power of 2, determine * the allocation according to the number of bits given to each color, * with green getting more than red, and red more than blue, if there * are to be inequities in the distribution. If the colormap size is * not an integral power of 2, let n = the number of colormap entries. * Then maximum red value = floor(cube_root(n)) - 1; * maximum blue value = floor(cube_root(n)) - 1; * maximum green value = n / ((# red values) * (# blue values)) - 1; * Which, on a GPX, allows for 252 entries in the best map, out of 254 * defineable colormap entries. */ static void best_allocation(vinfo, red, green, blue) XVisualInfo *vinfo; unsigned long *red, *green, *blue; { if (vinfo->class == DirectColor || vinfo->class == TrueColor) { *red = vinfo->red_mask; while ((*red & 01) == 0) *red >>= 1; *green = vinfo->green_mask; while ((*green & 01) == 0) *green >>=1; *blue = vinfo->blue_mask; while ((*blue & 01) == 0) *blue >>= 1; } else { register int bits, n; /* Determine n such that n is the least integral power of 2 which is * greater than or equal to the number of entries in the colormap. */ n = 1; bits = 0; while (vinfo->colormap_size > n) { n = n << 1; bits++; } /* If the number of entries in the colormap is a power of 2, determine * the allocation by "dealing" the bits, first to green, then red, then * blue. If not, find the maximum integral red, green, and blue values * which, when multiplied together, do not exceed the number of * colormap entries. */ if (n == vinfo->colormap_size) { register int r, g, b; b = bits / 3; g = b + ((bits % 3) ? 1 : 0); r = b + (((bits % 3) == 2) ? 1 : 0); *red = 1 << r; *green = 1 << g; *blue = 1 << b; } else { *red = icbrt_with_bits(vinfo->colormap_size, bits); *blue = *red; *green = (vinfo->colormap_size / ((*red) * (*blue))); } (*red)--; (*green)--; (*blue)--; } return; } /* * integer cube roots by Newton's method * * Stephen Gildea, MIT X Consortium, July 1991 */ static int icbrt(a) /* integer cube root */ int a; { register int bits = 0; register unsigned n = a; while (n) { bits++; n >>= 1; } return icbrt_with_bits(a, bits); } static int icbrt_with_bits(a, bits) int a; int bits; /* log 2 of a */ { return icbrt_with_guess(a, a>>2*bits/3); } #ifdef _X_ROOT_STATS int icbrt_loopcount; #endif /* Newton's Method: x_n+1 = x_n - ( f(x_n) / f'(x_n) ) */ /* for cube roots, x^3 - a = 0, x_new = x - 1/3 (x - a/x^2) */ /* * Quick and dirty cube roots. Nothing fancy here, just Newton's method. * Only works for positive integers (since that's all we need). * We actually return floor(cbrt(a)) because that's what we need here, too. */ static int icbrt_with_guess(a, guess) int a, guess; { register int delta; #ifdef _X_ROOT_STATS icbrt_loopcount = 0; #endif if (a <= 0) return 0; if (guess < 1) guess = 1; do { #ifdef _X_ROOT_STATS icbrt_loopcount++; #endif delta = (guess - a/(guess*guess))/3; #ifdef DEBUG printf("pass %d: guess=%d, delta=%d\n", icbrt_loopcount, guess, delta); #endif guess -= delta; } while (delta != 0); if (guess*guess*guess > a) guess--; return guess; } ================================================ FILE: ng/Togl2.1/Xmu/CrCmap.c ================================================ /* $XConsortium: CrCmap.c,v 1.6 94/04/17 20:15:53 rws Exp $ */ /* Copyright (c) 1989 X Consortium Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Except as contained in this notice, the name of the X Consortium shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from the X Consortium. */ /* * Author: Donna Converse, MIT X Consortium */ /* * CreateCmap.c - given a standard colormap description, make the map. */ #include #include #include #include static int ROmap(); /* allocate entire map Read Only */ static Status ROorRWcell(); /* allocate a cell, prefer Read Only */ static Status RWcell(); /* allocate a cell Read Write */ static int compare(); /* for quicksort */ static Status contiguous(); /* find contiguous sequence of cells */ static void free_cells(); /* frees resources before quitting */ static Status readonly_map(); /* create a map in a RO visual type */ static Status readwrite_map(); /* create a map in a RW visual type */ #define lowbit(x) ((x) & (~(x) + 1)) #define TRUEMATCH(mult,max,mask) \ (colormap->max * colormap->mult <= vinfo->mask && \ lowbit(vinfo->mask) == colormap->mult) /* * To create any one colormap which is described by an XStandardColormap * structure, use XmuCreateColormap(). * * Return 0 on failure, non-zero on success. * Resources created by this function are not made permanent. * No argument error checking is provided. Use at your own risk. * * All colormaps are created with read only allocations, with the exception * of read only allocations of colors in the default map or otherwise * which fail to return the expected pixel value, and these are individually * defined as read/write allocations. This is done so that all the cells * defined in the default map are contiguous, for use in image processing. * This typically happens with White and Black in the default map. * * Colormaps of static visuals are considered to be successfully created if * the map of the static visual matches the definition given in the * standard colormap structure. */ Status XmuCreateColormap(dpy, colormap) Display *dpy; /* specifies the connection under * which the map is created */ XStandardColormap *colormap; /* specifies the map to be created, * and returns, particularly if the * map is created as a subset of the * default colormap of the screen, * the base_pixel of the map. */ { XVisualInfo vinfo_template; /* template visual information */ XVisualInfo *vinfo; /* matching visual information */ XVisualInfo *vpointer; /* for freeing the entire list */ long vinfo_mask; /* specifies the visual mask value */ int n; /* number of matching visuals */ int status; vinfo_template.visualid = colormap->visualid; vinfo_mask = VisualIDMask; if ((vinfo = XGetVisualInfo(dpy, vinfo_mask, &vinfo_template, &n)) == NULL) return 0; /* A visual id may be valid on multiple screens. Also, there may * be multiple visuals with identical visual ids at different depths. * If the colormap is the Default Colormap, use the Default Visual. * Otherwise, arbitrarily, use the deepest visual. */ vpointer = vinfo; if (n > 1) { register int i; register int screen_number; Bool def_cmap; def_cmap = False; for (screen_number = ScreenCount(dpy); --screen_number >= 0; ) if (colormap->colormap == DefaultColormap(dpy, screen_number)) { def_cmap = True; break; } if (def_cmap) { for (i=0; i < n; i++, vinfo++) { if (vinfo->visual == DefaultVisual(dpy, screen_number)) break; } } else { unsigned int maxdepth = 0; XVisualInfo *v; for (i=0; i < n; i++, vinfo++) if (vinfo->depth > maxdepth) { maxdepth = vinfo->depth; v = vinfo; } vinfo = v; } } if (vinfo->class == PseudoColor || vinfo->class == DirectColor || vinfo->class == GrayScale) status = readwrite_map(dpy, vinfo, colormap); else if (vinfo->class == TrueColor) status = TRUEMATCH(red_mult, red_max, red_mask) && TRUEMATCH(green_mult, green_max, green_mask) && TRUEMATCH(blue_mult, blue_max, blue_mask); else status = readonly_map(dpy, vinfo, colormap); XFree((char *) vpointer); return status; } /****************************************************************************/ static Status readwrite_map(dpy, vinfo, colormap) Display *dpy; XVisualInfo *vinfo; XStandardColormap *colormap; { register unsigned long i, n; /* index counters */ int ncolors; /* number of colors to be defined */ int npixels; /* number of pixels allocated R/W */ int first_index; /* first index of pixels to use */ int remainder; /* first index of remainder */ XColor color; /* the definition of a color */ unsigned long *pixels; /* array of colormap pixels */ unsigned long delta; /* Determine ncolors, the number of colors to be defined. * Insure that 1 < ncolors <= the colormap size. */ if (vinfo->class == DirectColor) { ncolors = colormap->red_max; if (colormap->green_max > ncolors) ncolors = colormap->green_max; if (colormap->blue_max > ncolors) ncolors = colormap->blue_max; ncolors++; delta = lowbit(vinfo->red_mask) + lowbit(vinfo->green_mask) + lowbit(vinfo->blue_mask); } else { ncolors = colormap->red_max * colormap->red_mult + colormap->green_max * colormap->green_mult + colormap->blue_max * colormap->blue_mult + 1; delta = 1; } if (ncolors <= 1 || ncolors > vinfo->colormap_size) return 0; /* Allocate Read/Write as much of the colormap as we can possibly get. * Then insure that the pixels we were allocated are given in * monotonically increasing order, using a quicksort. Next, insure * that our allocation includes a subset of contiguous pixels at least * as long as the number of colors to be defined. Now we know that * these conditions are met: * 1) There are no free cells in the colormap. * 2) We have a contiguous sequence of pixels, monotonically * increasing, of length >= the number of colors requested. * * One cell at a time, we will free, compute the next color value, * then allocate read only. This takes a long time. * This is done to insure that cells are allocated read only in the * contiguous order which we prefer. If the server has a choice of * cells to grant to an allocation request, the server may give us any * cell, so that is why we do these slow gymnastics. */ if ((pixels = (unsigned long *) calloc((unsigned) vinfo->colormap_size, sizeof(unsigned long))) == NULL) return 0; if ((npixels = ROmap(dpy, colormap->colormap, pixels, vinfo->colormap_size, ncolors)) == 0) { free((char *) pixels); return 0; } qsort((char *) pixels, npixels, sizeof(unsigned long), compare); if (!contiguous(pixels, npixels, ncolors, delta, &first_index, &remainder)) { /* can't find enough contiguous cells, give up */ XFreeColors(dpy, colormap->colormap, pixels, npixels, (unsigned long) 0); free((char *) pixels); return 0; } colormap->base_pixel = pixels[first_index]; /* construct a gray map */ if (colormap->red_mult == 1 && colormap->green_mult == 1 && colormap->blue_mult == 1) for (n=colormap->base_pixel, i=0; i < ncolors; i++, n += delta) { color.pixel = n; color.blue = color.green = color.red = (unsigned short) ((i * 65535) / (colormap->red_max + colormap->green_max + colormap->blue_max)); if (! ROorRWcell(dpy, colormap->colormap, pixels, npixels, &color, first_index + i)) return 0; } /* construct a red ramp map */ else if (colormap->green_max == 0 && colormap->blue_max == 0) for (n=colormap->base_pixel, i=0; i < ncolors; i++, n += delta) { color.pixel = n; color.red = (unsigned short) ((i * 65535) / colormap->red_max); color.green = color.blue = 0; if (! ROorRWcell(dpy, colormap->colormap, pixels, npixels, &color, first_index + i)) return 0; } /* construct a green ramp map */ else if (colormap->red_max == 0 && colormap->blue_max == 0) for (n=colormap->base_pixel, i=0; i < ncolors; i++, n += delta) { color.pixel = n; color.green = (unsigned short) ((i * 65535) / colormap->green_max); color.red = color.blue = 0; if (! ROorRWcell(dpy, colormap->colormap, pixels, npixels, &color, first_index + i)) return 0; } /* construct a blue ramp map */ else if (colormap->red_max == 0 && colormap->green_max == 0) for (n=colormap->base_pixel, i=0; i < ncolors; i++, n += delta) { color.pixel = n; color.blue = (unsigned short) ((i * 65535) / colormap->blue_max); color.red = color.green = 0; if (! ROorRWcell(dpy, colormap->colormap, pixels, npixels, &color, first_index + i)) return 0; } /* construct a standard red green blue cube map */ else { #define calc(max,mult) (((n / colormap->mult) % \ (colormap->max + 1)) * 65535) / colormap->max for (n=0, i=0; i < ncolors; i++, n += delta) { color.pixel = n + colormap->base_pixel; color.red = calc(red_max, red_mult); color.green = calc(green_max, green_mult); color.blue = calc(blue_max, blue_mult); if (! ROorRWcell(dpy, colormap->colormap, pixels, npixels, &color, first_index + i)) return 0; } #undef calc } /* We have a read-only map defined. Now free unused cells, * first those occurring before the contiguous sequence begins, * then any following the contiguous sequence. */ if (first_index) XFreeColors(dpy, colormap->colormap, pixels, first_index, (unsigned long) 0); if (remainder) XFreeColors(dpy, colormap->colormap, &(pixels[first_index + ncolors]), remainder, (unsigned long) 0); free((char *) pixels); return 1; } /****************************************************************************/ static int ROmap(dpy, cmap, pixels, m, n) Display *dpy; /* the X server connection */ Colormap cmap; /* specifies colormap ID */ unsigned long pixels[]; /* returns pixel allocations */ int m; /* specifies colormap size */ int n; /* specifies number of colors */ { register int p; /* first try to allocate the entire colormap */ if (XAllocColorCells(dpy, cmap, 1, (unsigned long *) NULL, (unsigned) 0, pixels, (unsigned) m)) return m; /* Allocate all available cells in the colormap, using a binary * algorithm to discover how many cells we can allocate in the colormap. */ m--; while (n <= m) { p = n + ((m - n + 1) / 2); if (XAllocColorCells(dpy, cmap, 1, (unsigned long *) NULL, (unsigned) 0, pixels, (unsigned) p)) { if (p == m) return p; else { XFreeColors(dpy, cmap, pixels, p, (unsigned long) 0); n = p; } } else m = p - 1; } return 0; } /****************************************************************************/ static Status contiguous(pixels, npixels, ncolors, delta, first, rem) unsigned long pixels[]; /* specifies allocated pixels */ int npixels; /* specifies count of alloc'd pixels */ int ncolors; /* specifies needed sequence length */ unsigned long delta; /* between pixels */ int *first; /* returns first index of sequence */ int *rem; /* returns first index after sequence, * or 0, if none follow */ { register int i = 1; /* walking index into the pixel array */ register int count = 1; /* length of sequence discovered so far */ *first = 0; if (npixels == ncolors) { *rem = 0; return 1; } *rem = npixels - 1; while (count < ncolors && ncolors - count <= *rem) { if (pixels[i-1] + delta == pixels[i]) count++; else { count = 1; *first = i; } i++; (*rem)--; } if (count != ncolors) return 0; return 1; } /****************************************************************************/ static Status ROorRWcell(dpy, cmap, pixels, npixels, color, p) Display *dpy; Colormap cmap; unsigned long pixels[]; int npixels; XColor *color; unsigned long p; { unsigned long pixel; XColor request; /* Free the read/write allocation of one cell in the colormap. * Request a read only allocation of one cell in the colormap. * If the read only allocation cannot be granted, give up, because * there must be no free cells in the colormap. * If the read only allocation is granted, but gives us a cell which * is not the one that we just freed, it is probably the case that * we are trying allocate White or Black or some other color which * already has a read-only allocation in the map. So we try to * allocate the previously freed cell with a read/write allocation, * because we want contiguous cells for image processing algorithms. */ pixel = color->pixel; request.red = color->red; request.green = color->green; request.blue = color->blue; XFreeColors(dpy, cmap, &pixel, 1, (unsigned long) 0); if (! XAllocColor(dpy, cmap, color) || (color->pixel != pixel && (!RWcell(dpy, cmap, color, &request, &pixel)))) { free_cells(dpy, cmap, pixels, npixels, (int)p); return 0; } return 1; } /****************************************************************************/ static void free_cells(dpy, cmap, pixels, npixels, p) Display *dpy; Colormap cmap; unsigned long pixels[]; /* to be freed */ int npixels; /* original number allocated */ int p; { /* One of the npixels allocated has already been freed. * p is the index of the freed pixel. * First free the pixels preceding p, and there are p of them; * then free the pixels following p, there are npixels - p - 1 of them. */ XFreeColors(dpy, cmap, pixels, p, (unsigned long) 0); XFreeColors(dpy, cmap, &(pixels[p+1]), npixels - p - 1, (unsigned long) 0); free((char *) pixels); } /****************************************************************************/ static Status RWcell(dpy, cmap, color, request, pixel) Display *dpy; Colormap cmap; XColor *color; XColor *request; unsigned long *pixel; { unsigned long n = *pixel; XFreeColors(dpy, cmap, &(color->pixel), 1, (unsigned long)0); if (! XAllocColorCells(dpy, cmap, (Bool) 0, (unsigned long *) NULL, (unsigned) 0, pixel, (unsigned) 1)) return 0; if (*pixel != n) { XFreeColors(dpy, cmap, pixel, 1, (unsigned long) 0); return 0; } color->pixel = *pixel; color->flags = DoRed | DoGreen | DoBlue; color->red = request->red; color->green = request->green; color->blue = request->blue; XStoreColors(dpy, cmap, color, 1); return 1; } /****************************************************************************/ static int compare(e1, e2) unsigned long *e1, *e2; { if (*e1 < *e2) return -1; if (*e1 > *e2) return 1; return 0; } /****************************************************************************/ static Status readonly_map(dpy, vinfo, colormap) Display *dpy; XVisualInfo *vinfo; XStandardColormap *colormap; { int i, last_pixel; XColor color; last_pixel = (colormap->red_max + 1) * (colormap->green_max + 1) * (colormap->blue_max + 1) + colormap->base_pixel - 1; for(i=colormap->base_pixel; i <= last_pixel; i++) { color.pixel = (unsigned long) i; color.red = (unsigned short) (((i/colormap->red_mult) * 65535) / colormap->red_max); if (vinfo->class == StaticColor) { color.green = (unsigned short) ((((i/colormap->green_mult) % (colormap->green_max + 1)) * 65535) / colormap->green_max); color.blue = (unsigned short) (((i%colormap->green_mult) * 65535) / colormap->blue_max); } else /* vinfo->class == GrayScale, old style allocation XXX */ color.green = color.blue = color.red; XAllocColor(dpy, colormap->colormap, &color); if (color.pixel != (unsigned long) i) return 0; } return 1; } ================================================ FILE: ng/Togl2.1/Xmu/DelCmap.c ================================================ /* $XConsortium: DelCmap.c,v 1.2 94/04/17 20:15:58 converse Exp $ */ /* Copyright (c) 1989 X Consortium Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Except as contained in this notice, the name of the X Consortium shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from the X Consortium. */ /* * Author: Donna Converse, MIT X Consortium */ #include #include /* To remove any standard colormap property, use XmuDeleteStandardColormap(). * XmuDeleteStandardColormap() will remove the specified property from the * specified screen, releasing any resources used by the colormap(s) of the * property if possible. */ void XmuDeleteStandardColormap(dpy, screen, property) Display *dpy; /* specifies the X server to connect to */ int screen; /* specifies the screen of the display */ Atom property; /* specifies the standard colormap property */ { XStandardColormap *stdcmaps, *s; int count = 0; if (XGetRGBColormaps(dpy, RootWindow(dpy, screen), &stdcmaps, &count, property)) { for (s=stdcmaps; count > 0; count--, s++) { if ((s->killid == ReleaseByFreeingColormap) && (s->colormap != None) && (s->colormap != DefaultColormap(dpy, screen))) XFreeColormap(dpy, s->colormap); else if (s->killid != None) XKillClient(dpy, s->killid); } XDeleteProperty(dpy, RootWindow(dpy, screen), property); XFree((char *) stdcmaps); XSync(dpy, False); } } ================================================ FILE: ng/Togl2.1/Xmu/LookupCmap.c ================================================ /* $XConsortium: LookupCmap.c,v 1.10 94/04/17 20:16:11 rws Exp $ */ /* Copyright (c) 1989 X Consortium Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Except as contained in this notice, the name of the X Consortium shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from the X Consortium. */ /* * Author: Donna Converse, MIT X Consortium */ #include #include #include #include #include #include static Status lookup(); /* * To create a standard colormap if one does not currently exist, or * replace the currently existing standard colormap, use * XmuLookupStandardColormap(). * * Given a screen, a visual, and a property, XmuLookupStandardColormap() * will determine the best allocation for the property under the specified * visual, and determine the whether to create a new colormap or to use * the default colormap of the screen. It will call XmuStandardColormap() * to create the standard colormap. * * If replace is true, any previous definition of the property will be * replaced. If retain is true, the property and the colormap will be * made permanent for the duration of the server session. However, * pre-existing property definitions which are not replaced cannot be made * permanent by a call to XmuLookupStandardColormap(); a request to retain * resources pertains to newly created resources. * * Returns 0 on failure, non-zero on success. A request to create a * standard colormap upon a visual which cannot support such a map is * considered a failure. An example of this would be requesting any * standard colormap property on a monochrome visual, or, requesting an * RGB_BEST_MAP on a display whose colormap size is 16. */ Status XmuLookupStandardColormap(dpy, screen, visualid, depth, property, replace, retain) Display *dpy; /* specifies X server connection */ int screen; /* specifies screen of display */ VisualID visualid; /* specifies the visual type */ unsigned int depth; /* specifies the visual type */ Atom property; /* a standard colormap property */ Bool replace; /* specifies whether to replace */ Bool retain; /* specifies whether to retain */ { Display *odpy; /* original display connection */ XStandardColormap *colormap; XVisualInfo vinfo_template, *vinfo; /* visual */ long vinfo_mask; unsigned long r_max, g_max, b_max; /* allocation */ int count; Colormap cmap; /* colormap ID */ Status status = 0; /* Match the requested visual */ vinfo_template.visualid = visualid; vinfo_template.screen = screen; vinfo_template.depth = depth; vinfo_mask = VisualIDMask | VisualScreenMask | VisualDepthMask; if ((vinfo = XGetVisualInfo(dpy, vinfo_mask, &vinfo_template, &count)) == NULL) return 0; /* Monochrome visuals have no standard maps */ if (vinfo->colormap_size <= 2) { XFree((char *) vinfo); return 0; } /* If the requested property already exists on this screen, and, * if the replace flag has not been set to true, return success. * lookup() will remove a pre-existing map if replace is true. */ if (lookup(dpy, screen, visualid, property, (XStandardColormap *) NULL, replace) && !replace) { XFree((char *) vinfo); return 1; } /* Determine the best allocation for this property under the requested * visualid and depth, and determine whether or not to use the default * colormap of the screen. */ if (!XmuGetColormapAllocation(vinfo, property, &r_max, &g_max, &b_max)) { XFree((char *) vinfo); return 0; } cmap = (property == XA_RGB_DEFAULT_MAP && visualid == XVisualIDFromVisual(DefaultVisual(dpy, screen))) ? DefaultColormap(dpy, screen) : None; /* If retaining resources, open a new connection to the same server */ if (retain) { odpy = dpy; if ((dpy = XOpenDisplay(XDisplayString(odpy))) == NULL) { XFree((char *) vinfo); return 0; } } /* Create the standard colormap */ colormap = XmuStandardColormap(dpy, screen, visualid, depth, property, cmap, r_max, g_max, b_max); /* Set the standard colormap property */ if (colormap) { XGrabServer(dpy); if (lookup(dpy, screen, visualid, property, colormap, replace) && !replace) { /* Someone has defined the property since we last looked. * Since we will not replace it, release our own resources. * If this is the default map, our allocations will be freed * when this connection closes. */ if (colormap->killid == ReleaseByFreeingColormap) XFreeColormap(dpy, colormap->colormap); } else if (retain) { XSetCloseDownMode(dpy, RetainPermanent); } XUngrabServer(dpy); XFree((char *) colormap); status = 1; } if (retain) XCloseDisplay(dpy); XFree((char *) vinfo); return status; } /***************************************************************************/ /* Lookup a standard colormap property. If the property is RGB_DEFAULT_MAP, * the visualid is used to determine whether the indicated standard colormap * exists. If the map exists and replace is true, delete the resources used * by the map and remove the property. Return true if the map exists, * or did exist and was deleted; return false if the map was not found. * * Note that this is not the way that a Status return is normally used. * * If new is not NULL, new points to an XStandardColormap structure which * describes a standard colormap of the specified property. It will be made * a standard colormap of the screen if none already exists, or if replace * is true. */ static Status lookup(dpy, screen, visualid, property, new, replace) Display *dpy; /* specifies display connection */ int screen; /* specifies screen number */ VisualID visualid; /* specifies visualid for std map */ Atom property; /* specifies colormap property name */ XStandardColormap *new; /* specifies a standard colormap */ Bool replace; /* specifies whether to replace */ { register int i; int count; XStandardColormap *stdcmaps, *s; Window win = RootWindow(dpy, screen); /* The property does not already exist */ if (! XGetRGBColormaps(dpy, win, &stdcmaps, &count, property)) { if (new) XSetRGBColormaps(dpy, win, new, 1, property); return 0; } /* The property exists and is not describing the RGB_DEFAULT_MAP */ if (property != XA_RGB_DEFAULT_MAP) { if (replace) { XmuDeleteStandardColormap(dpy, screen, property); if (new) XSetRGBColormaps(dpy, win, new, 1, property); } XFree((char *)stdcmaps); return 1; } /* The property exists and is RGB_DEFAULT_MAP */ for (i=0, s=stdcmaps; (i < count) && (s->visualid != visualid); i++, s++) ; /* No RGB_DEFAULT_MAP property matches the given visualid */ if (i == count) { if (new) { XStandardColormap *m, *maps; s = (XStandardColormap *) malloc((unsigned) ((count+1) * sizeof (XStandardColormap))); for (i = 0, m = s, maps = stdcmaps; i < count; i++, m++, maps++) { m->colormap = maps->colormap; m->red_max = maps->red_max; m->red_mult = maps->red_mult; m->green_max = maps->green_max; m->green_mult = maps->green_mult; m->blue_max = maps->blue_max; m->blue_mult = maps->blue_mult; m->base_pixel = maps->base_pixel; m->visualid = maps->visualid; m->killid = maps->killid; } m->colormap = new->colormap; m->red_max = new->red_max; m->red_mult = new->red_mult; m->green_max = new->green_max; m->green_mult = new->green_mult; m->blue_max = new->blue_max; m->blue_mult = new->blue_mult; m->base_pixel = new->base_pixel; m->visualid = new->visualid; m->killid = new->killid; XSetRGBColormaps(dpy, win, s, ++count, property); free((char *) s); } XFree((char *) stdcmaps); return 0; } /* Found an RGB_DEFAULT_MAP property with a matching visualid */ if (replace) { /* Free old resources first - we may need them, particularly in * the default colormap of the screen. However, because of this, * it is possible that we will destroy the old resource and fail * to create a new one if XmuStandardColormap() fails. */ if (count == 1) { XmuDeleteStandardColormap(dpy, screen, property); if (new) XSetRGBColormaps(dpy, win, new, 1, property); } else { XStandardColormap *map; /* s still points to the matching standard colormap */ if (s->killid == ReleaseByFreeingColormap) { if ((s->colormap != None) && (s->colormap != DefaultColormap(dpy, screen))) XFreeColormap(dpy, s->colormap); } else if (s->killid != None) XKillClient(dpy, s->killid); map = (new) ? new : stdcmaps + --count; s->colormap = map->colormap; s->red_max = map->red_max; s->red_mult = map->red_mult; s->green_max = map->green_max; s->green_mult = map->green_mult; s->blue_max = map->blue_max; s->blue_mult = map->blue_mult; s->visualid = map->visualid; s->killid = map->killid; XSetRGBColormaps(dpy, win, stdcmaps, count, property); } } XFree((char *) stdcmaps); return 1; } ================================================ FILE: ng/Togl2.1/Xmu/README.togl ================================================ The source code in this directory is a subset of the Jun 12, 1995 X11R6 Xmu library that is needed for the Togl widget. The Xmu library is no longer installed by default on many Linux systems. ================================================ FILE: ng/Togl2.1/Xmu/StdCmap.c ================================================ /* $XConsortium: StdCmap.c,v 1.14 94/04/17 20:16:14 rws Exp $ */ /* Copyright (c) 1989 X Consortium Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Except as contained in this notice, the name of the X Consortium shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from the X Consortium. */ /* * Author: Donna Converse, MIT X Consortium */ #include #include #include #include #include #define lowbit(x) ((x) & (~(x) + 1)) static Status valid_args(); /* argument restrictions */ /* * To create any one standard colormap, use XmuStandardColormap(). * * Create a standard colormap for the given screen, visualid, and visual * depth, with the given red, green, and blue maximum values, with the * given standard property name. Return a pointer to an XStandardColormap * structure which describes the newly created colormap, upon success. * Upon failure, return NULL. * * XmuStandardColormap() calls XmuCreateColormap() to create the map. * * Resources created by this function are not made permanent; that is the * caller's responsibility. */ XStandardColormap *XmuStandardColormap(dpy, screen, visualid, depth, property, cmap, red_max, green_max, blue_max) Display *dpy; /* specifies X server connection */ int screen; /* specifies display screen */ VisualID visualid; /* identifies the visual type */ unsigned int depth; /* identifies the visual type */ Atom property; /* a standard colormap property */ Colormap cmap; /* specifies colormap ID or None */ unsigned long red_max, green_max, blue_max; /* allocations */ { XStandardColormap *stdcmap; Status status; XVisualInfo vinfo_template, *vinfo; long vinfo_mask; int n; /* Match the required visual information to an actual visual */ vinfo_template.visualid = visualid; vinfo_template.screen = screen; vinfo_template.depth = depth; vinfo_mask = VisualIDMask | VisualScreenMask | VisualDepthMask; if ((vinfo = XGetVisualInfo(dpy, vinfo_mask, &vinfo_template, &n)) == NULL) return 0; /* Check the validity of the combination of visual characteristics, * allocation, and colormap property. Create an XStandardColormap * structure. */ if (! valid_args(vinfo, red_max, green_max, blue_max, property) || ((stdcmap = XAllocStandardColormap()) == NULL)) { XFree((char *) vinfo); return 0; } /* Fill in the XStandardColormap structure */ if (cmap == DefaultColormap(dpy, screen)) { /* Allocating out of the default map, cannot use XFreeColormap() */ Window win = XCreateWindow(dpy, RootWindow(dpy, screen), 1, 1, 1, 1, 0, 0, InputOnly, vinfo->visual, (unsigned long) 0, (XSetWindowAttributes *)NULL); stdcmap->killid = (XID) XCreatePixmap(dpy, win, 1, 1, depth); XDestroyWindow(dpy, win); stdcmap->colormap = cmap; } else { stdcmap->killid = ReleaseByFreeingColormap; stdcmap->colormap = XCreateColormap(dpy, RootWindow(dpy, screen), vinfo->visual, AllocNone); } stdcmap->red_max = red_max; stdcmap->green_max = green_max; stdcmap->blue_max = blue_max; if (property == XA_RGB_GRAY_MAP) stdcmap->red_mult = stdcmap->green_mult = stdcmap->blue_mult = 1; else if (vinfo->class == TrueColor || vinfo->class == DirectColor) { stdcmap->red_mult = lowbit(vinfo->red_mask); stdcmap->green_mult = lowbit(vinfo->green_mask); stdcmap->blue_mult = lowbit(vinfo->blue_mask); } else { stdcmap->red_mult = (red_max > 0) ? (green_max + 1) * (blue_max + 1) : 0; stdcmap->green_mult = (green_max > 0) ? blue_max + 1 : 0; stdcmap->blue_mult = (blue_max > 0) ? 1 : 0; } stdcmap->base_pixel = 0; /* base pixel may change */ stdcmap->visualid = vinfo->visualid; /* Make the colormap */ status = XmuCreateColormap(dpy, stdcmap); /* Clean up */ XFree((char *) vinfo); if (!status) { /* Free the colormap or the pixmap, if we created one */ if (stdcmap->killid == ReleaseByFreeingColormap) XFreeColormap(dpy, stdcmap->colormap); else if (stdcmap->killid != None) XFreePixmap(dpy, stdcmap->killid); XFree((char *) stdcmap); return (XStandardColormap *) NULL; } return stdcmap; } /****************************************************************************/ static Status valid_args(vinfo, red_max, green_max, blue_max, property) XVisualInfo *vinfo; /* specifies visual */ unsigned long red_max, green_max, blue_max; /* specifies alloc */ Atom property; /* specifies property name */ { unsigned long ncolors; /* number of colors requested */ /* Determine that the number of colors requested is <= map size */ if ((vinfo->class == DirectColor) || (vinfo->class == TrueColor)) { unsigned long mask; mask = vinfo->red_mask; while (!(mask & 1)) mask >>= 1; if (red_max > mask) return 0; mask = vinfo->green_mask; while (!(mask & 1)) mask >>= 1; if (green_max > mask) return 0; mask = vinfo->blue_mask; while (!(mask & 1)) mask >>= 1; if (blue_max > mask) return 0; } else if (property == XA_RGB_GRAY_MAP) { ncolors = red_max + green_max + blue_max + 1; if (ncolors > vinfo->colormap_size) return 0; } else { ncolors = (red_max + 1) * (green_max + 1) * (blue_max + 1); if (ncolors > vinfo->colormap_size) return 0; } /* Determine that the allocation and visual make sense for the property */ switch (property) { case XA_RGB_DEFAULT_MAP: if (red_max == 0 || green_max == 0 || blue_max == 0) return 0; break; case XA_RGB_RED_MAP: if (red_max == 0) return 0; break; case XA_RGB_GREEN_MAP: if (green_max == 0) return 0; break; case XA_RGB_BLUE_MAP: if (blue_max == 0) return 0; break; case XA_RGB_BEST_MAP: if (red_max == 0 || green_max == 0 || blue_max == 0) return 0; break; case XA_RGB_GRAY_MAP: if (red_max == 0 || blue_max == 0 || green_max == 0) return 0; break; default: return 0; } return 1; } ================================================ FILE: ng/Togl2.1/Xmu/StdCmap.h ================================================ /* $XConsortium: StdCmap.h,v 1.4 94/04/17 20:16:15 converse Exp $ */ /* Copyright (c) 1988 X Consortium Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Except as contained in this notice, the name of the X Consortium shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from the X Consortium. */ /* * The interfaces described by this header file are for miscellaneous utilities * and are not part of the Xlib standard. */ #ifndef _XMU_STDCMAP_H_ #define _XMU_STDCMAP_H_ #include _XFUNCPROTOBEGIN Status XmuAllStandardColormaps( #if NeedFunctionPrototypes Display* /* dpy */ #endif ); Status XmuCreateColormap( #if NeedFunctionPrototypes Display* /* dpy */, XStandardColormap* /* colormap */ #endif ); void XmuDeleteStandardColormap( #if NeedFunctionPrototypes Display* /* dpy */, int /* screen */, Atom /* property */ #endif ); Status XmuGetColormapAllocation( #if NeedFunctionPrototypes XVisualInfo* /* vinfo */, Atom /* property */, unsigned long* /* red_max_return */, unsigned long* /* green_max_return */, unsigned long* /* blue_max_return */ #endif ); Status XmuLookupStandardColormap( #if NeedFunctionPrototypes Display* /* dpy */, int /* screen */, VisualID /* visualid */, unsigned int /* depth */, Atom /* property */, Bool /* replace */, Bool /* retain */ #endif ); XStandardColormap *XmuStandardColormap( #if NeedFunctionPrototypes Display* /* dpy */, int /* screen */, VisualID /* visualid */, unsigned int /* depth */, Atom /* property */, Colormap /* cmap */, unsigned long /* red_max */, unsigned long /* green_max */, unsigned long /* blue_max */ #endif ); Status XmuVisualStandardColormaps( #if NeedFunctionPrototypes Display* /* dpy */, int /* screen */, VisualID /* visualid */, unsigned int /* depth */, Bool /* replace */, Bool /* retain */ #endif ); _XFUNCPROTOEND #endif /* _XMU_STDCMAP_H_ */ ================================================ FILE: ng/Togl2.1/aclocal.m4 ================================================ # # Include the TEA standard macro set # builtin(include,tclconfig/tcl.m4) # # Add here whatever m4 macros you want to define for your package # #------------------------------------------------------------------------ # TOGL_ENABLE_STUBS -- # # Specify if stubs should be used. # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --enable-stubs # #------------------------------------------------------------------------ AC_DEFUN(TOGL_ENABLE_STUBS, [ AC_MSG_CHECKING([whether to link with stubs library]) AC_ARG_ENABLE(stubs, [ --enable-stubs build and link with stub libraries (--enable-stubs)], [tcl_ok=$enableval], [tcl_ok=yes]) if test "${enable_stubs+set}" = set; then enableval="$enable_stubs" tcl_ok=$enableval else tcl_ok=yes fi if test "$tcl_ok" = "yes" ; then AC_MSG_RESULT([stubs]) USE_STUBS=1 else AC_MSG_RESULT([no stubs]) USE_STUBS=0 fi ]) #------------------------------------------------------------------------ # TOGL_UNDEF_GET_PROC_ADDRESS -- # # Does defining GLX_GLXEXT_LEGACY interfere with including GL/glxext.h? # # Arguments: # none # # Results: # # defines TOGL_UNDEF_GET_PROC_ADDRESS # #------------------------------------------------------------------------ AC_DEFUN(TOGL_UNDEF_GET_PROC_ADDRESS, [ AC_MSG_CHECKING([if GLX_GLXEXT_LEGACY interferes with including GL/glxext.h]) AC_LANG_PUSH(C) ac_save_CFLAGS=$CFLAGS CFLAGS=$TK_XINCLUDES AC_COMPILE_IFELSE( [AC_LANG_SOURCE([[ #define GLX_GLXEXT_LEGACY #include #undef GLX_VERSION_1_3 #undef GLX_VERSION_1_4 #include int main() { return 0; } ]])], [AC_MSG_RESULT([no])], [AC_MSG_RESULT([yes]) AC_DEFINE(UNDEF_GET_PROC_ADDRESS, 1)]) CFLAGS=$ac_save_CFLAGS AC_LANG_POP() ]) ================================================ FILE: ng/Togl2.1/configure ================================================ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.65 for Togl 2.1. # # # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, # 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, # Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir/$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV export CONFIG_SHELL exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, $0: including any error possibly output before this $0: message. Then install a modern shell, or manually run $0: the script under such a shell if you do have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_error ERROR [LINENO LOG_FD] # --------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with status $?, using 1 if that was 0. as_fn_error () { as_status=$?; test $as_status -eq 0 && as_status=1 if test "$3"; then as_lineno=${as_lineno-"$2"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $1" >&$3 fi $as_echo "$as_me: error: $1" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -p'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -p' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi if test -x / >/dev/null 2>&1; then as_test_x='test -x' else if ls -dL / >/dev/null 2>&1; then as_ls_L_option=L else as_ls_L_option= fi as_test_x=' eval sh -c '\'' if test -d "$1"; then test -d "$1/."; else case $1 in #( -*)set "./$1";; esac; case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( ???[sx]*):;;*)false;;esac;fi '\'' sh ' fi as_executable_p=$as_test_x # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='Togl' PACKAGE_TARNAME='togl' PACKAGE_VERSION='2.1' PACKAGE_STRING='Togl 2.1' PACKAGE_BUGREPORT='' PACKAGE_URL='' # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_STRING_H # if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include # endif # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_subst_vars='LTLIBOBJS TCLSH_PROG RANLIB_STUB MAKE_STUB_LIB MAKE_STATIC_LIB MAKE_SHARED_LIB MAKE_LIB TCL_DBGX LDFLAGS_DEFAULT CFLAGS_DEFAULT SHLIB_SUFFIX LD_LIBRARY_PATH_VAR SHLIB_CFLAGS SHLIB_LD_LIBS SHLIB_LD STLIB_LD CFLAGS_WARNING CFLAGS_OPTIMIZE CFLAGS_DEBUG DL_LIBS LIBOBJS CELIB_DIR AR SHARED_BUILD TCL_THREADS TEA_WINDOWINGSYSTEM LIBGLU TOGL_WINDOWINGSYSTEM AUTOSTEREOD XMKMF TK_XLIB_DIR_NATIVE TK_TOP_DIR_NATIVE TK_INCLUDES TCL_TOP_DIR_NATIVE TCL_INCLUDES CLEANFILES PKG_OBJECTS PKG_SOURCES MATH_LIBS EGREP GREP RANLIB SET_MAKE INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM CPP OBJEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC TK_XINCLUDES TK_LIBS TK_STUB_LIB_SPEC TK_STUB_LIB_FLAG TK_STUB_LIB_FILE TK_LIB_SPEC TK_LIB_FLAG TK_LIB_FILE TK_SRC_DIR TK_BIN_DIR TK_VERSION TCL_SHLIB_LD_LIBS TCL_LD_FLAGS TCL_EXTRA_CFLAGS TCL_DEFS TCL_LIBS TCL_STUB_LIB_SPEC TCL_STUB_LIB_FLAG TCL_STUB_LIB_FILE TCL_LIB_SPEC TCL_LIB_FLAG TCL_LIB_FILE TCL_SRC_DIR TCL_BIN_DIR TCL_VERSION PKG_CFLAGS PKG_LIBS PKG_INCLUDES PKG_HEADERS PKG_TCL_SOURCES PKG_STUB_OBJECTS PKG_STUB_SOURCES PKG_STUB_LIB_FILE PKG_LIB_FILE EXEEXT CYGPATH target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking with_tcl with_tk enable_stubs with_tclinclude with_tkinclude with_x with_autostereo with_autostereod with_Xmu enable_threads enable_shared enable_64bit enable_64bit_vis enable_rpath enable_wince with_celib enable_load enable_symbols ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS CPP XMKMF AUTOSTEREOD' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error "unrecognized option: \`$ac_option' Try \`$0 --help' for more information." ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe $as_echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. If a cross compiler is detected then cross compile mode will be used." >&2 elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures Togl 2.1 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/togl] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF X features: --x-includes=DIR X include files are in DIR --x-libraries=DIR X library files are in DIR _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of Togl 2.1:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-stubs build and link with stub libraries (--enable-stubs) --enable-threads build with threads --enable-shared build and link with shared libraries (default: on) --enable-64bit enable 64bit support (default: off) --enable-64bit-vis enable 64bit Sparc VIS support (default: off) --disable-rpath disable rpath support (default: on) --enable-wince enable Win/CE support (where applicable) --enable-load allow dynamic loading and "load" command (default: on) --enable-symbols build with debugging symbols (default: off) Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-tcl directory containing tcl configuration (tclConfig.sh) --with-tk directory containing tk configuration (tkConfig.sh) --with-tclinclude directory containing the public Tcl header files --with-tkinclude directory containing the public Tk header files --with-x use the X Window System --with-autostereo directory with autostereo source (for SGI) --with-autostereod path to autostereod daemon (for SGI) --with-Xmu use system's shared Xmu library --with-celib=DIR use Windows/CE support library from DIR Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CPP C preprocessor XMKMF Path to xmkmf, Makefile generator for X Window System AUTOSTEREOD Path to autostereod for SGI IRIX computers Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to the package provider. _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF Togl configure 2.1 generated by GNU Autoconf 2.65 Copyright (C) 2009 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } >/dev/null && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} as_fn_set_status $ac_retval } # ac_fn_c_try_cpp # ac_fn_c_try_run LINENO # ---------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. Assumes # that executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then : ac_retval=0 else $as_echo "$as_me: program exited with status $ac_status" >&5 $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} as_fn_set_status $ac_retval } # ac_fn_c_try_run # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} } # ac_fn_c_check_header_compile # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main () { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} } # ac_fn_c_check_func # ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists, giving a warning if it cannot be compiled using # the include files in INCLUDES and setting the cache variable VAR # accordingly. ac_fn_c_check_header_mongrel () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } else # Is the header compilable? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 $as_echo_n "checking $2 usability... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_header_compiler=yes else ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 $as_echo "$ac_header_compiler" >&6; } # Is the header present? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 $as_echo_n "checking $2 presence... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <$2> _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : ac_header_preproc=yes else ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 $as_echo "$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( yes:no: ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 $as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; no:yes:* ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 $as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 $as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 $as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 $as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} } # ac_fn_c_check_header_mongrel cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by Togl $as_me 2.1, which was generated by GNU Autoconf 2.65. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo cat <<\_ASBOX ## ---------------- ## ## Cache variables. ## ## ---------------- ## _ASBOX echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo cat <<\_ASBOX ## ----------------- ## ## Output variables. ## ## ----------------- ## _ASBOX echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then cat <<\_ASBOX ## ------------------- ## ## File substitutions. ## ## ------------------- ## _ASBOX echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then cat <<\_ASBOX ## ----------- ## ## confdefs.h. ## ## ----------- ## _ASBOX echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h $as_echo "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then ac_site_file1=$CONFIG_SITE elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu #-------------------------------------------------------------------- # Call TEA_INIT as the first TEA_ macro to set up initial vars. # This will define a ${TEA_PLATFORM} variable == "unix" or "windows" # as well as PKG_LIB_FILE and PKG_STUB_LIB_FILE. #-------------------------------------------------------------------- # TEA extensions pass this us the version of TEA they think they # are compatible with. TEA_VERSION="3.7" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for correct TEA configuration" >&5 $as_echo_n "checking for correct TEA configuration... " >&6; } if test x"${PACKAGE_NAME}" = x ; then as_fn_error " The PACKAGE_NAME variable must be defined by your TEA configure.in" "$LINENO" 5 fi if test x"3.7" = x ; then as_fn_error " TEA version not specified." "$LINENO" 5 elif test "3.7" != "${TEA_VERSION}" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: warning: requested TEA version \"3.7\", have \"${TEA_VERSION}\"" >&5 $as_echo "warning: requested TEA version \"3.7\", have \"${TEA_VERSION}\"" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok (TEA ${TEA_VERSION})" >&5 $as_echo "ok (TEA ${TEA_VERSION})" >&6; } fi case "`uname -s`" in *win32*|*WIN32*|*CYGWIN_NT*|*CYGWIN_9*|*CYGWIN_ME*|*MINGW32_*) # Extract the first word of "cygpath", so it can be a program name with args. set dummy cygpath; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_CYGPATH+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CYGPATH"; then ac_cv_prog_CYGPATH="$CYGPATH" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CYGPATH="cygpath -w" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_CYGPATH" && ac_cv_prog_CYGPATH="echo" fi fi CYGPATH=$ac_cv_prog_CYGPATH if test -n "$CYGPATH"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CYGPATH" >&5 $as_echo "$CYGPATH" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi EXEEXT=".exe" TEA_PLATFORM="windows" ;; *) CYGPATH=echo EXEEXT="" TEA_PLATFORM="unix" ;; esac # Check if exec_prefix is set. If not use fall back to prefix. # Note when adjusted, so that TEA_PREFIX can correct for this. # This is needed for recursive configures, since autoconf propagates # $prefix, but not $exec_prefix (doh!). if test x$exec_prefix = xNONE ; then exec_prefix_default=yes exec_prefix=$prefix fi # This package name must be replaced statically for AC_SUBST to work # Substitute STUB_LIB_FILE in case package creates a stub library too. # We AC_SUBST these here to ensure they are subst'ed, # in case the user doesn't call TEA_ADD_... ac_aux_dir= for ac_dir in tclconfig "$srcdir"/tclconfig; do for ac_t in install-sh install.sh shtool; do if test -f "$ac_dir/$ac_t"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/$ac_t -c" break 2 fi done done if test -z "$ac_aux_dir"; then as_fn_error "cannot find install-sh, install.sh, or shtool in tclconfig \"$srcdir\"/tclconfig" "$LINENO" 5 fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. #-------------------------------------------------------------------- # Load the tclConfig.sh file #-------------------------------------------------------------------- # # Ok, lets find the tcl configuration # First, look for one uninstalled. # the alternative search directory is invoked by --with-tcl # if test x"${no_tcl}" = x ; then # we reset no_tcl in case something fails here no_tcl=true # Check whether --with-tcl was given. if test "${with_tcl+set}" = set; then : withval=$with_tcl; with_tclconfig=${withval} fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Tcl configuration" >&5 $as_echo_n "checking for Tcl configuration... " >&6; } if test "${ac_cv_c_tclconfig+set}" = set; then : $as_echo_n "(cached) " >&6 else # First check to see if --with-tcl was specified. if test x"${with_tclconfig}" != x ; then case ${with_tclconfig} in */tclConfig.sh ) if test -f ${with_tclconfig}; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: --with-tcl argument should refer to directory containing tclConfig.sh, not to tclConfig.sh itself" >&5 $as_echo "$as_me: WARNING: --with-tcl argument should refer to directory containing tclConfig.sh, not to tclConfig.sh itself" >&2;} with_tclconfig=`echo ${with_tclconfig} | sed 's!/tclConfig\.sh$!!'` fi ;; esac if test -f "${with_tclconfig}/tclConfig.sh" ; then ac_cv_c_tclconfig=`(cd ${with_tclconfig}; pwd)` else as_fn_error "${with_tclconfig} directory doesn't contain tclConfig.sh" "$LINENO" 5 fi fi # then check for a private Tcl installation if test x"${ac_cv_c_tclconfig}" = x ; then for i in \ ../tcl \ `ls -dr ../tcl[8-9].[0-9].[0-9]* 2>/dev/null` \ `ls -dr ../tcl[8-9].[0-9] 2>/dev/null` \ `ls -dr ../tcl[8-9].[0-9]* 2>/dev/null` \ ../../tcl \ `ls -dr ../../tcl[8-9].[0-9].[0-9]* 2>/dev/null` \ `ls -dr ../../tcl[8-9].[0-9] 2>/dev/null` \ `ls -dr ../../tcl[8-9].[0-9]* 2>/dev/null` \ ../../../tcl \ `ls -dr ../../../tcl[8-9].[0-9].[0-9]* 2>/dev/null` \ `ls -dr ../../../tcl[8-9].[0-9] 2>/dev/null` \ `ls -dr ../../../tcl[8-9].[0-9]* 2>/dev/null` ; do if test -f "$i/unix/tclConfig.sh" ; then ac_cv_c_tclconfig=`(cd $i/unix; pwd)` break fi done fi # on Darwin, check in Framework installation locations if test "`uname -s`" = "Darwin" -a x"${ac_cv_c_tclconfig}" = x ; then for i in `ls -d ~/Library/Frameworks 2>/dev/null` \ `ls -d /Library/Frameworks 2>/dev/null` \ `ls -d /Network/Library/Frameworks 2>/dev/null` \ `ls -d /System/Library/Frameworks 2>/dev/null` \ ; do if test -f "$i/Tcl.framework/tclConfig.sh" ; then ac_cv_c_tclconfig=`(cd $i/Tcl.framework; pwd)` break fi done fi # TEA specific: on Windows, check in common installation locations if test "${TEA_PLATFORM}" = "windows" \ -a x"${ac_cv_c_tclconfig}" = x ; then for i in `ls -d C:/Tcl/lib 2>/dev/null` \ `ls -d C:/Progra~1/Tcl/lib 2>/dev/null` \ ; do if test -f "$i/tclConfig.sh" ; then ac_cv_c_tclconfig=`(cd $i; pwd)` break fi done fi # check in a few common install locations if test x"${ac_cv_c_tclconfig}" = x ; then for i in `ls -d ${libdir} 2>/dev/null` \ `ls -d ${exec_prefix}/lib 2>/dev/null` \ `ls -d ${prefix}/lib 2>/dev/null` \ `ls -d /usr/local/lib 2>/dev/null` \ `ls -d /usr/contrib/lib 2>/dev/null` \ `ls -d /usr/lib 2>/dev/null` \ ; do if test -f "$i/tclConfig.sh" ; then ac_cv_c_tclconfig=`(cd $i; pwd)` break fi done fi # check in a few other private locations if test x"${ac_cv_c_tclconfig}" = x ; then for i in \ ${srcdir}/../tcl \ `ls -dr ${srcdir}/../tcl[8-9].[0-9].[0-9]* 2>/dev/null` \ `ls -dr ${srcdir}/../tcl[8-9].[0-9] 2>/dev/null` \ `ls -dr ${srcdir}/../tcl[8-9].[0-9]* 2>/dev/null` ; do if test -f "$i/unix/tclConfig.sh" ; then ac_cv_c_tclconfig=`(cd $i/unix; pwd)` break fi done fi fi if test x"${ac_cv_c_tclconfig}" = x ; then TCL_BIN_DIR="# no Tcl configs found" as_fn_error "Can't find Tcl configuration definitions" "$LINENO" 5 else no_tcl= TCL_BIN_DIR=${ac_cv_c_tclconfig} { $as_echo "$as_me:${as_lineno-$LINENO}: result: found ${TCL_BIN_DIR}/tclConfig.sh" >&5 $as_echo "found ${TCL_BIN_DIR}/tclConfig.sh" >&6; } fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for existence of ${TCL_BIN_DIR}/tclConfig.sh" >&5 $as_echo_n "checking for existence of ${TCL_BIN_DIR}/tclConfig.sh... " >&6; } if test -f "${TCL_BIN_DIR}/tclConfig.sh" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: loading" >&5 $as_echo "loading" >&6; } . "${TCL_BIN_DIR}/tclConfig.sh" else { $as_echo "$as_me:${as_lineno-$LINENO}: result: could not find ${TCL_BIN_DIR}/tclConfig.sh" >&5 $as_echo "could not find ${TCL_BIN_DIR}/tclConfig.sh" >&6; } fi # eval is required to do the TCL_DBGX substitution eval "TCL_LIB_FILE=\"${TCL_LIB_FILE}\"" eval "TCL_STUB_LIB_FILE=\"${TCL_STUB_LIB_FILE}\"" # If the TCL_BIN_DIR is the build directory (not the install directory), # then set the common variable name to the value of the build variables. # For example, the variable TCL_LIB_SPEC will be set to the value # of TCL_BUILD_LIB_SPEC. An extension should make use of TCL_LIB_SPEC # instead of TCL_BUILD_LIB_SPEC since it will work with both an # installed and uninstalled version of Tcl. if test -f "${TCL_BIN_DIR}/Makefile" ; then TCL_LIB_SPEC=${TCL_BUILD_LIB_SPEC} TCL_STUB_LIB_SPEC=${TCL_BUILD_STUB_LIB_SPEC} TCL_STUB_LIB_PATH=${TCL_BUILD_STUB_LIB_PATH} elif test "`uname -s`" = "Darwin"; then # If Tcl was built as a framework, attempt to use the libraries # from the framework at the given location so that linking works # against Tcl.framework installed in an arbitrary location. case ${TCL_DEFS} in *TCL_FRAMEWORK*) if test -f "${TCL_BIN_DIR}/${TCL_LIB_FILE}"; then for i in "`cd ${TCL_BIN_DIR}; pwd`" \ "`cd ${TCL_BIN_DIR}/../..; pwd`"; do if test "`basename "$i"`" = "${TCL_LIB_FILE}.framework"; then TCL_LIB_SPEC="-F`dirname "$i"` -framework ${TCL_LIB_FILE}" break fi done fi if test -f "${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}"; then TCL_STUB_LIB_SPEC="-L${TCL_BIN_DIR} ${TCL_STUB_LIB_FLAG}" TCL_STUB_LIB_PATH="${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}" fi ;; esac fi # eval is required to do the TCL_DBGX substitution eval "TCL_LIB_FLAG=\"${TCL_LIB_FLAG}\"" eval "TCL_LIB_SPEC=\"${TCL_LIB_SPEC}\"" eval "TCL_STUB_LIB_FLAG=\"${TCL_STUB_LIB_FLAG}\"" eval "TCL_STUB_LIB_SPEC=\"${TCL_STUB_LIB_SPEC}\"" # TEA specific: #-------------------------------------------------------------------- # Load the tkConfig.sh file if necessary (Tk extension) #-------------------------------------------------------------------- # # Ok, lets find the tk configuration # First, look for one uninstalled. # the alternative search directory is invoked by --with-tk # if test x"${no_tk}" = x ; then # we reset no_tk in case something fails here no_tk=true # Check whether --with-tk was given. if test "${with_tk+set}" = set; then : withval=$with_tk; with_tkconfig=${withval} fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Tk configuration" >&5 $as_echo_n "checking for Tk configuration... " >&6; } if test "${ac_cv_c_tkconfig+set}" = set; then : $as_echo_n "(cached) " >&6 else # First check to see if --with-tkconfig was specified. if test x"${with_tkconfig}" != x ; then case ${with_tkconfig} in */tkConfig.sh ) if test -f ${with_tkconfig}; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: --with-tk argument should refer to directory containing tkConfig.sh, not to tkConfig.sh itself" >&5 $as_echo "$as_me: WARNING: --with-tk argument should refer to directory containing tkConfig.sh, not to tkConfig.sh itself" >&2;} with_tkconfig=`echo ${with_tkconfig} | sed 's!/tkConfig\.sh$!!'` fi ;; esac if test -f "${with_tkconfig}/tkConfig.sh" ; then ac_cv_c_tkconfig=`(cd ${with_tkconfig}; pwd)` else as_fn_error "${with_tkconfig} directory doesn't contain tkConfig.sh" "$LINENO" 5 fi fi # then check for a private Tk library if test x"${ac_cv_c_tkconfig}" = x ; then for i in \ ../tk \ `ls -dr ../tk[8-9].[0-9].[0-9]* 2>/dev/null` \ `ls -dr ../tk[8-9].[0-9] 2>/dev/null` \ `ls -dr ../tk[8-9].[0-9]* 2>/dev/null` \ ../../tk \ `ls -dr ../../tk[8-9].[0-9].[0-9]* 2>/dev/null` \ `ls -dr ../../tk[8-9].[0-9] 2>/dev/null` \ `ls -dr ../../tk[8-9].[0-9]* 2>/dev/null` \ ../../../tk \ `ls -dr ../../../tk[8-9].[0-9].[0-9]* 2>/dev/null` \ `ls -dr ../../../tk[8-9].[0-9] 2>/dev/null` \ `ls -dr ../../../tk[8-9].[0-9]* 2>/dev/null` ; do if test -f "$i/unix/tkConfig.sh" ; then ac_cv_c_tkconfig=`(cd $i/unix; pwd)` break fi done fi # on Darwin, check in Framework installation locations if test "`uname -s`" = "Darwin" -a x"${ac_cv_c_tkconfig}" = x ; then for i in `ls -d ~/Library/Frameworks 2>/dev/null` \ `ls -d /Library/Frameworks 2>/dev/null` \ `ls -d /Network/Library/Frameworks 2>/dev/null` \ `ls -d /System/Library/Frameworks 2>/dev/null` \ ; do if test -f "$i/Tk.framework/tkConfig.sh" ; then ac_cv_c_tkconfig=`(cd $i/Tk.framework; pwd)` break fi done fi # check in a few common install locations if test x"${ac_cv_c_tkconfig}" = x ; then for i in `ls -d ${libdir} 2>/dev/null` \ `ls -d ${exec_prefix}/lib 2>/dev/null` \ `ls -d ${prefix}/lib 2>/dev/null` \ `ls -d /usr/local/lib 2>/dev/null` \ `ls -d /usr/contrib/lib 2>/dev/null` \ `ls -d /usr/lib 2>/dev/null` \ ; do if test -f "$i/tkConfig.sh" ; then ac_cv_c_tkconfig=`(cd $i; pwd)` break fi done fi # TEA specific: on Windows, check in common installation locations if test "${TEA_PLATFORM}" = "windows" \ -a x"${ac_cv_c_tkconfig}" = x ; then for i in `ls -d C:/Tcl/lib 2>/dev/null` \ `ls -d C:/Progra~1/Tcl/lib 2>/dev/null` \ ; do if test -f "$i/tkConfig.sh" ; then ac_cv_c_tkconfig=`(cd $i; pwd)` break fi done fi # check in a few other private locations if test x"${ac_cv_c_tkconfig}" = x ; then for i in \ ${srcdir}/../tk \ `ls -dr ${srcdir}/../tk[8-9].[0-9].[0-9]* 2>/dev/null` \ `ls -dr ${srcdir}/../tk[8-9].[0-9] 2>/dev/null` \ `ls -dr ${srcdir}/../tk[8-9].[0-9]* 2>/dev/null` ; do if test -f "$i/unix/tkConfig.sh" ; then ac_cv_c_tkconfig=`(cd $i/unix; pwd)` break fi done fi fi if test x"${ac_cv_c_tkconfig}" = x ; then TK_BIN_DIR="# no Tk configs found" as_fn_error "Can't find Tk configuration definitions" "$LINENO" 5 else no_tk= TK_BIN_DIR=${ac_cv_c_tkconfig} { $as_echo "$as_me:${as_lineno-$LINENO}: result: found ${TK_BIN_DIR}/tkConfig.sh" >&5 $as_echo "found ${TK_BIN_DIR}/tkConfig.sh" >&6; } fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for existence of ${TK_BIN_DIR}/tkConfig.sh" >&5 $as_echo_n "checking for existence of ${TK_BIN_DIR}/tkConfig.sh... " >&6; } if test -f "${TK_BIN_DIR}/tkConfig.sh" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: loading" >&5 $as_echo "loading" >&6; } . "${TK_BIN_DIR}/tkConfig.sh" else { $as_echo "$as_me:${as_lineno-$LINENO}: result: could not find ${TK_BIN_DIR}/tkConfig.sh" >&5 $as_echo "could not find ${TK_BIN_DIR}/tkConfig.sh" >&6; } fi # eval is required to do the TK_DBGX substitution eval "TK_LIB_FILE=\"${TK_LIB_FILE}\"" eval "TK_STUB_LIB_FILE=\"${TK_STUB_LIB_FILE}\"" # If the TK_BIN_DIR is the build directory (not the install directory), # then set the common variable name to the value of the build variables. # For example, the variable TK_LIB_SPEC will be set to the value # of TK_BUILD_LIB_SPEC. An extension should make use of TK_LIB_SPEC # instead of TK_BUILD_LIB_SPEC since it will work with both an # installed and uninstalled version of Tcl. if test -f "${TK_BIN_DIR}/Makefile" ; then TK_LIB_SPEC=${TK_BUILD_LIB_SPEC} TK_STUB_LIB_SPEC=${TK_BUILD_STUB_LIB_SPEC} TK_STUB_LIB_PATH=${TK_BUILD_STUB_LIB_PATH} elif test "`uname -s`" = "Darwin"; then # If Tk was built as a framework, attempt to use the libraries # from the framework at the given location so that linking works # against Tk.framework installed in an arbitrary location. case ${TK_DEFS} in *TK_FRAMEWORK*) if test -f "${TK_BIN_DIR}/${TK_LIB_FILE}"; then for i in "`cd ${TK_BIN_DIR}; pwd`" \ "`cd ${TK_BIN_DIR}/../..; pwd`"; do if test "`basename "$i"`" = "${TK_LIB_FILE}.framework"; then TK_LIB_SPEC="-F`dirname "$i"` -framework ${TK_LIB_FILE}" break fi done fi if test -f "${TK_BIN_DIR}/${TK_STUB_LIB_FILE}"; then TK_STUB_LIB_SPEC="-L${TK_BIN_DIR} ${TK_STUB_LIB_FLAG}" TK_STUB_LIB_PATH="${TK_BIN_DIR}/${TK_STUB_LIB_FILE}" fi ;; esac fi # eval is required to do the TK_DBGX substitution eval "TK_LIB_FLAG=\"${TK_LIB_FLAG}\"" eval "TK_LIB_SPEC=\"${TK_LIB_SPEC}\"" eval "TK_STUB_LIB_FLAG=\"${TK_STUB_LIB_FLAG}\"" eval "TK_STUB_LIB_SPEC=\"${TK_STUB_LIB_SPEC}\"" # TEA specific: Ensure windowingsystem is defined if test "${TEA_PLATFORM}" = "unix" ; then case ${TK_DEFS} in *MAC_OSX_TK*) $as_echo "#define MAC_OSX_TK 1" >>confdefs.h TEA_WINDOWINGSYSTEM="aqua" ;; *) TEA_WINDOWINGSYSTEM="x11" ;; esac elif test "${TEA_PLATFORM}" = "windows" ; then TEA_WINDOWINGSYSTEM="win32" fi # TEA specific: #----------------------------------------------------------------------- # Handle the --prefix=... option by defaulting to what Tcl gave. # Must be called after TEA_LOAD_TCLCONFIG and before TEA_SETUP_COMPILER. #----------------------------------------------------------------------- if test "${prefix}" = "NONE"; then prefix_default=yes if test x"${TCL_PREFIX}" != x; then { $as_echo "$as_me:${as_lineno-$LINENO}: --prefix defaulting to TCL_PREFIX ${TCL_PREFIX}" >&5 $as_echo "$as_me: --prefix defaulting to TCL_PREFIX ${TCL_PREFIX}" >&6;} prefix=${TCL_PREFIX} else { $as_echo "$as_me:${as_lineno-$LINENO}: --prefix defaulting to /usr/local" >&5 $as_echo "$as_me: --prefix defaulting to /usr/local" >&6;} prefix=/usr/local fi fi if test "${exec_prefix}" = "NONE" -a x"${prefix_default}" = x"yes" \ -o x"${exec_prefix_default}" = x"yes" ; then if test x"${TCL_EXEC_PREFIX}" != x; then { $as_echo "$as_me:${as_lineno-$LINENO}: --exec-prefix defaulting to TCL_EXEC_PREFIX ${TCL_EXEC_PREFIX}" >&5 $as_echo "$as_me: --exec-prefix defaulting to TCL_EXEC_PREFIX ${TCL_EXEC_PREFIX}" >&6;} exec_prefix=${TCL_EXEC_PREFIX} else { $as_echo "$as_me:${as_lineno-$LINENO}: --exec-prefix defaulting to ${prefix}" >&5 $as_echo "$as_me: --exec-prefix defaulting to ${prefix}" >&6;} exec_prefix=$prefix fi fi #----------------------------------------------------------------------- # Standard compiler checks. # This sets up CC by using the CC env var, or looks for gcc otherwise. # This also calls AC_PROG_CC, AC_PROG_INSTALL and a few others to create # the basic setup necessary to compile executables. #----------------------------------------------------------------------- # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 $as_echo_n "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if test "${ac_cv_path_install+set}" = set; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. # Account for people who put trailing slashes in PATH elements. case $as_dir/ in #(( ./ | .// | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else rm -rf conftest.one conftest.two conftest.dir echo one > conftest.one echo two > conftest.two mkdir conftest.dir if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi fi done done ;; esac done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir fi if test "${ac_cv_path_install+set}" = set; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 $as_echo "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' # Don't put any macros that use the compiler (e.g. AC_TRY_COMPILE) # in this macro, they need to go into TEA_SETUP_COMPILER instead. # If the user did not set CFLAGS, set it now to keep # the AC_PROG_CC macro from adding "-g -O2". if test "${CFLAGS+set}" != "set" ; then CFLAGS="" fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error "no acceptable C compiler found in \$PATH See \`config.log' for more details." "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 $as_echo_n "checking whether the C compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi if test -z "$ac_file"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { as_fn_set_status 77 as_fn_error "C compiler cannot create executables See \`config.log' for more details." "$LINENO" 5; }; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 $as_echo_n "checking for C compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details." "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details." "$LINENO" 5; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if test "${ac_cv_objext+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error "cannot compute suffix of object files: cannot compile See \`config.log' for more details." "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if test "${ac_cv_c_compiler_gnu+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if test "${ac_cv_prog_cc_g+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if test "${ac_cv_prog_cc_c89+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 $as_echo_n "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if test "${ac_cv_prog_CPP+set}" = set; then : $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 $as_echo "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details." "$LINENO" 5; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu #-------------------------------------------------------------------- # Checks to see if the make program sets the $MAKE variable. #-------------------------------------------------------------------- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 $as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } set x ${MAKE-make} ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` if { as_var=ac_cv_prog_make_${ac_make}_set; eval "test \"\${$as_var+set}\" = set"; }; then : $as_echo_n "(cached) " >&6 else cat >conftest.make <<\_ACEOF SHELL = /bin/sh all: @echo '@@@%%%=$(MAKE)=@@@%%%' _ACEOF # GNU make sometimes prints "make[1]: Entering...", which would confuse us. case `${MAKE-make} -f conftest.make 2>/dev/null` in *@@@%%%=?*=@@@%%%*) eval ac_cv_prog_make_${ac_make}_set=yes;; *) eval ac_cv_prog_make_${ac_make}_set=no;; esac rm -f conftest.make fi if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } SET_MAKE= else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } SET_MAKE="MAKE=${MAKE-make}" fi #-------------------------------------------------------------------- # Find ranlib #-------------------------------------------------------------------- if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_RANLIB+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi RANLIB=$ac_cv_prog_RANLIB if test -n "$RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 $as_echo "$RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_RANLIB"; then ac_ct_RANLIB=$RANLIB # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_RANLIB"; then ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_RANLIB="ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB if test -n "$ac_ct_RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 $as_echo "$ac_ct_RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_RANLIB" = x; then RANLIB=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac RANLIB=$ac_ct_RANLIB fi else RANLIB="$ac_cv_prog_RANLIB" fi #-------------------------------------------------------------------- # Determines the correct binary file extension (.o, .obj, .exe etc.) #-------------------------------------------------------------------- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } if test "${ac_cv_path_GREP+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 $as_echo "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } if test "${ac_cv_path_EGREP+set}" = set; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 $as_echo "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if test "${ac_cv_header_stdc+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " eval as_val=\$$as_ac_Header if test "x$as_val" = x""yes; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done # Any macros that use the compiler (e.g. AC_TRY_COMPILE) have to go here. #------------------------------------------------------------------------ # If we're using GCC, see if the compiler understands -pipe. If so, use it. # It makes compiling go faster. (This is only a performance feature.) #------------------------------------------------------------------------ if test -z "$no_pipe" -a -n "$GCC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking if the compiler understands -pipe" >&5 $as_echo_n "checking if the compiler understands -pipe... " >&6; } if test "${tcl_cv_cc_pipe+set}" = set; then : $as_echo_n "(cached) " >&6 else hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -pipe" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : tcl_cv_cc_pipe=yes else tcl_cv_cc_pipe=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext CFLAGS=$hold_cflags fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_cc_pipe" >&5 $as_echo "$tcl_cv_cc_pipe" >&6; } if test $tcl_cv_cc_pipe = yes; then CFLAGS="$CFLAGS -pipe" fi fi #-------------------------------------------------------------------- # Common compiler flag setup #-------------------------------------------------------------------- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5 $as_echo_n "checking whether byte ordering is bigendian... " >&6; } if test "${ac_cv_c_bigendian+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_cv_c_bigendian=unknown # See if we're dealing with a universal compiler. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifndef __APPLE_CC__ not a universal capable compiler #endif typedef int dummy; _ACEOF if ac_fn_c_try_compile "$LINENO"; then : # Check for potential -arch flags. It is not universal unless # there are at least two -arch flags with different values. ac_arch= ac_prev= for ac_word in $CC $CFLAGS $CPPFLAGS $LDFLAGS; do if test -n "$ac_prev"; then case $ac_word in i?86 | x86_64 | ppc | ppc64) if test -z "$ac_arch" || test "$ac_arch" = "$ac_word"; then ac_arch=$ac_word else ac_cv_c_bigendian=universal break fi ;; esac ac_prev= elif test "x$ac_word" = "x-arch"; then ac_prev=arch fi done fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_c_bigendian = unknown; then # See if sys/param.h defines the BYTE_ORDER macro. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { #if ! (defined BYTE_ORDER && defined BIG_ENDIAN \ && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \ && LITTLE_ENDIAN) bogus endian macros #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : # It does; now see whether it defined to BIG_ENDIAN or not. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { #if BYTE_ORDER != BIG_ENDIAN not big endian #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_bigendian=yes else ac_cv_c_bigendian=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi if test $ac_cv_c_bigendian = unknown; then # See if defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris). cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { #if ! (defined _LITTLE_ENDIAN || defined _BIG_ENDIAN) bogus endian macros #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : # It does; now see whether it defined to _BIG_ENDIAN or not. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { #ifndef _BIG_ENDIAN not big endian #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_bigendian=yes else ac_cv_c_bigendian=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi if test $ac_cv_c_bigendian = unknown; then # Compile a test program. if test "$cross_compiling" = yes; then : # Try to guess by grepping values from an object file. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ short int ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 }; short int ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 }; int use_ascii (int i) { return ascii_mm[i] + ascii_ii[i]; } short int ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 }; short int ebcdic_mm[] = { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 }; int use_ebcdic (int i) { return ebcdic_mm[i] + ebcdic_ii[i]; } extern int foo; int main () { return use_ascii (foo) == use_ebcdic (foo); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then ac_cv_c_bigendian=yes fi if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then if test "$ac_cv_c_bigendian" = unknown; then ac_cv_c_bigendian=no else # finding both strings is unlikely to happen, but who knows? ac_cv_c_bigendian=unknown fi fi fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main () { /* Are we little or big endian? From Harbison&Steele. */ union { long int l; char c[sizeof (long int)]; } u; u.l = 1; return u.c[sizeof (long int) - 1] == 1; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_c_bigendian=no else ac_cv_c_bigendian=yes fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5 $as_echo "$ac_cv_c_bigendian" >&6; } case $ac_cv_c_bigendian in #( yes) $as_echo "#define WORDS_BIGENDIAN 1" >>confdefs.h ;; #( no) ;; #( universal) $as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h ;; #( *) as_fn_error "unknown endianness presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;; esac if test "${TEA_PLATFORM}" = "unix" ; then #-------------------------------------------------------------------- # On a few very rare systems, all of the libm.a stuff is # already in libc.a. Set compiler flags accordingly. # Also, Linux requires the "ieee" library for math to work # right (and it must appear before "-lm"). #-------------------------------------------------------------------- ac_fn_c_check_func "$LINENO" "sin" "ac_cv_func_sin" if test "x$ac_cv_func_sin" = x""yes; then : MATH_LIBS="" else MATH_LIBS="-lm" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lieee" >&5 $as_echo_n "checking for main in -lieee... " >&6; } if test "${ac_cv_lib_ieee_main+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lieee $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_ieee_main=yes else ac_cv_lib_ieee_main=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ieee_main" >&5 $as_echo "$ac_cv_lib_ieee_main" >&6; } if test "x$ac_cv_lib_ieee_main" = x""yes; then : MATH_LIBS="-lieee $MATH_LIBS" fi #-------------------------------------------------------------------- # Interactive UNIX requires -linet instead of -lsocket, plus it # needs net/errno.h to define the socket-related error codes. #-------------------------------------------------------------------- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -linet" >&5 $as_echo_n "checking for main in -linet... " >&6; } if test "${ac_cv_lib_inet_main+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-linet $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_inet_main=yes else ac_cv_lib_inet_main=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_inet_main" >&5 $as_echo "$ac_cv_lib_inet_main" >&6; } if test "x$ac_cv_lib_inet_main" = x""yes; then : LIBS="$LIBS -linet" fi ac_fn_c_check_header_mongrel "$LINENO" "net/errno.h" "ac_cv_header_net_errno_h" "$ac_includes_default" if test "x$ac_cv_header_net_errno_h" = x""yes; then : $as_echo "#define HAVE_NET_ERRNO_H 1" >>confdefs.h fi #-------------------------------------------------------------------- # Check for the existence of the -lsocket and -lnsl libraries. # The order here is important, so that they end up in the right # order in the command line generated by make. Here are some # special considerations: # 1. Use "connect" and "accept" to check for -lsocket, and # "gethostbyname" to check for -lnsl. # 2. Use each function name only once: can't redo a check because # autoconf caches the results of the last check and won't redo it. # 3. Use -lnsl and -lsocket only if they supply procedures that # aren't already present in the normal libraries. This is because # IRIX 5.2 has libraries, but they aren't needed and they're # bogus: they goof up name resolution if used. # 4. On some SVR4 systems, can't use -lsocket without -lnsl too. # To get around this problem, check for both libraries together # if -lsocket doesn't work by itself. #-------------------------------------------------------------------- tcl_checkBoth=0 ac_fn_c_check_func "$LINENO" "connect" "ac_cv_func_connect" if test "x$ac_cv_func_connect" = x""yes; then : tcl_checkSocket=0 else tcl_checkSocket=1 fi if test "$tcl_checkSocket" = 1; then ac_fn_c_check_func "$LINENO" "setsockopt" "ac_cv_func_setsockopt" if test "x$ac_cv_func_setsockopt" = x""yes; then : else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for setsockopt in -lsocket" >&5 $as_echo_n "checking for setsockopt in -lsocket... " >&6; } if test "${ac_cv_lib_socket_setsockopt+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lsocket $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char setsockopt (); int main () { return setsockopt (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_socket_setsockopt=yes else ac_cv_lib_socket_setsockopt=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_setsockopt" >&5 $as_echo "$ac_cv_lib_socket_setsockopt" >&6; } if test "x$ac_cv_lib_socket_setsockopt" = x""yes; then : LIBS="$LIBS -lsocket" else tcl_checkBoth=1 fi fi fi if test "$tcl_checkBoth" = 1; then tk_oldLibs=$LIBS LIBS="$LIBS -lsocket -lnsl" ac_fn_c_check_func "$LINENO" "accept" "ac_cv_func_accept" if test "x$ac_cv_func_accept" = x""yes; then : tcl_checkNsl=0 else LIBS=$tk_oldLibs fi fi ac_fn_c_check_func "$LINENO" "gethostbyname" "ac_cv_func_gethostbyname" if test "x$ac_cv_func_gethostbyname" = x""yes; then : else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lnsl" >&5 $as_echo_n "checking for gethostbyname in -lnsl... " >&6; } if test "${ac_cv_lib_nsl_gethostbyname+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lnsl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char gethostbyname (); int main () { return gethostbyname (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_nsl_gethostbyname=yes else ac_cv_lib_nsl_gethostbyname=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_gethostbyname" >&5 $as_echo "$ac_cv_lib_nsl_gethostbyname" >&6; } if test "x$ac_cv_lib_nsl_gethostbyname" = x""yes; then : LIBS="$LIBS -lnsl" fi fi # TEA specific: Don't perform the eval of the libraries here because # DL_LIBS won't be set until we call TEA_CONFIG_CFLAGS TCL_LIBS='${DL_LIBS} ${LIBS} ${MATH_LIBS}' { $as_echo "$as_me:${as_lineno-$LINENO}: checking dirent.h" >&5 $as_echo_n "checking dirent.h... " >&6; } if test "${tcl_cv_dirent_h+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { #ifndef _POSIX_SOURCE # ifdef __Lynx__ /* * Generate compilation error to make the test fail: Lynx headers * are only valid if really in the POSIX environment. */ missing_procedure(); # endif #endif DIR *d; struct dirent *entryPtr; char *p; d = opendir("foobar"); entryPtr = readdir(d); p = entryPtr->d_name; closedir(d); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : tcl_cv_dirent_h=yes else tcl_cv_dirent_h=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_dirent_h" >&5 $as_echo "$tcl_cv_dirent_h" >&6; } if test $tcl_cv_dirent_h = no; then $as_echo "#define NO_DIRENT_H 1" >>confdefs.h fi # TEA specific: ac_fn_c_check_header_mongrel "$LINENO" "errno.h" "ac_cv_header_errno_h" "$ac_includes_default" if test "x$ac_cv_header_errno_h" = x""yes; then : else $as_echo "#define NO_ERRNO_H 1" >>confdefs.h fi ac_fn_c_check_header_mongrel "$LINENO" "float.h" "ac_cv_header_float_h" "$ac_includes_default" if test "x$ac_cv_header_float_h" = x""yes; then : else $as_echo "#define NO_FLOAT_H 1" >>confdefs.h fi ac_fn_c_check_header_mongrel "$LINENO" "values.h" "ac_cv_header_values_h" "$ac_includes_default" if test "x$ac_cv_header_values_h" = x""yes; then : else $as_echo "#define NO_VALUES_H 1" >>confdefs.h fi ac_fn_c_check_header_mongrel "$LINENO" "limits.h" "ac_cv_header_limits_h" "$ac_includes_default" if test "x$ac_cv_header_limits_h" = x""yes; then : $as_echo "#define HAVE_LIMITS_H 1" >>confdefs.h else $as_echo "#define NO_LIMITS_H 1" >>confdefs.h fi ac_fn_c_check_header_mongrel "$LINENO" "stdlib.h" "ac_cv_header_stdlib_h" "$ac_includes_default" if test "x$ac_cv_header_stdlib_h" = x""yes; then : tcl_ok=1 else tcl_ok=0 fi cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "strtol" >/dev/null 2>&1; then : else tcl_ok=0 fi rm -f conftest* cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "strtoul" >/dev/null 2>&1; then : else tcl_ok=0 fi rm -f conftest* cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "strtod" >/dev/null 2>&1; then : else tcl_ok=0 fi rm -f conftest* if test $tcl_ok = 0; then $as_echo "#define NO_STDLIB_H 1" >>confdefs.h fi ac_fn_c_check_header_mongrel "$LINENO" "string.h" "ac_cv_header_string_h" "$ac_includes_default" if test "x$ac_cv_header_string_h" = x""yes; then : tcl_ok=1 else tcl_ok=0 fi cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "strstr" >/dev/null 2>&1; then : else tcl_ok=0 fi rm -f conftest* cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "strerror" >/dev/null 2>&1; then : else tcl_ok=0 fi rm -f conftest* # See also memmove check below for a place where NO_STRING_H can be # set and why. if test $tcl_ok = 0; then $as_echo "#define NO_STRING_H 1" >>confdefs.h fi ac_fn_c_check_header_mongrel "$LINENO" "sys/wait.h" "ac_cv_header_sys_wait_h" "$ac_includes_default" if test "x$ac_cv_header_sys_wait_h" = x""yes; then : else $as_echo "#define NO_SYS_WAIT_H 1" >>confdefs.h fi ac_fn_c_check_header_mongrel "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default" if test "x$ac_cv_header_dlfcn_h" = x""yes; then : else $as_echo "#define NO_DLFCN_H 1" >>confdefs.h fi # OS/390 lacks sys/param.h (and doesn't need it, by chance). for ac_header in sys/param.h do : ac_fn_c_check_header_mongrel "$LINENO" "sys/param.h" "ac_cv_header_sys_param_h" "$ac_includes_default" if test "x$ac_cv_header_sys_param_h" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SYS_PARAM_H 1 _ACEOF fi done # Let the user call this, because if it triggers, they will # need a compat/strtod.c that is correct. Users can also # use Tcl_GetDouble(FromObj) instead. #TEA_BUGGY_STRTOD fi #----------------------------------------------------------------------- # __CHANGE__ # Specify the C source files to compile in TEA_ADD_SOURCES, # public headers that need to be installed in TEA_ADD_HEADERS, # stub library C source files to compile in TEA_ADD_STUB_SOURCES, # and runtime Tcl library files in TEA_ADD_TCL_SOURCES. # This defines PKG(_STUB)_SOURCES, PKG(_STUB)_OBJECTS, PKG_HEADERS # and PKG_TCL_SOURCES. #----------------------------------------------------------------------- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to link with stubs library" >&5 $as_echo_n "checking whether to link with stubs library... " >&6; } # Check whether --enable-stubs was given. if test "${enable_stubs+set}" = set; then : enableval=$enable_stubs; tcl_ok=$enableval else tcl_ok=yes fi if test "${enable_stubs+set}" = set; then enableval="$enable_stubs" tcl_ok=$enableval else tcl_ok=yes fi if test "$tcl_ok" = "yes" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: stubs" >&5 $as_echo "stubs" >&6; } USE_STUBS=1 else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no stubs" >&5 $as_echo "no stubs" >&6; } USE_STUBS=0 fi vars="togl.c toglProcAddr.c toglStubInit.c" for i in $vars; do case $i in \$*) # allow $-var names PKG_SOURCES="$PKG_SOURCES $i" PKG_OBJECTS="$PKG_OBJECTS $i" ;; *) # check for existence - allows for generic/win/unix VPATH # To add more dirs here (like 'src'), you have to update VPATH # in Makefile.in as well if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/generic/$i" \ -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ ; then as_fn_error "could not find source file '$i'" "$LINENO" 5 fi PKG_SOURCES="$PKG_SOURCES $i" # this assumes it is in a VPATH dir i=`basename $i` # handle user calling this before or after TEA_SETUP_COMPILER if test x"${OBJEXT}" != x ; then j="`echo $i | sed -e 's/\.[^.]*$//'`.${OBJEXT}" else j="`echo $i | sed -e 's/\.[^.]*$//'`.\${OBJEXT}" fi PKG_OBJECTS="$PKG_OBJECTS $j" ;; esac done # togl_ws.h is added in Makefile.in because it is generated vars="togl.h toglDecls.h" for i in $vars; do # check for existence, be strict because it is installed if test ! -f "${srcdir}/$i" ; then as_fn_error "could not find header file '${srcdir}/$i'" "$LINENO" 5 fi PKG_HEADERS="$PKG_HEADERS $i" done vars="" for i in $vars; do PKG_INCLUDES="$PKG_INCLUDES $i" done vars="" for i in $vars; do if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then # Convert foo.lib to -lfoo for GCC. No-op if not *.lib i=`echo "$i" | sed -e 's/^\([^-].*\)\.lib$/-l\1/i'` fi PKG_LIBS="$PKG_LIBS $i" done PKG_CFLAGS="$PKG_CFLAGS " if test "${USE_STUBS}" = "1" ; then vars="toglStubLib.c" for i in $vars; do # check for existence - allows for generic/win/unix VPATH if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/generic/$i" \ -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ ; then as_fn_error "could not find stub source file '$i'" "$LINENO" 5 fi PKG_STUB_SOURCES="$PKG_STUB_SOURCES $i" # this assumes it is in a VPATH dir i=`basename $i` # handle user calling this before or after TEA_SETUP_COMPILER if test x"${OBJEXT}" != x ; then j="`echo $i | sed -e 's/\.[^.]*$//'`.${OBJEXT}" else j="`echo $i | sed -e 's/\.[^.]*$//'`.\${OBJEXT}" fi PKG_STUB_OBJECTS="$PKG_STUB_OBJECTS $j" done fi vars="" for i in $vars; do # check for existence, be strict because it is installed if test ! -f "${srcdir}/$i" ; then as_fn_error "could not find tcl source file '${srcdir}/$i'" "$LINENO" 5 fi PKG_TCL_SOURCES="$PKG_TCL_SOURCES $i" done #-------------------------------------------------------------------- # __CHANGE__ # A few miscellaneous platform-specific items: # # Define a special symbol for Windows (BUILD_sample in this case) so # that we create the export library with the dll. # # Windows creates a few extra files that need to be cleaned up. # You can add more files to clean if your extension creates any extra # files. # # TEA_ADD_* any platform specific compiler/build info here. #-------------------------------------------------------------------- # Add pkgIndex.tcl if it is generated in the Makefile instead of ./configure # and change Makefile.in to move it from CONFIG_CLEAN_FILES to BINARIES var. #CLEANFILES="pkgIndex.tcl" if test "${TEA_PLATFORM}" = "windows" ; then $as_echo "#define BUILD_togl 1" >>confdefs.h CLEANFILES="$CLEANFILES *.lib *.dll *.exp *.ilk *.pdb vc*.pch *.manifest" #TEA_ADD_SOURCES([win/winFile.c]) #TEA_ADD_INCLUDES([-I\"$(${CYGPATH} ${srcdir}/win)\"]) else # Ensure no empty else clauses : CLEANFILES="so_locations" #TEA_ADD_SOURCES([unix/unixFile.c]) #TEA_ADD_LIBS([-lsuperfly]) fi #-------------------------------------------------------------------- # __CHANGE__ # Choose which headers you need. Extension authors should try very # hard to only rely on the Tcl public header files. Internal headers # contain private data structures and are subject to change without # notice. # This MUST be called after TEA_LOAD_TCLCONFIG / TEA_LOAD_TKCONFIG #-------------------------------------------------------------------- # find Tcl, Tk, and X11 headers #TEA_PUBLIC_TCL_HEADERS { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Tcl public headers" >&5 $as_echo_n "checking for Tcl public headers... " >&6; } # Check whether --with-tclinclude was given. if test "${with_tclinclude+set}" = set; then : withval=$with_tclinclude; with_tclinclude=${withval} fi if test "${ac_cv_c_tclh+set}" = set; then : $as_echo_n "(cached) " >&6 else # Use the value from --with-tclinclude, if it was given if test x"${with_tclinclude}" != x ; then if test -f "${with_tclinclude}/tcl.h" ; then ac_cv_c_tclh=${with_tclinclude} else as_fn_error "${with_tclinclude} directory does not contain tcl.h" "$LINENO" 5 fi else if test "`uname -s`" = "Darwin"; then # If Tcl was built as a framework, attempt to use # the framework's Headers directory case ${TCL_DEFS} in *TCL_FRAMEWORK*) list="`ls -d ${TCL_BIN_DIR}/Headers 2>/dev/null`" ;; esac fi # Look in the source dir only if Tcl is not installed, # and in that situation, look there before installed locations. if test -f "${TCL_BIN_DIR}/Makefile" ; then list="$list `ls -d ${TCL_SRC_DIR}/generic 2>/dev/null`" fi # Check order: pkg --prefix location, Tcl's --prefix location, # relative to directory of tclConfig.sh. eval "temp_includedir=${includedir}" list="$list \ `ls -d ${temp_includedir} 2>/dev/null` \ `ls -d ${TCL_PREFIX}/include 2>/dev/null` \ `ls -d ${TCL_BIN_DIR}/../include 2>/dev/null`" if test "${TEA_PLATFORM}" != "windows" -o "$GCC" = "yes"; then list="$list /usr/local/include /usr/include" if test x"${TCL_INCLUDE_SPEC}" != x ; then d=`echo "${TCL_INCLUDE_SPEC}" | sed -e 's/^-I//'` list="$list `ls -d ${d} 2>/dev/null`" fi fi for i in $list ; do if test -f "$i/tcl.h" ; then ac_cv_c_tclh=$i break fi done fi fi # Print a message based on how we determined the include path if test x"${ac_cv_c_tclh}" = x ; then as_fn_error "tcl.h not found. Please specify its location with --with-tclinclude" "$LINENO" 5 else { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${ac_cv_c_tclh}" >&5 $as_echo "${ac_cv_c_tclh}" >&6; } fi # Convert to a native path and substitute into the output files. INCLUDE_DIR_NATIVE=`${CYGPATH} ${ac_cv_c_tclh}` TCL_INCLUDES=-I\"${INCLUDE_DIR_NATIVE}\" # Allow for --with-tclinclude to take effect and define ${ac_cv_c_tclh} { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Tcl private include files" >&5 $as_echo_n "checking for Tcl private include files... " >&6; } TCL_SRC_DIR_NATIVE=`${CYGPATH} ${TCL_SRC_DIR}` TCL_TOP_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}\" # Check to see if tclPort.h isn't already with the public headers # Don't look for tclInt.h because that resides with tcl.h in the core # sources, but the Port headers are in a different directory if test "${TEA_PLATFORM}" = "windows" -a \ -f "${ac_cv_c_tclh}/tclWinPort.h"; then result="private headers found with public headers" elif test "${TEA_PLATFORM}" = "unix" -a \ -f "${ac_cv_c_tclh}/tclUnixPort.h"; then result="private headers found with public headers" else TCL_GENERIC_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/generic\" if test "${TEA_PLATFORM}" = "windows"; then TCL_PLATFORM_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/win\" else TCL_PLATFORM_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/unix\" fi # Overwrite the previous TCL_INCLUDES as this should capture both # public and private headers in the same set. # We want to ensure these are substituted so as not to require # any *_NATIVE vars be defined in the Makefile TCL_INCLUDES="-I${TCL_GENERIC_DIR_NATIVE} -I${TCL_PLATFORM_DIR_NATIVE}" if test "`uname -s`" = "Darwin"; then # If Tcl was built as a framework, attempt to use # the framework's Headers and PrivateHeaders directories case ${TCL_DEFS} in *TCL_FRAMEWORK*) if test -d "${TCL_BIN_DIR}/Headers" -a \ -d "${TCL_BIN_DIR}/PrivateHeaders"; then TCL_INCLUDES="-I\"${TCL_BIN_DIR}/Headers\" -I\"${TCL_BIN_DIR}/PrivateHeaders\" ${TCL_INCLUDES}" else TCL_INCLUDES="${TCL_INCLUDES} ${TCL_INCLUDE_SPEC} `echo "${TCL_INCLUDE_SPEC}" | sed -e 's/Headers/PrivateHeaders/'`" fi ;; esac result="Using ${TCL_INCLUDES}" else if test ! -f "${TCL_SRC_DIR}/generic/tclInt.h" ; then as_fn_error "Cannot find private header tclInt.h in ${TCL_SRC_DIR}" "$LINENO" 5 fi result="Using srcdir found in tclConfig.sh: ${TCL_SRC_DIR}" fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${result}" >&5 $as_echo "${result}" >&6; } #TEA_PUBLIC_TK_HEADERS { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Tk public headers" >&5 $as_echo_n "checking for Tk public headers... " >&6; } # Check whether --with-tkinclude was given. if test "${with_tkinclude+set}" = set; then : withval=$with_tkinclude; with_tkinclude=${withval} fi if test "${ac_cv_c_tkh+set}" = set; then : $as_echo_n "(cached) " >&6 else # Use the value from --with-tkinclude, if it was given if test x"${with_tkinclude}" != x ; then if test -f "${with_tkinclude}/tk.h" ; then ac_cv_c_tkh=${with_tkinclude} else as_fn_error "${with_tkinclude} directory does not contain tk.h" "$LINENO" 5 fi else if test "`uname -s`" = "Darwin"; then # If Tk was built as a framework, attempt to use # the framework's Headers directory. case ${TK_DEFS} in *TK_FRAMEWORK*) list="`ls -d ${TK_BIN_DIR}/Headers 2>/dev/null`" ;; esac fi # Look in the source dir only if Tk is not installed, # and in that situation, look there before installed locations. if test -f "${TK_BIN_DIR}/Makefile" ; then list="$list `ls -d ${TK_SRC_DIR}/generic 2>/dev/null`" fi # Check order: pkg --prefix location, Tk's --prefix location, # relative to directory of tkConfig.sh, Tcl's --prefix location, # relative to directory of tclConfig.sh. eval "temp_includedir=${includedir}" list="$list \ `ls -d ${temp_includedir} 2>/dev/null` \ `ls -d ${TK_PREFIX}/include 2>/dev/null` \ `ls -d ${TK_BIN_DIR}/../include 2>/dev/null` \ `ls -d ${TCL_PREFIX}/include 2>/dev/null` \ `ls -d ${TCL_BIN_DIR}/../include 2>/dev/null`" if test "${TEA_PLATFORM}" != "windows" -o "$GCC" = "yes"; then list="$list /usr/local/include /usr/include" fi for i in $list ; do if test -f "$i/tk.h" ; then ac_cv_c_tkh=$i break fi done fi fi # Print a message based on how we determined the include path if test x"${ac_cv_c_tkh}" = x ; then as_fn_error "tk.h not found. Please specify its location with --with-tkinclude" "$LINENO" 5 else { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${ac_cv_c_tkh}" >&5 $as_echo "${ac_cv_c_tkh}" >&6; } fi # Convert to a native path and substitute into the output files. INCLUDE_DIR_NATIVE=`${CYGPATH} ${ac_cv_c_tkh}` TK_INCLUDES=-I\"${INCLUDE_DIR_NATIVE}\" if test "${TEA_WINDOWINGSYSTEM}" != "x11"; then # On Windows and Aqua, we need the X compat headers { $as_echo "$as_me:${as_lineno-$LINENO}: checking for X11 header files" >&5 $as_echo_n "checking for X11 header files... " >&6; } if test ! -r "${INCLUDE_DIR_NATIVE}/X11/Xlib.h"; then INCLUDE_DIR_NATIVE="`${CYGPATH} ${TK_SRC_DIR}/xlib`" TK_XINCLUDES=-I\"${INCLUDE_DIR_NATIVE}\" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${INCLUDE_DIR_NATIVE}" >&5 $as_echo "${INCLUDE_DIR_NATIVE}" >&6; } fi # Allow for --with-tkinclude to take effect and define ${ac_cv_c_tkh} { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Tk private include files" >&5 $as_echo_n "checking for Tk private include files... " >&6; } TK_SRC_DIR_NATIVE=`${CYGPATH} ${TK_SRC_DIR}` TK_TOP_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}\" # Check to see if tkPort.h isn't already with the public headers # Don't look for tkInt.h because that resides with tk.h in the core # sources, but the Port headers are in a different directory if test "${TEA_PLATFORM}" = "windows" -a \ -f "${ac_cv_c_tkh}/tkWinPort.h"; then result="private headers found with public headers" elif test "${TEA_PLATFORM}" = "unix" -a \ -f "${ac_cv_c_tkh}/tkUnixPort.h"; then result="private headers found with public headers" else TK_GENERIC_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/generic\" TK_XLIB_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/xlib\" if test "${TEA_PLATFORM}" = "windows"; then TK_PLATFORM_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/win\" else TK_PLATFORM_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/unix\" fi # Overwrite the previous TK_INCLUDES as this should capture both # public and private headers in the same set. # We want to ensure these are substituted so as not to require # any *_NATIVE vars be defined in the Makefile TK_INCLUDES="-I${TK_GENERIC_DIR_NATIVE} -I${TK_PLATFORM_DIR_NATIVE}" # Detect and add ttk subdir if test -d "${TK_SRC_DIR}/generic/ttk"; then TK_INCLUDES="${TK_INCLUDES} -I\"${TK_SRC_DIR_NATIVE}/generic/ttk\"" fi if test "${TEA_WINDOWINGSYSTEM}" != "x11"; then TK_INCLUDES="${TK_INCLUDES} -I${TK_XLIB_DIR_NATIVE}" fi if test "${TEA_WINDOWINGSYSTEM}" = "aqua"; then TK_INCLUDES="${TK_INCLUDES} -I\"${TK_SRC_DIR_NATIVE}/macosx\"" fi if test "`uname -s`" = "Darwin"; then # If Tk was built as a framework, attempt to use # the framework's Headers and PrivateHeaders directories case ${TK_DEFS} in *TK_FRAMEWORK*) if test -d "${TK_BIN_DIR}/Headers" -a \ -d "${TK_BIN_DIR}/PrivateHeaders"; then TK_INCLUDES="-I\"${TK_BIN_DIR}/Headers\" -I\"${TK_BIN_DIR}/PrivateHeaders\" ${TK_INCLUDES}" else TK_INCLUDES="${TK_INCLUDES} ${TK_INCLUDE_SPEC} `echo "${TK_INCLUDE_SPEC}" | sed -e 's/Headers/PrivateHeaders/'`" fi ;; esac result="Using ${TK_INCLUDES}" else if test ! -f "${TK_SRC_DIR}/generic/tkInt.h" ; then as_fn_error "Cannot find private header tkInt.h in ${TK_SRC_DIR}" "$LINENO" 5 fi result="Using srcdir found in tkConfig.sh: ${TK_SRC_DIR}" fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${result}" >&5 $as_echo "${result}" >&6; } if test "${TEA_WINDOWINGSYSTEM}" = "x11" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for X" >&5 $as_echo_n "checking for X... " >&6; } # Check whether --with-x was given. if test "${with_x+set}" = set; then : withval=$with_x; fi # $have_x is `yes', `no', `disabled', or empty when we do not yet know. if test "x$with_x" = xno; then # The user explicitly disabled X. have_x=disabled else case $x_includes,$x_libraries in #( *\'*) as_fn_error "cannot use X directory names containing '" "$LINENO" 5;; #( *,NONE | NONE,*) if test "${ac_cv_have_x+set}" = set; then : $as_echo_n "(cached) " >&6 else # One or both of the vars are not set, and there is no cached value. ac_x_includes=no ac_x_libraries=no rm -f -r conftest.dir if mkdir conftest.dir; then cd conftest.dir cat >Imakefile <<'_ACEOF' incroot: @echo incroot='${INCROOT}' usrlibdir: @echo usrlibdir='${USRLIBDIR}' libdir: @echo libdir='${LIBDIR}' _ACEOF if (export CC; ${XMKMF-xmkmf}) >/dev/null 2>/dev/null && test -f Makefile; then # GNU make sometimes prints "make[1]: Entering...", which would confuse us. for ac_var in incroot usrlibdir libdir; do eval "ac_im_$ac_var=\`\${MAKE-make} $ac_var 2>/dev/null | sed -n 's/^$ac_var=//p'\`" done # Open Windows xmkmf reportedly sets LIBDIR instead of USRLIBDIR. for ac_extension in a so sl dylib la dll; do if test ! -f "$ac_im_usrlibdir/libX11.$ac_extension" && test -f "$ac_im_libdir/libX11.$ac_extension"; then ac_im_usrlibdir=$ac_im_libdir; break fi done # Screen out bogus values from the imake configuration. They are # bogus both because they are the default anyway, and because # using them would break gcc on systems where it needs fixed includes. case $ac_im_incroot in /usr/include) ac_x_includes= ;; *) test -f "$ac_im_incroot/X11/Xos.h" && ac_x_includes=$ac_im_incroot;; esac case $ac_im_usrlibdir in /usr/lib | /usr/lib64 | /lib | /lib64) ;; *) test -d "$ac_im_usrlibdir" && ac_x_libraries=$ac_im_usrlibdir ;; esac fi cd .. rm -f -r conftest.dir fi # Standard set of common directories for X headers. # Check X11 before X11Rn because it is often a symlink to the current release. ac_x_header_dirs=' /usr/X11/include /usr/X11R7/include /usr/X11R6/include /usr/X11R5/include /usr/X11R4/include /usr/include/X11 /usr/include/X11R7 /usr/include/X11R6 /usr/include/X11R5 /usr/include/X11R4 /usr/local/X11/include /usr/local/X11R7/include /usr/local/X11R6/include /usr/local/X11R5/include /usr/local/X11R4/include /usr/local/include/X11 /usr/local/include/X11R7 /usr/local/include/X11R6 /usr/local/include/X11R5 /usr/local/include/X11R4 /usr/X386/include /usr/x386/include /usr/XFree86/include/X11 /usr/include /usr/local/include /usr/unsupported/include /usr/athena/include /usr/local/x11r5/include /usr/lpp/Xamples/include /usr/openwin/include /usr/openwin/share/include' if test "$ac_x_includes" = no; then # Guess where to find include files, by looking for Xlib.h. # First, try using that file with no special directory specified. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # We can compile using X headers with no special include directory. ac_x_includes= else for ac_dir in $ac_x_header_dirs; do if test -r "$ac_dir/X11/Xlib.h"; then ac_x_includes=$ac_dir break fi done fi rm -f conftest.err conftest.$ac_ext fi # $ac_x_includes = no if test "$ac_x_libraries" = no; then # Check for the libraries. # See if we find them without any special options. # Don't add to $LIBS permanently. ac_save_LIBS=$LIBS LIBS="-lX11 $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { XrmInitialize () ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : LIBS=$ac_save_LIBS # We can link X programs with no special library path. ac_x_libraries= else LIBS=$ac_save_LIBS for ac_dir in `$as_echo "$ac_x_includes $ac_x_header_dirs" | sed s/include/lib/g` do # Don't even attempt the hair of trying to link an X program! for ac_extension in a so sl dylib la dll; do if test -r "$ac_dir/libX11.$ac_extension"; then ac_x_libraries=$ac_dir break 2 fi done done fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi # $ac_x_libraries = no case $ac_x_includes,$ac_x_libraries in #( no,* | *,no | *\'*) # Didn't find X, or a directory has "'" in its name. ac_cv_have_x="have_x=no";; #( *) # Record where we found X for the cache. ac_cv_have_x="have_x=yes\ ac_x_includes='$ac_x_includes'\ ac_x_libraries='$ac_x_libraries'" esac fi ;; #( *) have_x=yes;; esac eval "$ac_cv_have_x" fi # $with_x != no if test "$have_x" != yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_x" >&5 $as_echo "$have_x" >&6; } no_x=yes else # If each of the values was on the command line, it overrides each guess. test "x$x_includes" = xNONE && x_includes=$ac_x_includes test "x$x_libraries" = xNONE && x_libraries=$ac_x_libraries # Update the cache value to reflect the command line values. ac_cv_have_x="have_x=yes\ ac_x_includes='$x_includes'\ ac_x_libraries='$x_libraries'" { $as_echo "$as_me:${as_lineno-$LINENO}: result: libraries $x_libraries, headers $x_includes" >&5 $as_echo "libraries $x_libraries, headers $x_includes" >&6; } fi not_really_there="" if test "$no_x" = ""; then if test "$x_includes" = ""; then cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else not_really_there="yes" fi rm -f conftest.err conftest.$ac_ext else if test ! -r $x_includes/X11/Intrinsic.h; then not_really_there="yes" fi fi fi if test "$no_x" = "yes" -o "$not_really_there" = "yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for X11 header files" >&5 $as_echo_n "checking for X11 header files... " >&6; } found_xincludes="no" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : found_xincludes="yes" else found_xincludes="no" fi rm -f conftest.err conftest.$ac_ext if test "$found_xincludes" = "no"; then dirs="/usr/unsupported/include /usr/local/include /usr/X386/include /usr/X11R6/include /usr/X11R5/include /usr/include/X11R5 /usr/include/X11R4 /usr/openwin/include /usr/X11/include /usr/sww/include" for i in $dirs ; do if test -r $i/X11/Intrinsic.h; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $i" >&5 $as_echo "$i" >&6; } XINCLUDES=" -I$i" found_xincludes="yes" break fi done fi else if test "$x_includes" != ""; then XINCLUDES="-I$x_includes" found_xincludes="yes" fi fi if test found_xincludes = "no"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: couldn't find any!" >&5 $as_echo "couldn't find any!" >&6; } fi if test "$no_x" = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for X11 libraries" >&5 $as_echo_n "checking for X11 libraries... " >&6; } XLIBSW=nope dirs="/usr/unsupported/lib /usr/local/lib /usr/X386/lib /usr/X11R6/lib /usr/X11R5/lib /usr/lib/X11R5 /usr/lib/X11R4 /usr/openwin/lib /usr/X11/lib /usr/sww/X11/lib" for i in $dirs ; do if test -r $i/libX11.a -o -r $i/libX11.so -o -r $i/libX11.sl -o -r $i/libX11.dylib; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $i" >&5 $as_echo "$i" >&6; } XLIBSW="-L$i -lX11" x_libraries="$i" break fi done else if test "$x_libraries" = ""; then XLIBSW=-lX11 else XLIBSW="-L$x_libraries -lX11" fi fi if test "$XLIBSW" = nope ; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for XCreateWindow in -lXwindow" >&5 $as_echo_n "checking for XCreateWindow in -lXwindow... " >&6; } if test "${ac_cv_lib_Xwindow_XCreateWindow+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lXwindow $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char XCreateWindow (); int main () { return XCreateWindow (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_Xwindow_XCreateWindow=yes else ac_cv_lib_Xwindow_XCreateWindow=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_Xwindow_XCreateWindow" >&5 $as_echo "$ac_cv_lib_Xwindow_XCreateWindow" >&6; } if test "x$ac_cv_lib_Xwindow_XCreateWindow" = x""yes; then : XLIBSW=-lXwindow fi fi if test "$XLIBSW" = nope ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: could not find any! Using -lX11." >&5 $as_echo "could not find any! Using -lX11." >&6; } XLIBSW=-lX11 fi # TEA specific: if test x"${XLIBSW}" != x ; then PKG_LIBS="${PKG_LIBS} ${XLIBSW}" fi fi # find autostereo header, lib, and daemon # Check whether --with-autostereo was given. if test "${with_autostereo+set}" = set; then : withval=$with_autostereo; with_autostereo=${withval} fi # Check whether --with-autostereod was given. if test "${with_autostereod+set}" = set; then : withval=$with_autostereod; with_autostereod=${withval} fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for autostereo directory" >&5 $as_echo_n "checking for autostereo directory... " >&6; } if test x"${with_autostereo}" != x ; then if test -f "${with_autostereo}/lib/autostereo.h" ; then with_autostereo=`(cd ${with_autostereo}; pwd)` vars="-I${with_autostereo}/lib" for i in $vars; do PKG_INCLUDES="$PKG_INCLUDES $i" done vars="-L${with_autostereo}/lib -lautostereo" for i in $vars; do if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then # Convert foo.lib to -lfoo for GCC. No-op if not *.lib i=`echo "$i" | sed -e 's/^\([^-].*\)\.lib$/-l\1/i'` fi PKG_LIBS="$PKG_LIBS $i" done cat >>confdefs.h <<_ACEOF #define HAVE_AUTOSTEREO 1 _ACEOF else as_fn_error "${with_autostereo} directory doesn't contain lib/autostereo.h" "$LINENO" 5 fi fi # Extract the first word of "autostereod", so it can be a program name with args. set dummy autostereod; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_path_AUTOSTEREOD+set}" = set; then : $as_echo_n "(cached) " >&6 else case $AUTOSTEREOD in [\\/]* | ?:[\\/]*) ac_cv_path_AUTOSTEREOD="$AUTOSTEREOD" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_dummy="`eval \"echo $sbindir\"`:$PATH:/sbin:/usr/sbin" for as_dir in $as_dummy do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_AUTOSTEREOD="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi AUTOSTEREOD=$ac_cv_path_AUTOSTEREOD if test -n "$AUTOSTEREOD"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AUTOSTEREOD" >&5 $as_echo "$AUTOSTEREOD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Choose OpenGL platform case "${TEA_WINDOWINGSYSTEM}" in aqua) TOGL_WINDOWINGSYSTEM=TOGL_NSOPENGL CFLAGS="-ObjC" # vars="-framework AGL -framework OpenGL -framework ApplicationServices" vars="-framework OpenGL -framework AppKit -framework ApplicationServices" for i in $vars; do if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then # Convert foo.lib to -lfoo for GCC. No-op if not *.lib i=`echo "$i" | sed -e 's/^\([^-].*\)\.lib$/-l\1/i'` fi PKG_LIBS="$PKG_LIBS $i" done # libGLU is implicit in OpenGL framework LIBGLU= ;; x11) TOGL_WINDOWINGSYSTEM=TOGL_X11 # Check whether --with-Xmu was given. if test "${with_Xmu+set}" = set; then : withval=$with_Xmu; else with_Xmu=no fi if test "x$with_Xmu" != xno; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for XmuLookupStandardColormap in -lXmu" >&5 $as_echo_n "checking for XmuLookupStandardColormap in -lXmu... " >&6; } if test "${ac_cv_lib_Xmu_XmuLookupStandardColormap+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lXmu -lXt -lX11 $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char XmuLookupStandardColormap (); int main () { return XmuLookupStandardColormap (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_Xmu_XmuLookupStandardColormap=yes else ac_cv_lib_Xmu_XmuLookupStandardColormap=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_Xmu_XmuLookupStandardColormap" >&5 $as_echo "$ac_cv_lib_Xmu_XmuLookupStandardColormap" >&6; } if test "x$ac_cv_lib_Xmu_XmuLookupStandardColormap" = x""yes; then : vars="-lXmu" for i in $vars; do if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then # Convert foo.lib to -lfoo for GCC. No-op if not *.lib i=`echo "$i" | sed -e 's/^\([^-].*\)\.lib$/-l\1/i'` fi PKG_LIBS="$PKG_LIBS $i" done $as_echo "#define USE_SYSTEM_LIBXMU 1" >>confdefs.h else with_Xmu=no fi fi if test "x$with_Xmu" = xno; then : vars="Xmu/CmapAlloc.c Xmu/CrCmap.c Xmu/DelCmap.c Xmu/LookupCmap.c Xmu/StdCmap.c" for i in $vars; do case $i in \$*) # allow $-var names PKG_SOURCES="$PKG_SOURCES $i" PKG_OBJECTS="$PKG_OBJECTS $i" ;; *) # check for existence - allows for generic/win/unix VPATH # To add more dirs here (like 'src'), you have to update VPATH # in Makefile.in as well if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/generic/$i" \ -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ ; then as_fn_error "could not find source file '$i'" "$LINENO" 5 fi PKG_SOURCES="$PKG_SOURCES $i" # this assumes it is in a VPATH dir i=`basename $i` # handle user calling this before or after TEA_SETUP_COMPILER if test x"${OBJEXT}" != x ; then j="`echo $i | sed -e 's/\.[^.]*$//'`.${OBJEXT}" else j="`echo $i | sed -e 's/\.[^.]*$//'`.\${OBJEXT}" fi PKG_OBJECTS="$PKG_OBJECTS $j" ;; esac done fi vars="-lGL" for i in $vars; do if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then # Convert foo.lib to -lfoo for GCC. No-op if not *.lib i=`echo "$i" | sed -e 's/^\([^-].*\)\.lib$/-l\1/i'` fi PKG_LIBS="$PKG_LIBS $i" done LIBGLU=-lGLU { $as_echo "$as_me:${as_lineno-$LINENO}: checking if GLX_GLXEXT_LEGACY interferes with including GL/glxext.h" >&5 $as_echo_n "checking if GLX_GLXEXT_LEGACY interferes with including GL/glxext.h... " >&6; } ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_save_CFLAGS=$CFLAGS CFLAGS=$TK_XINCLUDES cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define GLX_GLXEXT_LEGACY #include #undef GLX_VERSION_1_3 #undef GLX_VERSION_1_4 #include int main() { return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define UNDEF_GET_PROC_ADDRESS 1" >>confdefs.h fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext CFLAGS=$ac_save_CFLAGS ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ;; win32) TOGL_WINDOWINGSYSTEM=TOGL_WGL vars="opengl32.lib user32.lib gdi32.lib" for i in $vars; do if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then # Convert foo.lib to -lfoo for GCC. No-op if not *.lib i=`echo "$i" | sed -e 's/^\([^-].*\)\.lib$/-l\1/i'` fi PKG_LIBS="$PKG_LIBS $i" done if test "$GCC" = "yes" ; then LIBGLU=-lglu32 else # assume Microsoft compiler LIBGLU=glu32.lib fi ;; *) as_fn_error "Unsupported windowing system: ${TEA_WINDOWINGSYSTEM}" "$LINENO" 5 ;; esac #-------------------------------------------------------------------- # Check whether --enable-threads or --disable-threads was given. # This auto-enables if Tcl was compiled threaded. #-------------------------------------------------------------------- # Check whether --enable-threads was given. if test "${enable_threads+set}" = set; then : enableval=$enable_threads; tcl_ok=$enableval else tcl_ok=yes fi if test "${enable_threads+set}" = set; then enableval="$enable_threads" tcl_ok=$enableval else tcl_ok=yes fi if test "$tcl_ok" = "yes" -o "${TCL_THREADS}" = 1; then TCL_THREADS=1 if test "${TEA_PLATFORM}" != "windows" ; then # We are always OK on Windows, so check what this platform wants: # USE_THREAD_ALLOC tells us to try the special thread-based # allocator that significantly reduces lock contention $as_echo "#define USE_THREAD_ALLOC 1" >>confdefs.h $as_echo "#define _REENTRANT 1" >>confdefs.h if test "`uname -s`" = "SunOS" ; then $as_echo "#define _POSIX_PTHREAD_SEMANTICS 1" >>confdefs.h fi $as_echo "#define _THREAD_SAFE 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_mutex_init in -lpthread" >&5 $as_echo_n "checking for pthread_mutex_init in -lpthread... " >&6; } if test "${ac_cv_lib_pthread_pthread_mutex_init+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lpthread $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pthread_mutex_init (); int main () { return pthread_mutex_init (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_pthread_pthread_mutex_init=yes else ac_cv_lib_pthread_pthread_mutex_init=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_mutex_init" >&5 $as_echo "$ac_cv_lib_pthread_pthread_mutex_init" >&6; } if test "x$ac_cv_lib_pthread_pthread_mutex_init" = x""yes; then : tcl_ok=yes else tcl_ok=no fi if test "$tcl_ok" = "no"; then # Check a little harder for __pthread_mutex_init in the same # library, as some systems hide it there until pthread.h is # defined. We could alternatively do an AC_TRY_COMPILE with # pthread.h, but that will work with libpthread really doesn't # exist, like AIX 4.2. [Bug: 4359] { $as_echo "$as_me:${as_lineno-$LINENO}: checking for __pthread_mutex_init in -lpthread" >&5 $as_echo_n "checking for __pthread_mutex_init in -lpthread... " >&6; } if test "${ac_cv_lib_pthread___pthread_mutex_init+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lpthread $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char __pthread_mutex_init (); int main () { return __pthread_mutex_init (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_pthread___pthread_mutex_init=yes else ac_cv_lib_pthread___pthread_mutex_init=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread___pthread_mutex_init" >&5 $as_echo "$ac_cv_lib_pthread___pthread_mutex_init" >&6; } if test "x$ac_cv_lib_pthread___pthread_mutex_init" = x""yes; then : tcl_ok=yes else tcl_ok=no fi fi if test "$tcl_ok" = "yes"; then # The space is needed THREADS_LIBS=" -lpthread" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_mutex_init in -lpthreads" >&5 $as_echo_n "checking for pthread_mutex_init in -lpthreads... " >&6; } if test "${ac_cv_lib_pthreads_pthread_mutex_init+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lpthreads $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pthread_mutex_init (); int main () { return pthread_mutex_init (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_pthreads_pthread_mutex_init=yes else ac_cv_lib_pthreads_pthread_mutex_init=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthreads_pthread_mutex_init" >&5 $as_echo "$ac_cv_lib_pthreads_pthread_mutex_init" >&6; } if test "x$ac_cv_lib_pthreads_pthread_mutex_init" = x""yes; then : tcl_ok=yes else tcl_ok=no fi if test "$tcl_ok" = "yes"; then # The space is needed THREADS_LIBS=" -lpthreads" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_mutex_init in -lc" >&5 $as_echo_n "checking for pthread_mutex_init in -lc... " >&6; } if test "${ac_cv_lib_c_pthread_mutex_init+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lc $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pthread_mutex_init (); int main () { return pthread_mutex_init (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_c_pthread_mutex_init=yes else ac_cv_lib_c_pthread_mutex_init=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_pthread_mutex_init" >&5 $as_echo "$ac_cv_lib_c_pthread_mutex_init" >&6; } if test "x$ac_cv_lib_c_pthread_mutex_init" = x""yes; then : tcl_ok=yes else tcl_ok=no fi if test "$tcl_ok" = "no"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_mutex_init in -lc_r" >&5 $as_echo_n "checking for pthread_mutex_init in -lc_r... " >&6; } if test "${ac_cv_lib_c_r_pthread_mutex_init+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lc_r $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pthread_mutex_init (); int main () { return pthread_mutex_init (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_c_r_pthread_mutex_init=yes else ac_cv_lib_c_r_pthread_mutex_init=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_r_pthread_mutex_init" >&5 $as_echo "$ac_cv_lib_c_r_pthread_mutex_init" >&6; } if test "x$ac_cv_lib_c_r_pthread_mutex_init" = x""yes; then : tcl_ok=yes else tcl_ok=no fi if test "$tcl_ok" = "yes"; then # The space is needed THREADS_LIBS=" -pthread" else TCL_THREADS=0 { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Do not know how to find pthread lib on your system - thread support disabled" >&5 $as_echo "$as_me: WARNING: Do not know how to find pthread lib on your system - thread support disabled" >&2;} fi fi fi fi fi else TCL_THREADS=0 fi # Do checking message here to not mess up interleaved configure output { $as_echo "$as_me:${as_lineno-$LINENO}: checking for building with threads" >&5 $as_echo_n "checking for building with threads... " >&6; } if test "${TCL_THREADS}" = 1; then $as_echo "#define TCL_THREADS 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes (default)" >&5 $as_echo "yes (default)" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # TCL_THREADS sanity checking. See if our request for building with # threads is the same as the way Tcl was built. If not, warn the user. case ${TCL_DEFS} in *THREADS=1*) if test "${TCL_THREADS}" = "0"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Building ${PACKAGE_NAME} without threads enabled, but building against Tcl that IS thread-enabled. It is recommended to use --enable-threads." >&5 $as_echo "$as_me: WARNING: Building ${PACKAGE_NAME} without threads enabled, but building against Tcl that IS thread-enabled. It is recommended to use --enable-threads." >&2;} fi ;; *) if test "${TCL_THREADS}" = "1"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: --enable-threads requested, but building against a Tcl that is NOT thread-enabled. This is an OK configuration that will also run in a thread-enabled core." >&5 $as_echo "$as_me: WARNING: --enable-threads requested, but building against a Tcl that is NOT thread-enabled. This is an OK configuration that will also run in a thread-enabled core." >&2;} fi ;; esac #-------------------------------------------------------------------- # The statement below defines a collection of symbols related to # building as a shared library instead of a static library. #-------------------------------------------------------------------- { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to build libraries" >&5 $as_echo_n "checking how to build libraries... " >&6; } # Check whether --enable-shared was given. if test "${enable_shared+set}" = set; then : enableval=$enable_shared; tcl_ok=$enableval else tcl_ok=yes fi if test "${enable_shared+set}" = set; then enableval="$enable_shared" tcl_ok=$enableval else tcl_ok=yes fi if test "$tcl_ok" = "yes" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: shared" >&5 $as_echo "shared" >&6; } SHARED_BUILD=1 else { $as_echo "$as_me:${as_lineno-$LINENO}: result: static" >&5 $as_echo "static" >&6; } SHARED_BUILD=0 $as_echo "#define STATIC_BUILD 1" >>confdefs.h fi #-------------------------------------------------------------------- # This macro figures out what flags to use with the compiler/linker # when building shared/static debug/optimized objects. This information # can be taken from the tclConfig.sh file, but this figures it all out. #-------------------------------------------------------------------- # Step 0.a: Enable 64 bit support? { $as_echo "$as_me:${as_lineno-$LINENO}: checking if 64bit support is requested" >&5 $as_echo_n "checking if 64bit support is requested... " >&6; } # Check whether --enable-64bit was given. if test "${enable_64bit+set}" = set; then : enableval=$enable_64bit; do64bit=$enableval else do64bit=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $do64bit" >&5 $as_echo "$do64bit" >&6; } # Step 0.b: Enable Solaris 64 bit VIS support? { $as_echo "$as_me:${as_lineno-$LINENO}: checking if 64bit Sparc VIS support is requested" >&5 $as_echo_n "checking if 64bit Sparc VIS support is requested... " >&6; } # Check whether --enable-64bit-vis was given. if test "${enable_64bit_vis+set}" = set; then : enableval=$enable_64bit_vis; do64bitVIS=$enableval else do64bitVIS=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $do64bitVIS" >&5 $as_echo "$do64bitVIS" >&6; } # Force 64bit on with VIS if test "$do64bitVIS" = "yes"; then : do64bit=yes fi # Step 0.c: Check if visibility support is available. Do this here so # that platform specific alternatives can be used below if this fails. { $as_echo "$as_me:${as_lineno-$LINENO}: checking if compiler supports visibility \"hidden\"" >&5 $as_echo_n "checking if compiler supports visibility \"hidden\"... " >&6; } if test "${tcl_cv_cc_visibility_hidden+set}" = set; then : $as_echo_n "(cached) " >&6 else hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -Werror" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ extern __attribute__((__visibility__("hidden"))) void f(void); void f(void) {} int main () { f(); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : tcl_cv_cc_visibility_hidden=yes else tcl_cv_cc_visibility_hidden=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext CFLAGS=$hold_cflags fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_cc_visibility_hidden" >&5 $as_echo "$tcl_cv_cc_visibility_hidden" >&6; } if test $tcl_cv_cc_visibility_hidden = yes; then : $as_echo "#define MODULE_SCOPE extern __attribute__((__visibility__(\"hidden\")))" >>confdefs.h fi # Step 0.d: Disable -rpath support? { $as_echo "$as_me:${as_lineno-$LINENO}: checking if rpath support is requested" >&5 $as_echo_n "checking if rpath support is requested... " >&6; } # Check whether --enable-rpath was given. if test "${enable_rpath+set}" = set; then : enableval=$enable_rpath; doRpath=$enableval else doRpath=yes fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $doRpath" >&5 $as_echo "$doRpath" >&6; } # TEA specific: Cross-compiling options for Windows/CE builds? if test "${TEA_PLATFORM}" = windows; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking if Windows/CE build is requested" >&5 $as_echo_n "checking if Windows/CE build is requested... " >&6; } # Check whether --enable-wince was given. if test "${enable_wince+set}" = set; then : enableval=$enable_wince; doWince=$enableval else doWince=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $doWince" >&5 $as_echo "$doWince" >&6; } fi # Step 1: set the variable "system" to hold the name and version number # for the system. { $as_echo "$as_me:${as_lineno-$LINENO}: checking system version" >&5 $as_echo_n "checking system version... " >&6; } if test "${tcl_cv_sys_version+set}" = set; then : $as_echo_n "(cached) " >&6 else # TEA specific: if test "${TEA_PLATFORM}" = "windows" ; then tcl_cv_sys_version=windows elif test -f /usr/lib/NextStep/software_version; then tcl_cv_sys_version=NEXTSTEP-`awk '/3/,/3/' /usr/lib/NextStep/software_version` else tcl_cv_sys_version=`uname -s`-`uname -r` if test "$?" -ne 0 ; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: can't find uname command" >&5 $as_echo "$as_me: WARNING: can't find uname command" >&2;} tcl_cv_sys_version=unknown else # Special check for weird MP-RAS system (uname returns weird # results, and the version is kept in special file). if test -r /etc/.relid -a "X`uname -n`" = "X`uname -s`" ; then tcl_cv_sys_version=MP-RAS-`awk '{print $3}' /etc/.relid` fi if test "`uname -s`" = "AIX" ; then tcl_cv_sys_version=AIX-`uname -v`.`uname -r` fi fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_sys_version" >&5 $as_echo "$tcl_cv_sys_version" >&6; } system=$tcl_cv_sys_version # Step 2: check for existence of -ldl library. This is needed because # Linux can use either -ldl or -ldld for dynamic loading. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } if test "${ac_cv_lib_dl_dlopen+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dl_dlopen=yes else ac_cv_lib_dl_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 $as_echo "$ac_cv_lib_dl_dlopen" >&6; } if test "x$ac_cv_lib_dl_dlopen" = x""yes; then : have_dl=yes else have_dl=no fi # Require ranlib early so we can override it in special cases below. # Step 3: set configuration options based on system name and version. # This is similar to Tcl's unix/tcl.m4 except that we've added a # "windows" case. do64bit_ok=no LDFLAGS_ORIG="$LDFLAGS" # When ld needs options to work in 64-bit mode, put them in # LDFLAGS_ARCH so they eventually end up in LDFLAGS even if [load] # is disabled by the user. [Bug 1016796] LDFLAGS_ARCH="" TCL_EXPORT_FILE_SUFFIX="" UNSHARED_LIB_SUFFIX="" # TEA specific: use PACKAGE_VERSION instead of VERSION TCL_TRIM_DOTS='`echo ${PACKAGE_VERSION} | tr -d .`' ECHO_VERSION='`echo ${PACKAGE_VERSION}`' TCL_LIB_VERSIONS_OK=ok CFLAGS_DEBUG=-g CFLAGS_OPTIMIZE=-O if test "$GCC" = yes; then : # TEA specific: CFLAGS_OPTIMIZE=-O2 CFLAGS_WARNING="-Wall -Wno-implicit-int" else CFLAGS_WARNING="" fi TCL_NEEDS_EXP_FILE=0 TCL_BUILD_EXP_FILE="" TCL_EXP_FILE="" # Extract the first word of "ar", so it can be a program name with args. set dummy ar; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_AR+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$AR"; then ac_cv_prog_AR="$AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_AR="ar" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AR=$ac_cv_prog_AR if test -n "$AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 $as_echo "$AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi STLIB_LD='${AR} cr' LD_LIBRARY_PATH_VAR="LD_LIBRARY_PATH" case $system in # TEA specific: windows) # This is a 2-stage check to make sure we have the 64-bit SDK # We have to know where the SDK is installed. # This magic is based on MS Platform SDK for Win2003 SP1 - hobbs # MACHINE is IX86 for LINK, but this is used by the manifest, # which requires x86|amd64|ia64. MACHINE="X86" if test "$do64bit" != "no" ; then if test "x${MSSDK}x" = "xx" ; then MSSDK="C:/Progra~1/Microsoft Platform SDK" fi MSSDK=`echo "$MSSDK" | sed -e 's!\\\!/!g'` PATH64="" case "$do64bit" in amd64|x64|yes) MACHINE="AMD64" ; # default to AMD64 64-bit build PATH64="${MSSDK}/Bin/Win64/x86/AMD64" ;; ia64) MACHINE="IA64" PATH64="${MSSDK}/Bin/Win64" ;; esac if test ! -d "${PATH64}" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Could not find 64-bit $MACHINE SDK to enable 64bit mode" >&5 $as_echo "$as_me: WARNING: Could not find 64-bit $MACHINE SDK to enable 64bit mode" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Ensure latest Platform SDK is installed" >&5 $as_echo "$as_me: WARNING: Ensure latest Platform SDK is installed" >&2;} do64bit="no" else { $as_echo "$as_me:${as_lineno-$LINENO}: result: Using 64-bit $MACHINE mode" >&5 $as_echo " Using 64-bit $MACHINE mode" >&6; } do64bit_ok="yes" fi fi if test "$doWince" != "no" ; then if test "$do64bit" != "no" ; then as_fn_error "Windows/CE and 64-bit builds incompatible" "$LINENO" 5 fi if test "$GCC" = "yes" ; then as_fn_error "Windows/CE and GCC builds incompatible" "$LINENO" 5 fi # First, look for one uninstalled. # the alternative search directory is invoked by --with-celib if test x"${no_celib}" = x ; then # we reset no_celib in case something fails here no_celib=true # Check whether --with-celib was given. if test "${with_celib+set}" = set; then : withval=$with_celib; with_celibconfig=${withval} fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Windows/CE celib directory" >&5 $as_echo_n "checking for Windows/CE celib directory... " >&6; } if test "${ac_cv_c_celibconfig+set}" = set; then : $as_echo_n "(cached) " >&6 else # First check to see if --with-celibconfig was specified. if test x"${with_celibconfig}" != x ; then if test -d "${with_celibconfig}/inc" ; then ac_cv_c_celibconfig=`(cd ${with_celibconfig}; pwd)` else as_fn_error "${with_celibconfig} directory doesn't contain inc directory" "$LINENO" 5 fi fi # then check for a celib library if test x"${ac_cv_c_celibconfig}" = x ; then for i in \ ../celib-palm-3.0 \ ../celib \ ../../celib-palm-3.0 \ ../../celib \ `ls -dr ../celib-*3.[0-9]* 2>/dev/null` \ ${srcdir}/../celib-palm-3.0 \ ${srcdir}/../celib \ `ls -dr ${srcdir}/../celib-*3.[0-9]* 2>/dev/null` \ ; do if test -d "$i/inc" ; then ac_cv_c_celibconfig=`(cd $i; pwd)` break fi done fi fi if test x"${ac_cv_c_celibconfig}" = x ; then as_fn_error "Cannot find celib support library directory" "$LINENO" 5 else no_celib= CELIB_DIR=${ac_cv_c_celibconfig} CELIB_DIR=`echo "$CELIB_DIR" | sed -e 's!\\\!/!g'` { $as_echo "$as_me:${as_lineno-$LINENO}: result: found $CELIB_DIR" >&5 $as_echo "found $CELIB_DIR" >&6; } fi fi # Set defaults for common evc4/PPC2003 setup # Currently Tcl requires 300+, possibly 420+ for sockets CEVERSION=420; # could be 211 300 301 400 420 ... TARGETCPU=ARMV4; # could be ARMV4 ARM MIPS SH3 X86 ... ARCH=ARM; # could be ARM MIPS X86EM ... PLATFORM="Pocket PC 2003"; # or "Pocket PC 2002" if test "$doWince" != "yes"; then # If !yes then the user specified something # Reset ARCH to allow user to skip specifying it ARCH= eval `echo $doWince | awk -F, '{ \ if (length($1)) { printf "CEVERSION=\"%s\"\n", $1; \ if ($1 < 400) { printf "PLATFORM=\"Pocket PC 2002\"\n" } }; \ if (length($2)) { printf "TARGETCPU=\"%s\"\n", toupper($2) }; \ if (length($3)) { printf "ARCH=\"%s\"\n", toupper($3) }; \ if (length($4)) { printf "PLATFORM=\"%s\"\n", $4 }; \ }'` if test "x${ARCH}" = "x" ; then ARCH=$TARGETCPU; fi fi OSVERSION=WCE$CEVERSION; if test "x${WCEROOT}" = "x" ; then WCEROOT="C:/Program Files/Microsoft eMbedded C++ 4.0" if test ! -d "${WCEROOT}" ; then WCEROOT="C:/Program Files/Microsoft eMbedded Tools" fi fi if test "x${SDKROOT}" = "x" ; then SDKROOT="C:/Program Files/Windows CE Tools" if test ! -d "${SDKROOT}" ; then SDKROOT="C:/Windows CE Tools" fi fi WCEROOT=`echo "$WCEROOT" | sed -e 's!\\\!/!g'` SDKROOT=`echo "$SDKROOT" | sed -e 's!\\\!/!g'` if test ! -d "${SDKROOT}/${OSVERSION}/${PLATFORM}/Lib/${TARGETCPU}" \ -o ! -d "${WCEROOT}/EVC/${OSVERSION}/bin"; then as_fn_error "could not find PocketPC SDK or target compiler to enable WinCE mode $CEVERSION,$TARGETCPU,$ARCH,$PLATFORM" "$LINENO" 5 doWince="no" else # We could PATH_NOSPACE these, but that's not important, # as long as we quote them when used. CEINCLUDE="${SDKROOT}/${OSVERSION}/${PLATFORM}/include" if test -d "${CEINCLUDE}/${TARGETCPU}" ; then CEINCLUDE="${CEINCLUDE}/${TARGETCPU}" fi CELIBPATH="${SDKROOT}/${OSVERSION}/${PLATFORM}/Lib/${TARGETCPU}" fi fi if test "$GCC" != "yes" ; then if test "${SHARED_BUILD}" = "0" ; then runtime=-MT else runtime=-MD fi if test "$do64bit" != "no" ; then # All this magic is necessary for the Win64 SDK RC1 - hobbs CC="\"${PATH64}/cl.exe\"" CFLAGS="${CFLAGS} -I\"${MSSDK}/Include\" -I\"${MSSDK}/Include/crt\" -I\"${MSSDK}/Include/crt/sys\"" RC="\"${MSSDK}/bin/rc.exe\"" lflags="-nologo -MACHINE:${MACHINE} -LIBPATH:\"${MSSDK}/Lib/${MACHINE}\"" LINKBIN="\"${PATH64}/link.exe\"" CFLAGS_DEBUG="-nologo -Zi -Od -W3 ${runtime}d" CFLAGS_OPTIMIZE="-nologo -O2 -W2 ${runtime}" # Avoid 'unresolved external symbol __security_cookie' # errors, c.f. http://support.microsoft.com/?id=894573 vars="bufferoverflowU.lib" for i in $vars; do if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then # Convert foo.lib to -lfoo for GCC. No-op if not *.lib i=`echo "$i" | sed -e 's/^\([^-].*\)\.lib$/-l\1/i'` fi PKG_LIBS="$PKG_LIBS $i" done elif test "$doWince" != "no" ; then CEBINROOT="${WCEROOT}/EVC/${OSVERSION}/bin" if test "${TARGETCPU}" = "X86"; then CC="\"${CEBINROOT}/cl.exe\"" else CC="\"${CEBINROOT}/cl${ARCH}.exe\"" fi CFLAGS="$CFLAGS -I\"${CELIB_DIR}/inc\" -I\"${CEINCLUDE}\"" RC="\"${WCEROOT}/Common/EVC/bin/rc.exe\"" arch=`echo ${ARCH} | awk '{print tolower($0)}'` defs="${ARCH} _${ARCH}_ ${arch} PALM_SIZE _MT _WINDOWS" if test "${SHARED_BUILD}" = "1" ; then # Static CE builds require static celib as well defs="${defs} _DLL" fi for i in $defs ; do cat >>confdefs.h <<_ACEOF #define $i 1 _ACEOF done cat >>confdefs.h <<_ACEOF #define _WIN32_WCE $CEVERSION _ACEOF cat >>confdefs.h <<_ACEOF #define UNDER_CE $CEVERSION _ACEOF CFLAGS_DEBUG="-nologo -Zi -Od" CFLAGS_OPTIMIZE="-nologo -Ox" lversion=`echo ${CEVERSION} | sed -e 's/\(.\)\(..\)/\1\.\2/'` lflags="-MACHINE:${ARCH} -LIBPATH:\"${CELIBPATH}\" -subsystem:windowsce,${lversion} -nologo" LINKBIN="\"${CEBINROOT}/link.exe\"" else RC="rc" lflags="-nologo" LINKBIN="link" CFLAGS_DEBUG="-nologo -Z7 -Od -W3 -WX ${runtime}d" CFLAGS_OPTIMIZE="-nologo -O2 -W2 ${runtime}" fi fi if test "$GCC" = "yes"; then # mingw gcc mode RC="windres" CFLAGS_DEBUG="-g" CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer" SHLIB_LD="$CC -shared" UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' LDFLAGS_CONSOLE="-wl,--subsystem,console ${lflags}" LDFLAGS_WINDOW="-wl,--subsystem,windows ${lflags}" else SHLIB_LD="${LINKBIN} -dll ${lflags}" # link -lib only works when -lib is the first arg STLIB_LD="${LINKBIN} -lib ${lflags}" UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.lib' PATHTYPE=-w # For information on what debugtype is most useful, see: # http://msdn.microsoft.com/library/en-us/dnvc60/html/gendepdebug.asp # and also # http://msdn2.microsoft.com/en-us/library/y0zzbyt4%28VS.80%29.aspx # This essentially turns it all on. LDFLAGS_DEBUG="-debug -debugtype:cv" LDFLAGS_OPTIMIZE="-release" if test "$doWince" != "no" ; then LDFLAGS_CONSOLE="-link ${lflags}" LDFLAGS_WINDOW=${LDFLAGS_CONSOLE} else LDFLAGS_CONSOLE="-link -subsystem:console ${lflags}" LDFLAGS_WINDOW="-link -subsystem:windows ${lflags}" fi fi SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".dll" SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.dll' TCL_LIB_VERSIONS_OK=nodots # Bogus to avoid getting this turned off DL_OBJS="tclLoadNone.obj" ;; AIX-*) if test "${TCL_THREADS}" = "1" -a "$GCC" != "yes"; then : # AIX requires the _r compiler when gcc isn't being used case "${CC}" in *_r) # ok ... ;; *) CC=${CC}_r ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: Using $CC for compiling with threads" >&5 $as_echo "Using $CC for compiling with threads" >&6; } fi LIBS="$LIBS -lc" SHLIB_CFLAGS="" SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" LD_LIBRARY_PATH_VAR="LIBPATH" # Check to enable 64-bit flags for compiler/linker on AIX 4+ if test "$do64bit" = yes -a "`uname -v`" -gt 3; then : if test "$GCC" = yes; then : { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 64bit mode not supported with GCC on $system" >&5 $as_echo "$as_me: WARNING: 64bit mode not supported with GCC on $system" >&2;} else do64bit_ok=yes CFLAGS="$CFLAGS -q64" LDFLAGS_ARCH="-q64" RANLIB="${RANLIB} -X64" AR="${AR} -X64" SHLIB_LD_FLAGS="-b64" fi fi if test "`uname -m`" = ia64; then : # AIX-5 uses ELF style dynamic libraries on IA-64, but not PPC SHLIB_LD="/usr/ccs/bin/ld -G -z text" # AIX-5 has dl* in libc.so DL_LIBS="" if test "$GCC" = yes; then : CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' else CC_SEARCH_FLAGS='-R${LIB_RUNTIME_DIR}' fi LD_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' else if test "$GCC" = yes; then : SHLIB_LD='${CC} -shared' else SHLIB_LD="/bin/ld -bhalt:4 -bM:SRE -bE:lib.exp -H512 -T512 -bnoentry" fi SHLIB_LD="${TCL_SRC_DIR}/unix/ldAix ${SHLIB_LD} ${SHLIB_LD_FLAGS}" DL_LIBS="-ldl" CC_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} TCL_NEEDS_EXP_FILE=1 # TEA specific: use PACKAGE_VERSION instead of VERSION TCL_EXPORT_FILE_SUFFIX='${PACKAGE_VERSION}.exp' fi # AIX v<=4.1 has some different flags than 4.2+ if test "$system" = "AIX-4.1" -o "`uname -v`" -lt 4; then : case " $LIBOBJS " in *" tclLoadAix.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS tclLoadAix.$ac_objext" ;; esac DL_LIBS="-lld" fi # On AIX <=v4 systems, libbsd.a has to be linked in to support # non-blocking file IO. This library has to be linked in after # the MATH_LIBS or it breaks the pow() function. The way to # insure proper sequencing, is to add it to the tail of MATH_LIBS. # This library also supplies gettimeofday. # # AIX does not have a timezone field in struct tm. When the AIX # bsd library is used, the timezone global and the gettimeofday # methods are to be avoided for timezone deduction instead, we # deduce the timezone by comparing the localtime result on a # known GMT value. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gettimeofday in -lbsd" >&5 $as_echo_n "checking for gettimeofday in -lbsd... " >&6; } if test "${ac_cv_lib_bsd_gettimeofday+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lbsd $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char gettimeofday (); int main () { return gettimeofday (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_bsd_gettimeofday=yes else ac_cv_lib_bsd_gettimeofday=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bsd_gettimeofday" >&5 $as_echo "$ac_cv_lib_bsd_gettimeofday" >&6; } if test "x$ac_cv_lib_bsd_gettimeofday" = x""yes; then : libbsd=yes else libbsd=no fi if test $libbsd = yes; then : MATH_LIBS="$MATH_LIBS -lbsd" $as_echo "#define USE_DELTA_FOR_TZ 1" >>confdefs.h fi ;; BeOS*) SHLIB_CFLAGS="-fPIC" SHLIB_LD='${CC} -nostart' SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" #----------------------------------------------------------- # Check for inet_ntoa in -lbind, for BeOS (which also needs # -lsocket, even if the network functions are in -lnet which # is always linked to, for compatibility. #----------------------------------------------------------- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inet_ntoa in -lbind" >&5 $as_echo_n "checking for inet_ntoa in -lbind... " >&6; } if test "${ac_cv_lib_bind_inet_ntoa+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lbind $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char inet_ntoa (); int main () { return inet_ntoa (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_bind_inet_ntoa=yes else ac_cv_lib_bind_inet_ntoa=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bind_inet_ntoa" >&5 $as_echo "$ac_cv_lib_bind_inet_ntoa" >&6; } if test "x$ac_cv_lib_bind_inet_ntoa" = x""yes; then : LIBS="$LIBS -lbind -lsocket" fi ;; BSD/OS-2.1*|BSD/OS-3*) SHLIB_CFLAGS="" SHLIB_LD="shlicc -r" SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; BSD/OS-4.*) SHLIB_CFLAGS="-export-dynamic -fPIC" SHLIB_LD='${CC} -shared' SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" LDFLAGS="$LDFLAGS -export-dynamic" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; dgux*) SHLIB_CFLAGS="-K PIC" SHLIB_LD='${CC} -G' SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; HP-UX-*.11.*) # Use updated header definitions where possible $as_echo "#define _XOPEN_SOURCE_EXTENDED 1" >>confdefs.h # TEA specific: Needed by Tcl, but not most extensions #AC_DEFINE(_XOPEN_SOURCE, 1, [Do we want to use the XOPEN network library?]) #LIBS="$LIBS -lxnet" # Use the XOPEN network library if test "`uname -m`" = ia64; then : SHLIB_SUFFIX=".so" # Use newer C++ library for C++ extensions #if test "$GCC" != "yes" ; then # CPPFLAGS="-AA" #fi else SHLIB_SUFFIX=".sl" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 $as_echo_n "checking for shl_load in -ldld... " >&6; } if test "${ac_cv_lib_dld_shl_load+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char shl_load (); int main () { return shl_load (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dld_shl_load=yes else ac_cv_lib_dld_shl_load=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 $as_echo "$ac_cv_lib_dld_shl_load" >&6; } if test "x$ac_cv_lib_dld_shl_load" = x""yes; then : tcl_ok=yes else tcl_ok=no fi if test "$tcl_ok" = yes; then : SHLIB_CFLAGS="+z" SHLIB_LD="ld -b" SHLIB_LD_LIBS='${LIBS}' DL_OBJS="tclLoadShl.o" DL_LIBS="-ldld" LDFLAGS="$LDFLAGS -Wl,-E" CC_SEARCH_FLAGS='-Wl,+s,+b,${LIB_RUNTIME_DIR}:.' LD_SEARCH_FLAGS='+s +b ${LIB_RUNTIME_DIR}:.' LD_LIBRARY_PATH_VAR="SHLIB_PATH" fi if test "$GCC" = yes; then : SHLIB_LD='${CC} -shared' SHLIB_LD_LIBS='${LIBS}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} fi # Users may want PA-RISC 1.1/2.0 portable code - needs HP cc #CFLAGS="$CFLAGS +DAportable" # Check to enable 64-bit flags for compiler/linker if test "$do64bit" = "yes"; then : if test "$GCC" = yes; then : case `${CC} -dumpmachine` in hppa64*) # 64-bit gcc in use. Fix flags for GNU ld. do64bit_ok=yes SHLIB_LD='${CC} -shared' SHLIB_LD_LIBS='${LIBS}' if test $doRpath = yes; then : CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' fi LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 64bit mode not supported with GCC on $system" >&5 $as_echo "$as_me: WARNING: 64bit mode not supported with GCC on $system" >&2;} ;; esac else do64bit_ok=yes CFLAGS="$CFLAGS +DD64" LDFLAGS_ARCH="+DD64" fi fi ;; HP-UX-*.08.*|HP-UX-*.09.*|HP-UX-*.10.*) SHLIB_SUFFIX=".sl" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 $as_echo_n "checking for shl_load in -ldld... " >&6; } if test "${ac_cv_lib_dld_shl_load+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char shl_load (); int main () { return shl_load (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dld_shl_load=yes else ac_cv_lib_dld_shl_load=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 $as_echo "$ac_cv_lib_dld_shl_load" >&6; } if test "x$ac_cv_lib_dld_shl_load" = x""yes; then : tcl_ok=yes else tcl_ok=no fi if test "$tcl_ok" = yes; then : SHLIB_CFLAGS="+z" SHLIB_LD="ld -b" SHLIB_LD_LIBS="" DL_OBJS="tclLoadShl.o" DL_LIBS="-ldld" LDFLAGS="$LDFLAGS -Wl,-E" CC_SEARCH_FLAGS='-Wl,+s,+b,${LIB_RUNTIME_DIR}:.' LD_SEARCH_FLAGS='+s +b ${LIB_RUNTIME_DIR}:.' LD_LIBRARY_PATH_VAR="SHLIB_PATH" fi ;; IRIX-5.*) SHLIB_CFLAGS="" SHLIB_LD="ld -shared -rdata_shared" SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" if test $doRpath = yes; then : CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}' fi ;; IRIX-6.*) SHLIB_CFLAGS="" SHLIB_LD="ld -n32 -shared -rdata_shared" SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" if test $doRpath = yes; then : CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}' fi if test "$GCC" = yes; then : CFLAGS="$CFLAGS -mabi=n32" LDFLAGS="$LDFLAGS -mabi=n32" else case $system in IRIX-6.3) # Use to build 6.2 compatible binaries on 6.3. CFLAGS="$CFLAGS -n32 -D_OLD_TERMIOS" ;; *) CFLAGS="$CFLAGS -n32" ;; esac LDFLAGS="$LDFLAGS -n32" fi ;; IRIX64-6.*) SHLIB_CFLAGS="" SHLIB_LD="ld -n32 -shared -rdata_shared" SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" if test $doRpath = yes; then : CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}' fi # Check to enable 64-bit flags for compiler/linker if test "$do64bit" = yes; then : if test "$GCC" = yes; then : { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 64bit mode not supported by gcc" >&5 $as_echo "$as_me: WARNING: 64bit mode not supported by gcc" >&2;} else do64bit_ok=yes SHLIB_LD="ld -64 -shared -rdata_shared" CFLAGS="$CFLAGS -64" LDFLAGS_ARCH="-64" fi fi ;; Linux*) SHLIB_CFLAGS="-fPIC" SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" # TEA specific: CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer" # egcs-2.91.66 on Redhat Linux 6.0 generates lots of warnings # when you inline the string and math operations. Turn this off to # get rid of the warnings. #CFLAGS_OPTIMIZE="${CFLAGS_OPTIMIZE} -D__NO_STRING_INLINES -D__NO_MATH_INLINES" # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS SHLIB_LD='${CC} -shared ${CFLAGS} ${LDFLAGS_DEFAULT}' DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" LDFLAGS="$LDFLAGS -Wl,--export-dynamic" if test $doRpath = yes; then : CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' fi LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} if test "`uname -m`" = "alpha"; then : CFLAGS="$CFLAGS -mieee" fi if test $do64bit = yes; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking if compiler accepts -m64 flag" >&5 $as_echo_n "checking if compiler accepts -m64 flag... " >&6; } if test "${tcl_cv_cc_m64+set}" = set; then : $as_echo_n "(cached) " >&6 else hold_cflags=$CFLAGS CFLAGS="$CFLAGS -m64" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : tcl_cv_cc_m64=yes else tcl_cv_cc_m64=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext CFLAGS=$hold_cflags fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_cc_m64" >&5 $as_echo "$tcl_cv_cc_m64" >&6; } if test $tcl_cv_cc_m64 = yes; then : CFLAGS="$CFLAGS -m64" do64bit_ok=yes fi fi # The combo of gcc + glibc has a bug related to inlining of # functions like strtod(). The -fno-builtin flag should address # this problem but it does not work. The -fno-inline flag is kind # of overkill but it works. Disable inlining only when one of the # files in compat/*.c is being linked in. if test x"${USE_COMPAT}" != x; then : CFLAGS="$CFLAGS -fno-inline" fi ;; GNU*) SHLIB_CFLAGS="-fPIC" SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" SHLIB_LD='${CC} -shared' DL_OBJS="" DL_LIBS="-ldl" LDFLAGS="$LDFLAGS -Wl,--export-dynamic" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" if test "`uname -m`" = "alpha"; then : CFLAGS="$CFLAGS -mieee" fi ;; Lynx*) SHLIB_CFLAGS="-fPIC" SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" CFLAGS_OPTIMIZE=-02 SHLIB_LD='${CC} -shared' DL_OBJS="tclLoadDl.o" DL_LIBS="-mshared -ldl" LD_FLAGS="-Wl,--export-dynamic" if test $doRpath = yes; then : CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' fi ;; MP-RAS-02*) SHLIB_CFLAGS="-K PIC" SHLIB_LD='${CC} -G' SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; MP-RAS-*) SHLIB_CFLAGS="-K PIC" SHLIB_LD='${CC} -G' SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" LDFLAGS="$LDFLAGS -Wl,-Bexport" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; NetBSD-1.*|FreeBSD-[1-2].*) SHLIB_CFLAGS="-fPIC" SHLIB_LD="ld -Bshareable -x" SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" if test $doRpath = yes; then : CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}' fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ELF" >&5 $as_echo_n "checking for ELF... " >&6; } if test "${tcl_cv_ld_elf+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __ELF__ yes #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "yes" >/dev/null 2>&1; then : tcl_cv_ld_elf=yes else tcl_cv_ld_elf=no fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_ld_elf" >&5 $as_echo "$tcl_cv_ld_elf" >&6; } if test $tcl_cv_ld_elf = yes; then : SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so' else SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so.1.0' fi # Ancient FreeBSD doesn't handle version numbers with dots. UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' TCL_LIB_VERSIONS_OK=nodots ;; OpenBSD-*) SHLIB_CFLAGS="-fPIC" SHLIB_LD='${CC} -shared ${SHLIB_CFLAGS}' SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" if test $doRpath = yes; then : CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' fi LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so.1.0' { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ELF" >&5 $as_echo_n "checking for ELF... " >&6; } if test "${tcl_cv_ld_elf+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __ELF__ yes #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "yes" >/dev/null 2>&1; then : tcl_cv_ld_elf=yes else tcl_cv_ld_elf=no fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_ld_elf" >&5 $as_echo "$tcl_cv_ld_elf" >&6; } if test $tcl_cv_ld_elf = yes; then : LDFLAGS=-Wl,-export-dynamic else LDFLAGS="" fi # OpenBSD doesn't do version numbers with dots. UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' TCL_LIB_VERSIONS_OK=nodots ;; NetBSD-*|FreeBSD-*) # FreeBSD 3.* and greater have ELF. # NetBSD 2.* has ELF and can use 'cc -shared' to build shared libs SHLIB_CFLAGS="-fPIC" SHLIB_LD='${CC} -shared ${SHLIB_CFLAGS}' SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" LDFLAGS="$LDFLAGS -export-dynamic" if test $doRpath = yes; then : CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' fi LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} if test "${TCL_THREADS}" = "1"; then : # The -pthread needs to go in the CFLAGS, not LIBS LIBS=`echo $LIBS | sed s/-pthread//` CFLAGS="$CFLAGS -pthread" LDFLAGS="$LDFLAGS -pthread" fi case $system in FreeBSD-3.*) # FreeBSD-3 doesn't handle version numbers with dots. UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so' TCL_LIB_VERSIONS_OK=nodots ;; esac ;; Darwin-*) CFLAGS_OPTIMIZE="-Os" SHLIB_CFLAGS="-fno-common" # To avoid discrepancies between what headers configure sees during # preprocessing tests and compiling tests, move any -isysroot and # -mmacosx-version-min flags from CFLAGS to CPPFLAGS: CPPFLAGS="${CPPFLAGS} `echo " ${CFLAGS}" | \ awk 'BEGIN {FS=" +-";ORS=" "}; {for (i=2;i<=NF;i++) \ if ($i~/^(isysroot|mmacosx-version-min)/) print "-"$i}'`" CFLAGS="`echo " ${CFLAGS}" | \ awk 'BEGIN {FS=" +-";ORS=" "}; {for (i=2;i<=NF;i++) \ if (!($i~/^(isysroot|mmacosx-version-min)/)) print "-"$i}'`" if test $do64bit = yes; then : case `arch` in ppc) { $as_echo "$as_me:${as_lineno-$LINENO}: checking if compiler accepts -arch ppc64 flag" >&5 $as_echo_n "checking if compiler accepts -arch ppc64 flag... " >&6; } if test "${tcl_cv_cc_arch_ppc64+set}" = set; then : $as_echo_n "(cached) " >&6 else hold_cflags=$CFLAGS CFLAGS="$CFLAGS -arch ppc64 -mpowerpc64 -mcpu=G5" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : tcl_cv_cc_arch_ppc64=yes else tcl_cv_cc_arch_ppc64=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext CFLAGS=$hold_cflags fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_cc_arch_ppc64" >&5 $as_echo "$tcl_cv_cc_arch_ppc64" >&6; } if test $tcl_cv_cc_arch_ppc64 = yes; then : CFLAGS="$CFLAGS -arch ppc64 -mpowerpc64 -mcpu=G5" do64bit_ok=yes fi;; i386) { $as_echo "$as_me:${as_lineno-$LINENO}: checking if compiler accepts -arch x86_64 flag" >&5 $as_echo_n "checking if compiler accepts -arch x86_64 flag... " >&6; } if test "${tcl_cv_cc_arch_x86_64+set}" = set; then : $as_echo_n "(cached) " >&6 else hold_cflags=$CFLAGS CFLAGS="$CFLAGS -arch x86_64" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : tcl_cv_cc_arch_x86_64=yes else tcl_cv_cc_arch_x86_64=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext CFLAGS=$hold_cflags fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_cc_arch_x86_64" >&5 $as_echo "$tcl_cv_cc_arch_x86_64" >&6; } if test $tcl_cv_cc_arch_x86_64 = yes; then : CFLAGS="$CFLAGS -arch x86_64" do64bit_ok=yes fi;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Don't know how enable 64-bit on architecture \`arch\`" >&5 $as_echo "$as_me: WARNING: Don't know how enable 64-bit on architecture \`arch\`" >&2;};; esac else # Check for combined 32-bit and 64-bit fat build if echo "$CFLAGS " |grep -E -q -- '-arch (ppc64|x86_64) ' \ && echo "$CFLAGS " |grep -E -q -- '-arch (ppc|i386) '; then : fat_32_64=yes fi fi # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS SHLIB_LD='${CC} -dynamiclib ${CFLAGS} ${LDFLAGS_DEFAULT}' { $as_echo "$as_me:${as_lineno-$LINENO}: checking if ld accepts -single_module flag" >&5 $as_echo_n "checking if ld accepts -single_module flag... " >&6; } if test "${tcl_cv_ld_single_module+set}" = set; then : $as_echo_n "(cached) " >&6 else hold_ldflags=$LDFLAGS LDFLAGS="$LDFLAGS -dynamiclib -Wl,-single_module" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { int i; ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : tcl_cv_ld_single_module=yes else tcl_cv_ld_single_module=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS=$hold_ldflags fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_ld_single_module" >&5 $as_echo "$tcl_cv_ld_single_module" >&6; } if test $tcl_cv_ld_single_module = yes; then : SHLIB_LD="${SHLIB_LD} -Wl,-single_module" fi # TEA specific: link shlib with current and compatibility version flags vers=`echo ${PACKAGE_VERSION} | sed -e 's/^\([0-9]\{1,5\}\)\(\(\.[0-9]\{1,3\}\)\{0,2\}\).*$/\1\2/p' -e d` SHLIB_LD="${SHLIB_LD} -current_version ${vers:-0} -compatibility_version ${vers:-0}" SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".dylib" DL_OBJS="tclLoadDyld.o" DL_LIBS="" # Don't use -prebind when building for Mac OS X 10.4 or later only: if test "`echo "${MACOSX_DEPLOYMENT_TARGET}" | awk -F '10\\.' '{print int($2)}'`" -lt 4 -a \ "`echo "${CPPFLAGS}" | awk -F '-mmacosx-version-min=10\\.' '{print int($2)}'`" -lt 4; then : LDFLAGS="$LDFLAGS -prebind" fi LDFLAGS="$LDFLAGS -headerpad_max_install_names" { $as_echo "$as_me:${as_lineno-$LINENO}: checking if ld accepts -search_paths_first flag" >&5 $as_echo_n "checking if ld accepts -search_paths_first flag... " >&6; } if test "${tcl_cv_ld_search_paths_first+set}" = set; then : $as_echo_n "(cached) " >&6 else hold_ldflags=$LDFLAGS LDFLAGS="$LDFLAGS -Wl,-search_paths_first" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { int i; ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : tcl_cv_ld_search_paths_first=yes else tcl_cv_ld_search_paths_first=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS=$hold_ldflags fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_ld_search_paths_first" >&5 $as_echo "$tcl_cv_ld_search_paths_first" >&6; } if test $tcl_cv_ld_search_paths_first = yes; then : LDFLAGS="$LDFLAGS -Wl,-search_paths_first" fi if test "$tcl_cv_cc_visibility_hidden" != yes; then : $as_echo "#define MODULE_SCOPE __private_extern__" >>confdefs.h fi CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" LD_LIBRARY_PATH_VAR="DYLD_LIBRARY_PATH" # TEA specific: for combined 32 & 64 bit fat builds of Tk # extensions, verify that 64-bit build is possible. if test "$fat_32_64" = yes && test -n "${TK_BIN_DIR}"; then : if test "${TEA_WINDOWINGSYSTEM}" = x11; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 64-bit X11" >&5 $as_echo_n "checking for 64-bit X11... " >&6; } if test "${tcl_cv_lib_x11_64+set}" = set; then : $as_echo_n "(cached) " >&6 else for v in CFLAGS CPPFLAGS LDFLAGS; do eval 'hold_'$v'="$'$v'";'$v'="`echo "$'$v' "|sed -e "s/-arch ppc / /g" -e "s/-arch i386 / /g"`"' done CPPFLAGS="$CPPFLAGS -I/usr/X11R6/include" LDFLAGS="$LDFLAGS -L/usr/X11R6/lib -lX11" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { XrmInitialize(); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : tcl_cv_lib_x11_64=yes else tcl_cv_lib_x11_64=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext for v in CFLAGS CPPFLAGS LDFLAGS; do eval $v'="$hold_'$v'"' done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_lib_x11_64" >&5 $as_echo "$tcl_cv_lib_x11_64" >&6; } fi # remove 64-bit arch flags from CFLAGS et al. if configuration # does not support 64-bit. if test "${TEA_WINDOWINGSYSTEM}" = aqua -o "$tcl_cv_lib_x11_64" = no; then : { $as_echo "$as_me:${as_lineno-$LINENO}: Removing 64-bit architectures from compiler & linker flags" >&5 $as_echo "$as_me: Removing 64-bit architectures from compiler & linker flags" >&6;} for v in CFLAGS CPPFLAGS LDFLAGS; do eval $v'="`echo "$'$v' "|sed -e "s/-arch ppc64 / /g" -e "s/-arch x86_64 / /g"`"' done fi fi ;; NEXTSTEP-*) SHLIB_CFLAGS="" SHLIB_LD='${CC} -nostdlib -r' SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadNext.o" DL_LIBS="" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; OS/390-*) CFLAGS_OPTIMIZE="" # Optimizer is buggy $as_echo "#define _OE_SOCKETS 1" >>confdefs.h ;; OSF1-1.0|OSF1-1.1|OSF1-1.2) # OSF/1 1.[012] from OSF, and derivatives, including Paragon OSF/1 SHLIB_CFLAGS="" # Hack: make package name same as library name SHLIB_LD='ld -R -export :' SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadOSF.o" DL_LIBS="" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; OSF1-1.*) # OSF/1 1.3 from OSF using ELF, and derivatives, including AD2 SHLIB_CFLAGS="-fPIC" if test "$SHARED_BUILD" = 1; then : SHLIB_LD="ld -shared" else SHLIB_LD="ld -non_shared" fi SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; OSF1-V*) # Digital OSF/1 SHLIB_CFLAGS="" if test "$SHARED_BUILD" = 1; then : SHLIB_LD='${CC} -shared' else SHLIB_LD='${CC} -non_shared' fi SHLIB_LD_LIBS="${LIBS}" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" if test $doRpath = yes; then : CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}' fi if test "$GCC" = yes; then : CFLAGS="$CFLAGS -mieee" else CFLAGS="$CFLAGS -DHAVE_TZSET -std1 -ieee" fi # see pthread_intro(3) for pthread support on osf1, k.furukawa if test "${TCL_THREADS}" = 1; then : CFLAGS="$CFLAGS -DHAVE_PTHREAD_ATTR_SETSTACKSIZE" CFLAGS="$CFLAGS -DTCL_THREAD_STACK_MIN=PTHREAD_STACK_MIN*64" LIBS=`echo $LIBS | sed s/-lpthreads//` if test "$GCC" = yes; then : LIBS="$LIBS -lpthread -lmach -lexc" else CFLAGS="$CFLAGS -pthread" LDFLAGS="$LDFLAGS -pthread" fi fi ;; QNX-6*) # QNX RTP # This may work for all QNX, but it was only reported for v6. SHLIB_CFLAGS="-fPIC" SHLIB_LD="ld -Bshareable -x" SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" # dlopen is in -lc on QNX DL_LIBS="" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; SCO_SV-3.2*) # Note, dlopen is available only on SCO 3.2.5 and greater. However, # this test works, since "uname -s" was non-standard in 3.2.4 and # below. if test "$GCC" = yes; then : SHLIB_CFLAGS="-fPIC -melf" LDFLAGS="$LDFLAGS -melf -Wl,-Bexport" else SHLIB_CFLAGS="-Kpic -belf" LDFLAGS="$LDFLAGS -belf -Wl,-Bexport" fi SHLIB_LD="ld -G" SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; SINIX*5.4*) SHLIB_CFLAGS="-K PIC" SHLIB_LD='${CC} -G' SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; SunOS-4*) SHLIB_CFLAGS="-PIC" SHLIB_LD="ld" SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" CC_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} # SunOS can't handle version numbers with dots in them in library # specs, like -ltcl7.5, so use -ltcl75 instead. Also, it # requires an extra version number at the end of .so file names. # So, the library has to have a name like libtcl75.so.1.0 SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so.1.0' UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' TCL_LIB_VERSIONS_OK=nodots ;; SunOS-5.[0-6]) # Careful to not let 5.10+ fall into this case # Note: If _REENTRANT isn't defined, then Solaris # won't define thread-safe library routines. $as_echo "#define _REENTRANT 1" >>confdefs.h $as_echo "#define _POSIX_PTHREAD_SEMANTICS 1" >>confdefs.h SHLIB_CFLAGS="-KPIC" # Note: need the LIBS below, otherwise Tk won't find Tcl's # symbols when dynamically loaded into tclsh. SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" if test "$GCC" = yes; then : SHLIB_LD='${CC} -shared' CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} else SHLIB_LD="/usr/ccs/bin/ld -G -z text" CC_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} fi ;; SunOS-5*) # Note: If _REENTRANT isn't defined, then Solaris # won't define thread-safe library routines. $as_echo "#define _REENTRANT 1" >>confdefs.h $as_echo "#define _POSIX_PTHREAD_SEMANTICS 1" >>confdefs.h SHLIB_CFLAGS="-KPIC" # Check to enable 64-bit flags for compiler/linker if test "$do64bit" = yes; then : arch=`isainfo` if test "$arch" = "sparcv9 sparc"; then : if test "$GCC" = yes; then : if test "`${CC} -dumpversion | awk -F. '{print $1}'`" -lt 3; then : { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 64bit mode not supported with GCC < 3.2 on $system" >&5 $as_echo "$as_me: WARNING: 64bit mode not supported with GCC < 3.2 on $system" >&2;} else do64bit_ok=yes CFLAGS="$CFLAGS -m64 -mcpu=v9" LDFLAGS="$LDFLAGS -m64 -mcpu=v9" SHLIB_CFLAGS="-fPIC" fi else do64bit_ok=yes if test "$do64bitVIS" = yes; then : CFLAGS="$CFLAGS -xarch=v9a" LDFLAGS_ARCH="-xarch=v9a" else CFLAGS="$CFLAGS -xarch=v9" LDFLAGS_ARCH="-xarch=v9" fi # Solaris 64 uses this as well #LD_LIBRARY_PATH_VAR="LD_LIBRARY_PATH_64" fi else if test "$arch" = "amd64 i386"; then : if test "$GCC" = yes; then : case $system in SunOS-5.1[1-9]*|SunOS-5.[2-9][0-9]*) do64bit_ok=yes CFLAGS="$CFLAGS -m64" LDFLAGS="$LDFLAGS -m64";; *) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 64bit mode not supported with GCC on $system" >&5 $as_echo "$as_me: WARNING: 64bit mode not supported with GCC on $system" >&2;};; esac else do64bit_ok=yes case $system in SunOS-5.1[1-9]*|SunOS-5.[2-9][0-9]*) CFLAGS="$CFLAGS -m64" LDFLAGS="$LDFLAGS -m64";; *) CFLAGS="$CFLAGS -xarch=amd64" LDFLAGS="$LDFLAGS -xarch=amd64";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 64bit mode not supported for $arch" >&5 $as_echo "$as_me: WARNING: 64bit mode not supported for $arch" >&2;} fi fi fi # Note: need the LIBS below, otherwise Tk won't find Tcl's # symbols when dynamically loaded into tclsh. SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" if test "$GCC" = yes; then : SHLIB_LD='${CC} -shared' CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} if test "$do64bit_ok" = yes; then : if test "$arch" = "sparcv9 sparc"; then : # We need to specify -static-libgcc or we need to # add the path to the sparv9 libgcc. # JH: static-libgcc is necessary for core Tcl, but may # not be necessary for extensions. SHLIB_LD="$SHLIB_LD -m64 -mcpu=v9 -static-libgcc" # for finding sparcv9 libgcc, get the regular libgcc # path, remove so name and append 'sparcv9' #v9gcclibdir="`gcc -print-file-name=libgcc_s.so` | ..." #CC_SEARCH_FLAGS="${CC_SEARCH_FLAGS},-R,$v9gcclibdir" else if test "$arch" = "amd64 i386"; then : # JH: static-libgcc is necessary for core Tcl, but may # not be necessary for extensions. SHLIB_LD="$SHLIB_LD -m64 -static-libgcc" fi fi fi else case $system in SunOS-5.[1-9][0-9]*) SHLIB_LD='${CC} -G -z text ${LDFLAGS}';; *) SHLIB_LD='/usr/ccs/bin/ld -G -z text';; esac CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' fi ;; UNIX_SV* | UnixWare-5*) SHLIB_CFLAGS="-KPIC" SHLIB_LD='${CC} -G' SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" # Some UNIX_SV* systems (unixware 1.1.2 for example) have linkers # that don't grok the -Bexport option. Test that it does. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld accepts -Bexport flag" >&5 $as_echo_n "checking for ld accepts -Bexport flag... " >&6; } if test "${tcl_cv_ld_Bexport+set}" = set; then : $as_echo_n "(cached) " >&6 else hold_ldflags=$LDFLAGS LDFLAGS="$LDFLAGS -Wl,-Bexport" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { int i; ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : tcl_cv_ld_Bexport=yes else tcl_cv_ld_Bexport=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS=$hold_ldflags fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_ld_Bexport" >&5 $as_echo "$tcl_cv_ld_Bexport" >&6; } if test $tcl_cv_ld_Bexport = yes; then : LDFLAGS="$LDFLAGS -Wl,-Bexport" fi CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; esac if test "$do64bit" = yes -a "$do64bit_ok" = no; then : { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 64bit support being disabled -- don't know magic for this platform" >&5 $as_echo "$as_me: WARNING: 64bit support being disabled -- don't know magic for this platform" >&2;} fi # Step 4: disable dynamic loading if requested via a command-line switch. # Check whether --enable-load was given. if test "${enable_load+set}" = set; then : enableval=$enable_load; tcl_ok=$enableval else tcl_ok=yes fi if test "$tcl_ok" = no; then : DL_OBJS="" fi if test "x$DL_OBJS" != x; then : BUILD_DLTEST="\$(DLTEST_TARGETS)" else { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Can't figure out how to do dynamic loading or shared libraries on this system." >&5 $as_echo "$as_me: WARNING: Can't figure out how to do dynamic loading or shared libraries on this system." >&2;} SHLIB_CFLAGS="" SHLIB_LD="" SHLIB_SUFFIX="" DL_OBJS="tclLoadNone.o" DL_LIBS="" LDFLAGS="$LDFLAGS_ORIG" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" BUILD_DLTEST="" fi LDFLAGS="$LDFLAGS $LDFLAGS_ARCH" # If we're running gcc, then change the C flags for compiling shared # libraries to the right flags for gcc, instead of those for the # standard manufacturer compiler. if test "$DL_OBJS" != "tclLoadNone.o" -a "$GCC" = yes; then : case $system in AIX-*) ;; BSD/OS*) ;; IRIX*) ;; NetBSD-*|FreeBSD-*) ;; Darwin-*) ;; SCO_SV-3.2*) ;; *) SHLIB_CFLAGS="-fPIC" ;; esac fi if test "$SHARED_LIB_SUFFIX" = ""; then : # TEA specific: use PACKAGE_VERSION instead of VERSION SHARED_LIB_SUFFIX='${PACKAGE_VERSION}${SHLIB_SUFFIX}' fi if test "$UNSHARED_LIB_SUFFIX" = ""; then : # TEA specific: use PACKAGE_VERSION instead of VERSION UNSHARED_LIB_SUFFIX='${PACKAGE_VERSION}.a' fi # These must be called after we do the basic CFLAGS checks and # verify any possible 64-bit or similar switches are necessary { $as_echo "$as_me:${as_lineno-$LINENO}: checking for required early compiler flags" >&5 $as_echo_n "checking for required early compiler flags... " >&6; } tcl_flags="" if test "${tcl_cv_flag__isoc99_source+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { char *p = (char *)strtoll; char *q = (char *)strtoull; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : tcl_cv_flag__isoc99_source=no else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _ISOC99_SOURCE 1 #include int main () { char *p = (char *)strtoll; char *q = (char *)strtoull; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : tcl_cv_flag__isoc99_source=yes else tcl_cv_flag__isoc99_source=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi if test "x${tcl_cv_flag__isoc99_source}" = "xyes" ; then $as_echo "#define _ISOC99_SOURCE 1" >>confdefs.h tcl_flags="$tcl_flags _ISOC99_SOURCE" fi if test "${tcl_cv_flag__largefile64_source+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { struct stat64 buf; int i = stat64("/", &buf); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : tcl_cv_flag__largefile64_source=no else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _LARGEFILE64_SOURCE 1 #include int main () { struct stat64 buf; int i = stat64("/", &buf); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : tcl_cv_flag__largefile64_source=yes else tcl_cv_flag__largefile64_source=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi if test "x${tcl_cv_flag__largefile64_source}" = "xyes" ; then $as_echo "#define _LARGEFILE64_SOURCE 1" >>confdefs.h tcl_flags="$tcl_flags _LARGEFILE64_SOURCE" fi if test "${tcl_cv_flag__largefile_source64+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { char *p = (char *)open64; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : tcl_cv_flag__largefile_source64=no else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _LARGEFILE_SOURCE64 1 #include int main () { char *p = (char *)open64; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : tcl_cv_flag__largefile_source64=yes else tcl_cv_flag__largefile_source64=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi if test "x${tcl_cv_flag__largefile_source64}" = "xyes" ; then $as_echo "#define _LARGEFILE_SOURCE64 1" >>confdefs.h tcl_flags="$tcl_flags _LARGEFILE_SOURCE64" fi if test "x${tcl_flags}" = "x" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5 $as_echo "none" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${tcl_flags}" >&5 $as_echo "${tcl_flags}" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 64-bit integer type" >&5 $as_echo_n "checking for 64-bit integer type... " >&6; } if test "${tcl_cv_type_64bit+set}" = set; then : $as_echo_n "(cached) " >&6 else tcl_cv_type_64bit=none # See if the compiler knows natively about __int64 cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { __int64 value = (__int64) 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : tcl_type_64bit=__int64 else tcl_type_64bit="long long" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext # See if we should use long anyway Note that we substitute in the # type that is our current guess for a 64-bit type inside this check # program, so it should be modified only carefully... cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { switch (0) { case 1: case (sizeof(${tcl_type_64bit})==sizeof(long)): ; } ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : tcl_cv_type_64bit=${tcl_type_64bit} fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi if test "${tcl_cv_type_64bit}" = none ; then $as_echo "#define TCL_WIDE_INT_IS_LONG 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: result: using long" >&5 $as_echo "using long" >&6; } elif test "${tcl_cv_type_64bit}" = "__int64" \ -a "${TEA_PLATFORM}" = "windows" ; then # TEA specific: We actually want to use the default tcl.h checks in # this case to handle both TCL_WIDE_INT_TYPE and TCL_LL_MODIFIER* { $as_echo "$as_me:${as_lineno-$LINENO}: result: using Tcl header defaults" >&5 $as_echo "using Tcl header defaults" >&6; } else cat >>confdefs.h <<_ACEOF #define TCL_WIDE_INT_TYPE ${tcl_cv_type_64bit} _ACEOF { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${tcl_cv_type_64bit}" >&5 $as_echo "${tcl_cv_type_64bit}" >&6; } # Now check for auxiliary declarations { $as_echo "$as_me:${as_lineno-$LINENO}: checking for struct dirent64" >&5 $as_echo_n "checking for struct dirent64... " >&6; } if test "${tcl_cv_struct_dirent64+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { struct dirent64 p; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : tcl_cv_struct_dirent64=yes else tcl_cv_struct_dirent64=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_struct_dirent64" >&5 $as_echo "$tcl_cv_struct_dirent64" >&6; } if test "x${tcl_cv_struct_dirent64}" = "xyes" ; then $as_echo "#define HAVE_STRUCT_DIRENT64 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for struct stat64" >&5 $as_echo_n "checking for struct stat64... " >&6; } if test "${tcl_cv_struct_stat64+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { struct stat64 p; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : tcl_cv_struct_stat64=yes else tcl_cv_struct_stat64=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_struct_stat64" >&5 $as_echo "$tcl_cv_struct_stat64" >&6; } if test "x${tcl_cv_struct_stat64}" = "xyes" ; then $as_echo "#define HAVE_STRUCT_STAT64 1" >>confdefs.h fi for ac_func in open64 lseek64 do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" eval as_val=\$$as_ac_var if test "x$as_val" = x""yes; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for off64_t" >&5 $as_echo_n "checking for off64_t... " >&6; } if test "${tcl_cv_type_off64_t+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { off64_t offset; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : tcl_cv_type_off64_t=yes else tcl_cv_type_off64_t=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi if test "x${tcl_cv_type_off64_t}" = "xyes" && \ test "x${ac_cv_func_lseek64}" = "xyes" && \ test "x${ac_cv_func_open64}" = "xyes" ; then $as_echo "#define HAVE_TYPE_OFF64_T 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi # should be part of TEA_CONFIG_CFLAGS, but more visible modification here #-------------------------------------------------------------------- # Set the default compiler switches based on the --enable-symbols option. #-------------------------------------------------------------------- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for build with symbols" >&5 $as_echo_n "checking for build with symbols... " >&6; } # Check whether --enable-symbols was given. if test "${enable_symbols+set}" = set; then : enableval=$enable_symbols; tcl_ok=$enableval else tcl_ok=no fi DBGX="" if test "$tcl_ok" = "no"; then CFLAGS_DEFAULT="${CFLAGS_OPTIMIZE}" LDFLAGS_DEFAULT="${LDFLAGS_OPTIMIZE}" { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } else CFLAGS_DEFAULT="${CFLAGS_DEBUG}" LDFLAGS_DEFAULT="${LDFLAGS_DEBUG}" if test "$tcl_ok" = "yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes (standard debugging)" >&5 $as_echo "yes (standard debugging)" >&6; } fi fi # TEA specific: if test "${TEA_PLATFORM}" != "windows" ; then LDFLAGS_DEFAULT="${LDFLAGS}" fi if test "$tcl_ok" = "mem" -o "$tcl_ok" = "all"; then $as_echo "#define TCL_MEM_DEBUG 1" >>confdefs.h fi if test "$tcl_ok" != "yes" -a "$tcl_ok" != "no"; then if test "$tcl_ok" = "all"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: enabled symbols mem debugging" >&5 $as_echo "enabled symbols mem debugging" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: enabled $tcl_ok debugging" >&5 $as_echo "enabled $tcl_ok debugging" >&6; } fi fi #-------------------------------------------------------------------- # Everyone should be linking against the Tcl stub library. If you # can't for some reason, remove this definition. If you aren't using # stubs, you also need to modify the SHLIB_LD_LIBS setting below to # link against the non-stubbed Tcl library. Add Tk too if necessary. #-------------------------------------------------------------------- if test "${USE_STUBS}" = "1" ; then $as_echo "#define USE_TCL_STUBS 1" >>confdefs.h $as_echo "#define USE_TK_STUBS 1" >>confdefs.h fi #-------------------------------------------------------------------- # This macro generates a line to use when building a library. It # depends on values set by the TEA_ENABLE_SHARED, TEA_ENABLE_SYMBOLS, # and TEA_LOAD_TCLCONFIG macros above. #-------------------------------------------------------------------- if test "${TEA_PLATFORM}" = "windows" -a "$GCC" != "yes"; then MAKE_STATIC_LIB="\${STLIB_LD} -out:\$@ \$(PKG_OBJECTS)" MAKE_SHARED_LIB="\${SHLIB_LD} \${SHLIB_LD_LIBS} \${LDFLAGS_DEFAULT} -out:\$@ \$(PKG_OBJECTS)" MAKE_STUB_LIB="\${STLIB_LD} -out:\$@ \$(PKG_STUB_OBJECTS)" else MAKE_STATIC_LIB="\${STLIB_LD} \$@ \$(PKG_OBJECTS)" MAKE_SHARED_LIB="\${SHLIB_LD} -o \$@ \$(PKG_OBJECTS) \${SHLIB_LD_LIBS}" MAKE_STUB_LIB="\${STLIB_LD} \$@ \$(PKG_STUB_OBJECTS)" fi if test "${SHARED_BUILD}" = "1" ; then MAKE_LIB="${MAKE_SHARED_LIB} " else MAKE_LIB="${MAKE_STATIC_LIB} " fi #-------------------------------------------------------------------- # Shared libraries and static libraries have different names. # Use the double eval to make sure any variables in the suffix is # substituted. (@@@ Might not be necessary anymore) #-------------------------------------------------------------------- if test "${TEA_PLATFORM}" = "windows" ; then if test "${SHARED_BUILD}" = "1" ; then # We force the unresolved linking of symbols that are really in # the private libraries of Tcl and Tk. SHLIB_LD_LIBS="${SHLIB_LD_LIBS} \"`${CYGPATH} ${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}`\"" if test x"${TK_BIN_DIR}" != x ; then SHLIB_LD_LIBS="${SHLIB_LD_LIBS} \"`${CYGPATH} ${TK_BIN_DIR}/${TK_STUB_LIB_FILE}`\"" fi eval eval "PKG_LIB_FILE=${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" else eval eval "PKG_LIB_FILE=${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" fi # Some packages build their own stubs libraries eval eval "PKG_STUB_LIB_FILE=${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}" if test "$GCC" = "yes"; then PKG_STUB_LIB_FILE=lib${PKG_STUB_LIB_FILE} fi # These aren't needed on Windows (either MSVC or gcc) RANLIB=: RANLIB_STUB=: else RANLIB_STUB="${RANLIB}" if test "${SHARED_BUILD}" = "1" ; then SHLIB_LD_LIBS="${SHLIB_LD_LIBS} ${TCL_STUB_LIB_SPEC}" if test x"${TK_BIN_DIR}" != x ; then SHLIB_LD_LIBS="${SHLIB_LD_LIBS} ${TK_STUB_LIB_SPEC}" fi eval eval "PKG_LIB_FILE=lib${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" RANLIB=: else eval eval "PKG_LIB_FILE=lib${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" fi # Some packages build their own stubs libraries eval eval "PKG_STUB_LIB_FILE=lib${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}" fi # These are escaped so that only CFLAGS is picked up at configure time. # The other values will be substituted at make time. CFLAGS="${CFLAGS} \${CFLAGS_DEFAULT} \${CFLAGS_WARNING}" if test "${SHARED_BUILD}" = "1" ; then CFLAGS="${CFLAGS} \${SHLIB_CFLAGS}" fi if test "${USE_STUBS}" = "0" ; then SHLIB_LD_LIBS=`echo "$SHLIB_LD_LIBS" | sed -e 's!stub!!g'` fi #-------------------------------------------------------------------- # Determine the name of the tclsh and/or wish executables in the # Tcl and Tk build directories or the location they were installed # into. These paths are used to support running test cases only, # the Makefile should not be making use of these paths to generate # a pkgIndex.tcl file or anything else at extension build time. #-------------------------------------------------------------------- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tclsh" >&5 $as_echo_n "checking for tclsh... " >&6; } if test -f "${TCL_BIN_DIR}/Makefile" ; then # tclConfig.sh is in Tcl build directory if test "${TEA_PLATFORM}" = "windows"; then TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}${EXEEXT}" else TCLSH_PROG="${TCL_BIN_DIR}/tclsh" fi else # tclConfig.sh is in install location if test "${TEA_PLATFORM}" = "windows"; then TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}${EXEEXT}" else TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}.${TCL_MINOR_VERSION}${TCL_DBGX}" fi list="`ls -d ${TCL_BIN_DIR}/../bin 2>/dev/null` \ `ls -d ${TCL_BIN_DIR}/.. 2>/dev/null` \ `ls -d ${TCL_PREFIX}/bin 2>/dev/null`" for i in $list ; do if test -f "$i/${TCLSH_PROG}" ; then REAL_TCL_BIN_DIR="`cd "$i"; pwd`/" break fi done TCLSH_PROG="${REAL_TCL_BIN_DIR}${TCLSH_PROG}" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${TCLSH_PROG}" >&5 $as_echo "${TCLSH_PROG}" >&6; } #TEA_PROG_WISH #-------------------------------------------------------------------- # Finally, substitute all of the various values into the Makefile. # You may alternatively have a special pkgIndex.tcl.in or other files # which require substituting th AC variables in. Include these here. #-------------------------------------------------------------------- ac_config_files="$ac_config_files Makefile pkgIndex.tcl togl_ws.h" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then test "x$cache_file" != "x/dev/null" && { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} cat confcache >$cache_file else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' # Transform confdefs.h into DEFS. # Protect against shell expansion while executing Makefile rules. # Protect against Makefile macro expansion. # # If the first sed substitution is executed (which looks for macros that # take arguments), then branch to the quote section. Otherwise, # look for a macro that doesn't take arguments. ac_script=' :mline /\\$/{ N s,\\\n,, b mline } t clear :clear s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g t quote s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g t quote b any :quote s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g s/\[/\\&/g s/\]/\\&/g s/\$/$$/g H :any ${ g s/^\n// s/\n/ /g p } ' DEFS=`sed -n "$ac_script" confdefs.h` ac_libobjs= ac_ltlibobjs= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs CFLAGS="${CFLAGS} ${CPPFLAGS}"; CPPFLAGS="" : ${CONFIG_STATUS=./config.status} ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error ERROR [LINENO LOG_FD] # --------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with status $?, using 1 if that was 0. as_fn_error () { as_status=$?; test $as_status -eq 0 && as_status=1 if test "$3"; then as_lineno=${as_lineno-"$2"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $1" >&$3 fi $as_echo "$as_me: error: $1" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -p'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -p' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi if test -x / >/dev/null 2>&1; then as_test_x='test -x' else if ls -dL / >/dev/null 2>&1; then as_ls_L_option=L else as_ls_L_option= fi as_test_x=' eval sh -c '\'' if test -d "$1"; then test -d "$1/."; else case $1 in #( -*)set "./$1";; esac; case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( ???[sx]*):;;*)false;;esac;fi '\'' sh ' fi as_executable_p=$as_test_x # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by Togl $as_me 2.1, which was generated by GNU Autoconf 2.65. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE Configuration files: $config_files Report bugs to the package provider." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ Togl config.status 2.1 configured by $0, generated by GNU Autoconf 2.65, with options \\"\$ac_cs_config\\" Copyright (C) 2009 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --he | --h | --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "pkgIndex.tcl") CONFIG_FILES="$CONFIG_FILES pkgIndex.tcl" ;; "togl_ws.h") CONFIG_FILES="$CONFIG_FILES togl_ws.h" ;; *) as_fn_error "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= trap 'exit_status=$? { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error "cannot create a temporary directory in ." "$LINENO" 5 # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '$'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \ || as_fn_error "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove $(srcdir), # ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=/{ s/:*\$(srcdir):*/:/ s/:*\${srcdir}:*/:/ s/:*@srcdir@:*/:/ s/^\([^=]*=[ ]*\):*/\1/ s/:*$// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" eval set X " :F $CONFIG_FILES " shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$tmp/stdin" \ || as_fn_error "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \ || as_fn_error "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined." >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined." >&2;} rm -f "$tmp/stdin" case $ac_file in -) cat "$tmp/out" && rm -f "$tmp/out";; *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";; esac \ || as_fn_error "could not create $ac_file" "$LINENO" 5 ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit $? fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi ================================================ FILE: ng/Togl2.1/configure.in ================================================ #!/bin/bash -norc dnl This file is an input file used by the GNU "autoconf" program to dnl generate the file "configure", which is run during Tcl installation dnl to configure the system for the local environment. # # RCS: @(#) $Id: configure.in,v 1.17 2009/03/03 21:49:56 gregcouch Exp $ #----------------------------------------------------------------------- # Sample configure.in for Tcl Extensions. The only places you should # need to modify this file are marked by the string __CHANGE__ #----------------------------------------------------------------------- #----------------------------------------------------------------------- # __CHANGE__ # Set your package name and version numbers here. # # This initializes the environment with PACKAGE_NAME and PACKAGE_VERSION # set as provided. These will also be added as -D defs in your Makefile # so you can encode the package version directly into the source files. #----------------------------------------------------------------------- AC_INIT([Togl], [2.1]) #-------------------------------------------------------------------- # Call TEA_INIT as the first TEA_ macro to set up initial vars. # This will define a ${TEA_PLATFORM} variable == "unix" or "windows" # as well as PKG_LIB_FILE and PKG_STUB_LIB_FILE. #-------------------------------------------------------------------- TEA_INIT([3.7]) AC_CONFIG_AUX_DIR(tclconfig) #-------------------------------------------------------------------- # Load the tclConfig.sh file #-------------------------------------------------------------------- TEA_PATH_TCLCONFIG TEA_LOAD_TCLCONFIG #-------------------------------------------------------------------- # Load the tkConfig.sh file if necessary (Tk extension) #-------------------------------------------------------------------- TEA_PATH_TKCONFIG TEA_LOAD_TKCONFIG #----------------------------------------------------------------------- # Handle the --prefix=... option by defaulting to what Tcl gave. # Must be called after TEA_LOAD_TCLCONFIG and before TEA_SETUP_COMPILER. #----------------------------------------------------------------------- TEA_PREFIX #----------------------------------------------------------------------- # Standard compiler checks. # This sets up CC by using the CC env var, or looks for gcc otherwise. # This also calls AC_PROG_CC, AC_PROG_INSTALL and a few others to create # the basic setup necessary to compile executables. #----------------------------------------------------------------------- TEA_SETUP_COMPILER #----------------------------------------------------------------------- # __CHANGE__ # Specify the C source files to compile in TEA_ADD_SOURCES, # public headers that need to be installed in TEA_ADD_HEADERS, # stub library C source files to compile in TEA_ADD_STUB_SOURCES, # and runtime Tcl library files in TEA_ADD_TCL_SOURCES. # This defines PKG(_STUB)_SOURCES, PKG(_STUB)_OBJECTS, PKG_HEADERS # and PKG_TCL_SOURCES. #----------------------------------------------------------------------- TOGL_ENABLE_STUBS TEA_ADD_SOURCES([togl.c toglProcAddr.c toglStubInit.c]) # togl_ws.h is added in Makefile.in because it is generated TEA_ADD_HEADERS([togl.h toglDecls.h]) TEA_ADD_INCLUDES([]) TEA_ADD_LIBS([]) TEA_ADD_CFLAGS([]) if test "${USE_STUBS}" = "1" ; then TEA_ADD_STUB_SOURCES([toglStubLib.c]) fi TEA_ADD_TCL_SOURCES([]) #-------------------------------------------------------------------- # __CHANGE__ # A few miscellaneous platform-specific items: # # Define a special symbol for Windows (BUILD_sample in this case) so # that we create the export library with the dll. # # Windows creates a few extra files that need to be cleaned up. # You can add more files to clean if your extension creates any extra # files. # # TEA_ADD_* any platform specific compiler/build info here. #-------------------------------------------------------------------- # Add pkgIndex.tcl if it is generated in the Makefile instead of ./configure # and change Makefile.in to move it from CONFIG_CLEAN_FILES to BINARIES var. #CLEANFILES="pkgIndex.tcl" if test "${TEA_PLATFORM}" = "windows" ; then AC_DEFINE(BUILD_togl, 1, [Build windows export dll]) CLEANFILES="$CLEANFILES *.lib *.dll *.exp *.ilk *.pdb vc*.pch *.manifest" #TEA_ADD_SOURCES([win/winFile.c]) #TEA_ADD_INCLUDES([-I\"$(${CYGPATH} ${srcdir}/win)\"]) else # Ensure no empty else clauses : CLEANFILES="so_locations" #TEA_ADD_SOURCES([unix/unixFile.c]) #TEA_ADD_LIBS([-lsuperfly]) fi AC_SUBST(CLEANFILES) #-------------------------------------------------------------------- # __CHANGE__ # Choose which headers you need. Extension authors should try very # hard to only rely on the Tcl public header files. Internal headers # contain private data structures and are subject to change without # notice. # This MUST be called after TEA_LOAD_TCLCONFIG / TEA_LOAD_TKCONFIG #-------------------------------------------------------------------- # find Tcl, Tk, and X11 headers #TEA_PUBLIC_TCL_HEADERS TEA_PRIVATE_TCL_HEADERS #TEA_PUBLIC_TK_HEADERS TEA_PRIVATE_TK_HEADERS TEA_PATH_X # find autostereo header, lib, and daemon AC_ARG_WITH([autostereo], [AS_HELP_STRING([--with-autostereo], [directory with autostereo source (for SGI)])], [with_autostereo=${withval}]) AC_ARG_WITH([autostereod], [AS_HELP_STRING([--with-autostereod], [path to autostereod daemon (for SGI)])], [with_autostereod=${withval}]) AC_ARG_VAR([AUTOSTEREOD], [Path to autostereod for SGI IRIX computers]) AC_MSG_CHECKING([for autostereo directory]) if test x"${with_autostereo}" != x ; then if test -f "${with_autostereo}/lib/autostereo.h" ; then with_autostereo=`(cd ${with_autostereo}; pwd)` TEA_ADD_INCLUDES([-I${with_autostereo}/lib]) TEA_ADD_LIBS([-L${with_autostereo}/lib -lautostereo]) AC_DEFINE_UNQUOTED(HAVE_AUTOSTEREO, 1, [Define this if you have the autostereo header]) else AC_MSG_ERROR([${with_autostereo} directory doesn't contain lib/autostereo.h]) fi fi AC_PATH_PROG([AUTOSTEREOD], [autostereod], [], [`eval \"echo $sbindir\"`:$PATH:/sbin:/usr/sbin]) # Choose OpenGL platform case "${TEA_WINDOWINGSYSTEM}" in aqua) AC_SUBST(TOGL_WINDOWINGSYSTEM,TOGL_AGL) TEA_ADD_LIBS([-framework AGL -framework OpenGL -framework ApplicationServices]) # libGLU is implicit in OpenGL framework LIBGLU= ;; x11) AC_SUBST(TOGL_WINDOWINGSYSTEM,TOGL_X11) AC_ARG_WITH([Xmu], [AS_HELP_STRING([--with-Xmu], [use system's shared Xmu library])], [], [with_Xmu=no]) AS_IF([test "x$with_Xmu" != xno], [AC_CHECK_LIB([Xmu], [XmuLookupStandardColormap], [TEA_ADD_LIBS([-lXmu]) AC_DEFINE(USE_SYSTEM_LIBXMU, 1, [Define to use system Xmu library]) ], [with_Xmu=no], [-lXt -lX11] )]) AS_IF([test "x$with_Xmu" = xno], [TEA_ADD_SOURCES([Xmu/CmapAlloc.c Xmu/CrCmap.c Xmu/DelCmap.c Xmu/LookupCmap.c Xmu/StdCmap.c])]) TEA_ADD_LIBS([-lGL]) LIBGLU=-lGLU TOGL_UNDEF_GET_PROC_ADDRESS ;; win32) AC_SUBST(TOGL_WINDOWINGSYSTEM,TOGL_WGL) TEA_ADD_LIBS([opengl32.lib user32.lib gdi32.lib]) if test "$GCC" = "yes" ; then LIBGLU=-lglu32 else # assume Microsoft compiler LIBGLU=glu32.lib fi ;; *) AC_MSG_ERROR([Unsupported windowing system: ${TEA_WINDOWINGSYSTEM}]) ;; esac AC_SUBST(LIBGLU) AC_SUBST(TEA_WINDOWINGSYSTEM) #-------------------------------------------------------------------- # Check whether --enable-threads or --disable-threads was given. # This auto-enables if Tcl was compiled threaded. #-------------------------------------------------------------------- TEA_ENABLE_THREADS #-------------------------------------------------------------------- # The statement below defines a collection of symbols related to # building as a shared library instead of a static library. #-------------------------------------------------------------------- TEA_ENABLE_SHARED #-------------------------------------------------------------------- # This macro figures out what flags to use with the compiler/linker # when building shared/static debug/optimized objects. This information # can be taken from the tclConfig.sh file, but this figures it all out. #-------------------------------------------------------------------- TEA_CONFIG_CFLAGS # should be part of TEA_CONFIG_CFLAGS, but more visible modification here AC_SUBST(SHLIB_SUFFIX) #-------------------------------------------------------------------- # Set the default compiler switches based on the --enable-symbols option. #-------------------------------------------------------------------- TEA_ENABLE_SYMBOLS #-------------------------------------------------------------------- # Everyone should be linking against the Tcl stub library. If you # can't for some reason, remove this definition. If you aren't using # stubs, you also need to modify the SHLIB_LD_LIBS setting below to # link against the non-stubbed Tcl library. Add Tk too if necessary. #-------------------------------------------------------------------- if test "${USE_STUBS}" = "1" ; then AC_DEFINE(USE_TCL_STUBS, 1, [Use Tcl stubs]) AC_DEFINE(USE_TK_STUBS, 1, [Use Tk stubs]) fi #-------------------------------------------------------------------- # This macro generates a line to use when building a library. It # depends on values set by the TEA_ENABLE_SHARED, TEA_ENABLE_SYMBOLS, # and TEA_LOAD_TCLCONFIG macros above. #-------------------------------------------------------------------- TEA_MAKE_LIB if test "${USE_STUBS}" = "0" ; then SHLIB_LD_LIBS=`echo "$SHLIB_LD_LIBS" | sed -e 's!stub!!g'` fi #-------------------------------------------------------------------- # Determine the name of the tclsh and/or wish executables in the # Tcl and Tk build directories or the location they were installed # into. These paths are used to support running test cases only, # the Makefile should not be making use of these paths to generate # a pkgIndex.tcl file or anything else at extension build time. #-------------------------------------------------------------------- TEA_PROG_TCLSH #TEA_PROG_WISH #-------------------------------------------------------------------- # Finally, substitute all of the various values into the Makefile. # You may alternatively have a special pkgIndex.tcl.in or other files # which require substituting th AC variables in. Include these here. #-------------------------------------------------------------------- AC_OUTPUT([Makefile pkgIndex.tcl togl_ws.h]) ================================================ FILE: ng/Togl2.1/doc/README.txt ================================================ This directory contains the documentation of Togl, the Tk OpenGL widget. The documentation also doubles as the contents of the Togl home page. ================================================ FILE: ng/Togl2.1/doc/capi.html ================================================ Togl C API

Togl C API

Contents


Compiling and linking C Togl Functions

All Togl functions are found in the Togl header file.

#include "togl.h"

For portability, you should include the togl.h header before any other OpenGL headers so it will compile on Microsoft Windows.

Before calling any Togl functions, you need to initialize it. Regardless if you're using stubs (by defining USE_TOGL_STUBS) or not, the following code will properly initialize togl:

if (Tcl_InitStubs(interp, "8.1", 0) == NULL
|| Togl_InitStubs(interp, "2.0", 0) == NULL) {
    /* fail */
}

If you are using a prebuilt binary distribution, you should be sure to define USE_TOGL_STUBS beforehand.

See the source for the demo programs in the Togl source distribution for working examples.

Linking

If you are using a prebuilt binary, be sure to link against the stub library. On Microsoft Windows, link against Toglstub21.lib opengl32.lib user32.lib gdi32.lib, on Mac OS X, link against -lToglstub2.1 -framework OpenGL, on other platforms, link against -lToglstub2.1 -lGLU -lGL -lm.

If building your own Togl package, you can use the stubs interface or link in the Tcl and Tk libraries as well. If using the stubs interface, link as shown above. Otherwise: on Microsoft Windows, link against Togl21.lib tk84.lib tcl84.lib opengl32.lib user32.lib gdi32.lib, on Mac OS X, link against -lTogl2.1 -framework Tk -framework Tcl -framework OpenGL, on other platforms, link against -lTogl2.1 -ltk8.4 -ltcl8.4 -lGLU -lGL -lm.

Setup and Initialization Functions

int Togl_Init(Tcl_Interp *interp)
Initializes the Togl module. This is typically called from the Tk_Main() function or other Tcl package initialization function that is directly linked to the Togl (shared) library. It is also indirectly called via Tcl's package require Togl command. If successful, the return value is TCL_OK.
const char *Togl_InitStubs(Tcl_Interp *interp, const char *version, int exact)
Loads the Togl package into the given interpreter and initializes it. version should be "2.0" or higher. This is typically called from C/C++ code that accesses Togl's C API and has installed Togl into the standard TCL hierarchy. See the Tcl InitStubs(3) or the Tk TkInitStubs(3) manual pages for more information.

Drawing-related Commands

void Togl_PostRedisplay(Togl *togl)
Signals that the widget should be redrawn. When Tk is next idle, the displaycommand callback will be invoked.
void Togl_SwapBuffers(const Togl *togl)
Swaps the front and back color buffers for a double-buffered widget. glFlush is executed if the window is single-buffered. So this call works for both single- and double-buffered contexts. This is typically called in the displaycommand callback function.
void Togl_MakeCurrent(const Togl *togl)
Sets the current rendering context to the given widget. This is done automatically before any Togl callback functions is called. So the call is only needed if you have multiple widgets with separate OpenGL contexts. If the argument is NULL, then the rendering context is cleared and subsequent OpenGL commands will fail.
Bool Togl_SwapInterval(const Togl *togl, int interval)
Returns True if successful. Attempts to change the maximum refresh rate by setting the minimum number of cycles between successive swap buffers. For benchmarking purposes, you should set the swap interval to 0.
int Togl_CopyContext(const Togl *from, const Togl *to, unsigned int mask)
Copy a subset of the OpenGL context state from from one context to another using the mask parameter who values are the same as glPushAttrib. The return value is TCL_OK if the context was copied.

Query Functions

char *Togl_Ident(const Togl *togl)
Returns a pointer to the identification string associated with a Togl widget or NULL if there's no identifier string.
int Togl_Width(const Togl *togl)
Returns the width of the given Togl widget. Typically called in the reshapecommand callback function.
int Togl_Height(const Togl *togl)
Returns the height of the given Togl widget. Typically called in the reshapecommand callback function.
Tcl_Interp *Togl_Interp(const Togl *togl)
Returns the Tcl interpreter associated with the given Togl widget.
Tk_Window Togl_TkWin(const Togl *togl)
Returns the Tk window associated with the given Togl widget.
Togl_FuncPtr Togl_GetProcAddr(const char *funcname)
Platform-independent way to get OpenGL function pointers from a function name. Note that in Microsoft Windows (WGL) versions that "the extension function addresses are unique for each pixel format. All rendering contexts of a given pixel format share the same extension function addresses." And on *nix (GLX/X11) platforms, "the function pointers returned are context independent" (Linux ABI documentation). The Mac OS X (AGL) platform acts like a *nix platform.
int Togl_ContextTag(const Togl *t)
Returns an integer that represents the context tag. All Togl widgets with the same context tag share display lists.
Bool Togl_UpdatePending(const Togl *t)
Returns True if the window should be redrawn. See Togl_PostRedisplay.
Bool Togl_HasRGBA(const Togl *t)
Return True if Togl widget has a RBGA color buffer. False means that the widget is using a color index buffer.
Bool Togl_IsDoubleBuffered(const Togl *t)
Return True if Togl widget is double buffered.
Bool Togl_HasDepthBuffer(const Togl *t)
Return True if Togl widget is has a depth buffer.
Bool Togl_HasAccumulationBuffer(const Togl *t)
Return True if Togl widget has an accumulation buffer.
Bool Togl_HasDestinationAlpha(const Togl *t)
Return True if Togl widget has a destination alpha buffer.
Bool Togl_HasStencilBuffer(const Togl *t)
Return True if Togl widget has a stencil buffer.
int Togl_StereoMode(const Togl *t)
Return current stereo mode. See ??
Bool Togl_HasMultisample(const Togl *t)
Return True if Togl widget has a multisample buffer.

Color Index Mode Functions

These functions are only used for color index mode.

unsigned long Togl_AllocColor(Togl *togl, float red, float green, float blue)
Allocate a color from a read-only colormap. Given a color specified by red, green, and blue return a colormap index (aka pixel value) whose entry most closely matches the red, green, blue color. Red, green, and blue are values in [0,1]. This function is only used in color index mode when the -privatecmap option is false.
void Togl_FreeColor(Togl *togl, unsigned long index)
Free a color in a read-only colormap. Index is a value which was returned by the Togl_AllocColor() function. This function is only used in color index mode when the -privatecmap option is false.
void Togl_SetColor(Togl *togl, int index, float red, float green, float blue)
Load the colormap entry specified by index with the given red, green and blue values. Red, green, and blue are values in [0,1]. This function is only used in color index mode when the -privatecmap option is true.

Font Functions

These functions provide an interface to the simple bitmap font capabilities that every OpenGL implementation provides. Better font support is found in other C APIs, e.g., QuesoGLC or FTGL.

Tcl_Obj *Togl_LoadBitmapFont(Togl *togl, const char *fontname)
Load the named font as a set of glBitmap display lists. fontname may be any of the font description styles accepted by the Tk font command. For maximum portability, one of the standard Tk fonts, Courier, Times, and Helvetica, should be used. Unicode fonts are treated as if they have only have an 8-bit index (so poorly). If successful, a Togl BitmapFont object is returned. NULL is returned on failure.
int Togl_UnloadBitmapFont(Togl *togl, Tcl_Obj *toglfont)
Destroys the bitmap display lists created by by Togl_LoadBitmapFont(). If successful, the return value is TCL_OK.
int Togl_WriteChars(const Togl *togl, const Tcl_Obj *toglfont, const char *string, int length) Draw the given string. If the given length is zero, then it is computed using strlen. Returns the length of the drawn string.
int Togl_WriteObj(const Togl *togl, const Tcl_Obj *toglfont, Tcl_Obj *obj)
Tcl_Obj interface to Tcl_WriteChars.

Client Data Functions

Each Togl structure has a pointer to an arbitrary client data structure.

void Togl_SetClientData(Togl *togl, ClientData clientData)
Set the Togl widget's client data pointer to clientData.
ClientData Togl_GetClientData(const Togl *togl)
Return the Togl widget's client data pointer.

Overlay Functions

These functions are modeled after GLUT's overlay sub-API.

void Togl_UseLayer(Togl *togl, int layer)
Select the layer into which subsequent OpenGL rendering will be directed. layer may be either TOGL_OVERLAY or TOGL_NORMAL.
void Togl_ShowOverlay(Togl *togl)
Display the overlay planes, if any.
void Togl_HideOverlay(Togl *togl)
Hide the overlay planes, if any.
void Togl_PostOverlayRedisplay(Togl *togl)
Signal that the overlay planes should be redraw. When Tk is next idle, the overlaydisplaycommand callback will be invoked.
int Togl_ExistsOverlay(Togl *togl)
Returns 1 if overlay planes exist, 0 otherwise.
int Togl_GetOverlayTransparentValue(const Togl *togl)
Returns the color index of the overlay's transparent pixel value.
int Togl_IsMappedOverlay(const Togl *togl)
Returns 1 if the overlay planes are currently displayed, 0 otherwise.
unsigned long Togl_AllocColorOverlay(const Togl *togl, float red, float green, float blue)
Allocate a color in the overlay planes. Red, green, and blue are values in [0,1]. Return the color index or -1 if the allocation fails.
void Togl_FreeColorOverlay(const Togl *togl, unsigned long index)
Free a color which was allocated with Togl_AllocColorOverlay().

Stereo Functions

Togl abstracts part of the stereo drawing process to seamlessly support quad-buffered stereo as well as various alternative stereo formats. The stereo viewing parameters, eyeseparation and convergence need to be set with the Togl's stereo options.

void Togl_DrawBuffer(Togl *togl, GLenum mode)
Switch to OpenGL draw buffer. Should be one of GL_BACK_LEFT, GL_BACK_RIGHT, GL_FRONT_LEFT, or GL_FRONT_RIGHT. It is not possible to draw in the left and right buffers at the same time in the alternate stereo modes.
void Togl_Clear(const Togl *togl, GLbitfield mask)
Replacement for OpenGL's glClear that takes into account the alternate stereo mode.
void Togl_Frustum(const Togl *togl, GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat near, GLfloat far)
Replacement for OpenGL's glFrustum that takes into account the alternate stereo mode.
void Togl_Ortho(const Togl *togl, GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat near, GLfloat far)
Replacement for OpenGL's glOrtho that takes into account the alternate stereo mode.
int Togl_NumEyes(const Togl *togl)

Stereo Example

This code works for quad-buffered stereo, as well as the other stereo modes.

if (Togl_NumEyes(togl) == 1) {
    Togl_DrawBuffer(togl, GL_BACK);
    Togl_Clear(togl);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    Togl_Frustum(togl, left, right, bottom, top, near, far);
    glMatrixMode(GL_MODELVIEW);
    draw image
} else {
    Togl_DrawBuffer(togl, GL_BACK_LEFT);
    Togl_Clear(togl);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    Togl_Frustum(togl, left, right, bottom, top, near, far);
    glMatrixMode(GL_MODELVIEW);
    draw left-eye image
    Togl_DrawBuffer(togl, GL_BACK_RIGHT);
    Togl_Clear(togl);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    Togl_Frustum(togl, left, right, bottom, top, near, far);
    glMatrixMode(GL_MODELVIEW);
    draw right-eye image
}
Togl_SwapBuffers(togl);

Image Functions

int Togl_TakePhoto(Togl *togl, Tk_PhotoHandle photo)
Take a photo image of the current Togl window and place it in the given photo object. If the window is partially obscured, either by other windows or by the edges of the display, the results are undefined in the obscured region. If successful, the return value is TCL_OK.

Conversion Functions

These functions aid the programmer when writing Togl callback functions.

int Togl_GetToglFromObj(Tcl_Interp *interp, Tcl_Obj *obj, Togl **toglPtr)
Attempt to return a Togl structure "toglPtr" from the Tcl object "obj". If successful, the return value is TCL_OK.
int Togl_GetToglFromName(Tcl_Interp *interp, const char *cmdName, Togl **toglPtr)
Attempt to return a Togl structure "toglPtr" from the Tcl command name "cmdName". If successful, the return value is TCL_OK.

Get Togl at SourceForge.net. Fast, secure and Free Open Source software downloads Valid HTML 4.01 Transitional ================================================ FILE: ng/Togl2.1/doc/download.html ================================================ Downloading and Installing Togl

Downloading and Installing Togl

Contents


Prerequisites

You should have Tcl and Tk installed on your computer. Togl works with Tcl/Tk version 8.1 and up (all recent testing has been with version 8.4). The Mac OS X version requires version 8.4 (note: versions 8.4.12 and 8.4.13 have a bug when unmapping Togl widgets).

You must also have OpenGL or Mesa (a free alternative to OpenGL with the same API) installed on your computer.

And one should be familiar with Tcl, Tk, OpenGL, and C programming to use Togl effectively.

Downloading Togl

Togl can be downloaded from the SourceForge Files page.

Several prebuilt binary distributions are available as well as a source distribution.

Installing Togl

Installing prebuild binaries

Prebuilt binaries provide a Togl2.1 directory, the togl.h, togl_ws.h and toglDecls.h include files, and the togl stub library (libToglstub2.1.a or Toglstub20.lib, etc). The Togl2.1 directory needs to copied into one of the directories on Tcl's package path (type puts $auto_path in the Tcl interpreter to see the list of directories). If you have C code that needs to access Togl's subroutines directly, place the include file in the same place as Tcl's include file and the stub library in the same place as Tcl's stub library.

Installing from source

Togl uses the Tcl Extension Architecture to be able to build on the same platforms Tcl can be built on. In addition to the Togl source, you will need to have the Tcl and Tk source distributions because not all installations have the needed Tcl and Tk internal header files.

How you link with Togl depends on how you're planning to use it. There are basically three ways of using Togl with your application:

  • Install the Togl shared library and pkgIndex.tcl file (using make install) and link to the Togl stubs library with your executable or shared library. In this case you must call Togl_InitStubs() (and probably Tcl_InitStubs() — Tk_InitStubs is only needed if you call Tk functions). This is the way the included Togl examples are built.
  • Link to the Togl shared library or "compile in" the Togl object files with your executable or shared library. In this case you must call Togl_Init() from your C code to initialize Togl.
  • Install the Togl shared library and pkgIndex.tcl file (using make install) and then load it using Tcl commands or Tcl_PkgRequire(). Then use Tcl commands to create and manipulate the Togl widget.
Since Togl is compiled into a shared library using the Tcl/Tk stubs-interface, the same binary can be used with any version of Tck/Tk from 8.1 and up. See README.stubs for more info.

Specific platform notes follow:

Unix/X11 usage

Unix/X systems only need the public Tcl/Tk include files. Just configure, make, and optionally make install.

Microsoft Windows usage

Microsoft Windows platforms need tkWinInt.h and other internal Tk header files. So you need a Tcl/Tk source distribution in addition to the Togl distribution (or copy over the various include files).

Here's the minimal way to build Togl with Tcl/Tk using the gcc that is distributed as part of the cygwin tools (Microsoft's compilers work too):


VER=8.4.12
SRCDIR=`pwd`

cd $SRCDIR/tcl$VER/win
env 'CC=gcc -mno-cygwin' ./configure --enable-threads
make libtclstub84.a

cd $SRCDIR/tk$VER/win
env 'CC=gcc -mno-cygwin' ./configure --enable-threads
make libtkstub84.a

cd $SRCDIR/Togl2.1
env 'CC=gcc -mno-cygwin' ./configure --with-tcl=../tcl$VER/win --with-tk=../tk$VER/win

make
The resulting Togl21.dll and pkgIndex.tcl should be installed into your Tcl installation just like any other package.

If you change all of the above make's to make install instead, then the Togl package is installed correctly.

Mac OS X usage

These special instructions are for building the Aqua version of Togl. Mac OS X needs tkMacOSXInt.h and other internal Tk header files. Unfortunately, the Tcl and Tk frameworks that Apple distributes are missing the internal headers. So you need a Tcl/Tk source distribution in addition to the Togl distribution (or copy over the various include files). You would probably want a newer version of Tcl and Tk anyway because each minor revision of 8.4 has many Aqua bug fixes.

Here's one way to build Tcl, Tk, and Togl on Mac OS X (assuming they are all in the same directory) to install in your home directory:


VER=8.4.12

mkdir -p ~/bin
make -C tcl$VER/macosx install PREFIX="${HOME}" INSTALL_PATH="${HOME}/Library/Frameworks"
make -C tk$VER/macosx install PREFIX="${HOME}" INSTALL_PATH="${HOME}/Library/Frameworks" APPLICATION_INSTALL_PATH="${HOME}/Applications"

cd Togl2.1
./configure --prefix="${HOME}"
make install

Version History

Version 1.0 — March, 1996

  • Initial version

Version 1.1 (never officially released)

  • Added Togl_LoadBitmapFont function
  • Fixed a few bugs

Version 1.2 — November, 1996

  • added swapbuffers and makecurrent Tcl commands
  • more bug fixes
  • upgraded to support Tcl 7.6 and Tk 4.2
  • added stereo and overlay plane support
  • added Togl_Get/SetClientData() functions
  • added Togl_DestroyFunc()

Version 1.3 — May 2, 1997

  • fixed a bug in Togl_Configure()
  • fixed a compilation problem in using Tcl_PkgProvide() with Tcl < 7.4
  • new overlay functions: Togl_ExistsOverlay, Togl_GetOverlayTransparentValue, Togl_IsMappedOverlay, Togl_AllocColorOverlay, Togl_FreeColorOverlay
  • added X11 functions: Togl_Display, Togl_Screen, Togl_ScreenNumber, Togl_Colormap
  • added Togl_DumpToEpsFile function
  • fixed a C++ compilation problem
  • more robust overlay code
  • added timers (Togl_TimerFunc) from Peter Dern and Elmar Gerwalin

Version 1.4 — September 17, 1997

  • ported to Microsoft Windows NT (Robert Casto)
  • updated for Tcl/Tk 8.0
  • added many config flags (-redsize, -depthsize, etc) (Matthias Ott)
  • added Togl_Set*Func() functions to reassign callback functions (Matthias Ott)
  • added Togl_ResetDefaultCallbacks() and Togl_ClientData() functions (Greg Couch)

Version 1.5 — September 18, 1998

  • fixed a few Unix and Microsoft Windows compilation bugs
  • added Ben Evan's SGI stereo functions
  • multiple expose events now reduced to one redraw
  • destroying Togl widgets caused problems, patched by Adrian J. Chung
  • added Togl_TkWin() function
  • updated for Tcl/Tk 8.0p2
  • added gears demo from Philip Quaife
  • added -sharelist and -sharecontext config flags
  • fixed a few overlay update bugs
  • added -indirect config flag

Version 1.6 — May 7, 2003

  • added Togl_SetTimerFunc function
  • updated for Tcl/Tk 8.0.5 and 8.1
  • context sharing added for Microsoft Windows
  • Macintosh support (by Paul Thiessen)
  • Tcl/Tk stubs support — see README.tcl (by Jonas Beskow)

Version 1.7 — January 6, 2006

  • added Mac OS X support
  • enabled asking for quad-buffered stereo pixel formats on all platforms (use -oldstereo on SGIs for splitscreen stereo — C API changed too)
  • configuring the cursor is no longer slow
  • added -pixelformat config flag
  • added setgrid support (unfortunately many window managers can't cope with 1x1 pixel grid)
  • only free context when last reference is gone
  • switched to TEA-based configure (instead of editing make files)

Version 2.0 — April 22, 2008

  • stubified C API
  • replaced EPS support with TK photo image support
  • simplified C API by requiring callback command options
  • Added command arguments for create, destroy, etc. callbacks, so there is a -createcommand option to the togl command (etc.). (and removed Togl_*Func from the C API)
  • added togl instance commands that call C API — see documentation
  • use Tcl objects internally
  • use Tcl object interface for callbacks
  • vertical sync control
  • fix thread safety in anticipation that OpenGL drivers may someday be thread safe
  • added simple stereo rendering interface
  • revised font C API
  • updated font support for Tk 8.4 on all platforms
  • updated documentation
  • prebuilt binaries

Version 2.1 — December 2009

  • incorporate the part of the X11R6 Xmu library that Togl uses so it will work on (Linux) systems that don't have the Xmu shared library
  • Mac OS X Aqua delete context bug fix
  • multisampling support
  • pbuffer support (Unix/X11, Microsoft Windows, Mac OS X)
  • Ability to copy context state
  • row interleaved stereo support

Future plans

Patches for the following are especially welcome:
  • Tk 8.5 fonts
  • Aqua Cocoa support (Tk 8.6b2)
  • OpenGL 3 contexts
  • EGL support
  • RGB overlays
  • Tcl access to colormap manipulation
  • NVidia consumer stereo support

Get Togl at SourceForge.net. Fast, secure and Free Open Source software downloads Valid HTML 4.01 Transitional ================================================ FILE: ng/Togl2.1/doc/faq.html ================================================ Togl Frequently Asked Questions

Togl Frequently Asked Questions

Contents

Frequently Asked Questions (and Problems)


If you have something to add to this section please let us know.

Bad Match X errors on Sun systems
There is(was?) a bug in Sun's XmuLookupStandardColormap X library function. If you compile togl.c with the SOLARIS_BUG symbol defined (-DSOLARIS_BUG) this function call will be omitted.

Is stereo rendering supported?
Several different stereo modes are supported.

Is fullscreen stereo rendering supported?
Before Tk 8.5, Tk does not support true fullscreen windows. Consequenly the full-screen stereo, that gaming graphics cards support (ATI Radeon, NVidia GeForce), won't be added until sometime after Tk 8.5 is available. Fullscreen stereo on workstation graphics cards (ATI FireGL, NVidia Quadro, Matrix Parhelia, 3Dlabs Wildcat) does work.

How do I get the Microsoft Windows device context?
First call Togl_MakeCurrent to make sure you have the right OpenGL context and device context set, then call wglGetCurrentDC.

How do I use Togl from Python?
The Togl source distribution comes with a Togl.py file that provides a Tkinter-style Togl widget. And for Togl callbacks that are C functions, there is a toglpy.h file that provides a function that converts a Python object into its corresponding Togl widget:
Togl *getToglFromWidget(PyObject *widget)

Is Togl compatible with Tile and Tk 8.5?
Yes, Togl works as is (except for the bitmap font support for X11 and Aqua). From Joe English:
Complex "owner-draw" widgets like tkZinc, or the text and canvas widgets, really don't benefit much from themability, so there's no reason to rewrite them. (http://wiki.tcl.tk/13373)

Get Togl at SourceForge.net. Fast, secure and Free Open Source software downloads Valid HTML 4.01 Transitional ================================================ FILE: ng/Togl2.1/doc/header.js ================================================ function displayHeader(pageTitle) { document.write("

" + pageTitle + "

"); } function NavigationBar() { document.write(""); document.write(" "); document.write(" "); document.write(" "); document.write(" "); document.write(" "); document.write(" "); document.write(" "); document.write(" "); document.write(" "); document.write("
IndexIntroDownload/InstallUsing ToglTcl APIC APIFAQ
"); document.write("
"); } ================================================ FILE: ng/Togl2.1/doc/index.html ================================================ Togl, a Tk OpenGL widget

Togl — a Tk OpenGL widget

Copyright © 1996-2009 Brian Paul, Ben Bederson, and Greg Couch

Index


Introduction

Togl is a Tk widget for OpenGL rendering. Togl was originally based on OGLTK, written by Benjamin Bederson at the University of New Mexico. Togl's main features are:
  • unifies Microsoft Windows, X11 (Linux/IRIX/...), and Mac OS X Aqua support
  • support for requesting stencil, accumulation, alpha buffers, etc.
  • multiple OpenGL drawing windows
  • simple stereo rendering support
  • simple, portable font support
  • color-index mode support including color allocation functions
  • overlay plane support
  • OpenGL extension testing from Tcl
  • Tcl Extension Architecture (TEA) 3 compliant

Togl does almost no OpenGL drawing itself, instead it manages OpenGL drawing by calling various Tcl commands (a.k.a., callback functions). Those commands can be C functions that call OpenGL (in)directly or another Tcl package (e.g., Tcl3D).

Togl is copyrighted by Brian Paul (brian_e_paulATyahooDOTcom), Benjamin Bederson (bedersonATcsDOTumdDOTedu), and Greg Couch (gregcouchATusersDOTsourceforgeDOTnet). See the LICENSE file for details.

The Togl project and home page are hosted by SourceForge.

Mailing list

See the Togl project at SourceForge for mailing list information.

Reporting Bugs

There is a bug database on the Togl Project Page. You may also discuss bugs on the mailing list.

It may be worth upgrading your graphics driver and retesting before reporting a bug, as, historically, many Togl "bugs" have been fixed by a graphics driver upgrade, especially on Microsoft Windows.

When reporting bugs please provide as much information as possible. Such as the version of Togl, which operating system (e,g., Microsoft Windows, Red Hat Linux, Mac OS X, etc.), the version of the operating system, and the version of the graphics driver. Also, it's very helpful to us if you can provide an example program which demonstrates the problem.

Contributors

Several people have contributed new features to Togl. Among them are:

  • Ramon Ramsan — overlay plane support
  • Miguel A. De Riera Pasenau — more overlay functions, X11 functions and EPS output
  • Peter Dern and Elmar Gerwalin — Togl_TimerFunc and related code
  • Robert Casto — Microsoft Windows NT port
  • Geza Groma — Microsoft Windows 95/NT patches
  • Ben Evans — SGI stereo support
  • Paul Thiessen — Macintosh support
  • Jonas Beskow — Tcl/Tk stubs support
  • Paul Kienzle — TEA debugging and patches
  • Greg Couch — version 1.7, 2.0, 2.1
Many others have contributed bug fixes. Thanks for your contributions!

Last edited on 4 February 2009 by Greg Couch.
Get Togl at SourceForge.net. Fast, secure and Free Open Source software downloads Valid HTML 4.01 Transitional ================================================ FILE: ng/Togl2.1/doc/stereo.html ================================================ Togl Stereo Modes

Togl Stereo Modes

Contents


There are lots of stereo modes in Togl because there are many ways to draw stereo with different tradeoffs. All of the stereo modes are chosen with the -stereo configuration option. All of the non-native stereo techniques are software-only and can be changed at anytime.

When using a non-native stereo mode, the OpenGL glDrawBuffer, glClear, glFrustum, and glOrtho calls should be replaced with the Togl Tcl or C versions for seamless stereo rendering.

The various stereo modes are:

none or "" or any false boolean value
Turn off stereo.
native or any true boolean value
Use native OpenGL hardware accelerated stereo (single- or double-buffered for both the left and the right eyes). Each eye is drawn at full window resolution which gives the best stereo image. This mode requires support from the graphics driver and is typically only supported on workstation-class graphics cards, e.g., NVidia Quadro, ATI FireGL, Matrix Parhelia, 3DLabs Wildcat graphics cards and SGI workstations. The video refresh rate is changed automatically by the windowing system except on SGI workstations. Developers for SGI workstations can either switch the video manually with /usr/gfx/setmon or /usr/bin/X11/xsetmon, or use the autostereo package.

Currently, there is a limitation that a togl widget can not be reconfigured in or out of the native stereo mode. And if/when it is supported, some graphics drivers might not allow it.

anaglyph
Draw the left eye in the red part of the color buffer and the right eye in the blue and green parts. Designed to be viewed with inexpensive red-blue or red-cyan glasses. Works best with gray scale and non-saturated color images.
cross-eye
Draw right eye image on the left half of screen, and draw left eye image on the right half of screen. So each eye is drawn at less than half of the window resolution.
wall-eye
Draw left eye image on the left half of the screen, and draw right eye image on the right half of the screen. So each eye is drawn at less than half of the window resolution.
dti
Designed for DTI displays. If you look at the window unassisted, you'll see horizonally squished images with the left eye image on the left, and right eye image on the right. So each eye is drawn at half of the window resolution.
row interleaved
Designed for VRex, Zalman, and Hyundai displays. Where the right eye is on the even scanlines and the left is on the odd ones. Requires that there be a stencil buffer and uses the most significant stencil bit. Changes to the stencil state should be placed within glPushAttrib(GL_STENCIL_BUFFER_BIT) and glPopAttrib() calls.
left eye
Only draw left eye view at full resolution.
right eye
Only draw right eye view at full resolution.
sgioldstyle
Support older-style SGI stereo where you lose half of the vertical resolution. This uses the SGIStereo X extension, that is only available on SGI workstations, to tell the X server to duplicate non-stereo windows into both eyes. This option only works when the monitor has been changed to the one of the str_top, str_bot, or str_rect video output modes.

Get Togl at SourceForge.net. Fast, secure and Free Open Source software downloads Valid HTML 4.01 Transitional ================================================ FILE: ng/Togl2.1/doc/tclapi.html ================================================ Togl Tcl API

Togl Tcl API

Contents


Togl Tcl command

The togl command creates a new Tk widget, a Tcl command, whose name is pathName. This command may be used to invoke various operations on the widget.

togl pathName [options]
If no options are given, a 400 by 400 pixel RGB window is created. This command may be used to invoke various operations on the widget.

Togl widget commands

The following commands are possible for an existing togl widget:

Configuration commands

pathName cget -option
Return current value of given configuration option.
pathName configure
pathName configure -option
If no option is given, then return information about all configuration options. Otherwise, return configuration information for given option. All configuration information consists of five values: the configuration option name, the option database name, the option database class, the default value, and the current value.
pathName configure -option value
Reconfigure a Togl widget. option may be any one of the options listed below.
pathName contexttag
Returns an integer that represents the context tag. All Togl widgets with the same context tag share display lists.

Extensions command

pathName extensions
Returns a list of OpenGL extensions available. For example:

if {[lsearch [pathName extensions] GL_EXT_bgra] != -1]} {
    ....
}
would check if the GL_EXT_bgra extension were supported.

Rendering commands

pathName postredisplay
Cause the displaycommand callback to be called the next time the event loop is idle.
pathName render
Causes the displaycommand callback to be called for pathName.
pathName swapbuffers
Causes front/back buffers to be swapped if in double buffer mode. And flushes the OpenGL command buffer if in single buffer mode. (So this is appropriate to call after every frame is drawn.)
pathName makecurrent
Make the widget specified by pathName and its OpenGL context the current ones. This is implicitly called before any callback command is invoked.
pathName copycontextto toPathName mask
Copy a subset of the OpenGL context state from pathName to toPathName according the given mask. The mask is an integer corresponding to the same values as glPushAttrib.

Image commands

pathName takephoto imagename
Copy the contents of the togl window into the given Tk photo image. Transparency values are copied and should be fully opaque for windows without alpha bitplanes.

Font commands

These functions provide an interface to the simple bitmap font capabilities that every OpenGL implementation provides. Better font support is found in other packages, e.g., Tcl3D or with different C APIs.

pathName loadbitmapfont font
font can be any of font descriptions listed in the Tk font command. It returns a togl font object.
pathName unloadbitmapfont toglfont
Releases the OpenGL resources needed by the toglfont.
pathName write toglfont [-pos xyzw] [-color rgba] string
Write the given string in the given toglfont, optionally at a particular position, xyzw and color, rgba. xyzw is either a 2, 3, or 4 element list of numbers. rgba is either a 3 or 4 element list of numbers.

Overlay Commands

pathName uselayer layer
This is a variation on the makecurrent command that makes the overlay OpenGL context current if layer is 2 and makes the normal OpenGL context current if layer is 1.
pathName showoverlay
Turn on drawing in the overlay planes.
pathName hideoverlay
Turn off drawing in the overlay planes.
pathName postredisplayoverlay
Cause the overlay OpenGL context to be redrawn the next time the Tcl event loop is idle.
pathName renderoverlay
Causes the overlaydisplaycommand callback to be called for pathName.
pathName existsoverlay
Return true if togl widget has overlay planes.
pathName ismappedoverlay
Return true if overlay planes are shown.
pathName getoverlaytransparentvalue
Return overlay plane's transparent pixel value.

OpenGL (Stereo) Commands

These commands exist to support stereo rendering. Just replace select OpenGL calls with the Togl versions and stereo rendering will magically work. And don't forget to update the stereo options.
pathName drawbuffer mode
Replaces calls to glDrawBuffer. The mode is an integer.
pathName clear mask
Replaces calls to glClear. The mask is an integer.
pathName frustum left right bottom top near far
Replaces calls to glFrustum.
pathName ortho left right bottom top near far
Replaces calls to glOrtho.
pathName numeyes
Returns numbers of eyes — basically, 2 for stereo views and 1 for all others, except some stereo views only need one eye from OpenGL.

Togl configuration options

Togl's configuration options can be separated into several categories: geometry, pixel format, and other. The pixel format related options can only be set at widget creation time. The other options can be changed dynamically by the pathName configure command (see above).

Drawing callbacks

Option Default Comments
-createcommand {} Can be abbreviated -create.
-displaycommand {} Can be abbreviated -display.
-reshapecommand {} Can be abbreviated -reshape.
-destroycommand {} Can be abbreviated -destroy.
-overlaydisplaycommand {} Can be abbreviated -overlaydisplay.

Geometry Options

Option Default Comments
-width 400 Set width of widget in pixels. It may have any of the forms accepted by Tk_GetPixels.
-height 400 Set height of widget in pixels. It may have any of the forms accepted by Tk_GetPixels(3).
-setgrid 0 Turn on gridded geometry management for togl widget's toplevel window and specify the geometry of the grid. See the manual pages for Tk's wm(n) and Tk_SetGrid(3) for more information. Unlike the text widget, the same value is used for both width and height increments.

Timer Options

Option Default Comments
-time 1 Specifies the interval, in milliseconds, for calling the timer callback function which was registered with -timercommand.
-timercommand {} Can be abbreviated -timer.

Stereo Options

Option Default Comments
-eyeseparation 2.0 Set the distance between the eyes in viewing coordinates.
-convergence 30.0 Set the distance to the screen from the eye in viewing coordinates (the distance at which the eyes converge).
You'd think these values would be given in physical units, but there's no single right way to convert to viewing coordinates from physical units. So if you're willing to use Tk's idea of the horizontal size of a window in millimeters (not always correct), you could convert the average eye separation of 63 mm to your viewing coordinates, and use that value as the eye separation.

Miscellaneous Options

Option Default Comments
-cursor "" Set the cursor in the widget window.
-swapinterval 1 Set the minimum swap interval measure in video frame periods. The default is 1 for for non-tearing artifacts when swapping buffers. Use a value of 0 when benchmarking frame rates.
-ident "" A user identification string. This is used match widgets for the -sharecontext and the -sharelist options (see below). This is also useful in your callback functions to determine which Togl widget is the caller.

Pixel Format Options

The following options can only be given when the togl widget is created — that is, unlike other options, the togl widget can not be reconfigured with different values for the following options after it is created.
Option Default Comments
-rgba true If true, use RGB(A) mode, otherwise use Color Index mode.
-redsize 1 Minimum number of bits in red component.
-greensize 1 Minimum number of bits in green component.
-bluesize 1 Minimum number of bits in blue component.
-alpha 1 If true and -rgba is true, request an alpha channel.
-alphasize 1 Minimum number of bits in alpha component.
 
-double false If true, request a double-buffered window, otherwise request a single-buffered window.
 
-depth false If true, request a depth buffer.
-depthsize 1 Minimum number of bits in depth buffer.
 
-accum false If true, request an accumulation buffer.
-accumredsize 1 Minimum number of bits in accumulation buffer red component.
-accumgreensize 1 Minimum number of bits in accumulation buffer green component.
-accumbluesize 1 Minimum number of bits in accumulation buffer blue component.
-accumalphasize 1 Minimum number of bits in accumulation buffer alpha component.
 
-stencil false If true, request a stencil buffer.
-stencilsize 1 Minimum number of bits in stencil component.
 
-auxbuffers 0 Desired number of auxiliary buffers.
 
-privatecmap false Only applicable in color index mode. If false, use a shared read-only colormap. If true, use a private read/write colormap.
 
-overlay false If true, request overlay planes.
 
-stereo mode See the stereo information for details about the various modes. Stereo parameters are changed with the stereo options.

When using a non-native stereo mode, the OpenGL glDrawBuffer, glClear, glFrustum, and glOrtho calls must be replaced with the Togl Tcl or C versions.

 
-pbuffer false If true, request off-screen framebuffer memory for the graphics. The resulting togl widget should not be managed.
-largestpbuffer false If true, when asking for a pbuffer of a given size and there isn't enough framebuffer memory available, fallback to the largest size available.
 
-multisample false If true, request an multisampled rendering context.
-indirect false If present, request an indirect rendering context. A direct rendering context is normally requested. Only significant on Unix/X11.
-sharelist "" Togl identification string or window path name of an existing Togl widget with which to share display lists. If it is not possible to share display lists between the two togl widgets (depends on the graphics driver and the particular formats), it fails.
-sharecontext "" Togl identification string or window path name of an existing Togl widget with which to share the OpenGL context. Note: all other pixel format options are ignored.
-pixelformat 0 Set the pixel format to the (platform-dependent) given value. This is a backdoor into choosing a particular pixel format that was determined by other means.

Get Togl at SourceForge.net. Fast, secure and Free Open Source software downloads Valid HTML 4.01 Transitional ================================================ FILE: ng/Togl2.1/doc/upgrading.html ================================================ Upgrading to Version 2

Upgrading to Version 2

Contents


Internally, Togl version 2 isn't very different from version 1, and much of the C interface is the same. The main difference is that the focus of the Togl API has changed from being a C API to being a Tcl API. Which means that the full power of Togl is accessible from Tcl (the few exceptions are considered bugs).

Widget callback changes

The biggest change is how the various callback are initialized. In version 1, the C API Togl_Set*Func functions had to be used to setup the callback functions before creating the Togl widget. And once the callbacks were set for a particular Togl widget, they could not be changed. If more than once Togl widget was needed, the callback functions would need to be reset before each widget creation. In version 2, the callbacks are configuration arguments to the widget and can be updated like any other standard widget configuration option. See the Tcl API for details.

Widget subcommand changes

Version 1 also allowed new subcommands to be added to the togl widget command via the C API. This was dropped for a variety of reasons: there is no exact Tcl equivalent, there is no standard object-oriented technique currently in the Tcl core (8.4.13), it is unclear how to make the API thread safe, and the internal Tcl C API doesn't support dynamically changing sets of subcommands. That said, this functionality might come back, especially when TIP #257 is implemented. Instead, in version 2, create a Tcl function that takes the Togl widget as an argument. Functions written in C can get the underlying Togl structure handle with either the Togl_GetToglFromObj or the Togl_GetToglFromName function, as appropriate. This means that there are no special Togl commands, only Tcl commands. See the C API for details.

Stereo changes

The stereo support has been totally revamped. Some form of stereo is available all of the time.

Font changes

Tcl support for writing strings has been added.

The font C API has been revised so that Togl_LoadBitmapFont returns a font object instead an integer (likewise for Togl_UnloadBitmapFont). So instead of calling glListBase and glCallLists directly, use Togl_WriteObj or Togl_WriteChars.

The TOGL_BITMAP_* constants remain for limited backwards source compatibility and are deprecated. The acceptable font names are now the same as Tk_GetFont and the Tk font command on all platforms.


Get Togl at SourceForge.net. Fast, secure and Free Open Source software downloads Valid HTML 4.01 Transitional ================================================ FILE: ng/Togl2.1/doc/using.html ================================================ Using the Togl Widget

Using the Togl Widget

Contents


Using Togl With Your Application

First, double check that you have all of the prerequisites and that you have compiled and installed Togl.

Then, Togl acts like any other extension package — to load it, you use the Tcl package command:

package require Togl 2.0
After that, you can create a Togl widget just like any other Tk widget.

Examples

There are eight working examples:

double.tcl — compares single vs double buffering with two Togl widgets
texture.tcl — lets you play with texture mapping options
index.tcl — example of using color index mode
overlay.tcl — example of using overlay planes (requires overlay hardware)
stereo.tcl — stereo example
gears.tcl — spinning gears example
multisample.tcl — multisampling example
pbuffer.tcl — pbuffer (off-screen rendering) example

Each example consists of two files: a Tcl script for the user interface, and a Tcl C package that does the OpenGL drawing. To compile the examples, type make examples in the Togl source directory. The C packages are compiled into shared libraries that are loaded into the Tcl interpreter as Tcl/Tk-extensions. The examples are started by running the corresponding Tcl script: just type ./double.tcl (or ./texture.tcl etc.) or run under one of the Tcl interpreters, i.e., tclsh or wish. For example:

tclsh84 double.tcl

Other examples that use Tcl for OpenGL drawing can be found in the Tcl3D demos.

Togl callbacks

All of the examples have similar structure. First they create the user interface with one or more Togl widgets. Each Togl widget is configured with the desired pixel format and several callback commands (not all are needed):
-createcommand Called when Togl widget is mapped — when it is safe to initialize the OpenGL context.
-reshapecommand Called when the Togl widget is resized — when the OpenGL context's viewport needs to be changed.
-displaycommand Called when the contents of the Togl widget needs to be redrawn. Redraws are normally delayed to be when the Tcl event loop is idle (see the togl widget's postredisplay command), or as the result of an explicit call to the togl's widgets render command.
-destroycommand Called when the Togl widget is destroyed. While OpenGL frees display lists and other resources, sometimes there's some associated state that is no longer needed.
-timercommand Called every n milliseconds as given by the -time option.
-overlaydisplaycommand Called when the overlay planes needs to be redrawn. The overlay planes are created and reshaped at the same time as the main OpenGL context.
Typically, only -createcommand, -reshapecommand and -displaycommand are used.


Get Togl at SourceForge.net. Fast, secure and Free Open Source software downloads Valid HTML 4.01 Transitional ================================================ FILE: ng/Togl2.1/double.c ================================================ /* $Id: double.c,v 1.22 2009/03/12 23:59:35 gregcouch Exp $ */ /* * Togl - a Tk OpenGL widget * Copyright (C) 1996-1997 Brian Paul and Ben Bederson * Copyright (C) 2006-2007 Greg Couch * See the LICENSE file for copyright details. */ #define USE_TOGL_STUBS #include "togl.h" #include #include #include #undef TCL_STORAGE_CLASS #define TCL_STORAGE_CLASS DLLEXPORT static Tcl_Obj *toglFont; static double xAngle = 0, yAngle = 0, zAngle = 0; static GLdouble CornerX, CornerY, CornerZ; /* where to print strings */ /* * Togl widget create callback. This is called by Tcl/Tk when the widget has * been realized. Here's where one may do some one-time context setup or * initializations. */ static int create_cb(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { Togl *togl; if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "pathName"); return TCL_ERROR; } if (Togl_GetToglFromObj(interp, objv[1], &togl) != TCL_OK) { return TCL_ERROR; } if (!toglFont) toglFont = Togl_LoadBitmapFont(togl, "Helvetica"); if (!toglFont) { static int shown; if (!shown) { fprintf(stderr, "Couldn't load font!\n"); shown = 1; } } return TCL_OK; } /* * Togl widget reshape callback. This is called by Tcl/Tk when the widget * has been resized. Typically, we call glViewport and perhaps setup the * projection matrix. */ static int reshape_cb(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { int width; int height; double aspect; Togl *togl; if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "pathName"); return TCL_ERROR; } if (Togl_GetToglFromObj(interp, objv[1], &togl) != TCL_OK) { return TCL_ERROR; } width = Togl_Width(togl); height = Togl_Height(togl); aspect = (double) width / (double) height; glViewport(0, 0, width, height); /* Set up projection transform */ glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustum(-aspect, aspect, -1, 1, 1, 10); CornerX = -aspect; CornerY = -1; CornerZ = -1.1; /* Change back to model view transform for rendering */ glMatrixMode(GL_MODELVIEW); return TCL_OK; } static void print_string(Togl *togl, const char *s) { if (toglFont) Togl_WriteChars(togl, toglFont, s, 0); } /* * Togl widget display callback. This is called by Tcl/Tk when the widget's * contents have to be redrawn. Typically, we clear the color and depth * buffers, render our objects, then swap the front/back color buffers. */ static int display_cb(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { static GLuint cubeList = 0; const char *ident; Togl *togl; if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "pathName"); return TCL_ERROR; } if (Togl_GetToglFromObj(interp, objv[1], &togl) != TCL_OK) return TCL_ERROR; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); /* Reset modelview matrix to the identity * matrix */ glTranslatef(0, 0, -3); /* Move the camera back three units */ glRotated(xAngle, 1, 0, 0); /* Rotate by X, Y, and Z angles */ glRotated(yAngle, 0, 1, 0); glRotated(zAngle, 0, 0, 1); glEnable(GL_DEPTH_TEST); if (!cubeList) { cubeList = glGenLists(1); glNewList(cubeList, GL_COMPILE); /* Front face */ glBegin(GL_QUADS); glColor3f(0, 0.7f, 0.1f); /* Green */ glVertex3f(-1, 1, 1); glVertex3f(1, 1, 1); glVertex3f(1, -1, 1); glVertex3f(-1, -1, 1); /* Back face */ glColor3f(0.9f, 1, 0); /* Yellow */ glVertex3f(-1, 1, -1); glVertex3f(1, 1, -1); glVertex3f(1, -1, -1); glVertex3f(-1, -1, -1); /* Top side face */ glColor3f(0.2f, 0.2f, 1); /* Blue */ glVertex3f(-1, 1, 1); glVertex3f(1, 1, 1); glVertex3f(1, 1, -1); glVertex3f(-1, 1, -1); /* Bottom side face */ glColor3f(0.7f, 0, 0.1f); /* Red */ glVertex3f(-1, -1, 1); glVertex3f(1, -1, 1); glVertex3f(1, -1, -1); glVertex3f(-1, -1, -1); glEnd(); glEndList(); } glCallList(cubeList); glDisable(GL_DEPTH_TEST); glLoadIdentity(); glColor3f(1, 1, 1); glRasterPos3d(CornerX, CornerY, CornerZ); ident = Togl_Ident(togl); if (ident) print_string(togl, ident); Togl_SwapBuffers(togl); return TCL_OK; } static int setXrot_cb(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "angle"); return TCL_ERROR; } if (Tcl_GetDoubleFromObj(interp, objv[1], &xAngle) != TCL_OK) { return TCL_ERROR; } /* printf( "before %f ", xAngle ); */ xAngle = fmod(xAngle, 360.0); if (xAngle < 0) xAngle += 360.0; /* printf( "after %f \n", xAngle ); */ /* Let result string equal value */ Tcl_SetObjResult(interp, objv[1]); return TCL_OK; } static int setYrot_cb(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "pathName angle"); return TCL_ERROR; } if (Tcl_GetDoubleFromObj(interp, objv[1], &yAngle) != TCL_OK) { return TCL_ERROR; } yAngle = fmod(yAngle, 360.0); if (yAngle < 0) yAngle += 360.0; /* Let result string equal value */ Tcl_SetObjResult(interp, objv[1]); return TCL_OK; } /* * Called by Tcl to let me initialize the modules (Togl) I will need. */ EXTERN int Double_Init(Tcl_Interp *interp) { /* * Initialize Tcl and the Togl widget module. */ if (Tcl_InitStubs(interp, "8.1", 0) == NULL || Togl_InitStubs(interp, "2.0", 0) == NULL) { return TCL_ERROR; } /* * Specify the C callback functions for widget creation, display, * and reshape. */ Tcl_CreateObjCommand(interp, "double::create_cb", create_cb, NULL, NULL); Tcl_CreateObjCommand(interp, "double::display_cb", display_cb, NULL, NULL); Tcl_CreateObjCommand(interp, "double::reshape_cb", reshape_cb, NULL, NULL); /* * Make a new Togl widget command so the Tcl code can set a C variable. */ Tcl_CreateObjCommand(interp, "double::setXrot", setXrot_cb, NULL, NULL); Tcl_CreateObjCommand(interp, "double::setYrot", setYrot_cb, NULL, NULL); /* * Call Tcl_CreateCommand for application-specific commands, if * they weren't already created by the init procedures called above. */ return TCL_OK; } ================================================ FILE: ng/Togl2.1/double.tcl ================================================ #!/bin/sh # the next line restarts using tclsh \ exec tclsh "$0" "$@" # $Id: double.tcl,v 1.11 2009/03/12 23:59:35 gregcouch Exp $ # Togl - a Tk OpenGL widget # Copyright (C) 1996 Brian Paul and Ben Bederson # Copyright (C) 2006-2007 Greg Couch # See the LICENSE file for copyright details. # An Tk/OpenGL widget demo with two windows, one single buffered and the # other double buffered. package provide double 1.0 # add parent directory to path to find Togl's pkgIndex in current directory if { [file exists pkgIndex.tcl] } { set auto_path [linsert $auto_path 0 ..] } # following load also loads Tk and Togl packages load [file dirname [info script]]/double[info sharedlibextension] # create ::double namespace namespace eval ::double { } proc double::setup {} { wm title . "Single vs Double Buffering" # create first Togl widget togl .o1 -width 200 -height 200 -rgba true -double false -depth true -ident "Single Buffered" -create double::create_cb -display double::display_cb -reshape double::reshape_cb # create second Togl widget, share display lists with first widget togl .o2 -width 200 -height 200 -rgba true -double true -depth true -ident "Double Buffered" -sharelist "Single Buffered" -create double::create_cb -display double::display_cb -reshape double::reshape_cb scale .sx -label {X Axis} -from 0 -to 360 -command {::double::setAngle x} -orient horizontal scale .sy -label {Y Axis} -from 0 -to 360 -command {::double::setAngle y} -orient horizontal button .btn -text Quit -command exit bind .o1 { ::double::motion_event [lindex [%W config -width] 4] \ [lindex [%W config -height] 4] \ %x %y } bind .o2 { ::double::motion_event [lindex [%W config -width] 4] \ [lindex [%W config -height] 4] \ %x %y } grid rowconfigure . 0 -weight 1 grid columnconfigure . 0 -weight 1 -uniform same grid columnconfigure . 1 -weight 1 -uniform same grid .o1 -row 0 -column 0 -sticky nesw -padx 3 -pady 3 grid .o2 -row 0 -column 1 -sticky nesw -padx 3 -pady 3 #grid .l1 -row 1 -column 0 -sticky ew -padx 3 -pady 3 #grid .l2 -row 1 -column 1 -sticky ew -padx 3 -pady 3 grid .sx -row 2 -column 0 -columnspan 2 -sticky ew grid .sy -row 3 -column 0 -columnspan 2 -sticky ew grid .btn -row 4 -column 0 -columnspan 2 -sticky ew } # This is called when mouse button 1 is pressed and moved in either of # the OpenGL windows. proc double::motion_event { width height x y } { .sx set [double::setXrot [expr 360.0 * $y / $height]] .sy set [double::setYrot [expr 360.0 * ($width - $x) / $width]] .o1 postredisplay .o2 postredisplay } # This is called when a slider is changed. proc double::setAngle {axis value} { global xAngle yAngle zAngle switch -exact $axis { x {double::setXrot $value double::setXrot $value} y {double::setYrot $value double::setYrot $value} } .o1 postredisplay .o2 postredisplay } # Execution starts here! if { [info script] == $argv0 } { ::double::setup } ================================================ FILE: ng/Togl2.1/gears.c ================================================ /* gears.c */ /* * 3-D gear wheels. This program is in the public domain. * * Brian Paul * * * Modified to work under Togl as a widget for TK 1997 * * Philip Quaife * */ #define USE_TOGL_STUBS #include "togl.h" #include #include #include #undef TCL_STORAGE_CLASS #define TCL_STORAGE_CLASS DLLEXPORT #ifndef M_PI # define M_PI 3.14159265 #endif #define FM_PI ((float) M_PI) #ifdef _MSC_VER __inline float sinf(double a) { return (float) sin(a); } __inline float cosf(double a) { return (float) cos(a); } __inline float sqrtf(double a) { return (float) sqrt(a); } # define sin sinf # define cos cosf # define sqrt sqrtf #endif struct WHIRLYGIZMO { int Gear1, Gear2, Gear3; double Rotx, Roty, Rotz; double Angle; int Height, Width; }; typedef struct WHIRLYGIZMO WHIRLYGIZMO; /* * Draw a gear wheel. You'll probably want to call this function when * building a display list since we do a lot of trig here. * * Input: inner_radius - radius of hole at center * outer_radius - radius at center of teeth * width - width of gear * teeth - number of teeth * tooth_depth - depth of tooth */ static void gear(GLfloat inner_radius, GLfloat outer_radius, GLfloat width, GLint teeth, GLfloat tooth_depth) { GLint i; GLfloat r0, r1, r2; GLfloat angle, da; GLfloat u, v, len; r0 = inner_radius; r1 = outer_radius - tooth_depth / 2; r2 = outer_radius + tooth_depth / 2; da = 2 * FM_PI / teeth / 4; glShadeModel(GL_FLAT); glNormal3f(0, 0, 1); /* draw front face */ glBegin(GL_QUAD_STRIP); for (i = 0; i <= teeth; i++) { angle = i * 2 * FM_PI / teeth; glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5f); glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5f); glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5f); glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), width * 0.5f); } glEnd(); /* draw front sides of teeth */ glBegin(GL_QUADS); da = 2 * FM_PI / teeth / 4; for (i = 0; i < teeth; i++) { angle = i * 2 * FM_PI / teeth; glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5f); glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5f); glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), width * 0.5f); glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), width * 0.5f); } glEnd(); glNormal3f(0, 0, -1); /* draw back face */ glBegin(GL_QUAD_STRIP); for (i = 0; i <= teeth; i++) { angle = i * 2 * FM_PI / teeth; glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5f); glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5f); glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -width * 0.5f); glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5f); } glEnd(); /* draw back sides of teeth */ glBegin(GL_QUADS); da = 2 * FM_PI / teeth / 4; for (i = 0; i < teeth; i++) { angle = i * 2 * FM_PI / teeth; glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -width * 0.5f); glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), -width * 0.5f); glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5f); glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5f); } glEnd(); /* draw outward faces of teeth */ glBegin(GL_QUAD_STRIP); for (i = 0; i < teeth; i++) { angle = i * 2 * FM_PI / teeth; glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5f); glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5f); u = r2 * cos(angle + da) - r1 * cos(angle); v = r2 * sin(angle + da) - r1 * sin(angle); len = sqrt(u * u + v * v); u /= len; v /= len; glNormal3f(v, -u, 0); glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5f); glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5f); glNormal3f(cos(angle), sin(angle), 0); glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), width * 0.5f); glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), -width * 0.5f); u = r1 * cos(angle + 3 * da) - r2 * cos(angle + 2 * da); v = r1 * sin(angle + 3 * da) - r2 * sin(angle + 2 * da); glNormal3f(v, -u, 0); glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), width * 0.5f); glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -width * 0.5f); glNormal3f(cos(angle), sin(angle), 0); } glVertex3f(r1 /* * cos(0) */ , /* r1 * sin(0) */ 0, width * 0.5f); glVertex3f(r1 /* * cos(0) */ , /* r1 * sin(0) */ 0, -width * 0.5f); glEnd(); glShadeModel(GL_SMOOTH); /* draw inside radius cylinder */ glBegin(GL_QUAD_STRIP); for (i = 0; i <= teeth; i++) { angle = i * 2 * FM_PI / teeth; glNormal3f(-cos(angle), -sin(angle), 0); glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5f); glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5f); } glEnd(); } /* * static GLfloat view_rotx=20, view_roty=30, view_rotz=0; static GLint * gear1, gear2, gear3; static GLfloat angle = 0; */ static GLuint limit; static GLuint count = 1; static GLubyte polycolor[4] = { 255, 255, 255, 255 }; static int draw(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { WHIRLYGIZMO *Wg; Togl *togl; if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "pathName"); return TCL_ERROR; } if (Togl_GetToglFromObj(interp, objv[1], &togl) != TCL_OK) { return TCL_ERROR; } glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); Wg = (WHIRLYGIZMO *) Togl_GetClientData(togl); glDisable(GL_TEXTURE_2D); glPushMatrix(); glRotatef((float) Wg->Rotx, 1, 0, 0); glRotatef((float) Wg->Roty, 0, 1, 0); glRotatef((float) Wg->Rotz, 0, 0, 1); glPushMatrix(); glTranslatef(-3, -2, 0); glRotatef((float) Wg->Angle, 0, 0, 1); glEnable(GL_DEPTH_TEST); glCallList(Wg->Gear1); glEnable(GL_DEPTH_TEST); glPopMatrix(); glPushMatrix(); glTranslatef(3.1f, -2, 0); glRotatef(-2 * (float) Wg->Angle - 9, 0, 0, 1); glCallList(Wg->Gear2); glPopMatrix(); glPushMatrix(); glTranslatef(-3.1f, 4.2f, 0); glRotatef(-2 * (float) Wg->Angle - 25, 0, 0, 1); glCallList(Wg->Gear3); glPopMatrix(); glPopMatrix(); Togl_SwapBuffers(togl); return TCL_OK; } static int zap(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { WHIRLYGIZMO *Wg; Togl *togl; if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "pathName"); return TCL_ERROR; } if (Togl_GetToglFromObj(interp, objv[1], &togl) != TCL_OK) { return TCL_ERROR; } Wg = (WHIRLYGIZMO *) Togl_GetClientData(togl); free(Wg); return TCL_OK; } static int idle(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { WHIRLYGIZMO *Wg; Togl *togl; if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "pathName"); return TCL_ERROR; } if (Togl_GetToglFromObj(interp, objv[1], &togl) != TCL_OK) { return TCL_ERROR; } Wg = (WHIRLYGIZMO *) Togl_GetClientData(togl); Wg->Angle += 2; Togl_PostRedisplay(togl); return TCL_OK; } /* change view angle, exit upon ESC */ /* * static GLenum key(int k, GLenum mask) { switch (k) { case TK_UP: view_rotx * += 5; return GL_TRUE; case TK_DOWN: view_rotx -= 5; return GL_TRUE; case * TK_LEFT: view_roty += 5; return GL_TRUE; case TK_RIGHT: view_roty -= 5; * return GL_TRUE; case TK_z: view_rotz += 5; return GL_TRUE; case TK_Z: * view_rotz -= 5; return GL_TRUE; } return GL_FALSE; } */ /* new window size or exposure */ static int reshape(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { int width, height; Togl *togl; if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "pathName"); return TCL_ERROR; } if (Togl_GetToglFromObj(interp, objv[1], &togl) != TCL_OK) { return TCL_ERROR; } width = Togl_Width(togl); height = Togl_Height(togl); glViewport(0, 0, (GLint) width, (GLint) height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (width > height) { GLfloat w = (GLfloat) width / (GLfloat) height; glFrustum(-w, w, -1, 1, 5, 60); } else { GLfloat h = (GLfloat) height / (GLfloat) width; glFrustum(-1, 1, -h, h, 5, 60); } glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(0, 0, -40); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); return TCL_OK; } static int init(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { WHIRLYGIZMO *Wg; static GLfloat red[4] = { 0.8f, 0.1f, 0, 1 }; static GLfloat green[4] = { 0, 0.8f, 0.2f, 1 }; static GLfloat blue[4] = { 0.2f, 0.2f, 1, 1 }; static GLfloat pos[4] = { 5, 5, 10, 0 }; Togl *togl; if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "pathName"); return TCL_ERROR; } if (Togl_GetToglFromObj(interp, objv[1], &togl) != TCL_OK) { return TCL_ERROR; } glLightfv(GL_LIGHT0, GL_POSITION, pos); glEnable(GL_CULL_FACE); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_DEPTH_TEST); /* make the gears */ Wg = (WHIRLYGIZMO *) malloc(sizeof (WHIRLYGIZMO)); if (!Wg) { Tcl_SetResult(Togl_Interp(togl), "\"Cannot allocate client data for widget\"", TCL_STATIC); } Wg->Gear1 = glGenLists(1); glNewList(Wg->Gear1, GL_COMPILE); glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red); gear(1, 4, 1, 20, 0.7f); glEndList(); Wg->Gear2 = glGenLists(1); glNewList(Wg->Gear2, GL_COMPILE); glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, green); gear(0.5f, 2, 2, 10, 0.7f); glEndList(); Wg->Gear3 = glGenLists(1); glNewList(Wg->Gear3, GL_COMPILE); glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, blue); gear(1.3f, 2, 0.5f, 10, 0.7f); glEndList(); glEnable(GL_NORMALIZE); Wg->Height = Togl_Height(togl); Wg->Width = Togl_Width(togl); Wg->Angle = 0; Wg->Rotx = 0; Wg->Roty = 0; Wg->Rotz = 0; Togl_SetClientData(togl, (ClientData) Wg); return TCL_OK; } static int position(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { WHIRLYGIZMO *Wg; char Result[100]; Togl *togl; if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "pathName"); return TCL_ERROR; } if (Togl_GetToglFromObj(interp, objv[1], &togl) != TCL_OK) { return TCL_ERROR; } Wg = (WHIRLYGIZMO *) Togl_GetClientData(togl); /* Let result string equal value */ sprintf(Result, "%g %g", Wg->Roty, Wg->Rotx); Tcl_SetResult(interp, Result, TCL_VOLATILE); return TCL_OK; } static int rotate(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { WHIRLYGIZMO *Wg; Togl *togl; if (objc != 4) { Tcl_WrongNumArgs(interp, 1, objv, "pathName yrot xrot"); return TCL_ERROR; } if (Togl_GetToglFromObj(interp, objv[1], &togl) != TCL_OK) { return TCL_ERROR; } Wg = (WHIRLYGIZMO *) Togl_GetClientData(togl); if (Tcl_GetDoubleFromObj(interp, objv[2], &Wg->Roty) != TCL_OK) { return TCL_ERROR; } if (Tcl_GetDoubleFromObj(interp, objv[3], &Wg->Rotx) != TCL_OK) { return TCL_ERROR; } Togl_PostRedisplay(togl); return TCL_OK; } EXTERN int Gears_Init(Tcl_Interp *interp) { /* * Initialize Tcl and the Togl widget module. */ if (Tcl_InitStubs(interp, "8.1", 0) == NULL || Togl_InitStubs(interp, "2.0", 0) == NULL) { return TCL_ERROR; } /* * Specify the C callback functions for widget creation, display, * and reshape. */ Tcl_CreateObjCommand(interp, "init", init, NULL, NULL); Tcl_CreateObjCommand(interp, "zap", zap, NULL, NULL); Tcl_CreateObjCommand(interp, "draw", draw, NULL, NULL); Tcl_CreateObjCommand(interp, "reshape", reshape, NULL, NULL); Tcl_CreateObjCommand(interp, "idle", idle, NULL, NULL); Tcl_CreateObjCommand(interp, "rotate", rotate, NULL, NULL); Tcl_CreateObjCommand(interp, "position", position, NULL, NULL); return TCL_OK; } ================================================ FILE: ng/Togl2.1/gears.tcl ================================================ #!/bin/sh # the next line restarts using tclsh \ exec tclsh "$0" "$@" # Togl - a Tk OpenGL widget # Copyright (C) 1996-1997 Brian Paul and Ben Bederson # Copyright (C) 2006-2007 Greg Couch # See the LICENSE file for copyright details. # # Test Togl using GL Gears Demo # # Copyright (C) 1997 Philip Quaife # package provide gears 1.0 # add parent directory to path to find Togl's pkgIndex in current directory if { [file exists pkgIndex.tcl] } { set auto_path [linsert $auto_path 0 ..] } # following load also loads Tk and Togl packages load [file dirname [info script]]/gears[info sharedlibextension] # create ::gears namespace namespace eval ::gears { } proc ::gears::setup {} { global startx starty xangle0 yangle0 xangle yangle RotCnt global vTime set RotCnt 1 set xangle 0.0 set yangle 0.0 set vTime 100 wm title . "Rotating Gear Widget Test" label .t -text "Click and drag to rotate image" pack .t -side top -padx 2 -pady 10 frame .f pack .f -side top button .f.n1 -text " Add " -command ::gears::AutoRot button .f.r1 -text "Remove" -command ::gears::DelRot button .f.b1 -text " Quit " -command exit entry .f.t -width 4 -textvariable vTime pack .f.n1 .f.t .f.r1 .f.b1 -side left -anchor w -padx 5 newRot .w0 10 } proc ::gears::AutoRot {} { global RotCnt vTime newRot .w$RotCnt $vTime set RotCnt [expr $RotCnt + 1] } proc ::gears::DelRot {} { global RotCnt vTime if { $RotCnt != 0 } { set RotCnt [expr $RotCnt - 1] destroy .w$RotCnt } } proc ::gears::newRot {win {tick 100} } { togl $win -width 200 -height 200 -rgba true -double true -depth true -privatecmap false -time $tick -create init -destroy zap -display draw -reshape reshape -timer idle bind $win {::gears::RotStart %x %y %W} bind $win {::gears::RotMove %x %y %W} pack $win -expand true -fill both } proc ::gears::RotStart {x y W} { global startx starty xangle0 yangle0 xangle yangle set startx $x set starty $y set vPos [position $W] set xangle0 [lindex $vPos 0] set yangle0 [lindex $vPos 1] } proc ::gears::RotMove {x y W} { global startx starty xangle0 yangle0 xangle yangle set xangle [expr $xangle0 + ($x - $startx)] set yangle [expr $yangle0 + ($y - $starty)] rotate $W $xangle $yangle } if { [info script] == $argv0 } { ::gears::setup } ================================================ FILE: ng/Togl2.1/gl/glext.h ================================================ #ifndef __glext_h_ #define __glext_h_ #ifdef __cplusplus extern "C" { #endif /* ** Copyright (c) 2007 The Khronos Group Inc. ** ** Permission is hereby granted, free of charge, to any person obtaining a ** copy of this software and/or associated documentation files (the ** "Materials"), to deal in the Materials without restriction, including ** without limitation the rights to use, copy, modify, merge, publish, ** distribute, sublicense, and/or sell copies of the Materials, and to ** permit persons to whom the Materials are furnished to do so, subject to ** the following conditions: ** ** The above copyright notice and this permission notice shall be included ** in all copies or substantial portions of the Materials. ** ** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, ** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE ** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. */ #if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) #define WIN32_LEAN_AND_MEAN 1 #include #endif #ifndef APIENTRY #define APIENTRY #endif #ifndef APIENTRYP #define APIENTRYP APIENTRY * #endif #ifndef GLAPI #define GLAPI extern #endif /*************************************************************/ /* Header file version number, required by OpenGL ABI for Linux */ /* glext.h last updated 2008/11/14 */ /* Current version at http://www.opengl.org/registry/ */ #define GL_GLEXT_VERSION 44 #ifndef GL_VERSION_1_2 #define GL_UNSIGNED_BYTE_3_3_2 0x8032 #define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 #define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 #define GL_UNSIGNED_INT_8_8_8_8 0x8035 #define GL_UNSIGNED_INT_10_10_10_2 0x8036 #define GL_RESCALE_NORMAL 0x803A #define GL_TEXTURE_BINDING_3D 0x806A #define GL_PACK_SKIP_IMAGES 0x806B #define GL_PACK_IMAGE_HEIGHT 0x806C #define GL_UNPACK_SKIP_IMAGES 0x806D #define GL_UNPACK_IMAGE_HEIGHT 0x806E #define GL_TEXTURE_3D 0x806F #define GL_PROXY_TEXTURE_3D 0x8070 #define GL_TEXTURE_DEPTH 0x8071 #define GL_TEXTURE_WRAP_R 0x8072 #define GL_MAX_3D_TEXTURE_SIZE 0x8073 #define GL_UNSIGNED_BYTE_2_3_3_REV 0x8362 #define GL_UNSIGNED_SHORT_5_6_5 0x8363 #define GL_UNSIGNED_SHORT_5_6_5_REV 0x8364 #define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365 #define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366 #define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367 #define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368 #define GL_BGR 0x80E0 #define GL_BGRA 0x80E1 #define GL_MAX_ELEMENTS_VERTICES 0x80E8 #define GL_MAX_ELEMENTS_INDICES 0x80E9 #define GL_CLAMP_TO_EDGE 0x812F #define GL_TEXTURE_MIN_LOD 0x813A #define GL_TEXTURE_MAX_LOD 0x813B #define GL_TEXTURE_BASE_LEVEL 0x813C #define GL_TEXTURE_MAX_LEVEL 0x813D #define GL_LIGHT_MODEL_COLOR_CONTROL 0x81F8 #define GL_SINGLE_COLOR 0x81F9 #define GL_SEPARATE_SPECULAR_COLOR 0x81FA #define GL_SMOOTH_POINT_SIZE_RANGE 0x0B12 #define GL_SMOOTH_POINT_SIZE_GRANULARITY 0x0B13 #define GL_SMOOTH_LINE_WIDTH_RANGE 0x0B22 #define GL_SMOOTH_LINE_WIDTH_GRANULARITY 0x0B23 #define GL_ALIASED_POINT_SIZE_RANGE 0x846D #define GL_ALIASED_LINE_WIDTH_RANGE 0x846E #endif #ifndef GL_ARB_imaging #define GL_CONSTANT_COLOR 0x8001 #define GL_ONE_MINUS_CONSTANT_COLOR 0x8002 #define GL_CONSTANT_ALPHA 0x8003 #define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004 #define GL_BLEND_COLOR 0x8005 #define GL_FUNC_ADD 0x8006 #define GL_MIN 0x8007 #define GL_MAX 0x8008 #define GL_BLEND_EQUATION 0x8009 #define GL_FUNC_SUBTRACT 0x800A #define GL_FUNC_REVERSE_SUBTRACT 0x800B #define GL_CONVOLUTION_1D 0x8010 #define GL_CONVOLUTION_2D 0x8011 #define GL_SEPARABLE_2D 0x8012 #define GL_CONVOLUTION_BORDER_MODE 0x8013 #define GL_CONVOLUTION_FILTER_SCALE 0x8014 #define GL_CONVOLUTION_FILTER_BIAS 0x8015 #define GL_REDUCE 0x8016 #define GL_CONVOLUTION_FORMAT 0x8017 #define GL_CONVOLUTION_WIDTH 0x8018 #define GL_CONVOLUTION_HEIGHT 0x8019 #define GL_MAX_CONVOLUTION_WIDTH 0x801A #define GL_MAX_CONVOLUTION_HEIGHT 0x801B #define GL_POST_CONVOLUTION_RED_SCALE 0x801C #define GL_POST_CONVOLUTION_GREEN_SCALE 0x801D #define GL_POST_CONVOLUTION_BLUE_SCALE 0x801E #define GL_POST_CONVOLUTION_ALPHA_SCALE 0x801F #define GL_POST_CONVOLUTION_RED_BIAS 0x8020 #define GL_POST_CONVOLUTION_GREEN_BIAS 0x8021 #define GL_POST_CONVOLUTION_BLUE_BIAS 0x8022 #define GL_POST_CONVOLUTION_ALPHA_BIAS 0x8023 #define GL_HISTOGRAM 0x8024 #define GL_PROXY_HISTOGRAM 0x8025 #define GL_HISTOGRAM_WIDTH 0x8026 #define GL_HISTOGRAM_FORMAT 0x8027 #define GL_HISTOGRAM_RED_SIZE 0x8028 #define GL_HISTOGRAM_GREEN_SIZE 0x8029 #define GL_HISTOGRAM_BLUE_SIZE 0x802A #define GL_HISTOGRAM_ALPHA_SIZE 0x802B #define GL_HISTOGRAM_LUMINANCE_SIZE 0x802C #define GL_HISTOGRAM_SINK 0x802D #define GL_MINMAX 0x802E #define GL_MINMAX_FORMAT 0x802F #define GL_MINMAX_SINK 0x8030 #define GL_TABLE_TOO_LARGE 0x8031 #define GL_COLOR_MATRIX 0x80B1 #define GL_COLOR_MATRIX_STACK_DEPTH 0x80B2 #define GL_MAX_COLOR_MATRIX_STACK_DEPTH 0x80B3 #define GL_POST_COLOR_MATRIX_RED_SCALE 0x80B4 #define GL_POST_COLOR_MATRIX_GREEN_SCALE 0x80B5 #define GL_POST_COLOR_MATRIX_BLUE_SCALE 0x80B6 #define GL_POST_COLOR_MATRIX_ALPHA_SCALE 0x80B7 #define GL_POST_COLOR_MATRIX_RED_BIAS 0x80B8 #define GL_POST_COLOR_MATRIX_GREEN_BIAS 0x80B9 #define GL_POST_COLOR_MATRIX_BLUE_BIAS 0x80BA #define GL_POST_COLOR_MATRIX_ALPHA_BIAS 0x80BB #define GL_COLOR_TABLE 0x80D0 #define GL_POST_CONVOLUTION_COLOR_TABLE 0x80D1 #define GL_POST_COLOR_MATRIX_COLOR_TABLE 0x80D2 #define GL_PROXY_COLOR_TABLE 0x80D3 #define GL_PROXY_POST_CONVOLUTION_COLOR_TABLE 0x80D4 #define GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE 0x80D5 #define GL_COLOR_TABLE_SCALE 0x80D6 #define GL_COLOR_TABLE_BIAS 0x80D7 #define GL_COLOR_TABLE_FORMAT 0x80D8 #define GL_COLOR_TABLE_WIDTH 0x80D9 #define GL_COLOR_TABLE_RED_SIZE 0x80DA #define GL_COLOR_TABLE_GREEN_SIZE 0x80DB #define GL_COLOR_TABLE_BLUE_SIZE 0x80DC #define GL_COLOR_TABLE_ALPHA_SIZE 0x80DD #define GL_COLOR_TABLE_LUMINANCE_SIZE 0x80DE #define GL_COLOR_TABLE_INTENSITY_SIZE 0x80DF #define GL_CONSTANT_BORDER 0x8151 #define GL_REPLICATE_BORDER 0x8153 #define GL_CONVOLUTION_BORDER_COLOR 0x8154 #endif #ifndef GL_VERSION_1_3 #define GL_TEXTURE0 0x84C0 #define GL_TEXTURE1 0x84C1 #define GL_TEXTURE2 0x84C2 #define GL_TEXTURE3 0x84C3 #define GL_TEXTURE4 0x84C4 #define GL_TEXTURE5 0x84C5 #define GL_TEXTURE6 0x84C6 #define GL_TEXTURE7 0x84C7 #define GL_TEXTURE8 0x84C8 #define GL_TEXTURE9 0x84C9 #define GL_TEXTURE10 0x84CA #define GL_TEXTURE11 0x84CB #define GL_TEXTURE12 0x84CC #define GL_TEXTURE13 0x84CD #define GL_TEXTURE14 0x84CE #define GL_TEXTURE15 0x84CF #define GL_TEXTURE16 0x84D0 #define GL_TEXTURE17 0x84D1 #define GL_TEXTURE18 0x84D2 #define GL_TEXTURE19 0x84D3 #define GL_TEXTURE20 0x84D4 #define GL_TEXTURE21 0x84D5 #define GL_TEXTURE22 0x84D6 #define GL_TEXTURE23 0x84D7 #define GL_TEXTURE24 0x84D8 #define GL_TEXTURE25 0x84D9 #define GL_TEXTURE26 0x84DA #define GL_TEXTURE27 0x84DB #define GL_TEXTURE28 0x84DC #define GL_TEXTURE29 0x84DD #define GL_TEXTURE30 0x84DE #define GL_TEXTURE31 0x84DF #define GL_ACTIVE_TEXTURE 0x84E0 #define GL_CLIENT_ACTIVE_TEXTURE 0x84E1 #define GL_MAX_TEXTURE_UNITS 0x84E2 #define GL_TRANSPOSE_MODELVIEW_MATRIX 0x84E3 #define GL_TRANSPOSE_PROJECTION_MATRIX 0x84E4 #define GL_TRANSPOSE_TEXTURE_MATRIX 0x84E5 #define GL_TRANSPOSE_COLOR_MATRIX 0x84E6 #define GL_MULTISAMPLE 0x809D #define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E #define GL_SAMPLE_ALPHA_TO_ONE 0x809F #define GL_SAMPLE_COVERAGE 0x80A0 #define GL_SAMPLE_BUFFERS 0x80A8 #define GL_SAMPLES 0x80A9 #define GL_SAMPLE_COVERAGE_VALUE 0x80AA #define GL_SAMPLE_COVERAGE_INVERT 0x80AB #define GL_MULTISAMPLE_BIT 0x20000000 #define GL_NORMAL_MAP 0x8511 #define GL_REFLECTION_MAP 0x8512 #define GL_TEXTURE_CUBE_MAP 0x8513 #define GL_TEXTURE_BINDING_CUBE_MAP 0x8514 #define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516 #define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518 #define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A #define GL_PROXY_TEXTURE_CUBE_MAP 0x851B #define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C #define GL_COMPRESSED_ALPHA 0x84E9 #define GL_COMPRESSED_LUMINANCE 0x84EA #define GL_COMPRESSED_LUMINANCE_ALPHA 0x84EB #define GL_COMPRESSED_INTENSITY 0x84EC #define GL_COMPRESSED_RGB 0x84ED #define GL_COMPRESSED_RGBA 0x84EE #define GL_TEXTURE_COMPRESSION_HINT 0x84EF #define GL_TEXTURE_COMPRESSED_IMAGE_SIZE 0x86A0 #define GL_TEXTURE_COMPRESSED 0x86A1 #define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2 #define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3 #define GL_CLAMP_TO_BORDER 0x812D #define GL_COMBINE 0x8570 #define GL_COMBINE_RGB 0x8571 #define GL_COMBINE_ALPHA 0x8572 #define GL_SOURCE0_RGB 0x8580 #define GL_SOURCE1_RGB 0x8581 #define GL_SOURCE2_RGB 0x8582 #define GL_SOURCE0_ALPHA 0x8588 #define GL_SOURCE1_ALPHA 0x8589 #define GL_SOURCE2_ALPHA 0x858A #define GL_OPERAND0_RGB 0x8590 #define GL_OPERAND1_RGB 0x8591 #define GL_OPERAND2_RGB 0x8592 #define GL_OPERAND0_ALPHA 0x8598 #define GL_OPERAND1_ALPHA 0x8599 #define GL_OPERAND2_ALPHA 0x859A #define GL_RGB_SCALE 0x8573 #define GL_ADD_SIGNED 0x8574 #define GL_INTERPOLATE 0x8575 #define GL_SUBTRACT 0x84E7 #define GL_CONSTANT 0x8576 #define GL_PRIMARY_COLOR 0x8577 #define GL_PREVIOUS 0x8578 #define GL_DOT3_RGB 0x86AE #define GL_DOT3_RGBA 0x86AF #endif #ifndef GL_VERSION_1_4 #define GL_BLEND_DST_RGB 0x80C8 #define GL_BLEND_SRC_RGB 0x80C9 #define GL_BLEND_DST_ALPHA 0x80CA #define GL_BLEND_SRC_ALPHA 0x80CB #define GL_POINT_SIZE_MIN 0x8126 #define GL_POINT_SIZE_MAX 0x8127 #define GL_POINT_FADE_THRESHOLD_SIZE 0x8128 #define GL_POINT_DISTANCE_ATTENUATION 0x8129 #define GL_GENERATE_MIPMAP 0x8191 #define GL_GENERATE_MIPMAP_HINT 0x8192 #define GL_DEPTH_COMPONENT16 0x81A5 #define GL_DEPTH_COMPONENT24 0x81A6 #define GL_DEPTH_COMPONENT32 0x81A7 #define GL_MIRRORED_REPEAT 0x8370 #define GL_FOG_COORDINATE_SOURCE 0x8450 #define GL_FOG_COORDINATE 0x8451 #define GL_FRAGMENT_DEPTH 0x8452 #define GL_CURRENT_FOG_COORDINATE 0x8453 #define GL_FOG_COORDINATE_ARRAY_TYPE 0x8454 #define GL_FOG_COORDINATE_ARRAY_STRIDE 0x8455 #define GL_FOG_COORDINATE_ARRAY_POINTER 0x8456 #define GL_FOG_COORDINATE_ARRAY 0x8457 #define GL_COLOR_SUM 0x8458 #define GL_CURRENT_SECONDARY_COLOR 0x8459 #define GL_SECONDARY_COLOR_ARRAY_SIZE 0x845A #define GL_SECONDARY_COLOR_ARRAY_TYPE 0x845B #define GL_SECONDARY_COLOR_ARRAY_STRIDE 0x845C #define GL_SECONDARY_COLOR_ARRAY_POINTER 0x845D #define GL_SECONDARY_COLOR_ARRAY 0x845E #define GL_MAX_TEXTURE_LOD_BIAS 0x84FD #define GL_TEXTURE_FILTER_CONTROL 0x8500 #define GL_TEXTURE_LOD_BIAS 0x8501 #define GL_INCR_WRAP 0x8507 #define GL_DECR_WRAP 0x8508 #define GL_TEXTURE_DEPTH_SIZE 0x884A #define GL_DEPTH_TEXTURE_MODE 0x884B #define GL_TEXTURE_COMPARE_MODE 0x884C #define GL_TEXTURE_COMPARE_FUNC 0x884D #define GL_COMPARE_R_TO_TEXTURE 0x884E #endif #ifndef GL_VERSION_1_5 #define GL_BUFFER_SIZE 0x8764 #define GL_BUFFER_USAGE 0x8765 #define GL_QUERY_COUNTER_BITS 0x8864 #define GL_CURRENT_QUERY 0x8865 #define GL_QUERY_RESULT 0x8866 #define GL_QUERY_RESULT_AVAILABLE 0x8867 #define GL_ARRAY_BUFFER 0x8892 #define GL_ELEMENT_ARRAY_BUFFER 0x8893 #define GL_ARRAY_BUFFER_BINDING 0x8894 #define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895 #define GL_VERTEX_ARRAY_BUFFER_BINDING 0x8896 #define GL_NORMAL_ARRAY_BUFFER_BINDING 0x8897 #define GL_COLOR_ARRAY_BUFFER_BINDING 0x8898 #define GL_INDEX_ARRAY_BUFFER_BINDING 0x8899 #define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING 0x889A #define GL_EDGE_FLAG_ARRAY_BUFFER_BINDING 0x889B #define GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING 0x889C #define GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING 0x889D #define GL_WEIGHT_ARRAY_BUFFER_BINDING 0x889E #define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F #define GL_READ_ONLY 0x88B8 #define GL_WRITE_ONLY 0x88B9 #define GL_READ_WRITE 0x88BA #define GL_BUFFER_ACCESS 0x88BB #define GL_BUFFER_MAPPED 0x88BC #define GL_BUFFER_MAP_POINTER 0x88BD #define GL_STREAM_DRAW 0x88E0 #define GL_STREAM_READ 0x88E1 #define GL_STREAM_COPY 0x88E2 #define GL_STATIC_DRAW 0x88E4 #define GL_STATIC_READ 0x88E5 #define GL_STATIC_COPY 0x88E6 #define GL_DYNAMIC_DRAW 0x88E8 #define GL_DYNAMIC_READ 0x88E9 #define GL_DYNAMIC_COPY 0x88EA #define GL_SAMPLES_PASSED 0x8914 #define GL_FOG_COORD_SRC GL_FOG_COORDINATE_SOURCE #define GL_FOG_COORD GL_FOG_COORDINATE #define GL_CURRENT_FOG_COORD GL_CURRENT_FOG_COORDINATE #define GL_FOG_COORD_ARRAY_TYPE GL_FOG_COORDINATE_ARRAY_TYPE #define GL_FOG_COORD_ARRAY_STRIDE GL_FOG_COORDINATE_ARRAY_STRIDE #define GL_FOG_COORD_ARRAY_POINTER GL_FOG_COORDINATE_ARRAY_POINTER #define GL_FOG_COORD_ARRAY GL_FOG_COORDINATE_ARRAY #define GL_FOG_COORD_ARRAY_BUFFER_BINDING GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING #define GL_SRC0_RGB GL_SOURCE0_RGB #define GL_SRC1_RGB GL_SOURCE1_RGB #define GL_SRC2_RGB GL_SOURCE2_RGB #define GL_SRC0_ALPHA GL_SOURCE0_ALPHA #define GL_SRC1_ALPHA GL_SOURCE1_ALPHA #define GL_SRC2_ALPHA GL_SOURCE2_ALPHA #endif #ifndef GL_VERSION_2_0 #define GL_BLEND_EQUATION_RGB GL_BLEND_EQUATION #define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622 #define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623 #define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624 #define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625 #define GL_CURRENT_VERTEX_ATTRIB 0x8626 #define GL_VERTEX_PROGRAM_POINT_SIZE 0x8642 #define GL_VERTEX_PROGRAM_TWO_SIDE 0x8643 #define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645 #define GL_STENCIL_BACK_FUNC 0x8800 #define GL_STENCIL_BACK_FAIL 0x8801 #define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802 #define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803 #define GL_MAX_DRAW_BUFFERS 0x8824 #define GL_DRAW_BUFFER0 0x8825 #define GL_DRAW_BUFFER1 0x8826 #define GL_DRAW_BUFFER2 0x8827 #define GL_DRAW_BUFFER3 0x8828 #define GL_DRAW_BUFFER4 0x8829 #define GL_DRAW_BUFFER5 0x882A #define GL_DRAW_BUFFER6 0x882B #define GL_DRAW_BUFFER7 0x882C #define GL_DRAW_BUFFER8 0x882D #define GL_DRAW_BUFFER9 0x882E #define GL_DRAW_BUFFER10 0x882F #define GL_DRAW_BUFFER11 0x8830 #define GL_DRAW_BUFFER12 0x8831 #define GL_DRAW_BUFFER13 0x8832 #define GL_DRAW_BUFFER14 0x8833 #define GL_DRAW_BUFFER15 0x8834 #define GL_BLEND_EQUATION_ALPHA 0x883D #define GL_POINT_SPRITE 0x8861 #define GL_COORD_REPLACE 0x8862 #define GL_MAX_VERTEX_ATTRIBS 0x8869 #define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A #define GL_MAX_TEXTURE_COORDS 0x8871 #define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872 #define GL_FRAGMENT_SHADER 0x8B30 #define GL_VERTEX_SHADER 0x8B31 #define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49 #define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A #define GL_MAX_VARYING_FLOATS 0x8B4B #define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C #define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D #define GL_SHADER_TYPE 0x8B4F #define GL_FLOAT_VEC2 0x8B50 #define GL_FLOAT_VEC3 0x8B51 #define GL_FLOAT_VEC4 0x8B52 #define GL_INT_VEC2 0x8B53 #define GL_INT_VEC3 0x8B54 #define GL_INT_VEC4 0x8B55 #define GL_BOOL 0x8B56 #define GL_BOOL_VEC2 0x8B57 #define GL_BOOL_VEC3 0x8B58 #define GL_BOOL_VEC4 0x8B59 #define GL_FLOAT_MAT2 0x8B5A #define GL_FLOAT_MAT3 0x8B5B #define GL_FLOAT_MAT4 0x8B5C #define GL_SAMPLER_1D 0x8B5D #define GL_SAMPLER_2D 0x8B5E #define GL_SAMPLER_3D 0x8B5F #define GL_SAMPLER_CUBE 0x8B60 #define GL_SAMPLER_1D_SHADOW 0x8B61 #define GL_SAMPLER_2D_SHADOW 0x8B62 #define GL_DELETE_STATUS 0x8B80 #define GL_COMPILE_STATUS 0x8B81 #define GL_LINK_STATUS 0x8B82 #define GL_VALIDATE_STATUS 0x8B83 #define GL_INFO_LOG_LENGTH 0x8B84 #define GL_ATTACHED_SHADERS 0x8B85 #define GL_ACTIVE_UNIFORMS 0x8B86 #define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87 #define GL_SHADER_SOURCE_LENGTH 0x8B88 #define GL_ACTIVE_ATTRIBUTES 0x8B89 #define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A #define GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B #define GL_SHADING_LANGUAGE_VERSION 0x8B8C #define GL_CURRENT_PROGRAM 0x8B8D #define GL_POINT_SPRITE_COORD_ORIGIN 0x8CA0 #define GL_LOWER_LEFT 0x8CA1 #define GL_UPPER_LEFT 0x8CA2 #define GL_STENCIL_BACK_REF 0x8CA3 #define GL_STENCIL_BACK_VALUE_MASK 0x8CA4 #define GL_STENCIL_BACK_WRITEMASK 0x8CA5 #endif #ifndef GL_VERSION_2_1 #define GL_CURRENT_RASTER_SECONDARY_COLOR 0x845F #define GL_PIXEL_PACK_BUFFER 0x88EB #define GL_PIXEL_UNPACK_BUFFER 0x88EC #define GL_PIXEL_PACK_BUFFER_BINDING 0x88ED #define GL_PIXEL_UNPACK_BUFFER_BINDING 0x88EF #define GL_FLOAT_MAT2x3 0x8B65 #define GL_FLOAT_MAT2x4 0x8B66 #define GL_FLOAT_MAT3x2 0x8B67 #define GL_FLOAT_MAT3x4 0x8B68 #define GL_FLOAT_MAT4x2 0x8B69 #define GL_FLOAT_MAT4x3 0x8B6A #define GL_SRGB 0x8C40 #define GL_SRGB8 0x8C41 #define GL_SRGB_ALPHA 0x8C42 #define GL_SRGB8_ALPHA8 0x8C43 #define GL_SLUMINANCE_ALPHA 0x8C44 #define GL_SLUMINANCE8_ALPHA8 0x8C45 #define GL_SLUMINANCE 0x8C46 #define GL_SLUMINANCE8 0x8C47 #define GL_COMPRESSED_SRGB 0x8C48 #define GL_COMPRESSED_SRGB_ALPHA 0x8C49 #define GL_COMPRESSED_SLUMINANCE 0x8C4A #define GL_COMPRESSED_SLUMINANCE_ALPHA 0x8C4B #endif #ifndef GL_VERSION_3_0 #define GL_COMPARE_REF_TO_TEXTURE GL_COMPARE_R_TO_TEXTURE_ARB #define GL_CLIP_DISTANCE0 GL_CLIP_PLANE0 #define GL_CLIP_DISTANCE1 GL_CLIP_PLANE1 #define GL_CLIP_DISTANCE2 GL_CLIP_PLANE2 #define GL_CLIP_DISTANCE3 GL_CLIP_PLANE3 #define GL_CLIP_DISTANCE4 GL_CLIP_PLANE4 #define GL_CLIP_DISTANCE5 GL_CLIP_PLANE5 #define GL_MAX_CLIP_DISTANCES GL_MAX_CLIP_PLANES #define GL_MAJOR_VERSION 0x821B #define GL_MINOR_VERSION 0x821C #define GL_NUM_EXTENSIONS 0x821D #define GL_CONTEXT_FLAGS 0x821E #define GL_DEPTH_BUFFER 0x8223 #define GL_STENCIL_BUFFER 0x8224 #define GL_COMPRESSED_RED 0x8225 #define GL_COMPRESSED_RG 0x8226 #define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x0001 #define GL_RGBA32F 0x8814 #define GL_RGB32F 0x8815 #define GL_RGBA16F 0x881A #define GL_RGB16F 0x881B #define GL_VERTEX_ATTRIB_ARRAY_INTEGER 0x88FD #define GL_MAX_ARRAY_TEXTURE_LAYERS 0x88FF #define GL_MIN_PROGRAM_TEXEL_OFFSET 0x8904 #define GL_MAX_PROGRAM_TEXEL_OFFSET 0x8905 #define GL_CLAMP_VERTEX_COLOR 0x891A #define GL_CLAMP_FRAGMENT_COLOR 0x891B #define GL_CLAMP_READ_COLOR 0x891C #define GL_FIXED_ONLY 0x891D #define GL_MAX_VARYING_COMPONENTS GL_MAX_VARYING_FLOATS #define GL_TEXTURE_RED_TYPE 0x8C10 #define GL_TEXTURE_GREEN_TYPE 0x8C11 #define GL_TEXTURE_BLUE_TYPE 0x8C12 #define GL_TEXTURE_ALPHA_TYPE 0x8C13 #define GL_TEXTURE_LUMINANCE_TYPE 0x8C14 #define GL_TEXTURE_INTENSITY_TYPE 0x8C15 #define GL_TEXTURE_DEPTH_TYPE 0x8C16 #define GL_UNSIGNED_NORMALIZED 0x8C17 #define GL_TEXTURE_1D_ARRAY 0x8C18 #define GL_PROXY_TEXTURE_1D_ARRAY 0x8C19 #define GL_TEXTURE_2D_ARRAY 0x8C1A #define GL_PROXY_TEXTURE_2D_ARRAY 0x8C1B #define GL_TEXTURE_BINDING_1D_ARRAY 0x8C1C #define GL_TEXTURE_BINDING_2D_ARRAY 0x8C1D #define GL_R11F_G11F_B10F 0x8C3A #define GL_UNSIGNED_INT_10F_11F_11F_REV 0x8C3B #define GL_RGB9_E5 0x8C3D #define GL_UNSIGNED_INT_5_9_9_9_REV 0x8C3E #define GL_TEXTURE_SHARED_SIZE 0x8C3F #define GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH 0x8C76 #define GL_TRANSFORM_FEEDBACK_BUFFER_MODE 0x8C7F #define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS 0x8C80 #define GL_TRANSFORM_FEEDBACK_VARYINGS 0x8C83 #define GL_TRANSFORM_FEEDBACK_BUFFER_START 0x8C84 #define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE 0x8C85 #define GL_PRIMITIVES_GENERATED 0x8C87 #define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 0x8C88 #define GL_RASTERIZER_DISCARD 0x8C89 #define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS 0x8C8A #define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS 0x8C8B #define GL_INTERLEAVED_ATTRIBS 0x8C8C #define GL_SEPARATE_ATTRIBS 0x8C8D #define GL_TRANSFORM_FEEDBACK_BUFFER 0x8C8E #define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING 0x8C8F #define GL_RGBA32UI 0x8D70 #define GL_RGB32UI 0x8D71 #define GL_RGBA16UI 0x8D76 #define GL_RGB16UI 0x8D77 #define GL_RGBA8UI 0x8D7C #define GL_RGB8UI 0x8D7D #define GL_RGBA32I 0x8D82 #define GL_RGB32I 0x8D83 #define GL_RGBA16I 0x8D88 #define GL_RGB16I 0x8D89 #define GL_RGBA8I 0x8D8E #define GL_RGB8I 0x8D8F #define GL_RED_INTEGER 0x8D94 #define GL_GREEN_INTEGER 0x8D95 #define GL_BLUE_INTEGER 0x8D96 #define GL_ALPHA_INTEGER 0x8D97 #define GL_RGB_INTEGER 0x8D98 #define GL_RGBA_INTEGER 0x8D99 #define GL_BGR_INTEGER 0x8D9A #define GL_BGRA_INTEGER 0x8D9B #define GL_SAMPLER_1D_ARRAY 0x8DC0 #define GL_SAMPLER_2D_ARRAY 0x8DC1 #define GL_SAMPLER_1D_ARRAY_SHADOW 0x8DC3 #define GL_SAMPLER_2D_ARRAY_SHADOW 0x8DC4 #define GL_SAMPLER_CUBE_SHADOW 0x8DC5 #define GL_UNSIGNED_INT_VEC2 0x8DC6 #define GL_UNSIGNED_INT_VEC3 0x8DC7 #define GL_UNSIGNED_INT_VEC4 0x8DC8 #define GL_INT_SAMPLER_1D 0x8DC9 #define GL_INT_SAMPLER_2D 0x8DCA #define GL_INT_SAMPLER_3D 0x8DCB #define GL_INT_SAMPLER_CUBE 0x8DCC #define GL_INT_SAMPLER_1D_ARRAY 0x8DCE #define GL_INT_SAMPLER_2D_ARRAY 0x8DCF #define GL_UNSIGNED_INT_SAMPLER_1D 0x8DD1 #define GL_UNSIGNED_INT_SAMPLER_2D 0x8DD2 #define GL_UNSIGNED_INT_SAMPLER_3D 0x8DD3 #define GL_UNSIGNED_INT_SAMPLER_CUBE 0x8DD4 #define GL_UNSIGNED_INT_SAMPLER_1D_ARRAY 0x8DD6 #define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY 0x8DD7 #define GL_QUERY_WAIT 0x8E13 #define GL_QUERY_NO_WAIT 0x8E14 #define GL_QUERY_BY_REGION_WAIT 0x8E15 #define GL_QUERY_BY_REGION_NO_WAIT 0x8E16 /* Reuse tokens from ARB_depth_buffer_float */ /* reuse GL_DEPTH_COMPONENT32F */ /* reuse GL_DEPTH32F_STENCIL8 */ /* reuse GL_FLOAT_32_UNSIGNED_INT_24_8_REV */ /* Reuse tokens from ARB_framebuffer_object */ /* reuse GL_INVALID_FRAMEBUFFER_OPERATION */ /* reuse GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING */ /* reuse GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE */ /* reuse GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE */ /* reuse GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE */ /* reuse GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE */ /* reuse GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE */ /* reuse GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE */ /* reuse GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE */ /* reuse GL_FRAMEBUFFER_DEFAULT */ /* reuse GL_FRAMEBUFFER_UNDEFINED */ /* reuse GL_DEPTH_STENCIL_ATTACHMENT */ /* reuse GL_INDEX */ /* reuse GL_MAX_RENDERBUFFER_SIZE */ /* reuse GL_DEPTH_STENCIL */ /* reuse GL_UNSIGNED_INT_24_8 */ /* reuse GL_DEPTH24_STENCIL8 */ /* reuse GL_TEXTURE_STENCIL_SIZE */ /* reuse GL_TEXTURE_RED_TYPE */ /* reuse GL_TEXTURE_GREEN_TYPE */ /* reuse GL_TEXTURE_BLUE_TYPE */ /* reuse GL_TEXTURE_ALPHA_TYPE */ /* reuse GL_TEXTURE_LUMINANCE_TYPE */ /* reuse GL_TEXTURE_INTENSITY_TYPE */ /* reuse GL_TEXTURE_DEPTH_TYPE */ /* reuse GL_UNSIGNED_NORMALIZED */ /* reuse GL_FRAMEBUFFER_BINDING */ /* reuse GL_DRAW_FRAMEBUFFER_BINDING */ /* reuse GL_RENDERBUFFER_BINDING */ /* reuse GL_READ_FRAMEBUFFER */ /* reuse GL_DRAW_FRAMEBUFFER */ /* reuse GL_READ_FRAMEBUFFER_BINDING */ /* reuse GL_RENDERBUFFER_SAMPLES */ /* reuse GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE */ /* reuse GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME */ /* reuse GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL */ /* reuse GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE */ /* reuse GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER */ /* reuse GL_FRAMEBUFFER_COMPLETE */ /* reuse GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT */ /* reuse GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT */ /* reuse GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER */ /* reuse GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER */ /* reuse GL_FRAMEBUFFER_UNSUPPORTED */ /* reuse GL_MAX_COLOR_ATTACHMENTS */ /* reuse GL_COLOR_ATTACHMENT0 */ /* reuse GL_COLOR_ATTACHMENT1 */ /* reuse GL_COLOR_ATTACHMENT2 */ /* reuse GL_COLOR_ATTACHMENT3 */ /* reuse GL_COLOR_ATTACHMENT4 */ /* reuse GL_COLOR_ATTACHMENT5 */ /* reuse GL_COLOR_ATTACHMENT6 */ /* reuse GL_COLOR_ATTACHMENT7 */ /* reuse GL_COLOR_ATTACHMENT8 */ /* reuse GL_COLOR_ATTACHMENT9 */ /* reuse GL_COLOR_ATTACHMENT10 */ /* reuse GL_COLOR_ATTACHMENT11 */ /* reuse GL_COLOR_ATTACHMENT12 */ /* reuse GL_COLOR_ATTACHMENT13 */ /* reuse GL_COLOR_ATTACHMENT14 */ /* reuse GL_COLOR_ATTACHMENT15 */ /* reuse GL_DEPTH_ATTACHMENT */ /* reuse GL_STENCIL_ATTACHMENT */ /* reuse GL_FRAMEBUFFER */ /* reuse GL_RENDERBUFFER */ /* reuse GL_RENDERBUFFER_WIDTH */ /* reuse GL_RENDERBUFFER_HEIGHT */ /* reuse GL_RENDERBUFFER_INTERNAL_FORMAT */ /* reuse GL_STENCIL_INDEX1 */ /* reuse GL_STENCIL_INDEX4 */ /* reuse GL_STENCIL_INDEX8 */ /* reuse GL_STENCIL_INDEX16 */ /* reuse GL_RENDERBUFFER_RED_SIZE */ /* reuse GL_RENDERBUFFER_GREEN_SIZE */ /* reuse GL_RENDERBUFFER_BLUE_SIZE */ /* reuse GL_RENDERBUFFER_ALPHA_SIZE */ /* reuse GL_RENDERBUFFER_DEPTH_SIZE */ /* reuse GL_RENDERBUFFER_STENCIL_SIZE */ /* reuse GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE */ /* reuse GL_MAX_SAMPLES */ /* Reuse tokens from ARB_framebuffer_sRGB */ /* reuse GL_FRAMEBUFFER_SRGB */ /* Reuse tokens from ARB_half_float_vertex */ /* reuse GL_HALF_FLOAT */ /* Reuse tokens from ARB_map_buffer_range */ /* reuse GL_MAP_READ_BIT */ /* reuse GL_MAP_WRITE_BIT */ /* reuse GL_MAP_INVALIDATE_RANGE_BIT */ /* reuse GL_MAP_INVALIDATE_BUFFER_BIT */ /* reuse GL_MAP_FLUSH_EXPLICIT_BIT */ /* reuse GL_MAP_UNSYNCHRONIZED_BIT */ /* Reuse tokens from ARB_texture_compression_rgtc */ /* reuse GL_COMPRESSED_RED_RGTC1 */ /* reuse GL_COMPRESSED_SIGNED_RED_RGTC1 */ /* reuse GL_COMPRESSED_RG_RGTC2 */ /* reuse GL_COMPRESSED_SIGNED_RG_RGTC2 */ /* Reuse tokens from ARB_texture_rg */ /* reuse GL_RG */ /* reuse GL_RG_INTEGER */ /* reuse GL_R8 */ /* reuse GL_R16 */ /* reuse GL_RG8 */ /* reuse GL_RG16 */ /* reuse GL_R16F */ /* reuse GL_R32F */ /* reuse GL_RG16F */ /* reuse GL_RG32F */ /* reuse GL_R8I */ /* reuse GL_R8UI */ /* reuse GL_R16I */ /* reuse GL_R16UI */ /* reuse GL_R32I */ /* reuse GL_R32UI */ /* reuse GL_RG8I */ /* reuse GL_RG8UI */ /* reuse GL_RG16I */ /* reuse GL_RG16UI */ /* reuse GL_RG32I */ /* reuse GL_RG32UI */ /* Reuse tokens from ARB_vertex_array_object */ /* reuse GL_VERTEX_ARRAY_BINDING */ #endif #ifndef GL_ARB_multitexture #define GL_TEXTURE0_ARB 0x84C0 #define GL_TEXTURE1_ARB 0x84C1 #define GL_TEXTURE2_ARB 0x84C2 #define GL_TEXTURE3_ARB 0x84C3 #define GL_TEXTURE4_ARB 0x84C4 #define GL_TEXTURE5_ARB 0x84C5 #define GL_TEXTURE6_ARB 0x84C6 #define GL_TEXTURE7_ARB 0x84C7 #define GL_TEXTURE8_ARB 0x84C8 #define GL_TEXTURE9_ARB 0x84C9 #define GL_TEXTURE10_ARB 0x84CA #define GL_TEXTURE11_ARB 0x84CB #define GL_TEXTURE12_ARB 0x84CC #define GL_TEXTURE13_ARB 0x84CD #define GL_TEXTURE14_ARB 0x84CE #define GL_TEXTURE15_ARB 0x84CF #define GL_TEXTURE16_ARB 0x84D0 #define GL_TEXTURE17_ARB 0x84D1 #define GL_TEXTURE18_ARB 0x84D2 #define GL_TEXTURE19_ARB 0x84D3 #define GL_TEXTURE20_ARB 0x84D4 #define GL_TEXTURE21_ARB 0x84D5 #define GL_TEXTURE22_ARB 0x84D6 #define GL_TEXTURE23_ARB 0x84D7 #define GL_TEXTURE24_ARB 0x84D8 #define GL_TEXTURE25_ARB 0x84D9 #define GL_TEXTURE26_ARB 0x84DA #define GL_TEXTURE27_ARB 0x84DB #define GL_TEXTURE28_ARB 0x84DC #define GL_TEXTURE29_ARB 0x84DD #define GL_TEXTURE30_ARB 0x84DE #define GL_TEXTURE31_ARB 0x84DF #define GL_ACTIVE_TEXTURE_ARB 0x84E0 #define GL_CLIENT_ACTIVE_TEXTURE_ARB 0x84E1 #define GL_MAX_TEXTURE_UNITS_ARB 0x84E2 #endif #ifndef GL_ARB_transpose_matrix #define GL_TRANSPOSE_MODELVIEW_MATRIX_ARB 0x84E3 #define GL_TRANSPOSE_PROJECTION_MATRIX_ARB 0x84E4 #define GL_TRANSPOSE_TEXTURE_MATRIX_ARB 0x84E5 #define GL_TRANSPOSE_COLOR_MATRIX_ARB 0x84E6 #endif #ifndef GL_ARB_multisample #define GL_MULTISAMPLE_ARB 0x809D #define GL_SAMPLE_ALPHA_TO_COVERAGE_ARB 0x809E #define GL_SAMPLE_ALPHA_TO_ONE_ARB 0x809F #define GL_SAMPLE_COVERAGE_ARB 0x80A0 #define GL_SAMPLE_BUFFERS_ARB 0x80A8 #define GL_SAMPLES_ARB 0x80A9 #define GL_SAMPLE_COVERAGE_VALUE_ARB 0x80AA #define GL_SAMPLE_COVERAGE_INVERT_ARB 0x80AB #define GL_MULTISAMPLE_BIT_ARB 0x20000000 #endif #ifndef GL_ARB_texture_env_add #endif #ifndef GL_ARB_texture_cube_map #define GL_NORMAL_MAP_ARB 0x8511 #define GL_REFLECTION_MAP_ARB 0x8512 #define GL_TEXTURE_CUBE_MAP_ARB 0x8513 #define GL_TEXTURE_BINDING_CUBE_MAP_ARB 0x8514 #define GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB 0x8515 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB 0x8516 #define GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB 0x8517 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB 0x8518 #define GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB 0x8519 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB 0x851A #define GL_PROXY_TEXTURE_CUBE_MAP_ARB 0x851B #define GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB 0x851C #endif #ifndef GL_ARB_texture_compression #define GL_COMPRESSED_ALPHA_ARB 0x84E9 #define GL_COMPRESSED_LUMINANCE_ARB 0x84EA #define GL_COMPRESSED_LUMINANCE_ALPHA_ARB 0x84EB #define GL_COMPRESSED_INTENSITY_ARB 0x84EC #define GL_COMPRESSED_RGB_ARB 0x84ED #define GL_COMPRESSED_RGBA_ARB 0x84EE #define GL_TEXTURE_COMPRESSION_HINT_ARB 0x84EF #define GL_TEXTURE_COMPRESSED_IMAGE_SIZE_ARB 0x86A0 #define GL_TEXTURE_COMPRESSED_ARB 0x86A1 #define GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A2 #define GL_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A3 #endif #ifndef GL_ARB_texture_border_clamp #define GL_CLAMP_TO_BORDER_ARB 0x812D #endif #ifndef GL_ARB_point_parameters #define GL_POINT_SIZE_MIN_ARB 0x8126 #define GL_POINT_SIZE_MAX_ARB 0x8127 #define GL_POINT_FADE_THRESHOLD_SIZE_ARB 0x8128 #define GL_POINT_DISTANCE_ATTENUATION_ARB 0x8129 #endif #ifndef GL_ARB_vertex_blend #define GL_MAX_VERTEX_UNITS_ARB 0x86A4 #define GL_ACTIVE_VERTEX_UNITS_ARB 0x86A5 #define GL_WEIGHT_SUM_UNITY_ARB 0x86A6 #define GL_VERTEX_BLEND_ARB 0x86A7 #define GL_CURRENT_WEIGHT_ARB 0x86A8 #define GL_WEIGHT_ARRAY_TYPE_ARB 0x86A9 #define GL_WEIGHT_ARRAY_STRIDE_ARB 0x86AA #define GL_WEIGHT_ARRAY_SIZE_ARB 0x86AB #define GL_WEIGHT_ARRAY_POINTER_ARB 0x86AC #define GL_WEIGHT_ARRAY_ARB 0x86AD #define GL_MODELVIEW0_ARB 0x1700 #define GL_MODELVIEW1_ARB 0x850A #define GL_MODELVIEW2_ARB 0x8722 #define GL_MODELVIEW3_ARB 0x8723 #define GL_MODELVIEW4_ARB 0x8724 #define GL_MODELVIEW5_ARB 0x8725 #define GL_MODELVIEW6_ARB 0x8726 #define GL_MODELVIEW7_ARB 0x8727 #define GL_MODELVIEW8_ARB 0x8728 #define GL_MODELVIEW9_ARB 0x8729 #define GL_MODELVIEW10_ARB 0x872A #define GL_MODELVIEW11_ARB 0x872B #define GL_MODELVIEW12_ARB 0x872C #define GL_MODELVIEW13_ARB 0x872D #define GL_MODELVIEW14_ARB 0x872E #define GL_MODELVIEW15_ARB 0x872F #define GL_MODELVIEW16_ARB 0x8730 #define GL_MODELVIEW17_ARB 0x8731 #define GL_MODELVIEW18_ARB 0x8732 #define GL_MODELVIEW19_ARB 0x8733 #define GL_MODELVIEW20_ARB 0x8734 #define GL_MODELVIEW21_ARB 0x8735 #define GL_MODELVIEW22_ARB 0x8736 #define GL_MODELVIEW23_ARB 0x8737 #define GL_MODELVIEW24_ARB 0x8738 #define GL_MODELVIEW25_ARB 0x8739 #define GL_MODELVIEW26_ARB 0x873A #define GL_MODELVIEW27_ARB 0x873B #define GL_MODELVIEW28_ARB 0x873C #define GL_MODELVIEW29_ARB 0x873D #define GL_MODELVIEW30_ARB 0x873E #define GL_MODELVIEW31_ARB 0x873F #endif #ifndef GL_ARB_matrix_palette #define GL_MATRIX_PALETTE_ARB 0x8840 #define GL_MAX_MATRIX_PALETTE_STACK_DEPTH_ARB 0x8841 #define GL_MAX_PALETTE_MATRICES_ARB 0x8842 #define GL_CURRENT_PALETTE_MATRIX_ARB 0x8843 #define GL_MATRIX_INDEX_ARRAY_ARB 0x8844 #define GL_CURRENT_MATRIX_INDEX_ARB 0x8845 #define GL_MATRIX_INDEX_ARRAY_SIZE_ARB 0x8846 #define GL_MATRIX_INDEX_ARRAY_TYPE_ARB 0x8847 #define GL_MATRIX_INDEX_ARRAY_STRIDE_ARB 0x8848 #define GL_MATRIX_INDEX_ARRAY_POINTER_ARB 0x8849 #endif #ifndef GL_ARB_texture_env_combine #define GL_COMBINE_ARB 0x8570 #define GL_COMBINE_RGB_ARB 0x8571 #define GL_COMBINE_ALPHA_ARB 0x8572 #define GL_SOURCE0_RGB_ARB 0x8580 #define GL_SOURCE1_RGB_ARB 0x8581 #define GL_SOURCE2_RGB_ARB 0x8582 #define GL_SOURCE0_ALPHA_ARB 0x8588 #define GL_SOURCE1_ALPHA_ARB 0x8589 #define GL_SOURCE2_ALPHA_ARB 0x858A #define GL_OPERAND0_RGB_ARB 0x8590 #define GL_OPERAND1_RGB_ARB 0x8591 #define GL_OPERAND2_RGB_ARB 0x8592 #define GL_OPERAND0_ALPHA_ARB 0x8598 #define GL_OPERAND1_ALPHA_ARB 0x8599 #define GL_OPERAND2_ALPHA_ARB 0x859A #define GL_RGB_SCALE_ARB 0x8573 #define GL_ADD_SIGNED_ARB 0x8574 #define GL_INTERPOLATE_ARB 0x8575 #define GL_SUBTRACT_ARB 0x84E7 #define GL_CONSTANT_ARB 0x8576 #define GL_PRIMARY_COLOR_ARB 0x8577 #define GL_PREVIOUS_ARB 0x8578 #endif #ifndef GL_ARB_texture_env_crossbar #endif #ifndef GL_ARB_texture_env_dot3 #define GL_DOT3_RGB_ARB 0x86AE #define GL_DOT3_RGBA_ARB 0x86AF #endif #ifndef GL_ARB_texture_mirrored_repeat #define GL_MIRRORED_REPEAT_ARB 0x8370 #endif #ifndef GL_ARB_depth_texture #define GL_DEPTH_COMPONENT16_ARB 0x81A5 #define GL_DEPTH_COMPONENT24_ARB 0x81A6 #define GL_DEPTH_COMPONENT32_ARB 0x81A7 #define GL_TEXTURE_DEPTH_SIZE_ARB 0x884A #define GL_DEPTH_TEXTURE_MODE_ARB 0x884B #endif #ifndef GL_ARB_shadow #define GL_TEXTURE_COMPARE_MODE_ARB 0x884C #define GL_TEXTURE_COMPARE_FUNC_ARB 0x884D #define GL_COMPARE_R_TO_TEXTURE_ARB 0x884E #endif #ifndef GL_ARB_shadow_ambient #define GL_TEXTURE_COMPARE_FAIL_VALUE_ARB 0x80BF #endif #ifndef GL_ARB_window_pos #endif #ifndef GL_ARB_vertex_program #define GL_COLOR_SUM_ARB 0x8458 #define GL_VERTEX_PROGRAM_ARB 0x8620 #define GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB 0x8622 #define GL_VERTEX_ATTRIB_ARRAY_SIZE_ARB 0x8623 #define GL_VERTEX_ATTRIB_ARRAY_STRIDE_ARB 0x8624 #define GL_VERTEX_ATTRIB_ARRAY_TYPE_ARB 0x8625 #define GL_CURRENT_VERTEX_ATTRIB_ARB 0x8626 #define GL_PROGRAM_LENGTH_ARB 0x8627 #define GL_PROGRAM_STRING_ARB 0x8628 #define GL_MAX_PROGRAM_MATRIX_STACK_DEPTH_ARB 0x862E #define GL_MAX_PROGRAM_MATRICES_ARB 0x862F #define GL_CURRENT_MATRIX_STACK_DEPTH_ARB 0x8640 #define GL_CURRENT_MATRIX_ARB 0x8641 #define GL_VERTEX_PROGRAM_POINT_SIZE_ARB 0x8642 #define GL_VERTEX_PROGRAM_TWO_SIDE_ARB 0x8643 #define GL_VERTEX_ATTRIB_ARRAY_POINTER_ARB 0x8645 #define GL_PROGRAM_ERROR_POSITION_ARB 0x864B #define GL_PROGRAM_BINDING_ARB 0x8677 #define GL_MAX_VERTEX_ATTRIBS_ARB 0x8869 #define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED_ARB 0x886A #define GL_PROGRAM_ERROR_STRING_ARB 0x8874 #define GL_PROGRAM_FORMAT_ASCII_ARB 0x8875 #define GL_PROGRAM_FORMAT_ARB 0x8876 #define GL_PROGRAM_INSTRUCTIONS_ARB 0x88A0 #define GL_MAX_PROGRAM_INSTRUCTIONS_ARB 0x88A1 #define GL_PROGRAM_NATIVE_INSTRUCTIONS_ARB 0x88A2 #define GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB 0x88A3 #define GL_PROGRAM_TEMPORARIES_ARB 0x88A4 #define GL_MAX_PROGRAM_TEMPORARIES_ARB 0x88A5 #define GL_PROGRAM_NATIVE_TEMPORARIES_ARB 0x88A6 #define GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB 0x88A7 #define GL_PROGRAM_PARAMETERS_ARB 0x88A8 #define GL_MAX_PROGRAM_PARAMETERS_ARB 0x88A9 #define GL_PROGRAM_NATIVE_PARAMETERS_ARB 0x88AA #define GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB 0x88AB #define GL_PROGRAM_ATTRIBS_ARB 0x88AC #define GL_MAX_PROGRAM_ATTRIBS_ARB 0x88AD #define GL_PROGRAM_NATIVE_ATTRIBS_ARB 0x88AE #define GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB 0x88AF #define GL_PROGRAM_ADDRESS_REGISTERS_ARB 0x88B0 #define GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB 0x88B1 #define GL_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB 0x88B2 #define GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB 0x88B3 #define GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB 0x88B4 #define GL_MAX_PROGRAM_ENV_PARAMETERS_ARB 0x88B5 #define GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB 0x88B6 #define GL_TRANSPOSE_CURRENT_MATRIX_ARB 0x88B7 #define GL_MATRIX0_ARB 0x88C0 #define GL_MATRIX1_ARB 0x88C1 #define GL_MATRIX2_ARB 0x88C2 #define GL_MATRIX3_ARB 0x88C3 #define GL_MATRIX4_ARB 0x88C4 #define GL_MATRIX5_ARB 0x88C5 #define GL_MATRIX6_ARB 0x88C6 #define GL_MATRIX7_ARB 0x88C7 #define GL_MATRIX8_ARB 0x88C8 #define GL_MATRIX9_ARB 0x88C9 #define GL_MATRIX10_ARB 0x88CA #define GL_MATRIX11_ARB 0x88CB #define GL_MATRIX12_ARB 0x88CC #define GL_MATRIX13_ARB 0x88CD #define GL_MATRIX14_ARB 0x88CE #define GL_MATRIX15_ARB 0x88CF #define GL_MATRIX16_ARB 0x88D0 #define GL_MATRIX17_ARB 0x88D1 #define GL_MATRIX18_ARB 0x88D2 #define GL_MATRIX19_ARB 0x88D3 #define GL_MATRIX20_ARB 0x88D4 #define GL_MATRIX21_ARB 0x88D5 #define GL_MATRIX22_ARB 0x88D6 #define GL_MATRIX23_ARB 0x88D7 #define GL_MATRIX24_ARB 0x88D8 #define GL_MATRIX25_ARB 0x88D9 #define GL_MATRIX26_ARB 0x88DA #define GL_MATRIX27_ARB 0x88DB #define GL_MATRIX28_ARB 0x88DC #define GL_MATRIX29_ARB 0x88DD #define GL_MATRIX30_ARB 0x88DE #define GL_MATRIX31_ARB 0x88DF #endif #ifndef GL_ARB_fragment_program #define GL_FRAGMENT_PROGRAM_ARB 0x8804 #define GL_PROGRAM_ALU_INSTRUCTIONS_ARB 0x8805 #define GL_PROGRAM_TEX_INSTRUCTIONS_ARB 0x8806 #define GL_PROGRAM_TEX_INDIRECTIONS_ARB 0x8807 #define GL_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB 0x8808 #define GL_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB 0x8809 #define GL_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB 0x880A #define GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB 0x880B #define GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB 0x880C #define GL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB 0x880D #define GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB 0x880E #define GL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB 0x880F #define GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB 0x8810 #define GL_MAX_TEXTURE_COORDS_ARB 0x8871 #define GL_MAX_TEXTURE_IMAGE_UNITS_ARB 0x8872 #endif #ifndef GL_ARB_vertex_buffer_object #define GL_BUFFER_SIZE_ARB 0x8764 #define GL_BUFFER_USAGE_ARB 0x8765 #define GL_ARRAY_BUFFER_ARB 0x8892 #define GL_ELEMENT_ARRAY_BUFFER_ARB 0x8893 #define GL_ARRAY_BUFFER_BINDING_ARB 0x8894 #define GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB 0x8895 #define GL_VERTEX_ARRAY_BUFFER_BINDING_ARB 0x8896 #define GL_NORMAL_ARRAY_BUFFER_BINDING_ARB 0x8897 #define GL_COLOR_ARRAY_BUFFER_BINDING_ARB 0x8898 #define GL_INDEX_ARRAY_BUFFER_BINDING_ARB 0x8899 #define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB 0x889A #define GL_EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB 0x889B #define GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB 0x889C #define GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB 0x889D #define GL_WEIGHT_ARRAY_BUFFER_BINDING_ARB 0x889E #define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB 0x889F #define GL_READ_ONLY_ARB 0x88B8 #define GL_WRITE_ONLY_ARB 0x88B9 #define GL_READ_WRITE_ARB 0x88BA #define GL_BUFFER_ACCESS_ARB 0x88BB #define GL_BUFFER_MAPPED_ARB 0x88BC #define GL_BUFFER_MAP_POINTER_ARB 0x88BD #define GL_STREAM_DRAW_ARB 0x88E0 #define GL_STREAM_READ_ARB 0x88E1 #define GL_STREAM_COPY_ARB 0x88E2 #define GL_STATIC_DRAW_ARB 0x88E4 #define GL_STATIC_READ_ARB 0x88E5 #define GL_STATIC_COPY_ARB 0x88E6 #define GL_DYNAMIC_DRAW_ARB 0x88E8 #define GL_DYNAMIC_READ_ARB 0x88E9 #define GL_DYNAMIC_COPY_ARB 0x88EA #endif #ifndef GL_ARB_occlusion_query #define GL_QUERY_COUNTER_BITS_ARB 0x8864 #define GL_CURRENT_QUERY_ARB 0x8865 #define GL_QUERY_RESULT_ARB 0x8866 #define GL_QUERY_RESULT_AVAILABLE_ARB 0x8867 #define GL_SAMPLES_PASSED_ARB 0x8914 #endif #ifndef GL_ARB_shader_objects #define GL_PROGRAM_OBJECT_ARB 0x8B40 #define GL_SHADER_OBJECT_ARB 0x8B48 #define GL_OBJECT_TYPE_ARB 0x8B4E #define GL_OBJECT_SUBTYPE_ARB 0x8B4F #define GL_FLOAT_VEC2_ARB 0x8B50 #define GL_FLOAT_VEC3_ARB 0x8B51 #define GL_FLOAT_VEC4_ARB 0x8B52 #define GL_INT_VEC2_ARB 0x8B53 #define GL_INT_VEC3_ARB 0x8B54 #define GL_INT_VEC4_ARB 0x8B55 #define GL_BOOL_ARB 0x8B56 #define GL_BOOL_VEC2_ARB 0x8B57 #define GL_BOOL_VEC3_ARB 0x8B58 #define GL_BOOL_VEC4_ARB 0x8B59 #define GL_FLOAT_MAT2_ARB 0x8B5A #define GL_FLOAT_MAT3_ARB 0x8B5B #define GL_FLOAT_MAT4_ARB 0x8B5C #define GL_SAMPLER_1D_ARB 0x8B5D #define GL_SAMPLER_2D_ARB 0x8B5E #define GL_SAMPLER_3D_ARB 0x8B5F #define GL_SAMPLER_CUBE_ARB 0x8B60 #define GL_SAMPLER_1D_SHADOW_ARB 0x8B61 #define GL_SAMPLER_2D_SHADOW_ARB 0x8B62 #define GL_SAMPLER_2D_RECT_ARB 0x8B63 #define GL_SAMPLER_2D_RECT_SHADOW_ARB 0x8B64 #define GL_OBJECT_DELETE_STATUS_ARB 0x8B80 #define GL_OBJECT_COMPILE_STATUS_ARB 0x8B81 #define GL_OBJECT_LINK_STATUS_ARB 0x8B82 #define GL_OBJECT_VALIDATE_STATUS_ARB 0x8B83 #define GL_OBJECT_INFO_LOG_LENGTH_ARB 0x8B84 #define GL_OBJECT_ATTACHED_OBJECTS_ARB 0x8B85 #define GL_OBJECT_ACTIVE_UNIFORMS_ARB 0x8B86 #define GL_OBJECT_ACTIVE_UNIFORM_MAX_LENGTH_ARB 0x8B87 #define GL_OBJECT_SHADER_SOURCE_LENGTH_ARB 0x8B88 #endif #ifndef GL_ARB_vertex_shader #define GL_VERTEX_SHADER_ARB 0x8B31 #define GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB 0x8B4A #define GL_MAX_VARYING_FLOATS_ARB 0x8B4B #define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB 0x8B4C #define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB 0x8B4D #define GL_OBJECT_ACTIVE_ATTRIBUTES_ARB 0x8B89 #define GL_OBJECT_ACTIVE_ATTRIBUTE_MAX_LENGTH_ARB 0x8B8A #endif #ifndef GL_ARB_fragment_shader #define GL_FRAGMENT_SHADER_ARB 0x8B30 #define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB 0x8B49 #define GL_FRAGMENT_SHADER_DERIVATIVE_HINT_ARB 0x8B8B #endif #ifndef GL_ARB_shading_language_100 #define GL_SHADING_LANGUAGE_VERSION_ARB 0x8B8C #endif #ifndef GL_ARB_texture_non_power_of_two #endif #ifndef GL_ARB_point_sprite #define GL_POINT_SPRITE_ARB 0x8861 #define GL_COORD_REPLACE_ARB 0x8862 #endif #ifndef GL_ARB_fragment_program_shadow #endif #ifndef GL_ARB_draw_buffers #define GL_MAX_DRAW_BUFFERS_ARB 0x8824 #define GL_DRAW_BUFFER0_ARB 0x8825 #define GL_DRAW_BUFFER1_ARB 0x8826 #define GL_DRAW_BUFFER2_ARB 0x8827 #define GL_DRAW_BUFFER3_ARB 0x8828 #define GL_DRAW_BUFFER4_ARB 0x8829 #define GL_DRAW_BUFFER5_ARB 0x882A #define GL_DRAW_BUFFER6_ARB 0x882B #define GL_DRAW_BUFFER7_ARB 0x882C #define GL_DRAW_BUFFER8_ARB 0x882D #define GL_DRAW_BUFFER9_ARB 0x882E #define GL_DRAW_BUFFER10_ARB 0x882F #define GL_DRAW_BUFFER11_ARB 0x8830 #define GL_DRAW_BUFFER12_ARB 0x8831 #define GL_DRAW_BUFFER13_ARB 0x8832 #define GL_DRAW_BUFFER14_ARB 0x8833 #define GL_DRAW_BUFFER15_ARB 0x8834 #endif #ifndef GL_ARB_texture_rectangle #define GL_TEXTURE_RECTANGLE_ARB 0x84F5 #define GL_TEXTURE_BINDING_RECTANGLE_ARB 0x84F6 #define GL_PROXY_TEXTURE_RECTANGLE_ARB 0x84F7 #define GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB 0x84F8 #endif #ifndef GL_ARB_color_buffer_float #define GL_RGBA_FLOAT_MODE_ARB 0x8820 #define GL_CLAMP_VERTEX_COLOR_ARB 0x891A #define GL_CLAMP_FRAGMENT_COLOR_ARB 0x891B #define GL_CLAMP_READ_COLOR_ARB 0x891C #define GL_FIXED_ONLY_ARB 0x891D #endif #ifndef GL_ARB_half_float_pixel #define GL_HALF_FLOAT_ARB 0x140B #endif #ifndef GL_ARB_texture_float #define GL_TEXTURE_RED_TYPE_ARB 0x8C10 #define GL_TEXTURE_GREEN_TYPE_ARB 0x8C11 #define GL_TEXTURE_BLUE_TYPE_ARB 0x8C12 #define GL_TEXTURE_ALPHA_TYPE_ARB 0x8C13 #define GL_TEXTURE_LUMINANCE_TYPE_ARB 0x8C14 #define GL_TEXTURE_INTENSITY_TYPE_ARB 0x8C15 #define GL_TEXTURE_DEPTH_TYPE_ARB 0x8C16 #define GL_UNSIGNED_NORMALIZED_ARB 0x8C17 #define GL_RGBA32F_ARB 0x8814 #define GL_RGB32F_ARB 0x8815 #define GL_ALPHA32F_ARB 0x8816 #define GL_INTENSITY32F_ARB 0x8817 #define GL_LUMINANCE32F_ARB 0x8818 #define GL_LUMINANCE_ALPHA32F_ARB 0x8819 #define GL_RGBA16F_ARB 0x881A #define GL_RGB16F_ARB 0x881B #define GL_ALPHA16F_ARB 0x881C #define GL_INTENSITY16F_ARB 0x881D #define GL_LUMINANCE16F_ARB 0x881E #define GL_LUMINANCE_ALPHA16F_ARB 0x881F #endif #ifndef GL_ARB_pixel_buffer_object #define GL_PIXEL_PACK_BUFFER_ARB 0x88EB #define GL_PIXEL_UNPACK_BUFFER_ARB 0x88EC #define GL_PIXEL_PACK_BUFFER_BINDING_ARB 0x88ED #define GL_PIXEL_UNPACK_BUFFER_BINDING_ARB 0x88EF #endif #ifndef GL_ARB_depth_buffer_float #define GL_DEPTH_COMPONENT32F 0x8CAC #define GL_DEPTH32F_STENCIL8 0x8CAD #define GL_FLOAT_32_UNSIGNED_INT_24_8_REV 0x8DAD #endif #ifndef GL_ARB_draw_instanced #endif #ifndef GL_ARB_framebuffer_object #define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506 #define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING 0x8210 #define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE 0x8211 #define GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE 0x8212 #define GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE 0x8213 #define GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE 0x8214 #define GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE 0x8215 #define GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE 0x8216 #define GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE 0x8217 #define GL_FRAMEBUFFER_DEFAULT 0x8218 #define GL_FRAMEBUFFER_UNDEFINED 0x8219 #define GL_DEPTH_STENCIL_ATTACHMENT 0x821A #define GL_INDEX 0x8222 #define GL_MAX_RENDERBUFFER_SIZE 0x84E8 #define GL_DEPTH_STENCIL 0x84F9 #define GL_UNSIGNED_INT_24_8 0x84FA #define GL_DEPTH24_STENCIL8 0x88F0 #define GL_TEXTURE_STENCIL_SIZE 0x88F1 #define GL_FRAMEBUFFER_BINDING 0x8CA6 #define GL_DRAW_FRAMEBUFFER_BINDING GL_FRAMEBUFFER_BINDING #define GL_RENDERBUFFER_BINDING 0x8CA7 #define GL_READ_FRAMEBUFFER 0x8CA8 #define GL_DRAW_FRAMEBUFFER 0x8CA9 #define GL_READ_FRAMEBUFFER_BINDING 0x8CAA #define GL_RENDERBUFFER_SAMPLES 0x8CAB #define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0 #define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER 0x8CD4 #define GL_FRAMEBUFFER_COMPLETE 0x8CD5 #define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6 #define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7 #define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER 0x8CDB #define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER 0x8CDC #define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD #define GL_MAX_COLOR_ATTACHMENTS 0x8CDF #define GL_COLOR_ATTACHMENT0 0x8CE0 #define GL_COLOR_ATTACHMENT1 0x8CE1 #define GL_COLOR_ATTACHMENT2 0x8CE2 #define GL_COLOR_ATTACHMENT3 0x8CE3 #define GL_COLOR_ATTACHMENT4 0x8CE4 #define GL_COLOR_ATTACHMENT5 0x8CE5 #define GL_COLOR_ATTACHMENT6 0x8CE6 #define GL_COLOR_ATTACHMENT7 0x8CE7 #define GL_COLOR_ATTACHMENT8 0x8CE8 #define GL_COLOR_ATTACHMENT9 0x8CE9 #define GL_COLOR_ATTACHMENT10 0x8CEA #define GL_COLOR_ATTACHMENT11 0x8CEB #define GL_COLOR_ATTACHMENT12 0x8CEC #define GL_COLOR_ATTACHMENT13 0x8CED #define GL_COLOR_ATTACHMENT14 0x8CEE #define GL_COLOR_ATTACHMENT15 0x8CEF #define GL_DEPTH_ATTACHMENT 0x8D00 #define GL_STENCIL_ATTACHMENT 0x8D20 #define GL_FRAMEBUFFER 0x8D40 #define GL_RENDERBUFFER 0x8D41 #define GL_RENDERBUFFER_WIDTH 0x8D42 #define GL_RENDERBUFFER_HEIGHT 0x8D43 #define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44 #define GL_STENCIL_INDEX1 0x8D46 #define GL_STENCIL_INDEX4 0x8D47 #define GL_STENCIL_INDEX8 0x8D48 #define GL_STENCIL_INDEX16 0x8D49 #define GL_RENDERBUFFER_RED_SIZE 0x8D50 #define GL_RENDERBUFFER_GREEN_SIZE 0x8D51 #define GL_RENDERBUFFER_BLUE_SIZE 0x8D52 #define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53 #define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54 #define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55 #define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE 0x8D56 #define GL_MAX_SAMPLES 0x8D57 #endif #ifndef GL_ARB_framebuffer_sRGB #define GL_FRAMEBUFFER_SRGB 0x8DB9 #endif #ifndef GL_ARB_geometry_shader4 #define GL_LINES_ADJACENCY_ARB 0x000A #define GL_LINE_STRIP_ADJACENCY_ARB 0x000B #define GL_TRIANGLES_ADJACENCY_ARB 0x000C #define GL_TRIANGLE_STRIP_ADJACENCY_ARB 0x000D #define GL_PROGRAM_POINT_SIZE_ARB 0x8642 #define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_ARB 0x8C29 #define GL_FRAMEBUFFER_ATTACHMENT_LAYERED_ARB 0x8DA7 #define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_ARB 0x8DA8 #define GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_ARB 0x8DA9 #define GL_GEOMETRY_SHADER_ARB 0x8DD9 #define GL_GEOMETRY_VERTICES_OUT_ARB 0x8DDA #define GL_GEOMETRY_INPUT_TYPE_ARB 0x8DDB #define GL_GEOMETRY_OUTPUT_TYPE_ARB 0x8DDC #define GL_MAX_GEOMETRY_VARYING_COMPONENTS_ARB 0x8DDD #define GL_MAX_VERTEX_VARYING_COMPONENTS_ARB 0x8DDE #define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_ARB 0x8DDF #define GL_MAX_GEOMETRY_OUTPUT_VERTICES_ARB 0x8DE0 #define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_ARB 0x8DE1 /* reuse GL_MAX_VARYING_COMPONENTS */ /* reuse GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER */ #endif #ifndef GL_ARB_half_float_vertex #define GL_HALF_FLOAT 0x140B #endif #ifndef GL_ARB_instanced_arrays #endif #ifndef GL_ARB_map_buffer_range #define GL_MAP_READ_BIT 0x0001 #define GL_MAP_WRITE_BIT 0x0002 #define GL_MAP_INVALIDATE_RANGE_BIT 0x0004 #define GL_MAP_INVALIDATE_BUFFER_BIT 0x0008 #define GL_MAP_FLUSH_EXPLICIT_BIT 0x0010 #define GL_MAP_UNSYNCHRONIZED_BIT 0x0020 #endif #ifndef GL_ARB_texture_buffer_object #define GL_TEXTURE_BUFFER_ARB 0x8C2A #define GL_MAX_TEXTURE_BUFFER_SIZE_ARB 0x8C2B #define GL_TEXTURE_BINDING_BUFFER_ARB 0x8C2C #define GL_TEXTURE_BUFFER_DATA_STORE_BINDING_ARB 0x8C2D #define GL_TEXTURE_BUFFER_FORMAT_ARB 0x8C2E #endif #ifndef GL_ARB_texture_compression_rgtc #define GL_COMPRESSED_RED_RGTC1 0x8DBB #define GL_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC #define GL_COMPRESSED_RG_RGTC2 0x8DBD #define GL_COMPRESSED_SIGNED_RG_RGTC2 0x8DBE #endif #ifndef GL_ARB_texture_rg #define GL_RG 0x8227 #define GL_RG_INTEGER 0x8228 #define GL_R8 0x8229 #define GL_R16 0x822A #define GL_RG8 0x822B #define GL_RG16 0x822C #define GL_R16F 0x822D #define GL_R32F 0x822E #define GL_RG16F 0x822F #define GL_RG32F 0x8230 #define GL_R8I 0x8231 #define GL_R8UI 0x8232 #define GL_R16I 0x8233 #define GL_R16UI 0x8234 #define GL_R32I 0x8235 #define GL_R32UI 0x8236 #define GL_RG8I 0x8237 #define GL_RG8UI 0x8238 #define GL_RG16I 0x8239 #define GL_RG16UI 0x823A #define GL_RG32I 0x823B #define GL_RG32UI 0x823C #endif #ifndef GL_ARB_vertex_array_object #define GL_VERTEX_ARRAY_BINDING 0x85B5 #endif #ifndef GL_EXT_abgr #define GL_ABGR_EXT 0x8000 #endif #ifndef GL_EXT_blend_color #define GL_CONSTANT_COLOR_EXT 0x8001 #define GL_ONE_MINUS_CONSTANT_COLOR_EXT 0x8002 #define GL_CONSTANT_ALPHA_EXT 0x8003 #define GL_ONE_MINUS_CONSTANT_ALPHA_EXT 0x8004 #define GL_BLEND_COLOR_EXT 0x8005 #endif #ifndef GL_EXT_polygon_offset #define GL_POLYGON_OFFSET_EXT 0x8037 #define GL_POLYGON_OFFSET_FACTOR_EXT 0x8038 #define GL_POLYGON_OFFSET_BIAS_EXT 0x8039 #endif #ifndef GL_EXT_texture #define GL_ALPHA4_EXT 0x803B #define GL_ALPHA8_EXT 0x803C #define GL_ALPHA12_EXT 0x803D #define GL_ALPHA16_EXT 0x803E #define GL_LUMINANCE4_EXT 0x803F #define GL_LUMINANCE8_EXT 0x8040 #define GL_LUMINANCE12_EXT 0x8041 #define GL_LUMINANCE16_EXT 0x8042 #define GL_LUMINANCE4_ALPHA4_EXT 0x8043 #define GL_LUMINANCE6_ALPHA2_EXT 0x8044 #define GL_LUMINANCE8_ALPHA8_EXT 0x8045 #define GL_LUMINANCE12_ALPHA4_EXT 0x8046 #define GL_LUMINANCE12_ALPHA12_EXT 0x8047 #define GL_LUMINANCE16_ALPHA16_EXT 0x8048 #define GL_INTENSITY_EXT 0x8049 #define GL_INTENSITY4_EXT 0x804A #define GL_INTENSITY8_EXT 0x804B #define GL_INTENSITY12_EXT 0x804C #define GL_INTENSITY16_EXT 0x804D #define GL_RGB2_EXT 0x804E #define GL_RGB4_EXT 0x804F #define GL_RGB5_EXT 0x8050 #define GL_RGB8_EXT 0x8051 #define GL_RGB10_EXT 0x8052 #define GL_RGB12_EXT 0x8053 #define GL_RGB16_EXT 0x8054 #define GL_RGBA2_EXT 0x8055 #define GL_RGBA4_EXT 0x8056 #define GL_RGB5_A1_EXT 0x8057 #define GL_RGBA8_EXT 0x8058 #define GL_RGB10_A2_EXT 0x8059 #define GL_RGBA12_EXT 0x805A #define GL_RGBA16_EXT 0x805B #define GL_TEXTURE_RED_SIZE_EXT 0x805C #define GL_TEXTURE_GREEN_SIZE_EXT 0x805D #define GL_TEXTURE_BLUE_SIZE_EXT 0x805E #define GL_TEXTURE_ALPHA_SIZE_EXT 0x805F #define GL_TEXTURE_LUMINANCE_SIZE_EXT 0x8060 #define GL_TEXTURE_INTENSITY_SIZE_EXT 0x8061 #define GL_REPLACE_EXT 0x8062 #define GL_PROXY_TEXTURE_1D_EXT 0x8063 #define GL_PROXY_TEXTURE_2D_EXT 0x8064 #define GL_TEXTURE_TOO_LARGE_EXT 0x8065 #endif #ifndef GL_EXT_texture3D #define GL_PACK_SKIP_IMAGES_EXT 0x806B #define GL_PACK_IMAGE_HEIGHT_EXT 0x806C #define GL_UNPACK_SKIP_IMAGES_EXT 0x806D #define GL_UNPACK_IMAGE_HEIGHT_EXT 0x806E #define GL_TEXTURE_3D_EXT 0x806F #define GL_PROXY_TEXTURE_3D_EXT 0x8070 #define GL_TEXTURE_DEPTH_EXT 0x8071 #define GL_TEXTURE_WRAP_R_EXT 0x8072 #define GL_MAX_3D_TEXTURE_SIZE_EXT 0x8073 #endif #ifndef GL_SGIS_texture_filter4 #define GL_FILTER4_SGIS 0x8146 #define GL_TEXTURE_FILTER4_SIZE_SGIS 0x8147 #endif #ifndef GL_EXT_subtexture #endif #ifndef GL_EXT_copy_texture #endif #ifndef GL_EXT_histogram #define GL_HISTOGRAM_EXT 0x8024 #define GL_PROXY_HISTOGRAM_EXT 0x8025 #define GL_HISTOGRAM_WIDTH_EXT 0x8026 #define GL_HISTOGRAM_FORMAT_EXT 0x8027 #define GL_HISTOGRAM_RED_SIZE_EXT 0x8028 #define GL_HISTOGRAM_GREEN_SIZE_EXT 0x8029 #define GL_HISTOGRAM_BLUE_SIZE_EXT 0x802A #define GL_HISTOGRAM_ALPHA_SIZE_EXT 0x802B #define GL_HISTOGRAM_LUMINANCE_SIZE_EXT 0x802C #define GL_HISTOGRAM_SINK_EXT 0x802D #define GL_MINMAX_EXT 0x802E #define GL_MINMAX_FORMAT_EXT 0x802F #define GL_MINMAX_SINK_EXT 0x8030 #define GL_TABLE_TOO_LARGE_EXT 0x8031 #endif #ifndef GL_EXT_convolution #define GL_CONVOLUTION_1D_EXT 0x8010 #define GL_CONVOLUTION_2D_EXT 0x8011 #define GL_SEPARABLE_2D_EXT 0x8012 #define GL_CONVOLUTION_BORDER_MODE_EXT 0x8013 #define GL_CONVOLUTION_FILTER_SCALE_EXT 0x8014 #define GL_CONVOLUTION_FILTER_BIAS_EXT 0x8015 #define GL_REDUCE_EXT 0x8016 #define GL_CONVOLUTION_FORMAT_EXT 0x8017 #define GL_CONVOLUTION_WIDTH_EXT 0x8018 #define GL_CONVOLUTION_HEIGHT_EXT 0x8019 #define GL_MAX_CONVOLUTION_WIDTH_EXT 0x801A #define GL_MAX_CONVOLUTION_HEIGHT_EXT 0x801B #define GL_POST_CONVOLUTION_RED_SCALE_EXT 0x801C #define GL_POST_CONVOLUTION_GREEN_SCALE_EXT 0x801D #define GL_POST_CONVOLUTION_BLUE_SCALE_EXT 0x801E #define GL_POST_CONVOLUTION_ALPHA_SCALE_EXT 0x801F #define GL_POST_CONVOLUTION_RED_BIAS_EXT 0x8020 #define GL_POST_CONVOLUTION_GREEN_BIAS_EXT 0x8021 #define GL_POST_CONVOLUTION_BLUE_BIAS_EXT 0x8022 #define GL_POST_CONVOLUTION_ALPHA_BIAS_EXT 0x8023 #endif #ifndef GL_SGI_color_matrix #define GL_COLOR_MATRIX_SGI 0x80B1 #define GL_COLOR_MATRIX_STACK_DEPTH_SGI 0x80B2 #define GL_MAX_COLOR_MATRIX_STACK_DEPTH_SGI 0x80B3 #define GL_POST_COLOR_MATRIX_RED_SCALE_SGI 0x80B4 #define GL_POST_COLOR_MATRIX_GREEN_SCALE_SGI 0x80B5 #define GL_POST_COLOR_MATRIX_BLUE_SCALE_SGI 0x80B6 #define GL_POST_COLOR_MATRIX_ALPHA_SCALE_SGI 0x80B7 #define GL_POST_COLOR_MATRIX_RED_BIAS_SGI 0x80B8 #define GL_POST_COLOR_MATRIX_GREEN_BIAS_SGI 0x80B9 #define GL_POST_COLOR_MATRIX_BLUE_BIAS_SGI 0x80BA #define GL_POST_COLOR_MATRIX_ALPHA_BIAS_SGI 0x80BB #endif #ifndef GL_SGI_color_table #define GL_COLOR_TABLE_SGI 0x80D0 #define GL_POST_CONVOLUTION_COLOR_TABLE_SGI 0x80D1 #define GL_POST_COLOR_MATRIX_COLOR_TABLE_SGI 0x80D2 #define GL_PROXY_COLOR_TABLE_SGI 0x80D3 #define GL_PROXY_POST_CONVOLUTION_COLOR_TABLE_SGI 0x80D4 #define GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE_SGI 0x80D5 #define GL_COLOR_TABLE_SCALE_SGI 0x80D6 #define GL_COLOR_TABLE_BIAS_SGI 0x80D7 #define GL_COLOR_TABLE_FORMAT_SGI 0x80D8 #define GL_COLOR_TABLE_WIDTH_SGI 0x80D9 #define GL_COLOR_TABLE_RED_SIZE_SGI 0x80DA #define GL_COLOR_TABLE_GREEN_SIZE_SGI 0x80DB #define GL_COLOR_TABLE_BLUE_SIZE_SGI 0x80DC #define GL_COLOR_TABLE_ALPHA_SIZE_SGI 0x80DD #define GL_COLOR_TABLE_LUMINANCE_SIZE_SGI 0x80DE #define GL_COLOR_TABLE_INTENSITY_SIZE_SGI 0x80DF #endif #ifndef GL_SGIS_pixel_texture #define GL_PIXEL_TEXTURE_SGIS 0x8353 #define GL_PIXEL_FRAGMENT_RGB_SOURCE_SGIS 0x8354 #define GL_PIXEL_FRAGMENT_ALPHA_SOURCE_SGIS 0x8355 #define GL_PIXEL_GROUP_COLOR_SGIS 0x8356 #endif #ifndef GL_SGIX_pixel_texture #define GL_PIXEL_TEX_GEN_SGIX 0x8139 #define GL_PIXEL_TEX_GEN_MODE_SGIX 0x832B #endif #ifndef GL_SGIS_texture4D #define GL_PACK_SKIP_VOLUMES_SGIS 0x8130 #define GL_PACK_IMAGE_DEPTH_SGIS 0x8131 #define GL_UNPACK_SKIP_VOLUMES_SGIS 0x8132 #define GL_UNPACK_IMAGE_DEPTH_SGIS 0x8133 #define GL_TEXTURE_4D_SGIS 0x8134 #define GL_PROXY_TEXTURE_4D_SGIS 0x8135 #define GL_TEXTURE_4DSIZE_SGIS 0x8136 #define GL_TEXTURE_WRAP_Q_SGIS 0x8137 #define GL_MAX_4D_TEXTURE_SIZE_SGIS 0x8138 #define GL_TEXTURE_4D_BINDING_SGIS 0x814F #endif #ifndef GL_SGI_texture_color_table #define GL_TEXTURE_COLOR_TABLE_SGI 0x80BC #define GL_PROXY_TEXTURE_COLOR_TABLE_SGI 0x80BD #endif #ifndef GL_EXT_cmyka #define GL_CMYK_EXT 0x800C #define GL_CMYKA_EXT 0x800D #define GL_PACK_CMYK_HINT_EXT 0x800E #define GL_UNPACK_CMYK_HINT_EXT 0x800F #endif #ifndef GL_EXT_texture_object #define GL_TEXTURE_PRIORITY_EXT 0x8066 #define GL_TEXTURE_RESIDENT_EXT 0x8067 #define GL_TEXTURE_1D_BINDING_EXT 0x8068 #define GL_TEXTURE_2D_BINDING_EXT 0x8069 #define GL_TEXTURE_3D_BINDING_EXT 0x806A #endif #ifndef GL_SGIS_detail_texture #define GL_DETAIL_TEXTURE_2D_SGIS 0x8095 #define GL_DETAIL_TEXTURE_2D_BINDING_SGIS 0x8096 #define GL_LINEAR_DETAIL_SGIS 0x8097 #define GL_LINEAR_DETAIL_ALPHA_SGIS 0x8098 #define GL_LINEAR_DETAIL_COLOR_SGIS 0x8099 #define GL_DETAIL_TEXTURE_LEVEL_SGIS 0x809A #define GL_DETAIL_TEXTURE_MODE_SGIS 0x809B #define GL_DETAIL_TEXTURE_FUNC_POINTS_SGIS 0x809C #endif #ifndef GL_SGIS_sharpen_texture #define GL_LINEAR_SHARPEN_SGIS 0x80AD #define GL_LINEAR_SHARPEN_ALPHA_SGIS 0x80AE #define GL_LINEAR_SHARPEN_COLOR_SGIS 0x80AF #define GL_SHARPEN_TEXTURE_FUNC_POINTS_SGIS 0x80B0 #endif #ifndef GL_EXT_packed_pixels #define GL_UNSIGNED_BYTE_3_3_2_EXT 0x8032 #define GL_UNSIGNED_SHORT_4_4_4_4_EXT 0x8033 #define GL_UNSIGNED_SHORT_5_5_5_1_EXT 0x8034 #define GL_UNSIGNED_INT_8_8_8_8_EXT 0x8035 #define GL_UNSIGNED_INT_10_10_10_2_EXT 0x8036 #endif #ifndef GL_SGIS_texture_lod #define GL_TEXTURE_MIN_LOD_SGIS 0x813A #define GL_TEXTURE_MAX_LOD_SGIS 0x813B #define GL_TEXTURE_BASE_LEVEL_SGIS 0x813C #define GL_TEXTURE_MAX_LEVEL_SGIS 0x813D #endif #ifndef GL_SGIS_multisample #define GL_MULTISAMPLE_SGIS 0x809D #define GL_SAMPLE_ALPHA_TO_MASK_SGIS 0x809E #define GL_SAMPLE_ALPHA_TO_ONE_SGIS 0x809F #define GL_SAMPLE_MASK_SGIS 0x80A0 #define GL_1PASS_SGIS 0x80A1 #define GL_2PASS_0_SGIS 0x80A2 #define GL_2PASS_1_SGIS 0x80A3 #define GL_4PASS_0_SGIS 0x80A4 #define GL_4PASS_1_SGIS 0x80A5 #define GL_4PASS_2_SGIS 0x80A6 #define GL_4PASS_3_SGIS 0x80A7 #define GL_SAMPLE_BUFFERS_SGIS 0x80A8 #define GL_SAMPLES_SGIS 0x80A9 #define GL_SAMPLE_MASK_VALUE_SGIS 0x80AA #define GL_SAMPLE_MASK_INVERT_SGIS 0x80AB #define GL_SAMPLE_PATTERN_SGIS 0x80AC #endif #ifndef GL_EXT_rescale_normal #define GL_RESCALE_NORMAL_EXT 0x803A #endif #ifndef GL_EXT_vertex_array #define GL_VERTEX_ARRAY_EXT 0x8074 #define GL_NORMAL_ARRAY_EXT 0x8075 #define GL_COLOR_ARRAY_EXT 0x8076 #define GL_INDEX_ARRAY_EXT 0x8077 #define GL_TEXTURE_COORD_ARRAY_EXT 0x8078 #define GL_EDGE_FLAG_ARRAY_EXT 0x8079 #define GL_VERTEX_ARRAY_SIZE_EXT 0x807A #define GL_VERTEX_ARRAY_TYPE_EXT 0x807B #define GL_VERTEX_ARRAY_STRIDE_EXT 0x807C #define GL_VERTEX_ARRAY_COUNT_EXT 0x807D #define GL_NORMAL_ARRAY_TYPE_EXT 0x807E #define GL_NORMAL_ARRAY_STRIDE_EXT 0x807F #define GL_NORMAL_ARRAY_COUNT_EXT 0x8080 #define GL_COLOR_ARRAY_SIZE_EXT 0x8081 #define GL_COLOR_ARRAY_TYPE_EXT 0x8082 #define GL_COLOR_ARRAY_STRIDE_EXT 0x8083 #define GL_COLOR_ARRAY_COUNT_EXT 0x8084 #define GL_INDEX_ARRAY_TYPE_EXT 0x8085 #define GL_INDEX_ARRAY_STRIDE_EXT 0x8086 #define GL_INDEX_ARRAY_COUNT_EXT 0x8087 #define GL_TEXTURE_COORD_ARRAY_SIZE_EXT 0x8088 #define GL_TEXTURE_COORD_ARRAY_TYPE_EXT 0x8089 #define GL_TEXTURE_COORD_ARRAY_STRIDE_EXT 0x808A #define GL_TEXTURE_COORD_ARRAY_COUNT_EXT 0x808B #define GL_EDGE_FLAG_ARRAY_STRIDE_EXT 0x808C #define GL_EDGE_FLAG_ARRAY_COUNT_EXT 0x808D #define GL_VERTEX_ARRAY_POINTER_EXT 0x808E #define GL_NORMAL_ARRAY_POINTER_EXT 0x808F #define GL_COLOR_ARRAY_POINTER_EXT 0x8090 #define GL_INDEX_ARRAY_POINTER_EXT 0x8091 #define GL_TEXTURE_COORD_ARRAY_POINTER_EXT 0x8092 #define GL_EDGE_FLAG_ARRAY_POINTER_EXT 0x8093 #endif #ifndef GL_EXT_misc_attribute #endif #ifndef GL_SGIS_generate_mipmap #define GL_GENERATE_MIPMAP_SGIS 0x8191 #define GL_GENERATE_MIPMAP_HINT_SGIS 0x8192 #endif #ifndef GL_SGIX_clipmap #define GL_LINEAR_CLIPMAP_LINEAR_SGIX 0x8170 #define GL_TEXTURE_CLIPMAP_CENTER_SGIX 0x8171 #define GL_TEXTURE_CLIPMAP_FRAME_SGIX 0x8172 #define GL_TEXTURE_CLIPMAP_OFFSET_SGIX 0x8173 #define GL_TEXTURE_CLIPMAP_VIRTUAL_DEPTH_SGIX 0x8174 #define GL_TEXTURE_CLIPMAP_LOD_OFFSET_SGIX 0x8175 #define GL_TEXTURE_CLIPMAP_DEPTH_SGIX 0x8176 #define GL_MAX_CLIPMAP_DEPTH_SGIX 0x8177 #define GL_MAX_CLIPMAP_VIRTUAL_DEPTH_SGIX 0x8178 #define GL_NEAREST_CLIPMAP_NEAREST_SGIX 0x844D #define GL_NEAREST_CLIPMAP_LINEAR_SGIX 0x844E #define GL_LINEAR_CLIPMAP_NEAREST_SGIX 0x844F #endif #ifndef GL_SGIX_shadow #define GL_TEXTURE_COMPARE_SGIX 0x819A #define GL_TEXTURE_COMPARE_OPERATOR_SGIX 0x819B #define GL_TEXTURE_LEQUAL_R_SGIX 0x819C #define GL_TEXTURE_GEQUAL_R_SGIX 0x819D #endif #ifndef GL_SGIS_texture_edge_clamp #define GL_CLAMP_TO_EDGE_SGIS 0x812F #endif #ifndef GL_SGIS_texture_border_clamp #define GL_CLAMP_TO_BORDER_SGIS 0x812D #endif #ifndef GL_EXT_blend_minmax #define GL_FUNC_ADD_EXT 0x8006 #define GL_MIN_EXT 0x8007 #define GL_MAX_EXT 0x8008 #define GL_BLEND_EQUATION_EXT 0x8009 #endif #ifndef GL_EXT_blend_subtract #define GL_FUNC_SUBTRACT_EXT 0x800A #define GL_FUNC_REVERSE_SUBTRACT_EXT 0x800B #endif #ifndef GL_EXT_blend_logic_op #endif #ifndef GL_SGIX_interlace #define GL_INTERLACE_SGIX 0x8094 #endif #ifndef GL_SGIX_pixel_tiles #define GL_PIXEL_TILE_BEST_ALIGNMENT_SGIX 0x813E #define GL_PIXEL_TILE_CACHE_INCREMENT_SGIX 0x813F #define GL_PIXEL_TILE_WIDTH_SGIX 0x8140 #define GL_PIXEL_TILE_HEIGHT_SGIX 0x8141 #define GL_PIXEL_TILE_GRID_WIDTH_SGIX 0x8142 #define GL_PIXEL_TILE_GRID_HEIGHT_SGIX 0x8143 #define GL_PIXEL_TILE_GRID_DEPTH_SGIX 0x8144 #define GL_PIXEL_TILE_CACHE_SIZE_SGIX 0x8145 #endif #ifndef GL_SGIS_texture_select #define GL_DUAL_ALPHA4_SGIS 0x8110 #define GL_DUAL_ALPHA8_SGIS 0x8111 #define GL_DUAL_ALPHA12_SGIS 0x8112 #define GL_DUAL_ALPHA16_SGIS 0x8113 #define GL_DUAL_LUMINANCE4_SGIS 0x8114 #define GL_DUAL_LUMINANCE8_SGIS 0x8115 #define GL_DUAL_LUMINANCE12_SGIS 0x8116 #define GL_DUAL_LUMINANCE16_SGIS 0x8117 #define GL_DUAL_INTENSITY4_SGIS 0x8118 #define GL_DUAL_INTENSITY8_SGIS 0x8119 #define GL_DUAL_INTENSITY12_SGIS 0x811A #define GL_DUAL_INTENSITY16_SGIS 0x811B #define GL_DUAL_LUMINANCE_ALPHA4_SGIS 0x811C #define GL_DUAL_LUMINANCE_ALPHA8_SGIS 0x811D #define GL_QUAD_ALPHA4_SGIS 0x811E #define GL_QUAD_ALPHA8_SGIS 0x811F #define GL_QUAD_LUMINANCE4_SGIS 0x8120 #define GL_QUAD_LUMINANCE8_SGIS 0x8121 #define GL_QUAD_INTENSITY4_SGIS 0x8122 #define GL_QUAD_INTENSITY8_SGIS 0x8123 #define GL_DUAL_TEXTURE_SELECT_SGIS 0x8124 #define GL_QUAD_TEXTURE_SELECT_SGIS 0x8125 #endif #ifndef GL_SGIX_sprite #define GL_SPRITE_SGIX 0x8148 #define GL_SPRITE_MODE_SGIX 0x8149 #define GL_SPRITE_AXIS_SGIX 0x814A #define GL_SPRITE_TRANSLATION_SGIX 0x814B #define GL_SPRITE_AXIAL_SGIX 0x814C #define GL_SPRITE_OBJECT_ALIGNED_SGIX 0x814D #define GL_SPRITE_EYE_ALIGNED_SGIX 0x814E #endif #ifndef GL_SGIX_texture_multi_buffer #define GL_TEXTURE_MULTI_BUFFER_HINT_SGIX 0x812E #endif #ifndef GL_EXT_point_parameters #define GL_POINT_SIZE_MIN_EXT 0x8126 #define GL_POINT_SIZE_MAX_EXT 0x8127 #define GL_POINT_FADE_THRESHOLD_SIZE_EXT 0x8128 #define GL_DISTANCE_ATTENUATION_EXT 0x8129 #endif #ifndef GL_SGIS_point_parameters #define GL_POINT_SIZE_MIN_SGIS 0x8126 #define GL_POINT_SIZE_MAX_SGIS 0x8127 #define GL_POINT_FADE_THRESHOLD_SIZE_SGIS 0x8128 #define GL_DISTANCE_ATTENUATION_SGIS 0x8129 #endif #ifndef GL_SGIX_instruments #define GL_INSTRUMENT_BUFFER_POINTER_SGIX 0x8180 #define GL_INSTRUMENT_MEASUREMENTS_SGIX 0x8181 #endif #ifndef GL_SGIX_texture_scale_bias #define GL_POST_TEXTURE_FILTER_BIAS_SGIX 0x8179 #define GL_POST_TEXTURE_FILTER_SCALE_SGIX 0x817A #define GL_POST_TEXTURE_FILTER_BIAS_RANGE_SGIX 0x817B #define GL_POST_TEXTURE_FILTER_SCALE_RANGE_SGIX 0x817C #endif #ifndef GL_SGIX_framezoom #define GL_FRAMEZOOM_SGIX 0x818B #define GL_FRAMEZOOM_FACTOR_SGIX 0x818C #define GL_MAX_FRAMEZOOM_FACTOR_SGIX 0x818D #endif #ifndef GL_SGIX_tag_sample_buffer #endif #ifndef GL_FfdMaskSGIX #define GL_TEXTURE_DEFORMATION_BIT_SGIX 0x00000001 #define GL_GEOMETRY_DEFORMATION_BIT_SGIX 0x00000002 #endif #ifndef GL_SGIX_polynomial_ffd #define GL_GEOMETRY_DEFORMATION_SGIX 0x8194 #define GL_TEXTURE_DEFORMATION_SGIX 0x8195 #define GL_DEFORMATIONS_MASK_SGIX 0x8196 #define GL_MAX_DEFORMATION_ORDER_SGIX 0x8197 #endif #ifndef GL_SGIX_reference_plane #define GL_REFERENCE_PLANE_SGIX 0x817D #define GL_REFERENCE_PLANE_EQUATION_SGIX 0x817E #endif #ifndef GL_SGIX_flush_raster #endif #ifndef GL_SGIX_depth_texture #define GL_DEPTH_COMPONENT16_SGIX 0x81A5 #define GL_DEPTH_COMPONENT24_SGIX 0x81A6 #define GL_DEPTH_COMPONENT32_SGIX 0x81A7 #endif #ifndef GL_SGIS_fog_function #define GL_FOG_FUNC_SGIS 0x812A #define GL_FOG_FUNC_POINTS_SGIS 0x812B #define GL_MAX_FOG_FUNC_POINTS_SGIS 0x812C #endif #ifndef GL_SGIX_fog_offset #define GL_FOG_OFFSET_SGIX 0x8198 #define GL_FOG_OFFSET_VALUE_SGIX 0x8199 #endif #ifndef GL_HP_image_transform #define GL_IMAGE_SCALE_X_HP 0x8155 #define GL_IMAGE_SCALE_Y_HP 0x8156 #define GL_IMAGE_TRANSLATE_X_HP 0x8157 #define GL_IMAGE_TRANSLATE_Y_HP 0x8158 #define GL_IMAGE_ROTATE_ANGLE_HP 0x8159 #define GL_IMAGE_ROTATE_ORIGIN_X_HP 0x815A #define GL_IMAGE_ROTATE_ORIGIN_Y_HP 0x815B #define GL_IMAGE_MAG_FILTER_HP 0x815C #define GL_IMAGE_MIN_FILTER_HP 0x815D #define GL_IMAGE_CUBIC_WEIGHT_HP 0x815E #define GL_CUBIC_HP 0x815F #define GL_AVERAGE_HP 0x8160 #define GL_IMAGE_TRANSFORM_2D_HP 0x8161 #define GL_POST_IMAGE_TRANSFORM_COLOR_TABLE_HP 0x8162 #define GL_PROXY_POST_IMAGE_TRANSFORM_COLOR_TABLE_HP 0x8163 #endif #ifndef GL_HP_convolution_border_modes #define GL_IGNORE_BORDER_HP 0x8150 #define GL_CONSTANT_BORDER_HP 0x8151 #define GL_REPLICATE_BORDER_HP 0x8153 #define GL_CONVOLUTION_BORDER_COLOR_HP 0x8154 #endif #ifndef GL_INGR_palette_buffer #endif #ifndef GL_SGIX_texture_add_env #define GL_TEXTURE_ENV_BIAS_SGIX 0x80BE #endif #ifndef GL_EXT_color_subtable #endif #ifndef GL_PGI_vertex_hints #define GL_VERTEX_DATA_HINT_PGI 0x1A22A #define GL_VERTEX_CONSISTENT_HINT_PGI 0x1A22B #define GL_MATERIAL_SIDE_HINT_PGI 0x1A22C #define GL_MAX_VERTEX_HINT_PGI 0x1A22D #define GL_COLOR3_BIT_PGI 0x00010000 #define GL_COLOR4_BIT_PGI 0x00020000 #define GL_EDGEFLAG_BIT_PGI 0x00040000 #define GL_INDEX_BIT_PGI 0x00080000 #define GL_MAT_AMBIENT_BIT_PGI 0x00100000 #define GL_MAT_AMBIENT_AND_DIFFUSE_BIT_PGI 0x00200000 #define GL_MAT_DIFFUSE_BIT_PGI 0x00400000 #define GL_MAT_EMISSION_BIT_PGI 0x00800000 #define GL_MAT_COLOR_INDEXES_BIT_PGI 0x01000000 #define GL_MAT_SHININESS_BIT_PGI 0x02000000 #define GL_MAT_SPECULAR_BIT_PGI 0x04000000 #define GL_NORMAL_BIT_PGI 0x08000000 #define GL_TEXCOORD1_BIT_PGI 0x10000000 #define GL_TEXCOORD2_BIT_PGI 0x20000000 #define GL_TEXCOORD3_BIT_PGI 0x40000000 #define GL_TEXCOORD4_BIT_PGI 0x80000000 #define GL_VERTEX23_BIT_PGI 0x00000004 #define GL_VERTEX4_BIT_PGI 0x00000008 #endif #ifndef GL_PGI_misc_hints #define GL_PREFER_DOUBLEBUFFER_HINT_PGI 0x1A1F8 #define GL_CONSERVE_MEMORY_HINT_PGI 0x1A1FD #define GL_RECLAIM_MEMORY_HINT_PGI 0x1A1FE #define GL_NATIVE_GRAPHICS_HANDLE_PGI 0x1A202 #define GL_NATIVE_GRAPHICS_BEGIN_HINT_PGI 0x1A203 #define GL_NATIVE_GRAPHICS_END_HINT_PGI 0x1A204 #define GL_ALWAYS_FAST_HINT_PGI 0x1A20C #define GL_ALWAYS_SOFT_HINT_PGI 0x1A20D #define GL_ALLOW_DRAW_OBJ_HINT_PGI 0x1A20E #define GL_ALLOW_DRAW_WIN_HINT_PGI 0x1A20F #define GL_ALLOW_DRAW_FRG_HINT_PGI 0x1A210 #define GL_ALLOW_DRAW_MEM_HINT_PGI 0x1A211 #define GL_STRICT_DEPTHFUNC_HINT_PGI 0x1A216 #define GL_STRICT_LIGHTING_HINT_PGI 0x1A217 #define GL_STRICT_SCISSOR_HINT_PGI 0x1A218 #define GL_FULL_STIPPLE_HINT_PGI 0x1A219 #define GL_CLIP_NEAR_HINT_PGI 0x1A220 #define GL_CLIP_FAR_HINT_PGI 0x1A221 #define GL_WIDE_LINE_HINT_PGI 0x1A222 #define GL_BACK_NORMALS_HINT_PGI 0x1A223 #endif #ifndef GL_EXT_paletted_texture #define GL_COLOR_INDEX1_EXT 0x80E2 #define GL_COLOR_INDEX2_EXT 0x80E3 #define GL_COLOR_INDEX4_EXT 0x80E4 #define GL_COLOR_INDEX8_EXT 0x80E5 #define GL_COLOR_INDEX12_EXT 0x80E6 #define GL_COLOR_INDEX16_EXT 0x80E7 #define GL_TEXTURE_INDEX_SIZE_EXT 0x80ED #endif #ifndef GL_EXT_clip_volume_hint #define GL_CLIP_VOLUME_CLIPPING_HINT_EXT 0x80F0 #endif #ifndef GL_SGIX_list_priority #define GL_LIST_PRIORITY_SGIX 0x8182 #endif #ifndef GL_SGIX_ir_instrument1 #define GL_IR_INSTRUMENT1_SGIX 0x817F #endif #ifndef GL_SGIX_calligraphic_fragment #define GL_CALLIGRAPHIC_FRAGMENT_SGIX 0x8183 #endif #ifndef GL_SGIX_texture_lod_bias #define GL_TEXTURE_LOD_BIAS_S_SGIX 0x818E #define GL_TEXTURE_LOD_BIAS_T_SGIX 0x818F #define GL_TEXTURE_LOD_BIAS_R_SGIX 0x8190 #endif #ifndef GL_SGIX_shadow_ambient #define GL_SHADOW_AMBIENT_SGIX 0x80BF #endif #ifndef GL_EXT_index_texture #endif #ifndef GL_EXT_index_material #define GL_INDEX_MATERIAL_EXT 0x81B8 #define GL_INDEX_MATERIAL_PARAMETER_EXT 0x81B9 #define GL_INDEX_MATERIAL_FACE_EXT 0x81BA #endif #ifndef GL_EXT_index_func #define GL_INDEX_TEST_EXT 0x81B5 #define GL_INDEX_TEST_FUNC_EXT 0x81B6 #define GL_INDEX_TEST_REF_EXT 0x81B7 #endif #ifndef GL_EXT_index_array_formats #define GL_IUI_V2F_EXT 0x81AD #define GL_IUI_V3F_EXT 0x81AE #define GL_IUI_N3F_V2F_EXT 0x81AF #define GL_IUI_N3F_V3F_EXT 0x81B0 #define GL_T2F_IUI_V2F_EXT 0x81B1 #define GL_T2F_IUI_V3F_EXT 0x81B2 #define GL_T2F_IUI_N3F_V2F_EXT 0x81B3 #define GL_T2F_IUI_N3F_V3F_EXT 0x81B4 #endif #ifndef GL_EXT_compiled_vertex_array #define GL_ARRAY_ELEMENT_LOCK_FIRST_EXT 0x81A8 #define GL_ARRAY_ELEMENT_LOCK_COUNT_EXT 0x81A9 #endif #ifndef GL_EXT_cull_vertex #define GL_CULL_VERTEX_EXT 0x81AA #define GL_CULL_VERTEX_EYE_POSITION_EXT 0x81AB #define GL_CULL_VERTEX_OBJECT_POSITION_EXT 0x81AC #endif #ifndef GL_SGIX_ycrcb #define GL_YCRCB_422_SGIX 0x81BB #define GL_YCRCB_444_SGIX 0x81BC #endif #ifndef GL_SGIX_fragment_lighting #define GL_FRAGMENT_LIGHTING_SGIX 0x8400 #define GL_FRAGMENT_COLOR_MATERIAL_SGIX 0x8401 #define GL_FRAGMENT_COLOR_MATERIAL_FACE_SGIX 0x8402 #define GL_FRAGMENT_COLOR_MATERIAL_PARAMETER_SGIX 0x8403 #define GL_MAX_FRAGMENT_LIGHTS_SGIX 0x8404 #define GL_MAX_ACTIVE_LIGHTS_SGIX 0x8405 #define GL_CURRENT_RASTER_NORMAL_SGIX 0x8406 #define GL_LIGHT_ENV_MODE_SGIX 0x8407 #define GL_FRAGMENT_LIGHT_MODEL_LOCAL_VIEWER_SGIX 0x8408 #define GL_FRAGMENT_LIGHT_MODEL_TWO_SIDE_SGIX 0x8409 #define GL_FRAGMENT_LIGHT_MODEL_AMBIENT_SGIX 0x840A #define GL_FRAGMENT_LIGHT_MODEL_NORMAL_INTERPOLATION_SGIX 0x840B #define GL_FRAGMENT_LIGHT0_SGIX 0x840C #define GL_FRAGMENT_LIGHT1_SGIX 0x840D #define GL_FRAGMENT_LIGHT2_SGIX 0x840E #define GL_FRAGMENT_LIGHT3_SGIX 0x840F #define GL_FRAGMENT_LIGHT4_SGIX 0x8410 #define GL_FRAGMENT_LIGHT5_SGIX 0x8411 #define GL_FRAGMENT_LIGHT6_SGIX 0x8412 #define GL_FRAGMENT_LIGHT7_SGIX 0x8413 #endif #ifndef GL_IBM_rasterpos_clip #define GL_RASTER_POSITION_UNCLIPPED_IBM 0x19262 #endif #ifndef GL_HP_texture_lighting #define GL_TEXTURE_LIGHTING_MODE_HP 0x8167 #define GL_TEXTURE_POST_SPECULAR_HP 0x8168 #define GL_TEXTURE_PRE_SPECULAR_HP 0x8169 #endif #ifndef GL_EXT_draw_range_elements #define GL_MAX_ELEMENTS_VERTICES_EXT 0x80E8 #define GL_MAX_ELEMENTS_INDICES_EXT 0x80E9 #endif #ifndef GL_WIN_phong_shading #define GL_PHONG_WIN 0x80EA #define GL_PHONG_HINT_WIN 0x80EB #endif #ifndef GL_WIN_specular_fog #define GL_FOG_SPECULAR_TEXTURE_WIN 0x80EC #endif #ifndef GL_EXT_light_texture #define GL_FRAGMENT_MATERIAL_EXT 0x8349 #define GL_FRAGMENT_NORMAL_EXT 0x834A #define GL_FRAGMENT_COLOR_EXT 0x834C #define GL_ATTENUATION_EXT 0x834D #define GL_SHADOW_ATTENUATION_EXT 0x834E #define GL_TEXTURE_APPLICATION_MODE_EXT 0x834F #define GL_TEXTURE_LIGHT_EXT 0x8350 #define GL_TEXTURE_MATERIAL_FACE_EXT 0x8351 #define GL_TEXTURE_MATERIAL_PARAMETER_EXT 0x8352 /* reuse GL_FRAGMENT_DEPTH_EXT */ #endif #ifndef GL_SGIX_blend_alpha_minmax #define GL_ALPHA_MIN_SGIX 0x8320 #define GL_ALPHA_MAX_SGIX 0x8321 #endif #ifndef GL_SGIX_impact_pixel_texture #define GL_PIXEL_TEX_GEN_Q_CEILING_SGIX 0x8184 #define GL_PIXEL_TEX_GEN_Q_ROUND_SGIX 0x8185 #define GL_PIXEL_TEX_GEN_Q_FLOOR_SGIX 0x8186 #define GL_PIXEL_TEX_GEN_ALPHA_REPLACE_SGIX 0x8187 #define GL_PIXEL_TEX_GEN_ALPHA_NO_REPLACE_SGIX 0x8188 #define GL_PIXEL_TEX_GEN_ALPHA_LS_SGIX 0x8189 #define GL_PIXEL_TEX_GEN_ALPHA_MS_SGIX 0x818A #endif #ifndef GL_EXT_bgra #define GL_BGR_EXT 0x80E0 #define GL_BGRA_EXT 0x80E1 #endif #ifndef GL_SGIX_async #define GL_ASYNC_MARKER_SGIX 0x8329 #endif #ifndef GL_SGIX_async_pixel #define GL_ASYNC_TEX_IMAGE_SGIX 0x835C #define GL_ASYNC_DRAW_PIXELS_SGIX 0x835D #define GL_ASYNC_READ_PIXELS_SGIX 0x835E #define GL_MAX_ASYNC_TEX_IMAGE_SGIX 0x835F #define GL_MAX_ASYNC_DRAW_PIXELS_SGIX 0x8360 #define GL_MAX_ASYNC_READ_PIXELS_SGIX 0x8361 #endif #ifndef GL_SGIX_async_histogram #define GL_ASYNC_HISTOGRAM_SGIX 0x832C #define GL_MAX_ASYNC_HISTOGRAM_SGIX 0x832D #endif #ifndef GL_INTEL_texture_scissor #endif #ifndef GL_INTEL_parallel_arrays #define GL_PARALLEL_ARRAYS_INTEL 0x83F4 #define GL_VERTEX_ARRAY_PARALLEL_POINTERS_INTEL 0x83F5 #define GL_NORMAL_ARRAY_PARALLEL_POINTERS_INTEL 0x83F6 #define GL_COLOR_ARRAY_PARALLEL_POINTERS_INTEL 0x83F7 #define GL_TEXTURE_COORD_ARRAY_PARALLEL_POINTERS_INTEL 0x83F8 #endif #ifndef GL_HP_occlusion_test #define GL_OCCLUSION_TEST_HP 0x8165 #define GL_OCCLUSION_TEST_RESULT_HP 0x8166 #endif #ifndef GL_EXT_pixel_transform #define GL_PIXEL_TRANSFORM_2D_EXT 0x8330 #define GL_PIXEL_MAG_FILTER_EXT 0x8331 #define GL_PIXEL_MIN_FILTER_EXT 0x8332 #define GL_PIXEL_CUBIC_WEIGHT_EXT 0x8333 #define GL_CUBIC_EXT 0x8334 #define GL_AVERAGE_EXT 0x8335 #define GL_PIXEL_TRANSFORM_2D_STACK_DEPTH_EXT 0x8336 #define GL_MAX_PIXEL_TRANSFORM_2D_STACK_DEPTH_EXT 0x8337 #define GL_PIXEL_TRANSFORM_2D_MATRIX_EXT 0x8338 #endif #ifndef GL_EXT_pixel_transform_color_table #endif #ifndef GL_EXT_shared_texture_palette #define GL_SHARED_TEXTURE_PALETTE_EXT 0x81FB #endif #ifndef GL_EXT_separate_specular_color #define GL_LIGHT_MODEL_COLOR_CONTROL_EXT 0x81F8 #define GL_SINGLE_COLOR_EXT 0x81F9 #define GL_SEPARATE_SPECULAR_COLOR_EXT 0x81FA #endif #ifndef GL_EXT_secondary_color #define GL_COLOR_SUM_EXT 0x8458 #define GL_CURRENT_SECONDARY_COLOR_EXT 0x8459 #define GL_SECONDARY_COLOR_ARRAY_SIZE_EXT 0x845A #define GL_SECONDARY_COLOR_ARRAY_TYPE_EXT 0x845B #define GL_SECONDARY_COLOR_ARRAY_STRIDE_EXT 0x845C #define GL_SECONDARY_COLOR_ARRAY_POINTER_EXT 0x845D #define GL_SECONDARY_COLOR_ARRAY_EXT 0x845E #endif #ifndef GL_EXT_texture_perturb_normal #define GL_PERTURB_EXT 0x85AE #define GL_TEXTURE_NORMAL_EXT 0x85AF #endif #ifndef GL_EXT_multi_draw_arrays #endif #ifndef GL_EXT_fog_coord #define GL_FOG_COORDINATE_SOURCE_EXT 0x8450 #define GL_FOG_COORDINATE_EXT 0x8451 #define GL_FRAGMENT_DEPTH_EXT 0x8452 #define GL_CURRENT_FOG_COORDINATE_EXT 0x8453 #define GL_FOG_COORDINATE_ARRAY_TYPE_EXT 0x8454 #define GL_FOG_COORDINATE_ARRAY_STRIDE_EXT 0x8455 #define GL_FOG_COORDINATE_ARRAY_POINTER_EXT 0x8456 #define GL_FOG_COORDINATE_ARRAY_EXT 0x8457 #endif #ifndef GL_REND_screen_coordinates #define GL_SCREEN_COORDINATES_REND 0x8490 #define GL_INVERTED_SCREEN_W_REND 0x8491 #endif #ifndef GL_EXT_coordinate_frame #define GL_TANGENT_ARRAY_EXT 0x8439 #define GL_BINORMAL_ARRAY_EXT 0x843A #define GL_CURRENT_TANGENT_EXT 0x843B #define GL_CURRENT_BINORMAL_EXT 0x843C #define GL_TANGENT_ARRAY_TYPE_EXT 0x843E #define GL_TANGENT_ARRAY_STRIDE_EXT 0x843F #define GL_BINORMAL_ARRAY_TYPE_EXT 0x8440 #define GL_BINORMAL_ARRAY_STRIDE_EXT 0x8441 #define GL_TANGENT_ARRAY_POINTER_EXT 0x8442 #define GL_BINORMAL_ARRAY_POINTER_EXT 0x8443 #define GL_MAP1_TANGENT_EXT 0x8444 #define GL_MAP2_TANGENT_EXT 0x8445 #define GL_MAP1_BINORMAL_EXT 0x8446 #define GL_MAP2_BINORMAL_EXT 0x8447 #endif #ifndef GL_EXT_texture_env_combine #define GL_COMBINE_EXT 0x8570 #define GL_COMBINE_RGB_EXT 0x8571 #define GL_COMBINE_ALPHA_EXT 0x8572 #define GL_RGB_SCALE_EXT 0x8573 #define GL_ADD_SIGNED_EXT 0x8574 #define GL_INTERPOLATE_EXT 0x8575 #define GL_CONSTANT_EXT 0x8576 #define GL_PRIMARY_COLOR_EXT 0x8577 #define GL_PREVIOUS_EXT 0x8578 #define GL_SOURCE0_RGB_EXT 0x8580 #define GL_SOURCE1_RGB_EXT 0x8581 #define GL_SOURCE2_RGB_EXT 0x8582 #define GL_SOURCE0_ALPHA_EXT 0x8588 #define GL_SOURCE1_ALPHA_EXT 0x8589 #define GL_SOURCE2_ALPHA_EXT 0x858A #define GL_OPERAND0_RGB_EXT 0x8590 #define GL_OPERAND1_RGB_EXT 0x8591 #define GL_OPERAND2_RGB_EXT 0x8592 #define GL_OPERAND0_ALPHA_EXT 0x8598 #define GL_OPERAND1_ALPHA_EXT 0x8599 #define GL_OPERAND2_ALPHA_EXT 0x859A #endif #ifndef GL_APPLE_specular_vector #define GL_LIGHT_MODEL_SPECULAR_VECTOR_APPLE 0x85B0 #endif #ifndef GL_APPLE_transform_hint #define GL_TRANSFORM_HINT_APPLE 0x85B1 #endif #ifndef GL_SGIX_fog_scale #define GL_FOG_SCALE_SGIX 0x81FC #define GL_FOG_SCALE_VALUE_SGIX 0x81FD #endif #ifndef GL_SUNX_constant_data #define GL_UNPACK_CONSTANT_DATA_SUNX 0x81D5 #define GL_TEXTURE_CONSTANT_DATA_SUNX 0x81D6 #endif #ifndef GL_SUN_global_alpha #define GL_GLOBAL_ALPHA_SUN 0x81D9 #define GL_GLOBAL_ALPHA_FACTOR_SUN 0x81DA #endif #ifndef GL_SUN_triangle_list #define GL_RESTART_SUN 0x0001 #define GL_REPLACE_MIDDLE_SUN 0x0002 #define GL_REPLACE_OLDEST_SUN 0x0003 #define GL_TRIANGLE_LIST_SUN 0x81D7 #define GL_REPLACEMENT_CODE_SUN 0x81D8 #define GL_REPLACEMENT_CODE_ARRAY_SUN 0x85C0 #define GL_REPLACEMENT_CODE_ARRAY_TYPE_SUN 0x85C1 #define GL_REPLACEMENT_CODE_ARRAY_STRIDE_SUN 0x85C2 #define GL_REPLACEMENT_CODE_ARRAY_POINTER_SUN 0x85C3 #define GL_R1UI_V3F_SUN 0x85C4 #define GL_R1UI_C4UB_V3F_SUN 0x85C5 #define GL_R1UI_C3F_V3F_SUN 0x85C6 #define GL_R1UI_N3F_V3F_SUN 0x85C7 #define GL_R1UI_C4F_N3F_V3F_SUN 0x85C8 #define GL_R1UI_T2F_V3F_SUN 0x85C9 #define GL_R1UI_T2F_N3F_V3F_SUN 0x85CA #define GL_R1UI_T2F_C4F_N3F_V3F_SUN 0x85CB #endif #ifndef GL_SUN_vertex #endif #ifndef GL_EXT_blend_func_separate #define GL_BLEND_DST_RGB_EXT 0x80C8 #define GL_BLEND_SRC_RGB_EXT 0x80C9 #define GL_BLEND_DST_ALPHA_EXT 0x80CA #define GL_BLEND_SRC_ALPHA_EXT 0x80CB #endif #ifndef GL_INGR_color_clamp #define GL_RED_MIN_CLAMP_INGR 0x8560 #define GL_GREEN_MIN_CLAMP_INGR 0x8561 #define GL_BLUE_MIN_CLAMP_INGR 0x8562 #define GL_ALPHA_MIN_CLAMP_INGR 0x8563 #define GL_RED_MAX_CLAMP_INGR 0x8564 #define GL_GREEN_MAX_CLAMP_INGR 0x8565 #define GL_BLUE_MAX_CLAMP_INGR 0x8566 #define GL_ALPHA_MAX_CLAMP_INGR 0x8567 #endif #ifndef GL_INGR_interlace_read #define GL_INTERLACE_READ_INGR 0x8568 #endif #ifndef GL_EXT_stencil_wrap #define GL_INCR_WRAP_EXT 0x8507 #define GL_DECR_WRAP_EXT 0x8508 #endif #ifndef GL_EXT_422_pixels #define GL_422_EXT 0x80CC #define GL_422_REV_EXT 0x80CD #define GL_422_AVERAGE_EXT 0x80CE #define GL_422_REV_AVERAGE_EXT 0x80CF #endif #ifndef GL_NV_texgen_reflection #define GL_NORMAL_MAP_NV 0x8511 #define GL_REFLECTION_MAP_NV 0x8512 #endif #ifndef GL_EXT_texture_cube_map #define GL_NORMAL_MAP_EXT 0x8511 #define GL_REFLECTION_MAP_EXT 0x8512 #define GL_TEXTURE_CUBE_MAP_EXT 0x8513 #define GL_TEXTURE_BINDING_CUBE_MAP_EXT 0x8514 #define GL_TEXTURE_CUBE_MAP_POSITIVE_X_EXT 0x8515 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_X_EXT 0x8516 #define GL_TEXTURE_CUBE_MAP_POSITIVE_Y_EXT 0x8517 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT 0x8518 #define GL_TEXTURE_CUBE_MAP_POSITIVE_Z_EXT 0x8519 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT 0x851A #define GL_PROXY_TEXTURE_CUBE_MAP_EXT 0x851B #define GL_MAX_CUBE_MAP_TEXTURE_SIZE_EXT 0x851C #endif #ifndef GL_SUN_convolution_border_modes #define GL_WRAP_BORDER_SUN 0x81D4 #endif #ifndef GL_EXT_texture_env_add #endif #ifndef GL_EXT_texture_lod_bias #define GL_MAX_TEXTURE_LOD_BIAS_EXT 0x84FD #define GL_TEXTURE_FILTER_CONTROL_EXT 0x8500 #define GL_TEXTURE_LOD_BIAS_EXT 0x8501 #endif #ifndef GL_EXT_texture_filter_anisotropic #define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE #define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF #endif #ifndef GL_EXT_vertex_weighting #define GL_MODELVIEW0_STACK_DEPTH_EXT GL_MODELVIEW_STACK_DEPTH #define GL_MODELVIEW1_STACK_DEPTH_EXT 0x8502 #define GL_MODELVIEW0_MATRIX_EXT GL_MODELVIEW_MATRIX #define GL_MODELVIEW1_MATRIX_EXT 0x8506 #define GL_VERTEX_WEIGHTING_EXT 0x8509 #define GL_MODELVIEW0_EXT GL_MODELVIEW #define GL_MODELVIEW1_EXT 0x850A #define GL_CURRENT_VERTEX_WEIGHT_EXT 0x850B #define GL_VERTEX_WEIGHT_ARRAY_EXT 0x850C #define GL_VERTEX_WEIGHT_ARRAY_SIZE_EXT 0x850D #define GL_VERTEX_WEIGHT_ARRAY_TYPE_EXT 0x850E #define GL_VERTEX_WEIGHT_ARRAY_STRIDE_EXT 0x850F #define GL_VERTEX_WEIGHT_ARRAY_POINTER_EXT 0x8510 #endif #ifndef GL_NV_light_max_exponent #define GL_MAX_SHININESS_NV 0x8504 #define GL_MAX_SPOT_EXPONENT_NV 0x8505 #endif #ifndef GL_NV_vertex_array_range #define GL_VERTEX_ARRAY_RANGE_NV 0x851D #define GL_VERTEX_ARRAY_RANGE_LENGTH_NV 0x851E #define GL_VERTEX_ARRAY_RANGE_VALID_NV 0x851F #define GL_MAX_VERTEX_ARRAY_RANGE_ELEMENT_NV 0x8520 #define GL_VERTEX_ARRAY_RANGE_POINTER_NV 0x8521 #endif #ifndef GL_NV_register_combiners #define GL_REGISTER_COMBINERS_NV 0x8522 #define GL_VARIABLE_A_NV 0x8523 #define GL_VARIABLE_B_NV 0x8524 #define GL_VARIABLE_C_NV 0x8525 #define GL_VARIABLE_D_NV 0x8526 #define GL_VARIABLE_E_NV 0x8527 #define GL_VARIABLE_F_NV 0x8528 #define GL_VARIABLE_G_NV 0x8529 #define GL_CONSTANT_COLOR0_NV 0x852A #define GL_CONSTANT_COLOR1_NV 0x852B #define GL_PRIMARY_COLOR_NV 0x852C #define GL_SECONDARY_COLOR_NV 0x852D #define GL_SPARE0_NV 0x852E #define GL_SPARE1_NV 0x852F #define GL_DISCARD_NV 0x8530 #define GL_E_TIMES_F_NV 0x8531 #define GL_SPARE0_PLUS_SECONDARY_COLOR_NV 0x8532 #define GL_UNSIGNED_IDENTITY_NV 0x8536 #define GL_UNSIGNED_INVERT_NV 0x8537 #define GL_EXPAND_NORMAL_NV 0x8538 #define GL_EXPAND_NEGATE_NV 0x8539 #define GL_HALF_BIAS_NORMAL_NV 0x853A #define GL_HALF_BIAS_NEGATE_NV 0x853B #define GL_SIGNED_IDENTITY_NV 0x853C #define GL_SIGNED_NEGATE_NV 0x853D #define GL_SCALE_BY_TWO_NV 0x853E #define GL_SCALE_BY_FOUR_NV 0x853F #define GL_SCALE_BY_ONE_HALF_NV 0x8540 #define GL_BIAS_BY_NEGATIVE_ONE_HALF_NV 0x8541 #define GL_COMBINER_INPUT_NV 0x8542 #define GL_COMBINER_MAPPING_NV 0x8543 #define GL_COMBINER_COMPONENT_USAGE_NV 0x8544 #define GL_COMBINER_AB_DOT_PRODUCT_NV 0x8545 #define GL_COMBINER_CD_DOT_PRODUCT_NV 0x8546 #define GL_COMBINER_MUX_SUM_NV 0x8547 #define GL_COMBINER_SCALE_NV 0x8548 #define GL_COMBINER_BIAS_NV 0x8549 #define GL_COMBINER_AB_OUTPUT_NV 0x854A #define GL_COMBINER_CD_OUTPUT_NV 0x854B #define GL_COMBINER_SUM_OUTPUT_NV 0x854C #define GL_MAX_GENERAL_COMBINERS_NV 0x854D #define GL_NUM_GENERAL_COMBINERS_NV 0x854E #define GL_COLOR_SUM_CLAMP_NV 0x854F #define GL_COMBINER0_NV 0x8550 #define GL_COMBINER1_NV 0x8551 #define GL_COMBINER2_NV 0x8552 #define GL_COMBINER3_NV 0x8553 #define GL_COMBINER4_NV 0x8554 #define GL_COMBINER5_NV 0x8555 #define GL_COMBINER6_NV 0x8556 #define GL_COMBINER7_NV 0x8557 /* reuse GL_TEXTURE0_ARB */ /* reuse GL_TEXTURE1_ARB */ /* reuse GL_ZERO */ /* reuse GL_NONE */ /* reuse GL_FOG */ #endif #ifndef GL_NV_fog_distance #define GL_FOG_DISTANCE_MODE_NV 0x855A #define GL_EYE_RADIAL_NV 0x855B #define GL_EYE_PLANE_ABSOLUTE_NV 0x855C /* reuse GL_EYE_PLANE */ #endif #ifndef GL_NV_texgen_emboss #define GL_EMBOSS_LIGHT_NV 0x855D #define GL_EMBOSS_CONSTANT_NV 0x855E #define GL_EMBOSS_MAP_NV 0x855F #endif #ifndef GL_NV_blend_square #endif #ifndef GL_NV_texture_env_combine4 #define GL_COMBINE4_NV 0x8503 #define GL_SOURCE3_RGB_NV 0x8583 #define GL_SOURCE3_ALPHA_NV 0x858B #define GL_OPERAND3_RGB_NV 0x8593 #define GL_OPERAND3_ALPHA_NV 0x859B #endif #ifndef GL_MESA_resize_buffers #endif #ifndef GL_MESA_window_pos #endif #ifndef GL_EXT_texture_compression_s3tc #define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0 #define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1 #define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2 #define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3 #endif #ifndef GL_IBM_cull_vertex #define GL_CULL_VERTEX_IBM 103050 #endif #ifndef GL_IBM_multimode_draw_arrays #endif #ifndef GL_IBM_vertex_array_lists #define GL_VERTEX_ARRAY_LIST_IBM 103070 #define GL_NORMAL_ARRAY_LIST_IBM 103071 #define GL_COLOR_ARRAY_LIST_IBM 103072 #define GL_INDEX_ARRAY_LIST_IBM 103073 #define GL_TEXTURE_COORD_ARRAY_LIST_IBM 103074 #define GL_EDGE_FLAG_ARRAY_LIST_IBM 103075 #define GL_FOG_COORDINATE_ARRAY_LIST_IBM 103076 #define GL_SECONDARY_COLOR_ARRAY_LIST_IBM 103077 #define GL_VERTEX_ARRAY_LIST_STRIDE_IBM 103080 #define GL_NORMAL_ARRAY_LIST_STRIDE_IBM 103081 #define GL_COLOR_ARRAY_LIST_STRIDE_IBM 103082 #define GL_INDEX_ARRAY_LIST_STRIDE_IBM 103083 #define GL_TEXTURE_COORD_ARRAY_LIST_STRIDE_IBM 103084 #define GL_EDGE_FLAG_ARRAY_LIST_STRIDE_IBM 103085 #define GL_FOG_COORDINATE_ARRAY_LIST_STRIDE_IBM 103086 #define GL_SECONDARY_COLOR_ARRAY_LIST_STRIDE_IBM 103087 #endif #ifndef GL_SGIX_subsample #define GL_PACK_SUBSAMPLE_RATE_SGIX 0x85A0 #define GL_UNPACK_SUBSAMPLE_RATE_SGIX 0x85A1 #define GL_PIXEL_SUBSAMPLE_4444_SGIX 0x85A2 #define GL_PIXEL_SUBSAMPLE_2424_SGIX 0x85A3 #define GL_PIXEL_SUBSAMPLE_4242_SGIX 0x85A4 #endif #ifndef GL_SGIX_ycrcb_subsample #endif #ifndef GL_SGIX_ycrcba #define GL_YCRCB_SGIX 0x8318 #define GL_YCRCBA_SGIX 0x8319 #endif #ifndef GL_SGI_depth_pass_instrument #define GL_DEPTH_PASS_INSTRUMENT_SGIX 0x8310 #define GL_DEPTH_PASS_INSTRUMENT_COUNTERS_SGIX 0x8311 #define GL_DEPTH_PASS_INSTRUMENT_MAX_SGIX 0x8312 #endif #ifndef GL_3DFX_texture_compression_FXT1 #define GL_COMPRESSED_RGB_FXT1_3DFX 0x86B0 #define GL_COMPRESSED_RGBA_FXT1_3DFX 0x86B1 #endif #ifndef GL_3DFX_multisample #define GL_MULTISAMPLE_3DFX 0x86B2 #define GL_SAMPLE_BUFFERS_3DFX 0x86B3 #define GL_SAMPLES_3DFX 0x86B4 #define GL_MULTISAMPLE_BIT_3DFX 0x20000000 #endif #ifndef GL_3DFX_tbuffer #endif #ifndef GL_EXT_multisample #define GL_MULTISAMPLE_EXT 0x809D #define GL_SAMPLE_ALPHA_TO_MASK_EXT 0x809E #define GL_SAMPLE_ALPHA_TO_ONE_EXT 0x809F #define GL_SAMPLE_MASK_EXT 0x80A0 #define GL_1PASS_EXT 0x80A1 #define GL_2PASS_0_EXT 0x80A2 #define GL_2PASS_1_EXT 0x80A3 #define GL_4PASS_0_EXT 0x80A4 #define GL_4PASS_1_EXT 0x80A5 #define GL_4PASS_2_EXT 0x80A6 #define GL_4PASS_3_EXT 0x80A7 #define GL_SAMPLE_BUFFERS_EXT 0x80A8 #define GL_SAMPLES_EXT 0x80A9 #define GL_SAMPLE_MASK_VALUE_EXT 0x80AA #define GL_SAMPLE_MASK_INVERT_EXT 0x80AB #define GL_SAMPLE_PATTERN_EXT 0x80AC #define GL_MULTISAMPLE_BIT_EXT 0x20000000 #endif #ifndef GL_SGIX_vertex_preclip #define GL_VERTEX_PRECLIP_SGIX 0x83EE #define GL_VERTEX_PRECLIP_HINT_SGIX 0x83EF #endif #ifndef GL_SGIX_convolution_accuracy #define GL_CONVOLUTION_HINT_SGIX 0x8316 #endif #ifndef GL_SGIX_resample #define GL_PACK_RESAMPLE_SGIX 0x842C #define GL_UNPACK_RESAMPLE_SGIX 0x842D #define GL_RESAMPLE_REPLICATE_SGIX 0x842E #define GL_RESAMPLE_ZERO_FILL_SGIX 0x842F #define GL_RESAMPLE_DECIMATE_SGIX 0x8430 #endif #ifndef GL_SGIS_point_line_texgen #define GL_EYE_DISTANCE_TO_POINT_SGIS 0x81F0 #define GL_OBJECT_DISTANCE_TO_POINT_SGIS 0x81F1 #define GL_EYE_DISTANCE_TO_LINE_SGIS 0x81F2 #define GL_OBJECT_DISTANCE_TO_LINE_SGIS 0x81F3 #define GL_EYE_POINT_SGIS 0x81F4 #define GL_OBJECT_POINT_SGIS 0x81F5 #define GL_EYE_LINE_SGIS 0x81F6 #define GL_OBJECT_LINE_SGIS 0x81F7 #endif #ifndef GL_SGIS_texture_color_mask #define GL_TEXTURE_COLOR_WRITEMASK_SGIS 0x81EF #endif #ifndef GL_EXT_texture_env_dot3 #define GL_DOT3_RGB_EXT 0x8740 #define GL_DOT3_RGBA_EXT 0x8741 #endif #ifndef GL_ATI_texture_mirror_once #define GL_MIRROR_CLAMP_ATI 0x8742 #define GL_MIRROR_CLAMP_TO_EDGE_ATI 0x8743 #endif #ifndef GL_NV_fence #define GL_ALL_COMPLETED_NV 0x84F2 #define GL_FENCE_STATUS_NV 0x84F3 #define GL_FENCE_CONDITION_NV 0x84F4 #endif #ifndef GL_IBM_texture_mirrored_repeat #define GL_MIRRORED_REPEAT_IBM 0x8370 #endif #ifndef GL_NV_evaluators #define GL_EVAL_2D_NV 0x86C0 #define GL_EVAL_TRIANGULAR_2D_NV 0x86C1 #define GL_MAP_TESSELLATION_NV 0x86C2 #define GL_MAP_ATTRIB_U_ORDER_NV 0x86C3 #define GL_MAP_ATTRIB_V_ORDER_NV 0x86C4 #define GL_EVAL_FRACTIONAL_TESSELLATION_NV 0x86C5 #define GL_EVAL_VERTEX_ATTRIB0_NV 0x86C6 #define GL_EVAL_VERTEX_ATTRIB1_NV 0x86C7 #define GL_EVAL_VERTEX_ATTRIB2_NV 0x86C8 #define GL_EVAL_VERTEX_ATTRIB3_NV 0x86C9 #define GL_EVAL_VERTEX_ATTRIB4_NV 0x86CA #define GL_EVAL_VERTEX_ATTRIB5_NV 0x86CB #define GL_EVAL_VERTEX_ATTRIB6_NV 0x86CC #define GL_EVAL_VERTEX_ATTRIB7_NV 0x86CD #define GL_EVAL_VERTEX_ATTRIB8_NV 0x86CE #define GL_EVAL_VERTEX_ATTRIB9_NV 0x86CF #define GL_EVAL_VERTEX_ATTRIB10_NV 0x86D0 #define GL_EVAL_VERTEX_ATTRIB11_NV 0x86D1 #define GL_EVAL_VERTEX_ATTRIB12_NV 0x86D2 #define GL_EVAL_VERTEX_ATTRIB13_NV 0x86D3 #define GL_EVAL_VERTEX_ATTRIB14_NV 0x86D4 #define GL_EVAL_VERTEX_ATTRIB15_NV 0x86D5 #define GL_MAX_MAP_TESSELLATION_NV 0x86D6 #define GL_MAX_RATIONAL_EVAL_ORDER_NV 0x86D7 #endif #ifndef GL_NV_packed_depth_stencil #define GL_DEPTH_STENCIL_NV 0x84F9 #define GL_UNSIGNED_INT_24_8_NV 0x84FA #endif #ifndef GL_NV_register_combiners2 #define GL_PER_STAGE_CONSTANTS_NV 0x8535 #endif #ifndef GL_NV_texture_compression_vtc #endif #ifndef GL_NV_texture_rectangle #define GL_TEXTURE_RECTANGLE_NV 0x84F5 #define GL_TEXTURE_BINDING_RECTANGLE_NV 0x84F6 #define GL_PROXY_TEXTURE_RECTANGLE_NV 0x84F7 #define GL_MAX_RECTANGLE_TEXTURE_SIZE_NV 0x84F8 #endif #ifndef GL_NV_texture_shader #define GL_OFFSET_TEXTURE_RECTANGLE_NV 0x864C #define GL_OFFSET_TEXTURE_RECTANGLE_SCALE_NV 0x864D #define GL_DOT_PRODUCT_TEXTURE_RECTANGLE_NV 0x864E #define GL_RGBA_UNSIGNED_DOT_PRODUCT_MAPPING_NV 0x86D9 #define GL_UNSIGNED_INT_S8_S8_8_8_NV 0x86DA #define GL_UNSIGNED_INT_8_8_S8_S8_REV_NV 0x86DB #define GL_DSDT_MAG_INTENSITY_NV 0x86DC #define GL_SHADER_CONSISTENT_NV 0x86DD #define GL_TEXTURE_SHADER_NV 0x86DE #define GL_SHADER_OPERATION_NV 0x86DF #define GL_CULL_MODES_NV 0x86E0 #define GL_OFFSET_TEXTURE_MATRIX_NV 0x86E1 #define GL_OFFSET_TEXTURE_SCALE_NV 0x86E2 #define GL_OFFSET_TEXTURE_BIAS_NV 0x86E3 #define GL_OFFSET_TEXTURE_2D_MATRIX_NV GL_OFFSET_TEXTURE_MATRIX_NV #define GL_OFFSET_TEXTURE_2D_SCALE_NV GL_OFFSET_TEXTURE_SCALE_NV #define GL_OFFSET_TEXTURE_2D_BIAS_NV GL_OFFSET_TEXTURE_BIAS_NV #define GL_PREVIOUS_TEXTURE_INPUT_NV 0x86E4 #define GL_CONST_EYE_NV 0x86E5 #define GL_PASS_THROUGH_NV 0x86E6 #define GL_CULL_FRAGMENT_NV 0x86E7 #define GL_OFFSET_TEXTURE_2D_NV 0x86E8 #define GL_DEPENDENT_AR_TEXTURE_2D_NV 0x86E9 #define GL_DEPENDENT_GB_TEXTURE_2D_NV 0x86EA #define GL_DOT_PRODUCT_NV 0x86EC #define GL_DOT_PRODUCT_DEPTH_REPLACE_NV 0x86ED #define GL_DOT_PRODUCT_TEXTURE_2D_NV 0x86EE #define GL_DOT_PRODUCT_TEXTURE_CUBE_MAP_NV 0x86F0 #define GL_DOT_PRODUCT_DIFFUSE_CUBE_MAP_NV 0x86F1 #define GL_DOT_PRODUCT_REFLECT_CUBE_MAP_NV 0x86F2 #define GL_DOT_PRODUCT_CONST_EYE_REFLECT_CUBE_MAP_NV 0x86F3 #define GL_HILO_NV 0x86F4 #define GL_DSDT_NV 0x86F5 #define GL_DSDT_MAG_NV 0x86F6 #define GL_DSDT_MAG_VIB_NV 0x86F7 #define GL_HILO16_NV 0x86F8 #define GL_SIGNED_HILO_NV 0x86F9 #define GL_SIGNED_HILO16_NV 0x86FA #define GL_SIGNED_RGBA_NV 0x86FB #define GL_SIGNED_RGBA8_NV 0x86FC #define GL_SIGNED_RGB_NV 0x86FE #define GL_SIGNED_RGB8_NV 0x86FF #define GL_SIGNED_LUMINANCE_NV 0x8701 #define GL_SIGNED_LUMINANCE8_NV 0x8702 #define GL_SIGNED_LUMINANCE_ALPHA_NV 0x8703 #define GL_SIGNED_LUMINANCE8_ALPHA8_NV 0x8704 #define GL_SIGNED_ALPHA_NV 0x8705 #define GL_SIGNED_ALPHA8_NV 0x8706 #define GL_SIGNED_INTENSITY_NV 0x8707 #define GL_SIGNED_INTENSITY8_NV 0x8708 #define GL_DSDT8_NV 0x8709 #define GL_DSDT8_MAG8_NV 0x870A #define GL_DSDT8_MAG8_INTENSITY8_NV 0x870B #define GL_SIGNED_RGB_UNSIGNED_ALPHA_NV 0x870C #define GL_SIGNED_RGB8_UNSIGNED_ALPHA8_NV 0x870D #define GL_HI_SCALE_NV 0x870E #define GL_LO_SCALE_NV 0x870F #define GL_DS_SCALE_NV 0x8710 #define GL_DT_SCALE_NV 0x8711 #define GL_MAGNITUDE_SCALE_NV 0x8712 #define GL_VIBRANCE_SCALE_NV 0x8713 #define GL_HI_BIAS_NV 0x8714 #define GL_LO_BIAS_NV 0x8715 #define GL_DS_BIAS_NV 0x8716 #define GL_DT_BIAS_NV 0x8717 #define GL_MAGNITUDE_BIAS_NV 0x8718 #define GL_VIBRANCE_BIAS_NV 0x8719 #define GL_TEXTURE_BORDER_VALUES_NV 0x871A #define GL_TEXTURE_HI_SIZE_NV 0x871B #define GL_TEXTURE_LO_SIZE_NV 0x871C #define GL_TEXTURE_DS_SIZE_NV 0x871D #define GL_TEXTURE_DT_SIZE_NV 0x871E #define GL_TEXTURE_MAG_SIZE_NV 0x871F #endif #ifndef GL_NV_texture_shader2 #define GL_DOT_PRODUCT_TEXTURE_3D_NV 0x86EF #endif #ifndef GL_NV_vertex_array_range2 #define GL_VERTEX_ARRAY_RANGE_WITHOUT_FLUSH_NV 0x8533 #endif #ifndef GL_NV_vertex_program #define GL_VERTEX_PROGRAM_NV 0x8620 #define GL_VERTEX_STATE_PROGRAM_NV 0x8621 #define GL_ATTRIB_ARRAY_SIZE_NV 0x8623 #define GL_ATTRIB_ARRAY_STRIDE_NV 0x8624 #define GL_ATTRIB_ARRAY_TYPE_NV 0x8625 #define GL_CURRENT_ATTRIB_NV 0x8626 #define GL_PROGRAM_LENGTH_NV 0x8627 #define GL_PROGRAM_STRING_NV 0x8628 #define GL_MODELVIEW_PROJECTION_NV 0x8629 #define GL_IDENTITY_NV 0x862A #define GL_INVERSE_NV 0x862B #define GL_TRANSPOSE_NV 0x862C #define GL_INVERSE_TRANSPOSE_NV 0x862D #define GL_MAX_TRACK_MATRIX_STACK_DEPTH_NV 0x862E #define GL_MAX_TRACK_MATRICES_NV 0x862F #define GL_MATRIX0_NV 0x8630 #define GL_MATRIX1_NV 0x8631 #define GL_MATRIX2_NV 0x8632 #define GL_MATRIX3_NV 0x8633 #define GL_MATRIX4_NV 0x8634 #define GL_MATRIX5_NV 0x8635 #define GL_MATRIX6_NV 0x8636 #define GL_MATRIX7_NV 0x8637 #define GL_CURRENT_MATRIX_STACK_DEPTH_NV 0x8640 #define GL_CURRENT_MATRIX_NV 0x8641 #define GL_VERTEX_PROGRAM_POINT_SIZE_NV 0x8642 #define GL_VERTEX_PROGRAM_TWO_SIDE_NV 0x8643 #define GL_PROGRAM_PARAMETER_NV 0x8644 #define GL_ATTRIB_ARRAY_POINTER_NV 0x8645 #define GL_PROGRAM_TARGET_NV 0x8646 #define GL_PROGRAM_RESIDENT_NV 0x8647 #define GL_TRACK_MATRIX_NV 0x8648 #define GL_TRACK_MATRIX_TRANSFORM_NV 0x8649 #define GL_VERTEX_PROGRAM_BINDING_NV 0x864A #define GL_PROGRAM_ERROR_POSITION_NV 0x864B #define GL_VERTEX_ATTRIB_ARRAY0_NV 0x8650 #define GL_VERTEX_ATTRIB_ARRAY1_NV 0x8651 #define GL_VERTEX_ATTRIB_ARRAY2_NV 0x8652 #define GL_VERTEX_ATTRIB_ARRAY3_NV 0x8653 #define GL_VERTEX_ATTRIB_ARRAY4_NV 0x8654 #define GL_VERTEX_ATTRIB_ARRAY5_NV 0x8655 #define GL_VERTEX_ATTRIB_ARRAY6_NV 0x8656 #define GL_VERTEX_ATTRIB_ARRAY7_NV 0x8657 #define GL_VERTEX_ATTRIB_ARRAY8_NV 0x8658 #define GL_VERTEX_ATTRIB_ARRAY9_NV 0x8659 #define GL_VERTEX_ATTRIB_ARRAY10_NV 0x865A #define GL_VERTEX_ATTRIB_ARRAY11_NV 0x865B #define GL_VERTEX_ATTRIB_ARRAY12_NV 0x865C #define GL_VERTEX_ATTRIB_ARRAY13_NV 0x865D #define GL_VERTEX_ATTRIB_ARRAY14_NV 0x865E #define GL_VERTEX_ATTRIB_ARRAY15_NV 0x865F #define GL_MAP1_VERTEX_ATTRIB0_4_NV 0x8660 #define GL_MAP1_VERTEX_ATTRIB1_4_NV 0x8661 #define GL_MAP1_VERTEX_ATTRIB2_4_NV 0x8662 #define GL_MAP1_VERTEX_ATTRIB3_4_NV 0x8663 #define GL_MAP1_VERTEX_ATTRIB4_4_NV 0x8664 #define GL_MAP1_VERTEX_ATTRIB5_4_NV 0x8665 #define GL_MAP1_VERTEX_ATTRIB6_4_NV 0x8666 #define GL_MAP1_VERTEX_ATTRIB7_4_NV 0x8667 #define GL_MAP1_VERTEX_ATTRIB8_4_NV 0x8668 #define GL_MAP1_VERTEX_ATTRIB9_4_NV 0x8669 #define GL_MAP1_VERTEX_ATTRIB10_4_NV 0x866A #define GL_MAP1_VERTEX_ATTRIB11_4_NV 0x866B #define GL_MAP1_VERTEX_ATTRIB12_4_NV 0x866C #define GL_MAP1_VERTEX_ATTRIB13_4_NV 0x866D #define GL_MAP1_VERTEX_ATTRIB14_4_NV 0x866E #define GL_MAP1_VERTEX_ATTRIB15_4_NV 0x866F #define GL_MAP2_VERTEX_ATTRIB0_4_NV 0x8670 #define GL_MAP2_VERTEX_ATTRIB1_4_NV 0x8671 #define GL_MAP2_VERTEX_ATTRIB2_4_NV 0x8672 #define GL_MAP2_VERTEX_ATTRIB3_4_NV 0x8673 #define GL_MAP2_VERTEX_ATTRIB4_4_NV 0x8674 #define GL_MAP2_VERTEX_ATTRIB5_4_NV 0x8675 #define GL_MAP2_VERTEX_ATTRIB6_4_NV 0x8676 #define GL_MAP2_VERTEX_ATTRIB7_4_NV 0x8677 #define GL_MAP2_VERTEX_ATTRIB8_4_NV 0x8678 #define GL_MAP2_VERTEX_ATTRIB9_4_NV 0x8679 #define GL_MAP2_VERTEX_ATTRIB10_4_NV 0x867A #define GL_MAP2_VERTEX_ATTRIB11_4_NV 0x867B #define GL_MAP2_VERTEX_ATTRIB12_4_NV 0x867C #define GL_MAP2_VERTEX_ATTRIB13_4_NV 0x867D #define GL_MAP2_VERTEX_ATTRIB14_4_NV 0x867E #define GL_MAP2_VERTEX_ATTRIB15_4_NV 0x867F #endif #ifndef GL_SGIX_texture_coordinate_clamp #define GL_TEXTURE_MAX_CLAMP_S_SGIX 0x8369 #define GL_TEXTURE_MAX_CLAMP_T_SGIX 0x836A #define GL_TEXTURE_MAX_CLAMP_R_SGIX 0x836B #endif #ifndef GL_SGIX_scalebias_hint #define GL_SCALEBIAS_HINT_SGIX 0x8322 #endif #ifndef GL_OML_interlace #define GL_INTERLACE_OML 0x8980 #define GL_INTERLACE_READ_OML 0x8981 #endif #ifndef GL_OML_subsample #define GL_FORMAT_SUBSAMPLE_24_24_OML 0x8982 #define GL_FORMAT_SUBSAMPLE_244_244_OML 0x8983 #endif #ifndef GL_OML_resample #define GL_PACK_RESAMPLE_OML 0x8984 #define GL_UNPACK_RESAMPLE_OML 0x8985 #define GL_RESAMPLE_REPLICATE_OML 0x8986 #define GL_RESAMPLE_ZERO_FILL_OML 0x8987 #define GL_RESAMPLE_AVERAGE_OML 0x8988 #define GL_RESAMPLE_DECIMATE_OML 0x8989 #endif #ifndef GL_NV_copy_depth_to_color #define GL_DEPTH_STENCIL_TO_RGBA_NV 0x886E #define GL_DEPTH_STENCIL_TO_BGRA_NV 0x886F #endif #ifndef GL_ATI_envmap_bumpmap #define GL_BUMP_ROT_MATRIX_ATI 0x8775 #define GL_BUMP_ROT_MATRIX_SIZE_ATI 0x8776 #define GL_BUMP_NUM_TEX_UNITS_ATI 0x8777 #define GL_BUMP_TEX_UNITS_ATI 0x8778 #define GL_DUDV_ATI 0x8779 #define GL_DU8DV8_ATI 0x877A #define GL_BUMP_ENVMAP_ATI 0x877B #define GL_BUMP_TARGET_ATI 0x877C #endif #ifndef GL_ATI_fragment_shader #define GL_FRAGMENT_SHADER_ATI 0x8920 #define GL_REG_0_ATI 0x8921 #define GL_REG_1_ATI 0x8922 #define GL_REG_2_ATI 0x8923 #define GL_REG_3_ATI 0x8924 #define GL_REG_4_ATI 0x8925 #define GL_REG_5_ATI 0x8926 #define GL_REG_6_ATI 0x8927 #define GL_REG_7_ATI 0x8928 #define GL_REG_8_ATI 0x8929 #define GL_REG_9_ATI 0x892A #define GL_REG_10_ATI 0x892B #define GL_REG_11_ATI 0x892C #define GL_REG_12_ATI 0x892D #define GL_REG_13_ATI 0x892E #define GL_REG_14_ATI 0x892F #define GL_REG_15_ATI 0x8930 #define GL_REG_16_ATI 0x8931 #define GL_REG_17_ATI 0x8932 #define GL_REG_18_ATI 0x8933 #define GL_REG_19_ATI 0x8934 #define GL_REG_20_ATI 0x8935 #define GL_REG_21_ATI 0x8936 #define GL_REG_22_ATI 0x8937 #define GL_REG_23_ATI 0x8938 #define GL_REG_24_ATI 0x8939 #define GL_REG_25_ATI 0x893A #define GL_REG_26_ATI 0x893B #define GL_REG_27_ATI 0x893C #define GL_REG_28_ATI 0x893D #define GL_REG_29_ATI 0x893E #define GL_REG_30_ATI 0x893F #define GL_REG_31_ATI 0x8940 #define GL_CON_0_ATI 0x8941 #define GL_CON_1_ATI 0x8942 #define GL_CON_2_ATI 0x8943 #define GL_CON_3_ATI 0x8944 #define GL_CON_4_ATI 0x8945 #define GL_CON_5_ATI 0x8946 #define GL_CON_6_ATI 0x8947 #define GL_CON_7_ATI 0x8948 #define GL_CON_8_ATI 0x8949 #define GL_CON_9_ATI 0x894A #define GL_CON_10_ATI 0x894B #define GL_CON_11_ATI 0x894C #define GL_CON_12_ATI 0x894D #define GL_CON_13_ATI 0x894E #define GL_CON_14_ATI 0x894F #define GL_CON_15_ATI 0x8950 #define GL_CON_16_ATI 0x8951 #define GL_CON_17_ATI 0x8952 #define GL_CON_18_ATI 0x8953 #define GL_CON_19_ATI 0x8954 #define GL_CON_20_ATI 0x8955 #define GL_CON_21_ATI 0x8956 #define GL_CON_22_ATI 0x8957 #define GL_CON_23_ATI 0x8958 #define GL_CON_24_ATI 0x8959 #define GL_CON_25_ATI 0x895A #define GL_CON_26_ATI 0x895B #define GL_CON_27_ATI 0x895C #define GL_CON_28_ATI 0x895D #define GL_CON_29_ATI 0x895E #define GL_CON_30_ATI 0x895F #define GL_CON_31_ATI 0x8960 #define GL_MOV_ATI 0x8961 #define GL_ADD_ATI 0x8963 #define GL_MUL_ATI 0x8964 #define GL_SUB_ATI 0x8965 #define GL_DOT3_ATI 0x8966 #define GL_DOT4_ATI 0x8967 #define GL_MAD_ATI 0x8968 #define GL_LERP_ATI 0x8969 #define GL_CND_ATI 0x896A #define GL_CND0_ATI 0x896B #define GL_DOT2_ADD_ATI 0x896C #define GL_SECONDARY_INTERPOLATOR_ATI 0x896D #define GL_NUM_FRAGMENT_REGISTERS_ATI 0x896E #define GL_NUM_FRAGMENT_CONSTANTS_ATI 0x896F #define GL_NUM_PASSES_ATI 0x8970 #define GL_NUM_INSTRUCTIONS_PER_PASS_ATI 0x8971 #define GL_NUM_INSTRUCTIONS_TOTAL_ATI 0x8972 #define GL_NUM_INPUT_INTERPOLATOR_COMPONENTS_ATI 0x8973 #define GL_NUM_LOOPBACK_COMPONENTS_ATI 0x8974 #define GL_COLOR_ALPHA_PAIRING_ATI 0x8975 #define GL_SWIZZLE_STR_ATI 0x8976 #define GL_SWIZZLE_STQ_ATI 0x8977 #define GL_SWIZZLE_STR_DR_ATI 0x8978 #define GL_SWIZZLE_STQ_DQ_ATI 0x8979 #define GL_SWIZZLE_STRQ_ATI 0x897A #define GL_SWIZZLE_STRQ_DQ_ATI 0x897B #define GL_RED_BIT_ATI 0x00000001 #define GL_GREEN_BIT_ATI 0x00000002 #define GL_BLUE_BIT_ATI 0x00000004 #define GL_2X_BIT_ATI 0x00000001 #define GL_4X_BIT_ATI 0x00000002 #define GL_8X_BIT_ATI 0x00000004 #define GL_HALF_BIT_ATI 0x00000008 #define GL_QUARTER_BIT_ATI 0x00000010 #define GL_EIGHTH_BIT_ATI 0x00000020 #define GL_SATURATE_BIT_ATI 0x00000040 #define GL_COMP_BIT_ATI 0x00000002 #define GL_NEGATE_BIT_ATI 0x00000004 #define GL_BIAS_BIT_ATI 0x00000008 #endif #ifndef GL_ATI_pn_triangles #define GL_PN_TRIANGLES_ATI 0x87F0 #define GL_MAX_PN_TRIANGLES_TESSELATION_LEVEL_ATI 0x87F1 #define GL_PN_TRIANGLES_POINT_MODE_ATI 0x87F2 #define GL_PN_TRIANGLES_NORMAL_MODE_ATI 0x87F3 #define GL_PN_TRIANGLES_TESSELATION_LEVEL_ATI 0x87F4 #define GL_PN_TRIANGLES_POINT_MODE_LINEAR_ATI 0x87F5 #define GL_PN_TRIANGLES_POINT_MODE_CUBIC_ATI 0x87F6 #define GL_PN_TRIANGLES_NORMAL_MODE_LINEAR_ATI 0x87F7 #define GL_PN_TRIANGLES_NORMAL_MODE_QUADRATIC_ATI 0x87F8 #endif #ifndef GL_ATI_vertex_array_object #define GL_STATIC_ATI 0x8760 #define GL_DYNAMIC_ATI 0x8761 #define GL_PRESERVE_ATI 0x8762 #define GL_DISCARD_ATI 0x8763 #define GL_OBJECT_BUFFER_SIZE_ATI 0x8764 #define GL_OBJECT_BUFFER_USAGE_ATI 0x8765 #define GL_ARRAY_OBJECT_BUFFER_ATI 0x8766 #define GL_ARRAY_OBJECT_OFFSET_ATI 0x8767 #endif #ifndef GL_EXT_vertex_shader #define GL_VERTEX_SHADER_EXT 0x8780 #define GL_VERTEX_SHADER_BINDING_EXT 0x8781 #define GL_OP_INDEX_EXT 0x8782 #define GL_OP_NEGATE_EXT 0x8783 #define GL_OP_DOT3_EXT 0x8784 #define GL_OP_DOT4_EXT 0x8785 #define GL_OP_MUL_EXT 0x8786 #define GL_OP_ADD_EXT 0x8787 #define GL_OP_MADD_EXT 0x8788 #define GL_OP_FRAC_EXT 0x8789 #define GL_OP_MAX_EXT 0x878A #define GL_OP_MIN_EXT 0x878B #define GL_OP_SET_GE_EXT 0x878C #define GL_OP_SET_LT_EXT 0x878D #define GL_OP_CLAMP_EXT 0x878E #define GL_OP_FLOOR_EXT 0x878F #define GL_OP_ROUND_EXT 0x8790 #define GL_OP_EXP_BASE_2_EXT 0x8791 #define GL_OP_LOG_BASE_2_EXT 0x8792 #define GL_OP_POWER_EXT 0x8793 #define GL_OP_RECIP_EXT 0x8794 #define GL_OP_RECIP_SQRT_EXT 0x8795 #define GL_OP_SUB_EXT 0x8796 #define GL_OP_CROSS_PRODUCT_EXT 0x8797 #define GL_OP_MULTIPLY_MATRIX_EXT 0x8798 #define GL_OP_MOV_EXT 0x8799 #define GL_OUTPUT_VERTEX_EXT 0x879A #define GL_OUTPUT_COLOR0_EXT 0x879B #define GL_OUTPUT_COLOR1_EXT 0x879C #define GL_OUTPUT_TEXTURE_COORD0_EXT 0x879D #define GL_OUTPUT_TEXTURE_COORD1_EXT 0x879E #define GL_OUTPUT_TEXTURE_COORD2_EXT 0x879F #define GL_OUTPUT_TEXTURE_COORD3_EXT 0x87A0 #define GL_OUTPUT_TEXTURE_COORD4_EXT 0x87A1 #define GL_OUTPUT_TEXTURE_COORD5_EXT 0x87A2 #define GL_OUTPUT_TEXTURE_COORD6_EXT 0x87A3 #define GL_OUTPUT_TEXTURE_COORD7_EXT 0x87A4 #define GL_OUTPUT_TEXTURE_COORD8_EXT 0x87A5 #define GL_OUTPUT_TEXTURE_COORD9_EXT 0x87A6 #define GL_OUTPUT_TEXTURE_COORD10_EXT 0x87A7 #define GL_OUTPUT_TEXTURE_COORD11_EXT 0x87A8 #define GL_OUTPUT_TEXTURE_COORD12_EXT 0x87A9 #define GL_OUTPUT_TEXTURE_COORD13_EXT 0x87AA #define GL_OUTPUT_TEXTURE_COORD14_EXT 0x87AB #define GL_OUTPUT_TEXTURE_COORD15_EXT 0x87AC #define GL_OUTPUT_TEXTURE_COORD16_EXT 0x87AD #define GL_OUTPUT_TEXTURE_COORD17_EXT 0x87AE #define GL_OUTPUT_TEXTURE_COORD18_EXT 0x87AF #define GL_OUTPUT_TEXTURE_COORD19_EXT 0x87B0 #define GL_OUTPUT_TEXTURE_COORD20_EXT 0x87B1 #define GL_OUTPUT_TEXTURE_COORD21_EXT 0x87B2 #define GL_OUTPUT_TEXTURE_COORD22_EXT 0x87B3 #define GL_OUTPUT_TEXTURE_COORD23_EXT 0x87B4 #define GL_OUTPUT_TEXTURE_COORD24_EXT 0x87B5 #define GL_OUTPUT_TEXTURE_COORD25_EXT 0x87B6 #define GL_OUTPUT_TEXTURE_COORD26_EXT 0x87B7 #define GL_OUTPUT_TEXTURE_COORD27_EXT 0x87B8 #define GL_OUTPUT_TEXTURE_COORD28_EXT 0x87B9 #define GL_OUTPUT_TEXTURE_COORD29_EXT 0x87BA #define GL_OUTPUT_TEXTURE_COORD30_EXT 0x87BB #define GL_OUTPUT_TEXTURE_COORD31_EXT 0x87BC #define GL_OUTPUT_FOG_EXT 0x87BD #define GL_SCALAR_EXT 0x87BE #define GL_VECTOR_EXT 0x87BF #define GL_MATRIX_EXT 0x87C0 #define GL_VARIANT_EXT 0x87C1 #define GL_INVARIANT_EXT 0x87C2 #define GL_LOCAL_CONSTANT_EXT 0x87C3 #define GL_LOCAL_EXT 0x87C4 #define GL_MAX_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87C5 #define GL_MAX_VERTEX_SHADER_VARIANTS_EXT 0x87C6 #define GL_MAX_VERTEX_SHADER_INVARIANTS_EXT 0x87C7 #define GL_MAX_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87C8 #define GL_MAX_VERTEX_SHADER_LOCALS_EXT 0x87C9 #define GL_MAX_OPTIMIZED_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87CA #define GL_MAX_OPTIMIZED_VERTEX_SHADER_VARIANTS_EXT 0x87CB #define GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87CC #define GL_MAX_OPTIMIZED_VERTEX_SHADER_INVARIANTS_EXT 0x87CD #define GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCALS_EXT 0x87CE #define GL_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87CF #define GL_VERTEX_SHADER_VARIANTS_EXT 0x87D0 #define GL_VERTEX_SHADER_INVARIANTS_EXT 0x87D1 #define GL_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87D2 #define GL_VERTEX_SHADER_LOCALS_EXT 0x87D3 #define GL_VERTEX_SHADER_OPTIMIZED_EXT 0x87D4 #define GL_X_EXT 0x87D5 #define GL_Y_EXT 0x87D6 #define GL_Z_EXT 0x87D7 #define GL_W_EXT 0x87D8 #define GL_NEGATIVE_X_EXT 0x87D9 #define GL_NEGATIVE_Y_EXT 0x87DA #define GL_NEGATIVE_Z_EXT 0x87DB #define GL_NEGATIVE_W_EXT 0x87DC #define GL_ZERO_EXT 0x87DD #define GL_ONE_EXT 0x87DE #define GL_NEGATIVE_ONE_EXT 0x87DF #define GL_NORMALIZED_RANGE_EXT 0x87E0 #define GL_FULL_RANGE_EXT 0x87E1 #define GL_CURRENT_VERTEX_EXT 0x87E2 #define GL_MVP_MATRIX_EXT 0x87E3 #define GL_VARIANT_VALUE_EXT 0x87E4 #define GL_VARIANT_DATATYPE_EXT 0x87E5 #define GL_VARIANT_ARRAY_STRIDE_EXT 0x87E6 #define GL_VARIANT_ARRAY_TYPE_EXT 0x87E7 #define GL_VARIANT_ARRAY_EXT 0x87E8 #define GL_VARIANT_ARRAY_POINTER_EXT 0x87E9 #define GL_INVARIANT_VALUE_EXT 0x87EA #define GL_INVARIANT_DATATYPE_EXT 0x87EB #define GL_LOCAL_CONSTANT_VALUE_EXT 0x87EC #define GL_LOCAL_CONSTANT_DATATYPE_EXT 0x87ED #endif #ifndef GL_ATI_vertex_streams #define GL_MAX_VERTEX_STREAMS_ATI 0x876B #define GL_VERTEX_STREAM0_ATI 0x876C #define GL_VERTEX_STREAM1_ATI 0x876D #define GL_VERTEX_STREAM2_ATI 0x876E #define GL_VERTEX_STREAM3_ATI 0x876F #define GL_VERTEX_STREAM4_ATI 0x8770 #define GL_VERTEX_STREAM5_ATI 0x8771 #define GL_VERTEX_STREAM6_ATI 0x8772 #define GL_VERTEX_STREAM7_ATI 0x8773 #define GL_VERTEX_SOURCE_ATI 0x8774 #endif #ifndef GL_ATI_element_array #define GL_ELEMENT_ARRAY_ATI 0x8768 #define GL_ELEMENT_ARRAY_TYPE_ATI 0x8769 #define GL_ELEMENT_ARRAY_POINTER_ATI 0x876A #endif #ifndef GL_SUN_mesh_array #define GL_QUAD_MESH_SUN 0x8614 #define GL_TRIANGLE_MESH_SUN 0x8615 #endif #ifndef GL_SUN_slice_accum #define GL_SLICE_ACCUM_SUN 0x85CC #endif #ifndef GL_NV_multisample_filter_hint #define GL_MULTISAMPLE_FILTER_HINT_NV 0x8534 #endif #ifndef GL_NV_depth_clamp #define GL_DEPTH_CLAMP_NV 0x864F #endif #ifndef GL_NV_occlusion_query #define GL_PIXEL_COUNTER_BITS_NV 0x8864 #define GL_CURRENT_OCCLUSION_QUERY_ID_NV 0x8865 #define GL_PIXEL_COUNT_NV 0x8866 #define GL_PIXEL_COUNT_AVAILABLE_NV 0x8867 #endif #ifndef GL_NV_point_sprite #define GL_POINT_SPRITE_NV 0x8861 #define GL_COORD_REPLACE_NV 0x8862 #define GL_POINT_SPRITE_R_MODE_NV 0x8863 #endif #ifndef GL_NV_texture_shader3 #define GL_OFFSET_PROJECTIVE_TEXTURE_2D_NV 0x8850 #define GL_OFFSET_PROJECTIVE_TEXTURE_2D_SCALE_NV 0x8851 #define GL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_NV 0x8852 #define GL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_SCALE_NV 0x8853 #define GL_OFFSET_HILO_TEXTURE_2D_NV 0x8854 #define GL_OFFSET_HILO_TEXTURE_RECTANGLE_NV 0x8855 #define GL_OFFSET_HILO_PROJECTIVE_TEXTURE_2D_NV 0x8856 #define GL_OFFSET_HILO_PROJECTIVE_TEXTURE_RECTANGLE_NV 0x8857 #define GL_DEPENDENT_HILO_TEXTURE_2D_NV 0x8858 #define GL_DEPENDENT_RGB_TEXTURE_3D_NV 0x8859 #define GL_DEPENDENT_RGB_TEXTURE_CUBE_MAP_NV 0x885A #define GL_DOT_PRODUCT_PASS_THROUGH_NV 0x885B #define GL_DOT_PRODUCT_TEXTURE_1D_NV 0x885C #define GL_DOT_PRODUCT_AFFINE_DEPTH_REPLACE_NV 0x885D #define GL_HILO8_NV 0x885E #define GL_SIGNED_HILO8_NV 0x885F #define GL_FORCE_BLUE_TO_ONE_NV 0x8860 #endif #ifndef GL_NV_vertex_program1_1 #endif #ifndef GL_EXT_shadow_funcs #endif #ifndef GL_EXT_stencil_two_side #define GL_STENCIL_TEST_TWO_SIDE_EXT 0x8910 #define GL_ACTIVE_STENCIL_FACE_EXT 0x8911 #endif #ifndef GL_ATI_text_fragment_shader #define GL_TEXT_FRAGMENT_SHADER_ATI 0x8200 #endif #ifndef GL_APPLE_client_storage #define GL_UNPACK_CLIENT_STORAGE_APPLE 0x85B2 #endif #ifndef GL_APPLE_element_array #define GL_ELEMENT_ARRAY_APPLE 0x8768 #define GL_ELEMENT_ARRAY_TYPE_APPLE 0x8769 #define GL_ELEMENT_ARRAY_POINTER_APPLE 0x876A #endif #ifndef GL_APPLE_fence #define GL_DRAW_PIXELS_APPLE 0x8A0A #define GL_FENCE_APPLE 0x8A0B #endif #ifndef GL_APPLE_vertex_array_object #define GL_VERTEX_ARRAY_BINDING_APPLE 0x85B5 #endif #ifndef GL_APPLE_vertex_array_range #define GL_VERTEX_ARRAY_RANGE_APPLE 0x851D #define GL_VERTEX_ARRAY_RANGE_LENGTH_APPLE 0x851E #define GL_VERTEX_ARRAY_STORAGE_HINT_APPLE 0x851F #define GL_VERTEX_ARRAY_RANGE_POINTER_APPLE 0x8521 #define GL_STORAGE_CACHED_APPLE 0x85BE #define GL_STORAGE_SHARED_APPLE 0x85BF #endif #ifndef GL_APPLE_ycbcr_422 #define GL_YCBCR_422_APPLE 0x85B9 #define GL_UNSIGNED_SHORT_8_8_APPLE 0x85BA #define GL_UNSIGNED_SHORT_8_8_REV_APPLE 0x85BB #endif #ifndef GL_S3_s3tc #define GL_RGB_S3TC 0x83A0 #define GL_RGB4_S3TC 0x83A1 #define GL_RGBA_S3TC 0x83A2 #define GL_RGBA4_S3TC 0x83A3 #endif #ifndef GL_ATI_draw_buffers #define GL_MAX_DRAW_BUFFERS_ATI 0x8824 #define GL_DRAW_BUFFER0_ATI 0x8825 #define GL_DRAW_BUFFER1_ATI 0x8826 #define GL_DRAW_BUFFER2_ATI 0x8827 #define GL_DRAW_BUFFER3_ATI 0x8828 #define GL_DRAW_BUFFER4_ATI 0x8829 #define GL_DRAW_BUFFER5_ATI 0x882A #define GL_DRAW_BUFFER6_ATI 0x882B #define GL_DRAW_BUFFER7_ATI 0x882C #define GL_DRAW_BUFFER8_ATI 0x882D #define GL_DRAW_BUFFER9_ATI 0x882E #define GL_DRAW_BUFFER10_ATI 0x882F #define GL_DRAW_BUFFER11_ATI 0x8830 #define GL_DRAW_BUFFER12_ATI 0x8831 #define GL_DRAW_BUFFER13_ATI 0x8832 #define GL_DRAW_BUFFER14_ATI 0x8833 #define GL_DRAW_BUFFER15_ATI 0x8834 #endif #ifndef GL_ATI_pixel_format_float #define GL_TYPE_RGBA_FLOAT_ATI 0x8820 #define GL_COLOR_CLEAR_UNCLAMPED_VALUE_ATI 0x8835 #endif #ifndef GL_ATI_texture_env_combine3 #define GL_MODULATE_ADD_ATI 0x8744 #define GL_MODULATE_SIGNED_ADD_ATI 0x8745 #define GL_MODULATE_SUBTRACT_ATI 0x8746 #endif #ifndef GL_ATI_texture_float #define GL_RGBA_FLOAT32_ATI 0x8814 #define GL_RGB_FLOAT32_ATI 0x8815 #define GL_ALPHA_FLOAT32_ATI 0x8816 #define GL_INTENSITY_FLOAT32_ATI 0x8817 #define GL_LUMINANCE_FLOAT32_ATI 0x8818 #define GL_LUMINANCE_ALPHA_FLOAT32_ATI 0x8819 #define GL_RGBA_FLOAT16_ATI 0x881A #define GL_RGB_FLOAT16_ATI 0x881B #define GL_ALPHA_FLOAT16_ATI 0x881C #define GL_INTENSITY_FLOAT16_ATI 0x881D #define GL_LUMINANCE_FLOAT16_ATI 0x881E #define GL_LUMINANCE_ALPHA_FLOAT16_ATI 0x881F #endif #ifndef GL_NV_float_buffer #define GL_FLOAT_R_NV 0x8880 #define GL_FLOAT_RG_NV 0x8881 #define GL_FLOAT_RGB_NV 0x8882 #define GL_FLOAT_RGBA_NV 0x8883 #define GL_FLOAT_R16_NV 0x8884 #define GL_FLOAT_R32_NV 0x8885 #define GL_FLOAT_RG16_NV 0x8886 #define GL_FLOAT_RG32_NV 0x8887 #define GL_FLOAT_RGB16_NV 0x8888 #define GL_FLOAT_RGB32_NV 0x8889 #define GL_FLOAT_RGBA16_NV 0x888A #define GL_FLOAT_RGBA32_NV 0x888B #define GL_TEXTURE_FLOAT_COMPONENTS_NV 0x888C #define GL_FLOAT_CLEAR_COLOR_VALUE_NV 0x888D #define GL_FLOAT_RGBA_MODE_NV 0x888E #endif #ifndef GL_NV_fragment_program #define GL_MAX_FRAGMENT_PROGRAM_LOCAL_PARAMETERS_NV 0x8868 #define GL_FRAGMENT_PROGRAM_NV 0x8870 #define GL_MAX_TEXTURE_COORDS_NV 0x8871 #define GL_MAX_TEXTURE_IMAGE_UNITS_NV 0x8872 #define GL_FRAGMENT_PROGRAM_BINDING_NV 0x8873 #define GL_PROGRAM_ERROR_STRING_NV 0x8874 #endif #ifndef GL_NV_half_float #define GL_HALF_FLOAT_NV 0x140B #endif #ifndef GL_NV_pixel_data_range #define GL_WRITE_PIXEL_DATA_RANGE_NV 0x8878 #define GL_READ_PIXEL_DATA_RANGE_NV 0x8879 #define GL_WRITE_PIXEL_DATA_RANGE_LENGTH_NV 0x887A #define GL_READ_PIXEL_DATA_RANGE_LENGTH_NV 0x887B #define GL_WRITE_PIXEL_DATA_RANGE_POINTER_NV 0x887C #define GL_READ_PIXEL_DATA_RANGE_POINTER_NV 0x887D #endif #ifndef GL_NV_primitive_restart #define GL_PRIMITIVE_RESTART_NV 0x8558 #define GL_PRIMITIVE_RESTART_INDEX_NV 0x8559 #endif #ifndef GL_NV_texture_expand_normal #define GL_TEXTURE_UNSIGNED_REMAP_MODE_NV 0x888F #endif #ifndef GL_NV_vertex_program2 #endif #ifndef GL_ATI_map_object_buffer #endif #ifndef GL_ATI_separate_stencil #define GL_STENCIL_BACK_FUNC_ATI 0x8800 #define GL_STENCIL_BACK_FAIL_ATI 0x8801 #define GL_STENCIL_BACK_PASS_DEPTH_FAIL_ATI 0x8802 #define GL_STENCIL_BACK_PASS_DEPTH_PASS_ATI 0x8803 #endif #ifndef GL_ATI_vertex_attrib_array_object #endif #ifndef GL_OES_read_format #define GL_IMPLEMENTATION_COLOR_READ_TYPE_OES 0x8B9A #define GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES 0x8B9B #endif #ifndef GL_EXT_depth_bounds_test #define GL_DEPTH_BOUNDS_TEST_EXT 0x8890 #define GL_DEPTH_BOUNDS_EXT 0x8891 #endif #ifndef GL_EXT_texture_mirror_clamp #define GL_MIRROR_CLAMP_EXT 0x8742 #define GL_MIRROR_CLAMP_TO_EDGE_EXT 0x8743 #define GL_MIRROR_CLAMP_TO_BORDER_EXT 0x8912 #endif #ifndef GL_EXT_blend_equation_separate #define GL_BLEND_EQUATION_RGB_EXT GL_BLEND_EQUATION #define GL_BLEND_EQUATION_ALPHA_EXT 0x883D #endif #ifndef GL_MESA_pack_invert #define GL_PACK_INVERT_MESA 0x8758 #endif #ifndef GL_MESA_ycbcr_texture #define GL_UNSIGNED_SHORT_8_8_MESA 0x85BA #define GL_UNSIGNED_SHORT_8_8_REV_MESA 0x85BB #define GL_YCBCR_MESA 0x8757 #endif #ifndef GL_EXT_pixel_buffer_object #define GL_PIXEL_PACK_BUFFER_EXT 0x88EB #define GL_PIXEL_UNPACK_BUFFER_EXT 0x88EC #define GL_PIXEL_PACK_BUFFER_BINDING_EXT 0x88ED #define GL_PIXEL_UNPACK_BUFFER_BINDING_EXT 0x88EF #endif #ifndef GL_NV_fragment_program_option #endif #ifndef GL_NV_fragment_program2 #define GL_MAX_PROGRAM_EXEC_INSTRUCTIONS_NV 0x88F4 #define GL_MAX_PROGRAM_CALL_DEPTH_NV 0x88F5 #define GL_MAX_PROGRAM_IF_DEPTH_NV 0x88F6 #define GL_MAX_PROGRAM_LOOP_DEPTH_NV 0x88F7 #define GL_MAX_PROGRAM_LOOP_COUNT_NV 0x88F8 #endif #ifndef GL_NV_vertex_program2_option /* reuse GL_MAX_PROGRAM_EXEC_INSTRUCTIONS_NV */ /* reuse GL_MAX_PROGRAM_CALL_DEPTH_NV */ #endif #ifndef GL_NV_vertex_program3 /* reuse GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB */ #endif #ifndef GL_EXT_framebuffer_object #define GL_INVALID_FRAMEBUFFER_OPERATION_EXT 0x0506 #define GL_MAX_RENDERBUFFER_SIZE_EXT 0x84E8 #define GL_FRAMEBUFFER_BINDING_EXT 0x8CA6 #define GL_RENDERBUFFER_BINDING_EXT 0x8CA7 #define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT 0x8CD0 #define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT 0x8CD1 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT 0x8CD2 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT 0x8CD3 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT 0x8CD4 #define GL_FRAMEBUFFER_COMPLETE_EXT 0x8CD5 #define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT 0x8CD6 #define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT 0x8CD7 #define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT 0x8CD9 #define GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT 0x8CDA #define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT 0x8CDB #define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT 0x8CDC #define GL_FRAMEBUFFER_UNSUPPORTED_EXT 0x8CDD #define GL_MAX_COLOR_ATTACHMENTS_EXT 0x8CDF #define GL_COLOR_ATTACHMENT0_EXT 0x8CE0 #define GL_COLOR_ATTACHMENT1_EXT 0x8CE1 #define GL_COLOR_ATTACHMENT2_EXT 0x8CE2 #define GL_COLOR_ATTACHMENT3_EXT 0x8CE3 #define GL_COLOR_ATTACHMENT4_EXT 0x8CE4 #define GL_COLOR_ATTACHMENT5_EXT 0x8CE5 #define GL_COLOR_ATTACHMENT6_EXT 0x8CE6 #define GL_COLOR_ATTACHMENT7_EXT 0x8CE7 #define GL_COLOR_ATTACHMENT8_EXT 0x8CE8 #define GL_COLOR_ATTACHMENT9_EXT 0x8CE9 #define GL_COLOR_ATTACHMENT10_EXT 0x8CEA #define GL_COLOR_ATTACHMENT11_EXT 0x8CEB #define GL_COLOR_ATTACHMENT12_EXT 0x8CEC #define GL_COLOR_ATTACHMENT13_EXT 0x8CED #define GL_COLOR_ATTACHMENT14_EXT 0x8CEE #define GL_COLOR_ATTACHMENT15_EXT 0x8CEF #define GL_DEPTH_ATTACHMENT_EXT 0x8D00 #define GL_STENCIL_ATTACHMENT_EXT 0x8D20 #define GL_FRAMEBUFFER_EXT 0x8D40 #define GL_RENDERBUFFER_EXT 0x8D41 #define GL_RENDERBUFFER_WIDTH_EXT 0x8D42 #define GL_RENDERBUFFER_HEIGHT_EXT 0x8D43 #define GL_RENDERBUFFER_INTERNAL_FORMAT_EXT 0x8D44 #define GL_STENCIL_INDEX1_EXT 0x8D46 #define GL_STENCIL_INDEX4_EXT 0x8D47 #define GL_STENCIL_INDEX8_EXT 0x8D48 #define GL_STENCIL_INDEX16_EXT 0x8D49 #define GL_RENDERBUFFER_RED_SIZE_EXT 0x8D50 #define GL_RENDERBUFFER_GREEN_SIZE_EXT 0x8D51 #define GL_RENDERBUFFER_BLUE_SIZE_EXT 0x8D52 #define GL_RENDERBUFFER_ALPHA_SIZE_EXT 0x8D53 #define GL_RENDERBUFFER_DEPTH_SIZE_EXT 0x8D54 #define GL_RENDERBUFFER_STENCIL_SIZE_EXT 0x8D55 #endif #ifndef GL_GREMEDY_string_marker #endif #ifndef GL_EXT_packed_depth_stencil #define GL_DEPTH_STENCIL_EXT 0x84F9 #define GL_UNSIGNED_INT_24_8_EXT 0x84FA #define GL_DEPTH24_STENCIL8_EXT 0x88F0 #define GL_TEXTURE_STENCIL_SIZE_EXT 0x88F1 #endif #ifndef GL_EXT_stencil_clear_tag #define GL_STENCIL_TAG_BITS_EXT 0x88F2 #define GL_STENCIL_CLEAR_TAG_VALUE_EXT 0x88F3 #endif #ifndef GL_EXT_texture_sRGB #define GL_SRGB_EXT 0x8C40 #define GL_SRGB8_EXT 0x8C41 #define GL_SRGB_ALPHA_EXT 0x8C42 #define GL_SRGB8_ALPHA8_EXT 0x8C43 #define GL_SLUMINANCE_ALPHA_EXT 0x8C44 #define GL_SLUMINANCE8_ALPHA8_EXT 0x8C45 #define GL_SLUMINANCE_EXT 0x8C46 #define GL_SLUMINANCE8_EXT 0x8C47 #define GL_COMPRESSED_SRGB_EXT 0x8C48 #define GL_COMPRESSED_SRGB_ALPHA_EXT 0x8C49 #define GL_COMPRESSED_SLUMINANCE_EXT 0x8C4A #define GL_COMPRESSED_SLUMINANCE_ALPHA_EXT 0x8C4B #define GL_COMPRESSED_SRGB_S3TC_DXT1_EXT 0x8C4C #define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT 0x8C4D #define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT 0x8C4E #define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT 0x8C4F #endif #ifndef GL_EXT_framebuffer_blit #define GL_READ_FRAMEBUFFER_EXT 0x8CA8 #define GL_DRAW_FRAMEBUFFER_EXT 0x8CA9 #define GL_DRAW_FRAMEBUFFER_BINDING_EXT GL_FRAMEBUFFER_BINDING_EXT #define GL_READ_FRAMEBUFFER_BINDING_EXT 0x8CAA #endif #ifndef GL_EXT_framebuffer_multisample #define GL_RENDERBUFFER_SAMPLES_EXT 0x8CAB #define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT 0x8D56 #define GL_MAX_SAMPLES_EXT 0x8D57 #endif #ifndef GL_MESAX_texture_stack #define GL_TEXTURE_1D_STACK_MESAX 0x8759 #define GL_TEXTURE_2D_STACK_MESAX 0x875A #define GL_PROXY_TEXTURE_1D_STACK_MESAX 0x875B #define GL_PROXY_TEXTURE_2D_STACK_MESAX 0x875C #define GL_TEXTURE_1D_STACK_BINDING_MESAX 0x875D #define GL_TEXTURE_2D_STACK_BINDING_MESAX 0x875E #endif #ifndef GL_EXT_timer_query #define GL_TIME_ELAPSED_EXT 0x88BF #endif #ifndef GL_EXT_gpu_program_parameters #endif #ifndef GL_APPLE_flush_buffer_range #define GL_BUFFER_SERIALIZED_MODIFY_APPLE 0x8A12 #define GL_BUFFER_FLUSHING_UNMAP_APPLE 0x8A13 #endif #ifndef GL_NV_gpu_program4 #define GL_MIN_PROGRAM_TEXEL_OFFSET_NV 0x8904 #define GL_MAX_PROGRAM_TEXEL_OFFSET_NV 0x8905 #define GL_PROGRAM_ATTRIB_COMPONENTS_NV 0x8906 #define GL_PROGRAM_RESULT_COMPONENTS_NV 0x8907 #define GL_MAX_PROGRAM_ATTRIB_COMPONENTS_NV 0x8908 #define GL_MAX_PROGRAM_RESULT_COMPONENTS_NV 0x8909 #define GL_MAX_PROGRAM_GENERIC_ATTRIBS_NV 0x8DA5 #define GL_MAX_PROGRAM_GENERIC_RESULTS_NV 0x8DA6 #endif #ifndef GL_NV_geometry_program4 #define GL_LINES_ADJACENCY_EXT 0x000A #define GL_LINE_STRIP_ADJACENCY_EXT 0x000B #define GL_TRIANGLES_ADJACENCY_EXT 0x000C #define GL_TRIANGLE_STRIP_ADJACENCY_EXT 0x000D #define GL_GEOMETRY_PROGRAM_NV 0x8C26 #define GL_MAX_PROGRAM_OUTPUT_VERTICES_NV 0x8C27 #define GL_MAX_PROGRAM_TOTAL_OUTPUT_COMPONENTS_NV 0x8C28 #define GL_GEOMETRY_VERTICES_OUT_EXT 0x8DDA #define GL_GEOMETRY_INPUT_TYPE_EXT 0x8DDB #define GL_GEOMETRY_OUTPUT_TYPE_EXT 0x8DDC #define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_EXT 0x8C29 #define GL_FRAMEBUFFER_ATTACHMENT_LAYERED_EXT 0x8DA7 #define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT 0x8DA8 #define GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_EXT 0x8DA9 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER_EXT 0x8CD4 #define GL_PROGRAM_POINT_SIZE_EXT 0x8642 #endif #ifndef GL_EXT_geometry_shader4 #define GL_GEOMETRY_SHADER_EXT 0x8DD9 /* reuse GL_GEOMETRY_VERTICES_OUT_EXT */ /* reuse GL_GEOMETRY_INPUT_TYPE_EXT */ /* reuse GL_GEOMETRY_OUTPUT_TYPE_EXT */ /* reuse GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_EXT */ #define GL_MAX_GEOMETRY_VARYING_COMPONENTS_EXT 0x8DDD #define GL_MAX_VERTEX_VARYING_COMPONENTS_EXT 0x8DDE #define GL_MAX_VARYING_COMPONENTS_EXT 0x8B4B #define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_EXT 0x8DDF #define GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT 0x8DE0 #define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_EXT 0x8DE1 /* reuse GL_LINES_ADJACENCY_EXT */ /* reuse GL_LINE_STRIP_ADJACENCY_EXT */ /* reuse GL_TRIANGLES_ADJACENCY_EXT */ /* reuse GL_TRIANGLE_STRIP_ADJACENCY_EXT */ /* reuse GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT */ /* reuse GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_EXT */ /* reuse GL_FRAMEBUFFER_ATTACHMENT_LAYERED_EXT */ /* reuse GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER_EXT */ /* reuse GL_PROGRAM_POINT_SIZE_EXT */ #endif #ifndef GL_NV_vertex_program4 #define GL_VERTEX_ATTRIB_ARRAY_INTEGER_NV 0x88FD #endif #ifndef GL_EXT_gpu_shader4 #define GL_SAMPLER_1D_ARRAY_EXT 0x8DC0 #define GL_SAMPLER_2D_ARRAY_EXT 0x8DC1 #define GL_SAMPLER_BUFFER_EXT 0x8DC2 #define GL_SAMPLER_1D_ARRAY_SHADOW_EXT 0x8DC3 #define GL_SAMPLER_2D_ARRAY_SHADOW_EXT 0x8DC4 #define GL_SAMPLER_CUBE_SHADOW_EXT 0x8DC5 #define GL_UNSIGNED_INT_VEC2_EXT 0x8DC6 #define GL_UNSIGNED_INT_VEC3_EXT 0x8DC7 #define GL_UNSIGNED_INT_VEC4_EXT 0x8DC8 #define GL_INT_SAMPLER_1D_EXT 0x8DC9 #define GL_INT_SAMPLER_2D_EXT 0x8DCA #define GL_INT_SAMPLER_3D_EXT 0x8DCB #define GL_INT_SAMPLER_CUBE_EXT 0x8DCC #define GL_INT_SAMPLER_2D_RECT_EXT 0x8DCD #define GL_INT_SAMPLER_1D_ARRAY_EXT 0x8DCE #define GL_INT_SAMPLER_2D_ARRAY_EXT 0x8DCF #define GL_INT_SAMPLER_BUFFER_EXT 0x8DD0 #define GL_UNSIGNED_INT_SAMPLER_1D_EXT 0x8DD1 #define GL_UNSIGNED_INT_SAMPLER_2D_EXT 0x8DD2 #define GL_UNSIGNED_INT_SAMPLER_3D_EXT 0x8DD3 #define GL_UNSIGNED_INT_SAMPLER_CUBE_EXT 0x8DD4 #define GL_UNSIGNED_INT_SAMPLER_2D_RECT_EXT 0x8DD5 #define GL_UNSIGNED_INT_SAMPLER_1D_ARRAY_EXT 0x8DD6 #define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY_EXT 0x8DD7 #define GL_UNSIGNED_INT_SAMPLER_BUFFER_EXT 0x8DD8 #endif #ifndef GL_EXT_draw_instanced #endif #ifndef GL_EXT_packed_float #define GL_R11F_G11F_B10F_EXT 0x8C3A #define GL_UNSIGNED_INT_10F_11F_11F_REV_EXT 0x8C3B #define GL_RGBA_SIGNED_COMPONENTS_EXT 0x8C3C #endif #ifndef GL_EXT_texture_array #define GL_TEXTURE_1D_ARRAY_EXT 0x8C18 #define GL_PROXY_TEXTURE_1D_ARRAY_EXT 0x8C19 #define GL_TEXTURE_2D_ARRAY_EXT 0x8C1A #define GL_PROXY_TEXTURE_2D_ARRAY_EXT 0x8C1B #define GL_TEXTURE_BINDING_1D_ARRAY_EXT 0x8C1C #define GL_TEXTURE_BINDING_2D_ARRAY_EXT 0x8C1D #define GL_MAX_ARRAY_TEXTURE_LAYERS_EXT 0x88FF #define GL_COMPARE_REF_DEPTH_TO_TEXTURE_EXT 0x884E /* reuse GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER_EXT */ #endif #ifndef GL_EXT_texture_buffer_object #define GL_TEXTURE_BUFFER_EXT 0x8C2A #define GL_MAX_TEXTURE_BUFFER_SIZE_EXT 0x8C2B #define GL_TEXTURE_BINDING_BUFFER_EXT 0x8C2C #define GL_TEXTURE_BUFFER_DATA_STORE_BINDING_EXT 0x8C2D #define GL_TEXTURE_BUFFER_FORMAT_EXT 0x8C2E #endif #ifndef GL_EXT_texture_compression_latc #define GL_COMPRESSED_LUMINANCE_LATC1_EXT 0x8C70 #define GL_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT 0x8C71 #define GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT 0x8C72 #define GL_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT 0x8C73 #endif #ifndef GL_EXT_texture_compression_rgtc #define GL_COMPRESSED_RED_RGTC1_EXT 0x8DBB #define GL_COMPRESSED_SIGNED_RED_RGTC1_EXT 0x8DBC #define GL_COMPRESSED_RED_GREEN_RGTC2_EXT 0x8DBD #define GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT 0x8DBE #endif #ifndef GL_EXT_texture_shared_exponent #define GL_RGB9_E5_EXT 0x8C3D #define GL_UNSIGNED_INT_5_9_9_9_REV_EXT 0x8C3E #define GL_TEXTURE_SHARED_SIZE_EXT 0x8C3F #endif #ifndef GL_NV_depth_buffer_float #define GL_DEPTH_COMPONENT32F_NV 0x8DAB #define GL_DEPTH32F_STENCIL8_NV 0x8DAC #define GL_FLOAT_32_UNSIGNED_INT_24_8_REV_NV 0x8DAD #define GL_DEPTH_BUFFER_FLOAT_MODE_NV 0x8DAF #endif #ifndef GL_NV_fragment_program4 #endif #ifndef GL_NV_framebuffer_multisample_coverage #define GL_RENDERBUFFER_COVERAGE_SAMPLES_NV 0x8CAB #define GL_RENDERBUFFER_COLOR_SAMPLES_NV 0x8E10 #define GL_MAX_MULTISAMPLE_COVERAGE_MODES_NV 0x8E11 #define GL_MULTISAMPLE_COVERAGE_MODES_NV 0x8E12 #endif #ifndef GL_EXT_framebuffer_sRGB #define GL_FRAMEBUFFER_SRGB_EXT 0x8DB9 #define GL_FRAMEBUFFER_SRGB_CAPABLE_EXT 0x8DBA #endif #ifndef GL_NV_geometry_shader4 #endif #ifndef GL_NV_parameter_buffer_object #define GL_MAX_PROGRAM_PARAMETER_BUFFER_BINDINGS_NV 0x8DA0 #define GL_MAX_PROGRAM_PARAMETER_BUFFER_SIZE_NV 0x8DA1 #define GL_VERTEX_PROGRAM_PARAMETER_BUFFER_NV 0x8DA2 #define GL_GEOMETRY_PROGRAM_PARAMETER_BUFFER_NV 0x8DA3 #define GL_FRAGMENT_PROGRAM_PARAMETER_BUFFER_NV 0x8DA4 #endif #ifndef GL_EXT_draw_buffers2 #endif #ifndef GL_NV_transform_feedback #define GL_BACK_PRIMARY_COLOR_NV 0x8C77 #define GL_BACK_SECONDARY_COLOR_NV 0x8C78 #define GL_TEXTURE_COORD_NV 0x8C79 #define GL_CLIP_DISTANCE_NV 0x8C7A #define GL_VERTEX_ID_NV 0x8C7B #define GL_PRIMITIVE_ID_NV 0x8C7C #define GL_GENERIC_ATTRIB_NV 0x8C7D #define GL_TRANSFORM_FEEDBACK_ATTRIBS_NV 0x8C7E #define GL_TRANSFORM_FEEDBACK_BUFFER_MODE_NV 0x8C7F #define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS_NV 0x8C80 #define GL_ACTIVE_VARYINGS_NV 0x8C81 #define GL_ACTIVE_VARYING_MAX_LENGTH_NV 0x8C82 #define GL_TRANSFORM_FEEDBACK_VARYINGS_NV 0x8C83 #define GL_TRANSFORM_FEEDBACK_BUFFER_START_NV 0x8C84 #define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE_NV 0x8C85 #define GL_TRANSFORM_FEEDBACK_RECORD_NV 0x8C86 #define GL_PRIMITIVES_GENERATED_NV 0x8C87 #define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN_NV 0x8C88 #define GL_RASTERIZER_DISCARD_NV 0x8C89 #define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_ATTRIBS_NV 0x8C8A #define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS_NV 0x8C8B #define GL_INTERLEAVED_ATTRIBS_NV 0x8C8C #define GL_SEPARATE_ATTRIBS_NV 0x8C8D #define GL_TRANSFORM_FEEDBACK_BUFFER_NV 0x8C8E #define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING_NV 0x8C8F #endif #ifndef GL_EXT_bindable_uniform #define GL_MAX_VERTEX_BINDABLE_UNIFORMS_EXT 0x8DE2 #define GL_MAX_FRAGMENT_BINDABLE_UNIFORMS_EXT 0x8DE3 #define GL_MAX_GEOMETRY_BINDABLE_UNIFORMS_EXT 0x8DE4 #define GL_MAX_BINDABLE_UNIFORM_SIZE_EXT 0x8DED #define GL_UNIFORM_BUFFER_EXT 0x8DEE #define GL_UNIFORM_BUFFER_BINDING_EXT 0x8DEF #endif #ifndef GL_EXT_texture_integer #define GL_RGBA32UI_EXT 0x8D70 #define GL_RGB32UI_EXT 0x8D71 #define GL_ALPHA32UI_EXT 0x8D72 #define GL_INTENSITY32UI_EXT 0x8D73 #define GL_LUMINANCE32UI_EXT 0x8D74 #define GL_LUMINANCE_ALPHA32UI_EXT 0x8D75 #define GL_RGBA16UI_EXT 0x8D76 #define GL_RGB16UI_EXT 0x8D77 #define GL_ALPHA16UI_EXT 0x8D78 #define GL_INTENSITY16UI_EXT 0x8D79 #define GL_LUMINANCE16UI_EXT 0x8D7A #define GL_LUMINANCE_ALPHA16UI_EXT 0x8D7B #define GL_RGBA8UI_EXT 0x8D7C #define GL_RGB8UI_EXT 0x8D7D #define GL_ALPHA8UI_EXT 0x8D7E #define GL_INTENSITY8UI_EXT 0x8D7F #define GL_LUMINANCE8UI_EXT 0x8D80 #define GL_LUMINANCE_ALPHA8UI_EXT 0x8D81 #define GL_RGBA32I_EXT 0x8D82 #define GL_RGB32I_EXT 0x8D83 #define GL_ALPHA32I_EXT 0x8D84 #define GL_INTENSITY32I_EXT 0x8D85 #define GL_LUMINANCE32I_EXT 0x8D86 #define GL_LUMINANCE_ALPHA32I_EXT 0x8D87 #define GL_RGBA16I_EXT 0x8D88 #define GL_RGB16I_EXT 0x8D89 #define GL_ALPHA16I_EXT 0x8D8A #define GL_INTENSITY16I_EXT 0x8D8B #define GL_LUMINANCE16I_EXT 0x8D8C #define GL_LUMINANCE_ALPHA16I_EXT 0x8D8D #define GL_RGBA8I_EXT 0x8D8E #define GL_RGB8I_EXT 0x8D8F #define GL_ALPHA8I_EXT 0x8D90 #define GL_INTENSITY8I_EXT 0x8D91 #define GL_LUMINANCE8I_EXT 0x8D92 #define GL_LUMINANCE_ALPHA8I_EXT 0x8D93 #define GL_RED_INTEGER_EXT 0x8D94 #define GL_GREEN_INTEGER_EXT 0x8D95 #define GL_BLUE_INTEGER_EXT 0x8D96 #define GL_ALPHA_INTEGER_EXT 0x8D97 #define GL_RGB_INTEGER_EXT 0x8D98 #define GL_RGBA_INTEGER_EXT 0x8D99 #define GL_BGR_INTEGER_EXT 0x8D9A #define GL_BGRA_INTEGER_EXT 0x8D9B #define GL_LUMINANCE_INTEGER_EXT 0x8D9C #define GL_LUMINANCE_ALPHA_INTEGER_EXT 0x8D9D #define GL_RGBA_INTEGER_MODE_EXT 0x8D9E #endif #ifndef GL_GREMEDY_frame_terminator #endif #ifndef GL_NV_conditional_render #define GL_QUERY_WAIT_NV 0x8E13 #define GL_QUERY_NO_WAIT_NV 0x8E14 #define GL_QUERY_BY_REGION_WAIT_NV 0x8E15 #define GL_QUERY_BY_REGION_NO_WAIT_NV 0x8E16 #endif #ifndef GL_NV_present_video #define GL_FRAME_NV 0x8E26 #define GL_FIELDS_NV 0x8E27 #define GL_CURRENT_TIME_NV 0x8E28 #define GL_NUM_FILL_STREAMS_NV 0x8E29 #define GL_PRESENT_TIME_NV 0x8E2A #define GL_PRESENT_DURATION_NV 0x8E2B #endif #ifndef GL_EXT_transform_feedback #define GL_TRANSFORM_FEEDBACK_BUFFER_EXT 0x8C8E #define GL_TRANSFORM_FEEDBACK_BUFFER_START_EXT 0x8C84 #define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE_EXT 0x8C85 #define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING_EXT 0x8C8F #define GL_INTERLEAVED_ATTRIBS_EXT 0x8C8C #define GL_SEPARATE_ATTRIBS_EXT 0x8C8D #define GL_PRIMITIVES_GENERATED_EXT 0x8C87 #define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN_EXT 0x8C88 #define GL_RASTERIZER_DISCARD_EXT 0x8C89 #define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS_EXT 0x8C8A #define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS_EXT 0x8C8B #define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS_EXT 0x8C80 #define GL_TRANSFORM_FEEDBACK_VARYINGS_EXT 0x8C83 #define GL_TRANSFORM_FEEDBACK_BUFFER_MODE_EXT 0x8C7F #define GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH_EXT 0x8C76 #endif #ifndef GL_EXT_direct_state_access #define GL_PROGRAM_MATRIX_EXT 0x8E2D #define GL_TRANSPOSE_PROGRAM_MATRIX_EXT 0x8E2E #define GL_PROGRAM_MATRIX_STACK_DEPTH_EXT 0x8E2F #endif #ifndef GL_EXT_vertex_array_bgra /* reuse GL_BGRA */ #endif #ifndef GL_EXT_texture_swizzle #define GL_TEXTURE_SWIZZLE_R_EXT 0x8E42 #define GL_TEXTURE_SWIZZLE_G_EXT 0x8E43 #define GL_TEXTURE_SWIZZLE_B_EXT 0x8E44 #define GL_TEXTURE_SWIZZLE_A_EXT 0x8E45 #define GL_TEXTURE_SWIZZLE_RGBA_EXT 0x8E46 #endif #ifndef GL_NV_explicit_multisample #define GL_SAMPLE_POSITION_NV 0x8E50 #define GL_SAMPLE_MASK_NV 0x8E51 #define GL_SAMPLE_MASK_VALUE_NV 0x8E52 #define GL_TEXTURE_BINDING_RENDERBUFFER_NV 0x8E53 #define GL_TEXTURE_RENDERBUFFER_DATA_STORE_BINDING_NV 0x8E54 #define GL_MAX_SAMPLE_MASK_WORDS_NV 0x8E59 #define GL_TEXTURE_RENDERBUFFER_NV 0x8E55 #define GL_SAMPLER_RENDERBUFFER_NV 0x8E56 #define GL_INT_SAMPLER_RENDERBUFFER_NV 0x8E57 #define GL_UNSIGNED_INT_SAMPLER_RENDERBUFFER_NV 0x8E58 #endif #ifndef GL_NV_transform_feedback2 #define GL_TRANSFORM_FEEDBACK_NV 0x8E22 #define GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED_NV 0x8E23 #define GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE_NV 0x8E24 #define GL_TRANSFORM_FEEDBACK_BINDING_NV 0x8E25 #endif /*************************************************************/ #include #ifndef GL_VERSION_2_0 /* GL type for program/shader text */ typedef char GLchar; /* native character */ #endif #ifndef GL_VERSION_1_5 /* GL types for handling large vertex buffer objects */ typedef ptrdiff_t GLintptr; typedef ptrdiff_t GLsizeiptr; #endif #ifndef GL_ARB_vertex_buffer_object /* GL types for handling large vertex buffer objects */ typedef ptrdiff_t GLintptrARB; typedef ptrdiff_t GLsizeiptrARB; #endif #ifndef GL_ARB_shader_objects /* GL types for handling shader object handles and program/shader text */ typedef char GLcharARB; /* native character */ typedef unsigned int GLhandleARB; /* shader object handle */ #endif /* GL types for "half" precision (s10e5) float data in host memory */ #ifndef GL_ARB_half_float_pixel typedef unsigned short GLhalfARB; #endif #ifndef GL_NV_half_float typedef unsigned short GLhalfNV; #endif #ifndef GLEXT_64_TYPES_DEFINED /* This code block is duplicated in glxext.h, so must be protected */ #define GLEXT_64_TYPES_DEFINED /* Define int32_t, int64_t, and uint64_t types for UST/MSC */ /* (as used in the GL_EXT_timer_query extension). */ #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L #include #elif defined(__sun__) || defined(__digital__) #include #if defined(__STDC__) #if defined(__arch64__) || defined(_LP64) typedef long int int64_t; typedef unsigned long int uint64_t; #else typedef long long int int64_t; typedef unsigned long long int uint64_t; #endif /* __arch64__ */ #endif /* __STDC__ */ #elif defined( __VMS ) || defined(__sgi) #include #elif defined(__SCO__) || defined(__USLC__) #include #elif defined(__UNIXOS2__) || defined(__SOL64__) typedef long int int32_t; typedef long long int int64_t; typedef unsigned long long int uint64_t; #elif defined(_WIN32) && defined(__GNUC__) #include #elif defined(_WIN32) typedef __int32 int32_t; typedef __int64 int64_t; typedef unsigned __int64 uint64_t; #else #include /* Fallback option */ #endif #endif #ifndef GL_EXT_timer_query typedef int64_t GLint64EXT; typedef uint64_t GLuint64EXT; #endif #ifndef GL_VERSION_1_2 #define GL_VERSION_1_2 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBlendColor (GLclampf, GLclampf, GLclampf, GLclampf); GLAPI void APIENTRY glBlendEquation (GLenum); GLAPI void APIENTRY glDrawRangeElements (GLenum, GLuint, GLuint, GLsizei, GLenum, const GLvoid *); GLAPI void APIENTRY glColorTable (GLenum, GLenum, GLsizei, GLenum, GLenum, const GLvoid *); GLAPI void APIENTRY glColorTableParameterfv (GLenum, GLenum, const GLfloat *); GLAPI void APIENTRY glColorTableParameteriv (GLenum, GLenum, const GLint *); GLAPI void APIENTRY glCopyColorTable (GLenum, GLenum, GLint, GLint, GLsizei); GLAPI void APIENTRY glGetColorTable (GLenum, GLenum, GLenum, GLvoid *); GLAPI void APIENTRY glGetColorTableParameterfv (GLenum, GLenum, GLfloat *); GLAPI void APIENTRY glGetColorTableParameteriv (GLenum, GLenum, GLint *); GLAPI void APIENTRY glColorSubTable (GLenum, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *); GLAPI void APIENTRY glCopyColorSubTable (GLenum, GLsizei, GLint, GLint, GLsizei); GLAPI void APIENTRY glConvolutionFilter1D (GLenum, GLenum, GLsizei, GLenum, GLenum, const GLvoid *); GLAPI void APIENTRY glConvolutionFilter2D (GLenum, GLenum, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *); GLAPI void APIENTRY glConvolutionParameterf (GLenum, GLenum, GLfloat); GLAPI void APIENTRY glConvolutionParameterfv (GLenum, GLenum, const GLfloat *); GLAPI void APIENTRY glConvolutionParameteri (GLenum, GLenum, GLint); GLAPI void APIENTRY glConvolutionParameteriv (GLenum, GLenum, const GLint *); GLAPI void APIENTRY glCopyConvolutionFilter1D (GLenum, GLenum, GLint, GLint, GLsizei); GLAPI void APIENTRY glCopyConvolutionFilter2D (GLenum, GLenum, GLint, GLint, GLsizei, GLsizei); GLAPI void APIENTRY glGetConvolutionFilter (GLenum, GLenum, GLenum, GLvoid *); GLAPI void APIENTRY glGetConvolutionParameterfv (GLenum, GLenum, GLfloat *); GLAPI void APIENTRY glGetConvolutionParameteriv (GLenum, GLenum, GLint *); GLAPI void APIENTRY glGetSeparableFilter (GLenum, GLenum, GLenum, GLvoid *, GLvoid *, GLvoid *); GLAPI void APIENTRY glSeparableFilter2D (GLenum, GLenum, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *, const GLvoid *); GLAPI void APIENTRY glGetHistogram (GLenum, GLboolean, GLenum, GLenum, GLvoid *); GLAPI void APIENTRY glGetHistogramParameterfv (GLenum, GLenum, GLfloat *); GLAPI void APIENTRY glGetHistogramParameteriv (GLenum, GLenum, GLint *); GLAPI void APIENTRY glGetMinmax (GLenum, GLboolean, GLenum, GLenum, GLvoid *); GLAPI void APIENTRY glGetMinmaxParameterfv (GLenum, GLenum, GLfloat *); GLAPI void APIENTRY glGetMinmaxParameteriv (GLenum, GLenum, GLint *); GLAPI void APIENTRY glHistogram (GLenum, GLsizei, GLenum, GLboolean); GLAPI void APIENTRY glMinmax (GLenum, GLenum, GLboolean); GLAPI void APIENTRY glResetHistogram (GLenum); GLAPI void APIENTRY glResetMinmax (GLenum); GLAPI void APIENTRY glTexImage3D (GLenum, GLint, GLint, GLsizei, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid *); GLAPI void APIENTRY glTexSubImage3D (GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *); GLAPI void APIENTRY glCopyTexSubImage3D (GLenum, GLint, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLBLENDCOLORPROC) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); typedef void (APIENTRYP PFNGLBLENDEQUATIONPROC) (GLenum mode); typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices); typedef void (APIENTRYP PFNGLCOLORTABLEPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table); typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLCOPYCOLORTABLEPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); typedef void (APIENTRYP PFNGLGETCOLORTABLEPROC) (GLenum target, GLenum format, GLenum type, GLvoid *table); typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLCOLORSUBTABLEPROC) (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data); typedef void (APIENTRYP PFNGLCOPYCOLORSUBTABLEPROC) (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width); typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER1DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *image); typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER2DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image); typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFPROC) (GLenum target, GLenum pname, GLfloat params); typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIPROC) (GLenum target, GLenum pname, GLint params); typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER1DPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER2DPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height); typedef void (APIENTRYP PFNGLGETCONVOLUTIONFILTERPROC) (GLenum target, GLenum format, GLenum type, GLvoid *image); typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETSEPARABLEFILTERPROC) (GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span); typedef void (APIENTRYP PFNGLSEPARABLEFILTER2DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column); typedef void (APIENTRYP PFNGLGETHISTOGRAMPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETMINMAXPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLHISTOGRAMPROC) (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink); typedef void (APIENTRYP PFNGLMINMAXPROC) (GLenum target, GLenum internalformat, GLboolean sink); typedef void (APIENTRYP PFNGLRESETHISTOGRAMPROC) (GLenum target); typedef void (APIENTRYP PFNGLRESETMINMAXPROC) (GLenum target); typedef void (APIENTRYP PFNGLTEXIMAGE3DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels); typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); #endif #ifndef GL_VERSION_1_3 #define GL_VERSION_1_3 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glActiveTexture (GLenum); GLAPI void APIENTRY glClientActiveTexture (GLenum); GLAPI void APIENTRY glMultiTexCoord1d (GLenum, GLdouble); GLAPI void APIENTRY glMultiTexCoord1dv (GLenum, const GLdouble *); GLAPI void APIENTRY glMultiTexCoord1f (GLenum, GLfloat); GLAPI void APIENTRY glMultiTexCoord1fv (GLenum, const GLfloat *); GLAPI void APIENTRY glMultiTexCoord1i (GLenum, GLint); GLAPI void APIENTRY glMultiTexCoord1iv (GLenum, const GLint *); GLAPI void APIENTRY glMultiTexCoord1s (GLenum, GLshort); GLAPI void APIENTRY glMultiTexCoord1sv (GLenum, const GLshort *); GLAPI void APIENTRY glMultiTexCoord2d (GLenum, GLdouble, GLdouble); GLAPI void APIENTRY glMultiTexCoord2dv (GLenum, const GLdouble *); GLAPI void APIENTRY glMultiTexCoord2f (GLenum, GLfloat, GLfloat); GLAPI void APIENTRY glMultiTexCoord2fv (GLenum, const GLfloat *); GLAPI void APIENTRY glMultiTexCoord2i (GLenum, GLint, GLint); GLAPI void APIENTRY glMultiTexCoord2iv (GLenum, const GLint *); GLAPI void APIENTRY glMultiTexCoord2s (GLenum, GLshort, GLshort); GLAPI void APIENTRY glMultiTexCoord2sv (GLenum, const GLshort *); GLAPI void APIENTRY glMultiTexCoord3d (GLenum, GLdouble, GLdouble, GLdouble); GLAPI void APIENTRY glMultiTexCoord3dv (GLenum, const GLdouble *); GLAPI void APIENTRY glMultiTexCoord3f (GLenum, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glMultiTexCoord3fv (GLenum, const GLfloat *); GLAPI void APIENTRY glMultiTexCoord3i (GLenum, GLint, GLint, GLint); GLAPI void APIENTRY glMultiTexCoord3iv (GLenum, const GLint *); GLAPI void APIENTRY glMultiTexCoord3s (GLenum, GLshort, GLshort, GLshort); GLAPI void APIENTRY glMultiTexCoord3sv (GLenum, const GLshort *); GLAPI void APIENTRY glMultiTexCoord4d (GLenum, GLdouble, GLdouble, GLdouble, GLdouble); GLAPI void APIENTRY glMultiTexCoord4dv (GLenum, const GLdouble *); GLAPI void APIENTRY glMultiTexCoord4f (GLenum, GLfloat, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glMultiTexCoord4fv (GLenum, const GLfloat *); GLAPI void APIENTRY glMultiTexCoord4i (GLenum, GLint, GLint, GLint, GLint); GLAPI void APIENTRY glMultiTexCoord4iv (GLenum, const GLint *); GLAPI void APIENTRY glMultiTexCoord4s (GLenum, GLshort, GLshort, GLshort, GLshort); GLAPI void APIENTRY glMultiTexCoord4sv (GLenum, const GLshort *); GLAPI void APIENTRY glLoadTransposeMatrixf (const GLfloat *); GLAPI void APIENTRY glLoadTransposeMatrixd (const GLdouble *); GLAPI void APIENTRY glMultTransposeMatrixf (const GLfloat *); GLAPI void APIENTRY glMultTransposeMatrixd (const GLdouble *); GLAPI void APIENTRY glSampleCoverage (GLclampf, GLboolean); GLAPI void APIENTRY glCompressedTexImage3D (GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLint, GLsizei, const GLvoid *); GLAPI void APIENTRY glCompressedTexImage2D (GLenum, GLint, GLenum, GLsizei, GLsizei, GLint, GLsizei, const GLvoid *); GLAPI void APIENTRY glCompressedTexImage1D (GLenum, GLint, GLenum, GLsizei, GLint, GLsizei, const GLvoid *); GLAPI void APIENTRY glCompressedTexSubImage3D (GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid *); GLAPI void APIENTRY glCompressedTexSubImage2D (GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid *); GLAPI void APIENTRY glCompressedTexSubImage1D (GLenum, GLint, GLint, GLsizei, GLenum, GLsizei, const GLvoid *); GLAPI void APIENTRY glGetCompressedTexImage (GLenum, GLint, GLvoid *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLACTIVETEXTUREPROC) (GLenum texture); typedef void (APIENTRYP PFNGLCLIENTACTIVETEXTUREPROC) (GLenum texture); typedef void (APIENTRYP PFNGLMULTITEXCOORD1DPROC) (GLenum target, GLdouble s); typedef void (APIENTRYP PFNGLMULTITEXCOORD1DVPROC) (GLenum target, const GLdouble *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD1FPROC) (GLenum target, GLfloat s); typedef void (APIENTRYP PFNGLMULTITEXCOORD1FVPROC) (GLenum target, const GLfloat *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD1IPROC) (GLenum target, GLint s); typedef void (APIENTRYP PFNGLMULTITEXCOORD1IVPROC) (GLenum target, const GLint *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD1SPROC) (GLenum target, GLshort s); typedef void (APIENTRYP PFNGLMULTITEXCOORD1SVPROC) (GLenum target, const GLshort *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD2DPROC) (GLenum target, GLdouble s, GLdouble t); typedef void (APIENTRYP PFNGLMULTITEXCOORD2DVPROC) (GLenum target, const GLdouble *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD2FPROC) (GLenum target, GLfloat s, GLfloat t); typedef void (APIENTRYP PFNGLMULTITEXCOORD2FVPROC) (GLenum target, const GLfloat *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD2IPROC) (GLenum target, GLint s, GLint t); typedef void (APIENTRYP PFNGLMULTITEXCOORD2IVPROC) (GLenum target, const GLint *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD2SPROC) (GLenum target, GLshort s, GLshort t); typedef void (APIENTRYP PFNGLMULTITEXCOORD2SVPROC) (GLenum target, const GLshort *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD3DPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r); typedef void (APIENTRYP PFNGLMULTITEXCOORD3DVPROC) (GLenum target, const GLdouble *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD3FPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r); typedef void (APIENTRYP PFNGLMULTITEXCOORD3FVPROC) (GLenum target, const GLfloat *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD3IPROC) (GLenum target, GLint s, GLint t, GLint r); typedef void (APIENTRYP PFNGLMULTITEXCOORD3IVPROC) (GLenum target, const GLint *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD3SPROC) (GLenum target, GLshort s, GLshort t, GLshort r); typedef void (APIENTRYP PFNGLMULTITEXCOORD3SVPROC) (GLenum target, const GLshort *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD4DPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q); typedef void (APIENTRYP PFNGLMULTITEXCOORD4DVPROC) (GLenum target, const GLdouble *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD4FPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); typedef void (APIENTRYP PFNGLMULTITEXCOORD4FVPROC) (GLenum target, const GLfloat *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD4IPROC) (GLenum target, GLint s, GLint t, GLint r, GLint q); typedef void (APIENTRYP PFNGLMULTITEXCOORD4IVPROC) (GLenum target, const GLint *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD4SPROC) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q); typedef void (APIENTRYP PFNGLMULTITEXCOORD4SVPROC) (GLenum target, const GLshort *v); typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXFPROC) (const GLfloat *m); typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXDPROC) (const GLdouble *m); typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXFPROC) (const GLfloat *m); typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXDPROC) (const GLdouble *m); typedef void (APIENTRYP PFNGLSAMPLECOVERAGEPROC) (GLclampf value, GLboolean invert); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data); typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEPROC) (GLenum target, GLint level, GLvoid *img); #endif #ifndef GL_VERSION_1_4 #define GL_VERSION_1_4 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBlendFuncSeparate (GLenum, GLenum, GLenum, GLenum); GLAPI void APIENTRY glFogCoordf (GLfloat); GLAPI void APIENTRY glFogCoordfv (const GLfloat *); GLAPI void APIENTRY glFogCoordd (GLdouble); GLAPI void APIENTRY glFogCoorddv (const GLdouble *); GLAPI void APIENTRY glFogCoordPointer (GLenum, GLsizei, const GLvoid *); GLAPI void APIENTRY glMultiDrawArrays (GLenum, GLint *, GLsizei *, GLsizei); GLAPI void APIENTRY glMultiDrawElements (GLenum, const GLsizei *, GLenum, const GLvoid* *, GLsizei); GLAPI void APIENTRY glPointParameterf (GLenum, GLfloat); GLAPI void APIENTRY glPointParameterfv (GLenum, const GLfloat *); GLAPI void APIENTRY glPointParameteri (GLenum, GLint); GLAPI void APIENTRY glPointParameteriv (GLenum, const GLint *); GLAPI void APIENTRY glSecondaryColor3b (GLbyte, GLbyte, GLbyte); GLAPI void APIENTRY glSecondaryColor3bv (const GLbyte *); GLAPI void APIENTRY glSecondaryColor3d (GLdouble, GLdouble, GLdouble); GLAPI void APIENTRY glSecondaryColor3dv (const GLdouble *); GLAPI void APIENTRY glSecondaryColor3f (GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glSecondaryColor3fv (const GLfloat *); GLAPI void APIENTRY glSecondaryColor3i (GLint, GLint, GLint); GLAPI void APIENTRY glSecondaryColor3iv (const GLint *); GLAPI void APIENTRY glSecondaryColor3s (GLshort, GLshort, GLshort); GLAPI void APIENTRY glSecondaryColor3sv (const GLshort *); GLAPI void APIENTRY glSecondaryColor3ub (GLubyte, GLubyte, GLubyte); GLAPI void APIENTRY glSecondaryColor3ubv (const GLubyte *); GLAPI void APIENTRY glSecondaryColor3ui (GLuint, GLuint, GLuint); GLAPI void APIENTRY glSecondaryColor3uiv (const GLuint *); GLAPI void APIENTRY glSecondaryColor3us (GLushort, GLushort, GLushort); GLAPI void APIENTRY glSecondaryColor3usv (const GLushort *); GLAPI void APIENTRY glSecondaryColorPointer (GLint, GLenum, GLsizei, const GLvoid *); GLAPI void APIENTRY glWindowPos2d (GLdouble, GLdouble); GLAPI void APIENTRY glWindowPos2dv (const GLdouble *); GLAPI void APIENTRY glWindowPos2f (GLfloat, GLfloat); GLAPI void APIENTRY glWindowPos2fv (const GLfloat *); GLAPI void APIENTRY glWindowPos2i (GLint, GLint); GLAPI void APIENTRY glWindowPos2iv (const GLint *); GLAPI void APIENTRY glWindowPos2s (GLshort, GLshort); GLAPI void APIENTRY glWindowPos2sv (const GLshort *); GLAPI void APIENTRY glWindowPos3d (GLdouble, GLdouble, GLdouble); GLAPI void APIENTRY glWindowPos3dv (const GLdouble *); GLAPI void APIENTRY glWindowPos3f (GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glWindowPos3fv (const GLfloat *); GLAPI void APIENTRY glWindowPos3i (GLint, GLint, GLint); GLAPI void APIENTRY glWindowPos3iv (const GLint *); GLAPI void APIENTRY glWindowPos3s (GLshort, GLshort, GLshort); GLAPI void APIENTRY glWindowPos3sv (const GLshort *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); typedef void (APIENTRYP PFNGLFOGCOORDFPROC) (GLfloat coord); typedef void (APIENTRYP PFNGLFOGCOORDFVPROC) (const GLfloat *coord); typedef void (APIENTRYP PFNGLFOGCOORDDPROC) (GLdouble coord); typedef void (APIENTRYP PFNGLFOGCOORDDVPROC) (const GLdouble *coord); typedef void (APIENTRYP PFNGLFOGCOORDPOINTERPROC) (GLenum type, GLsizei stride, const GLvoid *pointer); typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSPROC) (GLenum mode, GLint *first, GLsizei *count, GLsizei primcount); typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSPROC) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount); typedef void (APIENTRYP PFNGLPOINTPARAMETERFPROC) (GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLPOINTPARAMETERFVPROC) (GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLPOINTPARAMETERIPROC) (GLenum pname, GLint param); typedef void (APIENTRYP PFNGLPOINTPARAMETERIVPROC) (GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BPROC) (GLbyte red, GLbyte green, GLbyte blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BVPROC) (const GLbyte *v); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DPROC) (GLdouble red, GLdouble green, GLdouble blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DVPROC) (const GLdouble *v); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FPROC) (GLfloat red, GLfloat green, GLfloat blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FVPROC) (const GLfloat *v); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IPROC) (GLint red, GLint green, GLint blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IVPROC) (const GLint *v); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SPROC) (GLshort red, GLshort green, GLshort blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SVPROC) (const GLshort *v); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBPROC) (GLubyte red, GLubyte green, GLubyte blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBVPROC) (const GLubyte *v); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIPROC) (GLuint red, GLuint green, GLuint blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIVPROC) (const GLuint *v); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USPROC) (GLushort red, GLushort green, GLushort blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USVPROC) (const GLushort *v); typedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTERPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); typedef void (APIENTRYP PFNGLWINDOWPOS2DPROC) (GLdouble x, GLdouble y); typedef void (APIENTRYP PFNGLWINDOWPOS2DVPROC) (const GLdouble *v); typedef void (APIENTRYP PFNGLWINDOWPOS2FPROC) (GLfloat x, GLfloat y); typedef void (APIENTRYP PFNGLWINDOWPOS2FVPROC) (const GLfloat *v); typedef void (APIENTRYP PFNGLWINDOWPOS2IPROC) (GLint x, GLint y); typedef void (APIENTRYP PFNGLWINDOWPOS2IVPROC) (const GLint *v); typedef void (APIENTRYP PFNGLWINDOWPOS2SPROC) (GLshort x, GLshort y); typedef void (APIENTRYP PFNGLWINDOWPOS2SVPROC) (const GLshort *v); typedef void (APIENTRYP PFNGLWINDOWPOS3DPROC) (GLdouble x, GLdouble y, GLdouble z); typedef void (APIENTRYP PFNGLWINDOWPOS3DVPROC) (const GLdouble *v); typedef void (APIENTRYP PFNGLWINDOWPOS3FPROC) (GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLWINDOWPOS3FVPROC) (const GLfloat *v); typedef void (APIENTRYP PFNGLWINDOWPOS3IPROC) (GLint x, GLint y, GLint z); typedef void (APIENTRYP PFNGLWINDOWPOS3IVPROC) (const GLint *v); typedef void (APIENTRYP PFNGLWINDOWPOS3SPROC) (GLshort x, GLshort y, GLshort z); typedef void (APIENTRYP PFNGLWINDOWPOS3SVPROC) (const GLshort *v); #endif #ifndef GL_VERSION_1_5 #define GL_VERSION_1_5 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glGenQueries (GLsizei, GLuint *); GLAPI void APIENTRY glDeleteQueries (GLsizei, const GLuint *); GLAPI GLboolean APIENTRY glIsQuery (GLuint); GLAPI void APIENTRY glBeginQuery (GLenum, GLuint); GLAPI void APIENTRY glEndQuery (GLenum); GLAPI void APIENTRY glGetQueryiv (GLenum, GLenum, GLint *); GLAPI void APIENTRY glGetQueryObjectiv (GLuint, GLenum, GLint *); GLAPI void APIENTRY glGetQueryObjectuiv (GLuint, GLenum, GLuint *); GLAPI void APIENTRY glBindBuffer (GLenum, GLuint); GLAPI void APIENTRY glDeleteBuffers (GLsizei, const GLuint *); GLAPI void APIENTRY glGenBuffers (GLsizei, GLuint *); GLAPI GLboolean APIENTRY glIsBuffer (GLuint); GLAPI void APIENTRY glBufferData (GLenum, GLsizeiptr, const GLvoid *, GLenum); GLAPI void APIENTRY glBufferSubData (GLenum, GLintptr, GLsizeiptr, const GLvoid *); GLAPI void APIENTRY glGetBufferSubData (GLenum, GLintptr, GLsizeiptr, GLvoid *); GLAPI GLvoid* APIENTRY glMapBuffer (GLenum, GLenum); GLAPI GLboolean APIENTRY glUnmapBuffer (GLenum); GLAPI void APIENTRY glGetBufferParameteriv (GLenum, GLenum, GLint *); GLAPI void APIENTRY glGetBufferPointerv (GLenum, GLenum, GLvoid* *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLGENQUERIESPROC) (GLsizei n, GLuint *ids); typedef void (APIENTRYP PFNGLDELETEQUERIESPROC) (GLsizei n, const GLuint *ids); typedef GLboolean (APIENTRYP PFNGLISQUERYPROC) (GLuint id); typedef void (APIENTRYP PFNGLBEGINQUERYPROC) (GLenum target, GLuint id); typedef void (APIENTRYP PFNGLENDQUERYPROC) (GLenum target); typedef void (APIENTRYP PFNGLGETQUERYIVPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETQUERYOBJECTIVPROC) (GLuint id, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETQUERYOBJECTUIVPROC) (GLuint id, GLenum pname, GLuint *params); typedef void (APIENTRYP PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer); typedef void (APIENTRYP PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint *buffers); typedef void (APIENTRYP PFNGLGENBUFFERSPROC) (GLsizei n, GLuint *buffers); typedef GLboolean (APIENTRYP PFNGLISBUFFERPROC) (GLuint buffer); typedef void (APIENTRYP PFNGLBUFFERDATAPROC) (GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage); typedef void (APIENTRYP PFNGLBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data); typedef void (APIENTRYP PFNGLGETBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, GLvoid *data); typedef GLvoid* (APIENTRYP PFNGLMAPBUFFERPROC) (GLenum target, GLenum access); typedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERPROC) (GLenum target); typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETBUFFERPOINTERVPROC) (GLenum target, GLenum pname, GLvoid* *params); #endif #ifndef GL_VERSION_2_0 #define GL_VERSION_2_0 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBlendEquationSeparate (GLenum, GLenum); GLAPI void APIENTRY glDrawBuffers (GLsizei, const GLenum *); GLAPI void APIENTRY glStencilOpSeparate (GLenum, GLenum, GLenum, GLenum); GLAPI void APIENTRY glStencilFuncSeparate (GLenum, GLenum, GLint, GLuint); GLAPI void APIENTRY glStencilMaskSeparate (GLenum, GLuint); GLAPI void APIENTRY glAttachShader (GLuint, GLuint); GLAPI void APIENTRY glBindAttribLocation (GLuint, GLuint, const GLchar *); GLAPI void APIENTRY glCompileShader (GLuint); GLAPI GLuint APIENTRY glCreateProgram (void); GLAPI GLuint APIENTRY glCreateShader (GLenum); GLAPI void APIENTRY glDeleteProgram (GLuint); GLAPI void APIENTRY glDeleteShader (GLuint); GLAPI void APIENTRY glDetachShader (GLuint, GLuint); GLAPI void APIENTRY glDisableVertexAttribArray (GLuint); GLAPI void APIENTRY glEnableVertexAttribArray (GLuint); GLAPI void APIENTRY glGetActiveAttrib (GLuint, GLuint, GLsizei, GLsizei *, GLint *, GLenum *, GLchar *); GLAPI void APIENTRY glGetActiveUniform (GLuint, GLuint, GLsizei, GLsizei *, GLint *, GLenum *, GLchar *); GLAPI void APIENTRY glGetAttachedShaders (GLuint, GLsizei, GLsizei *, GLuint *); GLAPI GLint APIENTRY glGetAttribLocation (GLuint, const GLchar *); GLAPI void APIENTRY glGetProgramiv (GLuint, GLenum, GLint *); GLAPI void APIENTRY glGetProgramInfoLog (GLuint, GLsizei, GLsizei *, GLchar *); GLAPI void APIENTRY glGetShaderiv (GLuint, GLenum, GLint *); GLAPI void APIENTRY glGetShaderInfoLog (GLuint, GLsizei, GLsizei *, GLchar *); GLAPI void APIENTRY glGetShaderSource (GLuint, GLsizei, GLsizei *, GLchar *); GLAPI GLint APIENTRY glGetUniformLocation (GLuint, const GLchar *); GLAPI void APIENTRY glGetUniformfv (GLuint, GLint, GLfloat *); GLAPI void APIENTRY glGetUniformiv (GLuint, GLint, GLint *); GLAPI void APIENTRY glGetVertexAttribdv (GLuint, GLenum, GLdouble *); GLAPI void APIENTRY glGetVertexAttribfv (GLuint, GLenum, GLfloat *); GLAPI void APIENTRY glGetVertexAttribiv (GLuint, GLenum, GLint *); GLAPI void APIENTRY glGetVertexAttribPointerv (GLuint, GLenum, GLvoid* *); GLAPI GLboolean APIENTRY glIsProgram (GLuint); GLAPI GLboolean APIENTRY glIsShader (GLuint); GLAPI void APIENTRY glLinkProgram (GLuint); GLAPI void APIENTRY glShaderSource (GLuint, GLsizei, const GLchar* *, const GLint *); GLAPI void APIENTRY glUseProgram (GLuint); GLAPI void APIENTRY glUniform1f (GLint, GLfloat); GLAPI void APIENTRY glUniform2f (GLint, GLfloat, GLfloat); GLAPI void APIENTRY glUniform3f (GLint, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glUniform4f (GLint, GLfloat, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glUniform1i (GLint, GLint); GLAPI void APIENTRY glUniform2i (GLint, GLint, GLint); GLAPI void APIENTRY glUniform3i (GLint, GLint, GLint, GLint); GLAPI void APIENTRY glUniform4i (GLint, GLint, GLint, GLint, GLint); GLAPI void APIENTRY glUniform1fv (GLint, GLsizei, const GLfloat *); GLAPI void APIENTRY glUniform2fv (GLint, GLsizei, const GLfloat *); GLAPI void APIENTRY glUniform3fv (GLint, GLsizei, const GLfloat *); GLAPI void APIENTRY glUniform4fv (GLint, GLsizei, const GLfloat *); GLAPI void APIENTRY glUniform1iv (GLint, GLsizei, const GLint *); GLAPI void APIENTRY glUniform2iv (GLint, GLsizei, const GLint *); GLAPI void APIENTRY glUniform3iv (GLint, GLsizei, const GLint *); GLAPI void APIENTRY glUniform4iv (GLint, GLsizei, const GLint *); GLAPI void APIENTRY glUniformMatrix2fv (GLint, GLsizei, GLboolean, const GLfloat *); GLAPI void APIENTRY glUniformMatrix3fv (GLint, GLsizei, GLboolean, const GLfloat *); GLAPI void APIENTRY glUniformMatrix4fv (GLint, GLsizei, GLboolean, const GLfloat *); GLAPI void APIENTRY glValidateProgram (GLuint); GLAPI void APIENTRY glVertexAttrib1d (GLuint, GLdouble); GLAPI void APIENTRY glVertexAttrib1dv (GLuint, const GLdouble *); GLAPI void APIENTRY glVertexAttrib1f (GLuint, GLfloat); GLAPI void APIENTRY glVertexAttrib1fv (GLuint, const GLfloat *); GLAPI void APIENTRY glVertexAttrib1s (GLuint, GLshort); GLAPI void APIENTRY glVertexAttrib1sv (GLuint, const GLshort *); GLAPI void APIENTRY glVertexAttrib2d (GLuint, GLdouble, GLdouble); GLAPI void APIENTRY glVertexAttrib2dv (GLuint, const GLdouble *); GLAPI void APIENTRY glVertexAttrib2f (GLuint, GLfloat, GLfloat); GLAPI void APIENTRY glVertexAttrib2fv (GLuint, const GLfloat *); GLAPI void APIENTRY glVertexAttrib2s (GLuint, GLshort, GLshort); GLAPI void APIENTRY glVertexAttrib2sv (GLuint, const GLshort *); GLAPI void APIENTRY glVertexAttrib3d (GLuint, GLdouble, GLdouble, GLdouble); GLAPI void APIENTRY glVertexAttrib3dv (GLuint, const GLdouble *); GLAPI void APIENTRY glVertexAttrib3f (GLuint, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glVertexAttrib3fv (GLuint, const GLfloat *); GLAPI void APIENTRY glVertexAttrib3s (GLuint, GLshort, GLshort, GLshort); GLAPI void APIENTRY glVertexAttrib3sv (GLuint, const GLshort *); GLAPI void APIENTRY glVertexAttrib4Nbv (GLuint, const GLbyte *); GLAPI void APIENTRY glVertexAttrib4Niv (GLuint, const GLint *); GLAPI void APIENTRY glVertexAttrib4Nsv (GLuint, const GLshort *); GLAPI void APIENTRY glVertexAttrib4Nub (GLuint, GLubyte, GLubyte, GLubyte, GLubyte); GLAPI void APIENTRY glVertexAttrib4Nubv (GLuint, const GLubyte *); GLAPI void APIENTRY glVertexAttrib4Nuiv (GLuint, const GLuint *); GLAPI void APIENTRY glVertexAttrib4Nusv (GLuint, const GLushort *); GLAPI void APIENTRY glVertexAttrib4bv (GLuint, const GLbyte *); GLAPI void APIENTRY glVertexAttrib4d (GLuint, GLdouble, GLdouble, GLdouble, GLdouble); GLAPI void APIENTRY glVertexAttrib4dv (GLuint, const GLdouble *); GLAPI void APIENTRY glVertexAttrib4f (GLuint, GLfloat, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glVertexAttrib4fv (GLuint, const GLfloat *); GLAPI void APIENTRY glVertexAttrib4iv (GLuint, const GLint *); GLAPI void APIENTRY glVertexAttrib4s (GLuint, GLshort, GLshort, GLshort, GLshort); GLAPI void APIENTRY glVertexAttrib4sv (GLuint, const GLshort *); GLAPI void APIENTRY glVertexAttrib4ubv (GLuint, const GLubyte *); GLAPI void APIENTRY glVertexAttrib4uiv (GLuint, const GLuint *); GLAPI void APIENTRY glVertexAttrib4usv (GLuint, const GLushort *); GLAPI void APIENTRY glVertexAttribPointer (GLuint, GLint, GLenum, GLboolean, GLsizei, const GLvoid *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEPROC) (GLenum modeRGB, GLenum modeAlpha); typedef void (APIENTRYP PFNGLDRAWBUFFERSPROC) (GLsizei n, const GLenum *bufs); typedef void (APIENTRYP PFNGLSTENCILOPSEPARATEPROC) (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); typedef void (APIENTRYP PFNGLSTENCILFUNCSEPARATEPROC) (GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask); typedef void (APIENTRYP PFNGLSTENCILMASKSEPARATEPROC) (GLenum face, GLuint mask); typedef void (APIENTRYP PFNGLATTACHSHADERPROC) (GLuint program, GLuint shader); typedef void (APIENTRYP PFNGLBINDATTRIBLOCATIONPROC) (GLuint program, GLuint index, const GLchar *name); typedef void (APIENTRYP PFNGLCOMPILESHADERPROC) (GLuint shader); typedef GLuint (APIENTRYP PFNGLCREATEPROGRAMPROC) (void); typedef GLuint (APIENTRYP PFNGLCREATESHADERPROC) (GLenum type); typedef void (APIENTRYP PFNGLDELETEPROGRAMPROC) (GLuint program); typedef void (APIENTRYP PFNGLDELETESHADERPROC) (GLuint shader); typedef void (APIENTRYP PFNGLDETACHSHADERPROC) (GLuint program, GLuint shader); typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYPROC) (GLuint index); typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYPROC) (GLuint index); typedef void (APIENTRYP PFNGLGETACTIVEATTRIBPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); typedef void (APIENTRYP PFNGLGETATTACHEDSHADERSPROC) (GLuint program, GLsizei maxCount, GLsizei *count, GLuint *obj); typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONPROC) (GLuint program, const GLchar *name); typedef void (APIENTRYP PFNGLGETPROGRAMIVPROC) (GLuint program, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog); typedef void (APIENTRYP PFNGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog); typedef void (APIENTRYP PFNGLGETSHADERSOURCEPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source); typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONPROC) (GLuint program, const GLchar *name); typedef void (APIENTRYP PFNGLGETUNIFORMFVPROC) (GLuint program, GLint location, GLfloat *params); typedef void (APIENTRYP PFNGLGETUNIFORMIVPROC) (GLuint program, GLint location, GLint *params); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVPROC) (GLuint index, GLenum pname, GLdouble *params); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVPROC) (GLuint index, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVPROC) (GLuint index, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVPROC) (GLuint index, GLenum pname, GLvoid* *pointer); typedef GLboolean (APIENTRYP PFNGLISPROGRAMPROC) (GLuint program); typedef GLboolean (APIENTRYP PFNGLISSHADERPROC) (GLuint shader); typedef void (APIENTRYP PFNGLLINKPROGRAMPROC) (GLuint program); typedef void (APIENTRYP PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const GLchar* *string, const GLint *length); typedef void (APIENTRYP PFNGLUSEPROGRAMPROC) (GLuint program); typedef void (APIENTRYP PFNGLUNIFORM1FPROC) (GLint location, GLfloat v0); typedef void (APIENTRYP PFNGLUNIFORM2FPROC) (GLint location, GLfloat v0, GLfloat v1); typedef void (APIENTRYP PFNGLUNIFORM3FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); typedef void (APIENTRYP PFNGLUNIFORM4FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); typedef void (APIENTRYP PFNGLUNIFORM1IPROC) (GLint location, GLint v0); typedef void (APIENTRYP PFNGLUNIFORM2IPROC) (GLint location, GLint v0, GLint v1); typedef void (APIENTRYP PFNGLUNIFORM3IPROC) (GLint location, GLint v0, GLint v1, GLint v2); typedef void (APIENTRYP PFNGLUNIFORM4IPROC) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); typedef void (APIENTRYP PFNGLUNIFORM1FVPROC) (GLint location, GLsizei count, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORM2FVPROC) (GLint location, GLsizei count, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORM3FVPROC) (GLint location, GLsizei count, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORM4FVPROC) (GLint location, GLsizei count, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORM1IVPROC) (GLint location, GLsizei count, const GLint *value); typedef void (APIENTRYP PFNGLUNIFORM2IVPROC) (GLint location, GLsizei count, const GLint *value); typedef void (APIENTRYP PFNGLUNIFORM3IVPROC) (GLint location, GLsizei count, const GLint *value); typedef void (APIENTRYP PFNGLUNIFORM4IVPROC) (GLint location, GLsizei count, const GLint *value); typedef void (APIENTRYP PFNGLUNIFORMMATRIX2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORMMATRIX3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLVALIDATEPROGRAMPROC) (GLuint program); typedef void (APIENTRYP PFNGLVERTEXATTRIB1DPROC) (GLuint index, GLdouble x); typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB1FPROC) (GLuint index, GLfloat x); typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVPROC) (GLuint index, const GLfloat *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB1SPROC) (GLuint index, GLshort x); typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVPROC) (GLuint index, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB2DPROC) (GLuint index, GLdouble x, GLdouble y); typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB2FPROC) (GLuint index, GLfloat x, GLfloat y); typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVPROC) (GLuint index, const GLfloat *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB2SPROC) (GLuint index, GLshort x, GLshort y); typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVPROC) (GLuint index, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB3DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z); typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB3FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVPROC) (GLuint index, const GLfloat *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB3SPROC) (GLuint index, GLshort x, GLshort y, GLshort z); typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVPROC) (GLuint index, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4NBVPROC) (GLuint index, const GLbyte *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4NIVPROC) (GLuint index, const GLint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4NSVPROC) (GLuint index, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBVPROC) (GLuint index, const GLubyte *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUIVPROC) (GLuint index, const GLuint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUSVPROC) (GLuint index, const GLushort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4BVPROC) (GLuint index, const GLbyte *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVPROC) (GLuint index, const GLfloat *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4IVPROC) (GLuint index, const GLint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4SPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVPROC) (GLuint index, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVPROC) (GLuint index, const GLubyte *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4UIVPROC) (GLuint index, const GLuint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4USVPROC) (GLuint index, const GLushort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer); #endif #ifndef GL_VERSION_2_1 #define GL_VERSION_2_1 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glUniformMatrix2x3fv (GLint, GLsizei, GLboolean, const GLfloat *); GLAPI void APIENTRY glUniformMatrix3x2fv (GLint, GLsizei, GLboolean, const GLfloat *); GLAPI void APIENTRY glUniformMatrix2x4fv (GLint, GLsizei, GLboolean, const GLfloat *); GLAPI void APIENTRY glUniformMatrix4x2fv (GLint, GLsizei, GLboolean, const GLfloat *); GLAPI void APIENTRY glUniformMatrix3x4fv (GLint, GLsizei, GLboolean, const GLfloat *); GLAPI void APIENTRY glUniformMatrix4x3fv (GLint, GLsizei, GLboolean, const GLfloat *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); #endif #ifndef GL_VERSION_3_0 #define GL_VERSION_3_0 1 /* OpenGL 3.0 also reuses entry points from these extensions: */ /* ARB_framebuffer_object */ /* ARB_map_buffer_range */ /* ARB_vertex_array_object */ #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glColorMaski (GLuint, GLboolean, GLboolean, GLboolean, GLboolean); GLAPI void APIENTRY glGetBooleani_v (GLenum, GLuint, GLboolean *); GLAPI void APIENTRY glGetIntegeri_v (GLenum, GLuint, GLint *); GLAPI void APIENTRY glEnablei (GLenum, GLuint); GLAPI void APIENTRY glDisablei (GLenum, GLuint); GLAPI GLboolean APIENTRY glIsEnabledi (GLenum, GLuint); GLAPI void APIENTRY glBeginTransformFeedback (GLenum); GLAPI void APIENTRY glEndTransformFeedback (void); GLAPI void APIENTRY glBindBufferRange (GLenum, GLuint, GLuint, GLintptr, GLsizeiptr); GLAPI void APIENTRY glBindBufferBase (GLenum, GLuint, GLuint); GLAPI void APIENTRY glTransformFeedbackVaryings (GLuint, GLsizei, const GLint *, GLenum); GLAPI void APIENTRY glGetTransformFeedbackVarying (GLuint, GLuint, GLint *); GLAPI void APIENTRY glClampColor (GLenum, GLenum); GLAPI void APIENTRY glBeginConditionalRender (GLuint, GLenum); GLAPI void APIENTRY glEndConditionalRender (void); GLAPI void APIENTRY glVertexAttribI1i (GLuint, GLint); GLAPI void APIENTRY glVertexAttribI2i (GLuint, GLint, GLint); GLAPI void APIENTRY glVertexAttribI3i (GLuint, GLint, GLint, GLint); GLAPI void APIENTRY glVertexAttribI4i (GLuint, GLint, GLint, GLint, GLint); GLAPI void APIENTRY glVertexAttribI1ui (GLuint, GLuint); GLAPI void APIENTRY glVertexAttribI2ui (GLuint, GLuint, GLuint); GLAPI void APIENTRY glVertexAttribI3ui (GLuint, GLuint, GLuint, GLuint); GLAPI void APIENTRY glVertexAttribI4ui (GLuint, GLuint, GLuint, GLuint, GLuint); GLAPI void APIENTRY glVertexAttribI1iv (GLuint, const GLint *); GLAPI void APIENTRY glVertexAttribI2iv (GLuint, const GLint *); GLAPI void APIENTRY glVertexAttribI3iv (GLuint, const GLint *); GLAPI void APIENTRY glVertexAttribI4iv (GLuint, const GLint *); GLAPI void APIENTRY glVertexAttribI1uiv (GLuint, const GLuint *); GLAPI void APIENTRY glVertexAttribI2uiv (GLuint, const GLuint *); GLAPI void APIENTRY glVertexAttribI3uiv (GLuint, const GLuint *); GLAPI void APIENTRY glVertexAttribI4uiv (GLuint, const GLuint *); GLAPI void APIENTRY glVertexAttribI4bv (GLuint, const GLbyte *); GLAPI void APIENTRY glVertexAttribI4sv (GLuint, const GLshort *); GLAPI void APIENTRY glVertexAttribI4ubv (GLuint, const GLubyte *); GLAPI void APIENTRY glVertexAttribI4usv (GLuint, const GLushort *); GLAPI void APIENTRY glVertexAttribIPointer (GLuint, GLint, GLenum, GLsizei, const GLvoid *); GLAPI void APIENTRY glGetVertexAttribIiv (GLuint, GLenum, GLint *); GLAPI void APIENTRY glGetVertexAttribIuiv (GLuint, GLenum, GLuint *); GLAPI void APIENTRY glGetUniformuiv (GLuint, GLint, GLuint *); GLAPI void APIENTRY glBindFragDataLocation (GLuint, GLuint, const GLchar *); GLAPI GLint APIENTRY glGetFragDataLocation (GLuint, const GLchar *); GLAPI void APIENTRY glUniform1ui (GLint, GLuint); GLAPI void APIENTRY glUniform2ui (GLint, GLuint, GLuint); GLAPI void APIENTRY glUniform3ui (GLint, GLuint, GLuint, GLuint); GLAPI void APIENTRY glUniform4ui (GLint, GLuint, GLuint, GLuint, GLuint); GLAPI void APIENTRY glUniform1uiv (GLint, GLsizei, const GLuint *); GLAPI void APIENTRY glUniform2uiv (GLint, GLsizei, const GLuint *); GLAPI void APIENTRY glUniform3uiv (GLint, GLsizei, const GLuint *); GLAPI void APIENTRY glUniform4uiv (GLint, GLsizei, const GLuint *); GLAPI void APIENTRY glTexParameterIiv (GLenum, GLenum, const GLint *); GLAPI void APIENTRY glTexParameterIuiv (GLenum, GLenum, const GLuint *); GLAPI void APIENTRY glGetTexParameterIiv (GLenum, GLenum, GLint *); GLAPI void APIENTRY glGetTexParameterIuiv (GLenum, GLenum, GLuint *); GLAPI void APIENTRY glClearBufferiv (GLenum, GLint, const GLint *); GLAPI void APIENTRY glClearBufferuiv (GLenum, GLint, const GLuint *); GLAPI void APIENTRY glClearBufferfv (GLenum, GLint, const GLfloat *); GLAPI void APIENTRY glClearBufferfi (GLenum, GLint, GLfloat, GLint); GLAPI const GLubyte * APIENTRY glGetStringi (GLenum, GLuint); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLCOLORMASKIPROC) (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); typedef void (APIENTRYP PFNGLGETBOOLEANI_VPROC) (GLenum target, GLuint index, GLboolean *data); typedef void (APIENTRYP PFNGLGETINTEGERI_VPROC) (GLenum target, GLuint index, GLint *data); typedef void (APIENTRYP PFNGLENABLEIPROC) (GLenum target, GLuint index); typedef void (APIENTRYP PFNGLDISABLEIPROC) (GLenum target, GLuint index); typedef GLboolean (APIENTRYP PFNGLISENABLEDIPROC) (GLenum target, GLuint index); typedef void (APIENTRYP PFNGLBEGINTRANSFORMFEEDBACKPROC) (GLenum primitiveMode); typedef void (APIENTRYP PFNGLENDTRANSFORMFEEDBACKPROC) (void); typedef void (APIENTRYP PFNGLBINDBUFFERRANGEPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); typedef void (APIENTRYP PFNGLBINDBUFFERBASEPROC) (GLenum target, GLuint index, GLuint buffer); typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKVARYINGSPROC) (GLuint program, GLsizei count, const GLint *locations, GLenum bufferMode); typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKVARYINGPROC) (GLuint program, GLuint index, GLint *location); typedef void (APIENTRYP PFNGLCLAMPCOLORPROC) (GLenum target, GLenum clamp); typedef void (APIENTRYP PFNGLBEGINCONDITIONALRENDERPROC) (GLuint id, GLenum mode); typedef void (APIENTRYP PFNGLENDCONDITIONALRENDERPROC) (void); typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IPROC) (GLuint index, GLint x); typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IPROC) (GLuint index, GLint x, GLint y); typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IPROC) (GLuint index, GLint x, GLint y, GLint z); typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IPROC) (GLuint index, GLint x, GLint y, GLint z, GLint w); typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIPROC) (GLuint index, GLuint x); typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIPROC) (GLuint index, GLuint x, GLuint y); typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIPROC) (GLuint index, GLuint x, GLuint y, GLuint z); typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIPROC) (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IVPROC) (GLuint index, const GLint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IVPROC) (GLuint index, const GLint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IVPROC) (GLuint index, const GLint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IVPROC) (GLuint index, const GLint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIVPROC) (GLuint index, const GLuint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIVPROC) (GLuint index, const GLuint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIVPROC) (GLuint index, const GLuint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIVPROC) (GLuint index, const GLuint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI4BVPROC) (GLuint index, const GLbyte *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI4SVPROC) (GLuint index, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UBVPROC) (GLuint index, const GLubyte *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI4USVPROC) (GLuint index, const GLushort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBIPOINTERPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIIVPROC) (GLuint index, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIUIVPROC) (GLuint index, GLenum pname, GLuint *params); typedef void (APIENTRYP PFNGLGETUNIFORMUIVPROC) (GLuint program, GLint location, GLuint *params); typedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONPROC) (GLuint program, GLuint color, const GLchar *name); typedef GLint (APIENTRYP PFNGLGETFRAGDATALOCATIONPROC) (GLuint program, const GLchar *name); typedef void (APIENTRYP PFNGLUNIFORM1UIPROC) (GLint location, GLuint v0); typedef void (APIENTRYP PFNGLUNIFORM2UIPROC) (GLint location, GLuint v0, GLuint v1); typedef void (APIENTRYP PFNGLUNIFORM3UIPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2); typedef void (APIENTRYP PFNGLUNIFORM4UIPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); typedef void (APIENTRYP PFNGLUNIFORM1UIVPROC) (GLint location, GLsizei count, const GLuint *value); typedef void (APIENTRYP PFNGLUNIFORM2UIVPROC) (GLint location, GLsizei count, const GLuint *value); typedef void (APIENTRYP PFNGLUNIFORM3UIVPROC) (GLint location, GLsizei count, const GLuint *value); typedef void (APIENTRYP PFNGLUNIFORM4UIVPROC) (GLint location, GLsizei count, const GLuint *value); typedef void (APIENTRYP PFNGLTEXPARAMETERIIVPROC) (GLenum target, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLTEXPARAMETERIUIVPROC) (GLenum target, GLenum pname, const GLuint *params); typedef void (APIENTRYP PFNGLGETTEXPARAMETERIIVPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETTEXPARAMETERIUIVPROC) (GLenum target, GLenum pname, GLuint *params); typedef void (APIENTRYP PFNGLCLEARBUFFERIVPROC) (GLenum buffer, GLint drawbuffer, const GLint *value); typedef void (APIENTRYP PFNGLCLEARBUFFERUIVPROC) (GLenum buffer, GLint drawbuffer, const GLuint *value); typedef void (APIENTRYP PFNGLCLEARBUFFERFVPROC) (GLenum buffer, GLint drawbuffer, const GLfloat *value); typedef void (APIENTRYP PFNGLCLEARBUFFERFIPROC) (GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); typedef const GLubyte * (APIENTRYP PFNGLGETSTRINGIPROC) (GLenum name, GLuint index); #endif #ifndef GL_ARB_multitexture #define GL_ARB_multitexture 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glActiveTextureARB (GLenum); GLAPI void APIENTRY glClientActiveTextureARB (GLenum); GLAPI void APIENTRY glMultiTexCoord1dARB (GLenum, GLdouble); GLAPI void APIENTRY glMultiTexCoord1dvARB (GLenum, const GLdouble *); GLAPI void APIENTRY glMultiTexCoord1fARB (GLenum, GLfloat); GLAPI void APIENTRY glMultiTexCoord1fvARB (GLenum, const GLfloat *); GLAPI void APIENTRY glMultiTexCoord1iARB (GLenum, GLint); GLAPI void APIENTRY glMultiTexCoord1ivARB (GLenum, const GLint *); GLAPI void APIENTRY glMultiTexCoord1sARB (GLenum, GLshort); GLAPI void APIENTRY glMultiTexCoord1svARB (GLenum, const GLshort *); GLAPI void APIENTRY glMultiTexCoord2dARB (GLenum, GLdouble, GLdouble); GLAPI void APIENTRY glMultiTexCoord2dvARB (GLenum, const GLdouble *); GLAPI void APIENTRY glMultiTexCoord2fARB (GLenum, GLfloat, GLfloat); GLAPI void APIENTRY glMultiTexCoord2fvARB (GLenum, const GLfloat *); GLAPI void APIENTRY glMultiTexCoord2iARB (GLenum, GLint, GLint); GLAPI void APIENTRY glMultiTexCoord2ivARB (GLenum, const GLint *); GLAPI void APIENTRY glMultiTexCoord2sARB (GLenum, GLshort, GLshort); GLAPI void APIENTRY glMultiTexCoord2svARB (GLenum, const GLshort *); GLAPI void APIENTRY glMultiTexCoord3dARB (GLenum, GLdouble, GLdouble, GLdouble); GLAPI void APIENTRY glMultiTexCoord3dvARB (GLenum, const GLdouble *); GLAPI void APIENTRY glMultiTexCoord3fARB (GLenum, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glMultiTexCoord3fvARB (GLenum, const GLfloat *); GLAPI void APIENTRY glMultiTexCoord3iARB (GLenum, GLint, GLint, GLint); GLAPI void APIENTRY glMultiTexCoord3ivARB (GLenum, const GLint *); GLAPI void APIENTRY glMultiTexCoord3sARB (GLenum, GLshort, GLshort, GLshort); GLAPI void APIENTRY glMultiTexCoord3svARB (GLenum, const GLshort *); GLAPI void APIENTRY glMultiTexCoord4dARB (GLenum, GLdouble, GLdouble, GLdouble, GLdouble); GLAPI void APIENTRY glMultiTexCoord4dvARB (GLenum, const GLdouble *); GLAPI void APIENTRY glMultiTexCoord4fARB (GLenum, GLfloat, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glMultiTexCoord4fvARB (GLenum, const GLfloat *); GLAPI void APIENTRY glMultiTexCoord4iARB (GLenum, GLint, GLint, GLint, GLint); GLAPI void APIENTRY glMultiTexCoord4ivARB (GLenum, const GLint *); GLAPI void APIENTRY glMultiTexCoord4sARB (GLenum, GLshort, GLshort, GLshort, GLshort); GLAPI void APIENTRY glMultiTexCoord4svARB (GLenum, const GLshort *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLACTIVETEXTUREARBPROC) (GLenum texture); typedef void (APIENTRYP PFNGLCLIENTACTIVETEXTUREARBPROC) (GLenum texture); typedef void (APIENTRYP PFNGLMULTITEXCOORD1DARBPROC) (GLenum target, GLdouble s); typedef void (APIENTRYP PFNGLMULTITEXCOORD1DVARBPROC) (GLenum target, const GLdouble *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD1FARBPROC) (GLenum target, GLfloat s); typedef void (APIENTRYP PFNGLMULTITEXCOORD1FVARBPROC) (GLenum target, const GLfloat *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD1IARBPROC) (GLenum target, GLint s); typedef void (APIENTRYP PFNGLMULTITEXCOORD1IVARBPROC) (GLenum target, const GLint *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD1SARBPROC) (GLenum target, GLshort s); typedef void (APIENTRYP PFNGLMULTITEXCOORD1SVARBPROC) (GLenum target, const GLshort *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD2DARBPROC) (GLenum target, GLdouble s, GLdouble t); typedef void (APIENTRYP PFNGLMULTITEXCOORD2DVARBPROC) (GLenum target, const GLdouble *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD2FARBPROC) (GLenum target, GLfloat s, GLfloat t); typedef void (APIENTRYP PFNGLMULTITEXCOORD2FVARBPROC) (GLenum target, const GLfloat *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD2IARBPROC) (GLenum target, GLint s, GLint t); typedef void (APIENTRYP PFNGLMULTITEXCOORD2IVARBPROC) (GLenum target, const GLint *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD2SARBPROC) (GLenum target, GLshort s, GLshort t); typedef void (APIENTRYP PFNGLMULTITEXCOORD2SVARBPROC) (GLenum target, const GLshort *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD3DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r); typedef void (APIENTRYP PFNGLMULTITEXCOORD3DVARBPROC) (GLenum target, const GLdouble *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD3FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r); typedef void (APIENTRYP PFNGLMULTITEXCOORD3FVARBPROC) (GLenum target, const GLfloat *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD3IARBPROC) (GLenum target, GLint s, GLint t, GLint r); typedef void (APIENTRYP PFNGLMULTITEXCOORD3IVARBPROC) (GLenum target, const GLint *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD3SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r); typedef void (APIENTRYP PFNGLMULTITEXCOORD3SVARBPROC) (GLenum target, const GLshort *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD4DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q); typedef void (APIENTRYP PFNGLMULTITEXCOORD4DVARBPROC) (GLenum target, const GLdouble *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD4FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); typedef void (APIENTRYP PFNGLMULTITEXCOORD4FVARBPROC) (GLenum target, const GLfloat *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD4IARBPROC) (GLenum target, GLint s, GLint t, GLint r, GLint q); typedef void (APIENTRYP PFNGLMULTITEXCOORD4IVARBPROC) (GLenum target, const GLint *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD4SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q); typedef void (APIENTRYP PFNGLMULTITEXCOORD4SVARBPROC) (GLenum target, const GLshort *v); #endif #ifndef GL_ARB_transpose_matrix #define GL_ARB_transpose_matrix 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glLoadTransposeMatrixfARB (const GLfloat *); GLAPI void APIENTRY glLoadTransposeMatrixdARB (const GLdouble *); GLAPI void APIENTRY glMultTransposeMatrixfARB (const GLfloat *); GLAPI void APIENTRY glMultTransposeMatrixdARB (const GLdouble *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXFARBPROC) (const GLfloat *m); typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXDARBPROC) (const GLdouble *m); typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXFARBPROC) (const GLfloat *m); typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXDARBPROC) (const GLdouble *m); #endif #ifndef GL_ARB_multisample #define GL_ARB_multisample 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glSampleCoverageARB (GLclampf, GLboolean); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLSAMPLECOVERAGEARBPROC) (GLclampf value, GLboolean invert); #endif #ifndef GL_ARB_texture_env_add #define GL_ARB_texture_env_add 1 #endif #ifndef GL_ARB_texture_cube_map #define GL_ARB_texture_cube_map 1 #endif #ifndef GL_ARB_texture_compression #define GL_ARB_texture_compression 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glCompressedTexImage3DARB (GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLint, GLsizei, const GLvoid *); GLAPI void APIENTRY glCompressedTexImage2DARB (GLenum, GLint, GLenum, GLsizei, GLsizei, GLint, GLsizei, const GLvoid *); GLAPI void APIENTRY glCompressedTexImage1DARB (GLenum, GLint, GLenum, GLsizei, GLint, GLsizei, const GLvoid *); GLAPI void APIENTRY glCompressedTexSubImage3DARB (GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid *); GLAPI void APIENTRY glCompressedTexSubImage2DARB (GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid *); GLAPI void APIENTRY glCompressedTexSubImage1DARB (GLenum, GLint, GLint, GLsizei, GLenum, GLsizei, const GLvoid *); GLAPI void APIENTRY glGetCompressedTexImageARB (GLenum, GLint, GLvoid *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data); typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEARBPROC) (GLenum target, GLint level, GLvoid *img); #endif #ifndef GL_ARB_texture_border_clamp #define GL_ARB_texture_border_clamp 1 #endif #ifndef GL_ARB_point_parameters #define GL_ARB_point_parameters 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glPointParameterfARB (GLenum, GLfloat); GLAPI void APIENTRY glPointParameterfvARB (GLenum, const GLfloat *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLPOINTPARAMETERFARBPROC) (GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLPOINTPARAMETERFVARBPROC) (GLenum pname, const GLfloat *params); #endif #ifndef GL_ARB_vertex_blend #define GL_ARB_vertex_blend 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glWeightbvARB (GLint, const GLbyte *); GLAPI void APIENTRY glWeightsvARB (GLint, const GLshort *); GLAPI void APIENTRY glWeightivARB (GLint, const GLint *); GLAPI void APIENTRY glWeightfvARB (GLint, const GLfloat *); GLAPI void APIENTRY glWeightdvARB (GLint, const GLdouble *); GLAPI void APIENTRY glWeightubvARB (GLint, const GLubyte *); GLAPI void APIENTRY glWeightusvARB (GLint, const GLushort *); GLAPI void APIENTRY glWeightuivARB (GLint, const GLuint *); GLAPI void APIENTRY glWeightPointerARB (GLint, GLenum, GLsizei, const GLvoid *); GLAPI void APIENTRY glVertexBlendARB (GLint); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLWEIGHTBVARBPROC) (GLint size, const GLbyte *weights); typedef void (APIENTRYP PFNGLWEIGHTSVARBPROC) (GLint size, const GLshort *weights); typedef void (APIENTRYP PFNGLWEIGHTIVARBPROC) (GLint size, const GLint *weights); typedef void (APIENTRYP PFNGLWEIGHTFVARBPROC) (GLint size, const GLfloat *weights); typedef void (APIENTRYP PFNGLWEIGHTDVARBPROC) (GLint size, const GLdouble *weights); typedef void (APIENTRYP PFNGLWEIGHTUBVARBPROC) (GLint size, const GLubyte *weights); typedef void (APIENTRYP PFNGLWEIGHTUSVARBPROC) (GLint size, const GLushort *weights); typedef void (APIENTRYP PFNGLWEIGHTUIVARBPROC) (GLint size, const GLuint *weights); typedef void (APIENTRYP PFNGLWEIGHTPOINTERARBPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); typedef void (APIENTRYP PFNGLVERTEXBLENDARBPROC) (GLint count); #endif #ifndef GL_ARB_matrix_palette #define GL_ARB_matrix_palette 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glCurrentPaletteMatrixARB (GLint); GLAPI void APIENTRY glMatrixIndexubvARB (GLint, const GLubyte *); GLAPI void APIENTRY glMatrixIndexusvARB (GLint, const GLushort *); GLAPI void APIENTRY glMatrixIndexuivARB (GLint, const GLuint *); GLAPI void APIENTRY glMatrixIndexPointerARB (GLint, GLenum, GLsizei, const GLvoid *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLCURRENTPALETTEMATRIXARBPROC) (GLint index); typedef void (APIENTRYP PFNGLMATRIXINDEXUBVARBPROC) (GLint size, const GLubyte *indices); typedef void (APIENTRYP PFNGLMATRIXINDEXUSVARBPROC) (GLint size, const GLushort *indices); typedef void (APIENTRYP PFNGLMATRIXINDEXUIVARBPROC) (GLint size, const GLuint *indices); typedef void (APIENTRYP PFNGLMATRIXINDEXPOINTERARBPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); #endif #ifndef GL_ARB_texture_env_combine #define GL_ARB_texture_env_combine 1 #endif #ifndef GL_ARB_texture_env_crossbar #define GL_ARB_texture_env_crossbar 1 #endif #ifndef GL_ARB_texture_env_dot3 #define GL_ARB_texture_env_dot3 1 #endif #ifndef GL_ARB_texture_mirrored_repeat #define GL_ARB_texture_mirrored_repeat 1 #endif #ifndef GL_ARB_depth_texture #define GL_ARB_depth_texture 1 #endif #ifndef GL_ARB_shadow #define GL_ARB_shadow 1 #endif #ifndef GL_ARB_shadow_ambient #define GL_ARB_shadow_ambient 1 #endif #ifndef GL_ARB_window_pos #define GL_ARB_window_pos 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glWindowPos2dARB (GLdouble, GLdouble); GLAPI void APIENTRY glWindowPos2dvARB (const GLdouble *); GLAPI void APIENTRY glWindowPos2fARB (GLfloat, GLfloat); GLAPI void APIENTRY glWindowPos2fvARB (const GLfloat *); GLAPI void APIENTRY glWindowPos2iARB (GLint, GLint); GLAPI void APIENTRY glWindowPos2ivARB (const GLint *); GLAPI void APIENTRY glWindowPos2sARB (GLshort, GLshort); GLAPI void APIENTRY glWindowPos2svARB (const GLshort *); GLAPI void APIENTRY glWindowPos3dARB (GLdouble, GLdouble, GLdouble); GLAPI void APIENTRY glWindowPos3dvARB (const GLdouble *); GLAPI void APIENTRY glWindowPos3fARB (GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glWindowPos3fvARB (const GLfloat *); GLAPI void APIENTRY glWindowPos3iARB (GLint, GLint, GLint); GLAPI void APIENTRY glWindowPos3ivARB (const GLint *); GLAPI void APIENTRY glWindowPos3sARB (GLshort, GLshort, GLshort); GLAPI void APIENTRY glWindowPos3svARB (const GLshort *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLWINDOWPOS2DARBPROC) (GLdouble x, GLdouble y); typedef void (APIENTRYP PFNGLWINDOWPOS2DVARBPROC) (const GLdouble *v); typedef void (APIENTRYP PFNGLWINDOWPOS2FARBPROC) (GLfloat x, GLfloat y); typedef void (APIENTRYP PFNGLWINDOWPOS2FVARBPROC) (const GLfloat *v); typedef void (APIENTRYP PFNGLWINDOWPOS2IARBPROC) (GLint x, GLint y); typedef void (APIENTRYP PFNGLWINDOWPOS2IVARBPROC) (const GLint *v); typedef void (APIENTRYP PFNGLWINDOWPOS2SARBPROC) (GLshort x, GLshort y); typedef void (APIENTRYP PFNGLWINDOWPOS2SVARBPROC) (const GLshort *v); typedef void (APIENTRYP PFNGLWINDOWPOS3DARBPROC) (GLdouble x, GLdouble y, GLdouble z); typedef void (APIENTRYP PFNGLWINDOWPOS3DVARBPROC) (const GLdouble *v); typedef void (APIENTRYP PFNGLWINDOWPOS3FARBPROC) (GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLWINDOWPOS3FVARBPROC) (const GLfloat *v); typedef void (APIENTRYP PFNGLWINDOWPOS3IARBPROC) (GLint x, GLint y, GLint z); typedef void (APIENTRYP PFNGLWINDOWPOS3IVARBPROC) (const GLint *v); typedef void (APIENTRYP PFNGLWINDOWPOS3SARBPROC) (GLshort x, GLshort y, GLshort z); typedef void (APIENTRYP PFNGLWINDOWPOS3SVARBPROC) (const GLshort *v); #endif #ifndef GL_ARB_vertex_program #define GL_ARB_vertex_program 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glVertexAttrib1dARB (GLuint, GLdouble); GLAPI void APIENTRY glVertexAttrib1dvARB (GLuint, const GLdouble *); GLAPI void APIENTRY glVertexAttrib1fARB (GLuint, GLfloat); GLAPI void APIENTRY glVertexAttrib1fvARB (GLuint, const GLfloat *); GLAPI void APIENTRY glVertexAttrib1sARB (GLuint, GLshort); GLAPI void APIENTRY glVertexAttrib1svARB (GLuint, const GLshort *); GLAPI void APIENTRY glVertexAttrib2dARB (GLuint, GLdouble, GLdouble); GLAPI void APIENTRY glVertexAttrib2dvARB (GLuint, const GLdouble *); GLAPI void APIENTRY glVertexAttrib2fARB (GLuint, GLfloat, GLfloat); GLAPI void APIENTRY glVertexAttrib2fvARB (GLuint, const GLfloat *); GLAPI void APIENTRY glVertexAttrib2sARB (GLuint, GLshort, GLshort); GLAPI void APIENTRY glVertexAttrib2svARB (GLuint, const GLshort *); GLAPI void APIENTRY glVertexAttrib3dARB (GLuint, GLdouble, GLdouble, GLdouble); GLAPI void APIENTRY glVertexAttrib3dvARB (GLuint, const GLdouble *); GLAPI void APIENTRY glVertexAttrib3fARB (GLuint, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glVertexAttrib3fvARB (GLuint, const GLfloat *); GLAPI void APIENTRY glVertexAttrib3sARB (GLuint, GLshort, GLshort, GLshort); GLAPI void APIENTRY glVertexAttrib3svARB (GLuint, const GLshort *); GLAPI void APIENTRY glVertexAttrib4NbvARB (GLuint, const GLbyte *); GLAPI void APIENTRY glVertexAttrib4NivARB (GLuint, const GLint *); GLAPI void APIENTRY glVertexAttrib4NsvARB (GLuint, const GLshort *); GLAPI void APIENTRY glVertexAttrib4NubARB (GLuint, GLubyte, GLubyte, GLubyte, GLubyte); GLAPI void APIENTRY glVertexAttrib4NubvARB (GLuint, const GLubyte *); GLAPI void APIENTRY glVertexAttrib4NuivARB (GLuint, const GLuint *); GLAPI void APIENTRY glVertexAttrib4NusvARB (GLuint, const GLushort *); GLAPI void APIENTRY glVertexAttrib4bvARB (GLuint, const GLbyte *); GLAPI void APIENTRY glVertexAttrib4dARB (GLuint, GLdouble, GLdouble, GLdouble, GLdouble); GLAPI void APIENTRY glVertexAttrib4dvARB (GLuint, const GLdouble *); GLAPI void APIENTRY glVertexAttrib4fARB (GLuint, GLfloat, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glVertexAttrib4fvARB (GLuint, const GLfloat *); GLAPI void APIENTRY glVertexAttrib4ivARB (GLuint, const GLint *); GLAPI void APIENTRY glVertexAttrib4sARB (GLuint, GLshort, GLshort, GLshort, GLshort); GLAPI void APIENTRY glVertexAttrib4svARB (GLuint, const GLshort *); GLAPI void APIENTRY glVertexAttrib4ubvARB (GLuint, const GLubyte *); GLAPI void APIENTRY glVertexAttrib4uivARB (GLuint, const GLuint *); GLAPI void APIENTRY glVertexAttrib4usvARB (GLuint, const GLushort *); GLAPI void APIENTRY glVertexAttribPointerARB (GLuint, GLint, GLenum, GLboolean, GLsizei, const GLvoid *); GLAPI void APIENTRY glEnableVertexAttribArrayARB (GLuint); GLAPI void APIENTRY glDisableVertexAttribArrayARB (GLuint); GLAPI void APIENTRY glProgramStringARB (GLenum, GLenum, GLsizei, const GLvoid *); GLAPI void APIENTRY glBindProgramARB (GLenum, GLuint); GLAPI void APIENTRY glDeleteProgramsARB (GLsizei, const GLuint *); GLAPI void APIENTRY glGenProgramsARB (GLsizei, GLuint *); GLAPI void APIENTRY glProgramEnvParameter4dARB (GLenum, GLuint, GLdouble, GLdouble, GLdouble, GLdouble); GLAPI void APIENTRY glProgramEnvParameter4dvARB (GLenum, GLuint, const GLdouble *); GLAPI void APIENTRY glProgramEnvParameter4fARB (GLenum, GLuint, GLfloat, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glProgramEnvParameter4fvARB (GLenum, GLuint, const GLfloat *); GLAPI void APIENTRY glProgramLocalParameter4dARB (GLenum, GLuint, GLdouble, GLdouble, GLdouble, GLdouble); GLAPI void APIENTRY glProgramLocalParameter4dvARB (GLenum, GLuint, const GLdouble *); GLAPI void APIENTRY glProgramLocalParameter4fARB (GLenum, GLuint, GLfloat, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glProgramLocalParameter4fvARB (GLenum, GLuint, const GLfloat *); GLAPI void APIENTRY glGetProgramEnvParameterdvARB (GLenum, GLuint, GLdouble *); GLAPI void APIENTRY glGetProgramEnvParameterfvARB (GLenum, GLuint, GLfloat *); GLAPI void APIENTRY glGetProgramLocalParameterdvARB (GLenum, GLuint, GLdouble *); GLAPI void APIENTRY glGetProgramLocalParameterfvARB (GLenum, GLuint, GLfloat *); GLAPI void APIENTRY glGetProgramivARB (GLenum, GLenum, GLint *); GLAPI void APIENTRY glGetProgramStringARB (GLenum, GLenum, GLvoid *); GLAPI void APIENTRY glGetVertexAttribdvARB (GLuint, GLenum, GLdouble *); GLAPI void APIENTRY glGetVertexAttribfvARB (GLuint, GLenum, GLfloat *); GLAPI void APIENTRY glGetVertexAttribivARB (GLuint, GLenum, GLint *); GLAPI void APIENTRY glGetVertexAttribPointervARB (GLuint, GLenum, GLvoid* *); GLAPI GLboolean APIENTRY glIsProgramARB (GLuint); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLVERTEXATTRIB1DARBPROC) (GLuint index, GLdouble x); typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVARBPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB1FARBPROC) (GLuint index, GLfloat x); typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVARBPROC) (GLuint index, const GLfloat *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB1SARBPROC) (GLuint index, GLshort x); typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVARBPROC) (GLuint index, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB2DARBPROC) (GLuint index, GLdouble x, GLdouble y); typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVARBPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB2FARBPROC) (GLuint index, GLfloat x, GLfloat y); typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVARBPROC) (GLuint index, const GLfloat *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB2SARBPROC) (GLuint index, GLshort x, GLshort y); typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVARBPROC) (GLuint index, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB3DARBPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z); typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVARBPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB3FARBPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVARBPROC) (GLuint index, const GLfloat *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB3SARBPROC) (GLuint index, GLshort x, GLshort y, GLshort z); typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVARBPROC) (GLuint index, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4NBVARBPROC) (GLuint index, const GLbyte *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4NIVARBPROC) (GLuint index, const GLint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4NSVARBPROC) (GLuint index, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBARBPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBVARBPROC) (GLuint index, const GLubyte *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUIVARBPROC) (GLuint index, const GLuint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUSVARBPROC) (GLuint index, const GLushort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4BVARBPROC) (GLuint index, const GLbyte *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4DARBPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVARBPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4FARBPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVARBPROC) (GLuint index, const GLfloat *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4IVARBPROC) (GLuint index, const GLint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4SARBPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVARBPROC) (GLuint index, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVARBPROC) (GLuint index, const GLubyte *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4UIVARBPROC) (GLuint index, const GLuint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4USVARBPROC) (GLuint index, const GLushort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERARBPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer); typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYARBPROC) (GLuint index); typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYARBPROC) (GLuint index); typedef void (APIENTRYP PFNGLPROGRAMSTRINGARBPROC) (GLenum target, GLenum format, GLsizei len, const GLvoid *string); typedef void (APIENTRYP PFNGLBINDPROGRAMARBPROC) (GLenum target, GLuint program); typedef void (APIENTRYP PFNGLDELETEPROGRAMSARBPROC) (GLsizei n, const GLuint *programs); typedef void (APIENTRYP PFNGLGENPROGRAMSARBPROC) (GLsizei n, GLuint *programs); typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4DARBPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4DVARBPROC) (GLenum target, GLuint index, const GLdouble *params); typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4FARBPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4FVARBPROC) (GLenum target, GLuint index, const GLfloat *params); typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4DARBPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4DVARBPROC) (GLenum target, GLuint index, const GLdouble *params); typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4FARBPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4FVARBPROC) (GLenum target, GLuint index, const GLfloat *params); typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERDVARBPROC) (GLenum target, GLuint index, GLdouble *params); typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERFVARBPROC) (GLenum target, GLuint index, GLfloat *params); typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC) (GLenum target, GLuint index, GLdouble *params); typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC) (GLenum target, GLuint index, GLfloat *params); typedef void (APIENTRYP PFNGLGETPROGRAMIVARBPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETPROGRAMSTRINGARBPROC) (GLenum target, GLenum pname, GLvoid *string); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVARBPROC) (GLuint index, GLenum pname, GLdouble *params); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVARBPROC) (GLuint index, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVARBPROC) (GLuint index, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVARBPROC) (GLuint index, GLenum pname, GLvoid* *pointer); typedef GLboolean (APIENTRYP PFNGLISPROGRAMARBPROC) (GLuint program); #endif #ifndef GL_ARB_fragment_program #define GL_ARB_fragment_program 1 /* All ARB_fragment_program entry points are shared with ARB_vertex_program. */ #endif #ifndef GL_ARB_vertex_buffer_object #define GL_ARB_vertex_buffer_object 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBindBufferARB (GLenum, GLuint); GLAPI void APIENTRY glDeleteBuffersARB (GLsizei, const GLuint *); GLAPI void APIENTRY glGenBuffersARB (GLsizei, GLuint *); GLAPI GLboolean APIENTRY glIsBufferARB (GLuint); GLAPI void APIENTRY glBufferDataARB (GLenum, GLsizeiptrARB, const GLvoid *, GLenum); GLAPI void APIENTRY glBufferSubDataARB (GLenum, GLintptrARB, GLsizeiptrARB, const GLvoid *); GLAPI void APIENTRY glGetBufferSubDataARB (GLenum, GLintptrARB, GLsizeiptrARB, GLvoid *); GLAPI GLvoid* APIENTRY glMapBufferARB (GLenum, GLenum); GLAPI GLboolean APIENTRY glUnmapBufferARB (GLenum); GLAPI void APIENTRY glGetBufferParameterivARB (GLenum, GLenum, GLint *); GLAPI void APIENTRY glGetBufferPointervARB (GLenum, GLenum, GLvoid* *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLBINDBUFFERARBPROC) (GLenum target, GLuint buffer); typedef void (APIENTRYP PFNGLDELETEBUFFERSARBPROC) (GLsizei n, const GLuint *buffers); typedef void (APIENTRYP PFNGLGENBUFFERSARBPROC) (GLsizei n, GLuint *buffers); typedef GLboolean (APIENTRYP PFNGLISBUFFERARBPROC) (GLuint buffer); typedef void (APIENTRYP PFNGLBUFFERDATAARBPROC) (GLenum target, GLsizeiptrARB size, const GLvoid *data, GLenum usage); typedef void (APIENTRYP PFNGLBUFFERSUBDATAARBPROC) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const GLvoid *data); typedef void (APIENTRYP PFNGLGETBUFFERSUBDATAARBPROC) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, GLvoid *data); typedef GLvoid* (APIENTRYP PFNGLMAPBUFFERARBPROC) (GLenum target, GLenum access); typedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERARBPROC) (GLenum target); typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERIVARBPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETBUFFERPOINTERVARBPROC) (GLenum target, GLenum pname, GLvoid* *params); #endif #ifndef GL_ARB_occlusion_query #define GL_ARB_occlusion_query 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glGenQueriesARB (GLsizei, GLuint *); GLAPI void APIENTRY glDeleteQueriesARB (GLsizei, const GLuint *); GLAPI GLboolean APIENTRY glIsQueryARB (GLuint); GLAPI void APIENTRY glBeginQueryARB (GLenum, GLuint); GLAPI void APIENTRY glEndQueryARB (GLenum); GLAPI void APIENTRY glGetQueryivARB (GLenum, GLenum, GLint *); GLAPI void APIENTRY glGetQueryObjectivARB (GLuint, GLenum, GLint *); GLAPI void APIENTRY glGetQueryObjectuivARB (GLuint, GLenum, GLuint *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLGENQUERIESARBPROC) (GLsizei n, GLuint *ids); typedef void (APIENTRYP PFNGLDELETEQUERIESARBPROC) (GLsizei n, const GLuint *ids); typedef GLboolean (APIENTRYP PFNGLISQUERYARBPROC) (GLuint id); typedef void (APIENTRYP PFNGLBEGINQUERYARBPROC) (GLenum target, GLuint id); typedef void (APIENTRYP PFNGLENDQUERYARBPROC) (GLenum target); typedef void (APIENTRYP PFNGLGETQUERYIVARBPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETQUERYOBJECTIVARBPROC) (GLuint id, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETQUERYOBJECTUIVARBPROC) (GLuint id, GLenum pname, GLuint *params); #endif #ifndef GL_ARB_shader_objects #define GL_ARB_shader_objects 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDeleteObjectARB (GLhandleARB); GLAPI GLhandleARB APIENTRY glGetHandleARB (GLenum); GLAPI void APIENTRY glDetachObjectARB (GLhandleARB, GLhandleARB); GLAPI GLhandleARB APIENTRY glCreateShaderObjectARB (GLenum); GLAPI void APIENTRY glShaderSourceARB (GLhandleARB, GLsizei, const GLcharARB* *, const GLint *); GLAPI void APIENTRY glCompileShaderARB (GLhandleARB); GLAPI GLhandleARB APIENTRY glCreateProgramObjectARB (void); GLAPI void APIENTRY glAttachObjectARB (GLhandleARB, GLhandleARB); GLAPI void APIENTRY glLinkProgramARB (GLhandleARB); GLAPI void APIENTRY glUseProgramObjectARB (GLhandleARB); GLAPI void APIENTRY glValidateProgramARB (GLhandleARB); GLAPI void APIENTRY glUniform1fARB (GLint, GLfloat); GLAPI void APIENTRY glUniform2fARB (GLint, GLfloat, GLfloat); GLAPI void APIENTRY glUniform3fARB (GLint, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glUniform4fARB (GLint, GLfloat, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glUniform1iARB (GLint, GLint); GLAPI void APIENTRY glUniform2iARB (GLint, GLint, GLint); GLAPI void APIENTRY glUniform3iARB (GLint, GLint, GLint, GLint); GLAPI void APIENTRY glUniform4iARB (GLint, GLint, GLint, GLint, GLint); GLAPI void APIENTRY glUniform1fvARB (GLint, GLsizei, const GLfloat *); GLAPI void APIENTRY glUniform2fvARB (GLint, GLsizei, const GLfloat *); GLAPI void APIENTRY glUniform3fvARB (GLint, GLsizei, const GLfloat *); GLAPI void APIENTRY glUniform4fvARB (GLint, GLsizei, const GLfloat *); GLAPI void APIENTRY glUniform1ivARB (GLint, GLsizei, const GLint *); GLAPI void APIENTRY glUniform2ivARB (GLint, GLsizei, const GLint *); GLAPI void APIENTRY glUniform3ivARB (GLint, GLsizei, const GLint *); GLAPI void APIENTRY glUniform4ivARB (GLint, GLsizei, const GLint *); GLAPI void APIENTRY glUniformMatrix2fvARB (GLint, GLsizei, GLboolean, const GLfloat *); GLAPI void APIENTRY glUniformMatrix3fvARB (GLint, GLsizei, GLboolean, const GLfloat *); GLAPI void APIENTRY glUniformMatrix4fvARB (GLint, GLsizei, GLboolean, const GLfloat *); GLAPI void APIENTRY glGetObjectParameterfvARB (GLhandleARB, GLenum, GLfloat *); GLAPI void APIENTRY glGetObjectParameterivARB (GLhandleARB, GLenum, GLint *); GLAPI void APIENTRY glGetInfoLogARB (GLhandleARB, GLsizei, GLsizei *, GLcharARB *); GLAPI void APIENTRY glGetAttachedObjectsARB (GLhandleARB, GLsizei, GLsizei *, GLhandleARB *); GLAPI GLint APIENTRY glGetUniformLocationARB (GLhandleARB, const GLcharARB *); GLAPI void APIENTRY glGetActiveUniformARB (GLhandleARB, GLuint, GLsizei, GLsizei *, GLint *, GLenum *, GLcharARB *); GLAPI void APIENTRY glGetUniformfvARB (GLhandleARB, GLint, GLfloat *); GLAPI void APIENTRY glGetUniformivARB (GLhandleARB, GLint, GLint *); GLAPI void APIENTRY glGetShaderSourceARB (GLhandleARB, GLsizei, GLsizei *, GLcharARB *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLDELETEOBJECTARBPROC) (GLhandleARB obj); typedef GLhandleARB (APIENTRYP PFNGLGETHANDLEARBPROC) (GLenum pname); typedef void (APIENTRYP PFNGLDETACHOBJECTARBPROC) (GLhandleARB containerObj, GLhandleARB attachedObj); typedef GLhandleARB (APIENTRYP PFNGLCREATESHADEROBJECTARBPROC) (GLenum shaderType); typedef void (APIENTRYP PFNGLSHADERSOURCEARBPROC) (GLhandleARB shaderObj, GLsizei count, const GLcharARB* *string, const GLint *length); typedef void (APIENTRYP PFNGLCOMPILESHADERARBPROC) (GLhandleARB shaderObj); typedef GLhandleARB (APIENTRYP PFNGLCREATEPROGRAMOBJECTARBPROC) (void); typedef void (APIENTRYP PFNGLATTACHOBJECTARBPROC) (GLhandleARB containerObj, GLhandleARB obj); typedef void (APIENTRYP PFNGLLINKPROGRAMARBPROC) (GLhandleARB programObj); typedef void (APIENTRYP PFNGLUSEPROGRAMOBJECTARBPROC) (GLhandleARB programObj); typedef void (APIENTRYP PFNGLVALIDATEPROGRAMARBPROC) (GLhandleARB programObj); typedef void (APIENTRYP PFNGLUNIFORM1FARBPROC) (GLint location, GLfloat v0); typedef void (APIENTRYP PFNGLUNIFORM2FARBPROC) (GLint location, GLfloat v0, GLfloat v1); typedef void (APIENTRYP PFNGLUNIFORM3FARBPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); typedef void (APIENTRYP PFNGLUNIFORM4FARBPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); typedef void (APIENTRYP PFNGLUNIFORM1IARBPROC) (GLint location, GLint v0); typedef void (APIENTRYP PFNGLUNIFORM2IARBPROC) (GLint location, GLint v0, GLint v1); typedef void (APIENTRYP PFNGLUNIFORM3IARBPROC) (GLint location, GLint v0, GLint v1, GLint v2); typedef void (APIENTRYP PFNGLUNIFORM4IARBPROC) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); typedef void (APIENTRYP PFNGLUNIFORM1FVARBPROC) (GLint location, GLsizei count, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORM2FVARBPROC) (GLint location, GLsizei count, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORM3FVARBPROC) (GLint location, GLsizei count, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORM4FVARBPROC) (GLint location, GLsizei count, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORM1IVARBPROC) (GLint location, GLsizei count, const GLint *value); typedef void (APIENTRYP PFNGLUNIFORM2IVARBPROC) (GLint location, GLsizei count, const GLint *value); typedef void (APIENTRYP PFNGLUNIFORM3IVARBPROC) (GLint location, GLsizei count, const GLint *value); typedef void (APIENTRYP PFNGLUNIFORM4IVARBPROC) (GLint location, GLsizei count, const GLint *value); typedef void (APIENTRYP PFNGLUNIFORMMATRIX2FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORMMATRIX3FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLGETOBJECTPARAMETERFVARBPROC) (GLhandleARB obj, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETOBJECTPARAMETERIVARBPROC) (GLhandleARB obj, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETINFOLOGARBPROC) (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *infoLog); typedef void (APIENTRYP PFNGLGETATTACHEDOBJECTSARBPROC) (GLhandleARB containerObj, GLsizei maxCount, GLsizei *count, GLhandleARB *obj); typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONARBPROC) (GLhandleARB programObj, const GLcharARB *name); typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMARBPROC) (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name); typedef void (APIENTRYP PFNGLGETUNIFORMFVARBPROC) (GLhandleARB programObj, GLint location, GLfloat *params); typedef void (APIENTRYP PFNGLGETUNIFORMIVARBPROC) (GLhandleARB programObj, GLint location, GLint *params); typedef void (APIENTRYP PFNGLGETSHADERSOURCEARBPROC) (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *source); #endif #ifndef GL_ARB_vertex_shader #define GL_ARB_vertex_shader 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBindAttribLocationARB (GLhandleARB, GLuint, const GLcharARB *); GLAPI void APIENTRY glGetActiveAttribARB (GLhandleARB, GLuint, GLsizei, GLsizei *, GLint *, GLenum *, GLcharARB *); GLAPI GLint APIENTRY glGetAttribLocationARB (GLhandleARB, const GLcharARB *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLBINDATTRIBLOCATIONARBPROC) (GLhandleARB programObj, GLuint index, const GLcharARB *name); typedef void (APIENTRYP PFNGLGETACTIVEATTRIBARBPROC) (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name); typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONARBPROC) (GLhandleARB programObj, const GLcharARB *name); #endif #ifndef GL_ARB_fragment_shader #define GL_ARB_fragment_shader 1 #endif #ifndef GL_ARB_shading_language_100 #define GL_ARB_shading_language_100 1 #endif #ifndef GL_ARB_texture_non_power_of_two #define GL_ARB_texture_non_power_of_two 1 #endif #ifndef GL_ARB_point_sprite #define GL_ARB_point_sprite 1 #endif #ifndef GL_ARB_fragment_program_shadow #define GL_ARB_fragment_program_shadow 1 #endif #ifndef GL_ARB_draw_buffers #define GL_ARB_draw_buffers 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDrawBuffersARB (GLsizei, const GLenum *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLDRAWBUFFERSARBPROC) (GLsizei n, const GLenum *bufs); #endif #ifndef GL_ARB_texture_rectangle #define GL_ARB_texture_rectangle 1 #endif #ifndef GL_ARB_color_buffer_float #define GL_ARB_color_buffer_float 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glClampColorARB (GLenum, GLenum); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLCLAMPCOLORARBPROC) (GLenum target, GLenum clamp); #endif #ifndef GL_ARB_half_float_pixel #define GL_ARB_half_float_pixel 1 #endif #ifndef GL_ARB_texture_float #define GL_ARB_texture_float 1 #endif #ifndef GL_ARB_pixel_buffer_object #define GL_ARB_pixel_buffer_object 1 #endif #ifndef GL_ARB_depth_buffer_float #define GL_ARB_depth_buffer_float 1 #endif #ifndef GL_ARB_draw_instanced #define GL_ARB_draw_instanced 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDrawArraysInstancedARB (GLenum, GLint, GLsizei, GLsizei); GLAPI void APIENTRY glDrawElementsInstancedARB (GLenum, GLsizei, GLenum, const GLvoid *, GLsizei); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDARBPROC) (GLenum mode, GLint first, GLsizei count, GLsizei primcount); typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDARBPROC) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount); #endif #ifndef GL_ARB_framebuffer_object #define GL_ARB_framebuffer_object 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI GLboolean APIENTRY glIsRenderbuffer (GLuint); GLAPI void APIENTRY glBindRenderbuffer (GLenum, GLuint); GLAPI void APIENTRY glDeleteRenderbuffers (GLsizei, const GLuint *); GLAPI void APIENTRY glGenRenderbuffers (GLsizei, GLuint *); GLAPI void APIENTRY glRenderbufferStorage (GLenum, GLenum, GLsizei, GLsizei); GLAPI void APIENTRY glGetRenderbufferParameteriv (GLenum, GLenum, GLint *); GLAPI GLboolean APIENTRY glIsFramebuffer (GLuint); GLAPI void APIENTRY glBindFramebuffer (GLenum, GLuint); GLAPI void APIENTRY glDeleteFramebuffers (GLsizei, const GLuint *); GLAPI void APIENTRY glGenFramebuffers (GLsizei, GLuint *); GLAPI GLenum APIENTRY glCheckFramebufferStatus (GLenum); GLAPI void APIENTRY glFramebufferTexture1D (GLenum, GLenum, GLenum, GLuint, GLint); GLAPI void APIENTRY glFramebufferTexture2D (GLenum, GLenum, GLenum, GLuint, GLint); GLAPI void APIENTRY glFramebufferTexture3D (GLenum, GLenum, GLenum, GLuint, GLint, GLint); GLAPI void APIENTRY glFramebufferRenderbuffer (GLenum, GLenum, GLenum, GLuint); GLAPI void APIENTRY glGetFramebufferAttachmentParameteriv (GLenum, GLenum, GLenum, GLint *); GLAPI void APIENTRY glGenerateMipmap (GLenum); GLAPI void APIENTRY glBlitFramebuffer (GLint, GLint, GLint, GLint, GLint, GLint, GLint, GLint, GLbitfield, GLenum); GLAPI void APIENTRY glRenderbufferStorageMultisample (GLenum, GLsizei, GLenum, GLsizei, GLsizei); GLAPI void APIENTRY glFramebufferTextureLayer (GLenum, GLenum, GLuint, GLint, GLint); #endif /* GL_GLEXT_PROTOTYPES */ typedef GLboolean (APIENTRYP PFNGLISRENDERBUFFERPROC) (GLuint renderbuffer); typedef void (APIENTRYP PFNGLBINDRENDERBUFFERPROC) (GLenum target, GLuint renderbuffer); typedef void (APIENTRYP PFNGLDELETERENDERBUFFERSPROC) (GLsizei n, const GLuint *renderbuffers); typedef void (APIENTRYP PFNGLGENRENDERBUFFERSPROC) (GLsizei n, GLuint *renderbuffers); typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); typedef void (APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); typedef GLboolean (APIENTRYP PFNGLISFRAMEBUFFERPROC) (GLuint framebuffer); typedef void (APIENTRYP PFNGLBINDFRAMEBUFFERPROC) (GLenum target, GLuint framebuffer); typedef void (APIENTRYP PFNGLDELETEFRAMEBUFFERSPROC) (GLsizei n, const GLuint *framebuffers); typedef void (APIENTRYP PFNGLGENFRAMEBUFFERSPROC) (GLsizei n, GLuint *framebuffers); typedef GLenum (APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSPROC) (GLenum target); typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE1DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); typedef void (APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFERPROC) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); typedef void (APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC) (GLenum target, GLenum attachment, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGENERATEMIPMAPPROC) (GLenum target); typedef void (APIENTRYP PFNGLBLITFRAMEBUFFERPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYERPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); #endif #ifndef GL_ARB_framebuffer_sRGB #define GL_ARB_framebuffer_sRGB 1 #endif #ifndef GL_ARB_geometry_shader4 #define GL_ARB_geometry_shader4 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glProgramParameteriARB (GLuint, GLenum, GLint); GLAPI void APIENTRY glFramebufferTextureARB (GLenum, GLenum, GLuint, GLint); GLAPI void APIENTRY glFramebufferTextureLayerARB (GLenum, GLenum, GLuint, GLint, GLint); GLAPI void APIENTRY glFramebufferTextureFaceARB (GLenum, GLenum, GLuint, GLint, GLenum); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLPROGRAMPARAMETERIARBPROC) (GLuint program, GLenum pname, GLint value); typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREARBPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level); typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYERARBPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREFACEARBPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLenum face); #endif #ifndef GL_ARB_half_float_vertex #define GL_ARB_half_float_vertex 1 #endif #ifndef GL_ARB_instanced_arrays #define GL_ARB_instanced_arrays 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glVertexAttribDivisor (GLuint, GLuint); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLVERTEXATTRIBDIVISORPROC) (GLuint index, GLuint divisor); #endif #ifndef GL_ARB_map_buffer_range #define GL_ARB_map_buffer_range 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glMapBufferRange (GLenum, GLintptr, GLsizeiptr, GLbitfield); GLAPI void APIENTRY glFlushMappedBufferRange (GLenum, GLintptr, GLsizeiptr); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLMAPBUFFERRANGEPROC) (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); typedef void (APIENTRYP PFNGLFLUSHMAPPEDBUFFERRANGEPROC) (GLenum target, GLintptr offset, GLsizeiptr length); #endif #ifndef GL_ARB_texture_buffer_object #define GL_ARB_texture_buffer_object 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glTexBufferARB (GLenum, GLenum, GLuint); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLTEXBUFFERARBPROC) (GLenum target, GLenum internalformat, GLuint buffer); #endif #ifndef GL_ARB_texture_compression_rgtc #define GL_ARB_texture_compression_rgtc 1 #endif #ifndef GL_ARB_texture_rg #define GL_ARB_texture_rg 1 #endif #ifndef GL_ARB_vertex_array_object #define GL_ARB_vertex_array_object 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBindVertexArray (GLuint); GLAPI void APIENTRY glDeleteVertexArrays (GLsizei, const GLuint *); GLAPI void APIENTRY glGenVertexArrays (GLsizei, GLuint *); GLAPI GLboolean APIENTRY glIsVertexArray (GLuint); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLBINDVERTEXARRAYPROC) (GLuint array); typedef void (APIENTRYP PFNGLDELETEVERTEXARRAYSPROC) (GLsizei n, const GLuint *arrays); typedef void (APIENTRYP PFNGLGENVERTEXARRAYSPROC) (GLsizei n, GLuint *arrays); typedef GLboolean (APIENTRYP PFNGLISVERTEXARRAYPROC) (GLuint array); #endif #ifndef GL_EXT_abgr #define GL_EXT_abgr 1 #endif #ifndef GL_EXT_blend_color #define GL_EXT_blend_color 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBlendColorEXT (GLclampf, GLclampf, GLclampf, GLclampf); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLBLENDCOLOREXTPROC) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); #endif #ifndef GL_EXT_polygon_offset #define GL_EXT_polygon_offset 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glPolygonOffsetEXT (GLfloat, GLfloat); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLPOLYGONOFFSETEXTPROC) (GLfloat factor, GLfloat bias); #endif #ifndef GL_EXT_texture #define GL_EXT_texture 1 #endif #ifndef GL_EXT_texture3D #define GL_EXT_texture3D 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glTexImage3DEXT (GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid *); GLAPI void APIENTRY glTexSubImage3DEXT (GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLTEXIMAGE3DEXTPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels); #endif #ifndef GL_SGIS_texture_filter4 #define GL_SGIS_texture_filter4 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glGetTexFilterFuncSGIS (GLenum, GLenum, GLfloat *); GLAPI void APIENTRY glTexFilterFuncSGIS (GLenum, GLenum, GLsizei, const GLfloat *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLGETTEXFILTERFUNCSGISPROC) (GLenum target, GLenum filter, GLfloat *weights); typedef void (APIENTRYP PFNGLTEXFILTERFUNCSGISPROC) (GLenum target, GLenum filter, GLsizei n, const GLfloat *weights); #endif #ifndef GL_EXT_subtexture #define GL_EXT_subtexture 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glTexSubImage1DEXT (GLenum, GLint, GLint, GLsizei, GLenum, GLenum, const GLvoid *); GLAPI void APIENTRY glTexSubImage2DEXT (GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLTEXSUBIMAGE1DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); typedef void (APIENTRYP PFNGLTEXSUBIMAGE2DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); #endif #ifndef GL_EXT_copy_texture #define GL_EXT_copy_texture 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glCopyTexImage1DEXT (GLenum, GLint, GLenum, GLint, GLint, GLsizei, GLint); GLAPI void APIENTRY glCopyTexImage2DEXT (GLenum, GLint, GLenum, GLint, GLint, GLsizei, GLsizei, GLint); GLAPI void APIENTRY glCopyTexSubImage1DEXT (GLenum, GLint, GLint, GLint, GLint, GLsizei); GLAPI void APIENTRY glCopyTexSubImage2DEXT (GLenum, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei); GLAPI void APIENTRY glCopyTexSubImage3DEXT (GLenum, GLint, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLCOPYTEXIMAGE1DEXTPROC) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); typedef void (APIENTRYP PFNGLCOPYTEXIMAGE2DEXTPROC) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE1DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE2DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE3DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); #endif #ifndef GL_EXT_histogram #define GL_EXT_histogram 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glGetHistogramEXT (GLenum, GLboolean, GLenum, GLenum, GLvoid *); GLAPI void APIENTRY glGetHistogramParameterfvEXT (GLenum, GLenum, GLfloat *); GLAPI void APIENTRY glGetHistogramParameterivEXT (GLenum, GLenum, GLint *); GLAPI void APIENTRY glGetMinmaxEXT (GLenum, GLboolean, GLenum, GLenum, GLvoid *); GLAPI void APIENTRY glGetMinmaxParameterfvEXT (GLenum, GLenum, GLfloat *); GLAPI void APIENTRY glGetMinmaxParameterivEXT (GLenum, GLenum, GLint *); GLAPI void APIENTRY glHistogramEXT (GLenum, GLsizei, GLenum, GLboolean); GLAPI void APIENTRY glMinmaxEXT (GLenum, GLenum, GLboolean); GLAPI void APIENTRY glResetHistogramEXT (GLenum); GLAPI void APIENTRY glResetMinmaxEXT (GLenum); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLGETHISTOGRAMEXTPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETMINMAXEXTPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLHISTOGRAMEXTPROC) (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink); typedef void (APIENTRYP PFNGLMINMAXEXTPROC) (GLenum target, GLenum internalformat, GLboolean sink); typedef void (APIENTRYP PFNGLRESETHISTOGRAMEXTPROC) (GLenum target); typedef void (APIENTRYP PFNGLRESETMINMAXEXTPROC) (GLenum target); #endif #ifndef GL_EXT_convolution #define GL_EXT_convolution 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glConvolutionFilter1DEXT (GLenum, GLenum, GLsizei, GLenum, GLenum, const GLvoid *); GLAPI void APIENTRY glConvolutionFilter2DEXT (GLenum, GLenum, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *); GLAPI void APIENTRY glConvolutionParameterfEXT (GLenum, GLenum, GLfloat); GLAPI void APIENTRY glConvolutionParameterfvEXT (GLenum, GLenum, const GLfloat *); GLAPI void APIENTRY glConvolutionParameteriEXT (GLenum, GLenum, GLint); GLAPI void APIENTRY glConvolutionParameterivEXT (GLenum, GLenum, const GLint *); GLAPI void APIENTRY glCopyConvolutionFilter1DEXT (GLenum, GLenum, GLint, GLint, GLsizei); GLAPI void APIENTRY glCopyConvolutionFilter2DEXT (GLenum, GLenum, GLint, GLint, GLsizei, GLsizei); GLAPI void APIENTRY glGetConvolutionFilterEXT (GLenum, GLenum, GLenum, GLvoid *); GLAPI void APIENTRY glGetConvolutionParameterfvEXT (GLenum, GLenum, GLfloat *); GLAPI void APIENTRY glGetConvolutionParameterivEXT (GLenum, GLenum, GLint *); GLAPI void APIENTRY glGetSeparableFilterEXT (GLenum, GLenum, GLenum, GLvoid *, GLvoid *, GLvoid *); GLAPI void APIENTRY glSeparableFilter2DEXT (GLenum, GLenum, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *, const GLvoid *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER1DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *image); typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image); typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFEXTPROC) (GLenum target, GLenum pname, GLfloat params); typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFVEXTPROC) (GLenum target, GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIEXTPROC) (GLenum target, GLenum pname, GLint params); typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIVEXTPROC) (GLenum target, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER1DEXTPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height); typedef void (APIENTRYP PFNGLGETCONVOLUTIONFILTEREXTPROC) (GLenum target, GLenum format, GLenum type, GLvoid *image); typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETSEPARABLEFILTEREXTPROC) (GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span); typedef void (APIENTRYP PFNGLSEPARABLEFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column); #endif #ifndef GL_SGI_color_matrix #define GL_SGI_color_matrix 1 #endif #ifndef GL_SGI_color_table #define GL_SGI_color_table 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glColorTableSGI (GLenum, GLenum, GLsizei, GLenum, GLenum, const GLvoid *); GLAPI void APIENTRY glColorTableParameterfvSGI (GLenum, GLenum, const GLfloat *); GLAPI void APIENTRY glColorTableParameterivSGI (GLenum, GLenum, const GLint *); GLAPI void APIENTRY glCopyColorTableSGI (GLenum, GLenum, GLint, GLint, GLsizei); GLAPI void APIENTRY glGetColorTableSGI (GLenum, GLenum, GLenum, GLvoid *); GLAPI void APIENTRY glGetColorTableParameterfvSGI (GLenum, GLenum, GLfloat *); GLAPI void APIENTRY glGetColorTableParameterivSGI (GLenum, GLenum, GLint *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLCOLORTABLESGIPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table); typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERFVSGIPROC) (GLenum target, GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERIVSGIPROC) (GLenum target, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLCOPYCOLORTABLESGIPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); typedef void (APIENTRYP PFNGLGETCOLORTABLESGIPROC) (GLenum target, GLenum format, GLenum type, GLvoid *table); typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERFVSGIPROC) (GLenum target, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERIVSGIPROC) (GLenum target, GLenum pname, GLint *params); #endif #ifndef GL_SGIX_pixel_texture #define GL_SGIX_pixel_texture 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glPixelTexGenSGIX (GLenum); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLPIXELTEXGENSGIXPROC) (GLenum mode); #endif #ifndef GL_SGIS_pixel_texture #define GL_SGIS_pixel_texture 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glPixelTexGenParameteriSGIS (GLenum, GLint); GLAPI void APIENTRY glPixelTexGenParameterivSGIS (GLenum, const GLint *); GLAPI void APIENTRY glPixelTexGenParameterfSGIS (GLenum, GLfloat); GLAPI void APIENTRY glPixelTexGenParameterfvSGIS (GLenum, const GLfloat *); GLAPI void APIENTRY glGetPixelTexGenParameterivSGIS (GLenum, GLint *); GLAPI void APIENTRY glGetPixelTexGenParameterfvSGIS (GLenum, GLfloat *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERISGISPROC) (GLenum pname, GLint param); typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERIVSGISPROC) (GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERFSGISPROC) (GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERFVSGISPROC) (GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLGETPIXELTEXGENPARAMETERIVSGISPROC) (GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETPIXELTEXGENPARAMETERFVSGISPROC) (GLenum pname, GLfloat *params); #endif #ifndef GL_SGIS_texture4D #define GL_SGIS_texture4D 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glTexImage4DSGIS (GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid *); GLAPI void APIENTRY glTexSubImage4DSGIS (GLenum, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLTEXIMAGE4DSGISPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLint border, GLenum format, GLenum type, const GLvoid *pixels); typedef void (APIENTRYP PFNGLTEXSUBIMAGE4DSGISPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint woffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLenum format, GLenum type, const GLvoid *pixels); #endif #ifndef GL_SGI_texture_color_table #define GL_SGI_texture_color_table 1 #endif #ifndef GL_EXT_cmyka #define GL_EXT_cmyka 1 #endif #ifndef GL_EXT_texture_object #define GL_EXT_texture_object 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI GLboolean APIENTRY glAreTexturesResidentEXT (GLsizei, const GLuint *, GLboolean *); GLAPI void APIENTRY glBindTextureEXT (GLenum, GLuint); GLAPI void APIENTRY glDeleteTexturesEXT (GLsizei, const GLuint *); GLAPI void APIENTRY glGenTexturesEXT (GLsizei, GLuint *); GLAPI GLboolean APIENTRY glIsTextureEXT (GLuint); GLAPI void APIENTRY glPrioritizeTexturesEXT (GLsizei, const GLuint *, const GLclampf *); #endif /* GL_GLEXT_PROTOTYPES */ typedef GLboolean (APIENTRYP PFNGLARETEXTURESRESIDENTEXTPROC) (GLsizei n, const GLuint *textures, GLboolean *residences); typedef void (APIENTRYP PFNGLBINDTEXTUREEXTPROC) (GLenum target, GLuint texture); typedef void (APIENTRYP PFNGLDELETETEXTURESEXTPROC) (GLsizei n, const GLuint *textures); typedef void (APIENTRYP PFNGLGENTEXTURESEXTPROC) (GLsizei n, GLuint *textures); typedef GLboolean (APIENTRYP PFNGLISTEXTUREEXTPROC) (GLuint texture); typedef void (APIENTRYP PFNGLPRIORITIZETEXTURESEXTPROC) (GLsizei n, const GLuint *textures, const GLclampf *priorities); #endif #ifndef GL_SGIS_detail_texture #define GL_SGIS_detail_texture 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDetailTexFuncSGIS (GLenum, GLsizei, const GLfloat *); GLAPI void APIENTRY glGetDetailTexFuncSGIS (GLenum, GLfloat *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLDETAILTEXFUNCSGISPROC) (GLenum target, GLsizei n, const GLfloat *points); typedef void (APIENTRYP PFNGLGETDETAILTEXFUNCSGISPROC) (GLenum target, GLfloat *points); #endif #ifndef GL_SGIS_sharpen_texture #define GL_SGIS_sharpen_texture 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glSharpenTexFuncSGIS (GLenum, GLsizei, const GLfloat *); GLAPI void APIENTRY glGetSharpenTexFuncSGIS (GLenum, GLfloat *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLSHARPENTEXFUNCSGISPROC) (GLenum target, GLsizei n, const GLfloat *points); typedef void (APIENTRYP PFNGLGETSHARPENTEXFUNCSGISPROC) (GLenum target, GLfloat *points); #endif #ifndef GL_EXT_packed_pixels #define GL_EXT_packed_pixels 1 #endif #ifndef GL_SGIS_texture_lod #define GL_SGIS_texture_lod 1 #endif #ifndef GL_SGIS_multisample #define GL_SGIS_multisample 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glSampleMaskSGIS (GLclampf, GLboolean); GLAPI void APIENTRY glSamplePatternSGIS (GLenum); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLSAMPLEMASKSGISPROC) (GLclampf value, GLboolean invert); typedef void (APIENTRYP PFNGLSAMPLEPATTERNSGISPROC) (GLenum pattern); #endif #ifndef GL_EXT_rescale_normal #define GL_EXT_rescale_normal 1 #endif #ifndef GL_EXT_vertex_array #define GL_EXT_vertex_array 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glArrayElementEXT (GLint); GLAPI void APIENTRY glColorPointerEXT (GLint, GLenum, GLsizei, GLsizei, const GLvoid *); GLAPI void APIENTRY glDrawArraysEXT (GLenum, GLint, GLsizei); GLAPI void APIENTRY glEdgeFlagPointerEXT (GLsizei, GLsizei, const GLboolean *); GLAPI void APIENTRY glGetPointervEXT (GLenum, GLvoid* *); GLAPI void APIENTRY glIndexPointerEXT (GLenum, GLsizei, GLsizei, const GLvoid *); GLAPI void APIENTRY glNormalPointerEXT (GLenum, GLsizei, GLsizei, const GLvoid *); GLAPI void APIENTRY glTexCoordPointerEXT (GLint, GLenum, GLsizei, GLsizei, const GLvoid *); GLAPI void APIENTRY glVertexPointerEXT (GLint, GLenum, GLsizei, GLsizei, const GLvoid *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLARRAYELEMENTEXTPROC) (GLint i); typedef void (APIENTRYP PFNGLCOLORPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); typedef void (APIENTRYP PFNGLDRAWARRAYSEXTPROC) (GLenum mode, GLint first, GLsizei count); typedef void (APIENTRYP PFNGLEDGEFLAGPOINTEREXTPROC) (GLsizei stride, GLsizei count, const GLboolean *pointer); typedef void (APIENTRYP PFNGLGETPOINTERVEXTPROC) (GLenum pname, GLvoid* *params); typedef void (APIENTRYP PFNGLINDEXPOINTEREXTPROC) (GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); typedef void (APIENTRYP PFNGLNORMALPOINTEREXTPROC) (GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); typedef void (APIENTRYP PFNGLTEXCOORDPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); typedef void (APIENTRYP PFNGLVERTEXPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); #endif #ifndef GL_EXT_misc_attribute #define GL_EXT_misc_attribute 1 #endif #ifndef GL_SGIS_generate_mipmap #define GL_SGIS_generate_mipmap 1 #endif #ifndef GL_SGIX_clipmap #define GL_SGIX_clipmap 1 #endif #ifndef GL_SGIX_shadow #define GL_SGIX_shadow 1 #endif #ifndef GL_SGIS_texture_edge_clamp #define GL_SGIS_texture_edge_clamp 1 #endif #ifndef GL_SGIS_texture_border_clamp #define GL_SGIS_texture_border_clamp 1 #endif #ifndef GL_EXT_blend_minmax #define GL_EXT_blend_minmax 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBlendEquationEXT (GLenum); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLBLENDEQUATIONEXTPROC) (GLenum mode); #endif #ifndef GL_EXT_blend_subtract #define GL_EXT_blend_subtract 1 #endif #ifndef GL_EXT_blend_logic_op #define GL_EXT_blend_logic_op 1 #endif #ifndef GL_SGIX_interlace #define GL_SGIX_interlace 1 #endif #ifndef GL_SGIX_pixel_tiles #define GL_SGIX_pixel_tiles 1 #endif #ifndef GL_SGIX_texture_select #define GL_SGIX_texture_select 1 #endif #ifndef GL_SGIX_sprite #define GL_SGIX_sprite 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glSpriteParameterfSGIX (GLenum, GLfloat); GLAPI void APIENTRY glSpriteParameterfvSGIX (GLenum, const GLfloat *); GLAPI void APIENTRY glSpriteParameteriSGIX (GLenum, GLint); GLAPI void APIENTRY glSpriteParameterivSGIX (GLenum, const GLint *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLSPRITEPARAMETERFSGIXPROC) (GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLSPRITEPARAMETERFVSGIXPROC) (GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLSPRITEPARAMETERISGIXPROC) (GLenum pname, GLint param); typedef void (APIENTRYP PFNGLSPRITEPARAMETERIVSGIXPROC) (GLenum pname, const GLint *params); #endif #ifndef GL_SGIX_texture_multi_buffer #define GL_SGIX_texture_multi_buffer 1 #endif #ifndef GL_EXT_point_parameters #define GL_EXT_point_parameters 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glPointParameterfEXT (GLenum, GLfloat); GLAPI void APIENTRY glPointParameterfvEXT (GLenum, const GLfloat *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLPOINTPARAMETERFEXTPROC) (GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLPOINTPARAMETERFVEXTPROC) (GLenum pname, const GLfloat *params); #endif #ifndef GL_SGIS_point_parameters #define GL_SGIS_point_parameters 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glPointParameterfSGIS (GLenum, GLfloat); GLAPI void APIENTRY glPointParameterfvSGIS (GLenum, const GLfloat *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLPOINTPARAMETERFSGISPROC) (GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLPOINTPARAMETERFVSGISPROC) (GLenum pname, const GLfloat *params); #endif #ifndef GL_SGIX_instruments #define GL_SGIX_instruments 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI GLint APIENTRY glGetInstrumentsSGIX (void); GLAPI void APIENTRY glInstrumentsBufferSGIX (GLsizei, GLint *); GLAPI GLint APIENTRY glPollInstrumentsSGIX (GLint *); GLAPI void APIENTRY glReadInstrumentsSGIX (GLint); GLAPI void APIENTRY glStartInstrumentsSGIX (void); GLAPI void APIENTRY glStopInstrumentsSGIX (GLint); #endif /* GL_GLEXT_PROTOTYPES */ typedef GLint (APIENTRYP PFNGLGETINSTRUMENTSSGIXPROC) (void); typedef void (APIENTRYP PFNGLINSTRUMENTSBUFFERSGIXPROC) (GLsizei size, GLint *buffer); typedef GLint (APIENTRYP PFNGLPOLLINSTRUMENTSSGIXPROC) (GLint *marker_p); typedef void (APIENTRYP PFNGLREADINSTRUMENTSSGIXPROC) (GLint marker); typedef void (APIENTRYP PFNGLSTARTINSTRUMENTSSGIXPROC) (void); typedef void (APIENTRYP PFNGLSTOPINSTRUMENTSSGIXPROC) (GLint marker); #endif #ifndef GL_SGIX_texture_scale_bias #define GL_SGIX_texture_scale_bias 1 #endif #ifndef GL_SGIX_framezoom #define GL_SGIX_framezoom 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glFrameZoomSGIX (GLint); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLFRAMEZOOMSGIXPROC) (GLint factor); #endif #ifndef GL_SGIX_tag_sample_buffer #define GL_SGIX_tag_sample_buffer 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glTagSampleBufferSGIX (void); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLTAGSAMPLEBUFFERSGIXPROC) (void); #endif #ifndef GL_SGIX_polynomial_ffd #define GL_SGIX_polynomial_ffd 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDeformationMap3dSGIX (GLenum, GLdouble, GLdouble, GLint, GLint, GLdouble, GLdouble, GLint, GLint, GLdouble, GLdouble, GLint, GLint, const GLdouble *); GLAPI void APIENTRY glDeformationMap3fSGIX (GLenum, GLfloat, GLfloat, GLint, GLint, GLfloat, GLfloat, GLint, GLint, GLfloat, GLfloat, GLint, GLint, const GLfloat *); GLAPI void APIENTRY glDeformSGIX (GLbitfield); GLAPI void APIENTRY glLoadIdentityDeformationMapSGIX (GLbitfield); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLDEFORMATIONMAP3DSGIXPROC) (GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, GLdouble w1, GLdouble w2, GLint wstride, GLint worder, const GLdouble *points); typedef void (APIENTRYP PFNGLDEFORMATIONMAP3FSGIXPROC) (GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, GLfloat w1, GLfloat w2, GLint wstride, GLint worder, const GLfloat *points); typedef void (APIENTRYP PFNGLDEFORMSGIXPROC) (GLbitfield mask); typedef void (APIENTRYP PFNGLLOADIDENTITYDEFORMATIONMAPSGIXPROC) (GLbitfield mask); #endif #ifndef GL_SGIX_reference_plane #define GL_SGIX_reference_plane 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glReferencePlaneSGIX (const GLdouble *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLREFERENCEPLANESGIXPROC) (const GLdouble *equation); #endif #ifndef GL_SGIX_flush_raster #define GL_SGIX_flush_raster 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glFlushRasterSGIX (void); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLFLUSHRASTERSGIXPROC) (void); #endif #ifndef GL_SGIX_depth_texture #define GL_SGIX_depth_texture 1 #endif #ifndef GL_SGIS_fog_function #define GL_SGIS_fog_function 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glFogFuncSGIS (GLsizei, const GLfloat *); GLAPI void APIENTRY glGetFogFuncSGIS (GLfloat *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLFOGFUNCSGISPROC) (GLsizei n, const GLfloat *points); typedef void (APIENTRYP PFNGLGETFOGFUNCSGISPROC) (GLfloat *points); #endif #ifndef GL_SGIX_fog_offset #define GL_SGIX_fog_offset 1 #endif #ifndef GL_HP_image_transform #define GL_HP_image_transform 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glImageTransformParameteriHP (GLenum, GLenum, GLint); GLAPI void APIENTRY glImageTransformParameterfHP (GLenum, GLenum, GLfloat); GLAPI void APIENTRY glImageTransformParameterivHP (GLenum, GLenum, const GLint *); GLAPI void APIENTRY glImageTransformParameterfvHP (GLenum, GLenum, const GLfloat *); GLAPI void APIENTRY glGetImageTransformParameterivHP (GLenum, GLenum, GLint *); GLAPI void APIENTRY glGetImageTransformParameterfvHP (GLenum, GLenum, GLfloat *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERIHPPROC) (GLenum target, GLenum pname, GLint param); typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERFHPPROC) (GLenum target, GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERIVHPPROC) (GLenum target, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERFVHPPROC) (GLenum target, GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLGETIMAGETRANSFORMPARAMETERIVHPPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETIMAGETRANSFORMPARAMETERFVHPPROC) (GLenum target, GLenum pname, GLfloat *params); #endif #ifndef GL_HP_convolution_border_modes #define GL_HP_convolution_border_modes 1 #endif #ifndef GL_SGIX_texture_add_env #define GL_SGIX_texture_add_env 1 #endif #ifndef GL_EXT_color_subtable #define GL_EXT_color_subtable 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glColorSubTableEXT (GLenum, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *); GLAPI void APIENTRY glCopyColorSubTableEXT (GLenum, GLsizei, GLint, GLint, GLsizei); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLCOLORSUBTABLEEXTPROC) (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data); typedef void (APIENTRYP PFNGLCOPYCOLORSUBTABLEEXTPROC) (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width); #endif #ifndef GL_PGI_vertex_hints #define GL_PGI_vertex_hints 1 #endif #ifndef GL_PGI_misc_hints #define GL_PGI_misc_hints 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glHintPGI (GLenum, GLint); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLHINTPGIPROC) (GLenum target, GLint mode); #endif #ifndef GL_EXT_paletted_texture #define GL_EXT_paletted_texture 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glColorTableEXT (GLenum, GLenum, GLsizei, GLenum, GLenum, const GLvoid *); GLAPI void APIENTRY glGetColorTableEXT (GLenum, GLenum, GLenum, GLvoid *); GLAPI void APIENTRY glGetColorTableParameterivEXT (GLenum, GLenum, GLint *); GLAPI void APIENTRY glGetColorTableParameterfvEXT (GLenum, GLenum, GLfloat *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLCOLORTABLEEXTPROC) (GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const GLvoid *table); typedef void (APIENTRYP PFNGLGETCOLORTABLEEXTPROC) (GLenum target, GLenum format, GLenum type, GLvoid *data); typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params); #endif #ifndef GL_EXT_clip_volume_hint #define GL_EXT_clip_volume_hint 1 #endif #ifndef GL_SGIX_list_priority #define GL_SGIX_list_priority 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glGetListParameterfvSGIX (GLuint, GLenum, GLfloat *); GLAPI void APIENTRY glGetListParameterivSGIX (GLuint, GLenum, GLint *); GLAPI void APIENTRY glListParameterfSGIX (GLuint, GLenum, GLfloat); GLAPI void APIENTRY glListParameterfvSGIX (GLuint, GLenum, const GLfloat *); GLAPI void APIENTRY glListParameteriSGIX (GLuint, GLenum, GLint); GLAPI void APIENTRY glListParameterivSGIX (GLuint, GLenum, const GLint *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLGETLISTPARAMETERFVSGIXPROC) (GLuint list, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETLISTPARAMETERIVSGIXPROC) (GLuint list, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLLISTPARAMETERFSGIXPROC) (GLuint list, GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLLISTPARAMETERFVSGIXPROC) (GLuint list, GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLLISTPARAMETERISGIXPROC) (GLuint list, GLenum pname, GLint param); typedef void (APIENTRYP PFNGLLISTPARAMETERIVSGIXPROC) (GLuint list, GLenum pname, const GLint *params); #endif #ifndef GL_SGIX_ir_instrument1 #define GL_SGIX_ir_instrument1 1 #endif #ifndef GL_SGIX_calligraphic_fragment #define GL_SGIX_calligraphic_fragment 1 #endif #ifndef GL_SGIX_texture_lod_bias #define GL_SGIX_texture_lod_bias 1 #endif #ifndef GL_SGIX_shadow_ambient #define GL_SGIX_shadow_ambient 1 #endif #ifndef GL_EXT_index_texture #define GL_EXT_index_texture 1 #endif #ifndef GL_EXT_index_material #define GL_EXT_index_material 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glIndexMaterialEXT (GLenum, GLenum); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLINDEXMATERIALEXTPROC) (GLenum face, GLenum mode); #endif #ifndef GL_EXT_index_func #define GL_EXT_index_func 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glIndexFuncEXT (GLenum, GLclampf); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLINDEXFUNCEXTPROC) (GLenum func, GLclampf ref); #endif #ifndef GL_EXT_index_array_formats #define GL_EXT_index_array_formats 1 #endif #ifndef GL_EXT_compiled_vertex_array #define GL_EXT_compiled_vertex_array 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glLockArraysEXT (GLint, GLsizei); GLAPI void APIENTRY glUnlockArraysEXT (void); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLLOCKARRAYSEXTPROC) (GLint first, GLsizei count); typedef void (APIENTRYP PFNGLUNLOCKARRAYSEXTPROC) (void); #endif #ifndef GL_EXT_cull_vertex #define GL_EXT_cull_vertex 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glCullParameterdvEXT (GLenum, GLdouble *); GLAPI void APIENTRY glCullParameterfvEXT (GLenum, GLfloat *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLCULLPARAMETERDVEXTPROC) (GLenum pname, GLdouble *params); typedef void (APIENTRYP PFNGLCULLPARAMETERFVEXTPROC) (GLenum pname, GLfloat *params); #endif #ifndef GL_SGIX_ycrcb #define GL_SGIX_ycrcb 1 #endif #ifndef GL_SGIX_fragment_lighting #define GL_SGIX_fragment_lighting 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glFragmentColorMaterialSGIX (GLenum, GLenum); GLAPI void APIENTRY glFragmentLightfSGIX (GLenum, GLenum, GLfloat); GLAPI void APIENTRY glFragmentLightfvSGIX (GLenum, GLenum, const GLfloat *); GLAPI void APIENTRY glFragmentLightiSGIX (GLenum, GLenum, GLint); GLAPI void APIENTRY glFragmentLightivSGIX (GLenum, GLenum, const GLint *); GLAPI void APIENTRY glFragmentLightModelfSGIX (GLenum, GLfloat); GLAPI void APIENTRY glFragmentLightModelfvSGIX (GLenum, const GLfloat *); GLAPI void APIENTRY glFragmentLightModeliSGIX (GLenum, GLint); GLAPI void APIENTRY glFragmentLightModelivSGIX (GLenum, const GLint *); GLAPI void APIENTRY glFragmentMaterialfSGIX (GLenum, GLenum, GLfloat); GLAPI void APIENTRY glFragmentMaterialfvSGIX (GLenum, GLenum, const GLfloat *); GLAPI void APIENTRY glFragmentMaterialiSGIX (GLenum, GLenum, GLint); GLAPI void APIENTRY glFragmentMaterialivSGIX (GLenum, GLenum, const GLint *); GLAPI void APIENTRY glGetFragmentLightfvSGIX (GLenum, GLenum, GLfloat *); GLAPI void APIENTRY glGetFragmentLightivSGIX (GLenum, GLenum, GLint *); GLAPI void APIENTRY glGetFragmentMaterialfvSGIX (GLenum, GLenum, GLfloat *); GLAPI void APIENTRY glGetFragmentMaterialivSGIX (GLenum, GLenum, GLint *); GLAPI void APIENTRY glLightEnviSGIX (GLenum, GLint); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLFRAGMENTCOLORMATERIALSGIXPROC) (GLenum face, GLenum mode); typedef void (APIENTRYP PFNGLFRAGMENTLIGHTFSGIXPROC) (GLenum light, GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLFRAGMENTLIGHTFVSGIXPROC) (GLenum light, GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLFRAGMENTLIGHTISGIXPROC) (GLenum light, GLenum pname, GLint param); typedef void (APIENTRYP PFNGLFRAGMENTLIGHTIVSGIXPROC) (GLenum light, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELFSGIXPROC) (GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELFVSGIXPROC) (GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELISGIXPROC) (GLenum pname, GLint param); typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELIVSGIXPROC) (GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLFRAGMENTMATERIALFSGIXPROC) (GLenum face, GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLFRAGMENTMATERIALFVSGIXPROC) (GLenum face, GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLFRAGMENTMATERIALISGIXPROC) (GLenum face, GLenum pname, GLint param); typedef void (APIENTRYP PFNGLFRAGMENTMATERIALIVSGIXPROC) (GLenum face, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLGETFRAGMENTLIGHTFVSGIXPROC) (GLenum light, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETFRAGMENTLIGHTIVSGIXPROC) (GLenum light, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETFRAGMENTMATERIALFVSGIXPROC) (GLenum face, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETFRAGMENTMATERIALIVSGIXPROC) (GLenum face, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLLIGHTENVISGIXPROC) (GLenum pname, GLint param); #endif #ifndef GL_IBM_rasterpos_clip #define GL_IBM_rasterpos_clip 1 #endif #ifndef GL_HP_texture_lighting #define GL_HP_texture_lighting 1 #endif #ifndef GL_EXT_draw_range_elements #define GL_EXT_draw_range_elements 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDrawRangeElementsEXT (GLenum, GLuint, GLuint, GLsizei, GLenum, const GLvoid *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSEXTPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices); #endif #ifndef GL_WIN_phong_shading #define GL_WIN_phong_shading 1 #endif #ifndef GL_WIN_specular_fog #define GL_WIN_specular_fog 1 #endif #ifndef GL_EXT_light_texture #define GL_EXT_light_texture 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glApplyTextureEXT (GLenum); GLAPI void APIENTRY glTextureLightEXT (GLenum); GLAPI void APIENTRY glTextureMaterialEXT (GLenum, GLenum); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLAPPLYTEXTUREEXTPROC) (GLenum mode); typedef void (APIENTRYP PFNGLTEXTURELIGHTEXTPROC) (GLenum pname); typedef void (APIENTRYP PFNGLTEXTUREMATERIALEXTPROC) (GLenum face, GLenum mode); #endif #ifndef GL_SGIX_blend_alpha_minmax #define GL_SGIX_blend_alpha_minmax 1 #endif #ifndef GL_EXT_bgra #define GL_EXT_bgra 1 #endif #ifndef GL_SGIX_async #define GL_SGIX_async 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glAsyncMarkerSGIX (GLuint); GLAPI GLint APIENTRY glFinishAsyncSGIX (GLuint *); GLAPI GLint APIENTRY glPollAsyncSGIX (GLuint *); GLAPI GLuint APIENTRY glGenAsyncMarkersSGIX (GLsizei); GLAPI void APIENTRY glDeleteAsyncMarkersSGIX (GLuint, GLsizei); GLAPI GLboolean APIENTRY glIsAsyncMarkerSGIX (GLuint); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLASYNCMARKERSGIXPROC) (GLuint marker); typedef GLint (APIENTRYP PFNGLFINISHASYNCSGIXPROC) (GLuint *markerp); typedef GLint (APIENTRYP PFNGLPOLLASYNCSGIXPROC) (GLuint *markerp); typedef GLuint (APIENTRYP PFNGLGENASYNCMARKERSSGIXPROC) (GLsizei range); typedef void (APIENTRYP PFNGLDELETEASYNCMARKERSSGIXPROC) (GLuint marker, GLsizei range); typedef GLboolean (APIENTRYP PFNGLISASYNCMARKERSGIXPROC) (GLuint marker); #endif #ifndef GL_SGIX_async_pixel #define GL_SGIX_async_pixel 1 #endif #ifndef GL_SGIX_async_histogram #define GL_SGIX_async_histogram 1 #endif #ifndef GL_INTEL_parallel_arrays #define GL_INTEL_parallel_arrays 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glVertexPointervINTEL (GLint, GLenum, const GLvoid* *); GLAPI void APIENTRY glNormalPointervINTEL (GLenum, const GLvoid* *); GLAPI void APIENTRY glColorPointervINTEL (GLint, GLenum, const GLvoid* *); GLAPI void APIENTRY glTexCoordPointervINTEL (GLint, GLenum, const GLvoid* *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLVERTEXPOINTERVINTELPROC) (GLint size, GLenum type, const GLvoid* *pointer); typedef void (APIENTRYP PFNGLNORMALPOINTERVINTELPROC) (GLenum type, const GLvoid* *pointer); typedef void (APIENTRYP PFNGLCOLORPOINTERVINTELPROC) (GLint size, GLenum type, const GLvoid* *pointer); typedef void (APIENTRYP PFNGLTEXCOORDPOINTERVINTELPROC) (GLint size, GLenum type, const GLvoid* *pointer); #endif #ifndef GL_HP_occlusion_test #define GL_HP_occlusion_test 1 #endif #ifndef GL_EXT_pixel_transform #define GL_EXT_pixel_transform 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glPixelTransformParameteriEXT (GLenum, GLenum, GLint); GLAPI void APIENTRY glPixelTransformParameterfEXT (GLenum, GLenum, GLfloat); GLAPI void APIENTRY glPixelTransformParameterivEXT (GLenum, GLenum, const GLint *); GLAPI void APIENTRY glPixelTransformParameterfvEXT (GLenum, GLenum, const GLfloat *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERIEXTPROC) (GLenum target, GLenum pname, GLint param); typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERFEXTPROC) (GLenum target, GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERIVEXTPROC) (GLenum target, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERFVEXTPROC) (GLenum target, GLenum pname, const GLfloat *params); #endif #ifndef GL_EXT_pixel_transform_color_table #define GL_EXT_pixel_transform_color_table 1 #endif #ifndef GL_EXT_shared_texture_palette #define GL_EXT_shared_texture_palette 1 #endif #ifndef GL_EXT_separate_specular_color #define GL_EXT_separate_specular_color 1 #endif #ifndef GL_EXT_secondary_color #define GL_EXT_secondary_color 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glSecondaryColor3bEXT (GLbyte, GLbyte, GLbyte); GLAPI void APIENTRY glSecondaryColor3bvEXT (const GLbyte *); GLAPI void APIENTRY glSecondaryColor3dEXT (GLdouble, GLdouble, GLdouble); GLAPI void APIENTRY glSecondaryColor3dvEXT (const GLdouble *); GLAPI void APIENTRY glSecondaryColor3fEXT (GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glSecondaryColor3fvEXT (const GLfloat *); GLAPI void APIENTRY glSecondaryColor3iEXT (GLint, GLint, GLint); GLAPI void APIENTRY glSecondaryColor3ivEXT (const GLint *); GLAPI void APIENTRY glSecondaryColor3sEXT (GLshort, GLshort, GLshort); GLAPI void APIENTRY glSecondaryColor3svEXT (const GLshort *); GLAPI void APIENTRY glSecondaryColor3ubEXT (GLubyte, GLubyte, GLubyte); GLAPI void APIENTRY glSecondaryColor3ubvEXT (const GLubyte *); GLAPI void APIENTRY glSecondaryColor3uiEXT (GLuint, GLuint, GLuint); GLAPI void APIENTRY glSecondaryColor3uivEXT (const GLuint *); GLAPI void APIENTRY glSecondaryColor3usEXT (GLushort, GLushort, GLushort); GLAPI void APIENTRY glSecondaryColor3usvEXT (const GLushort *); GLAPI void APIENTRY glSecondaryColorPointerEXT (GLint, GLenum, GLsizei, const GLvoid *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BEXTPROC) (GLbyte red, GLbyte green, GLbyte blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BVEXTPROC) (const GLbyte *v); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DEXTPROC) (GLdouble red, GLdouble green, GLdouble blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DVEXTPROC) (const GLdouble *v); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FEXTPROC) (GLfloat red, GLfloat green, GLfloat blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FVEXTPROC) (const GLfloat *v); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IEXTPROC) (GLint red, GLint green, GLint blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IVEXTPROC) (const GLint *v); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SEXTPROC) (GLshort red, GLshort green, GLshort blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SVEXTPROC) (const GLshort *v); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBEXTPROC) (GLubyte red, GLubyte green, GLubyte blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBVEXTPROC) (const GLubyte *v); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIEXTPROC) (GLuint red, GLuint green, GLuint blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIVEXTPROC) (const GLuint *v); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USEXTPROC) (GLushort red, GLushort green, GLushort blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USVEXTPROC) (const GLushort *v); typedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); #endif #ifndef GL_EXT_texture_perturb_normal #define GL_EXT_texture_perturb_normal 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glTextureNormalEXT (GLenum); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLTEXTURENORMALEXTPROC) (GLenum mode); #endif #ifndef GL_EXT_multi_draw_arrays #define GL_EXT_multi_draw_arrays 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glMultiDrawArraysEXT (GLenum, GLint *, GLsizei *, GLsizei); GLAPI void APIENTRY glMultiDrawElementsEXT (GLenum, const GLsizei *, GLenum, const GLvoid* *, GLsizei); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSEXTPROC) (GLenum mode, GLint *first, GLsizei *count, GLsizei primcount); typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSEXTPROC) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount); #endif #ifndef GL_EXT_fog_coord #define GL_EXT_fog_coord 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glFogCoordfEXT (GLfloat); GLAPI void APIENTRY glFogCoordfvEXT (const GLfloat *); GLAPI void APIENTRY glFogCoorddEXT (GLdouble); GLAPI void APIENTRY glFogCoorddvEXT (const GLdouble *); GLAPI void APIENTRY glFogCoordPointerEXT (GLenum, GLsizei, const GLvoid *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLFOGCOORDFEXTPROC) (GLfloat coord); typedef void (APIENTRYP PFNGLFOGCOORDFVEXTPROC) (const GLfloat *coord); typedef void (APIENTRYP PFNGLFOGCOORDDEXTPROC) (GLdouble coord); typedef void (APIENTRYP PFNGLFOGCOORDDVEXTPROC) (const GLdouble *coord); typedef void (APIENTRYP PFNGLFOGCOORDPOINTEREXTPROC) (GLenum type, GLsizei stride, const GLvoid *pointer); #endif #ifndef GL_REND_screen_coordinates #define GL_REND_screen_coordinates 1 #endif #ifndef GL_EXT_coordinate_frame #define GL_EXT_coordinate_frame 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glTangent3bEXT (GLbyte, GLbyte, GLbyte); GLAPI void APIENTRY glTangent3bvEXT (const GLbyte *); GLAPI void APIENTRY glTangent3dEXT (GLdouble, GLdouble, GLdouble); GLAPI void APIENTRY glTangent3dvEXT (const GLdouble *); GLAPI void APIENTRY glTangent3fEXT (GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glTangent3fvEXT (const GLfloat *); GLAPI void APIENTRY glTangent3iEXT (GLint, GLint, GLint); GLAPI void APIENTRY glTangent3ivEXT (const GLint *); GLAPI void APIENTRY glTangent3sEXT (GLshort, GLshort, GLshort); GLAPI void APIENTRY glTangent3svEXT (const GLshort *); GLAPI void APIENTRY glBinormal3bEXT (GLbyte, GLbyte, GLbyte); GLAPI void APIENTRY glBinormal3bvEXT (const GLbyte *); GLAPI void APIENTRY glBinormal3dEXT (GLdouble, GLdouble, GLdouble); GLAPI void APIENTRY glBinormal3dvEXT (const GLdouble *); GLAPI void APIENTRY glBinormal3fEXT (GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glBinormal3fvEXT (const GLfloat *); GLAPI void APIENTRY glBinormal3iEXT (GLint, GLint, GLint); GLAPI void APIENTRY glBinormal3ivEXT (const GLint *); GLAPI void APIENTRY glBinormal3sEXT (GLshort, GLshort, GLshort); GLAPI void APIENTRY glBinormal3svEXT (const GLshort *); GLAPI void APIENTRY glTangentPointerEXT (GLenum, GLsizei, const GLvoid *); GLAPI void APIENTRY glBinormalPointerEXT (GLenum, GLsizei, const GLvoid *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLTANGENT3BEXTPROC) (GLbyte tx, GLbyte ty, GLbyte tz); typedef void (APIENTRYP PFNGLTANGENT3BVEXTPROC) (const GLbyte *v); typedef void (APIENTRYP PFNGLTANGENT3DEXTPROC) (GLdouble tx, GLdouble ty, GLdouble tz); typedef void (APIENTRYP PFNGLTANGENT3DVEXTPROC) (const GLdouble *v); typedef void (APIENTRYP PFNGLTANGENT3FEXTPROC) (GLfloat tx, GLfloat ty, GLfloat tz); typedef void (APIENTRYP PFNGLTANGENT3FVEXTPROC) (const GLfloat *v); typedef void (APIENTRYP PFNGLTANGENT3IEXTPROC) (GLint tx, GLint ty, GLint tz); typedef void (APIENTRYP PFNGLTANGENT3IVEXTPROC) (const GLint *v); typedef void (APIENTRYP PFNGLTANGENT3SEXTPROC) (GLshort tx, GLshort ty, GLshort tz); typedef void (APIENTRYP PFNGLTANGENT3SVEXTPROC) (const GLshort *v); typedef void (APIENTRYP PFNGLBINORMAL3BEXTPROC) (GLbyte bx, GLbyte by, GLbyte bz); typedef void (APIENTRYP PFNGLBINORMAL3BVEXTPROC) (const GLbyte *v); typedef void (APIENTRYP PFNGLBINORMAL3DEXTPROC) (GLdouble bx, GLdouble by, GLdouble bz); typedef void (APIENTRYP PFNGLBINORMAL3DVEXTPROC) (const GLdouble *v); typedef void (APIENTRYP PFNGLBINORMAL3FEXTPROC) (GLfloat bx, GLfloat by, GLfloat bz); typedef void (APIENTRYP PFNGLBINORMAL3FVEXTPROC) (const GLfloat *v); typedef void (APIENTRYP PFNGLBINORMAL3IEXTPROC) (GLint bx, GLint by, GLint bz); typedef void (APIENTRYP PFNGLBINORMAL3IVEXTPROC) (const GLint *v); typedef void (APIENTRYP PFNGLBINORMAL3SEXTPROC) (GLshort bx, GLshort by, GLshort bz); typedef void (APIENTRYP PFNGLBINORMAL3SVEXTPROC) (const GLshort *v); typedef void (APIENTRYP PFNGLTANGENTPOINTEREXTPROC) (GLenum type, GLsizei stride, const GLvoid *pointer); typedef void (APIENTRYP PFNGLBINORMALPOINTEREXTPROC) (GLenum type, GLsizei stride, const GLvoid *pointer); #endif #ifndef GL_EXT_texture_env_combine #define GL_EXT_texture_env_combine 1 #endif #ifndef GL_APPLE_specular_vector #define GL_APPLE_specular_vector 1 #endif #ifndef GL_APPLE_transform_hint #define GL_APPLE_transform_hint 1 #endif #ifndef GL_SGIX_fog_scale #define GL_SGIX_fog_scale 1 #endif #ifndef GL_SUNX_constant_data #define GL_SUNX_constant_data 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glFinishTextureSUNX (void); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLFINISHTEXTURESUNXPROC) (void); #endif #ifndef GL_SUN_global_alpha #define GL_SUN_global_alpha 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glGlobalAlphaFactorbSUN (GLbyte); GLAPI void APIENTRY glGlobalAlphaFactorsSUN (GLshort); GLAPI void APIENTRY glGlobalAlphaFactoriSUN (GLint); GLAPI void APIENTRY glGlobalAlphaFactorfSUN (GLfloat); GLAPI void APIENTRY glGlobalAlphaFactordSUN (GLdouble); GLAPI void APIENTRY glGlobalAlphaFactorubSUN (GLubyte); GLAPI void APIENTRY glGlobalAlphaFactorusSUN (GLushort); GLAPI void APIENTRY glGlobalAlphaFactoruiSUN (GLuint); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORBSUNPROC) (GLbyte factor); typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORSSUNPROC) (GLshort factor); typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORISUNPROC) (GLint factor); typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORFSUNPROC) (GLfloat factor); typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORDSUNPROC) (GLdouble factor); typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORUBSUNPROC) (GLubyte factor); typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORUSSUNPROC) (GLushort factor); typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORUISUNPROC) (GLuint factor); #endif #ifndef GL_SUN_triangle_list #define GL_SUN_triangle_list 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glReplacementCodeuiSUN (GLuint); GLAPI void APIENTRY glReplacementCodeusSUN (GLushort); GLAPI void APIENTRY glReplacementCodeubSUN (GLubyte); GLAPI void APIENTRY glReplacementCodeuivSUN (const GLuint *); GLAPI void APIENTRY glReplacementCodeusvSUN (const GLushort *); GLAPI void APIENTRY glReplacementCodeubvSUN (const GLubyte *); GLAPI void APIENTRY glReplacementCodePointerSUN (GLenum, GLsizei, const GLvoid* *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLREPLACEMENTCODEUISUNPROC) (GLuint code); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUSSUNPROC) (GLushort code); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUBSUNPROC) (GLubyte code); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUIVSUNPROC) (const GLuint *code); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUSVSUNPROC) (const GLushort *code); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUBVSUNPROC) (const GLubyte *code); typedef void (APIENTRYP PFNGLREPLACEMENTCODEPOINTERSUNPROC) (GLenum type, GLsizei stride, const GLvoid* *pointer); #endif #ifndef GL_SUN_vertex #define GL_SUN_vertex 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glColor4ubVertex2fSUN (GLubyte, GLubyte, GLubyte, GLubyte, GLfloat, GLfloat); GLAPI void APIENTRY glColor4ubVertex2fvSUN (const GLubyte *, const GLfloat *); GLAPI void APIENTRY glColor4ubVertex3fSUN (GLubyte, GLubyte, GLubyte, GLubyte, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glColor4ubVertex3fvSUN (const GLubyte *, const GLfloat *); GLAPI void APIENTRY glColor3fVertex3fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glColor3fVertex3fvSUN (const GLfloat *, const GLfloat *); GLAPI void APIENTRY glNormal3fVertex3fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glNormal3fVertex3fvSUN (const GLfloat *, const GLfloat *); GLAPI void APIENTRY glColor4fNormal3fVertex3fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glColor4fNormal3fVertex3fvSUN (const GLfloat *, const GLfloat *, const GLfloat *); GLAPI void APIENTRY glTexCoord2fVertex3fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glTexCoord2fVertex3fvSUN (const GLfloat *, const GLfloat *); GLAPI void APIENTRY glTexCoord4fVertex4fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glTexCoord4fVertex4fvSUN (const GLfloat *, const GLfloat *); GLAPI void APIENTRY glTexCoord2fColor4ubVertex3fSUN (GLfloat, GLfloat, GLubyte, GLubyte, GLubyte, GLubyte, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glTexCoord2fColor4ubVertex3fvSUN (const GLfloat *, const GLubyte *, const GLfloat *); GLAPI void APIENTRY glTexCoord2fColor3fVertex3fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glTexCoord2fColor3fVertex3fvSUN (const GLfloat *, const GLfloat *, const GLfloat *); GLAPI void APIENTRY glTexCoord2fNormal3fVertex3fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glTexCoord2fNormal3fVertex3fvSUN (const GLfloat *, const GLfloat *, const GLfloat *); GLAPI void APIENTRY glTexCoord2fColor4fNormal3fVertex3fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glTexCoord2fColor4fNormal3fVertex3fvSUN (const GLfloat *, const GLfloat *, const GLfloat *, const GLfloat *); GLAPI void APIENTRY glTexCoord4fColor4fNormal3fVertex4fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glTexCoord4fColor4fNormal3fVertex4fvSUN (const GLfloat *, const GLfloat *, const GLfloat *, const GLfloat *); GLAPI void APIENTRY glReplacementCodeuiVertex3fSUN (GLuint, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glReplacementCodeuiVertex3fvSUN (const GLuint *, const GLfloat *); GLAPI void APIENTRY glReplacementCodeuiColor4ubVertex3fSUN (GLuint, GLubyte, GLubyte, GLubyte, GLubyte, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glReplacementCodeuiColor4ubVertex3fvSUN (const GLuint *, const GLubyte *, const GLfloat *); GLAPI void APIENTRY glReplacementCodeuiColor3fVertex3fSUN (GLuint, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glReplacementCodeuiColor3fVertex3fvSUN (const GLuint *, const GLfloat *, const GLfloat *); GLAPI void APIENTRY glReplacementCodeuiNormal3fVertex3fSUN (GLuint, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glReplacementCodeuiNormal3fVertex3fvSUN (const GLuint *, const GLfloat *, const GLfloat *); GLAPI void APIENTRY glReplacementCodeuiColor4fNormal3fVertex3fSUN (GLuint, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glReplacementCodeuiColor4fNormal3fVertex3fvSUN (const GLuint *, const GLfloat *, const GLfloat *, const GLfloat *); GLAPI void APIENTRY glReplacementCodeuiTexCoord2fVertex3fSUN (GLuint, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glReplacementCodeuiTexCoord2fVertex3fvSUN (const GLuint *, const GLfloat *, const GLfloat *); GLAPI void APIENTRY glReplacementCodeuiTexCoord2fNormal3fVertex3fSUN (GLuint, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN (const GLuint *, const GLfloat *, const GLfloat *, const GLfloat *); GLAPI void APIENTRY glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN (GLuint, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN (const GLuint *, const GLfloat *, const GLfloat *, const GLfloat *, const GLfloat *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX2FSUNPROC) (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y); typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX2FVSUNPROC) (const GLubyte *c, const GLfloat *v); typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX3FSUNPROC) (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX3FVSUNPROC) (const GLubyte *c, const GLfloat *v); typedef void (APIENTRYP PFNGLCOLOR3FVERTEX3FSUNPROC) (GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLCOLOR3FVERTEX3FVSUNPROC) (const GLfloat *c, const GLfloat *v); typedef void (APIENTRYP PFNGLNORMAL3FVERTEX3FSUNPROC) (GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *n, const GLfloat *v); typedef void (APIENTRYP PFNGLCOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLCOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *c, const GLfloat *n, const GLfloat *v); typedef void (APIENTRYP PFNGLTEXCOORD2FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLTEXCOORD2FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *v); typedef void (APIENTRYP PFNGLTEXCOORD4FVERTEX4FSUNPROC) (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat x, GLfloat y, GLfloat z, GLfloat w); typedef void (APIENTRYP PFNGLTEXCOORD4FVERTEX4FVSUNPROC) (const GLfloat *tc, const GLfloat *v); typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4UBVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4UBVERTEX3FVSUNPROC) (const GLfloat *tc, const GLubyte *c, const GLfloat *v); typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR3FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR3FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *c, const GLfloat *v); typedef void (APIENTRYP PFNGLTEXCOORD2FNORMAL3FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLTEXCOORD2FNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *n, const GLfloat *v); typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); typedef void (APIENTRYP PFNGLTEXCOORD4FCOLOR4FNORMAL3FVERTEX4FSUNPROC) (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z, GLfloat w); typedef void (APIENTRYP PFNGLTEXCOORD4FCOLOR4FNORMAL3FVERTEX4FVSUNPROC) (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUIVERTEX3FSUNPROC) (GLuint rc, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUIVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *v); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4UBVERTEX3FSUNPROC) (GLuint rc, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4UBVERTEX3FVSUNPROC) (const GLuint *rc, const GLubyte *c, const GLfloat *v); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR3FVERTEX3FSUNPROC) (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *c, const GLfloat *v); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUINORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUINORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *n, const GLfloat *v); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *c, const GLfloat *n, const GLfloat *v); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FVERTEX3FSUNPROC) (GLuint rc, GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *tc, const GLfloat *v); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FNORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FNORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *tc, const GLfloat *n, const GLfloat *v); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FCOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FCOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); #endif #ifndef GL_EXT_blend_func_separate #define GL_EXT_blend_func_separate 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBlendFuncSeparateEXT (GLenum, GLenum, GLenum, GLenum); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEEXTPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); #endif #ifndef GL_INGR_blend_func_separate #define GL_INGR_blend_func_separate 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBlendFuncSeparateINGR (GLenum, GLenum, GLenum, GLenum); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEINGRPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); #endif #ifndef GL_INGR_color_clamp #define GL_INGR_color_clamp 1 #endif #ifndef GL_INGR_interlace_read #define GL_INGR_interlace_read 1 #endif #ifndef GL_EXT_stencil_wrap #define GL_EXT_stencil_wrap 1 #endif #ifndef GL_EXT_422_pixels #define GL_EXT_422_pixels 1 #endif #ifndef GL_NV_texgen_reflection #define GL_NV_texgen_reflection 1 #endif #ifndef GL_SUN_convolution_border_modes #define GL_SUN_convolution_border_modes 1 #endif #ifndef GL_EXT_texture_env_add #define GL_EXT_texture_env_add 1 #endif #ifndef GL_EXT_texture_lod_bias #define GL_EXT_texture_lod_bias 1 #endif #ifndef GL_EXT_texture_filter_anisotropic #define GL_EXT_texture_filter_anisotropic 1 #endif #ifndef GL_EXT_vertex_weighting #define GL_EXT_vertex_weighting 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glVertexWeightfEXT (GLfloat); GLAPI void APIENTRY glVertexWeightfvEXT (const GLfloat *); GLAPI void APIENTRY glVertexWeightPointerEXT (GLsizei, GLenum, GLsizei, const GLvoid *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLVERTEXWEIGHTFEXTPROC) (GLfloat weight); typedef void (APIENTRYP PFNGLVERTEXWEIGHTFVEXTPROC) (const GLfloat *weight); typedef void (APIENTRYP PFNGLVERTEXWEIGHTPOINTEREXTPROC) (GLsizei size, GLenum type, GLsizei stride, const GLvoid *pointer); #endif #ifndef GL_NV_light_max_exponent #define GL_NV_light_max_exponent 1 #endif #ifndef GL_NV_vertex_array_range #define GL_NV_vertex_array_range 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glFlushVertexArrayRangeNV (void); GLAPI void APIENTRY glVertexArrayRangeNV (GLsizei, const GLvoid *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLFLUSHVERTEXARRAYRANGENVPROC) (void); typedef void (APIENTRYP PFNGLVERTEXARRAYRANGENVPROC) (GLsizei length, const GLvoid *pointer); #endif #ifndef GL_NV_register_combiners #define GL_NV_register_combiners 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glCombinerParameterfvNV (GLenum, const GLfloat *); GLAPI void APIENTRY glCombinerParameterfNV (GLenum, GLfloat); GLAPI void APIENTRY glCombinerParameterivNV (GLenum, const GLint *); GLAPI void APIENTRY glCombinerParameteriNV (GLenum, GLint); GLAPI void APIENTRY glCombinerInputNV (GLenum, GLenum, GLenum, GLenum, GLenum, GLenum); GLAPI void APIENTRY glCombinerOutputNV (GLenum, GLenum, GLenum, GLenum, GLenum, GLenum, GLenum, GLboolean, GLboolean, GLboolean); GLAPI void APIENTRY glFinalCombinerInputNV (GLenum, GLenum, GLenum, GLenum); GLAPI void APIENTRY glGetCombinerInputParameterfvNV (GLenum, GLenum, GLenum, GLenum, GLfloat *); GLAPI void APIENTRY glGetCombinerInputParameterivNV (GLenum, GLenum, GLenum, GLenum, GLint *); GLAPI void APIENTRY glGetCombinerOutputParameterfvNV (GLenum, GLenum, GLenum, GLfloat *); GLAPI void APIENTRY glGetCombinerOutputParameterivNV (GLenum, GLenum, GLenum, GLint *); GLAPI void APIENTRY glGetFinalCombinerInputParameterfvNV (GLenum, GLenum, GLfloat *); GLAPI void APIENTRY glGetFinalCombinerInputParameterivNV (GLenum, GLenum, GLint *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLCOMBINERPARAMETERFVNVPROC) (GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLCOMBINERPARAMETERFNVPROC) (GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLCOMBINERPARAMETERIVNVPROC) (GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLCOMBINERPARAMETERINVPROC) (GLenum pname, GLint param); typedef void (APIENTRYP PFNGLCOMBINERINPUTNVPROC) (GLenum stage, GLenum portion, GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage); typedef void (APIENTRYP PFNGLCOMBINEROUTPUTNVPROC) (GLenum stage, GLenum portion, GLenum abOutput, GLenum cdOutput, GLenum sumOutput, GLenum scale, GLenum bias, GLboolean abDotProduct, GLboolean cdDotProduct, GLboolean muxSum); typedef void (APIENTRYP PFNGLFINALCOMBINERINPUTNVPROC) (GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage); typedef void (APIENTRYP PFNGLGETCOMBINERINPUTPARAMETERFVNVPROC) (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETCOMBINERINPUTPARAMETERIVNVPROC) (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETCOMBINEROUTPUTPARAMETERFVNVPROC) (GLenum stage, GLenum portion, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETCOMBINEROUTPUTPARAMETERIVNVPROC) (GLenum stage, GLenum portion, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETFINALCOMBINERINPUTPARAMETERFVNVPROC) (GLenum variable, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETFINALCOMBINERINPUTPARAMETERIVNVPROC) (GLenum variable, GLenum pname, GLint *params); #endif #ifndef GL_NV_fog_distance #define GL_NV_fog_distance 1 #endif #ifndef GL_NV_texgen_emboss #define GL_NV_texgen_emboss 1 #endif #ifndef GL_NV_blend_square #define GL_NV_blend_square 1 #endif #ifndef GL_NV_texture_env_combine4 #define GL_NV_texture_env_combine4 1 #endif #ifndef GL_MESA_resize_buffers #define GL_MESA_resize_buffers 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glResizeBuffersMESA (void); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLRESIZEBUFFERSMESAPROC) (void); #endif #ifndef GL_MESA_window_pos #define GL_MESA_window_pos 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glWindowPos2dMESA (GLdouble, GLdouble); GLAPI void APIENTRY glWindowPos2dvMESA (const GLdouble *); GLAPI void APIENTRY glWindowPos2fMESA (GLfloat, GLfloat); GLAPI void APIENTRY glWindowPos2fvMESA (const GLfloat *); GLAPI void APIENTRY glWindowPos2iMESA (GLint, GLint); GLAPI void APIENTRY glWindowPos2ivMESA (const GLint *); GLAPI void APIENTRY glWindowPos2sMESA (GLshort, GLshort); GLAPI void APIENTRY glWindowPos2svMESA (const GLshort *); GLAPI void APIENTRY glWindowPos3dMESA (GLdouble, GLdouble, GLdouble); GLAPI void APIENTRY glWindowPos3dvMESA (const GLdouble *); GLAPI void APIENTRY glWindowPos3fMESA (GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glWindowPos3fvMESA (const GLfloat *); GLAPI void APIENTRY glWindowPos3iMESA (GLint, GLint, GLint); GLAPI void APIENTRY glWindowPos3ivMESA (const GLint *); GLAPI void APIENTRY glWindowPos3sMESA (GLshort, GLshort, GLshort); GLAPI void APIENTRY glWindowPos3svMESA (const GLshort *); GLAPI void APIENTRY glWindowPos4dMESA (GLdouble, GLdouble, GLdouble, GLdouble); GLAPI void APIENTRY glWindowPos4dvMESA (const GLdouble *); GLAPI void APIENTRY glWindowPos4fMESA (GLfloat, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glWindowPos4fvMESA (const GLfloat *); GLAPI void APIENTRY glWindowPos4iMESA (GLint, GLint, GLint, GLint); GLAPI void APIENTRY glWindowPos4ivMESA (const GLint *); GLAPI void APIENTRY glWindowPos4sMESA (GLshort, GLshort, GLshort, GLshort); GLAPI void APIENTRY glWindowPos4svMESA (const GLshort *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLWINDOWPOS2DMESAPROC) (GLdouble x, GLdouble y); typedef void (APIENTRYP PFNGLWINDOWPOS2DVMESAPROC) (const GLdouble *v); typedef void (APIENTRYP PFNGLWINDOWPOS2FMESAPROC) (GLfloat x, GLfloat y); typedef void (APIENTRYP PFNGLWINDOWPOS2FVMESAPROC) (const GLfloat *v); typedef void (APIENTRYP PFNGLWINDOWPOS2IMESAPROC) (GLint x, GLint y); typedef void (APIENTRYP PFNGLWINDOWPOS2IVMESAPROC) (const GLint *v); typedef void (APIENTRYP PFNGLWINDOWPOS2SMESAPROC) (GLshort x, GLshort y); typedef void (APIENTRYP PFNGLWINDOWPOS2SVMESAPROC) (const GLshort *v); typedef void (APIENTRYP PFNGLWINDOWPOS3DMESAPROC) (GLdouble x, GLdouble y, GLdouble z); typedef void (APIENTRYP PFNGLWINDOWPOS3DVMESAPROC) (const GLdouble *v); typedef void (APIENTRYP PFNGLWINDOWPOS3FMESAPROC) (GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLWINDOWPOS3FVMESAPROC) (const GLfloat *v); typedef void (APIENTRYP PFNGLWINDOWPOS3IMESAPROC) (GLint x, GLint y, GLint z); typedef void (APIENTRYP PFNGLWINDOWPOS3IVMESAPROC) (const GLint *v); typedef void (APIENTRYP PFNGLWINDOWPOS3SMESAPROC) (GLshort x, GLshort y, GLshort z); typedef void (APIENTRYP PFNGLWINDOWPOS3SVMESAPROC) (const GLshort *v); typedef void (APIENTRYP PFNGLWINDOWPOS4DMESAPROC) (GLdouble x, GLdouble y, GLdouble z, GLdouble w); typedef void (APIENTRYP PFNGLWINDOWPOS4DVMESAPROC) (const GLdouble *v); typedef void (APIENTRYP PFNGLWINDOWPOS4FMESAPROC) (GLfloat x, GLfloat y, GLfloat z, GLfloat w); typedef void (APIENTRYP PFNGLWINDOWPOS4FVMESAPROC) (const GLfloat *v); typedef void (APIENTRYP PFNGLWINDOWPOS4IMESAPROC) (GLint x, GLint y, GLint z, GLint w); typedef void (APIENTRYP PFNGLWINDOWPOS4IVMESAPROC) (const GLint *v); typedef void (APIENTRYP PFNGLWINDOWPOS4SMESAPROC) (GLshort x, GLshort y, GLshort z, GLshort w); typedef void (APIENTRYP PFNGLWINDOWPOS4SVMESAPROC) (const GLshort *v); #endif #ifndef GL_IBM_cull_vertex #define GL_IBM_cull_vertex 1 #endif #ifndef GL_IBM_multimode_draw_arrays #define GL_IBM_multimode_draw_arrays 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glMultiModeDrawArraysIBM (const GLenum *, const GLint *, const GLsizei *, GLsizei, GLint); GLAPI void APIENTRY glMultiModeDrawElementsIBM (const GLenum *, const GLsizei *, GLenum, const GLvoid* const *, GLsizei, GLint); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLMULTIMODEDRAWARRAYSIBMPROC) (const GLenum *mode, const GLint *first, const GLsizei *count, GLsizei primcount, GLint modestride); typedef void (APIENTRYP PFNGLMULTIMODEDRAWELEMENTSIBMPROC) (const GLenum *mode, const GLsizei *count, GLenum type, const GLvoid* const *indices, GLsizei primcount, GLint modestride); #endif #ifndef GL_IBM_vertex_array_lists #define GL_IBM_vertex_array_lists 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glColorPointerListIBM (GLint, GLenum, GLint, const GLvoid* *, GLint); GLAPI void APIENTRY glSecondaryColorPointerListIBM (GLint, GLenum, GLint, const GLvoid* *, GLint); GLAPI void APIENTRY glEdgeFlagPointerListIBM (GLint, const GLboolean* *, GLint); GLAPI void APIENTRY glFogCoordPointerListIBM (GLenum, GLint, const GLvoid* *, GLint); GLAPI void APIENTRY glIndexPointerListIBM (GLenum, GLint, const GLvoid* *, GLint); GLAPI void APIENTRY glNormalPointerListIBM (GLenum, GLint, const GLvoid* *, GLint); GLAPI void APIENTRY glTexCoordPointerListIBM (GLint, GLenum, GLint, const GLvoid* *, GLint); GLAPI void APIENTRY glVertexPointerListIBM (GLint, GLenum, GLint, const GLvoid* *, GLint); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLCOLORPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); typedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); typedef void (APIENTRYP PFNGLEDGEFLAGPOINTERLISTIBMPROC) (GLint stride, const GLboolean* *pointer, GLint ptrstride); typedef void (APIENTRYP PFNGLFOGCOORDPOINTERLISTIBMPROC) (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); typedef void (APIENTRYP PFNGLINDEXPOINTERLISTIBMPROC) (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); typedef void (APIENTRYP PFNGLNORMALPOINTERLISTIBMPROC) (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); typedef void (APIENTRYP PFNGLTEXCOORDPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); typedef void (APIENTRYP PFNGLVERTEXPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); #endif #ifndef GL_SGIX_subsample #define GL_SGIX_subsample 1 #endif #ifndef GL_SGIX_ycrcba #define GL_SGIX_ycrcba 1 #endif #ifndef GL_SGIX_ycrcb_subsample #define GL_SGIX_ycrcb_subsample 1 #endif #ifndef GL_SGIX_depth_pass_instrument #define GL_SGIX_depth_pass_instrument 1 #endif #ifndef GL_3DFX_texture_compression_FXT1 #define GL_3DFX_texture_compression_FXT1 1 #endif #ifndef GL_3DFX_multisample #define GL_3DFX_multisample 1 #endif #ifndef GL_3DFX_tbuffer #define GL_3DFX_tbuffer 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glTbufferMask3DFX (GLuint); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLTBUFFERMASK3DFXPROC) (GLuint mask); #endif #ifndef GL_EXT_multisample #define GL_EXT_multisample 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glSampleMaskEXT (GLclampf, GLboolean); GLAPI void APIENTRY glSamplePatternEXT (GLenum); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLSAMPLEMASKEXTPROC) (GLclampf value, GLboolean invert); typedef void (APIENTRYP PFNGLSAMPLEPATTERNEXTPROC) (GLenum pattern); #endif #ifndef GL_SGIX_vertex_preclip #define GL_SGIX_vertex_preclip 1 #endif #ifndef GL_SGIX_convolution_accuracy #define GL_SGIX_convolution_accuracy 1 #endif #ifndef GL_SGIX_resample #define GL_SGIX_resample 1 #endif #ifndef GL_SGIS_point_line_texgen #define GL_SGIS_point_line_texgen 1 #endif #ifndef GL_SGIS_texture_color_mask #define GL_SGIS_texture_color_mask 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glTextureColorMaskSGIS (GLboolean, GLboolean, GLboolean, GLboolean); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLTEXTURECOLORMASKSGISPROC) (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); #endif #ifndef GL_SGIX_igloo_interface #define GL_SGIX_igloo_interface 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glIglooInterfaceSGIX (GLenum, const GLvoid *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLIGLOOINTERFACESGIXPROC) (GLenum pname, const GLvoid *params); #endif #ifndef GL_EXT_texture_env_dot3 #define GL_EXT_texture_env_dot3 1 #endif #ifndef GL_ATI_texture_mirror_once #define GL_ATI_texture_mirror_once 1 #endif #ifndef GL_NV_fence #define GL_NV_fence 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDeleteFencesNV (GLsizei, const GLuint *); GLAPI void APIENTRY glGenFencesNV (GLsizei, GLuint *); GLAPI GLboolean APIENTRY glIsFenceNV (GLuint); GLAPI GLboolean APIENTRY glTestFenceNV (GLuint); GLAPI void APIENTRY glGetFenceivNV (GLuint, GLenum, GLint *); GLAPI void APIENTRY glFinishFenceNV (GLuint); GLAPI void APIENTRY glSetFenceNV (GLuint, GLenum); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLDELETEFENCESNVPROC) (GLsizei n, const GLuint *fences); typedef void (APIENTRYP PFNGLGENFENCESNVPROC) (GLsizei n, GLuint *fences); typedef GLboolean (APIENTRYP PFNGLISFENCENVPROC) (GLuint fence); typedef GLboolean (APIENTRYP PFNGLTESTFENCENVPROC) (GLuint fence); typedef void (APIENTRYP PFNGLGETFENCEIVNVPROC) (GLuint fence, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLFINISHFENCENVPROC) (GLuint fence); typedef void (APIENTRYP PFNGLSETFENCENVPROC) (GLuint fence, GLenum condition); #endif #ifndef GL_NV_evaluators #define GL_NV_evaluators 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glMapControlPointsNV (GLenum, GLuint, GLenum, GLsizei, GLsizei, GLint, GLint, GLboolean, const GLvoid *); GLAPI void APIENTRY glMapParameterivNV (GLenum, GLenum, const GLint *); GLAPI void APIENTRY glMapParameterfvNV (GLenum, GLenum, const GLfloat *); GLAPI void APIENTRY glGetMapControlPointsNV (GLenum, GLuint, GLenum, GLsizei, GLsizei, GLboolean, GLvoid *); GLAPI void APIENTRY glGetMapParameterivNV (GLenum, GLenum, GLint *); GLAPI void APIENTRY glGetMapParameterfvNV (GLenum, GLenum, GLfloat *); GLAPI void APIENTRY glGetMapAttribParameterivNV (GLenum, GLuint, GLenum, GLint *); GLAPI void APIENTRY glGetMapAttribParameterfvNV (GLenum, GLuint, GLenum, GLfloat *); GLAPI void APIENTRY glEvalMapsNV (GLenum, GLenum); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLMAPCONTROLPOINTSNVPROC) (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLint uorder, GLint vorder, GLboolean packed, const GLvoid *points); typedef void (APIENTRYP PFNGLMAPPARAMETERIVNVPROC) (GLenum target, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLMAPPARAMETERFVNVPROC) (GLenum target, GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLGETMAPCONTROLPOINTSNVPROC) (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLboolean packed, GLvoid *points); typedef void (APIENTRYP PFNGLGETMAPPARAMETERIVNVPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETMAPPARAMETERFVNVPROC) (GLenum target, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETMAPATTRIBPARAMETERIVNVPROC) (GLenum target, GLuint index, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETMAPATTRIBPARAMETERFVNVPROC) (GLenum target, GLuint index, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLEVALMAPSNVPROC) (GLenum target, GLenum mode); #endif #ifndef GL_NV_packed_depth_stencil #define GL_NV_packed_depth_stencil 1 #endif #ifndef GL_NV_register_combiners2 #define GL_NV_register_combiners2 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glCombinerStageParameterfvNV (GLenum, GLenum, const GLfloat *); GLAPI void APIENTRY glGetCombinerStageParameterfvNV (GLenum, GLenum, GLfloat *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLCOMBINERSTAGEPARAMETERFVNVPROC) (GLenum stage, GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLGETCOMBINERSTAGEPARAMETERFVNVPROC) (GLenum stage, GLenum pname, GLfloat *params); #endif #ifndef GL_NV_texture_compression_vtc #define GL_NV_texture_compression_vtc 1 #endif #ifndef GL_NV_texture_rectangle #define GL_NV_texture_rectangle 1 #endif #ifndef GL_NV_texture_shader #define GL_NV_texture_shader 1 #endif #ifndef GL_NV_texture_shader2 #define GL_NV_texture_shader2 1 #endif #ifndef GL_NV_vertex_array_range2 #define GL_NV_vertex_array_range2 1 #endif #ifndef GL_NV_vertex_program #define GL_NV_vertex_program 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI GLboolean APIENTRY glAreProgramsResidentNV (GLsizei, const GLuint *, GLboolean *); GLAPI void APIENTRY glBindProgramNV (GLenum, GLuint); GLAPI void APIENTRY glDeleteProgramsNV (GLsizei, const GLuint *); GLAPI void APIENTRY glExecuteProgramNV (GLenum, GLuint, const GLfloat *); GLAPI void APIENTRY glGenProgramsNV (GLsizei, GLuint *); GLAPI void APIENTRY glGetProgramParameterdvNV (GLenum, GLuint, GLenum, GLdouble *); GLAPI void APIENTRY glGetProgramParameterfvNV (GLenum, GLuint, GLenum, GLfloat *); GLAPI void APIENTRY glGetProgramivNV (GLuint, GLenum, GLint *); GLAPI void APIENTRY glGetProgramStringNV (GLuint, GLenum, GLubyte *); GLAPI void APIENTRY glGetTrackMatrixivNV (GLenum, GLuint, GLenum, GLint *); GLAPI void APIENTRY glGetVertexAttribdvNV (GLuint, GLenum, GLdouble *); GLAPI void APIENTRY glGetVertexAttribfvNV (GLuint, GLenum, GLfloat *); GLAPI void APIENTRY glGetVertexAttribivNV (GLuint, GLenum, GLint *); GLAPI void APIENTRY glGetVertexAttribPointervNV (GLuint, GLenum, GLvoid* *); GLAPI GLboolean APIENTRY glIsProgramNV (GLuint); GLAPI void APIENTRY glLoadProgramNV (GLenum, GLuint, GLsizei, const GLubyte *); GLAPI void APIENTRY glProgramParameter4dNV (GLenum, GLuint, GLdouble, GLdouble, GLdouble, GLdouble); GLAPI void APIENTRY glProgramParameter4dvNV (GLenum, GLuint, const GLdouble *); GLAPI void APIENTRY glProgramParameter4fNV (GLenum, GLuint, GLfloat, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glProgramParameter4fvNV (GLenum, GLuint, const GLfloat *); GLAPI void APIENTRY glProgramParameters4dvNV (GLenum, GLuint, GLuint, const GLdouble *); GLAPI void APIENTRY glProgramParameters4fvNV (GLenum, GLuint, GLuint, const GLfloat *); GLAPI void APIENTRY glRequestResidentProgramsNV (GLsizei, const GLuint *); GLAPI void APIENTRY glTrackMatrixNV (GLenum, GLuint, GLenum, GLenum); GLAPI void APIENTRY glVertexAttribPointerNV (GLuint, GLint, GLenum, GLsizei, const GLvoid *); GLAPI void APIENTRY glVertexAttrib1dNV (GLuint, GLdouble); GLAPI void APIENTRY glVertexAttrib1dvNV (GLuint, const GLdouble *); GLAPI void APIENTRY glVertexAttrib1fNV (GLuint, GLfloat); GLAPI void APIENTRY glVertexAttrib1fvNV (GLuint, const GLfloat *); GLAPI void APIENTRY glVertexAttrib1sNV (GLuint, GLshort); GLAPI void APIENTRY glVertexAttrib1svNV (GLuint, const GLshort *); GLAPI void APIENTRY glVertexAttrib2dNV (GLuint, GLdouble, GLdouble); GLAPI void APIENTRY glVertexAttrib2dvNV (GLuint, const GLdouble *); GLAPI void APIENTRY glVertexAttrib2fNV (GLuint, GLfloat, GLfloat); GLAPI void APIENTRY glVertexAttrib2fvNV (GLuint, const GLfloat *); GLAPI void APIENTRY glVertexAttrib2sNV (GLuint, GLshort, GLshort); GLAPI void APIENTRY glVertexAttrib2svNV (GLuint, const GLshort *); GLAPI void APIENTRY glVertexAttrib3dNV (GLuint, GLdouble, GLdouble, GLdouble); GLAPI void APIENTRY glVertexAttrib3dvNV (GLuint, const GLdouble *); GLAPI void APIENTRY glVertexAttrib3fNV (GLuint, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glVertexAttrib3fvNV (GLuint, const GLfloat *); GLAPI void APIENTRY glVertexAttrib3sNV (GLuint, GLshort, GLshort, GLshort); GLAPI void APIENTRY glVertexAttrib3svNV (GLuint, const GLshort *); GLAPI void APIENTRY glVertexAttrib4dNV (GLuint, GLdouble, GLdouble, GLdouble, GLdouble); GLAPI void APIENTRY glVertexAttrib4dvNV (GLuint, const GLdouble *); GLAPI void APIENTRY glVertexAttrib4fNV (GLuint, GLfloat, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glVertexAttrib4fvNV (GLuint, const GLfloat *); GLAPI void APIENTRY glVertexAttrib4sNV (GLuint, GLshort, GLshort, GLshort, GLshort); GLAPI void APIENTRY glVertexAttrib4svNV (GLuint, const GLshort *); GLAPI void APIENTRY glVertexAttrib4ubNV (GLuint, GLubyte, GLubyte, GLubyte, GLubyte); GLAPI void APIENTRY glVertexAttrib4ubvNV (GLuint, const GLubyte *); GLAPI void APIENTRY glVertexAttribs1dvNV (GLuint, GLsizei, const GLdouble *); GLAPI void APIENTRY glVertexAttribs1fvNV (GLuint, GLsizei, const GLfloat *); GLAPI void APIENTRY glVertexAttribs1svNV (GLuint, GLsizei, const GLshort *); GLAPI void APIENTRY glVertexAttribs2dvNV (GLuint, GLsizei, const GLdouble *); GLAPI void APIENTRY glVertexAttribs2fvNV (GLuint, GLsizei, const GLfloat *); GLAPI void APIENTRY glVertexAttribs2svNV (GLuint, GLsizei, const GLshort *); GLAPI void APIENTRY glVertexAttribs3dvNV (GLuint, GLsizei, const GLdouble *); GLAPI void APIENTRY glVertexAttribs3fvNV (GLuint, GLsizei, const GLfloat *); GLAPI void APIENTRY glVertexAttribs3svNV (GLuint, GLsizei, const GLshort *); GLAPI void APIENTRY glVertexAttribs4dvNV (GLuint, GLsizei, const GLdouble *); GLAPI void APIENTRY glVertexAttribs4fvNV (GLuint, GLsizei, const GLfloat *); GLAPI void APIENTRY glVertexAttribs4svNV (GLuint, GLsizei, const GLshort *); GLAPI void APIENTRY glVertexAttribs4ubvNV (GLuint, GLsizei, const GLubyte *); #endif /* GL_GLEXT_PROTOTYPES */ typedef GLboolean (APIENTRYP PFNGLAREPROGRAMSRESIDENTNVPROC) (GLsizei n, const GLuint *programs, GLboolean *residences); typedef void (APIENTRYP PFNGLBINDPROGRAMNVPROC) (GLenum target, GLuint id); typedef void (APIENTRYP PFNGLDELETEPROGRAMSNVPROC) (GLsizei n, const GLuint *programs); typedef void (APIENTRYP PFNGLEXECUTEPROGRAMNVPROC) (GLenum target, GLuint id, const GLfloat *params); typedef void (APIENTRYP PFNGLGENPROGRAMSNVPROC) (GLsizei n, GLuint *programs); typedef void (APIENTRYP PFNGLGETPROGRAMPARAMETERDVNVPROC) (GLenum target, GLuint index, GLenum pname, GLdouble *params); typedef void (APIENTRYP PFNGLGETPROGRAMPARAMETERFVNVPROC) (GLenum target, GLuint index, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETPROGRAMIVNVPROC) (GLuint id, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETPROGRAMSTRINGNVPROC) (GLuint id, GLenum pname, GLubyte *program); typedef void (APIENTRYP PFNGLGETTRACKMATRIXIVNVPROC) (GLenum target, GLuint address, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVNVPROC) (GLuint index, GLenum pname, GLdouble *params); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVNVPROC) (GLuint index, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVNVPROC) (GLuint index, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVNVPROC) (GLuint index, GLenum pname, GLvoid* *pointer); typedef GLboolean (APIENTRYP PFNGLISPROGRAMNVPROC) (GLuint id); typedef void (APIENTRYP PFNGLLOADPROGRAMNVPROC) (GLenum target, GLuint id, GLsizei len, const GLubyte *program); typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4DNVPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4DVNVPROC) (GLenum target, GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4FNVPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4FVNVPROC) (GLenum target, GLuint index, const GLfloat *v); typedef void (APIENTRYP PFNGLPROGRAMPARAMETERS4DVNVPROC) (GLenum target, GLuint index, GLuint count, const GLdouble *v); typedef void (APIENTRYP PFNGLPROGRAMPARAMETERS4FVNVPROC) (GLenum target, GLuint index, GLuint count, const GLfloat *v); typedef void (APIENTRYP PFNGLREQUESTRESIDENTPROGRAMSNVPROC) (GLsizei n, const GLuint *programs); typedef void (APIENTRYP PFNGLTRACKMATRIXNVPROC) (GLenum target, GLuint address, GLenum matrix, GLenum transform); typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERNVPROC) (GLuint index, GLint fsize, GLenum type, GLsizei stride, const GLvoid *pointer); typedef void (APIENTRYP PFNGLVERTEXATTRIB1DNVPROC) (GLuint index, GLdouble x); typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVNVPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB1FNVPROC) (GLuint index, GLfloat x); typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVNVPROC) (GLuint index, const GLfloat *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB1SNVPROC) (GLuint index, GLshort x); typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVNVPROC) (GLuint index, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB2DNVPROC) (GLuint index, GLdouble x, GLdouble y); typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVNVPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB2FNVPROC) (GLuint index, GLfloat x, GLfloat y); typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVNVPROC) (GLuint index, const GLfloat *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB2SNVPROC) (GLuint index, GLshort x, GLshort y); typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVNVPROC) (GLuint index, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB3DNVPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z); typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVNVPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB3FNVPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVNVPROC) (GLuint index, const GLfloat *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB3SNVPROC) (GLuint index, GLshort x, GLshort y, GLshort z); typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVNVPROC) (GLuint index, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4DNVPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVNVPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4FNVPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVNVPROC) (GLuint index, const GLfloat *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4SNVPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVNVPROC) (GLuint index, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBNVPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVNVPROC) (GLuint index, const GLubyte *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS1DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS1FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS1SVNVPROC) (GLuint index, GLsizei count, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS2DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS2FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS2SVNVPROC) (GLuint index, GLsizei count, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS3DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS3FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS3SVNVPROC) (GLuint index, GLsizei count, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS4DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS4FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS4SVNVPROC) (GLuint index, GLsizei count, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS4UBVNVPROC) (GLuint index, GLsizei count, const GLubyte *v); #endif #ifndef GL_SGIX_texture_coordinate_clamp #define GL_SGIX_texture_coordinate_clamp 1 #endif #ifndef GL_SGIX_scalebias_hint #define GL_SGIX_scalebias_hint 1 #endif #ifndef GL_OML_interlace #define GL_OML_interlace 1 #endif #ifndef GL_OML_subsample #define GL_OML_subsample 1 #endif #ifndef GL_OML_resample #define GL_OML_resample 1 #endif #ifndef GL_NV_copy_depth_to_color #define GL_NV_copy_depth_to_color 1 #endif #ifndef GL_ATI_envmap_bumpmap #define GL_ATI_envmap_bumpmap 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glTexBumpParameterivATI (GLenum, const GLint *); GLAPI void APIENTRY glTexBumpParameterfvATI (GLenum, const GLfloat *); GLAPI void APIENTRY glGetTexBumpParameterivATI (GLenum, GLint *); GLAPI void APIENTRY glGetTexBumpParameterfvATI (GLenum, GLfloat *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLTEXBUMPPARAMETERIVATIPROC) (GLenum pname, const GLint *param); typedef void (APIENTRYP PFNGLTEXBUMPPARAMETERFVATIPROC) (GLenum pname, const GLfloat *param); typedef void (APIENTRYP PFNGLGETTEXBUMPPARAMETERIVATIPROC) (GLenum pname, GLint *param); typedef void (APIENTRYP PFNGLGETTEXBUMPPARAMETERFVATIPROC) (GLenum pname, GLfloat *param); #endif #ifndef GL_ATI_fragment_shader #define GL_ATI_fragment_shader 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI GLuint APIENTRY glGenFragmentShadersATI (GLuint); GLAPI void APIENTRY glBindFragmentShaderATI (GLuint); GLAPI void APIENTRY glDeleteFragmentShaderATI (GLuint); GLAPI void APIENTRY glBeginFragmentShaderATI (void); GLAPI void APIENTRY glEndFragmentShaderATI (void); GLAPI void APIENTRY glPassTexCoordATI (GLuint, GLuint, GLenum); GLAPI void APIENTRY glSampleMapATI (GLuint, GLuint, GLenum); GLAPI void APIENTRY glColorFragmentOp1ATI (GLenum, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint); GLAPI void APIENTRY glColorFragmentOp2ATI (GLenum, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint); GLAPI void APIENTRY glColorFragmentOp3ATI (GLenum, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint); GLAPI void APIENTRY glAlphaFragmentOp1ATI (GLenum, GLuint, GLuint, GLuint, GLuint, GLuint); GLAPI void APIENTRY glAlphaFragmentOp2ATI (GLenum, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint); GLAPI void APIENTRY glAlphaFragmentOp3ATI (GLenum, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint); GLAPI void APIENTRY glSetFragmentShaderConstantATI (GLuint, const GLfloat *); #endif /* GL_GLEXT_PROTOTYPES */ typedef GLuint (APIENTRYP PFNGLGENFRAGMENTSHADERSATIPROC) (GLuint range); typedef void (APIENTRYP PFNGLBINDFRAGMENTSHADERATIPROC) (GLuint id); typedef void (APIENTRYP PFNGLDELETEFRAGMENTSHADERATIPROC) (GLuint id); typedef void (APIENTRYP PFNGLBEGINFRAGMENTSHADERATIPROC) (void); typedef void (APIENTRYP PFNGLENDFRAGMENTSHADERATIPROC) (void); typedef void (APIENTRYP PFNGLPASSTEXCOORDATIPROC) (GLuint dst, GLuint coord, GLenum swizzle); typedef void (APIENTRYP PFNGLSAMPLEMAPATIPROC) (GLuint dst, GLuint interp, GLenum swizzle); typedef void (APIENTRYP PFNGLCOLORFRAGMENTOP1ATIPROC) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod); typedef void (APIENTRYP PFNGLCOLORFRAGMENTOP2ATIPROC) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod); typedef void (APIENTRYP PFNGLCOLORFRAGMENTOP3ATIPROC) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod); typedef void (APIENTRYP PFNGLALPHAFRAGMENTOP1ATIPROC) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod); typedef void (APIENTRYP PFNGLALPHAFRAGMENTOP2ATIPROC) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod); typedef void (APIENTRYP PFNGLALPHAFRAGMENTOP3ATIPROC) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod); typedef void (APIENTRYP PFNGLSETFRAGMENTSHADERCONSTANTATIPROC) (GLuint dst, const GLfloat *value); #endif #ifndef GL_ATI_pn_triangles #define GL_ATI_pn_triangles 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glPNTrianglesiATI (GLenum, GLint); GLAPI void APIENTRY glPNTrianglesfATI (GLenum, GLfloat); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLPNTRIANGLESIATIPROC) (GLenum pname, GLint param); typedef void (APIENTRYP PFNGLPNTRIANGLESFATIPROC) (GLenum pname, GLfloat param); #endif #ifndef GL_ATI_vertex_array_object #define GL_ATI_vertex_array_object 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI GLuint APIENTRY glNewObjectBufferATI (GLsizei, const GLvoid *, GLenum); GLAPI GLboolean APIENTRY glIsObjectBufferATI (GLuint); GLAPI void APIENTRY glUpdateObjectBufferATI (GLuint, GLuint, GLsizei, const GLvoid *, GLenum); GLAPI void APIENTRY glGetObjectBufferfvATI (GLuint, GLenum, GLfloat *); GLAPI void APIENTRY glGetObjectBufferivATI (GLuint, GLenum, GLint *); GLAPI void APIENTRY glFreeObjectBufferATI (GLuint); GLAPI void APIENTRY glArrayObjectATI (GLenum, GLint, GLenum, GLsizei, GLuint, GLuint); GLAPI void APIENTRY glGetArrayObjectfvATI (GLenum, GLenum, GLfloat *); GLAPI void APIENTRY glGetArrayObjectivATI (GLenum, GLenum, GLint *); GLAPI void APIENTRY glVariantArrayObjectATI (GLuint, GLenum, GLsizei, GLuint, GLuint); GLAPI void APIENTRY glGetVariantArrayObjectfvATI (GLuint, GLenum, GLfloat *); GLAPI void APIENTRY glGetVariantArrayObjectivATI (GLuint, GLenum, GLint *); #endif /* GL_GLEXT_PROTOTYPES */ typedef GLuint (APIENTRYP PFNGLNEWOBJECTBUFFERATIPROC) (GLsizei size, const GLvoid *pointer, GLenum usage); typedef GLboolean (APIENTRYP PFNGLISOBJECTBUFFERATIPROC) (GLuint buffer); typedef void (APIENTRYP PFNGLUPDATEOBJECTBUFFERATIPROC) (GLuint buffer, GLuint offset, GLsizei size, const GLvoid *pointer, GLenum preserve); typedef void (APIENTRYP PFNGLGETOBJECTBUFFERFVATIPROC) (GLuint buffer, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETOBJECTBUFFERIVATIPROC) (GLuint buffer, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLFREEOBJECTBUFFERATIPROC) (GLuint buffer); typedef void (APIENTRYP PFNGLARRAYOBJECTATIPROC) (GLenum array, GLint size, GLenum type, GLsizei stride, GLuint buffer, GLuint offset); typedef void (APIENTRYP PFNGLGETARRAYOBJECTFVATIPROC) (GLenum array, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETARRAYOBJECTIVATIPROC) (GLenum array, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLVARIANTARRAYOBJECTATIPROC) (GLuint id, GLenum type, GLsizei stride, GLuint buffer, GLuint offset); typedef void (APIENTRYP PFNGLGETVARIANTARRAYOBJECTFVATIPROC) (GLuint id, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETVARIANTARRAYOBJECTIVATIPROC) (GLuint id, GLenum pname, GLint *params); #endif #ifndef GL_EXT_vertex_shader #define GL_EXT_vertex_shader 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBeginVertexShaderEXT (void); GLAPI void APIENTRY glEndVertexShaderEXT (void); GLAPI void APIENTRY glBindVertexShaderEXT (GLuint); GLAPI GLuint APIENTRY glGenVertexShadersEXT (GLuint); GLAPI void APIENTRY glDeleteVertexShaderEXT (GLuint); GLAPI void APIENTRY glShaderOp1EXT (GLenum, GLuint, GLuint); GLAPI void APIENTRY glShaderOp2EXT (GLenum, GLuint, GLuint, GLuint); GLAPI void APIENTRY glShaderOp3EXT (GLenum, GLuint, GLuint, GLuint, GLuint); GLAPI void APIENTRY glSwizzleEXT (GLuint, GLuint, GLenum, GLenum, GLenum, GLenum); GLAPI void APIENTRY glWriteMaskEXT (GLuint, GLuint, GLenum, GLenum, GLenum, GLenum); GLAPI void APIENTRY glInsertComponentEXT (GLuint, GLuint, GLuint); GLAPI void APIENTRY glExtractComponentEXT (GLuint, GLuint, GLuint); GLAPI GLuint APIENTRY glGenSymbolsEXT (GLenum, GLenum, GLenum, GLuint); GLAPI void APIENTRY glSetInvariantEXT (GLuint, GLenum, const GLvoid *); GLAPI void APIENTRY glSetLocalConstantEXT (GLuint, GLenum, const GLvoid *); GLAPI void APIENTRY glVariantbvEXT (GLuint, const GLbyte *); GLAPI void APIENTRY glVariantsvEXT (GLuint, const GLshort *); GLAPI void APIENTRY glVariantivEXT (GLuint, const GLint *); GLAPI void APIENTRY glVariantfvEXT (GLuint, const GLfloat *); GLAPI void APIENTRY glVariantdvEXT (GLuint, const GLdouble *); GLAPI void APIENTRY glVariantubvEXT (GLuint, const GLubyte *); GLAPI void APIENTRY glVariantusvEXT (GLuint, const GLushort *); GLAPI void APIENTRY glVariantuivEXT (GLuint, const GLuint *); GLAPI void APIENTRY glVariantPointerEXT (GLuint, GLenum, GLuint, const GLvoid *); GLAPI void APIENTRY glEnableVariantClientStateEXT (GLuint); GLAPI void APIENTRY glDisableVariantClientStateEXT (GLuint); GLAPI GLuint APIENTRY glBindLightParameterEXT (GLenum, GLenum); GLAPI GLuint APIENTRY glBindMaterialParameterEXT (GLenum, GLenum); GLAPI GLuint APIENTRY glBindTexGenParameterEXT (GLenum, GLenum, GLenum); GLAPI GLuint APIENTRY glBindTextureUnitParameterEXT (GLenum, GLenum); GLAPI GLuint APIENTRY glBindParameterEXT (GLenum); GLAPI GLboolean APIENTRY glIsVariantEnabledEXT (GLuint, GLenum); GLAPI void APIENTRY glGetVariantBooleanvEXT (GLuint, GLenum, GLboolean *); GLAPI void APIENTRY glGetVariantIntegervEXT (GLuint, GLenum, GLint *); GLAPI void APIENTRY glGetVariantFloatvEXT (GLuint, GLenum, GLfloat *); GLAPI void APIENTRY glGetVariantPointervEXT (GLuint, GLenum, GLvoid* *); GLAPI void APIENTRY glGetInvariantBooleanvEXT (GLuint, GLenum, GLboolean *); GLAPI void APIENTRY glGetInvariantIntegervEXT (GLuint, GLenum, GLint *); GLAPI void APIENTRY glGetInvariantFloatvEXT (GLuint, GLenum, GLfloat *); GLAPI void APIENTRY glGetLocalConstantBooleanvEXT (GLuint, GLenum, GLboolean *); GLAPI void APIENTRY glGetLocalConstantIntegervEXT (GLuint, GLenum, GLint *); GLAPI void APIENTRY glGetLocalConstantFloatvEXT (GLuint, GLenum, GLfloat *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLBEGINVERTEXSHADEREXTPROC) (void); typedef void (APIENTRYP PFNGLENDVERTEXSHADEREXTPROC) (void); typedef void (APIENTRYP PFNGLBINDVERTEXSHADEREXTPROC) (GLuint id); typedef GLuint (APIENTRYP PFNGLGENVERTEXSHADERSEXTPROC) (GLuint range); typedef void (APIENTRYP PFNGLDELETEVERTEXSHADEREXTPROC) (GLuint id); typedef void (APIENTRYP PFNGLSHADEROP1EXTPROC) (GLenum op, GLuint res, GLuint arg1); typedef void (APIENTRYP PFNGLSHADEROP2EXTPROC) (GLenum op, GLuint res, GLuint arg1, GLuint arg2); typedef void (APIENTRYP PFNGLSHADEROP3EXTPROC) (GLenum op, GLuint res, GLuint arg1, GLuint arg2, GLuint arg3); typedef void (APIENTRYP PFNGLSWIZZLEEXTPROC) (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW); typedef void (APIENTRYP PFNGLWRITEMASKEXTPROC) (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW); typedef void (APIENTRYP PFNGLINSERTCOMPONENTEXTPROC) (GLuint res, GLuint src, GLuint num); typedef void (APIENTRYP PFNGLEXTRACTCOMPONENTEXTPROC) (GLuint res, GLuint src, GLuint num); typedef GLuint (APIENTRYP PFNGLGENSYMBOLSEXTPROC) (GLenum datatype, GLenum storagetype, GLenum range, GLuint components); typedef void (APIENTRYP PFNGLSETINVARIANTEXTPROC) (GLuint id, GLenum type, const GLvoid *addr); typedef void (APIENTRYP PFNGLSETLOCALCONSTANTEXTPROC) (GLuint id, GLenum type, const GLvoid *addr); typedef void (APIENTRYP PFNGLVARIANTBVEXTPROC) (GLuint id, const GLbyte *addr); typedef void (APIENTRYP PFNGLVARIANTSVEXTPROC) (GLuint id, const GLshort *addr); typedef void (APIENTRYP PFNGLVARIANTIVEXTPROC) (GLuint id, const GLint *addr); typedef void (APIENTRYP PFNGLVARIANTFVEXTPROC) (GLuint id, const GLfloat *addr); typedef void (APIENTRYP PFNGLVARIANTDVEXTPROC) (GLuint id, const GLdouble *addr); typedef void (APIENTRYP PFNGLVARIANTUBVEXTPROC) (GLuint id, const GLubyte *addr); typedef void (APIENTRYP PFNGLVARIANTUSVEXTPROC) (GLuint id, const GLushort *addr); typedef void (APIENTRYP PFNGLVARIANTUIVEXTPROC) (GLuint id, const GLuint *addr); typedef void (APIENTRYP PFNGLVARIANTPOINTEREXTPROC) (GLuint id, GLenum type, GLuint stride, const GLvoid *addr); typedef void (APIENTRYP PFNGLENABLEVARIANTCLIENTSTATEEXTPROC) (GLuint id); typedef void (APIENTRYP PFNGLDISABLEVARIANTCLIENTSTATEEXTPROC) (GLuint id); typedef GLuint (APIENTRYP PFNGLBINDLIGHTPARAMETEREXTPROC) (GLenum light, GLenum value); typedef GLuint (APIENTRYP PFNGLBINDMATERIALPARAMETEREXTPROC) (GLenum face, GLenum value); typedef GLuint (APIENTRYP PFNGLBINDTEXGENPARAMETEREXTPROC) (GLenum unit, GLenum coord, GLenum value); typedef GLuint (APIENTRYP PFNGLBINDTEXTUREUNITPARAMETEREXTPROC) (GLenum unit, GLenum value); typedef GLuint (APIENTRYP PFNGLBINDPARAMETEREXTPROC) (GLenum value); typedef GLboolean (APIENTRYP PFNGLISVARIANTENABLEDEXTPROC) (GLuint id, GLenum cap); typedef void (APIENTRYP PFNGLGETVARIANTBOOLEANVEXTPROC) (GLuint id, GLenum value, GLboolean *data); typedef void (APIENTRYP PFNGLGETVARIANTINTEGERVEXTPROC) (GLuint id, GLenum value, GLint *data); typedef void (APIENTRYP PFNGLGETVARIANTFLOATVEXTPROC) (GLuint id, GLenum value, GLfloat *data); typedef void (APIENTRYP PFNGLGETVARIANTPOINTERVEXTPROC) (GLuint id, GLenum value, GLvoid* *data); typedef void (APIENTRYP PFNGLGETINVARIANTBOOLEANVEXTPROC) (GLuint id, GLenum value, GLboolean *data); typedef void (APIENTRYP PFNGLGETINVARIANTINTEGERVEXTPROC) (GLuint id, GLenum value, GLint *data); typedef void (APIENTRYP PFNGLGETINVARIANTFLOATVEXTPROC) (GLuint id, GLenum value, GLfloat *data); typedef void (APIENTRYP PFNGLGETLOCALCONSTANTBOOLEANVEXTPROC) (GLuint id, GLenum value, GLboolean *data); typedef void (APIENTRYP PFNGLGETLOCALCONSTANTINTEGERVEXTPROC) (GLuint id, GLenum value, GLint *data); typedef void (APIENTRYP PFNGLGETLOCALCONSTANTFLOATVEXTPROC) (GLuint id, GLenum value, GLfloat *data); #endif #ifndef GL_ATI_vertex_streams #define GL_ATI_vertex_streams 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glVertexStream1sATI (GLenum, GLshort); GLAPI void APIENTRY glVertexStream1svATI (GLenum, const GLshort *); GLAPI void APIENTRY glVertexStream1iATI (GLenum, GLint); GLAPI void APIENTRY glVertexStream1ivATI (GLenum, const GLint *); GLAPI void APIENTRY glVertexStream1fATI (GLenum, GLfloat); GLAPI void APIENTRY glVertexStream1fvATI (GLenum, const GLfloat *); GLAPI void APIENTRY glVertexStream1dATI (GLenum, GLdouble); GLAPI void APIENTRY glVertexStream1dvATI (GLenum, const GLdouble *); GLAPI void APIENTRY glVertexStream2sATI (GLenum, GLshort, GLshort); GLAPI void APIENTRY glVertexStream2svATI (GLenum, const GLshort *); GLAPI void APIENTRY glVertexStream2iATI (GLenum, GLint, GLint); GLAPI void APIENTRY glVertexStream2ivATI (GLenum, const GLint *); GLAPI void APIENTRY glVertexStream2fATI (GLenum, GLfloat, GLfloat); GLAPI void APIENTRY glVertexStream2fvATI (GLenum, const GLfloat *); GLAPI void APIENTRY glVertexStream2dATI (GLenum, GLdouble, GLdouble); GLAPI void APIENTRY glVertexStream2dvATI (GLenum, const GLdouble *); GLAPI void APIENTRY glVertexStream3sATI (GLenum, GLshort, GLshort, GLshort); GLAPI void APIENTRY glVertexStream3svATI (GLenum, const GLshort *); GLAPI void APIENTRY glVertexStream3iATI (GLenum, GLint, GLint, GLint); GLAPI void APIENTRY glVertexStream3ivATI (GLenum, const GLint *); GLAPI void APIENTRY glVertexStream3fATI (GLenum, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glVertexStream3fvATI (GLenum, const GLfloat *); GLAPI void APIENTRY glVertexStream3dATI (GLenum, GLdouble, GLdouble, GLdouble); GLAPI void APIENTRY glVertexStream3dvATI (GLenum, const GLdouble *); GLAPI void APIENTRY glVertexStream4sATI (GLenum, GLshort, GLshort, GLshort, GLshort); GLAPI void APIENTRY glVertexStream4svATI (GLenum, const GLshort *); GLAPI void APIENTRY glVertexStream4iATI (GLenum, GLint, GLint, GLint, GLint); GLAPI void APIENTRY glVertexStream4ivATI (GLenum, const GLint *); GLAPI void APIENTRY glVertexStream4fATI (GLenum, GLfloat, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glVertexStream4fvATI (GLenum, const GLfloat *); GLAPI void APIENTRY glVertexStream4dATI (GLenum, GLdouble, GLdouble, GLdouble, GLdouble); GLAPI void APIENTRY glVertexStream4dvATI (GLenum, const GLdouble *); GLAPI void APIENTRY glNormalStream3bATI (GLenum, GLbyte, GLbyte, GLbyte); GLAPI void APIENTRY glNormalStream3bvATI (GLenum, const GLbyte *); GLAPI void APIENTRY glNormalStream3sATI (GLenum, GLshort, GLshort, GLshort); GLAPI void APIENTRY glNormalStream3svATI (GLenum, const GLshort *); GLAPI void APIENTRY glNormalStream3iATI (GLenum, GLint, GLint, GLint); GLAPI void APIENTRY glNormalStream3ivATI (GLenum, const GLint *); GLAPI void APIENTRY glNormalStream3fATI (GLenum, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glNormalStream3fvATI (GLenum, const GLfloat *); GLAPI void APIENTRY glNormalStream3dATI (GLenum, GLdouble, GLdouble, GLdouble); GLAPI void APIENTRY glNormalStream3dvATI (GLenum, const GLdouble *); GLAPI void APIENTRY glClientActiveVertexStreamATI (GLenum); GLAPI void APIENTRY glVertexBlendEnviATI (GLenum, GLint); GLAPI void APIENTRY glVertexBlendEnvfATI (GLenum, GLfloat); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLVERTEXSTREAM1SATIPROC) (GLenum stream, GLshort x); typedef void (APIENTRYP PFNGLVERTEXSTREAM1SVATIPROC) (GLenum stream, const GLshort *coords); typedef void (APIENTRYP PFNGLVERTEXSTREAM1IATIPROC) (GLenum stream, GLint x); typedef void (APIENTRYP PFNGLVERTEXSTREAM1IVATIPROC) (GLenum stream, const GLint *coords); typedef void (APIENTRYP PFNGLVERTEXSTREAM1FATIPROC) (GLenum stream, GLfloat x); typedef void (APIENTRYP PFNGLVERTEXSTREAM1FVATIPROC) (GLenum stream, const GLfloat *coords); typedef void (APIENTRYP PFNGLVERTEXSTREAM1DATIPROC) (GLenum stream, GLdouble x); typedef void (APIENTRYP PFNGLVERTEXSTREAM1DVATIPROC) (GLenum stream, const GLdouble *coords); typedef void (APIENTRYP PFNGLVERTEXSTREAM2SATIPROC) (GLenum stream, GLshort x, GLshort y); typedef void (APIENTRYP PFNGLVERTEXSTREAM2SVATIPROC) (GLenum stream, const GLshort *coords); typedef void (APIENTRYP PFNGLVERTEXSTREAM2IATIPROC) (GLenum stream, GLint x, GLint y); typedef void (APIENTRYP PFNGLVERTEXSTREAM2IVATIPROC) (GLenum stream, const GLint *coords); typedef void (APIENTRYP PFNGLVERTEXSTREAM2FATIPROC) (GLenum stream, GLfloat x, GLfloat y); typedef void (APIENTRYP PFNGLVERTEXSTREAM2FVATIPROC) (GLenum stream, const GLfloat *coords); typedef void (APIENTRYP PFNGLVERTEXSTREAM2DATIPROC) (GLenum stream, GLdouble x, GLdouble y); typedef void (APIENTRYP PFNGLVERTEXSTREAM2DVATIPROC) (GLenum stream, const GLdouble *coords); typedef void (APIENTRYP PFNGLVERTEXSTREAM3SATIPROC) (GLenum stream, GLshort x, GLshort y, GLshort z); typedef void (APIENTRYP PFNGLVERTEXSTREAM3SVATIPROC) (GLenum stream, const GLshort *coords); typedef void (APIENTRYP PFNGLVERTEXSTREAM3IATIPROC) (GLenum stream, GLint x, GLint y, GLint z); typedef void (APIENTRYP PFNGLVERTEXSTREAM3IVATIPROC) (GLenum stream, const GLint *coords); typedef void (APIENTRYP PFNGLVERTEXSTREAM3FATIPROC) (GLenum stream, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLVERTEXSTREAM3FVATIPROC) (GLenum stream, const GLfloat *coords); typedef void (APIENTRYP PFNGLVERTEXSTREAM3DATIPROC) (GLenum stream, GLdouble x, GLdouble y, GLdouble z); typedef void (APIENTRYP PFNGLVERTEXSTREAM3DVATIPROC) (GLenum stream, const GLdouble *coords); typedef void (APIENTRYP PFNGLVERTEXSTREAM4SATIPROC) (GLenum stream, GLshort x, GLshort y, GLshort z, GLshort w); typedef void (APIENTRYP PFNGLVERTEXSTREAM4SVATIPROC) (GLenum stream, const GLshort *coords); typedef void (APIENTRYP PFNGLVERTEXSTREAM4IATIPROC) (GLenum stream, GLint x, GLint y, GLint z, GLint w); typedef void (APIENTRYP PFNGLVERTEXSTREAM4IVATIPROC) (GLenum stream, const GLint *coords); typedef void (APIENTRYP PFNGLVERTEXSTREAM4FATIPROC) (GLenum stream, GLfloat x, GLfloat y, GLfloat z, GLfloat w); typedef void (APIENTRYP PFNGLVERTEXSTREAM4FVATIPROC) (GLenum stream, const GLfloat *coords); typedef void (APIENTRYP PFNGLVERTEXSTREAM4DATIPROC) (GLenum stream, GLdouble x, GLdouble y, GLdouble z, GLdouble w); typedef void (APIENTRYP PFNGLVERTEXSTREAM4DVATIPROC) (GLenum stream, const GLdouble *coords); typedef void (APIENTRYP PFNGLNORMALSTREAM3BATIPROC) (GLenum stream, GLbyte nx, GLbyte ny, GLbyte nz); typedef void (APIENTRYP PFNGLNORMALSTREAM3BVATIPROC) (GLenum stream, const GLbyte *coords); typedef void (APIENTRYP PFNGLNORMALSTREAM3SATIPROC) (GLenum stream, GLshort nx, GLshort ny, GLshort nz); typedef void (APIENTRYP PFNGLNORMALSTREAM3SVATIPROC) (GLenum stream, const GLshort *coords); typedef void (APIENTRYP PFNGLNORMALSTREAM3IATIPROC) (GLenum stream, GLint nx, GLint ny, GLint nz); typedef void (APIENTRYP PFNGLNORMALSTREAM3IVATIPROC) (GLenum stream, const GLint *coords); typedef void (APIENTRYP PFNGLNORMALSTREAM3FATIPROC) (GLenum stream, GLfloat nx, GLfloat ny, GLfloat nz); typedef void (APIENTRYP PFNGLNORMALSTREAM3FVATIPROC) (GLenum stream, const GLfloat *coords); typedef void (APIENTRYP PFNGLNORMALSTREAM3DATIPROC) (GLenum stream, GLdouble nx, GLdouble ny, GLdouble nz); typedef void (APIENTRYP PFNGLNORMALSTREAM3DVATIPROC) (GLenum stream, const GLdouble *coords); typedef void (APIENTRYP PFNGLCLIENTACTIVEVERTEXSTREAMATIPROC) (GLenum stream); typedef void (APIENTRYP PFNGLVERTEXBLENDENVIATIPROC) (GLenum pname, GLint param); typedef void (APIENTRYP PFNGLVERTEXBLENDENVFATIPROC) (GLenum pname, GLfloat param); #endif #ifndef GL_ATI_element_array #define GL_ATI_element_array 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glElementPointerATI (GLenum, const GLvoid *); GLAPI void APIENTRY glDrawElementArrayATI (GLenum, GLsizei); GLAPI void APIENTRY glDrawRangeElementArrayATI (GLenum, GLuint, GLuint, GLsizei); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLELEMENTPOINTERATIPROC) (GLenum type, const GLvoid *pointer); typedef void (APIENTRYP PFNGLDRAWELEMENTARRAYATIPROC) (GLenum mode, GLsizei count); typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTARRAYATIPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count); #endif #ifndef GL_SUN_mesh_array #define GL_SUN_mesh_array 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDrawMeshArraysSUN (GLenum, GLint, GLsizei, GLsizei); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLDRAWMESHARRAYSSUNPROC) (GLenum mode, GLint first, GLsizei count, GLsizei width); #endif #ifndef GL_SUN_slice_accum #define GL_SUN_slice_accum 1 #endif #ifndef GL_NV_multisample_filter_hint #define GL_NV_multisample_filter_hint 1 #endif #ifndef GL_NV_depth_clamp #define GL_NV_depth_clamp 1 #endif #ifndef GL_NV_occlusion_query #define GL_NV_occlusion_query 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glGenOcclusionQueriesNV (GLsizei, GLuint *); GLAPI void APIENTRY glDeleteOcclusionQueriesNV (GLsizei, const GLuint *); GLAPI GLboolean APIENTRY glIsOcclusionQueryNV (GLuint); GLAPI void APIENTRY glBeginOcclusionQueryNV (GLuint); GLAPI void APIENTRY glEndOcclusionQueryNV (void); GLAPI void APIENTRY glGetOcclusionQueryivNV (GLuint, GLenum, GLint *); GLAPI void APIENTRY glGetOcclusionQueryuivNV (GLuint, GLenum, GLuint *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLGENOCCLUSIONQUERIESNVPROC) (GLsizei n, GLuint *ids); typedef void (APIENTRYP PFNGLDELETEOCCLUSIONQUERIESNVPROC) (GLsizei n, const GLuint *ids); typedef GLboolean (APIENTRYP PFNGLISOCCLUSIONQUERYNVPROC) (GLuint id); typedef void (APIENTRYP PFNGLBEGINOCCLUSIONQUERYNVPROC) (GLuint id); typedef void (APIENTRYP PFNGLENDOCCLUSIONQUERYNVPROC) (void); typedef void (APIENTRYP PFNGLGETOCCLUSIONQUERYIVNVPROC) (GLuint id, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETOCCLUSIONQUERYUIVNVPROC) (GLuint id, GLenum pname, GLuint *params); #endif #ifndef GL_NV_point_sprite #define GL_NV_point_sprite 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glPointParameteriNV (GLenum, GLint); GLAPI void APIENTRY glPointParameterivNV (GLenum, const GLint *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLPOINTPARAMETERINVPROC) (GLenum pname, GLint param); typedef void (APIENTRYP PFNGLPOINTPARAMETERIVNVPROC) (GLenum pname, const GLint *params); #endif #ifndef GL_NV_texture_shader3 #define GL_NV_texture_shader3 1 #endif #ifndef GL_NV_vertex_program1_1 #define GL_NV_vertex_program1_1 1 #endif #ifndef GL_EXT_shadow_funcs #define GL_EXT_shadow_funcs 1 #endif #ifndef GL_EXT_stencil_two_side #define GL_EXT_stencil_two_side 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glActiveStencilFaceEXT (GLenum); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLACTIVESTENCILFACEEXTPROC) (GLenum face); #endif #ifndef GL_ATI_text_fragment_shader #define GL_ATI_text_fragment_shader 1 #endif #ifndef GL_APPLE_client_storage #define GL_APPLE_client_storage 1 #endif #ifndef GL_APPLE_element_array #define GL_APPLE_element_array 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glElementPointerAPPLE (GLenum, const GLvoid *); GLAPI void APIENTRY glDrawElementArrayAPPLE (GLenum, GLint, GLsizei); GLAPI void APIENTRY glDrawRangeElementArrayAPPLE (GLenum, GLuint, GLuint, GLint, GLsizei); GLAPI void APIENTRY glMultiDrawElementArrayAPPLE (GLenum, const GLint *, const GLsizei *, GLsizei); GLAPI void APIENTRY glMultiDrawRangeElementArrayAPPLE (GLenum, GLuint, GLuint, const GLint *, const GLsizei *, GLsizei); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLELEMENTPOINTERAPPLEPROC) (GLenum type, const GLvoid *pointer); typedef void (APIENTRYP PFNGLDRAWELEMENTARRAYAPPLEPROC) (GLenum mode, GLint first, GLsizei count); typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTARRAYAPPLEPROC) (GLenum mode, GLuint start, GLuint end, GLint first, GLsizei count); typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTARRAYAPPLEPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount); typedef void (APIENTRYP PFNGLMULTIDRAWRANGEELEMENTARRAYAPPLEPROC) (GLenum mode, GLuint start, GLuint end, const GLint *first, const GLsizei *count, GLsizei primcount); #endif #ifndef GL_APPLE_fence #define GL_APPLE_fence 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glGenFencesAPPLE (GLsizei, GLuint *); GLAPI void APIENTRY glDeleteFencesAPPLE (GLsizei, const GLuint *); GLAPI void APIENTRY glSetFenceAPPLE (GLuint); GLAPI GLboolean APIENTRY glIsFenceAPPLE (GLuint); GLAPI GLboolean APIENTRY glTestFenceAPPLE (GLuint); GLAPI void APIENTRY glFinishFenceAPPLE (GLuint); GLAPI GLboolean APIENTRY glTestObjectAPPLE (GLenum, GLuint); GLAPI void APIENTRY glFinishObjectAPPLE (GLenum, GLint); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLGENFENCESAPPLEPROC) (GLsizei n, GLuint *fences); typedef void (APIENTRYP PFNGLDELETEFENCESAPPLEPROC) (GLsizei n, const GLuint *fences); typedef void (APIENTRYP PFNGLSETFENCEAPPLEPROC) (GLuint fence); typedef GLboolean (APIENTRYP PFNGLISFENCEAPPLEPROC) (GLuint fence); typedef GLboolean (APIENTRYP PFNGLTESTFENCEAPPLEPROC) (GLuint fence); typedef void (APIENTRYP PFNGLFINISHFENCEAPPLEPROC) (GLuint fence); typedef GLboolean (APIENTRYP PFNGLTESTOBJECTAPPLEPROC) (GLenum object, GLuint name); typedef void (APIENTRYP PFNGLFINISHOBJECTAPPLEPROC) (GLenum object, GLint name); #endif #ifndef GL_APPLE_vertex_array_object #define GL_APPLE_vertex_array_object 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBindVertexArrayAPPLE (GLuint); GLAPI void APIENTRY glDeleteVertexArraysAPPLE (GLsizei, const GLuint *); GLAPI void APIENTRY glGenVertexArraysAPPLE (GLsizei, GLuint *); GLAPI GLboolean APIENTRY glIsVertexArrayAPPLE (GLuint); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLBINDVERTEXARRAYAPPLEPROC) (GLuint array); typedef void (APIENTRYP PFNGLDELETEVERTEXARRAYSAPPLEPROC) (GLsizei n, const GLuint *arrays); typedef void (APIENTRYP PFNGLGENVERTEXARRAYSAPPLEPROC) (GLsizei n, GLuint *arrays); typedef GLboolean (APIENTRYP PFNGLISVERTEXARRAYAPPLEPROC) (GLuint array); #endif #ifndef GL_APPLE_vertex_array_range #define GL_APPLE_vertex_array_range 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glVertexArrayRangeAPPLE (GLsizei, GLvoid *); GLAPI void APIENTRY glFlushVertexArrayRangeAPPLE (GLsizei, GLvoid *); GLAPI void APIENTRY glVertexArrayParameteriAPPLE (GLenum, GLint); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLVERTEXARRAYRANGEAPPLEPROC) (GLsizei length, GLvoid *pointer); typedef void (APIENTRYP PFNGLFLUSHVERTEXARRAYRANGEAPPLEPROC) (GLsizei length, GLvoid *pointer); typedef void (APIENTRYP PFNGLVERTEXARRAYPARAMETERIAPPLEPROC) (GLenum pname, GLint param); #endif #ifndef GL_APPLE_ycbcr_422 #define GL_APPLE_ycbcr_422 1 #endif #ifndef GL_S3_s3tc #define GL_S3_s3tc 1 #endif #ifndef GL_ATI_draw_buffers #define GL_ATI_draw_buffers 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDrawBuffersATI (GLsizei, const GLenum *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLDRAWBUFFERSATIPROC) (GLsizei n, const GLenum *bufs); #endif #ifndef GL_ATI_pixel_format_float #define GL_ATI_pixel_format_float 1 /* This is really a WGL extension, but defines some associated GL enums. * ATI does not export "GL_ATI_pixel_format_float" in the GL_EXTENSIONS string. */ #endif #ifndef GL_ATI_texture_env_combine3 #define GL_ATI_texture_env_combine3 1 #endif #ifndef GL_ATI_texture_float #define GL_ATI_texture_float 1 #endif #ifndef GL_NV_float_buffer #define GL_NV_float_buffer 1 #endif #ifndef GL_NV_fragment_program #define GL_NV_fragment_program 1 /* Some NV_fragment_program entry points are shared with ARB_vertex_program. */ #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glProgramNamedParameter4fNV (GLuint, GLsizei, const GLubyte *, GLfloat, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glProgramNamedParameter4dNV (GLuint, GLsizei, const GLubyte *, GLdouble, GLdouble, GLdouble, GLdouble); GLAPI void APIENTRY glProgramNamedParameter4fvNV (GLuint, GLsizei, const GLubyte *, const GLfloat *); GLAPI void APIENTRY glProgramNamedParameter4dvNV (GLuint, GLsizei, const GLubyte *, const GLdouble *); GLAPI void APIENTRY glGetProgramNamedParameterfvNV (GLuint, GLsizei, const GLubyte *, GLfloat *); GLAPI void APIENTRY glGetProgramNamedParameterdvNV (GLuint, GLsizei, const GLubyte *, GLdouble *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4FNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w); typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4DNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLdouble x, GLdouble y, GLdouble z, GLdouble w); typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4FVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, const GLfloat *v); typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4DVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, const GLdouble *v); typedef void (APIENTRYP PFNGLGETPROGRAMNAMEDPARAMETERFVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLfloat *params); typedef void (APIENTRYP PFNGLGETPROGRAMNAMEDPARAMETERDVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLdouble *params); #endif #ifndef GL_NV_half_float #define GL_NV_half_float 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glVertex2hNV (GLhalfNV, GLhalfNV); GLAPI void APIENTRY glVertex2hvNV (const GLhalfNV *); GLAPI void APIENTRY glVertex3hNV (GLhalfNV, GLhalfNV, GLhalfNV); GLAPI void APIENTRY glVertex3hvNV (const GLhalfNV *); GLAPI void APIENTRY glVertex4hNV (GLhalfNV, GLhalfNV, GLhalfNV, GLhalfNV); GLAPI void APIENTRY glVertex4hvNV (const GLhalfNV *); GLAPI void APIENTRY glNormal3hNV (GLhalfNV, GLhalfNV, GLhalfNV); GLAPI void APIENTRY glNormal3hvNV (const GLhalfNV *); GLAPI void APIENTRY glColor3hNV (GLhalfNV, GLhalfNV, GLhalfNV); GLAPI void APIENTRY glColor3hvNV (const GLhalfNV *); GLAPI void APIENTRY glColor4hNV (GLhalfNV, GLhalfNV, GLhalfNV, GLhalfNV); GLAPI void APIENTRY glColor4hvNV (const GLhalfNV *); GLAPI void APIENTRY glTexCoord1hNV (GLhalfNV); GLAPI void APIENTRY glTexCoord1hvNV (const GLhalfNV *); GLAPI void APIENTRY glTexCoord2hNV (GLhalfNV, GLhalfNV); GLAPI void APIENTRY glTexCoord2hvNV (const GLhalfNV *); GLAPI void APIENTRY glTexCoord3hNV (GLhalfNV, GLhalfNV, GLhalfNV); GLAPI void APIENTRY glTexCoord3hvNV (const GLhalfNV *); GLAPI void APIENTRY glTexCoord4hNV (GLhalfNV, GLhalfNV, GLhalfNV, GLhalfNV); GLAPI void APIENTRY glTexCoord4hvNV (const GLhalfNV *); GLAPI void APIENTRY glMultiTexCoord1hNV (GLenum, GLhalfNV); GLAPI void APIENTRY glMultiTexCoord1hvNV (GLenum, const GLhalfNV *); GLAPI void APIENTRY glMultiTexCoord2hNV (GLenum, GLhalfNV, GLhalfNV); GLAPI void APIENTRY glMultiTexCoord2hvNV (GLenum, const GLhalfNV *); GLAPI void APIENTRY glMultiTexCoord3hNV (GLenum, GLhalfNV, GLhalfNV, GLhalfNV); GLAPI void APIENTRY glMultiTexCoord3hvNV (GLenum, const GLhalfNV *); GLAPI void APIENTRY glMultiTexCoord4hNV (GLenum, GLhalfNV, GLhalfNV, GLhalfNV, GLhalfNV); GLAPI void APIENTRY glMultiTexCoord4hvNV (GLenum, const GLhalfNV *); GLAPI void APIENTRY glFogCoordhNV (GLhalfNV); GLAPI void APIENTRY glFogCoordhvNV (const GLhalfNV *); GLAPI void APIENTRY glSecondaryColor3hNV (GLhalfNV, GLhalfNV, GLhalfNV); GLAPI void APIENTRY glSecondaryColor3hvNV (const GLhalfNV *); GLAPI void APIENTRY glVertexWeighthNV (GLhalfNV); GLAPI void APIENTRY glVertexWeighthvNV (const GLhalfNV *); GLAPI void APIENTRY glVertexAttrib1hNV (GLuint, GLhalfNV); GLAPI void APIENTRY glVertexAttrib1hvNV (GLuint, const GLhalfNV *); GLAPI void APIENTRY glVertexAttrib2hNV (GLuint, GLhalfNV, GLhalfNV); GLAPI void APIENTRY glVertexAttrib2hvNV (GLuint, const GLhalfNV *); GLAPI void APIENTRY glVertexAttrib3hNV (GLuint, GLhalfNV, GLhalfNV, GLhalfNV); GLAPI void APIENTRY glVertexAttrib3hvNV (GLuint, const GLhalfNV *); GLAPI void APIENTRY glVertexAttrib4hNV (GLuint, GLhalfNV, GLhalfNV, GLhalfNV, GLhalfNV); GLAPI void APIENTRY glVertexAttrib4hvNV (GLuint, const GLhalfNV *); GLAPI void APIENTRY glVertexAttribs1hvNV (GLuint, GLsizei, const GLhalfNV *); GLAPI void APIENTRY glVertexAttribs2hvNV (GLuint, GLsizei, const GLhalfNV *); GLAPI void APIENTRY glVertexAttribs3hvNV (GLuint, GLsizei, const GLhalfNV *); GLAPI void APIENTRY glVertexAttribs4hvNV (GLuint, GLsizei, const GLhalfNV *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLVERTEX2HNVPROC) (GLhalfNV x, GLhalfNV y); typedef void (APIENTRYP PFNGLVERTEX2HVNVPROC) (const GLhalfNV *v); typedef void (APIENTRYP PFNGLVERTEX3HNVPROC) (GLhalfNV x, GLhalfNV y, GLhalfNV z); typedef void (APIENTRYP PFNGLVERTEX3HVNVPROC) (const GLhalfNV *v); typedef void (APIENTRYP PFNGLVERTEX4HNVPROC) (GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w); typedef void (APIENTRYP PFNGLVERTEX4HVNVPROC) (const GLhalfNV *v); typedef void (APIENTRYP PFNGLNORMAL3HNVPROC) (GLhalfNV nx, GLhalfNV ny, GLhalfNV nz); typedef void (APIENTRYP PFNGLNORMAL3HVNVPROC) (const GLhalfNV *v); typedef void (APIENTRYP PFNGLCOLOR3HNVPROC) (GLhalfNV red, GLhalfNV green, GLhalfNV blue); typedef void (APIENTRYP PFNGLCOLOR3HVNVPROC) (const GLhalfNV *v); typedef void (APIENTRYP PFNGLCOLOR4HNVPROC) (GLhalfNV red, GLhalfNV green, GLhalfNV blue, GLhalfNV alpha); typedef void (APIENTRYP PFNGLCOLOR4HVNVPROC) (const GLhalfNV *v); typedef void (APIENTRYP PFNGLTEXCOORD1HNVPROC) (GLhalfNV s); typedef void (APIENTRYP PFNGLTEXCOORD1HVNVPROC) (const GLhalfNV *v); typedef void (APIENTRYP PFNGLTEXCOORD2HNVPROC) (GLhalfNV s, GLhalfNV t); typedef void (APIENTRYP PFNGLTEXCOORD2HVNVPROC) (const GLhalfNV *v); typedef void (APIENTRYP PFNGLTEXCOORD3HNVPROC) (GLhalfNV s, GLhalfNV t, GLhalfNV r); typedef void (APIENTRYP PFNGLTEXCOORD3HVNVPROC) (const GLhalfNV *v); typedef void (APIENTRYP PFNGLTEXCOORD4HNVPROC) (GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q); typedef void (APIENTRYP PFNGLTEXCOORD4HVNVPROC) (const GLhalfNV *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD1HNVPROC) (GLenum target, GLhalfNV s); typedef void (APIENTRYP PFNGLMULTITEXCOORD1HVNVPROC) (GLenum target, const GLhalfNV *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD2HNVPROC) (GLenum target, GLhalfNV s, GLhalfNV t); typedef void (APIENTRYP PFNGLMULTITEXCOORD2HVNVPROC) (GLenum target, const GLhalfNV *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD3HNVPROC) (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r); typedef void (APIENTRYP PFNGLMULTITEXCOORD3HVNVPROC) (GLenum target, const GLhalfNV *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD4HNVPROC) (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q); typedef void (APIENTRYP PFNGLMULTITEXCOORD4HVNVPROC) (GLenum target, const GLhalfNV *v); typedef void (APIENTRYP PFNGLFOGCOORDHNVPROC) (GLhalfNV fog); typedef void (APIENTRYP PFNGLFOGCOORDHVNVPROC) (const GLhalfNV *fog); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3HNVPROC) (GLhalfNV red, GLhalfNV green, GLhalfNV blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3HVNVPROC) (const GLhalfNV *v); typedef void (APIENTRYP PFNGLVERTEXWEIGHTHNVPROC) (GLhalfNV weight); typedef void (APIENTRYP PFNGLVERTEXWEIGHTHVNVPROC) (const GLhalfNV *weight); typedef void (APIENTRYP PFNGLVERTEXATTRIB1HNVPROC) (GLuint index, GLhalfNV x); typedef void (APIENTRYP PFNGLVERTEXATTRIB1HVNVPROC) (GLuint index, const GLhalfNV *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB2HNVPROC) (GLuint index, GLhalfNV x, GLhalfNV y); typedef void (APIENTRYP PFNGLVERTEXATTRIB2HVNVPROC) (GLuint index, const GLhalfNV *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB3HNVPROC) (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z); typedef void (APIENTRYP PFNGLVERTEXATTRIB3HVNVPROC) (GLuint index, const GLhalfNV *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4HNVPROC) (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w); typedef void (APIENTRYP PFNGLVERTEXATTRIB4HVNVPROC) (GLuint index, const GLhalfNV *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS1HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS2HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS3HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS4HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v); #endif #ifndef GL_NV_pixel_data_range #define GL_NV_pixel_data_range 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glPixelDataRangeNV (GLenum, GLsizei, GLvoid *); GLAPI void APIENTRY glFlushPixelDataRangeNV (GLenum); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLPIXELDATARANGENVPROC) (GLenum target, GLsizei length, GLvoid *pointer); typedef void (APIENTRYP PFNGLFLUSHPIXELDATARANGENVPROC) (GLenum target); #endif #ifndef GL_NV_primitive_restart #define GL_NV_primitive_restart 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glPrimitiveRestartNV (void); GLAPI void APIENTRY glPrimitiveRestartIndexNV (GLuint); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLPRIMITIVERESTARTNVPROC) (void); typedef void (APIENTRYP PFNGLPRIMITIVERESTARTINDEXNVPROC) (GLuint index); #endif #ifndef GL_NV_texture_expand_normal #define GL_NV_texture_expand_normal 1 #endif #ifndef GL_NV_vertex_program2 #define GL_NV_vertex_program2 1 #endif #ifndef GL_ATI_map_object_buffer #define GL_ATI_map_object_buffer 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI GLvoid* APIENTRY glMapObjectBufferATI (GLuint); GLAPI void APIENTRY glUnmapObjectBufferATI (GLuint); #endif /* GL_GLEXT_PROTOTYPES */ typedef GLvoid* (APIENTRYP PFNGLMAPOBJECTBUFFERATIPROC) (GLuint buffer); typedef void (APIENTRYP PFNGLUNMAPOBJECTBUFFERATIPROC) (GLuint buffer); #endif #ifndef GL_ATI_separate_stencil #define GL_ATI_separate_stencil 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glStencilOpSeparateATI (GLenum, GLenum, GLenum, GLenum); GLAPI void APIENTRY glStencilFuncSeparateATI (GLenum, GLenum, GLint, GLuint); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLSTENCILOPSEPARATEATIPROC) (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); typedef void (APIENTRYP PFNGLSTENCILFUNCSEPARATEATIPROC) (GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask); #endif #ifndef GL_ATI_vertex_attrib_array_object #define GL_ATI_vertex_attrib_array_object 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glVertexAttribArrayObjectATI (GLuint, GLint, GLenum, GLboolean, GLsizei, GLuint, GLuint); GLAPI void APIENTRY glGetVertexAttribArrayObjectfvATI (GLuint, GLenum, GLfloat *); GLAPI void APIENTRY glGetVertexAttribArrayObjectivATI (GLuint, GLenum, GLint *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLVERTEXATTRIBARRAYOBJECTATIPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLuint buffer, GLuint offset); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBARRAYOBJECTFVATIPROC) (GLuint index, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBARRAYOBJECTIVATIPROC) (GLuint index, GLenum pname, GLint *params); #endif #ifndef GL_OES_read_format #define GL_OES_read_format 1 #endif #ifndef GL_EXT_depth_bounds_test #define GL_EXT_depth_bounds_test 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDepthBoundsEXT (GLclampd, GLclampd); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLDEPTHBOUNDSEXTPROC) (GLclampd zmin, GLclampd zmax); #endif #ifndef GL_EXT_texture_mirror_clamp #define GL_EXT_texture_mirror_clamp 1 #endif #ifndef GL_EXT_blend_equation_separate #define GL_EXT_blend_equation_separate 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBlendEquationSeparateEXT (GLenum, GLenum); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEEXTPROC) (GLenum modeRGB, GLenum modeAlpha); #endif #ifndef GL_MESA_pack_invert #define GL_MESA_pack_invert 1 #endif #ifndef GL_MESA_ycbcr_texture #define GL_MESA_ycbcr_texture 1 #endif #ifndef GL_EXT_pixel_buffer_object #define GL_EXT_pixel_buffer_object 1 #endif #ifndef GL_NV_fragment_program_option #define GL_NV_fragment_program_option 1 #endif #ifndef GL_NV_fragment_program2 #define GL_NV_fragment_program2 1 #endif #ifndef GL_NV_vertex_program2_option #define GL_NV_vertex_program2_option 1 #endif #ifndef GL_NV_vertex_program3 #define GL_NV_vertex_program3 1 #endif #ifndef GL_EXT_framebuffer_object #define GL_EXT_framebuffer_object 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI GLboolean APIENTRY glIsRenderbufferEXT (GLuint); GLAPI void APIENTRY glBindRenderbufferEXT (GLenum, GLuint); GLAPI void APIENTRY glDeleteRenderbuffersEXT (GLsizei, const GLuint *); GLAPI void APIENTRY glGenRenderbuffersEXT (GLsizei, GLuint *); GLAPI void APIENTRY glRenderbufferStorageEXT (GLenum, GLenum, GLsizei, GLsizei); GLAPI void APIENTRY glGetRenderbufferParameterivEXT (GLenum, GLenum, GLint *); GLAPI GLboolean APIENTRY glIsFramebufferEXT (GLuint); GLAPI void APIENTRY glBindFramebufferEXT (GLenum, GLuint); GLAPI void APIENTRY glDeleteFramebuffersEXT (GLsizei, const GLuint *); GLAPI void APIENTRY glGenFramebuffersEXT (GLsizei, GLuint *); GLAPI GLenum APIENTRY glCheckFramebufferStatusEXT (GLenum); GLAPI void APIENTRY glFramebufferTexture1DEXT (GLenum, GLenum, GLenum, GLuint, GLint); GLAPI void APIENTRY glFramebufferTexture2DEXT (GLenum, GLenum, GLenum, GLuint, GLint); GLAPI void APIENTRY glFramebufferTexture3DEXT (GLenum, GLenum, GLenum, GLuint, GLint, GLint); GLAPI void APIENTRY glFramebufferRenderbufferEXT (GLenum, GLenum, GLenum, GLuint); GLAPI void APIENTRY glGetFramebufferAttachmentParameterivEXT (GLenum, GLenum, GLenum, GLint *); GLAPI void APIENTRY glGenerateMipmapEXT (GLenum); #endif /* GL_GLEXT_PROTOTYPES */ typedef GLboolean (APIENTRYP PFNGLISRENDERBUFFEREXTPROC) (GLuint renderbuffer); typedef void (APIENTRYP PFNGLBINDRENDERBUFFEREXTPROC) (GLenum target, GLuint renderbuffer); typedef void (APIENTRYP PFNGLDELETERENDERBUFFERSEXTPROC) (GLsizei n, const GLuint *renderbuffers); typedef void (APIENTRYP PFNGLGENRENDERBUFFERSEXTPROC) (GLsizei n, GLuint *renderbuffers); typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); typedef void (APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); typedef GLboolean (APIENTRYP PFNGLISFRAMEBUFFEREXTPROC) (GLuint framebuffer); typedef void (APIENTRYP PFNGLBINDFRAMEBUFFEREXTPROC) (GLenum target, GLuint framebuffer); typedef void (APIENTRYP PFNGLDELETEFRAMEBUFFERSEXTPROC) (GLsizei n, const GLuint *framebuffers); typedef void (APIENTRYP PFNGLGENFRAMEBUFFERSEXTPROC) (GLsizei n, GLuint *framebuffers); typedef GLenum (APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC) (GLenum target); typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE1DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); typedef void (APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); typedef void (APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC) (GLenum target, GLenum attachment, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGENERATEMIPMAPEXTPROC) (GLenum target); #endif #ifndef GL_GREMEDY_string_marker #define GL_GREMEDY_string_marker 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glStringMarkerGREMEDY (GLsizei, const GLvoid *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLSTRINGMARKERGREMEDYPROC) (GLsizei len, const GLvoid *string); #endif #ifndef GL_EXT_packed_depth_stencil #define GL_EXT_packed_depth_stencil 1 #endif #ifndef GL_EXT_stencil_clear_tag #define GL_EXT_stencil_clear_tag 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glStencilClearTagEXT (GLsizei, GLuint); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLSTENCILCLEARTAGEXTPROC) (GLsizei stencilTagBits, GLuint stencilClearTag); #endif #ifndef GL_EXT_texture_sRGB #define GL_EXT_texture_sRGB 1 #endif #ifndef GL_EXT_framebuffer_blit #define GL_EXT_framebuffer_blit 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBlitFramebufferEXT (GLint, GLint, GLint, GLint, GLint, GLint, GLint, GLint, GLbitfield, GLenum); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLBLITFRAMEBUFFEREXTPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); #endif #ifndef GL_EXT_framebuffer_multisample #define GL_EXT_framebuffer_multisample 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glRenderbufferStorageMultisampleEXT (GLenum, GLsizei, GLenum, GLsizei, GLsizei); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); #endif #ifndef GL_MESAX_texture_stack #define GL_MESAX_texture_stack 1 #endif #ifndef GL_EXT_timer_query #define GL_EXT_timer_query 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glGetQueryObjecti64vEXT (GLuint, GLenum, GLint64EXT *); GLAPI void APIENTRY glGetQueryObjectui64vEXT (GLuint, GLenum, GLuint64EXT *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLGETQUERYOBJECTI64VEXTPROC) (GLuint id, GLenum pname, GLint64EXT *params); typedef void (APIENTRYP PFNGLGETQUERYOBJECTUI64VEXTPROC) (GLuint id, GLenum pname, GLuint64EXT *params); #endif #ifndef GL_EXT_gpu_program_parameters #define GL_EXT_gpu_program_parameters 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glProgramEnvParameters4fvEXT (GLenum, GLuint, GLsizei, const GLfloat *); GLAPI void APIENTRY glProgramLocalParameters4fvEXT (GLenum, GLuint, GLsizei, const GLfloat *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERS4FVEXTPROC) (GLenum target, GLuint index, GLsizei count, const GLfloat *params); typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERS4FVEXTPROC) (GLenum target, GLuint index, GLsizei count, const GLfloat *params); #endif #ifndef GL_APPLE_flush_buffer_range #define GL_APPLE_flush_buffer_range 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBufferParameteriAPPLE (GLenum, GLenum, GLint); GLAPI void APIENTRY glFlushMappedBufferRangeAPPLE (GLenum, GLintptr, GLsizeiptr); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLBUFFERPARAMETERIAPPLEPROC) (GLenum target, GLenum pname, GLint param); typedef void (APIENTRYP PFNGLFLUSHMAPPEDBUFFERRANGEAPPLEPROC) (GLenum target, GLintptr offset, GLsizeiptr size); #endif #ifndef GL_NV_gpu_program4 #define GL_NV_gpu_program4 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glProgramLocalParameterI4iNV (GLenum, GLuint, GLint, GLint, GLint, GLint); GLAPI void APIENTRY glProgramLocalParameterI4ivNV (GLenum, GLuint, const GLint *); GLAPI void APIENTRY glProgramLocalParametersI4ivNV (GLenum, GLuint, GLsizei, const GLint *); GLAPI void APIENTRY glProgramLocalParameterI4uiNV (GLenum, GLuint, GLuint, GLuint, GLuint, GLuint); GLAPI void APIENTRY glProgramLocalParameterI4uivNV (GLenum, GLuint, const GLuint *); GLAPI void APIENTRY glProgramLocalParametersI4uivNV (GLenum, GLuint, GLsizei, const GLuint *); GLAPI void APIENTRY glProgramEnvParameterI4iNV (GLenum, GLuint, GLint, GLint, GLint, GLint); GLAPI void APIENTRY glProgramEnvParameterI4ivNV (GLenum, GLuint, const GLint *); GLAPI void APIENTRY glProgramEnvParametersI4ivNV (GLenum, GLuint, GLsizei, const GLint *); GLAPI void APIENTRY glProgramEnvParameterI4uiNV (GLenum, GLuint, GLuint, GLuint, GLuint, GLuint); GLAPI void APIENTRY glProgramEnvParameterI4uivNV (GLenum, GLuint, const GLuint *); GLAPI void APIENTRY glProgramEnvParametersI4uivNV (GLenum, GLuint, GLsizei, const GLuint *); GLAPI void APIENTRY glGetProgramLocalParameterIivNV (GLenum, GLuint, GLint *); GLAPI void APIENTRY glGetProgramLocalParameterIuivNV (GLenum, GLuint, GLuint *); GLAPI void APIENTRY glGetProgramEnvParameterIivNV (GLenum, GLuint, GLint *); GLAPI void APIENTRY glGetProgramEnvParameterIuivNV (GLenum, GLuint, GLuint *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERI4INVPROC) (GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w); typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERI4IVNVPROC) (GLenum target, GLuint index, const GLint *params); typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERSI4IVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLint *params); typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERI4UINVPROC) (GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERI4UIVNVPROC) (GLenum target, GLuint index, const GLuint *params); typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERSI4UIVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLuint *params); typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERI4INVPROC) (GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w); typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERI4IVNVPROC) (GLenum target, GLuint index, const GLint *params); typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERSI4IVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLint *params); typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERI4UINVPROC) (GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERI4UIVNVPROC) (GLenum target, GLuint index, const GLuint *params); typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERSI4UIVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLuint *params); typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERIIVNVPROC) (GLenum target, GLuint index, GLint *params); typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERIUIVNVPROC) (GLenum target, GLuint index, GLuint *params); typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERIIVNVPROC) (GLenum target, GLuint index, GLint *params); typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERIUIVNVPROC) (GLenum target, GLuint index, GLuint *params); #endif #ifndef GL_NV_geometry_program4 #define GL_NV_geometry_program4 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glProgramVertexLimitNV (GLenum, GLint); GLAPI void APIENTRY glFramebufferTextureEXT (GLenum, GLenum, GLuint, GLint); GLAPI void APIENTRY glFramebufferTextureLayerEXT (GLenum, GLenum, GLuint, GLint, GLint); GLAPI void APIENTRY glFramebufferTextureFaceEXT (GLenum, GLenum, GLuint, GLint, GLenum); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLPROGRAMVERTEXLIMITNVPROC) (GLenum target, GLint limit); typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREEXTPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level); typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYEREXTPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREFACEEXTPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLenum face); #endif #ifndef GL_EXT_geometry_shader4 #define GL_EXT_geometry_shader4 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glProgramParameteriEXT (GLuint, GLenum, GLint); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLPROGRAMPARAMETERIEXTPROC) (GLuint program, GLenum pname, GLint value); #endif #ifndef GL_NV_vertex_program4 #define GL_NV_vertex_program4 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glVertexAttribI1iEXT (GLuint, GLint); GLAPI void APIENTRY glVertexAttribI2iEXT (GLuint, GLint, GLint); GLAPI void APIENTRY glVertexAttribI3iEXT (GLuint, GLint, GLint, GLint); GLAPI void APIENTRY glVertexAttribI4iEXT (GLuint, GLint, GLint, GLint, GLint); GLAPI void APIENTRY glVertexAttribI1uiEXT (GLuint, GLuint); GLAPI void APIENTRY glVertexAttribI2uiEXT (GLuint, GLuint, GLuint); GLAPI void APIENTRY glVertexAttribI3uiEXT (GLuint, GLuint, GLuint, GLuint); GLAPI void APIENTRY glVertexAttribI4uiEXT (GLuint, GLuint, GLuint, GLuint, GLuint); GLAPI void APIENTRY glVertexAttribI1ivEXT (GLuint, const GLint *); GLAPI void APIENTRY glVertexAttribI2ivEXT (GLuint, const GLint *); GLAPI void APIENTRY glVertexAttribI3ivEXT (GLuint, const GLint *); GLAPI void APIENTRY glVertexAttribI4ivEXT (GLuint, const GLint *); GLAPI void APIENTRY glVertexAttribI1uivEXT (GLuint, const GLuint *); GLAPI void APIENTRY glVertexAttribI2uivEXT (GLuint, const GLuint *); GLAPI void APIENTRY glVertexAttribI3uivEXT (GLuint, const GLuint *); GLAPI void APIENTRY glVertexAttribI4uivEXT (GLuint, const GLuint *); GLAPI void APIENTRY glVertexAttribI4bvEXT (GLuint, const GLbyte *); GLAPI void APIENTRY glVertexAttribI4svEXT (GLuint, const GLshort *); GLAPI void APIENTRY glVertexAttribI4ubvEXT (GLuint, const GLubyte *); GLAPI void APIENTRY glVertexAttribI4usvEXT (GLuint, const GLushort *); GLAPI void APIENTRY glVertexAttribIPointerEXT (GLuint, GLint, GLenum, GLsizei, const GLvoid *); GLAPI void APIENTRY glGetVertexAttribIivEXT (GLuint, GLenum, GLint *); GLAPI void APIENTRY glGetVertexAttribIuivEXT (GLuint, GLenum, GLuint *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IEXTPROC) (GLuint index, GLint x); typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IEXTPROC) (GLuint index, GLint x, GLint y); typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IEXTPROC) (GLuint index, GLint x, GLint y, GLint z); typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IEXTPROC) (GLuint index, GLint x, GLint y, GLint z, GLint w); typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIEXTPROC) (GLuint index, GLuint x); typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIEXTPROC) (GLuint index, GLuint x, GLuint y); typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIEXTPROC) (GLuint index, GLuint x, GLuint y, GLuint z); typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIEXTPROC) (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IVEXTPROC) (GLuint index, const GLint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IVEXTPROC) (GLuint index, const GLint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IVEXTPROC) (GLuint index, const GLint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IVEXTPROC) (GLuint index, const GLint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIVEXTPROC) (GLuint index, const GLuint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIVEXTPROC) (GLuint index, const GLuint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIVEXTPROC) (GLuint index, const GLuint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIVEXTPROC) (GLuint index, const GLuint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI4BVEXTPROC) (GLuint index, const GLbyte *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI4SVEXTPROC) (GLuint index, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UBVEXTPROC) (GLuint index, const GLubyte *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI4USVEXTPROC) (GLuint index, const GLushort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBIPOINTEREXTPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIIVEXTPROC) (GLuint index, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIUIVEXTPROC) (GLuint index, GLenum pname, GLuint *params); #endif #ifndef GL_EXT_gpu_shader4 #define GL_EXT_gpu_shader4 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glGetUniformuivEXT (GLuint, GLint, GLuint *); GLAPI void APIENTRY glBindFragDataLocationEXT (GLuint, GLuint, const GLchar *); GLAPI GLint APIENTRY glGetFragDataLocationEXT (GLuint, const GLchar *); GLAPI void APIENTRY glUniform1uiEXT (GLint, GLuint); GLAPI void APIENTRY glUniform2uiEXT (GLint, GLuint, GLuint); GLAPI void APIENTRY glUniform3uiEXT (GLint, GLuint, GLuint, GLuint); GLAPI void APIENTRY glUniform4uiEXT (GLint, GLuint, GLuint, GLuint, GLuint); GLAPI void APIENTRY glUniform1uivEXT (GLint, GLsizei, const GLuint *); GLAPI void APIENTRY glUniform2uivEXT (GLint, GLsizei, const GLuint *); GLAPI void APIENTRY glUniform3uivEXT (GLint, GLsizei, const GLuint *); GLAPI void APIENTRY glUniform4uivEXT (GLint, GLsizei, const GLuint *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLGETUNIFORMUIVEXTPROC) (GLuint program, GLint location, GLuint *params); typedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONEXTPROC) (GLuint program, GLuint color, const GLchar *name); typedef GLint (APIENTRYP PFNGLGETFRAGDATALOCATIONEXTPROC) (GLuint program, const GLchar *name); typedef void (APIENTRYP PFNGLUNIFORM1UIEXTPROC) (GLint location, GLuint v0); typedef void (APIENTRYP PFNGLUNIFORM2UIEXTPROC) (GLint location, GLuint v0, GLuint v1); typedef void (APIENTRYP PFNGLUNIFORM3UIEXTPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2); typedef void (APIENTRYP PFNGLUNIFORM4UIEXTPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); typedef void (APIENTRYP PFNGLUNIFORM1UIVEXTPROC) (GLint location, GLsizei count, const GLuint *value); typedef void (APIENTRYP PFNGLUNIFORM2UIVEXTPROC) (GLint location, GLsizei count, const GLuint *value); typedef void (APIENTRYP PFNGLUNIFORM3UIVEXTPROC) (GLint location, GLsizei count, const GLuint *value); typedef void (APIENTRYP PFNGLUNIFORM4UIVEXTPROC) (GLint location, GLsizei count, const GLuint *value); #endif #ifndef GL_EXT_draw_instanced #define GL_EXT_draw_instanced 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDrawArraysInstancedEXT (GLenum, GLint, GLsizei, GLsizei); GLAPI void APIENTRY glDrawElementsInstancedEXT (GLenum, GLsizei, GLenum, const GLvoid *, GLsizei); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDEXTPROC) (GLenum mode, GLint start, GLsizei count, GLsizei primcount); typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDEXTPROC) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount); #endif #ifndef GL_EXT_packed_float #define GL_EXT_packed_float 1 #endif #ifndef GL_EXT_texture_array #define GL_EXT_texture_array 1 #endif #ifndef GL_EXT_texture_buffer_object #define GL_EXT_texture_buffer_object 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glTexBufferEXT (GLenum, GLenum, GLuint); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLTEXBUFFEREXTPROC) (GLenum target, GLenum internalformat, GLuint buffer); #endif #ifndef GL_EXT_texture_compression_latc #define GL_EXT_texture_compression_latc 1 #endif #ifndef GL_EXT_texture_compression_rgtc #define GL_EXT_texture_compression_rgtc 1 #endif #ifndef GL_EXT_texture_shared_exponent #define GL_EXT_texture_shared_exponent 1 #endif #ifndef GL_NV_depth_buffer_float #define GL_NV_depth_buffer_float 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDepthRangedNV (GLdouble, GLdouble); GLAPI void APIENTRY glClearDepthdNV (GLdouble); GLAPI void APIENTRY glDepthBoundsdNV (GLdouble, GLdouble); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLDEPTHRANGEDNVPROC) (GLdouble zNear, GLdouble zFar); typedef void (APIENTRYP PFNGLCLEARDEPTHDNVPROC) (GLdouble depth); typedef void (APIENTRYP PFNGLDEPTHBOUNDSDNVPROC) (GLdouble zmin, GLdouble zmax); #endif #ifndef GL_NV_fragment_program4 #define GL_NV_fragment_program4 1 #endif #ifndef GL_NV_framebuffer_multisample_coverage #define GL_NV_framebuffer_multisample_coverage 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glRenderbufferStorageMultisampleCoverageNV (GLenum, GLsizei, GLsizei, GLenum, GLsizei, GLsizei); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLECOVERAGENVPROC) (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLenum internalformat, GLsizei width, GLsizei height); #endif #ifndef GL_EXT_framebuffer_sRGB #define GL_EXT_framebuffer_sRGB 1 #endif #ifndef GL_NV_geometry_shader4 #define GL_NV_geometry_shader4 1 #endif #ifndef GL_NV_parameter_buffer_object #define GL_NV_parameter_buffer_object 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glProgramBufferParametersfvNV (GLenum, GLuint, GLuint, GLsizei, const GLfloat *); GLAPI void APIENTRY glProgramBufferParametersIivNV (GLenum, GLuint, GLuint, GLsizei, const GLint *); GLAPI void APIENTRY glProgramBufferParametersIuivNV (GLenum, GLuint, GLuint, GLsizei, const GLuint *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLPROGRAMBUFFERPARAMETERSFVNVPROC) (GLenum target, GLuint buffer, GLuint index, GLsizei count, const GLfloat *params); typedef void (APIENTRYP PFNGLPROGRAMBUFFERPARAMETERSIIVNVPROC) (GLenum target, GLuint buffer, GLuint index, GLsizei count, const GLint *params); typedef void (APIENTRYP PFNGLPROGRAMBUFFERPARAMETERSIUIVNVPROC) (GLenum target, GLuint buffer, GLuint index, GLsizei count, const GLuint *params); #endif #ifndef GL_EXT_draw_buffers2 #define GL_EXT_draw_buffers2 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glColorMaskIndexedEXT (GLuint, GLboolean, GLboolean, GLboolean, GLboolean); GLAPI void APIENTRY glGetBooleanIndexedvEXT (GLenum, GLuint, GLboolean *); GLAPI void APIENTRY glGetIntegerIndexedvEXT (GLenum, GLuint, GLint *); GLAPI void APIENTRY glEnableIndexedEXT (GLenum, GLuint); GLAPI void APIENTRY glDisableIndexedEXT (GLenum, GLuint); GLAPI GLboolean APIENTRY glIsEnabledIndexedEXT (GLenum, GLuint); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLCOLORMASKINDEXEDEXTPROC) (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); typedef void (APIENTRYP PFNGLGETBOOLEANINDEXEDVEXTPROC) (GLenum target, GLuint index, GLboolean *data); typedef void (APIENTRYP PFNGLGETINTEGERINDEXEDVEXTPROC) (GLenum target, GLuint index, GLint *data); typedef void (APIENTRYP PFNGLENABLEINDEXEDEXTPROC) (GLenum target, GLuint index); typedef void (APIENTRYP PFNGLDISABLEINDEXEDEXTPROC) (GLenum target, GLuint index); typedef GLboolean (APIENTRYP PFNGLISENABLEDINDEXEDEXTPROC) (GLenum target, GLuint index); #endif #ifndef GL_NV_transform_feedback #define GL_NV_transform_feedback 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBeginTransformFeedbackNV (GLenum); GLAPI void APIENTRY glEndTransformFeedbackNV (void); GLAPI void APIENTRY glTransformFeedbackAttribsNV (GLuint, const GLint *, GLenum); GLAPI void APIENTRY glBindBufferRangeNV (GLenum, GLuint, GLuint, GLintptr, GLsizeiptr); GLAPI void APIENTRY glBindBufferOffsetNV (GLenum, GLuint, GLuint, GLintptr); GLAPI void APIENTRY glBindBufferBaseNV (GLenum, GLuint, GLuint); GLAPI void APIENTRY glTransformFeedbackVaryingsNV (GLuint, GLsizei, const GLint *, GLenum); GLAPI void APIENTRY glActiveVaryingNV (GLuint, const GLchar *); GLAPI GLint APIENTRY glGetVaryingLocationNV (GLuint, const GLchar *); GLAPI void APIENTRY glGetActiveVaryingNV (GLuint, GLuint, GLsizei, GLsizei *, GLsizei *, GLenum *, GLchar *); GLAPI void APIENTRY glGetTransformFeedbackVaryingNV (GLuint, GLuint, GLint *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLBEGINTRANSFORMFEEDBACKNVPROC) (GLenum primitiveMode); typedef void (APIENTRYP PFNGLENDTRANSFORMFEEDBACKNVPROC) (void); typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKATTRIBSNVPROC) (GLuint count, const GLint *attribs, GLenum bufferMode); typedef void (APIENTRYP PFNGLBINDBUFFERRANGENVPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); typedef void (APIENTRYP PFNGLBINDBUFFEROFFSETNVPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset); typedef void (APIENTRYP PFNGLBINDBUFFERBASENVPROC) (GLenum target, GLuint index, GLuint buffer); typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKVARYINGSNVPROC) (GLuint program, GLsizei count, const GLint *locations, GLenum bufferMode); typedef void (APIENTRYP PFNGLACTIVEVARYINGNVPROC) (GLuint program, const GLchar *name); typedef GLint (APIENTRYP PFNGLGETVARYINGLOCATIONNVPROC) (GLuint program, const GLchar *name); typedef void (APIENTRYP PFNGLGETACTIVEVARYINGNVPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKVARYINGNVPROC) (GLuint program, GLuint index, GLint *location); #endif #ifndef GL_EXT_bindable_uniform #define GL_EXT_bindable_uniform 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glUniformBufferEXT (GLuint, GLint, GLuint); GLAPI GLint APIENTRY glGetUniformBufferSizeEXT (GLuint, GLint); GLAPI GLintptr APIENTRY glGetUniformOffsetEXT (GLuint, GLint); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLUNIFORMBUFFEREXTPROC) (GLuint program, GLint location, GLuint buffer); typedef GLint (APIENTRYP PFNGLGETUNIFORMBUFFERSIZEEXTPROC) (GLuint program, GLint location); typedef GLintptr (APIENTRYP PFNGLGETUNIFORMOFFSETEXTPROC) (GLuint program, GLint location); #endif #ifndef GL_EXT_texture_integer #define GL_EXT_texture_integer 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glTexParameterIivEXT (GLenum, GLenum, const GLint *); GLAPI void APIENTRY glTexParameterIuivEXT (GLenum, GLenum, const GLuint *); GLAPI void APIENTRY glGetTexParameterIivEXT (GLenum, GLenum, GLint *); GLAPI void APIENTRY glGetTexParameterIuivEXT (GLenum, GLenum, GLuint *); GLAPI void APIENTRY glClearColorIiEXT (GLint, GLint, GLint, GLint); GLAPI void APIENTRY glClearColorIuiEXT (GLuint, GLuint, GLuint, GLuint); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLTEXPARAMETERIIVEXTPROC) (GLenum target, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLTEXPARAMETERIUIVEXTPROC) (GLenum target, GLenum pname, const GLuint *params); typedef void (APIENTRYP PFNGLGETTEXPARAMETERIIVEXTPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETTEXPARAMETERIUIVEXTPROC) (GLenum target, GLenum pname, GLuint *params); typedef void (APIENTRYP PFNGLCLEARCOLORIIEXTPROC) (GLint red, GLint green, GLint blue, GLint alpha); typedef void (APIENTRYP PFNGLCLEARCOLORIUIEXTPROC) (GLuint red, GLuint green, GLuint blue, GLuint alpha); #endif #ifndef GL_GREMEDY_frame_terminator #define GL_GREMEDY_frame_terminator 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glFrameTerminatorGREMEDY (void); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLFRAMETERMINATORGREMEDYPROC) (void); #endif #ifndef GL_NV_conditional_render #define GL_NV_conditional_render 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBeginConditionalRenderNV (GLuint, GLenum); GLAPI void APIENTRY glEndConditionalRenderNV (void); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLBEGINCONDITIONALRENDERNVPROC) (GLuint id, GLenum mode); typedef void (APIENTRYP PFNGLENDCONDITIONALRENDERNVPROC) (void); #endif #ifndef GL_NV_present_video #define GL_NV_present_video 1 #endif #ifndef GL_EXT_transform_feedback #define GL_EXT_transform_feedback 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBeginTransformFeedbackEXT (GLenum); GLAPI void APIENTRY glEndTransformFeedbackEXT (void); GLAPI void APIENTRY glBindBufferRangeEXT (GLenum, GLuint, GLuint, GLintptr, GLsizeiptr); GLAPI void APIENTRY glBindBufferOffsetEXT (GLenum, GLuint, GLuint, GLintptr); GLAPI void APIENTRY glBindBufferBaseEXT (GLenum, GLuint, GLuint); GLAPI void APIENTRY glTransformFeedbackVaryingsEXT (GLuint, GLsizei, const GLint *, GLenum); GLAPI void APIENTRY glGetTransformFeedbackVaryingEXT (GLuint, GLuint, GLint *); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLBEGINTRANSFORMFEEDBACKEXTPROC) (GLenum primitiveMode); typedef void (APIENTRYP PFNGLENDTRANSFORMFEEDBACKEXTPROC) (void); typedef void (APIENTRYP PFNGLBINDBUFFERRANGEEXTPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); typedef void (APIENTRYP PFNGLBINDBUFFEROFFSETEXTPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset); typedef void (APIENTRYP PFNGLBINDBUFFERBASEEXTPROC) (GLenum target, GLuint index, GLuint buffer); typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKVARYINGSEXTPROC) (GLuint program, GLsizei count, const GLint *locations, GLenum bufferMode); typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKVARYINGEXTPROC) (GLuint program, GLuint index, GLint *location); #endif #ifndef GL_EXT_direct_state_access #define GL_EXT_direct_state_access 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glClientAttribDefaultEXT (GLbitfield); GLAPI void APIENTRY glPushClientAttribDefaultEXT (GLbitfield); GLAPI void APIENTRY glMatrixLoadfEXT (GLenum, const GLfloat *); GLAPI void APIENTRY glMatrixLoaddEXT (GLenum, const GLdouble *); GLAPI void APIENTRY glMatrixMultfEXT (GLenum, const GLfloat *); GLAPI void APIENTRY glMatrixMultdEXT (GLenum, const GLdouble *); GLAPI void APIENTRY glMatrixLoadIdentityEXT (GLenum); GLAPI void APIENTRY glMatrixRotatefEXT (GLenum, GLfloat, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glMatrixRotatedEXT (GLenum, GLdouble, GLdouble, GLdouble, GLdouble); GLAPI void APIENTRY glMatrixScalefEXT (GLenum, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glMatrixScaledEXT (GLenum, GLdouble, GLdouble, GLdouble); GLAPI void APIENTRY glMatrixTranslatefEXT (GLenum, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glMatrixTranslatedEXT (GLenum, GLdouble, GLdouble, GLdouble); GLAPI void APIENTRY glMatrixFrustumEXT (GLenum, GLdouble, GLdouble, GLdouble, GLdouble, GLdouble, GLdouble); GLAPI void APIENTRY glMatrixOrthoEXT (GLenum, GLdouble, GLdouble, GLdouble, GLdouble, GLdouble, GLdouble); GLAPI void APIENTRY glMatrixPopEXT (GLenum); GLAPI void APIENTRY glMatrixPushEXT (GLenum); GLAPI void APIENTRY glMatrixLoadTransposefEXT (GLenum, const GLfloat *); GLAPI void APIENTRY glMatrixLoadTransposedEXT (GLenum, const GLdouble *); GLAPI void APIENTRY glMatrixMultTransposefEXT (GLenum, const GLfloat *); GLAPI void APIENTRY glMatrixMultTransposedEXT (GLenum, const GLdouble *); GLAPI void APIENTRY glTextureParameterfEXT (GLuint, GLenum, GLenum, GLfloat); GLAPI void APIENTRY glTextureParameterfvEXT (GLuint, GLenum, GLenum, const GLfloat *); GLAPI void APIENTRY glTextureParameteriEXT (GLuint, GLenum, GLenum, GLint); GLAPI void APIENTRY glTextureParameterivEXT (GLuint, GLenum, GLenum, const GLint *); GLAPI void APIENTRY glTextureImage1DEXT (GLuint, GLenum, GLint, GLenum, GLsizei, GLint, GLenum, GLenum, const GLvoid *); GLAPI void APIENTRY glTextureImage2DEXT (GLuint, GLenum, GLint, GLenum, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid *); GLAPI void APIENTRY glTextureSubImage1DEXT (GLuint, GLenum, GLint, GLint, GLsizei, GLenum, GLenum, const GLvoid *); GLAPI void APIENTRY glTextureSubImage2DEXT (GLuint, GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *); GLAPI void APIENTRY glCopyTextureImage1DEXT (GLuint, GLenum, GLint, GLenum, GLint, GLint, GLsizei, GLint); GLAPI void APIENTRY glCopyTextureImage2DEXT (GLuint, GLenum, GLint, GLenum, GLint, GLint, GLsizei, GLsizei, GLint); GLAPI void APIENTRY glCopyTextureSubImage1DEXT (GLuint, GLenum, GLint, GLint, GLint, GLint, GLsizei); GLAPI void APIENTRY glCopyTextureSubImage2DEXT (GLuint, GLenum, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei); GLAPI void APIENTRY glGetTextureImageEXT (GLuint, GLenum, GLint, GLenum, GLenum, GLvoid *); GLAPI void APIENTRY glGetTextureParameterfvEXT (GLuint, GLenum, GLenum, GLfloat *); GLAPI void APIENTRY glGetTextureParameterivEXT (GLuint, GLenum, GLenum, GLint *); GLAPI void APIENTRY glGetTextureLevelParameterfvEXT (GLuint, GLenum, GLint, GLenum, GLfloat *); GLAPI void APIENTRY glGetTextureLevelParameterivEXT (GLuint, GLenum, GLint, GLenum, GLint *); GLAPI void APIENTRY glTextureImage3DEXT (GLuint, GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid *); GLAPI void APIENTRY glTextureSubImage3DEXT (GLuint, GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *); GLAPI void APIENTRY glCopyTextureSubImage3DEXT (GLuint, GLenum, GLint, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei); GLAPI void APIENTRY glMultiTexParameterfEXT (GLenum, GLenum, GLenum, GLfloat); GLAPI void APIENTRY glMultiTexParameterfvEXT (GLenum, GLenum, GLenum, const GLfloat *); GLAPI void APIENTRY glMultiTexParameteriEXT (GLenum, GLenum, GLenum, GLint); GLAPI void APIENTRY glMultiTexParameterivEXT (GLenum, GLenum, GLenum, const GLint *); GLAPI void APIENTRY glMultiTexImage1DEXT (GLenum, GLenum, GLint, GLenum, GLsizei, GLint, GLenum, GLenum, const GLvoid *); GLAPI void APIENTRY glMultiTexImage2DEXT (GLenum, GLenum, GLint, GLenum, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid *); GLAPI void APIENTRY glMultiTexSubImage1DEXT (GLenum, GLenum, GLint, GLint, GLsizei, GLenum, GLenum, const GLvoid *); GLAPI void APIENTRY glMultiTexSubImage2DEXT (GLenum, GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *); GLAPI void APIENTRY glCopyMultiTexImage1DEXT (GLenum, GLenum, GLint, GLenum, GLint, GLint, GLsizei, GLint); GLAPI void APIENTRY glCopyMultiTexImage2DEXT (GLenum, GLenum, GLint, GLenum, GLint, GLint, GLsizei, GLsizei, GLint); GLAPI void APIENTRY glCopyMultiTexSubImage1DEXT (GLenum, GLenum, GLint, GLint, GLint, GLint, GLsizei); GLAPI void APIENTRY glCopyMultiTexSubImage2DEXT (GLenum, GLenum, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei); GLAPI void APIENTRY glGetMultiTexImageEXT (GLenum, GLenum, GLint, GLenum, GLenum, GLvoid *); GLAPI void APIENTRY glGetMultiTexParameterfvEXT (GLenum, GLenum, GLenum, GLfloat *); GLAPI void APIENTRY glGetMultiTexParameterivEXT (GLenum, GLenum, GLenum, GLint *); GLAPI void APIENTRY glGetMultiTexLevelParameterfvEXT (GLenum, GLenum, GLint, GLenum, GLfloat *); GLAPI void APIENTRY glGetMultiTexLevelParameterivEXT (GLenum, GLenum, GLint, GLenum, GLint *); GLAPI void APIENTRY glMultiTexImage3DEXT (GLenum, GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid *); GLAPI void APIENTRY glMultiTexSubImage3DEXT (GLenum, GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *); GLAPI void APIENTRY glCopyMultiTexSubImage3DEXT (GLenum, GLenum, GLint, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei); GLAPI void APIENTRY glBindMultiTextureEXT (GLenum, GLenum, GLuint); GLAPI void APIENTRY glEnableClientStateIndexedEXT (GLenum, GLuint); GLAPI void APIENTRY glDisableClientStateIndexedEXT (GLenum, GLuint); GLAPI void APIENTRY glMultiTexCoordPointerEXT (GLenum, GLint, GLenum, GLsizei, const GLvoid *); GLAPI void APIENTRY glMultiTexEnvfEXT (GLenum, GLenum, GLenum, GLfloat); GLAPI void APIENTRY glMultiTexEnvfvEXT (GLenum, GLenum, GLenum, const GLfloat *); GLAPI void APIENTRY glMultiTexEnviEXT (GLenum, GLenum, GLenum, GLint); GLAPI void APIENTRY glMultiTexEnvivEXT (GLenum, GLenum, GLenum, const GLint *); GLAPI void APIENTRY glMultiTexGendEXT (GLenum, GLenum, GLenum, GLdouble); GLAPI void APIENTRY glMultiTexGendvEXT (GLenum, GLenum, GLenum, const GLdouble *); GLAPI void APIENTRY glMultiTexGenfEXT (GLenum, GLenum, GLenum, GLfloat); GLAPI void APIENTRY glMultiTexGenfvEXT (GLenum, GLenum, GLenum, const GLfloat *); GLAPI void APIENTRY glMultiTexGeniEXT (GLenum, GLenum, GLenum, GLint); GLAPI void APIENTRY glMultiTexGenivEXT (GLenum, GLenum, GLenum, const GLint *); GLAPI void APIENTRY glGetMultiTexEnvfvEXT (GLenum, GLenum, GLenum, GLfloat *); GLAPI void APIENTRY glGetMultiTexEnvivEXT (GLenum, GLenum, GLenum, GLint *); GLAPI void APIENTRY glGetMultiTexGendvEXT (GLenum, GLenum, GLenum, GLdouble *); GLAPI void APIENTRY glGetMultiTexGenfvEXT (GLenum, GLenum, GLenum, GLfloat *); GLAPI void APIENTRY glGetMultiTexGenivEXT (GLenum, GLenum, GLenum, GLint *); GLAPI void APIENTRY glGetFloatIndexedvEXT (GLenum, GLuint, GLfloat *); GLAPI void APIENTRY glGetDoubleIndexedvEXT (GLenum, GLuint, GLdouble *); GLAPI void APIENTRY glGetPointerIndexedvEXT (GLenum, GLuint, GLvoid* *); GLAPI void APIENTRY glCompressedTextureImage3DEXT (GLuint, GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLint, GLsizei, const GLvoid *); GLAPI void APIENTRY glCompressedTextureImage2DEXT (GLuint, GLenum, GLint, GLenum, GLsizei, GLsizei, GLint, GLsizei, const GLvoid *); GLAPI void APIENTRY glCompressedTextureImage1DEXT (GLuint, GLenum, GLint, GLenum, GLsizei, GLint, GLsizei, const GLvoid *); GLAPI void APIENTRY glCompressedTextureSubImage3DEXT (GLuint, GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid *); GLAPI void APIENTRY glCompressedTextureSubImage2DEXT (GLuint, GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid *); GLAPI void APIENTRY glCompressedTextureSubImage1DEXT (GLuint, GLenum, GLint, GLint, GLsizei, GLenum, GLsizei, const GLvoid *); GLAPI void APIENTRY glGetCompressedTextureImageEXT (GLuint, GLenum, GLint, GLvoid *); GLAPI void APIENTRY glCompressedMultiTexImage3DEXT (GLenum, GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLint, GLsizei, const GLvoid *); GLAPI void APIENTRY glCompressedMultiTexImage2DEXT (GLenum, GLenum, GLint, GLenum, GLsizei, GLsizei, GLint, GLsizei, const GLvoid *); GLAPI void APIENTRY glCompressedMultiTexImage1DEXT (GLenum, GLenum, GLint, GLenum, GLsizei, GLint, GLsizei, const GLvoid *); GLAPI void APIENTRY glCompressedMultiTexSubImage3DEXT (GLenum, GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid *); GLAPI void APIENTRY glCompressedMultiTexSubImage2DEXT (GLenum, GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid *); GLAPI void APIENTRY glCompressedMultiTexSubImage1DEXT (GLenum, GLenum, GLint, GLint, GLsizei, GLenum, GLsizei, const GLvoid *); GLAPI void APIENTRY glGetCompressedMultiTexImageEXT (GLenum, GLenum, GLint, GLvoid *); GLAPI void APIENTRY glNamedProgramStringEXT (GLuint, GLenum, GLenum, GLsizei, const GLvoid *); GLAPI void APIENTRY glNamedProgramLocalParameter4dEXT (GLuint, GLenum, GLuint, GLdouble, GLdouble, GLdouble, GLdouble); GLAPI void APIENTRY glNamedProgramLocalParameter4dvEXT (GLuint, GLenum, GLuint, const GLdouble *); GLAPI void APIENTRY glNamedProgramLocalParameter4fEXT (GLuint, GLenum, GLuint, GLfloat, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glNamedProgramLocalParameter4fvEXT (GLuint, GLenum, GLuint, const GLfloat *); GLAPI void APIENTRY glGetNamedProgramLocalParameterdvEXT (GLuint, GLenum, GLuint, GLdouble *); GLAPI void APIENTRY glGetNamedProgramLocalParameterfvEXT (GLuint, GLenum, GLuint, GLfloat *); GLAPI void APIENTRY glGetNamedProgramivEXT (GLuint, GLenum, GLenum, GLint *); GLAPI void APIENTRY glGetNamedProgramStringEXT (GLuint, GLenum, GLenum, GLvoid *); GLAPI void APIENTRY glNamedProgramLocalParameters4fvEXT (GLuint, GLenum, GLuint, GLsizei, const GLfloat *); GLAPI void APIENTRY glNamedProgramLocalParameterI4iEXT (GLuint, GLenum, GLuint, GLint, GLint, GLint, GLint); GLAPI void APIENTRY glNamedProgramLocalParameterI4ivEXT (GLuint, GLenum, GLuint, const GLint *); GLAPI void APIENTRY glNamedProgramLocalParametersI4ivEXT (GLuint, GLenum, GLuint, GLsizei, const GLint *); GLAPI void APIENTRY glNamedProgramLocalParameterI4uiEXT (GLuint, GLenum, GLuint, GLuint, GLuint, GLuint, GLuint); GLAPI void APIENTRY glNamedProgramLocalParameterI4uivEXT (GLuint, GLenum, GLuint, const GLuint *); GLAPI void APIENTRY glNamedProgramLocalParametersI4uivEXT (GLuint, GLenum, GLuint, GLsizei, const GLuint *); GLAPI void APIENTRY glGetNamedProgramLocalParameterIivEXT (GLuint, GLenum, GLuint, GLint *); GLAPI void APIENTRY glGetNamedProgramLocalParameterIuivEXT (GLuint, GLenum, GLuint, GLuint *); GLAPI void APIENTRY glTextureParameterIivEXT (GLuint, GLenum, GLenum, const GLint *); GLAPI void APIENTRY glTextureParameterIuivEXT (GLuint, GLenum, GLenum, const GLuint *); GLAPI void APIENTRY glGetTextureParameterIivEXT (GLuint, GLenum, GLenum, GLint *); GLAPI void APIENTRY glGetTextureParameterIuivEXT (GLuint, GLenum, GLenum, GLuint *); GLAPI void APIENTRY glMultiTexParameterIivEXT (GLenum, GLenum, GLenum, const GLint *); GLAPI void APIENTRY glMultiTexParameterIuivEXT (GLenum, GLenum, GLenum, const GLuint *); GLAPI void APIENTRY glGetMultiTexParameterIivEXT (GLenum, GLenum, GLenum, GLint *); GLAPI void APIENTRY glGetMultiTexParameterIuivEXT (GLenum, GLenum, GLenum, GLuint *); GLAPI void APIENTRY glProgramUniform1fEXT (GLuint, GLint, GLfloat); GLAPI void APIENTRY glProgramUniform2fEXT (GLuint, GLint, GLfloat, GLfloat); GLAPI void APIENTRY glProgramUniform3fEXT (GLuint, GLint, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glProgramUniform4fEXT (GLuint, GLint, GLfloat, GLfloat, GLfloat, GLfloat); GLAPI void APIENTRY glProgramUniform1iEXT (GLuint, GLint, GLint); GLAPI void APIENTRY glProgramUniform2iEXT (GLuint, GLint, GLint, GLint); GLAPI void APIENTRY glProgramUniform3iEXT (GLuint, GLint, GLint, GLint, GLint); GLAPI void APIENTRY glProgramUniform4iEXT (GLuint, GLint, GLint, GLint, GLint, GLint); GLAPI void APIENTRY glProgramUniform1fvEXT (GLuint, GLint, GLsizei, const GLfloat *); GLAPI void APIENTRY glProgramUniform2fvEXT (GLuint, GLint, GLsizei, const GLfloat *); GLAPI void APIENTRY glProgramUniform3fvEXT (GLuint, GLint, GLsizei, const GLfloat *); GLAPI void APIENTRY glProgramUniform4fvEXT (GLuint, GLint, GLsizei, const GLfloat *); GLAPI void APIENTRY glProgramUniform1ivEXT (GLuint, GLint, GLsizei, const GLint *); GLAPI void APIENTRY glProgramUniform2ivEXT (GLuint, GLint, GLsizei, const GLint *); GLAPI void APIENTRY glProgramUniform3ivEXT (GLuint, GLint, GLsizei, const GLint *); GLAPI void APIENTRY glProgramUniform4ivEXT (GLuint, GLint, GLsizei, const GLint *); GLAPI void APIENTRY glProgramUniformMatrix2fvEXT (GLuint, GLint, GLsizei, GLboolean, const GLfloat *); GLAPI void APIENTRY glProgramUniformMatrix3fvEXT (GLuint, GLint, GLsizei, GLboolean, const GLfloat *); GLAPI void APIENTRY glProgramUniformMatrix4fvEXT (GLuint, GLint, GLsizei, GLboolean, const GLfloat *); GLAPI void APIENTRY glProgramUniformMatrix2x3fvEXT (GLuint, GLint, GLsizei, GLboolean, const GLfloat *); GLAPI void APIENTRY glProgramUniformMatrix3x2fvEXT (GLuint, GLint, GLsizei, GLboolean, const GLfloat *); GLAPI void APIENTRY glProgramUniformMatrix2x4fvEXT (GLuint, GLint, GLsizei, GLboolean, const GLfloat *); GLAPI void APIENTRY glProgramUniformMatrix4x2fvEXT (GLuint, GLint, GLsizei, GLboolean, const GLfloat *); GLAPI void APIENTRY glProgramUniformMatrix3x4fvEXT (GLuint, GLint, GLsizei, GLboolean, const GLfloat *); GLAPI void APIENTRY glProgramUniformMatrix4x3fvEXT (GLuint, GLint, GLsizei, GLboolean, const GLfloat *); GLAPI void APIENTRY glProgramUniform1uiEXT (GLuint, GLint, GLuint); GLAPI void APIENTRY glProgramUniform2uiEXT (GLuint, GLint, GLuint, GLuint); GLAPI void APIENTRY glProgramUniform3uiEXT (GLuint, GLint, GLuint, GLuint, GLuint); GLAPI void APIENTRY glProgramUniform4uiEXT (GLuint, GLint, GLuint, GLuint, GLuint, GLuint); GLAPI void APIENTRY glProgramUniform1uivEXT (GLuint, GLint, GLsizei, const GLuint *); GLAPI void APIENTRY glProgramUniform2uivEXT (GLuint, GLint, GLsizei, const GLuint *); GLAPI void APIENTRY glProgramUniform3uivEXT (GLuint, GLint, GLsizei, const GLuint *); GLAPI void APIENTRY glProgramUniform4uivEXT (GLuint, GLint, GLsizei, const GLuint *); GLAPI void APIENTRY glNamedBufferDataEXT (GLuint, GLsizeiptr, const GLvoid *, GLenum); GLAPI void APIENTRY glNamedBufferSubDataEXT (GLuint, GLintptr, GLsizeiptr, const GLvoid *); GLAPI GLvoid* APIENTRY glMapNamedBufferEXT (GLuint, GLenum); GLAPI GLboolean APIENTRY glUnmapNamedBufferEXT (GLuint); GLAPI void APIENTRY glGetNamedBufferParameterivEXT (GLuint, GLenum, GLint *); GLAPI void APIENTRY glGetNamedBufferPointervEXT (GLuint, GLenum, GLvoid* *); GLAPI void APIENTRY glGetNamedBufferSubDataEXT (GLuint, GLintptr, GLsizeiptr, GLvoid *); GLAPI void APIENTRY glTextureBufferEXT (GLuint, GLenum, GLenum, GLuint); GLAPI void APIENTRY glMultiTexBufferEXT (GLenum, GLenum, GLenum, GLuint); GLAPI void APIENTRY glNamedRenderbufferStorageEXT (GLuint, GLenum, GLsizei, GLsizei); GLAPI void APIENTRY glGetNamedRenderbufferParameterivEXT (GLuint, GLenum, GLint *); GLAPI GLenum APIENTRY glCheckNamedFramebufferStatusEXT (GLuint, GLenum); GLAPI void APIENTRY glNamedFramebufferTexture1DEXT (GLuint, GLenum, GLenum, GLuint, GLint); GLAPI void APIENTRY glNamedFramebufferTexture2DEXT (GLuint, GLenum, GLenum, GLuint, GLint); GLAPI void APIENTRY glNamedFramebufferTexture3DEXT (GLuint, GLenum, GLenum, GLuint, GLint, GLint); GLAPI void APIENTRY glNamedFramebufferRenderbufferEXT (GLuint, GLenum, GLenum, GLuint); GLAPI void APIENTRY glGetNamedFramebufferAttachmentParameterivEXT (GLuint, GLenum, GLenum, GLint *); GLAPI void APIENTRY glGenerateTextureMipmapEXT (GLuint, GLenum); GLAPI void APIENTRY glGenerateMultiTexMipmapEXT (GLenum, GLenum); GLAPI void APIENTRY glFramebufferDrawBufferEXT (GLuint, GLenum); GLAPI void APIENTRY glFramebufferDrawBuffersEXT (GLuint, GLsizei, const GLenum *); GLAPI void APIENTRY glFramebufferReadBufferEXT (GLuint, GLenum); GLAPI void APIENTRY glGetFramebufferParameterivEXT (GLuint, GLenum, GLint *); GLAPI void APIENTRY glNamedRenderbufferStorageMultisampleEXT (GLuint, GLsizei, GLenum, GLsizei, GLsizei); GLAPI void APIENTRY glNamedRenderbufferStorageMultisampleCoverageEXT (GLuint, GLsizei, GLsizei, GLenum, GLsizei, GLsizei); GLAPI void APIENTRY glNamedFramebufferTextureEXT (GLuint, GLenum, GLuint, GLint); GLAPI void APIENTRY glNamedFramebufferTextureLayerEXT (GLuint, GLenum, GLuint, GLint, GLint); GLAPI void APIENTRY glNamedFramebufferTextureFaceEXT (GLuint, GLenum, GLuint, GLint, GLenum); GLAPI void APIENTRY glTextureRenderbufferEXT (GLuint, GLenum, GLuint); GLAPI void APIENTRY glMultiTexRenderbufferEXT (GLenum, GLenum, GLuint); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLCLIENTATTRIBDEFAULTEXTPROC) (GLbitfield mask); typedef void (APIENTRYP PFNGLPUSHCLIENTATTRIBDEFAULTEXTPROC) (GLbitfield mask); typedef void (APIENTRYP PFNGLMATRIXLOADFEXTPROC) (GLenum mode, const GLfloat *m); typedef void (APIENTRYP PFNGLMATRIXLOADDEXTPROC) (GLenum mode, const GLdouble *m); typedef void (APIENTRYP PFNGLMATRIXMULTFEXTPROC) (GLenum mode, const GLfloat *m); typedef void (APIENTRYP PFNGLMATRIXMULTDEXTPROC) (GLenum mode, const GLdouble *m); typedef void (APIENTRYP PFNGLMATRIXLOADIDENTITYEXTPROC) (GLenum mode); typedef void (APIENTRYP PFNGLMATRIXROTATEFEXTPROC) (GLenum mode, GLfloat angle, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLMATRIXROTATEDEXTPROC) (GLenum mode, GLdouble angle, GLdouble x, GLdouble y, GLdouble z); typedef void (APIENTRYP PFNGLMATRIXSCALEFEXTPROC) (GLenum mode, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLMATRIXSCALEDEXTPROC) (GLenum mode, GLdouble x, GLdouble y, GLdouble z); typedef void (APIENTRYP PFNGLMATRIXTRANSLATEFEXTPROC) (GLenum mode, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLMATRIXTRANSLATEDEXTPROC) (GLenum mode, GLdouble x, GLdouble y, GLdouble z); typedef void (APIENTRYP PFNGLMATRIXFRUSTUMEXTPROC) (GLenum mode, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); typedef void (APIENTRYP PFNGLMATRIXORTHOEXTPROC) (GLenum mode, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); typedef void (APIENTRYP PFNGLMATRIXPOPEXTPROC) (GLenum mode); typedef void (APIENTRYP PFNGLMATRIXPUSHEXTPROC) (GLenum mode); typedef void (APIENTRYP PFNGLMATRIXLOADTRANSPOSEFEXTPROC) (GLenum mode, const GLfloat *m); typedef void (APIENTRYP PFNGLMATRIXLOADTRANSPOSEDEXTPROC) (GLenum mode, const GLdouble *m); typedef void (APIENTRYP PFNGLMATRIXMULTTRANSPOSEFEXTPROC) (GLenum mode, const GLfloat *m); typedef void (APIENTRYP PFNGLMATRIXMULTTRANSPOSEDEXTPROC) (GLenum mode, const GLdouble *m); typedef void (APIENTRYP PFNGLTEXTUREPARAMETERFEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLTEXTUREPARAMETERFVEXTPROC) (GLuint texture, GLenum target, GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLint param); typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLTEXTUREIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels); typedef void (APIENTRYP PFNGLTEXTUREIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); typedef void (APIENTRYP PFNGLTEXTURESUBIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); typedef void (APIENTRYP PFNGLTEXTURESUBIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); typedef void (APIENTRYP PFNGLCOPYTEXTUREIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); typedef void (APIENTRYP PFNGLCOPYTEXTUREIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); typedef void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); typedef void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); typedef void (APIENTRYP PFNGLGETTEXTUREIMAGEEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels); typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERFVEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETTEXTURELEVELPARAMETERFVEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETTEXTURELEVELPARAMETERIVEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLTEXTUREIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); typedef void (APIENTRYP PFNGLTEXTURESUBIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels); typedef void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); typedef void (APIENTRYP PFNGLMULTITEXPARAMETERFEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLMULTITEXPARAMETERFVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLMULTITEXPARAMETERIEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint param); typedef void (APIENTRYP PFNGLMULTITEXPARAMETERIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLMULTITEXIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels); typedef void (APIENTRYP PFNGLMULTITEXIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); typedef void (APIENTRYP PFNGLMULTITEXSUBIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); typedef void (APIENTRYP PFNGLMULTITEXSUBIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); typedef void (APIENTRYP PFNGLCOPYMULTITEXIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); typedef void (APIENTRYP PFNGLCOPYMULTITEXIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); typedef void (APIENTRYP PFNGLCOPYMULTITEXSUBIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); typedef void (APIENTRYP PFNGLCOPYMULTITEXSUBIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); typedef void (APIENTRYP PFNGLGETMULTITEXIMAGEEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels); typedef void (APIENTRYP PFNGLGETMULTITEXPARAMETERFVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETMULTITEXPARAMETERIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETMULTITEXLEVELPARAMETERFVEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETMULTITEXLEVELPARAMETERIVEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLMULTITEXIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); typedef void (APIENTRYP PFNGLMULTITEXSUBIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels); typedef void (APIENTRYP PFNGLCOPYMULTITEXSUBIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); typedef void (APIENTRYP PFNGLBINDMULTITEXTUREEXTPROC) (GLenum texunit, GLenum target, GLuint texture); typedef void (APIENTRYP PFNGLENABLECLIENTSTATEINDEXEDEXTPROC) (GLenum array, GLuint index); typedef void (APIENTRYP PFNGLDISABLECLIENTSTATEINDEXEDEXTPROC) (GLenum array, GLuint index); typedef void (APIENTRYP PFNGLMULTITEXCOORDPOINTEREXTPROC) (GLenum texunit, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); typedef void (APIENTRYP PFNGLMULTITEXENVFEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLMULTITEXENVFVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLMULTITEXENVIEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint param); typedef void (APIENTRYP PFNGLMULTITEXENVIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLMULTITEXGENDEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLdouble param); typedef void (APIENTRYP PFNGLMULTITEXGENDVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, const GLdouble *params); typedef void (APIENTRYP PFNGLMULTITEXGENFEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLMULTITEXGENFVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLMULTITEXGENIEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLint param); typedef void (APIENTRYP PFNGLMULTITEXGENIVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLGETMULTITEXENVFVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETMULTITEXENVIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETMULTITEXGENDVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLdouble *params); typedef void (APIENTRYP PFNGLGETMULTITEXGENFVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETMULTITEXGENIVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETFLOATINDEXEDVEXTPROC) (GLenum target, GLuint index, GLfloat *data); typedef void (APIENTRYP PFNGLGETDOUBLEINDEXEDVEXTPROC) (GLenum target, GLuint index, GLdouble *data); typedef void (APIENTRYP PFNGLGETPOINTERINDEXEDVEXTPROC) (GLenum target, GLuint index, GLvoid* *data); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTUREIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *bits); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTUREIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *bits); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTUREIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *bits); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *bits); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *bits); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *bits); typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXTUREIMAGEEXTPROC) (GLuint texture, GLenum target, GLint lod, GLvoid *img); typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *bits); typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *bits); typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *bits); typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXSUBIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *bits); typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXSUBIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *bits); typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXSUBIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *bits); typedef void (APIENTRYP PFNGLGETCOMPRESSEDMULTITEXIMAGEEXTPROC) (GLenum texunit, GLenum target, GLint lod, GLvoid *img); typedef void (APIENTRYP PFNGLNAMEDPROGRAMSTRINGEXTPROC) (GLuint program, GLenum target, GLenum format, GLsizei len, const GLvoid *string); typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETER4DEXTPROC) (GLuint program, GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETER4DVEXTPROC) (GLuint program, GLenum target, GLuint index, const GLdouble *params); typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETER4FEXTPROC) (GLuint program, GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETER4FVEXTPROC) (GLuint program, GLenum target, GLuint index, const GLfloat *params); typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMLOCALPARAMETERDVEXTPROC) (GLuint program, GLenum target, GLuint index, GLdouble *params); typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMLOCALPARAMETERFVEXTPROC) (GLuint program, GLenum target, GLuint index, GLfloat *params); typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMIVEXTPROC) (GLuint program, GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMSTRINGEXTPROC) (GLuint program, GLenum target, GLenum pname, GLvoid *string); typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERS4FVEXTPROC) (GLuint program, GLenum target, GLuint index, GLsizei count, const GLfloat *params); typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERI4IEXTPROC) (GLuint program, GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w); typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERI4IVEXTPROC) (GLuint program, GLenum target, GLuint index, const GLint *params); typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERSI4IVEXTPROC) (GLuint program, GLenum target, GLuint index, GLsizei count, const GLint *params); typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERI4UIEXTPROC) (GLuint program, GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERI4UIVEXTPROC) (GLuint program, GLenum target, GLuint index, const GLuint *params); typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERSI4UIVEXTPROC) (GLuint program, GLenum target, GLuint index, GLsizei count, const GLuint *params); typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMLOCALPARAMETERIIVEXTPROC) (GLuint program, GLenum target, GLuint index, GLint *params); typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMLOCALPARAMETERIUIVEXTPROC) (GLuint program, GLenum target, GLuint index, GLuint *params); typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIUIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, const GLuint *params); typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERIIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERIUIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLuint *params); typedef void (APIENTRYP PFNGLMULTITEXPARAMETERIIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLMULTITEXPARAMETERIUIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLuint *params); typedef void (APIENTRYP PFNGLGETMULTITEXPARAMETERIIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETMULTITEXPARAMETERIUIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLuint *params); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FEXTPROC) (GLuint program, GLint location, GLfloat v0); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IEXTPROC) (GLuint program, GLint location, GLint v0); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIEXTPROC) (GLuint program, GLint location, GLuint v0); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); typedef void (APIENTRYP PFNGLNAMEDBUFFERDATAEXTPROC) (GLuint buffer, GLsizeiptr size, const GLvoid *data, GLenum usage); typedef void (APIENTRYP PFNGLNAMEDBUFFERSUBDATAEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, const GLvoid *data); typedef GLvoid* (APIENTRYP PFNGLMAPNAMEDBUFFEREXTPROC) (GLuint buffer, GLenum access); typedef GLboolean (APIENTRYP PFNGLUNMAPNAMEDBUFFEREXTPROC) (GLuint buffer); typedef void (APIENTRYP PFNGLGETNAMEDBUFFERPARAMETERIVEXTPROC) (GLuint buffer, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETNAMEDBUFFERPOINTERVEXTPROC) (GLuint buffer, GLenum pname, GLvoid* *params); typedef void (APIENTRYP PFNGLGETNAMEDBUFFERSUBDATAEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, GLvoid *data); typedef void (APIENTRYP PFNGLTEXTUREBUFFEREXTPROC) (GLuint texture, GLenum target, GLenum internalformat, GLuint buffer); typedef void (APIENTRYP PFNGLMULTITEXBUFFEREXTPROC) (GLenum texunit, GLenum target, GLenum internalformat, GLuint buffer); typedef void (APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEEXTPROC) (GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height); typedef void (APIENTRYP PFNGLGETNAMEDRENDERBUFFERPARAMETERIVEXTPROC) (GLuint renderbuffer, GLenum pname, GLint *params); typedef GLenum (APIENTRYP PFNGLCHECKNAMEDFRAMEBUFFERSTATUSEXTPROC) (GLuint framebuffer, GLenum target); typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURE1DEXTPROC) (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level); typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURE2DEXTPROC) (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level); typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURE3DEXTPROC) (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERRENDERBUFFEREXTPROC) (GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); typedef void (APIENTRYP PFNGLGETNAMEDFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC) (GLuint framebuffer, GLenum attachment, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGENERATETEXTUREMIPMAPEXTPROC) (GLuint texture, GLenum target); typedef void (APIENTRYP PFNGLGENERATEMULTITEXMIPMAPEXTPROC) (GLenum texunit, GLenum target); typedef void (APIENTRYP PFNGLFRAMEBUFFERDRAWBUFFEREXTPROC) (GLuint framebuffer, GLenum mode); typedef void (APIENTRYP PFNGLFRAMEBUFFERDRAWBUFFERSEXTPROC) (GLuint framebuffer, GLsizei n, const GLenum *bufs); typedef void (APIENTRYP PFNGLFRAMEBUFFERREADBUFFEREXTPROC) (GLuint framebuffer, GLenum mode); typedef void (APIENTRYP PFNGLGETFRAMEBUFFERPARAMETERIVEXTPROC) (GLuint framebuffer, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) (GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); typedef void (APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLECOVERAGEEXTPROC) (GLuint renderbuffer, GLsizei coverageSamples, GLsizei colorSamples, GLenum internalformat, GLsizei width, GLsizei height); typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTUREEXTPROC) (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level); typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURELAYEREXTPROC) (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLint layer); typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTUREFACEEXTPROC) (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLenum face); typedef void (APIENTRYP PFNGLTEXTURERENDERBUFFEREXTPROC) (GLuint texture, GLenum target, GLuint renderbuffer); typedef void (APIENTRYP PFNGLMULTITEXRENDERBUFFEREXTPROC) (GLenum texunit, GLenum target, GLuint renderbuffer); #endif #ifndef GL_EXT_vertex_array_bgra #define GL_EXT_vertex_array_bgra 1 #endif #ifndef GL_EXT_texture_swizzle #define GL_EXT_texture_swizzle 1 #endif #ifndef GL_NV_explicit_multisample #define GL_NV_explicit_multisample 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glGetMultisamplefvNV (GLenum, GLuint, GLfloat *); GLAPI void APIENTRY glSampleMaskIndexedNV (GLuint, GLbitfield); GLAPI void APIENTRY glTexRenderbufferNV (GLenum, GLuint); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLGETMULTISAMPLEFVNVPROC) (GLenum pname, GLuint index, GLfloat *val); typedef void (APIENTRYP PFNGLSAMPLEMASKINDEXEDNVPROC) (GLuint index, GLbitfield mask); typedef void (APIENTRYP PFNGLTEXRENDERBUFFERNVPROC) (GLenum target, GLuint renderbuffer); #endif #ifndef GL_NV_transform_feedback2 #define GL_NV_transform_feedback2 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBindTransformFeedbackNV (GLenum, GLuint); GLAPI void APIENTRY glDeleteTransformFeedbacksNV (GLsizei, const GLuint *); GLAPI void APIENTRY glGenTransformFeedbacksNV (GLsizei, GLuint *); GLAPI GLboolean APIENTRY glIsTransformFeedbackNV (GLuint); GLAPI void APIENTRY glPauseTransformFeedbackNV (void); GLAPI void APIENTRY glResumeTransformFeedbackNV (void); GLAPI void APIENTRY glDrawTransformFeedbackNV (GLenum, GLuint); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLBINDTRANSFORMFEEDBACKNVPROC) (GLenum target, GLuint id); typedef void (APIENTRYP PFNGLDELETETRANSFORMFEEDBACKSNVPROC) (GLsizei n, const GLuint *ids); typedef void (APIENTRYP PFNGLGENTRANSFORMFEEDBACKSNVPROC) (GLsizei n, GLuint *ids); typedef GLboolean (APIENTRYP PFNGLISTRANSFORMFEEDBACKNVPROC) (GLuint id); typedef void (APIENTRYP PFNGLPAUSETRANSFORMFEEDBACKNVPROC) (void); typedef void (APIENTRYP PFNGLRESUMETRANSFORMFEEDBACKNVPROC) (void); typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKNVPROC) (GLenum mode, GLuint id); #endif #ifdef __cplusplus } #endif #endif ================================================ FILE: ng/Togl2.1/gl/glxext.h ================================================ #ifndef __glxext_h_ #define __glxext_h_ #ifdef __cplusplus extern "C" { #endif /* ** Copyright (c) 2007 The Khronos Group Inc. ** ** Permission is hereby granted, free of charge, to any person obtaining a ** copy of this software and/or associated documentation files (the ** "Materials"), to deal in the Materials without restriction, including ** without limitation the rights to use, copy, modify, merge, publish, ** distribute, sublicense, and/or sell copies of the Materials, and to ** permit persons to whom the Materials are furnished to do so, subject to ** the following conditions: ** ** The above copyright notice and this permission notice shall be included ** in all copies or substantial portions of the Materials. ** ** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, ** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE ** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. */ #if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) #define WIN32_LEAN_AND_MEAN 1 #include #endif #ifndef APIENTRY #define APIENTRY #endif #ifndef APIENTRYP #define APIENTRYP APIENTRY * #endif #ifndef GLAPI #define GLAPI extern #endif /*************************************************************/ /* Header file version number, required by OpenGL ABI for Linux */ /* glxext.h last updated 2008/10/22 */ /* Current version at http://www.opengl.org/registry/ */ #define GLX_GLXEXT_VERSION 21 #ifndef GLX_VERSION_1_3 #define GLX_WINDOW_BIT 0x00000001 #define GLX_PIXMAP_BIT 0x00000002 #define GLX_PBUFFER_BIT 0x00000004 #define GLX_RGBA_BIT 0x00000001 #define GLX_COLOR_INDEX_BIT 0x00000002 #define GLX_PBUFFER_CLOBBER_MASK 0x08000000 #define GLX_FRONT_LEFT_BUFFER_BIT 0x00000001 #define GLX_FRONT_RIGHT_BUFFER_BIT 0x00000002 #define GLX_BACK_LEFT_BUFFER_BIT 0x00000004 #define GLX_BACK_RIGHT_BUFFER_BIT 0x00000008 #define GLX_AUX_BUFFERS_BIT 0x00000010 #define GLX_DEPTH_BUFFER_BIT 0x00000020 #define GLX_STENCIL_BUFFER_BIT 0x00000040 #define GLX_ACCUM_BUFFER_BIT 0x00000080 #define GLX_CONFIG_CAVEAT 0x20 #define GLX_X_VISUAL_TYPE 0x22 #define GLX_TRANSPARENT_TYPE 0x23 #define GLX_TRANSPARENT_INDEX_VALUE 0x24 #define GLX_TRANSPARENT_RED_VALUE 0x25 #define GLX_TRANSPARENT_GREEN_VALUE 0x26 #define GLX_TRANSPARENT_BLUE_VALUE 0x27 #define GLX_TRANSPARENT_ALPHA_VALUE 0x28 #define GLX_DONT_CARE 0xFFFFFFFF #define GLX_NONE 0x8000 #define GLX_SLOW_CONFIG 0x8001 #define GLX_TRUE_COLOR 0x8002 #define GLX_DIRECT_COLOR 0x8003 #define GLX_PSEUDO_COLOR 0x8004 #define GLX_STATIC_COLOR 0x8005 #define GLX_GRAY_SCALE 0x8006 #define GLX_STATIC_GRAY 0x8007 #define GLX_TRANSPARENT_RGB 0x8008 #define GLX_TRANSPARENT_INDEX 0x8009 #define GLX_VISUAL_ID 0x800B #define GLX_SCREEN 0x800C #define GLX_NON_CONFORMANT_CONFIG 0x800D #define GLX_DRAWABLE_TYPE 0x8010 #define GLX_RENDER_TYPE 0x8011 #define GLX_X_RENDERABLE 0x8012 #define GLX_FBCONFIG_ID 0x8013 #define GLX_RGBA_TYPE 0x8014 #define GLX_COLOR_INDEX_TYPE 0x8015 #define GLX_MAX_PBUFFER_WIDTH 0x8016 #define GLX_MAX_PBUFFER_HEIGHT 0x8017 #define GLX_MAX_PBUFFER_PIXELS 0x8018 #define GLX_PRESERVED_CONTENTS 0x801B #define GLX_LARGEST_PBUFFER 0x801C #define GLX_WIDTH 0x801D #define GLX_HEIGHT 0x801E #define GLX_EVENT_MASK 0x801F #define GLX_DAMAGED 0x8020 #define GLX_SAVED 0x8021 #define GLX_WINDOW 0x8022 #define GLX_PBUFFER 0x8023 #define GLX_PBUFFER_HEIGHT 0x8040 #define GLX_PBUFFER_WIDTH 0x8041 #endif #ifndef GLX_VERSION_1_4 #define GLX_SAMPLE_BUFFERS 100000 #define GLX_SAMPLES 100001 #endif #ifndef GLX_ARB_get_proc_address #endif #ifndef GLX_ARB_multisample #define GLX_SAMPLE_BUFFERS_ARB 100000 #define GLX_SAMPLES_ARB 100001 #endif #ifndef GLX_ARB_fbconfig_float #define GLX_RGBA_FLOAT_TYPE_ARB 0x20B9 #define GLX_RGBA_FLOAT_BIT_ARB 0x00000004 #endif #ifndef GLX_ARB_create_context #define GLX_CONTEXT_DEBUG_BIT_ARB 0x00000001 #define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002 #define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091 #define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092 #define GLX_CONTEXT_FLAGS_ARB 0x2094 #endif #ifndef GLX_SGIS_multisample #define GLX_SAMPLE_BUFFERS_SGIS 100000 #define GLX_SAMPLES_SGIS 100001 #endif #ifndef GLX_EXT_visual_info #define GLX_X_VISUAL_TYPE_EXT 0x22 #define GLX_TRANSPARENT_TYPE_EXT 0x23 #define GLX_TRANSPARENT_INDEX_VALUE_EXT 0x24 #define GLX_TRANSPARENT_RED_VALUE_EXT 0x25 #define GLX_TRANSPARENT_GREEN_VALUE_EXT 0x26 #define GLX_TRANSPARENT_BLUE_VALUE_EXT 0x27 #define GLX_TRANSPARENT_ALPHA_VALUE_EXT 0x28 #define GLX_NONE_EXT 0x8000 #define GLX_TRUE_COLOR_EXT 0x8002 #define GLX_DIRECT_COLOR_EXT 0x8003 #define GLX_PSEUDO_COLOR_EXT 0x8004 #define GLX_STATIC_COLOR_EXT 0x8005 #define GLX_GRAY_SCALE_EXT 0x8006 #define GLX_STATIC_GRAY_EXT 0x8007 #define GLX_TRANSPARENT_RGB_EXT 0x8008 #define GLX_TRANSPARENT_INDEX_EXT 0x8009 #endif #ifndef GLX_SGI_swap_control #endif #ifndef GLX_SGI_video_sync #endif #ifndef GLX_SGI_make_current_read #endif #ifndef GLX_SGIX_video_source #endif #ifndef GLX_EXT_visual_rating #define GLX_VISUAL_CAVEAT_EXT 0x20 #define GLX_SLOW_VISUAL_EXT 0x8001 #define GLX_NON_CONFORMANT_VISUAL_EXT 0x800D /* reuse GLX_NONE_EXT */ #endif #ifndef GLX_EXT_import_context #define GLX_SHARE_CONTEXT_EXT 0x800A #define GLX_VISUAL_ID_EXT 0x800B #define GLX_SCREEN_EXT 0x800C #endif #ifndef GLX_SGIX_fbconfig #define GLX_WINDOW_BIT_SGIX 0x00000001 #define GLX_PIXMAP_BIT_SGIX 0x00000002 #define GLX_RGBA_BIT_SGIX 0x00000001 #define GLX_COLOR_INDEX_BIT_SGIX 0x00000002 #define GLX_DRAWABLE_TYPE_SGIX 0x8010 #define GLX_RENDER_TYPE_SGIX 0x8011 #define GLX_X_RENDERABLE_SGIX 0x8012 #define GLX_FBCONFIG_ID_SGIX 0x8013 #define GLX_RGBA_TYPE_SGIX 0x8014 #define GLX_COLOR_INDEX_TYPE_SGIX 0x8015 /* reuse GLX_SCREEN_EXT */ #endif #ifndef GLX_SGIX_pbuffer #define GLX_PBUFFER_BIT_SGIX 0x00000004 #define GLX_BUFFER_CLOBBER_MASK_SGIX 0x08000000 #define GLX_FRONT_LEFT_BUFFER_BIT_SGIX 0x00000001 #define GLX_FRONT_RIGHT_BUFFER_BIT_SGIX 0x00000002 #define GLX_BACK_LEFT_BUFFER_BIT_SGIX 0x00000004 #define GLX_BACK_RIGHT_BUFFER_BIT_SGIX 0x00000008 #define GLX_AUX_BUFFERS_BIT_SGIX 0x00000010 #define GLX_DEPTH_BUFFER_BIT_SGIX 0x00000020 #define GLX_STENCIL_BUFFER_BIT_SGIX 0x00000040 #define GLX_ACCUM_BUFFER_BIT_SGIX 0x00000080 #define GLX_SAMPLE_BUFFERS_BIT_SGIX 0x00000100 #define GLX_MAX_PBUFFER_WIDTH_SGIX 0x8016 #define GLX_MAX_PBUFFER_HEIGHT_SGIX 0x8017 #define GLX_MAX_PBUFFER_PIXELS_SGIX 0x8018 #define GLX_OPTIMAL_PBUFFER_WIDTH_SGIX 0x8019 #define GLX_OPTIMAL_PBUFFER_HEIGHT_SGIX 0x801A #define GLX_PRESERVED_CONTENTS_SGIX 0x801B #define GLX_LARGEST_PBUFFER_SGIX 0x801C #define GLX_WIDTH_SGIX 0x801D #define GLX_HEIGHT_SGIX 0x801E #define GLX_EVENT_MASK_SGIX 0x801F #define GLX_DAMAGED_SGIX 0x8020 #define GLX_SAVED_SGIX 0x8021 #define GLX_WINDOW_SGIX 0x8022 #define GLX_PBUFFER_SGIX 0x8023 #endif #ifndef GLX_SGI_cushion #endif #ifndef GLX_SGIX_video_resize #define GLX_SYNC_FRAME_SGIX 0x00000000 #define GLX_SYNC_SWAP_SGIX 0x00000001 #endif #ifndef GLX_SGIX_dmbuffer #define GLX_DIGITAL_MEDIA_PBUFFER_SGIX 0x8024 #endif #ifndef GLX_SGIX_swap_group #endif #ifndef GLX_SGIX_swap_barrier #endif #ifndef GLX_SGIS_blended_overlay #define GLX_BLENDED_RGBA_SGIS 0x8025 #endif #ifndef GLX_SGIS_shared_multisample #define GLX_MULTISAMPLE_SUB_RECT_WIDTH_SGIS 0x8026 #define GLX_MULTISAMPLE_SUB_RECT_HEIGHT_SGIS 0x8027 #endif #ifndef GLX_SUN_get_transparent_index #endif #ifndef GLX_3DFX_multisample #define GLX_SAMPLE_BUFFERS_3DFX 0x8050 #define GLX_SAMPLES_3DFX 0x8051 #endif #ifndef GLX_MESA_copy_sub_buffer #endif #ifndef GLX_MESA_pixmap_colormap #endif #ifndef GLX_MESA_release_buffers #endif #ifndef GLX_MESA_set_3dfx_mode #define GLX_3DFX_WINDOW_MODE_MESA 0x1 #define GLX_3DFX_FULLSCREEN_MODE_MESA 0x2 #endif #ifndef GLX_SGIX_visual_select_group #define GLX_VISUAL_SELECT_GROUP_SGIX 0x8028 #endif #ifndef GLX_OML_swap_method #define GLX_SWAP_METHOD_OML 0x8060 #define GLX_SWAP_EXCHANGE_OML 0x8061 #define GLX_SWAP_COPY_OML 0x8062 #define GLX_SWAP_UNDEFINED_OML 0x8063 #endif #ifndef GLX_OML_sync_control #endif #ifndef GLX_NV_float_buffer #define GLX_FLOAT_COMPONENTS_NV 0x20B0 #endif #ifndef GLX_SGIX_hyperpipe #define GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX 80 #define GLX_BAD_HYPERPIPE_CONFIG_SGIX 91 #define GLX_BAD_HYPERPIPE_SGIX 92 #define GLX_HYPERPIPE_DISPLAY_PIPE_SGIX 0x00000001 #define GLX_HYPERPIPE_RENDER_PIPE_SGIX 0x00000002 #define GLX_PIPE_RECT_SGIX 0x00000001 #define GLX_PIPE_RECT_LIMITS_SGIX 0x00000002 #define GLX_HYPERPIPE_STEREO_SGIX 0x00000003 #define GLX_HYPERPIPE_PIXEL_AVERAGE_SGIX 0x00000004 #define GLX_HYPERPIPE_ID_SGIX 0x8030 #endif #ifndef GLX_MESA_agp_offset #endif #ifndef GLX_EXT_fbconfig_packed_float #define GLX_RGBA_UNSIGNED_FLOAT_TYPE_EXT 0x20B1 #define GLX_RGBA_UNSIGNED_FLOAT_BIT_EXT 0x00000008 #endif #ifndef GLX_EXT_framebuffer_sRGB #define GLX_FRAMEBUFFER_SRGB_CAPABLE_EXT 0x20B2 #endif #ifndef GLX_EXT_texture_from_pixmap #define GLX_TEXTURE_1D_BIT_EXT 0x00000001 #define GLX_TEXTURE_2D_BIT_EXT 0x00000002 #define GLX_TEXTURE_RECTANGLE_BIT_EXT 0x00000004 #define GLX_BIND_TO_TEXTURE_RGB_EXT 0x20D0 #define GLX_BIND_TO_TEXTURE_RGBA_EXT 0x20D1 #define GLX_BIND_TO_MIPMAP_TEXTURE_EXT 0x20D2 #define GLX_BIND_TO_TEXTURE_TARGETS_EXT 0x20D3 #define GLX_Y_INVERTED_EXT 0x20D4 #define GLX_TEXTURE_FORMAT_EXT 0x20D5 #define GLX_TEXTURE_TARGET_EXT 0x20D6 #define GLX_MIPMAP_TEXTURE_EXT 0x20D7 #define GLX_TEXTURE_FORMAT_NONE_EXT 0x20D8 #define GLX_TEXTURE_FORMAT_RGB_EXT 0x20D9 #define GLX_TEXTURE_FORMAT_RGBA_EXT 0x20DA #define GLX_TEXTURE_1D_EXT 0x20DB #define GLX_TEXTURE_2D_EXT 0x20DC #define GLX_TEXTURE_RECTANGLE_EXT 0x20DD #define GLX_FRONT_LEFT_EXT 0x20DE #define GLX_FRONT_RIGHT_EXT 0x20DF #define GLX_BACK_LEFT_EXT 0x20E0 #define GLX_BACK_RIGHT_EXT 0x20E1 #define GLX_FRONT_EXT GLX_FRONT_LEFT_EXT #define GLX_BACK_EXT GLX_BACK_LEFT_EXT #define GLX_AUX0_EXT 0x20E2 #define GLX_AUX1_EXT 0x20E3 #define GLX_AUX2_EXT 0x20E4 #define GLX_AUX3_EXT 0x20E5 #define GLX_AUX4_EXT 0x20E6 #define GLX_AUX5_EXT 0x20E7 #define GLX_AUX6_EXT 0x20E8 #define GLX_AUX7_EXT 0x20E9 #define GLX_AUX8_EXT 0x20EA #define GLX_AUX9_EXT 0x20EB #endif #ifndef GLX_NV_present_video #define GLX_NUM_VIDEO_SLOTS_NV 0x20F0 #endif #ifndef GLX_NV_video_out #define GLX_VIDEO_OUT_COLOR_NV 0x20C3 #define GLX_VIDEO_OUT_ALPHA_NV 0x20C4 #define GLX_VIDEO_OUT_DEPTH_NV 0x20C5 #define GLX_VIDEO_OUT_COLOR_AND_ALPHA_NV 0x20C6 #define GLX_VIDEO_OUT_COLOR_AND_DEPTH_NV 0x20C7 #define GLX_VIDEO_OUT_FRAME_NV 0x20C8 #define GLX_VIDEO_OUT_FIELD_1_NV 0x20C9 #define GLX_VIDEO_OUT_FIELD_2_NV 0x20CA #define GLX_VIDEO_OUT_STACKED_FIELDS_1_2_NV 0x20CB #define GLX_VIDEO_OUT_STACKED_FIELDS_2_1_NV 0x20CC #endif #ifndef GLX_NV_swap_group #endif /*************************************************************/ #ifndef GLX_ARB_get_proc_address typedef void (*__GLXextFuncPtr)(void); #endif #ifndef GLX_SGIX_video_source typedef XID GLXVideoSourceSGIX; #endif #ifndef GLX_SGIX_fbconfig typedef XID GLXFBConfigIDSGIX; typedef struct __GLXFBConfigRec *GLXFBConfigSGIX; #endif #ifndef GLX_SGIX_pbuffer typedef XID GLXPbufferSGIX; typedef struct { int type; unsigned long serial; /* # of last request processed by server */ Bool send_event; /* true if this came for SendEvent request */ Display *display; /* display the event was read from */ GLXDrawable drawable; /* i.d. of Drawable */ int event_type; /* GLX_DAMAGED_SGIX or GLX_SAVED_SGIX */ int draw_type; /* GLX_WINDOW_SGIX or GLX_PBUFFER_SGIX */ unsigned int mask; /* mask indicating which buffers are affected*/ int x, y; int width, height; int count; /* if nonzero, at least this many more */ } GLXBufferClobberEventSGIX; #endif #ifndef GLEXT_64_TYPES_DEFINED /* This code block is duplicated in glext.h, so must be protected */ #define GLEXT_64_TYPES_DEFINED /* Define int32_t, int64_t, and uint64_t types for UST/MSC */ /* (as used in the GLX_OML_sync_control extension). */ #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L #include #elif defined(__sun__) || defined(__digital__) #include #if defined(__STDC__) #if defined(__arch64__) || defined(_LP64) typedef long int int64_t; typedef unsigned long int uint64_t; #else typedef long long int int64_t; typedef unsigned long long int uint64_t; #endif /* __arch64__ */ #endif /* __STDC__ */ #elif defined( __VMS ) || defined(__sgi) #include #elif defined(__SCO__) || defined(__USLC__) #include #elif defined(__UNIXOS2__) || defined(__SOL64__) typedef long int int32_t; typedef long long int int64_t; typedef unsigned long long int uint64_t; #elif defined(_WIN32) && defined(__GNUC__) #include #elif defined(_WIN32) typedef __int32 int32_t; typedef __int64 int64_t; typedef unsigned __int64 uint64_t; #else #include /* Fallback option */ #endif #endif #ifndef GLX_VERSION_1_3 #define GLX_VERSION_1_3 1 #ifdef GLX_GLXEXT_PROTOTYPES extern GLXFBConfig * glXGetFBConfigs (Display *, int, int *); extern GLXFBConfig * glXChooseFBConfig (Display *, int, const int *, int *); extern int glXGetFBConfigAttrib (Display *, GLXFBConfig, int, int *); extern XVisualInfo * glXGetVisualFromFBConfig (Display *, GLXFBConfig); extern GLXWindow glXCreateWindow (Display *, GLXFBConfig, Window, const int *); extern void glXDestroyWindow (Display *, GLXWindow); extern GLXPixmap glXCreatePixmap (Display *, GLXFBConfig, Pixmap, const int *); extern void glXDestroyPixmap (Display *, GLXPixmap); extern GLXPbuffer glXCreatePbuffer (Display *, GLXFBConfig, const int *); extern void glXDestroyPbuffer (Display *, GLXPbuffer); extern void glXQueryDrawable (Display *, GLXDrawable, int, unsigned int *); extern GLXContext glXCreateNewContext (Display *, GLXFBConfig, int, GLXContext, Bool); extern Bool glXMakeContextCurrent (Display *, GLXDrawable, GLXDrawable, GLXContext); extern GLXDrawable glXGetCurrentReadDrawable (void); extern Display * glXGetCurrentDisplay (void); extern int glXQueryContext (Display *, GLXContext, int, int *); extern void glXSelectEvent (Display *, GLXDrawable, unsigned long); extern void glXGetSelectedEvent (Display *, GLXDrawable, unsigned long *); #endif /* GLX_GLXEXT_PROTOTYPES */ typedef GLXFBConfig * ( * PFNGLXGETFBCONFIGSPROC) (Display *dpy, int screen, int *nelements); typedef GLXFBConfig * ( * PFNGLXCHOOSEFBCONFIGPROC) (Display *dpy, int screen, const int *attrib_list, int *nelements); typedef int ( * PFNGLXGETFBCONFIGATTRIBPROC) (Display *dpy, GLXFBConfig config, int attribute, int *value); typedef XVisualInfo * ( * PFNGLXGETVISUALFROMFBCONFIGPROC) (Display *dpy, GLXFBConfig config); typedef GLXWindow ( * PFNGLXCREATEWINDOWPROC) (Display *dpy, GLXFBConfig config, Window win, const int *attrib_list); typedef void ( * PFNGLXDESTROYWINDOWPROC) (Display *dpy, GLXWindow win); typedef GLXPixmap ( * PFNGLXCREATEPIXMAPPROC) (Display *dpy, GLXFBConfig config, Pixmap pixmap, const int *attrib_list); typedef void ( * PFNGLXDESTROYPIXMAPPROC) (Display *dpy, GLXPixmap pixmap); typedef GLXPbuffer ( * PFNGLXCREATEPBUFFERPROC) (Display *dpy, GLXFBConfig config, const int *attrib_list); typedef void ( * PFNGLXDESTROYPBUFFERPROC) (Display *dpy, GLXPbuffer pbuf); typedef void ( * PFNGLXQUERYDRAWABLEPROC) (Display *dpy, GLXDrawable draw, int attribute, unsigned int *value); typedef GLXContext ( * PFNGLXCREATENEWCONTEXTPROC) (Display *dpy, GLXFBConfig config, int render_type, GLXContext share_list, Bool direct); typedef Bool ( * PFNGLXMAKECONTEXTCURRENTPROC) (Display *dpy, GLXDrawable draw, GLXDrawable read, GLXContext ctx); typedef GLXDrawable ( * PFNGLXGETCURRENTREADDRAWABLEPROC) (void); typedef Display * ( * PFNGLXGETCURRENTDISPLAYPROC) (void); typedef int ( * PFNGLXQUERYCONTEXTPROC) (Display *dpy, GLXContext ctx, int attribute, int *value); typedef void ( * PFNGLXSELECTEVENTPROC) (Display *dpy, GLXDrawable draw, unsigned long event_mask); typedef void ( * PFNGLXGETSELECTEDEVENTPROC) (Display *dpy, GLXDrawable draw, unsigned long *event_mask); #endif #ifndef GLX_VERSION_1_4 #define GLX_VERSION_1_4 1 #ifdef GLX_GLXEXT_PROTOTYPES extern __GLXextFuncPtr glXGetProcAddress (const GLubyte *); #endif /* GLX_GLXEXT_PROTOTYPES */ typedef __GLXextFuncPtr ( * PFNGLXGETPROCADDRESSPROC) (const GLubyte *procName); #endif #ifndef GLX_ARB_get_proc_address #define GLX_ARB_get_proc_address 1 #ifdef GLX_GLXEXT_PROTOTYPES extern __GLXextFuncPtr glXGetProcAddressARB (const GLubyte *); #endif /* GLX_GLXEXT_PROTOTYPES */ typedef __GLXextFuncPtr ( * PFNGLXGETPROCADDRESSARBPROC) (const GLubyte *procName); #endif #ifndef GLX_ARB_multisample #define GLX_ARB_multisample 1 #endif #ifndef GLX_ARB_fbconfig_float #define GLX_ARB_fbconfig_float 1 #endif #ifndef GLX_ARB_create_context #define GLX_ARB_create_context 1 #ifdef GLX_GLXEXT_PROTOTYPES extern GLXContext glXCreateContextAttribsARB (Display *, GLXFBConfig, GLXContext, Bool, const int *); #endif /* GLX_GLXEXT_PROTOTYPES */ typedef GLXContext ( * PFNGLXCREATECONTEXTATTRIBSARBPROC) (Display *dpy, GLXFBConfig config, GLXContext share_context, Bool direct, const int *attrib_list); #endif #ifndef GLX_SGIS_multisample #define GLX_SGIS_multisample 1 #endif #ifndef GLX_EXT_visual_info #define GLX_EXT_visual_info 1 #endif #ifndef GLX_SGI_swap_control #define GLX_SGI_swap_control 1 #ifdef GLX_GLXEXT_PROTOTYPES extern int glXSwapIntervalSGI (int); #endif /* GLX_GLXEXT_PROTOTYPES */ typedef int ( * PFNGLXSWAPINTERVALSGIPROC) (int interval); #endif #ifndef GLX_SGI_video_sync #define GLX_SGI_video_sync 1 #ifdef GLX_GLXEXT_PROTOTYPES extern int glXGetVideoSyncSGI (unsigned int *); extern int glXWaitVideoSyncSGI (int, int, unsigned int *); #endif /* GLX_GLXEXT_PROTOTYPES */ typedef int ( * PFNGLXGETVIDEOSYNCSGIPROC) (unsigned int *count); typedef int ( * PFNGLXWAITVIDEOSYNCSGIPROC) (int divisor, int remainder, unsigned int *count); #endif #ifndef GLX_SGI_make_current_read #define GLX_SGI_make_current_read 1 #ifdef GLX_GLXEXT_PROTOTYPES extern Bool glXMakeCurrentReadSGI (Display *, GLXDrawable, GLXDrawable, GLXContext); extern GLXDrawable glXGetCurrentReadDrawableSGI (void); #endif /* GLX_GLXEXT_PROTOTYPES */ typedef Bool ( * PFNGLXMAKECURRENTREADSGIPROC) (Display *dpy, GLXDrawable draw, GLXDrawable read, GLXContext ctx); typedef GLXDrawable ( * PFNGLXGETCURRENTREADDRAWABLESGIPROC) (void); #endif #ifndef GLX_SGIX_video_source #define GLX_SGIX_video_source 1 #ifdef _VL_H #ifdef GLX_GLXEXT_PROTOTYPES extern GLXVideoSourceSGIX glXCreateGLXVideoSourceSGIX (Display *, int, VLServer, VLPath, int, VLNode); extern void glXDestroyGLXVideoSourceSGIX (Display *, GLXVideoSourceSGIX); #endif /* GLX_GLXEXT_PROTOTYPES */ typedef GLXVideoSourceSGIX ( * PFNGLXCREATEGLXVIDEOSOURCESGIXPROC) (Display *display, int screen, VLServer server, VLPath path, int nodeClass, VLNode drainNode); typedef void ( * PFNGLXDESTROYGLXVIDEOSOURCESGIXPROC) (Display *dpy, GLXVideoSourceSGIX glxvideosource); #endif /* _VL_H */ #endif #ifndef GLX_EXT_visual_rating #define GLX_EXT_visual_rating 1 #endif #ifndef GLX_EXT_import_context #define GLX_EXT_import_context 1 #ifdef GLX_GLXEXT_PROTOTYPES extern Display * glXGetCurrentDisplayEXT (void); extern int glXQueryContextInfoEXT (Display *, GLXContext, int, int *); extern GLXContextID glXGetContextIDEXT (const GLXContext); extern GLXContext glXImportContextEXT (Display *, GLXContextID); extern void glXFreeContextEXT (Display *, GLXContext); #endif /* GLX_GLXEXT_PROTOTYPES */ typedef Display * ( * PFNGLXGETCURRENTDISPLAYEXTPROC) (void); typedef int ( * PFNGLXQUERYCONTEXTINFOEXTPROC) (Display *dpy, GLXContext context, int attribute, int *value); typedef GLXContextID ( * PFNGLXGETCONTEXTIDEXTPROC) (const GLXContext context); typedef GLXContext ( * PFNGLXIMPORTCONTEXTEXTPROC) (Display *dpy, GLXContextID contextID); typedef void ( * PFNGLXFREECONTEXTEXTPROC) (Display *dpy, GLXContext context); #endif #ifndef GLX_SGIX_fbconfig #define GLX_SGIX_fbconfig 1 #ifdef GLX_GLXEXT_PROTOTYPES extern int glXGetFBConfigAttribSGIX (Display *, GLXFBConfigSGIX, int, int *); extern GLXFBConfigSGIX * glXChooseFBConfigSGIX (Display *, int, int *, int *); extern GLXPixmap glXCreateGLXPixmapWithConfigSGIX (Display *, GLXFBConfigSGIX, Pixmap); extern GLXContext glXCreateContextWithConfigSGIX (Display *, GLXFBConfigSGIX, int, GLXContext, Bool); extern XVisualInfo * glXGetVisualFromFBConfigSGIX (Display *, GLXFBConfigSGIX); extern GLXFBConfigSGIX glXGetFBConfigFromVisualSGIX (Display *, XVisualInfo *); #endif /* GLX_GLXEXT_PROTOTYPES */ typedef int ( * PFNGLXGETFBCONFIGATTRIBSGIXPROC) (Display *dpy, GLXFBConfigSGIX config, int attribute, int *value); typedef GLXFBConfigSGIX * ( * PFNGLXCHOOSEFBCONFIGSGIXPROC) (Display *dpy, int screen, int *attrib_list, int *nelements); typedef GLXPixmap ( * PFNGLXCREATEGLXPIXMAPWITHCONFIGSGIXPROC) (Display *dpy, GLXFBConfigSGIX config, Pixmap pixmap); typedef GLXContext ( * PFNGLXCREATECONTEXTWITHCONFIGSGIXPROC) (Display *dpy, GLXFBConfigSGIX config, int render_type, GLXContext share_list, Bool direct); typedef XVisualInfo * ( * PFNGLXGETVISUALFROMFBCONFIGSGIXPROC) (Display *dpy, GLXFBConfigSGIX config); typedef GLXFBConfigSGIX ( * PFNGLXGETFBCONFIGFROMVISUALSGIXPROC) (Display *dpy, XVisualInfo *vis); #endif #ifndef GLX_SGIX_pbuffer #define GLX_SGIX_pbuffer 1 #ifdef GLX_GLXEXT_PROTOTYPES extern GLXPbufferSGIX glXCreateGLXPbufferSGIX (Display *, GLXFBConfigSGIX, unsigned int, unsigned int, int *); extern void glXDestroyGLXPbufferSGIX (Display *, GLXPbufferSGIX); extern int glXQueryGLXPbufferSGIX (Display *, GLXPbufferSGIX, int, unsigned int *); extern void glXSelectEventSGIX (Display *, GLXDrawable, unsigned long); extern void glXGetSelectedEventSGIX (Display *, GLXDrawable, unsigned long *); #endif /* GLX_GLXEXT_PROTOTYPES */ typedef GLXPbufferSGIX ( * PFNGLXCREATEGLXPBUFFERSGIXPROC) (Display *dpy, GLXFBConfigSGIX config, unsigned int width, unsigned int height, int *attrib_list); typedef void ( * PFNGLXDESTROYGLXPBUFFERSGIXPROC) (Display *dpy, GLXPbufferSGIX pbuf); typedef int ( * PFNGLXQUERYGLXPBUFFERSGIXPROC) (Display *dpy, GLXPbufferSGIX pbuf, int attribute, unsigned int *value); typedef void ( * PFNGLXSELECTEVENTSGIXPROC) (Display *dpy, GLXDrawable drawable, unsigned long mask); typedef void ( * PFNGLXGETSELECTEDEVENTSGIXPROC) (Display *dpy, GLXDrawable drawable, unsigned long *mask); #endif #ifndef GLX_SGI_cushion #define GLX_SGI_cushion 1 #ifdef GLX_GLXEXT_PROTOTYPES extern void glXCushionSGI (Display *, Window, float); #endif /* GLX_GLXEXT_PROTOTYPES */ typedef void ( * PFNGLXCUSHIONSGIPROC) (Display *dpy, Window window, float cushion); #endif #ifndef GLX_SGIX_video_resize #define GLX_SGIX_video_resize 1 #ifdef GLX_GLXEXT_PROTOTYPES extern int glXBindChannelToWindowSGIX (Display *, int, int, Window); extern int glXChannelRectSGIX (Display *, int, int, int, int, int, int); extern int glXQueryChannelRectSGIX (Display *, int, int, int *, int *, int *, int *); extern int glXQueryChannelDeltasSGIX (Display *, int, int, int *, int *, int *, int *); extern int glXChannelRectSyncSGIX (Display *, int, int, GLenum); #endif /* GLX_GLXEXT_PROTOTYPES */ typedef int ( * PFNGLXBINDCHANNELTOWINDOWSGIXPROC) (Display *display, int screen, int channel, Window window); typedef int ( * PFNGLXCHANNELRECTSGIXPROC) (Display *display, int screen, int channel, int x, int y, int w, int h); typedef int ( * PFNGLXQUERYCHANNELRECTSGIXPROC) (Display *display, int screen, int channel, int *dx, int *dy, int *dw, int *dh); typedef int ( * PFNGLXQUERYCHANNELDELTASSGIXPROC) (Display *display, int screen, int channel, int *x, int *y, int *w, int *h); typedef int ( * PFNGLXCHANNELRECTSYNCSGIXPROC) (Display *display, int screen, int channel, GLenum synctype); #endif #ifndef GLX_SGIX_dmbuffer #define GLX_SGIX_dmbuffer 1 #ifdef _DM_BUFFER_H_ #ifdef GLX_GLXEXT_PROTOTYPES extern Bool glXAssociateDMPbufferSGIX (Display *, GLXPbufferSGIX, DMparams *, DMbuffer); #endif /* GLX_GLXEXT_PROTOTYPES */ typedef Bool ( * PFNGLXASSOCIATEDMPBUFFERSGIXPROC) (Display *dpy, GLXPbufferSGIX pbuffer, DMparams *params, DMbuffer dmbuffer); #endif /* _DM_BUFFER_H_ */ #endif #ifndef GLX_SGIX_swap_group #define GLX_SGIX_swap_group 1 #ifdef GLX_GLXEXT_PROTOTYPES extern void glXJoinSwapGroupSGIX (Display *, GLXDrawable, GLXDrawable); #endif /* GLX_GLXEXT_PROTOTYPES */ typedef void ( * PFNGLXJOINSWAPGROUPSGIXPROC) (Display *dpy, GLXDrawable drawable, GLXDrawable member); #endif #ifndef GLX_SGIX_swap_barrier #define GLX_SGIX_swap_barrier 1 #ifdef GLX_GLXEXT_PROTOTYPES extern void glXBindSwapBarrierSGIX (Display *, GLXDrawable, int); extern Bool glXQueryMaxSwapBarriersSGIX (Display *, int, int *); #endif /* GLX_GLXEXT_PROTOTYPES */ typedef void ( * PFNGLXBINDSWAPBARRIERSGIXPROC) (Display *dpy, GLXDrawable drawable, int barrier); typedef Bool ( * PFNGLXQUERYMAXSWAPBARRIERSSGIXPROC) (Display *dpy, int screen, int *max); #endif #ifndef GLX_SUN_get_transparent_index #define GLX_SUN_get_transparent_index 1 #ifdef GLX_GLXEXT_PROTOTYPES extern Status glXGetTransparentIndexSUN (Display *, Window, Window, long *); #endif /* GLX_GLXEXT_PROTOTYPES */ typedef Status ( * PFNGLXGETTRANSPARENTINDEXSUNPROC) (Display *dpy, Window overlay, Window underlay, long *pTransparentIndex); #endif #ifndef GLX_MESA_copy_sub_buffer #define GLX_MESA_copy_sub_buffer 1 #ifdef GLX_GLXEXT_PROTOTYPES extern void glXCopySubBufferMESA (Display *, GLXDrawable, int, int, int, int); #endif /* GLX_GLXEXT_PROTOTYPES */ typedef void ( * PFNGLXCOPYSUBBUFFERMESAPROC) (Display *dpy, GLXDrawable drawable, int x, int y, int width, int height); #endif #ifndef GLX_MESA_pixmap_colormap #define GLX_MESA_pixmap_colormap 1 #ifdef GLX_GLXEXT_PROTOTYPES extern GLXPixmap glXCreateGLXPixmapMESA (Display *, XVisualInfo *, Pixmap, Colormap); #endif /* GLX_GLXEXT_PROTOTYPES */ typedef GLXPixmap ( * PFNGLXCREATEGLXPIXMAPMESAPROC) (Display *dpy, XVisualInfo *visual, Pixmap pixmap, Colormap cmap); #endif #ifndef GLX_MESA_release_buffers #define GLX_MESA_release_buffers 1 #ifdef GLX_GLXEXT_PROTOTYPES extern Bool glXReleaseBuffersMESA (Display *, GLXDrawable); #endif /* GLX_GLXEXT_PROTOTYPES */ typedef Bool ( * PFNGLXRELEASEBUFFERSMESAPROC) (Display *dpy, GLXDrawable drawable); #endif #ifndef GLX_MESA_set_3dfx_mode #define GLX_MESA_set_3dfx_mode 1 #ifdef GLX_GLXEXT_PROTOTYPES extern Bool glXSet3DfxModeMESA (int); #endif /* GLX_GLXEXT_PROTOTYPES */ typedef Bool ( * PFNGLXSET3DFXMODEMESAPROC) (int mode); #endif #ifndef GLX_SGIX_visual_select_group #define GLX_SGIX_visual_select_group 1 #endif #ifndef GLX_OML_swap_method #define GLX_OML_swap_method 1 #endif #ifndef GLX_OML_sync_control #define GLX_OML_sync_control 1 #ifdef GLX_GLXEXT_PROTOTYPES extern Bool glXGetSyncValuesOML (Display *, GLXDrawable, int64_t *, int64_t *, int64_t *); extern Bool glXGetMscRateOML (Display *, GLXDrawable, int32_t *, int32_t *); extern int64_t glXSwapBuffersMscOML (Display *, GLXDrawable, int64_t, int64_t, int64_t); extern Bool glXWaitForMscOML (Display *, GLXDrawable, int64_t, int64_t, int64_t, int64_t *, int64_t *, int64_t *); extern Bool glXWaitForSbcOML (Display *, GLXDrawable, int64_t, int64_t *, int64_t *, int64_t *); #endif /* GLX_GLXEXT_PROTOTYPES */ typedef Bool ( * PFNGLXGETSYNCVALUESOMLPROC) (Display *dpy, GLXDrawable drawable, int64_t *ust, int64_t *msc, int64_t *sbc); typedef Bool ( * PFNGLXGETMSCRATEOMLPROC) (Display *dpy, GLXDrawable drawable, int32_t *numerator, int32_t *denominator); typedef int64_t ( * PFNGLXSWAPBUFFERSMSCOMLPROC) (Display *dpy, GLXDrawable drawable, int64_t target_msc, int64_t divisor, int64_t remainder); typedef Bool ( * PFNGLXWAITFORMSCOMLPROC) (Display *dpy, GLXDrawable drawable, int64_t target_msc, int64_t divisor, int64_t remainder, int64_t *ust, int64_t *msc, int64_t *sbc); typedef Bool ( * PFNGLXWAITFORSBCOMLPROC) (Display *dpy, GLXDrawable drawable, int64_t target_sbc, int64_t *ust, int64_t *msc, int64_t *sbc); #endif #ifndef GLX_NV_float_buffer #define GLX_NV_float_buffer 1 #endif #ifndef GLX_SGIX_hyperpipe #define GLX_SGIX_hyperpipe 1 typedef struct { char pipeName[GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX]; int networkId; } GLXHyperpipeNetworkSGIX; typedef struct { char pipeName[GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX]; int channel; unsigned int participationType; int timeSlice; } GLXHyperpipeConfigSGIX; typedef struct { char pipeName[GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX]; int srcXOrigin, srcYOrigin, srcWidth, srcHeight; int destXOrigin, destYOrigin, destWidth, destHeight; } GLXPipeRect; typedef struct { char pipeName[GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX]; int XOrigin, YOrigin, maxHeight, maxWidth; } GLXPipeRectLimits; #ifdef GLX_GLXEXT_PROTOTYPES extern GLXHyperpipeNetworkSGIX * glXQueryHyperpipeNetworkSGIX (Display *, int *); extern int glXHyperpipeConfigSGIX (Display *, int, int, GLXHyperpipeConfigSGIX *, int *); extern GLXHyperpipeConfigSGIX * glXQueryHyperpipeConfigSGIX (Display *, int, int *); extern int glXDestroyHyperpipeConfigSGIX (Display *, int); extern int glXBindHyperpipeSGIX (Display *, int); extern int glXQueryHyperpipeBestAttribSGIX (Display *, int, int, int, void *, void *); extern int glXHyperpipeAttribSGIX (Display *, int, int, int, void *); extern int glXQueryHyperpipeAttribSGIX (Display *, int, int, int, void *); #endif /* GLX_GLXEXT_PROTOTYPES */ typedef GLXHyperpipeNetworkSGIX * ( * PFNGLXQUERYHYPERPIPENETWORKSGIXPROC) (Display *dpy, int *npipes); typedef int ( * PFNGLXHYPERPIPECONFIGSGIXPROC) (Display *dpy, int networkId, int npipes, GLXHyperpipeConfigSGIX *cfg, int *hpId); typedef GLXHyperpipeConfigSGIX * ( * PFNGLXQUERYHYPERPIPECONFIGSGIXPROC) (Display *dpy, int hpId, int *npipes); typedef int ( * PFNGLXDESTROYHYPERPIPECONFIGSGIXPROC) (Display *dpy, int hpId); typedef int ( * PFNGLXBINDHYPERPIPESGIXPROC) (Display *dpy, int hpId); typedef int ( * PFNGLXQUERYHYPERPIPEBESTATTRIBSGIXPROC) (Display *dpy, int timeSlice, int attrib, int size, void *attribList, void *returnAttribList); typedef int ( * PFNGLXHYPERPIPEATTRIBSGIXPROC) (Display *dpy, int timeSlice, int attrib, int size, void *attribList); typedef int ( * PFNGLXQUERYHYPERPIPEATTRIBSGIXPROC) (Display *dpy, int timeSlice, int attrib, int size, void *returnAttribList); #endif #ifndef GLX_MESA_agp_offset #define GLX_MESA_agp_offset 1 #ifdef GLX_GLXEXT_PROTOTYPES extern unsigned int glXGetAGPOffsetMESA (const void *); #endif /* GLX_GLXEXT_PROTOTYPES */ typedef unsigned int ( * PFNGLXGETAGPOFFSETMESAPROC) (const void *pointer); #endif #ifndef GLX_EXT_fbconfig_packed_float #define GLX_EXT_fbconfig_packed_float 1 #endif #ifndef GLX_EXT_framebuffer_sRGB #define GLX_EXT_framebuffer_sRGB 1 #endif #ifndef GLX_EXT_texture_from_pixmap #define GLX_EXT_texture_from_pixmap 1 #ifdef GLX_GLXEXT_PROTOTYPES extern void glXBindTexImageEXT (Display *, GLXDrawable, int, const int *); extern void glXReleaseTexImageEXT (Display *, GLXDrawable, int); #endif /* GLX_GLXEXT_PROTOTYPES */ typedef void ( * PFNGLXBINDTEXIMAGEEXTPROC) (Display *dpy, GLXDrawable drawable, int buffer, const int *attrib_list); typedef void ( * PFNGLXRELEASETEXIMAGEEXTPROC) (Display *dpy, GLXDrawable drawable, int buffer); #endif #ifndef GLX_NV_present_video #define GLX_NV_present_video 1 #endif #ifndef GLX_NV_video_out #define GLX_NV_video_out 1 #endif #ifndef GLX_NV_swap_group #define GLX_NV_swap_group 1 #endif #ifdef __cplusplus } #endif #endif ================================================ FILE: ng/Togl2.1/gl/wglext.h ================================================ #ifndef __wglext_h_ #define __wglext_h_ #ifdef __cplusplus extern "C" { #endif /* ** Copyright (c) 2007 The Khronos Group Inc. ** ** Permission is hereby granted, free of charge, to any person obtaining a ** copy of this software and/or associated documentation files (the ** "Materials"), to deal in the Materials without restriction, including ** without limitation the rights to use, copy, modify, merge, publish, ** distribute, sublicense, and/or sell copies of the Materials, and to ** permit persons to whom the Materials are furnished to do so, subject to ** the following conditions: ** ** The above copyright notice and this permission notice shall be included ** in all copies or substantial portions of the Materials. ** ** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, ** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE ** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. */ #if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) #define WIN32_LEAN_AND_MEAN 1 #include #endif #ifndef APIENTRY #define APIENTRY #endif #ifndef APIENTRYP #define APIENTRYP APIENTRY * #endif #ifndef GLAPI #define GLAPI extern #endif /*************************************************************/ /* Header file version number */ /* wglext.h last updated 2008/10/07 */ /* Current version at http://www.opengl.org/registry/ */ #define WGL_WGLEXT_VERSION 11 #ifndef WGL_ARB_buffer_region #define WGL_FRONT_COLOR_BUFFER_BIT_ARB 0x00000001 #define WGL_BACK_COLOR_BUFFER_BIT_ARB 0x00000002 #define WGL_DEPTH_BUFFER_BIT_ARB 0x00000004 #define WGL_STENCIL_BUFFER_BIT_ARB 0x00000008 #endif #ifndef WGL_ARB_multisample #define WGL_SAMPLE_BUFFERS_ARB 0x2041 #define WGL_SAMPLES_ARB 0x2042 #endif #ifndef WGL_ARB_extensions_string #endif #ifndef WGL_ARB_pixel_format #define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000 #define WGL_DRAW_TO_WINDOW_ARB 0x2001 #define WGL_DRAW_TO_BITMAP_ARB 0x2002 #define WGL_ACCELERATION_ARB 0x2003 #define WGL_NEED_PALETTE_ARB 0x2004 #define WGL_NEED_SYSTEM_PALETTE_ARB 0x2005 #define WGL_SWAP_LAYER_BUFFERS_ARB 0x2006 #define WGL_SWAP_METHOD_ARB 0x2007 #define WGL_NUMBER_OVERLAYS_ARB 0x2008 #define WGL_NUMBER_UNDERLAYS_ARB 0x2009 #define WGL_TRANSPARENT_ARB 0x200A #define WGL_TRANSPARENT_RED_VALUE_ARB 0x2037 #define WGL_TRANSPARENT_GREEN_VALUE_ARB 0x2038 #define WGL_TRANSPARENT_BLUE_VALUE_ARB 0x2039 #define WGL_TRANSPARENT_ALPHA_VALUE_ARB 0x203A #define WGL_TRANSPARENT_INDEX_VALUE_ARB 0x203B #define WGL_SHARE_DEPTH_ARB 0x200C #define WGL_SHARE_STENCIL_ARB 0x200D #define WGL_SHARE_ACCUM_ARB 0x200E #define WGL_SUPPORT_GDI_ARB 0x200F #define WGL_SUPPORT_OPENGL_ARB 0x2010 #define WGL_DOUBLE_BUFFER_ARB 0x2011 #define WGL_STEREO_ARB 0x2012 #define WGL_PIXEL_TYPE_ARB 0x2013 #define WGL_COLOR_BITS_ARB 0x2014 #define WGL_RED_BITS_ARB 0x2015 #define WGL_RED_SHIFT_ARB 0x2016 #define WGL_GREEN_BITS_ARB 0x2017 #define WGL_GREEN_SHIFT_ARB 0x2018 #define WGL_BLUE_BITS_ARB 0x2019 #define WGL_BLUE_SHIFT_ARB 0x201A #define WGL_ALPHA_BITS_ARB 0x201B #define WGL_ALPHA_SHIFT_ARB 0x201C #define WGL_ACCUM_BITS_ARB 0x201D #define WGL_ACCUM_RED_BITS_ARB 0x201E #define WGL_ACCUM_GREEN_BITS_ARB 0x201F #define WGL_ACCUM_BLUE_BITS_ARB 0x2020 #define WGL_ACCUM_ALPHA_BITS_ARB 0x2021 #define WGL_DEPTH_BITS_ARB 0x2022 #define WGL_STENCIL_BITS_ARB 0x2023 #define WGL_AUX_BUFFERS_ARB 0x2024 #define WGL_NO_ACCELERATION_ARB 0x2025 #define WGL_GENERIC_ACCELERATION_ARB 0x2026 #define WGL_FULL_ACCELERATION_ARB 0x2027 #define WGL_SWAP_EXCHANGE_ARB 0x2028 #define WGL_SWAP_COPY_ARB 0x2029 #define WGL_SWAP_UNDEFINED_ARB 0x202A #define WGL_TYPE_RGBA_ARB 0x202B #define WGL_TYPE_COLORINDEX_ARB 0x202C #endif #ifndef WGL_ARB_make_current_read #define ERROR_INVALID_PIXEL_TYPE_ARB 0x2043 #define ERROR_INCOMPATIBLE_DEVICE_CONTEXTS_ARB 0x2054 #endif #ifndef WGL_ARB_pbuffer #define WGL_DRAW_TO_PBUFFER_ARB 0x202D #define WGL_MAX_PBUFFER_PIXELS_ARB 0x202E #define WGL_MAX_PBUFFER_WIDTH_ARB 0x202F #define WGL_MAX_PBUFFER_HEIGHT_ARB 0x2030 #define WGL_PBUFFER_LARGEST_ARB 0x2033 #define WGL_PBUFFER_WIDTH_ARB 0x2034 #define WGL_PBUFFER_HEIGHT_ARB 0x2035 #define WGL_PBUFFER_LOST_ARB 0x2036 #endif #ifndef WGL_ARB_render_texture #define WGL_BIND_TO_TEXTURE_RGB_ARB 0x2070 #define WGL_BIND_TO_TEXTURE_RGBA_ARB 0x2071 #define WGL_TEXTURE_FORMAT_ARB 0x2072 #define WGL_TEXTURE_TARGET_ARB 0x2073 #define WGL_MIPMAP_TEXTURE_ARB 0x2074 #define WGL_TEXTURE_RGB_ARB 0x2075 #define WGL_TEXTURE_RGBA_ARB 0x2076 #define WGL_NO_TEXTURE_ARB 0x2077 #define WGL_TEXTURE_CUBE_MAP_ARB 0x2078 #define WGL_TEXTURE_1D_ARB 0x2079 #define WGL_TEXTURE_2D_ARB 0x207A #define WGL_MIPMAP_LEVEL_ARB 0x207B #define WGL_CUBE_MAP_FACE_ARB 0x207C #define WGL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB 0x207D #define WGL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB 0x207E #define WGL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB 0x207F #define WGL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB 0x2080 #define WGL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB 0x2081 #define WGL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB 0x2082 #define WGL_FRONT_LEFT_ARB 0x2083 #define WGL_FRONT_RIGHT_ARB 0x2084 #define WGL_BACK_LEFT_ARB 0x2085 #define WGL_BACK_RIGHT_ARB 0x2086 #define WGL_AUX0_ARB 0x2087 #define WGL_AUX1_ARB 0x2088 #define WGL_AUX2_ARB 0x2089 #define WGL_AUX3_ARB 0x208A #define WGL_AUX4_ARB 0x208B #define WGL_AUX5_ARB 0x208C #define WGL_AUX6_ARB 0x208D #define WGL_AUX7_ARB 0x208E #define WGL_AUX8_ARB 0x208F #define WGL_AUX9_ARB 0x2090 #endif #ifndef WGL_ARB_pixel_format_float #define WGL_TYPE_RGBA_FLOAT_ARB 0x21A0 #endif #ifndef WGL_ARB_create_context #define WGL_CONTEXT_DEBUG_BIT_ARB 0x0001 #define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002 #define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 #define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 #define WGL_CONTEXT_LAYER_PLANE_ARB 0x2093 #define WGL_CONTEXT_FLAGS_ARB 0x2094 #define ERROR_INVALID_VERSION_ARB 0x2095 #endif #ifndef WGL_EXT_make_current_read #define ERROR_INVALID_PIXEL_TYPE_EXT 0x2043 #endif #ifndef WGL_EXT_pixel_format #define WGL_NUMBER_PIXEL_FORMATS_EXT 0x2000 #define WGL_DRAW_TO_WINDOW_EXT 0x2001 #define WGL_DRAW_TO_BITMAP_EXT 0x2002 #define WGL_ACCELERATION_EXT 0x2003 #define WGL_NEED_PALETTE_EXT 0x2004 #define WGL_NEED_SYSTEM_PALETTE_EXT 0x2005 #define WGL_SWAP_LAYER_BUFFERS_EXT 0x2006 #define WGL_SWAP_METHOD_EXT 0x2007 #define WGL_NUMBER_OVERLAYS_EXT 0x2008 #define WGL_NUMBER_UNDERLAYS_EXT 0x2009 #define WGL_TRANSPARENT_EXT 0x200A #define WGL_TRANSPARENT_VALUE_EXT 0x200B #define WGL_SHARE_DEPTH_EXT 0x200C #define WGL_SHARE_STENCIL_EXT 0x200D #define WGL_SHARE_ACCUM_EXT 0x200E #define WGL_SUPPORT_GDI_EXT 0x200F #define WGL_SUPPORT_OPENGL_EXT 0x2010 #define WGL_DOUBLE_BUFFER_EXT 0x2011 #define WGL_STEREO_EXT 0x2012 #define WGL_PIXEL_TYPE_EXT 0x2013 #define WGL_COLOR_BITS_EXT 0x2014 #define WGL_RED_BITS_EXT 0x2015 #define WGL_RED_SHIFT_EXT 0x2016 #define WGL_GREEN_BITS_EXT 0x2017 #define WGL_GREEN_SHIFT_EXT 0x2018 #define WGL_BLUE_BITS_EXT 0x2019 #define WGL_BLUE_SHIFT_EXT 0x201A #define WGL_ALPHA_BITS_EXT 0x201B #define WGL_ALPHA_SHIFT_EXT 0x201C #define WGL_ACCUM_BITS_EXT 0x201D #define WGL_ACCUM_RED_BITS_EXT 0x201E #define WGL_ACCUM_GREEN_BITS_EXT 0x201F #define WGL_ACCUM_BLUE_BITS_EXT 0x2020 #define WGL_ACCUM_ALPHA_BITS_EXT 0x2021 #define WGL_DEPTH_BITS_EXT 0x2022 #define WGL_STENCIL_BITS_EXT 0x2023 #define WGL_AUX_BUFFERS_EXT 0x2024 #define WGL_NO_ACCELERATION_EXT 0x2025 #define WGL_GENERIC_ACCELERATION_EXT 0x2026 #define WGL_FULL_ACCELERATION_EXT 0x2027 #define WGL_SWAP_EXCHANGE_EXT 0x2028 #define WGL_SWAP_COPY_EXT 0x2029 #define WGL_SWAP_UNDEFINED_EXT 0x202A #define WGL_TYPE_RGBA_EXT 0x202B #define WGL_TYPE_COLORINDEX_EXT 0x202C #endif #ifndef WGL_EXT_pbuffer #define WGL_DRAW_TO_PBUFFER_EXT 0x202D #define WGL_MAX_PBUFFER_PIXELS_EXT 0x202E #define WGL_MAX_PBUFFER_WIDTH_EXT 0x202F #define WGL_MAX_PBUFFER_HEIGHT_EXT 0x2030 #define WGL_OPTIMAL_PBUFFER_WIDTH_EXT 0x2031 #define WGL_OPTIMAL_PBUFFER_HEIGHT_EXT 0x2032 #define WGL_PBUFFER_LARGEST_EXT 0x2033 #define WGL_PBUFFER_WIDTH_EXT 0x2034 #define WGL_PBUFFER_HEIGHT_EXT 0x2035 #endif #ifndef WGL_EXT_depth_float #define WGL_DEPTH_FLOAT_EXT 0x2040 #endif #ifndef WGL_3DFX_multisample #define WGL_SAMPLE_BUFFERS_3DFX 0x2060 #define WGL_SAMPLES_3DFX 0x2061 #endif #ifndef WGL_EXT_multisample #define WGL_SAMPLE_BUFFERS_EXT 0x2041 #define WGL_SAMPLES_EXT 0x2042 #endif #ifndef WGL_I3D_digital_video_control #define WGL_DIGITAL_VIDEO_CURSOR_ALPHA_FRAMEBUFFER_I3D 0x2050 #define WGL_DIGITAL_VIDEO_CURSOR_ALPHA_VALUE_I3D 0x2051 #define WGL_DIGITAL_VIDEO_CURSOR_INCLUDED_I3D 0x2052 #define WGL_DIGITAL_VIDEO_GAMMA_CORRECTED_I3D 0x2053 #endif #ifndef WGL_I3D_gamma #define WGL_GAMMA_TABLE_SIZE_I3D 0x204E #define WGL_GAMMA_EXCLUDE_DESKTOP_I3D 0x204F #endif #ifndef WGL_I3D_genlock #define WGL_GENLOCK_SOURCE_MULTIVIEW_I3D 0x2044 #define WGL_GENLOCK_SOURCE_EXTENAL_SYNC_I3D 0x2045 #define WGL_GENLOCK_SOURCE_EXTENAL_FIELD_I3D 0x2046 #define WGL_GENLOCK_SOURCE_EXTENAL_TTL_I3D 0x2047 #define WGL_GENLOCK_SOURCE_DIGITAL_SYNC_I3D 0x2048 #define WGL_GENLOCK_SOURCE_DIGITAL_FIELD_I3D 0x2049 #define WGL_GENLOCK_SOURCE_EDGE_FALLING_I3D 0x204A #define WGL_GENLOCK_SOURCE_EDGE_RISING_I3D 0x204B #define WGL_GENLOCK_SOURCE_EDGE_BOTH_I3D 0x204C #endif #ifndef WGL_I3D_image_buffer #define WGL_IMAGE_BUFFER_MIN_ACCESS_I3D 0x00000001 #define WGL_IMAGE_BUFFER_LOCK_I3D 0x00000002 #endif #ifndef WGL_I3D_swap_frame_lock #endif #ifndef WGL_NV_render_depth_texture #define WGL_BIND_TO_TEXTURE_DEPTH_NV 0x20A3 #define WGL_BIND_TO_TEXTURE_RECTANGLE_DEPTH_NV 0x20A4 #define WGL_DEPTH_TEXTURE_FORMAT_NV 0x20A5 #define WGL_TEXTURE_DEPTH_COMPONENT_NV 0x20A6 #define WGL_DEPTH_COMPONENT_NV 0x20A7 #endif #ifndef WGL_NV_render_texture_rectangle #define WGL_BIND_TO_TEXTURE_RECTANGLE_RGB_NV 0x20A0 #define WGL_BIND_TO_TEXTURE_RECTANGLE_RGBA_NV 0x20A1 #define WGL_TEXTURE_RECTANGLE_NV 0x20A2 #endif #ifndef WGL_ATI_pixel_format_float #define WGL_TYPE_RGBA_FLOAT_ATI 0x21A0 #endif #ifndef WGL_NV_float_buffer #define WGL_FLOAT_COMPONENTS_NV 0x20B0 #define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_R_NV 0x20B1 #define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RG_NV 0x20B2 #define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGB_NV 0x20B3 #define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGBA_NV 0x20B4 #define WGL_TEXTURE_FLOAT_R_NV 0x20B5 #define WGL_TEXTURE_FLOAT_RG_NV 0x20B6 #define WGL_TEXTURE_FLOAT_RGB_NV 0x20B7 #define WGL_TEXTURE_FLOAT_RGBA_NV 0x20B8 #endif #ifndef WGL_3DL_stereo_control #define WGL_STEREO_EMITTER_ENABLE_3DL 0x2055 #define WGL_STEREO_EMITTER_DISABLE_3DL 0x2056 #define WGL_STEREO_POLARITY_NORMAL_3DL 0x2057 #define WGL_STEREO_POLARITY_INVERT_3DL 0x2058 #endif #ifndef WGL_EXT_pixel_format_packed_float #define WGL_TYPE_RGBA_UNSIGNED_FLOAT_EXT 0x20A8 #endif #ifndef WGL_EXT_framebuffer_sRGB #define WGL_FRAMEBUFFER_SRGB_CAPABLE_EXT 0x20A9 #endif #ifndef WGL_NV_present_video #define WGL_NUM_VIDEO_SLOTS_NV 0x20F0 #endif #ifndef WGL_NV_video_out #define WGL_BIND_TO_VIDEO_RGB_NV 0x20C0 #define WGL_BIND_TO_VIDEO_RGBA_NV 0x20C1 #define WGL_BIND_TO_VIDEO_RGB_AND_DEPTH_NV 0x20C2 #define WGL_VIDEO_OUT_COLOR_NV 0x20C3 #define WGL_VIDEO_OUT_ALPHA_NV 0x20C4 #define WGL_VIDEO_OUT_DEPTH_NV 0x20C5 #define WGL_VIDEO_OUT_COLOR_AND_ALPHA_NV 0x20C6 #define WGL_VIDEO_OUT_COLOR_AND_DEPTH_NV 0x20C7 #define WGL_VIDEO_OUT_FRAME 0x20C8 #define WGL_VIDEO_OUT_FIELD_1 0x20C9 #define WGL_VIDEO_OUT_FIELD_2 0x20CA #define WGL_VIDEO_OUT_STACKED_FIELDS_1_2 0x20CB #define WGL_VIDEO_OUT_STACKED_FIELDS_2_1 0x20CC #endif #ifndef WGL_NV_swap_group #endif #ifndef WGL_NV_gpu_affinity #define WGL_ERROR_INCOMPATIBLE_AFFINITY_MASKS_NV 0x20D0 #define WGL_ERROR_MISSING_AFFINITY_MASK_NV 0x20D1 #endif /*************************************************************/ #ifndef WGL_ARB_pbuffer DECLARE_HANDLE(HPBUFFERARB); #endif #ifndef WGL_EXT_pbuffer DECLARE_HANDLE(HPBUFFEREXT); #endif #ifndef WGL_NV_present_video DECLARE_HANDLE(HVIDEOOUTPUTDEVICENV); #endif #ifndef WGL_NV_video_out DECLARE_HANDLE(HPVIDEODEV); #endif #ifndef WGL_NV_gpu_affinity DECLARE_HANDLE(HPGPUNV); DECLARE_HANDLE(HGPUNV); typedef struct _GPU_DEVICE { DWORD cb; CHAR DeviceName[32]; CHAR DeviceString[128]; DWORD Flags; RECT rcVirtualScreen; } GPU_DEVICE, *PGPU_DEVICE; #endif #ifndef WGL_ARB_buffer_region #define WGL_ARB_buffer_region 1 #ifdef WGL_WGLEXT_PROTOTYPES extern HANDLE WINAPI wglCreateBufferRegionARB (HDC, int, UINT); extern VOID WINAPI wglDeleteBufferRegionARB (HANDLE); extern BOOL WINAPI wglSaveBufferRegionARB (HANDLE, int, int, int, int); extern BOOL WINAPI wglRestoreBufferRegionARB (HANDLE, int, int, int, int, int, int); #endif /* WGL_WGLEXT_PROTOTYPES */ typedef HANDLE (WINAPI * PFNWGLCREATEBUFFERREGIONARBPROC) (HDC hDC, int iLayerPlane, UINT uType); typedef VOID (WINAPI * PFNWGLDELETEBUFFERREGIONARBPROC) (HANDLE hRegion); typedef BOOL (WINAPI * PFNWGLSAVEBUFFERREGIONARBPROC) (HANDLE hRegion, int x, int y, int width, int height); typedef BOOL (WINAPI * PFNWGLRESTOREBUFFERREGIONARBPROC) (HANDLE hRegion, int x, int y, int width, int height, int xSrc, int ySrc); #endif #ifndef WGL_ARB_multisample #define WGL_ARB_multisample 1 #endif #ifndef WGL_ARB_extensions_string #define WGL_ARB_extensions_string 1 #ifdef WGL_WGLEXT_PROTOTYPES extern const char * WINAPI wglGetExtensionsStringARB (HDC); #endif /* WGL_WGLEXT_PROTOTYPES */ typedef const char * (WINAPI * PFNWGLGETEXTENSIONSSTRINGARBPROC) (HDC hdc); #endif #ifndef WGL_ARB_pixel_format #define WGL_ARB_pixel_format 1 #ifdef WGL_WGLEXT_PROTOTYPES extern BOOL WINAPI wglGetPixelFormatAttribivARB (HDC, int, int, UINT, const int *, int *); extern BOOL WINAPI wglGetPixelFormatAttribfvARB (HDC, int, int, UINT, const int *, FLOAT *); extern BOOL WINAPI wglChoosePixelFormatARB (HDC, const int *, const FLOAT *, UINT, int *, UINT *); #endif /* WGL_WGLEXT_PROTOTYPES */ typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBIVARBPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, int *piValues); typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBFVARBPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, FLOAT *pfValues); typedef BOOL (WINAPI * PFNWGLCHOOSEPIXELFORMATARBPROC) (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats); #endif #ifndef WGL_ARB_make_current_read #define WGL_ARB_make_current_read 1 #ifdef WGL_WGLEXT_PROTOTYPES extern BOOL WINAPI wglMakeContextCurrentARB (HDC, HDC, HGLRC); extern HDC WINAPI wglGetCurrentReadDCARB (void); #endif /* WGL_WGLEXT_PROTOTYPES */ typedef BOOL (WINAPI * PFNWGLMAKECONTEXTCURRENTARBPROC) (HDC hDrawDC, HDC hReadDC, HGLRC hglrc); typedef HDC (WINAPI * PFNWGLGETCURRENTREADDCARBPROC) (void); #endif #ifndef WGL_ARB_pbuffer #define WGL_ARB_pbuffer 1 #ifdef WGL_WGLEXT_PROTOTYPES extern HPBUFFERARB WINAPI wglCreatePbufferARB (HDC, int, int, int, const int *); extern HDC WINAPI wglGetPbufferDCARB (HPBUFFERARB); extern int WINAPI wglReleasePbufferDCARB (HPBUFFERARB, HDC); extern BOOL WINAPI wglDestroyPbufferARB (HPBUFFERARB); extern BOOL WINAPI wglQueryPbufferARB (HPBUFFERARB, int, int *); #endif /* WGL_WGLEXT_PROTOTYPES */ typedef HPBUFFERARB (WINAPI * PFNWGLCREATEPBUFFERARBPROC) (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList); typedef HDC (WINAPI * PFNWGLGETPBUFFERDCARBPROC) (HPBUFFERARB hPbuffer); typedef int (WINAPI * PFNWGLRELEASEPBUFFERDCARBPROC) (HPBUFFERARB hPbuffer, HDC hDC); typedef BOOL (WINAPI * PFNWGLDESTROYPBUFFERARBPROC) (HPBUFFERARB hPbuffer); typedef BOOL (WINAPI * PFNWGLQUERYPBUFFERARBPROC) (HPBUFFERARB hPbuffer, int iAttribute, int *piValue); #endif #ifndef WGL_ARB_render_texture #define WGL_ARB_render_texture 1 #ifdef WGL_WGLEXT_PROTOTYPES extern BOOL WINAPI wglBindTexImageARB (HPBUFFERARB, int); extern BOOL WINAPI wglReleaseTexImageARB (HPBUFFERARB, int); extern BOOL WINAPI wglSetPbufferAttribARB (HPBUFFERARB, const int *); #endif /* WGL_WGLEXT_PROTOTYPES */ typedef BOOL (WINAPI * PFNWGLBINDTEXIMAGEARBPROC) (HPBUFFERARB hPbuffer, int iBuffer); typedef BOOL (WINAPI * PFNWGLRELEASETEXIMAGEARBPROC) (HPBUFFERARB hPbuffer, int iBuffer); typedef BOOL (WINAPI * PFNWGLSETPBUFFERATTRIBARBPROC) (HPBUFFERARB hPbuffer, const int *piAttribList); #endif #ifndef WGL_ARB_pixel_format_float #define WGL_ARB_pixel_format_float 1 #endif #ifndef WGL_ARB_create_context #define WGL_ARB_create_context 1 #ifdef WGL_WGLEXT_PROTOTYPES extern HGLRC WINAPI wglCreateContextAttribsARB (HDC, HGLRC, const int *); #endif /* WGL_WGLEXT_PROTOTYPES */ typedef HGLRC (WINAPI * PFNWGLCREATECONTEXTATTRIBSARBPROC) (HDC hDC, HGLRC hShareContext, const int *attribList); #endif #ifndef WGL_EXT_display_color_table #define WGL_EXT_display_color_table 1 #ifdef WGL_WGLEXT_PROTOTYPES extern GLboolean WINAPI wglCreateDisplayColorTableEXT (GLushort); extern GLboolean WINAPI wglLoadDisplayColorTableEXT (const GLushort *, GLuint); extern GLboolean WINAPI wglBindDisplayColorTableEXT (GLushort); extern VOID WINAPI wglDestroyDisplayColorTableEXT (GLushort); #endif /* WGL_WGLEXT_PROTOTYPES */ typedef GLboolean (WINAPI * PFNWGLCREATEDISPLAYCOLORTABLEEXTPROC) (GLushort id); typedef GLboolean (WINAPI * PFNWGLLOADDISPLAYCOLORTABLEEXTPROC) (const GLushort *table, GLuint length); typedef GLboolean (WINAPI * PFNWGLBINDDISPLAYCOLORTABLEEXTPROC) (GLushort id); typedef VOID (WINAPI * PFNWGLDESTROYDISPLAYCOLORTABLEEXTPROC) (GLushort id); #endif #ifndef WGL_EXT_extensions_string #define WGL_EXT_extensions_string 1 #ifdef WGL_WGLEXT_PROTOTYPES extern const char * WINAPI wglGetExtensionsStringEXT (void); #endif /* WGL_WGLEXT_PROTOTYPES */ typedef const char * (WINAPI * PFNWGLGETEXTENSIONSSTRINGEXTPROC) (void); #endif #ifndef WGL_EXT_make_current_read #define WGL_EXT_make_current_read 1 #ifdef WGL_WGLEXT_PROTOTYPES extern BOOL WINAPI wglMakeContextCurrentEXT (HDC, HDC, HGLRC); extern HDC WINAPI wglGetCurrentReadDCEXT (void); #endif /* WGL_WGLEXT_PROTOTYPES */ typedef BOOL (WINAPI * PFNWGLMAKECONTEXTCURRENTEXTPROC) (HDC hDrawDC, HDC hReadDC, HGLRC hglrc); typedef HDC (WINAPI * PFNWGLGETCURRENTREADDCEXTPROC) (void); #endif #ifndef WGL_EXT_pbuffer #define WGL_EXT_pbuffer 1 #ifdef WGL_WGLEXT_PROTOTYPES extern HPBUFFEREXT WINAPI wglCreatePbufferEXT (HDC, int, int, int, const int *); extern HDC WINAPI wglGetPbufferDCEXT (HPBUFFEREXT); extern int WINAPI wglReleasePbufferDCEXT (HPBUFFEREXT, HDC); extern BOOL WINAPI wglDestroyPbufferEXT (HPBUFFEREXT); extern BOOL WINAPI wglQueryPbufferEXT (HPBUFFEREXT, int, int *); #endif /* WGL_WGLEXT_PROTOTYPES */ typedef HPBUFFEREXT (WINAPI * PFNWGLCREATEPBUFFEREXTPROC) (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList); typedef HDC (WINAPI * PFNWGLGETPBUFFERDCEXTPROC) (HPBUFFEREXT hPbuffer); typedef int (WINAPI * PFNWGLRELEASEPBUFFERDCEXTPROC) (HPBUFFEREXT hPbuffer, HDC hDC); typedef BOOL (WINAPI * PFNWGLDESTROYPBUFFEREXTPROC) (HPBUFFEREXT hPbuffer); typedef BOOL (WINAPI * PFNWGLQUERYPBUFFEREXTPROC) (HPBUFFEREXT hPbuffer, int iAttribute, int *piValue); #endif #ifndef WGL_EXT_pixel_format #define WGL_EXT_pixel_format 1 #ifdef WGL_WGLEXT_PROTOTYPES extern BOOL WINAPI wglGetPixelFormatAttribivEXT (HDC, int, int, UINT, int *, int *); extern BOOL WINAPI wglGetPixelFormatAttribfvEXT (HDC, int, int, UINT, int *, FLOAT *); extern BOOL WINAPI wglChoosePixelFormatEXT (HDC, const int *, const FLOAT *, UINT, int *, UINT *); #endif /* WGL_WGLEXT_PROTOTYPES */ typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBIVEXTPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, int *piValues); typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBFVEXTPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, FLOAT *pfValues); typedef BOOL (WINAPI * PFNWGLCHOOSEPIXELFORMATEXTPROC) (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats); #endif #ifndef WGL_EXT_swap_control #define WGL_EXT_swap_control 1 #ifdef WGL_WGLEXT_PROTOTYPES extern BOOL WINAPI wglSwapIntervalEXT (int); extern int WINAPI wglGetSwapIntervalEXT (void); #endif /* WGL_WGLEXT_PROTOTYPES */ typedef BOOL (WINAPI * PFNWGLSWAPINTERVALEXTPROC) (int interval); typedef int (WINAPI * PFNWGLGETSWAPINTERVALEXTPROC) (void); #endif #ifndef WGL_EXT_depth_float #define WGL_EXT_depth_float 1 #endif #ifndef WGL_NV_vertex_array_range #define WGL_NV_vertex_array_range 1 #ifdef WGL_WGLEXT_PROTOTYPES extern void* WINAPI wglAllocateMemoryNV (GLsizei, GLfloat, GLfloat, GLfloat); extern void WINAPI wglFreeMemoryNV (void *); #endif /* WGL_WGLEXT_PROTOTYPES */ typedef void* (WINAPI * PFNWGLALLOCATEMEMORYNVPROC) (GLsizei size, GLfloat readfreq, GLfloat writefreq, GLfloat priority); typedef void (WINAPI * PFNWGLFREEMEMORYNVPROC) (void *pointer); #endif #ifndef WGL_3DFX_multisample #define WGL_3DFX_multisample 1 #endif #ifndef WGL_EXT_multisample #define WGL_EXT_multisample 1 #endif #ifndef WGL_OML_sync_control #define WGL_OML_sync_control 1 #ifdef WGL_WGLEXT_PROTOTYPES extern BOOL WINAPI wglGetSyncValuesOML (HDC, INT64 *, INT64 *, INT64 *); extern BOOL WINAPI wglGetMscRateOML (HDC, INT32 *, INT32 *); extern INT64 WINAPI wglSwapBuffersMscOML (HDC, INT64, INT64, INT64); extern INT64 WINAPI wglSwapLayerBuffersMscOML (HDC, int, INT64, INT64, INT64); extern BOOL WINAPI wglWaitForMscOML (HDC, INT64, INT64, INT64, INT64 *, INT64 *, INT64 *); extern BOOL WINAPI wglWaitForSbcOML (HDC, INT64, INT64 *, INT64 *, INT64 *); #endif /* WGL_WGLEXT_PROTOTYPES */ typedef BOOL (WINAPI * PFNWGLGETSYNCVALUESOMLPROC) (HDC hdc, INT64 *ust, INT64 *msc, INT64 *sbc); typedef BOOL (WINAPI * PFNWGLGETMSCRATEOMLPROC) (HDC hdc, INT32 *numerator, INT32 *denominator); typedef INT64 (WINAPI * PFNWGLSWAPBUFFERSMSCOMLPROC) (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder); typedef INT64 (WINAPI * PFNWGLSWAPLAYERBUFFERSMSCOMLPROC) (HDC hdc, int fuPlanes, INT64 target_msc, INT64 divisor, INT64 remainder); typedef BOOL (WINAPI * PFNWGLWAITFORMSCOMLPROC) (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder, INT64 *ust, INT64 *msc, INT64 *sbc); typedef BOOL (WINAPI * PFNWGLWAITFORSBCOMLPROC) (HDC hdc, INT64 target_sbc, INT64 *ust, INT64 *msc, INT64 *sbc); #endif #ifndef WGL_I3D_digital_video_control #define WGL_I3D_digital_video_control 1 #ifdef WGL_WGLEXT_PROTOTYPES extern BOOL WINAPI wglGetDigitalVideoParametersI3D (HDC, int, int *); extern BOOL WINAPI wglSetDigitalVideoParametersI3D (HDC, int, const int *); #endif /* WGL_WGLEXT_PROTOTYPES */ typedef BOOL (WINAPI * PFNWGLGETDIGITALVIDEOPARAMETERSI3DPROC) (HDC hDC, int iAttribute, int *piValue); typedef BOOL (WINAPI * PFNWGLSETDIGITALVIDEOPARAMETERSI3DPROC) (HDC hDC, int iAttribute, const int *piValue); #endif #ifndef WGL_I3D_gamma #define WGL_I3D_gamma 1 #ifdef WGL_WGLEXT_PROTOTYPES extern BOOL WINAPI wglGetGammaTableParametersI3D (HDC, int, int *); extern BOOL WINAPI wglSetGammaTableParametersI3D (HDC, int, const int *); extern BOOL WINAPI wglGetGammaTableI3D (HDC, int, USHORT *, USHORT *, USHORT *); extern BOOL WINAPI wglSetGammaTableI3D (HDC, int, const USHORT *, const USHORT *, const USHORT *); #endif /* WGL_WGLEXT_PROTOTYPES */ typedef BOOL (WINAPI * PFNWGLGETGAMMATABLEPARAMETERSI3DPROC) (HDC hDC, int iAttribute, int *piValue); typedef BOOL (WINAPI * PFNWGLSETGAMMATABLEPARAMETERSI3DPROC) (HDC hDC, int iAttribute, const int *piValue); typedef BOOL (WINAPI * PFNWGLGETGAMMATABLEI3DPROC) (HDC hDC, int iEntries, USHORT *puRed, USHORT *puGreen, USHORT *puBlue); typedef BOOL (WINAPI * PFNWGLSETGAMMATABLEI3DPROC) (HDC hDC, int iEntries, const USHORT *puRed, const USHORT *puGreen, const USHORT *puBlue); #endif #ifndef WGL_I3D_genlock #define WGL_I3D_genlock 1 #ifdef WGL_WGLEXT_PROTOTYPES extern BOOL WINAPI wglEnableGenlockI3D (HDC); extern BOOL WINAPI wglDisableGenlockI3D (HDC); extern BOOL WINAPI wglIsEnabledGenlockI3D (HDC, BOOL *); extern BOOL WINAPI wglGenlockSourceI3D (HDC, UINT); extern BOOL WINAPI wglGetGenlockSourceI3D (HDC, UINT *); extern BOOL WINAPI wglGenlockSourceEdgeI3D (HDC, UINT); extern BOOL WINAPI wglGetGenlockSourceEdgeI3D (HDC, UINT *); extern BOOL WINAPI wglGenlockSampleRateI3D (HDC, UINT); extern BOOL WINAPI wglGetGenlockSampleRateI3D (HDC, UINT *); extern BOOL WINAPI wglGenlockSourceDelayI3D (HDC, UINT); extern BOOL WINAPI wglGetGenlockSourceDelayI3D (HDC, UINT *); extern BOOL WINAPI wglQueryGenlockMaxSourceDelayI3D (HDC, UINT *, UINT *); #endif /* WGL_WGLEXT_PROTOTYPES */ typedef BOOL (WINAPI * PFNWGLENABLEGENLOCKI3DPROC) (HDC hDC); typedef BOOL (WINAPI * PFNWGLDISABLEGENLOCKI3DPROC) (HDC hDC); typedef BOOL (WINAPI * PFNWGLISENABLEDGENLOCKI3DPROC) (HDC hDC, BOOL *pFlag); typedef BOOL (WINAPI * PFNWGLGENLOCKSOURCEI3DPROC) (HDC hDC, UINT uSource); typedef BOOL (WINAPI * PFNWGLGETGENLOCKSOURCEI3DPROC) (HDC hDC, UINT *uSource); typedef BOOL (WINAPI * PFNWGLGENLOCKSOURCEEDGEI3DPROC) (HDC hDC, UINT uEdge); typedef BOOL (WINAPI * PFNWGLGETGENLOCKSOURCEEDGEI3DPROC) (HDC hDC, UINT *uEdge); typedef BOOL (WINAPI * PFNWGLGENLOCKSAMPLERATEI3DPROC) (HDC hDC, UINT uRate); typedef BOOL (WINAPI * PFNWGLGETGENLOCKSAMPLERATEI3DPROC) (HDC hDC, UINT *uRate); typedef BOOL (WINAPI * PFNWGLGENLOCKSOURCEDELAYI3DPROC) (HDC hDC, UINT uDelay); typedef BOOL (WINAPI * PFNWGLGETGENLOCKSOURCEDELAYI3DPROC) (HDC hDC, UINT *uDelay); typedef BOOL (WINAPI * PFNWGLQUERYGENLOCKMAXSOURCEDELAYI3DPROC) (HDC hDC, UINT *uMaxLineDelay, UINT *uMaxPixelDelay); #endif #ifndef WGL_I3D_image_buffer #define WGL_I3D_image_buffer 1 #ifdef WGL_WGLEXT_PROTOTYPES extern LPVOID WINAPI wglCreateImageBufferI3D (HDC, DWORD, UINT); extern BOOL WINAPI wglDestroyImageBufferI3D (HDC, LPVOID); extern BOOL WINAPI wglAssociateImageBufferEventsI3D (HDC, const HANDLE *, const LPVOID *, const DWORD *, UINT); extern BOOL WINAPI wglReleaseImageBufferEventsI3D (HDC, const LPVOID *, UINT); #endif /* WGL_WGLEXT_PROTOTYPES */ typedef LPVOID (WINAPI * PFNWGLCREATEIMAGEBUFFERI3DPROC) (HDC hDC, DWORD dwSize, UINT uFlags); typedef BOOL (WINAPI * PFNWGLDESTROYIMAGEBUFFERI3DPROC) (HDC hDC, LPVOID pAddress); typedef BOOL (WINAPI * PFNWGLASSOCIATEIMAGEBUFFEREVENTSI3DPROC) (HDC hDC, const HANDLE *pEvent, const LPVOID *pAddress, const DWORD *pSize, UINT count); typedef BOOL (WINAPI * PFNWGLRELEASEIMAGEBUFFEREVENTSI3DPROC) (HDC hDC, const LPVOID *pAddress, UINT count); #endif #ifndef WGL_I3D_swap_frame_lock #define WGL_I3D_swap_frame_lock 1 #ifdef WGL_WGLEXT_PROTOTYPES extern BOOL WINAPI wglEnableFrameLockI3D (void); extern BOOL WINAPI wglDisableFrameLockI3D (void); extern BOOL WINAPI wglIsEnabledFrameLockI3D (BOOL *); extern BOOL WINAPI wglQueryFrameLockMasterI3D (BOOL *); #endif /* WGL_WGLEXT_PROTOTYPES */ typedef BOOL (WINAPI * PFNWGLENABLEFRAMELOCKI3DPROC) (void); typedef BOOL (WINAPI * PFNWGLDISABLEFRAMELOCKI3DPROC) (void); typedef BOOL (WINAPI * PFNWGLISENABLEDFRAMELOCKI3DPROC) (BOOL *pFlag); typedef BOOL (WINAPI * PFNWGLQUERYFRAMELOCKMASTERI3DPROC) (BOOL *pFlag); #endif #ifndef WGL_I3D_swap_frame_usage #define WGL_I3D_swap_frame_usage 1 #ifdef WGL_WGLEXT_PROTOTYPES extern BOOL WINAPI wglGetFrameUsageI3D (float *); extern BOOL WINAPI wglBeginFrameTrackingI3D (void); extern BOOL WINAPI wglEndFrameTrackingI3D (void); extern BOOL WINAPI wglQueryFrameTrackingI3D (DWORD *, DWORD *, float *); #endif /* WGL_WGLEXT_PROTOTYPES */ typedef BOOL (WINAPI * PFNWGLGETFRAMEUSAGEI3DPROC) (float *pUsage); typedef BOOL (WINAPI * PFNWGLBEGINFRAMETRACKINGI3DPROC) (void); typedef BOOL (WINAPI * PFNWGLENDFRAMETRACKINGI3DPROC) (void); typedef BOOL (WINAPI * PFNWGLQUERYFRAMETRACKINGI3DPROC) (DWORD *pFrameCount, DWORD *pMissedFrames, float *pLastMissedUsage); #endif #ifndef WGL_ATI_pixel_format_float #define WGL_ATI_pixel_format_float 1 #endif #ifndef WGL_NV_float_buffer #define WGL_NV_float_buffer 1 #endif #ifndef WGL_EXT_pixel_format_packed_float #define WGL_EXT_pixel_format_packed_float 1 #endif #ifndef WGL_EXT_framebuffer_sRGB #define WGL_EXT_framebuffer_sRGB 1 #endif #ifndef WGL_NV_present_video #define WGL_NV_present_video 1 #ifdef WGL_WGLEXT_PROTOTYPES extern int WINAPI wglEnumerateVideoDevicesNV (HDC, HVIDEOOUTPUTDEVICENV *); extern BOOL WINAPI wglBindVideoDeviceNV (HDC, unsigned int, HVIDEOOUTPUTDEVICENV, const int *); extern BOOL WINAPI wglQueryCurrentContextNV (int, int *); #endif /* WGL_WGLEXT_PROTOTYPES */ typedef int (WINAPI * PFNWGLENUMERATEVIDEODEVICESNVPROC) (HDC hDC, HVIDEOOUTPUTDEVICENV *phDeviceList); typedef BOOL (WINAPI * PFNWGLBINDVIDEODEVICENVPROC) (HDC hDC, unsigned int uVideoSlot, HVIDEOOUTPUTDEVICENV hVideoDevice, const int *piAttribList); typedef BOOL (WINAPI * PFNWGLQUERYCURRENTCONTEXTNVPROC) (int iAttribute, int *piValue); #endif #ifndef WGL_NV_video_out #define WGL_NV_video_out 1 #ifdef WGL_WGLEXT_PROTOTYPES extern BOOL WINAPI wglGetVideoDeviceNV (HDC, int, HPVIDEODEV *); extern BOOL WINAPI wglReleaseVideoDeviceNV (HPVIDEODEV); extern BOOL WINAPI wglBindVideoImageNV (HPVIDEODEV, HPBUFFERARB, int); extern BOOL WINAPI wglReleaseVideoImageNV (HPBUFFERARB, int); extern BOOL WINAPI wglSendPbufferToVideoNV (HPBUFFERARB, int, unsigned long *, BOOL); extern BOOL WINAPI wglGetVideoInfoNV (HPVIDEODEV, unsigned long *, unsigned long *); #endif /* WGL_WGLEXT_PROTOTYPES */ typedef BOOL (WINAPI * PFNWGLGETVIDEODEVICENVPROC) (HDC hDC, int numDevices, HPVIDEODEV *hVideoDevice); typedef BOOL (WINAPI * PFNWGLRELEASEVIDEODEVICENVPROC) (HPVIDEODEV hVideoDevice); typedef BOOL (WINAPI * PFNWGLBINDVIDEOIMAGENVPROC) (HPVIDEODEV hVideoDevice, HPBUFFERARB hPbuffer, int iVideoBuffer); typedef BOOL (WINAPI * PFNWGLRELEASEVIDEOIMAGENVPROC) (HPBUFFERARB hPbuffer, int iVideoBuffer); typedef BOOL (WINAPI * PFNWGLSENDPBUFFERTOVIDEONVPROC) (HPBUFFERARB hPbuffer, int iBufferType, unsigned long *pulCounterPbuffer, BOOL bBlock); typedef BOOL (WINAPI * PFNWGLGETVIDEOINFONVPROC) (HPVIDEODEV hpVideoDevice, unsigned long *pulCounterOutputPbuffer, unsigned long *pulCounterOutputVideo); #endif #ifndef WGL_NV_swap_group #define WGL_NV_swap_group 1 #ifdef WGL_WGLEXT_PROTOTYPES extern BOOL WINAPI wglJoinSwapGroupNV (HDC, GLuint); extern BOOL WINAPI wglBindSwapBarrierNV (GLuint, GLuint); extern BOOL WINAPI wglQuerySwapGroupNV (HDC, GLuint *, GLuint *); extern BOOL WINAPI wglQueryMaxSwapGroupsNV (HDC, GLuint *, GLuint *); extern BOOL WINAPI wglQueryFrameCountNV (HDC, GLuint *); extern BOOL WINAPI wglResetFrameCountNV (HDC); #endif /* WGL_WGLEXT_PROTOTYPES */ typedef BOOL (WINAPI * PFNWGLJOINSWAPGROUPNVPROC) (HDC hDC, GLuint group); typedef BOOL (WINAPI * PFNWGLBINDSWAPBARRIERNVPROC) (GLuint group, GLuint barrier); typedef BOOL (WINAPI * PFNWGLQUERYSWAPGROUPNVPROC) (HDC hDC, GLuint *group, GLuint *barrier); typedef BOOL (WINAPI * PFNWGLQUERYMAXSWAPGROUPSNVPROC) (HDC hDC, GLuint *maxGroups, GLuint *maxBarriers); typedef BOOL (WINAPI * PFNWGLQUERYFRAMECOUNTNVPROC) (HDC hDC, GLuint *count); typedef BOOL (WINAPI * PFNWGLRESETFRAMECOUNTNVPROC) (HDC hDC); #endif #ifndef WGL_NV_gpu_affinity #define WGL_NV_gpu_affinity 1 #ifdef WGL_WGLEXT_PROTOTYPES extern BOOL WINAPI wglEnumGpusNV (UINT, HGPUNV *); extern BOOL WINAPI wglEnumGpuDevicesNV (HGPUNV, UINT, PGPU_DEVICE); extern HDC WINAPI wglCreateAffinityDCNV (const HGPUNV *); extern BOOL WINAPI wglEnumGpusFromAffinityDCNV (HDC, UINT, HGPUNV *); extern BOOL WINAPI wglDeleteDCNV (HDC); #endif /* WGL_WGLEXT_PROTOTYPES */ typedef BOOL (WINAPI * PFNWGLENUMGPUSNVPROC) (UINT iGpuIndex, HGPUNV *phGpu); typedef BOOL (WINAPI * PFNWGLENUMGPUDEVICESNVPROC) (HGPUNV hGpu, UINT iDeviceIndex, PGPU_DEVICE lpGpuDevice); typedef HDC (WINAPI * PFNWGLCREATEAFFINITYDCNVPROC) (const HGPUNV *phGpuList); typedef BOOL (WINAPI * PFNWGLENUMGPUSFROMAFFINITYDCNVPROC) (HDC hAffinityDC, UINT iGpuIndex, HGPUNV *hGpu); typedef BOOL (WINAPI * PFNWGLDELETEDCNVPROC) (HDC hdc); #endif #ifdef __cplusplus } #endif #endif ================================================ FILE: ng/Togl2.1/image.c ================================================ /* * SGI rgb file reader borrowed from gltk library */ #include "togl.h" /* added by GG to include windows.h */ #include #include #include #include "image.h" #ifndef SEEK_SET # define SEEK_SET 0 #endif static void tkQuit(void) { exit(0); } /******************************************************************************/ typedef struct _rawImageRec { unsigned short imagic; unsigned short type; unsigned short dim; unsigned short sizeX, sizeY, sizeZ; unsigned long min, max; unsigned long wasteBytes; char name[80]; unsigned long colorMap; FILE *file; unsigned char *tmp, *tmpR, *tmpG, *tmpB, *tmpA; unsigned long rleEnd; GLuint *rowStart; GLint *rowSize; } rawImageRec; /******************************************************************************/ static void ConvertShort(unsigned short *array, long length) { unsigned long b1, b2; unsigned char *ptr; ptr = (unsigned char *) array; while (length--) { b1 = *ptr++; b2 = *ptr++; *array++ = (unsigned short) ((b1 << 8) | b2); } } static void ConvertLong(GLuint *array, long length) { unsigned long b1, b2, b3, b4; unsigned char *ptr; ptr = (unsigned char *) array; while (length--) { b1 = *ptr++; b2 = *ptr++; b3 = *ptr++; b4 = *ptr++; *array++ = (b1 << 24) | (b2 << 16) | (b3 << 8) | (b4); } } static rawImageRec * RawImageOpen(const char *fileName) { union { int testWord; char testByte[4]; } endianTest; rawImageRec *raw; GLenum swapFlag; int x; endianTest.testWord = 1; if (endianTest.testByte[0] == 1) { swapFlag = GL_TRUE; } else { swapFlag = GL_FALSE; } raw = (rawImageRec *) malloc(sizeof (rawImageRec)); if (raw == NULL) { fprintf(stderr, "Out of memory!\n"); tkQuit(); } if ((raw->file = fopen(fileName, "rb")) == NULL) { perror(fileName); tkQuit(); } fread(raw, 1, 12, raw->file); if (swapFlag) { ConvertShort(&raw->imagic, 6); } raw->tmp = (unsigned char *) malloc(raw->sizeX * 256); raw->tmpR = (unsigned char *) malloc(raw->sizeX * 256); raw->tmpG = (unsigned char *) malloc(raw->sizeX * 256); raw->tmpB = (unsigned char *) malloc(raw->sizeX * 256); raw->tmpA = (unsigned char *) malloc(raw->sizeX * 256); if (raw->tmp == NULL || raw->tmpR == NULL || raw->tmpG == NULL || raw->tmpB == NULL || raw->tmpA == NULL) { fprintf(stderr, "Out of memory!\n"); tkQuit(); } if ((raw->type & 0xFF00) == 0x0100) { x = raw->sizeY * raw->sizeZ * sizeof (GLuint); raw->rowStart = (GLuint *) malloc(x); raw->rowSize = (GLint *) malloc(x); if (raw->rowStart == NULL || raw->rowSize == NULL) { fprintf(stderr, "Out of memory!\n"); tkQuit(); } raw->rleEnd = 512 + (2 * x); fseek(raw->file, 512, SEEK_SET); fread(raw->rowStart, 1, x, raw->file); fread(raw->rowSize, 1, x, raw->file); if (swapFlag) { ConvertLong(raw->rowStart, x / sizeof (GLuint)); ConvertLong((GLuint *) raw->rowSize, x / sizeof (GLint)); } } return raw; } static void RawImageClose(rawImageRec * raw) { fclose(raw->file); free(raw->tmp); free(raw->tmpR); free(raw->tmpG); free(raw->tmpB); free(raw->tmpA); free(raw); } static void RawImageGetRow(rawImageRec * raw, unsigned char *buf, int y, int z) { unsigned char *iPtr, *oPtr, pixel; int count; if ((raw->type & 0xFF00) == 0x0100) { fseek(raw->file, raw->rowStart[y + z * raw->sizeY], SEEK_SET); fread(raw->tmp, 1, (unsigned int) raw->rowSize[y + z * raw->sizeY], raw->file); iPtr = raw->tmp; oPtr = buf; while (1) { pixel = *iPtr++; count = (int) (pixel & 0x7F); if (!count) { return; } if (pixel & 0x80) { while (count--) { *oPtr++ = *iPtr++; } } else { pixel = *iPtr++; while (count--) { *oPtr++ = pixel; } } } } else { fseek(raw->file, 512 + (y * raw->sizeX) + (z * raw->sizeX * raw->sizeY), SEEK_SET); fread(buf, 1, raw->sizeX, raw->file); } } static void RawImageGetData(rawImageRec * raw, TK_RGBImageRec * final) { unsigned char *ptr; int i, j; final->data = (unsigned char *) malloc((raw->sizeX + 1) * (raw->sizeY + 1) * 4); if (final->data == NULL) { fprintf(stderr, "Out of memory!\n"); tkQuit(); } ptr = final->data; for (i = 0; i < (int) (raw->sizeY); i++) { RawImageGetRow(raw, raw->tmpR, i, 0); RawImageGetRow(raw, raw->tmpG, i, 1); RawImageGetRow(raw, raw->tmpB, i, 2); if (raw->sizeZ == 4) { /* 4 components */ RawImageGetRow(raw, raw->tmpA, i, 3); for (j = 0; j < (int) (raw->sizeX); j++) { *ptr++ = *(raw->tmpR + j); *ptr++ = *(raw->tmpG + j); *ptr++ = *(raw->tmpB + j); *ptr++ = *(raw->tmpA + j); } } else { /* 3 components */ for (j = 0; j < (int) (raw->sizeX); j++) { *ptr++ = *(raw->tmpR + j); *ptr++ = *(raw->tmpG + j); *ptr++ = *(raw->tmpB + j); } } } } TK_RGBImageRec * tkRGBImageLoad(const char *fileName) { rawImageRec *raw; TK_RGBImageRec *final; raw = RawImageOpen(fileName); final = (TK_RGBImageRec *) malloc(sizeof (TK_RGBImageRec)); if (final == NULL) { fprintf(stderr, "Out of memory!\n"); tkQuit(); } final->sizeX = raw->sizeX; final->sizeY = raw->sizeY; final->sizeZ = raw->sizeZ; RawImageGetData(raw, final); RawImageClose(raw); return final; } /******************************************************************************/ ================================================ FILE: ng/Togl2.1/image.h ================================================ /* image.h */ #ifndef IMAGE_H # define IMAGE_H typedef struct _TK_RGBImageRec { int sizeX, sizeY, sizeZ; unsigned char *data; } TK_RGBImageRec; extern TK_RGBImageRec *tkRGBImageLoad(const char *fileName); #endif ================================================ FILE: ng/Togl2.1/index.c ================================================ /* $Id: index.c,v 1.13 2007/08/03 16:48:50 gregcouch Exp $ */ /* * Togl - a Tk OpenGL widget * Copyright (C) 1996-1997 Brian Paul and Ben Bederson * Copyright (C) 2006-2007 Greg Couch * See the LICENSE file for copyright details. */ /* * An example Togl program using color-index mode. */ #define USE_TOGL_STUBS #include "togl.h" #include #include #undef TCL_STORAGE_CLASS #define TCL_STORAGE_CLASS DLLEXPORT /* Our color indexes: */ static unsigned long black, red, green, blue; /* Rotation angle */ static float Angle = 0; /* * Togl widget create callback. This is called by Tcl/Tk when the widget has * been realized. Here's where one may do some one-time context setup or * initializations. */ static int create_cb(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { Togl *togl; if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "pathName"); return TCL_ERROR; } if (Togl_GetToglFromObj(interp, objv[1], &togl) != TCL_OK) { return TCL_ERROR; } /* allocate color indexes */ black = Togl_AllocColor(togl, 0, 0, 0); red = Togl_AllocColor(togl, 1, 0, 0); green = Togl_AllocColor(togl, 0, 1, 0); blue = Togl_AllocColor(togl, 0, 0, 1); /* If we were using a private read/write colormap we'd setup our color * table with something like this: */ /* * black = 1; Togl_SetColor( togl, black, 0, 0, 0 ); red = 2; * Togl_SetColor( togl, red, 1, 0, 0 ); green = 3; Togl_SetColor( * togl, green, 0, 1, 0 ); blue = 4; Togl_SetColor( togl, blue, 0, * 0, 1 ); */ glShadeModel(GL_FLAT); glDisable(GL_DITHER); return TCL_OK; } /* * Togl widget reshape callback. This is called by Tcl/Tk when the widget * has been resized. Typically, we call glViewport and perhaps setup the * projection matrix. */ static int reshape_cb(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { int width; int height; float aspect; Togl *togl; if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "pathName"); return TCL_ERROR; } if (Togl_GetToglFromObj(interp, objv[1], &togl) != TCL_OK) { return TCL_ERROR; } width = Togl_Width(togl); height = Togl_Height(togl); aspect = (float) width / (float) height; glViewport(0, 0, width, height); /* Set up projection transform */ glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-aspect, aspect, -1, 1, -1, 1); /* Change back to model view transform for rendering */ glMatrixMode(GL_MODELVIEW); return TCL_OK; } /* * Togl widget display callback. This is called by Tcl/Tk when the widget's * contents have to be redrawn. Typically, we clear the color and depth * buffers, render our objects, then swap the front/back color buffers. */ static int display_cb(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { Togl *togl; if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "pathName"); return TCL_ERROR; } if (Togl_GetToglFromObj(interp, objv[1], &togl) != TCL_OK) { return TCL_ERROR; } glClearIndex((float) black); glClear(GL_COLOR_BUFFER_BIT); glPushMatrix(); glTranslatef(0.3f, -0.3f, 0); glRotatef(Angle, 0, 0, 1); glIndexi(red); glBegin(GL_TRIANGLES); glVertex2f(-0.5f, -0.3f); glVertex2f(0.5f, -0.3f); glVertex2f(0, 0.6f); glEnd(); glPopMatrix(); glPushMatrix(); glRotatef(Angle, 0, 0, 1); glIndexi(green); glBegin(GL_TRIANGLES); glVertex2f(-0.5f, -0.3f); glVertex2f(0.5f, -0.3f); glVertex2f(0, 0.6f); glEnd(); glPopMatrix(); glPushMatrix(); glTranslatef(-0.3f, 0.3f, 0); glRotatef(Angle, 0, 0, 1); glIndexi(blue); glBegin(GL_TRIANGLES); glVertex2f(-0.5f, -0.3f); glVertex2f(0.5f, -0.3f); glVertex2f(0, 0.6f); glEnd(); glPopMatrix(); glFlush(); Togl_SwapBuffers(togl); return TCL_OK; } static int timer_cb(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { Togl *togl; if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "pathName"); return TCL_ERROR; } if (Togl_GetToglFromObj(interp, objv[1], &togl) != TCL_OK) { return TCL_ERROR; } Angle += 5.0; Togl_PostRedisplay(togl); return TCL_OK; } EXTERN int Index_Init(Tcl_Interp *interp) { /* * Initialize Tcl and the Togl widget module. */ if (Tcl_InitStubs(interp, "8.1", 0) == NULL || Togl_InitStubs(interp, "2.0", 0) == NULL) { return TCL_ERROR; } /* * Specify the C callback functions for widget creation, display, * and reshape. */ Tcl_CreateObjCommand(interp, "::index::create_cb", create_cb, NULL, NULL); Tcl_CreateObjCommand(interp, "::index::display_cb", display_cb, NULL, NULL); Tcl_CreateObjCommand(interp, "::index::reshape_cb", reshape_cb, NULL, NULL); Tcl_CreateObjCommand(interp, "::index::timer_cb", timer_cb, NULL, NULL); /* * Make a new Togl widget command so the Tcl code can set a C variable. */ /* NONE */ /* * Call Tcl_CreateCommand for application-specific commands, if * they weren't already created by the init procedures called above. */ return TCL_OK; } ================================================ FILE: ng/Togl2.1/index.tcl ================================================ #!/bin/sh # the next line restarts using tclsh \ exec tclsh "$0" "$@" # $Id: index.tcl,v 1.8 2007/08/03 16:48:50 gregcouch Exp $ # Togl - a Tk OpenGL widget # Copyright (C) 1996 Brian Paul and Ben Bederson # Copyright (C) 2006-2007 Greg Couch # See the LICENSE file for copyright details. # A Tk/OpenGL widget demo using color-index mode. package provide index 1.0 # add parent directory to path to find Togl's pkgIndex in current directory if { [file exists pkgIndex.tcl] } { set auto_path [linsert $auto_path 0 ..] } # following load also loads Tk and Togl packages load [file dirname [info script]]/index[info sharedlibextension] # create ::index namespace namespace eval ::index { } proc ::index::setup {} { wm title . "Color index demo" togl .win -width 200 -height 200 -rgba false -double true -privatecmap false -time 10 -timer ::index::timer_cb -create ::index::create_cb -reshape ::index::reshape_cb -display ::index::display_cb button .photo -text "Take Photo" -command ::index::take_photo button .btn -text Quit -command exit pack .win -expand true -fill both pack .photo -expand true -fill both pack .btn -expand true -fill both } proc ::index::take_photo {} { image create photo img .win takephoto img img write image.ppm -format ppm } # Execution starts here! if { [info script] == $argv0 } { ::index::setup } ================================================ FILE: ng/Togl2.1/multisample.tcl ================================================ #!/bin/sh # the next line restarts using tclsh \ exec tclsh "$0" "$@" # $Id: multisample.tcl,v 1.3 2009/03/12 23:59:35 gregcouch Exp $ # Togl - a Tk OpenGL widget # Copyright (C) 1996 Brian Paul and Ben Bederson # Copyright (C) 2006-2007 Greg Couch # See the LICENSE file for copyright details. # An Tk/OpenGL widget demo with two windows, one aliased and the # other multisampled. Reuse C code from double buffering demo. package provide multisample 1.0 # add parent directory to path to find Togl's pkgIndex in current directory if { [file exists pkgIndex.tcl] } { set auto_path [linsert $auto_path 0 ..] } # following load also loads Tk and Togl packages load [file dirname [info script]]/double[info sharedlibextension] # create ::multisample namespace namespace eval ::multisample { } proc multisample::setup {} { wm title . "Multisample vs Aliased" # create first Togl widget togl .o1 -width 200 -height 200 -rgba true -double true -depth true -create double::create_cb -display double::display_cb -reshape double::reshape_cb -multisample false -ident Aliased # create second Togl widget, share display lists with first widget togl .o2 -width 200 -height 200 -rgba true -double true -depth true -create double::create_cb -display double::display_cb -reshape double::reshape_cb -multisample true -ident Multisampled -sharelist Aliased scale .sx -label {X Axis} -from 0 -to 360 -command {::multisample::setAngle x} -orient horizontal scale .sy -label {Y Axis} -from 0 -to 360 -command {::multisample::setAngle y} -orient horizontal button .btn -text Quit -command exit bind .o1 { ::multisample::motion_event [lindex [%W config -width] 4] \ [lindex [%W config -height] 4] \ %x %y } bind .o2 { ::multisample::motion_event [lindex [%W config -width] 4] \ [lindex [%W config -height] 4] \ %x %y } grid rowconfigure . 0 -weight 1 grid columnconfigure . 0 -weight 1 -uniform same grid columnconfigure . 1 -weight 1 -uniform same grid .o1 -row 0 -column 0 -sticky nesw -padx 3 -pady 3 grid .o2 -row 0 -column 1 -sticky nesw -padx 3 -pady 3 #grid .l1 -row 1 -column 0 -sticky ew -padx 3 -pady 3 #grid .l2 -row 1 -column 1 -sticky ew -padx 3 -pady 3 grid .sx -row 2 -column 0 -columnspan 2 -sticky ew grid .sy -row 3 -column 0 -columnspan 2 -sticky ew grid .btn -row 4 -column 0 -columnspan 2 -sticky ew } # This is called when mouse button 1 is pressed and moved in either of # the OpenGL windows. proc multisample::motion_event { width height x y } { .sx set [double::setXrot [expr 360.0 * $y / $height]] .sy set [double::setYrot [expr 360.0 * ($width - $x) / $width]] .o1 postredisplay .o2 postredisplay } # This is called when a slider is changed. proc multisample::setAngle {axis value} { global xAngle yAngle zAngle switch -exact $axis { x {double::setXrot $value double::setXrot $value} y {double::setYrot $value double::setYrot $value} } .o1 postredisplay .o2 postredisplay } # Execution starts here! if { [info script] == $argv0 } { ::multisample::setup } ================================================ FILE: ng/Togl2.1/overlay.c ================================================ /* $Id: overlay.c,v 1.10 2007/08/03 16:48:50 gregcouch Exp $ */ /* * Togl - a Tk OpenGL widget * Copyright (C) 1996-1997 Brian Paul and Ben Bederson * Copyright (C) 2006-2007 Greg Couch * See the LICENSE file for copyright details. */ /* * An example Togl program using an overlay. */ #define USE_TOGL_STUBS #include "togl.h" #include #include #undef TCL_STORAGE_CLASS #define TCL_STORAGE_CLASS DLLEXPORT /* Overlay color indexes: */ static unsigned long Red, Green; /* * Togl widget create callback. This is called by Tcl/Tk when the widget has * been realized. Here's where one may do some one-time context setup or * initializations. */ static int create_cb(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { Togl *togl; if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "pathName"); return TCL_ERROR; } if (Togl_GetToglFromObj(interp, objv[1], &togl) != TCL_OK) { return TCL_ERROR; } /* allocate overlay color indexes */ Red = Togl_AllocColorOverlay(togl, 1, 0, 0); Green = Togl_AllocColorOverlay(togl, 0, 1, 0); /* in this demo we always show the overlay */ if (Togl_ExistsOverlay(togl)) { Togl_ShowOverlay(togl); printf("Red and green lines are in the overlay\n"); } else { printf("Sorry, this display doesn't support overlays\n"); } return TCL_OK; } /* * Togl widget reshape callback. This is called by Tcl/Tk when the widget * has been resized. Typically, we call glViewport and perhaps setup the * projection matrix. */ static int reshape_cb(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { int width; int height; float aspect; Togl *togl; if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "pathName"); return TCL_ERROR; } if (Togl_GetToglFromObj(interp, objv[1], &togl) != TCL_OK) { return TCL_ERROR; } width = Togl_Width(togl); height = Togl_Height(togl); aspect = (float) width / (float) height; /* Set up viewing for normal plane's context */ glViewport(0, 0, width, height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-aspect, aspect, -1, 1, -1, 1); glMatrixMode(GL_MODELVIEW); /* Set up viewing for overlay plane's context */ if (Togl_ExistsOverlay(togl)) { Togl_UseLayer(togl, TOGL_OVERLAY); glViewport(0, 0, width, height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-1, 1, -1, 1, -1, 1); glMatrixMode(GL_MODELVIEW); Togl_UseLayer(togl, TOGL_NORMAL); } return TCL_OK; } /* * Togl widget overlay display callback. This is called by Tcl/Tk when the * overlay has to be redrawn. */ static int overlay_display_cb(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { glClear(GL_COLOR_BUFFER_BIT); glIndexi(Red); glBegin(GL_LINES); glVertex2f(-1, -1); glVertex2f(1, 1); glVertex2f(-1, 1); glVertex2f(1, -1); glEnd(); glIndexi(Green); glBegin(GL_LINE_LOOP); glVertex2f(-0.5f, -0.5f); glVertex2f(0.5f, -0.5f); glVertex2f(0.5f, 0.5f); glVertex2f(-0.5f, 0.5f); glEnd(); glFlush(); return TCL_OK; } /* * Togl widget display callback. This is called by Tcl/Tk when the widget's * contents have to be redrawn. Typically, we clear the color and depth * buffers, render our objects, then swap the front/back color buffers. */ static int display_cb(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { glClear(GL_COLOR_BUFFER_BIT); glLoadIdentity(); glBegin(GL_TRIANGLES); glColor3f(1, 0, 1); glVertex2f(-0.5f, -0.3f); glVertex2f(0.5f, -0.3f); glVertex2f(0, 0.6f); glColor3f(1, 1, 0); glVertex2f(-0.5f + 0.2f, -0.3f - 0.2f); glVertex2f(0.5f + 0.2f, -0.3f - 0.2f); glVertex2f(0 + 0.2f, 0.6f - 0.2f); glColor3f(0, 1, 1); glVertex2f(-0.5f + 0.4f, -0.3f - 0.4f); glVertex2f(0.5f + 0.4f, -0.3f - 0.4f); glVertex2f(0 + 0.4f, 0.6f - 0.4f); glEnd(); glFlush(); return TCL_OK; } /* * Called by Tcl to let me initialize the modules (Togl) I will need. */ EXTERN int Overlay_Init(Tcl_Interp *interp) { /* * Initialize Tcl and the Togl widget module. */ if (Tcl_InitStubs(interp, "8.1", 0) == NULL || Togl_InitStubs(interp, "2.0", 0) == NULL) { return TCL_ERROR; } /* * Specify the C callback functions for widget creation, display, * and reshape. */ Tcl_CreateObjCommand(interp, "create_cb", create_cb, NULL, NULL); Tcl_CreateObjCommand(interp, "display_cb", display_cb, NULL, NULL); Tcl_CreateObjCommand(interp, "reshape_cb", reshape_cb, NULL, NULL); Tcl_CreateObjCommand(interp, "overlay_display_cb", overlay_display_cb, NULL, NULL); /* * Make a new Togl widget command so the Tcl code can set a C variable. */ /* NONE */ /* * Call Tcl_CreateCommand for application-specific commands, if * they weren't already created by the init procedures called above. */ return TCL_OK; } ================================================ FILE: ng/Togl2.1/overlay.tcl ================================================ #!/bin/sh # the next line restarts using tclsh \ exec tclsh "$0" "$@" # $Id: overlay.tcl,v 1.7 2007/08/03 16:48:50 gregcouch Exp $ # Togl - a Tk OpenGL widget # Copyright (C) 1996 Brian Paul and Ben Bederson # Copyright (C) 2006-2007 Greg Couch # See the LICENSE file for copyright details. # A Tk/OpenGL widget demo using an overlay. # add parent directory to path to find Togl's pkgIndex in current directory if { [file exists pkgIndex.tcl] } { set auto_path [linsert $auto_path 0 ..] } # following load also loads Tk and Togl packages load [file dirname [info script]]/overlay[info sharedlibextension] proc setup {} { wm title . "Overlay demo" togl .win -width 200 -height 200 -rgba true -double false -overlay true -create create_cb -reshape reshape_cb -display display_cb -overlaydisplay overlay_display_cb button .btn -text Quit -command exit pack .win -expand true -fill both pack .btn -expand true -fill both } # Execution starts here! # Execution starts here! if { [info script] == $argv0 } { setup } ================================================ FILE: ng/Togl2.1/pbuffer.c ================================================ /* $Id: pbuffer.c,v 1.2 2009/02/05 06:57:10 gregcouch Exp $ */ /* * Togl - a Tk OpenGL widget * Copyright (C) 1996-1997 Brian Paul and Ben Bederson * Copyright (C) 2006-2007 Greg Couch * See the LICENSE file for copyright details. */ #undef PBUFFER_DEBUG #define USE_TOGL_STUBS #include "togl.h" #include #include #include #if defined(TOGL_AGL) # include # include #elif defined(TOGL_NSOPENGL) # include # include #else # include #endif #include /* OpenGL 1.4 GL_GENERATE_MIPMAP */ #undef TCL_STORAGE_CLASS #define TCL_STORAGE_CLASS DLLEXPORT static double xAngle = 0, yAngle = 0, zAngle = 0; static GLdouble CornerX, CornerY, CornerZ; /* where to print strings */ static GLuint texture; static Togl *output; /* * Togl widget create callback. This is called by Tcl/Tk when the widget has * been realized. Here's where one may do some one-time context setup or * initializations. */ static int create_cb(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { Togl *togl; double version; if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "pathName"); return TCL_ERROR; } if (Togl_GetToglFromObj(interp, objv[1], &togl) != TCL_OK) { return TCL_ERROR; } version = atof((const char *) glGetString(GL_VERSION)); if (version < 1.4) { Tcl_SetResult(interp, "need OpenGL 1.4 or later", TCL_STATIC); return TCL_ERROR; } return TCL_OK; } /* * Togl widget reshape callback. This is called by Tcl/Tk when the widget * has been resized. Typically, we call glViewport and perhaps setup the * projection matrix. */ static int reshape_cb(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { int width; int height; double aspect; Togl *togl; if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "pathName"); return TCL_ERROR; } if (Togl_GetToglFromObj(interp, objv[1], &togl) != TCL_OK) { return TCL_ERROR; } width = Togl_Width(togl); height = Togl_Height(togl); aspect = (double) width / (double) height; glViewport(0, 0, width, height); /* Set up projection transform */ glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustum(-aspect, aspect, -1, 1, 1, 10); CornerX = -aspect; CornerY = -1; CornerZ = -1.1; /* Change back to model view transform for rendering */ glMatrixMode(GL_MODELVIEW); return TCL_OK; } /* * Togl widget reshape callback. This is called by Tcl/Tk when the widget * has been resized. Typically, we call glViewport and perhaps setup the * projection matrix. */ static int reshape2_cb(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { int width; int height; double aspect; Togl *togl; if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "pathName"); return TCL_ERROR; } if (Togl_GetToglFromObj(interp, objv[1], &togl) != TCL_OK) { return TCL_ERROR; } width = Togl_Width(togl); height = Togl_Height(togl); aspect = (double) width / (double) height; glViewport(0, 0, width, height); /* Set up projection transform */ glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-aspect, aspect, -1, 1, -1, 1); /* Change back to model view transform for rendering */ glMatrixMode(GL_MODELVIEW); glLoadIdentity(); return TCL_OK; } static void draw_object() { static GLuint cubeList = 0; glLoadIdentity(); /* Reset modelview matrix to the identity * matrix */ glTranslatef(0, 0, -3); /* Move the camera back three units */ glRotated(xAngle, 1, 0, 0); /* Rotate by X, Y, and Z angles */ glRotated(yAngle, 0, 1, 0); glRotated(zAngle, 0, 0, 1); glEnable(GL_DEPTH_TEST); if (!cubeList) { cubeList = glGenLists(1); glNewList(cubeList, GL_COMPILE); /* Front face */ glBegin(GL_QUADS); glColor3f(0, 0.7f, 0.1f); /* Green */ glVertex3f(-1, 1, 1); glVertex3f(1, 1, 1); glVertex3f(1, -1, 1); glVertex3f(-1, -1, 1); /* Back face */ glColor3f(0.9f, 1, 0); /* Yellow */ glVertex3f(-1, 1, -1); glVertex3f(1, 1, -1); glVertex3f(1, -1, -1); glVertex3f(-1, -1, -1); /* Top side face */ glColor3f(0.2f, 0.2f, 1); /* Blue */ glVertex3f(-1, 1, 1); glVertex3f(1, 1, 1); glVertex3f(1, 1, -1); glVertex3f(-1, 1, -1); /* Bottom side face */ glColor3f(0.7f, 0, 0.1f); /* Red */ glVertex3f(-1, -1, 1); glVertex3f(1, -1, 1); glVertex3f(1, -1, -1); glVertex3f(-1, -1, -1); glEnd(); glEndList(); } glCallList(cubeList); } /* * Togl widget display callback. This is called by Tcl/Tk when the widget's * contents have to be redrawn. Typically, we clear the color and depth * buffers, render our objects, then swap the front/back color buffers. */ static int display_cb(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { Togl *togl; if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "pathName"); return TCL_ERROR; } if (Togl_GetToglFromObj(interp, objv[1], &togl) != TCL_OK) return TCL_ERROR; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); draw_object(); #ifdef PBUFFER_DEBUG { Tk_PhotoHandle photo; /* first tcl: image create photo test */ photo = Tk_FindPhoto(interp, "test2"); if (photo == NULL) { fprintf(stderr, "missing tk photo object test2\n"); } else { Togl_TakePhoto(togl, photo); Tcl_Eval(interp, "test2 write test2.ppm -format ppm"); } } #endif Togl_SwapBuffers(togl); return TCL_OK; } /* * Togl widget display callback. This is called by Tcl/Tk when the widget's * contents have to be redrawn. Typically, we clear the color and depth * buffers, render our objects, then swap the front/back color buffers. */ static int display2_cb(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { Togl *togl; if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "pathName"); return TCL_ERROR; } if (Togl_GetToglFromObj(interp, objv[1], &togl) != TCL_OK) return TCL_ERROR; glClear(GL_COLOR_BUFFER_BIT); if (texture) { glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, texture); glBegin(GL_QUADS); glTexCoord2i(0, 0); glVertex2i(-1, -1); glTexCoord2i(1, 0); glVertex2i(1, -1); glTexCoord2i(1, 1); glVertex2i(1, 1); glTexCoord2i(0, 1); glVertex2i(-1, 1); glEnd(); glBindTexture(GL_TEXTURE_2D, 0); } Togl_SwapBuffers(togl); return TCL_OK; } /* * Togl widget display callback. This is called by Tcl/Tk when the widget's * contents have to be redrawn. Typically, we clear the color and depth * buffers, render our objects, then swap the front/back color buffers. */ static int pbuffer_cb(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { Togl *togl; int width; int height; GLenum error; if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "pathName"); return TCL_ERROR; } if (Togl_GetToglFromObj(interp, objv[1], &togl) != TCL_OK) return TCL_ERROR; width = Togl_Width(togl); height = Togl_Height(togl); if (texture == 0) { glGenTextures(1, &texture); glBindTexture(GL_TEXTURE_2D, texture); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); #if !defined(TOGL_AGL) && !defined(TOGL_NSOPENGL) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); #else glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); #endif glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_BYTE, NULL); glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); glBindTexture(GL_TEXTURE_2D, 0); error = glGetError(); if (error != GL_NO_ERROR) { fprintf(stderr, "texture init: %s\n", gluErrorString(error)); } #if 0 && defined(TOGL_AGL) AGLContext ctx = aglGetCurrentContext(); AGLPbuffer pbuf; GLint face, level, screen; GLenum err; aglGetPBuffer(ctx, &pbuf, &face, &level, &screen); err = aglGetError(); if (err != AGL_NO_ERROR) fprintf(stderr, "getPBuffer: %s\n", aglErrorString(err)); aglTexImagePBuffer(ctx, pbuf, GL_FRONT); err = aglGetError(); if (err != AGL_NO_ERROR) fprintf(stderr, "teximagepbuffer: %s\n", aglErrorString(err)); #endif } glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); draw_object(); #if 1 || !defined(TOGL_AGL) glBindTexture(GL_TEXTURE_2D, texture); glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, width, height); glBindTexture(GL_TEXTURE_2D, 0); error = glGetError(); if (error != GL_NO_ERROR) { fprintf(stderr, "after tex copy: %s\n", gluErrorString(error)); } #endif #ifdef PBUFFER_DEBUG { Tk_PhotoHandle photo; /* first tcl: image create photo test */ photo = Tk_FindPhoto(interp, "test"); Togl_TakePhoto(togl, photo); Tcl_Eval(interp, "test write test.ppm -format ppm"); } #endif Togl_SwapBuffers(togl); if (output) Togl_PostRedisplay(output); return TCL_OK; } static int setXrot_cb(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "angle"); return TCL_ERROR; } if (Tcl_GetDoubleFromObj(interp, objv[1], &xAngle) != TCL_OK) { return TCL_ERROR; } /* printf( "before %f ", xAngle ); */ xAngle = fmod(xAngle, 360.0); if (xAngle < 0.0) xAngle += 360.0; /* printf( "after %f \n", xAngle ); */ /* Let result string equal value */ Tcl_SetObjResult(interp, objv[1]); return TCL_OK; } static int setYrot_cb(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "angle"); return TCL_ERROR; } if (Tcl_GetDoubleFromObj(interp, objv[1], &yAngle) != TCL_OK) { return TCL_ERROR; } yAngle = fmod(yAngle, 360.0); if (yAngle < 0.0) yAngle += 360.0; /* Let result equal value */ Tcl_SetObjResult(interp, objv[1]); return TCL_OK; } static int setOutput_cb(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "pathName"); return TCL_ERROR; } if (Togl_GetToglFromObj(interp, objv[1], &output) != TCL_OK) return TCL_ERROR; return TCL_OK; } /* * Called by Tcl to let me initialize the modules (Togl) I will need. */ EXTERN int Pbuffer_Init(Tcl_Interp *interp) { /* * Initialize Tcl and the Togl widget module. */ if (Tcl_InitStubs(interp, "8.1", 0) == NULL #ifdef PBUFFER_DEBUG || Tk_InitStubs(interp, "8.1", 0) == NULL #endif || Togl_InitStubs(interp, "2.0", 0) == NULL) { return TCL_ERROR; } /* * Specify the C callback functions for widget creation, display, * and reshape. */ Tcl_CreateObjCommand(interp, "create_cb", create_cb, NULL, NULL); Tcl_CreateObjCommand(interp, "display_cb", display_cb, NULL, NULL); Tcl_CreateObjCommand(interp, "display2_cb", display2_cb, NULL, NULL); Tcl_CreateObjCommand(interp, "pbuffer_cb", pbuffer_cb, NULL, NULL); Tcl_CreateObjCommand(interp, "reshape_cb", reshape_cb, NULL, NULL); Tcl_CreateObjCommand(interp, "reshape2_cb", reshape2_cb, NULL, NULL); /* * Make a new Togl widget command so the Tcl code can set a C variable. */ Tcl_CreateObjCommand(interp, "setXrot", setXrot_cb, NULL, NULL); Tcl_CreateObjCommand(interp, "setYrot", setYrot_cb, NULL, NULL); Tcl_CreateObjCommand(interp, "setOutput", setOutput_cb, NULL, NULL); /* * Call Tcl_CreateCommand for application-specific commands, if * they weren't already created by the init procedures called above. */ return TCL_OK; } ================================================ FILE: ng/Togl2.1/pbuffer.tcl ================================================ #!/bin/sh # the next line restarts using tclsh \ exec tclsh "$0" "$@" # $Id: pbuffer.tcl,v 1.1 2009/01/29 22:45:46 gregcouch Exp $ # Togl - a Tk OpenGL widget # Copyright (C) 1996 Brian Paul and Ben Bederson # Copyright (C) 2006-2007 Greg Couch # See the LICENSE file for copyright details. # An Tk/OpenGL widget demo with two double-buffered OpenGL windows. # The first shows the aliased object, the second show the results of # rendering the same object in a higher resolution Pbuffer and using # texture mapping to antialias it. package provide pbuffer 1.0 # add parent directory to path to find Togl's pkgIndex in current directory if { [file exists pkgIndex.tcl] } { set auto_path [linsert $auto_path 0 ..] } # following load also loads Tk and Togl packages load [file dirname [info script]]/pbuffer[info sharedlibextension] # create ::pbuffer namespace namespace eval ::pbuffer { } proc pbuffer::setup {} { wm title . "Pbuffer test" #debug image create photo test image create photo test2 #end debug # create first Togl widget togl .o1 -width 300 -height 300 -rgba true -double true -depth true -ident main -create create_cb -reshape reshape_cb -display display_cb label .l1 -text "RGB, Z, double" # create second Togl widget, share display lists with first widget, no depth togl .o2 -width 300 -height 300 -rgba true -double true -sharelist main -reshape reshape2_cb -display display2_cb -ident second setOutput .o2 label .l2 -text "RGB from pbuffer texture" # create off-screen pbuffer, share display lists with other widgets # must power of 2 squared in size togl .pbuf -width 2048 -height 2048 -rgba true -depth true -sharelist main -pbuffer 1 -reshape reshape_cb -display pbuffer_cb -ident pbuffer scale .sx -label {X Axis} -from 0 -to 360 -command {::pbuffer::setAngle x} -orient horizontal scale .sy -label {Y Axis} -from 0 -to 360 -command {::pbuffer::setAngle y} -orient horizontal button .btn -text Quit -command exit bind .o1 { ::pbuffer::motion_event [lindex [%W config -width] 4] \ [lindex [%W config -height] 4] \ %x %y } bind .o2 { ::pbuffer::motion_event [lindex [%W config -width] 4] \ [lindex [%W config -height] 4] \ %x %y } grid rowconfigure . 0 -weight 1 grid columnconfigure . 0 -weight 1 -uniform same grid columnconfigure . 1 -weight 1 -uniform same grid .o1 -row 0 -column 0 -sticky nesw -padx 3 -pady 3 grid .o2 -row 0 -column 1 -sticky nesw -padx 3 -pady 3 grid .l1 -row 1 -column 0 -sticky ew -padx 3 -pady 3 grid .l2 -row 1 -column 1 -sticky ew -padx 3 -pady 3 grid .sx -row 2 -column 0 -columnspan 2 -sticky ew grid .sy -row 3 -column 0 -columnspan 2 -sticky ew grid .btn -row 4 -column 0 -columnspan 2 -sticky ew } proc pbuffer::display { } { pbuffer_cb .pbuf .o2 postredisplay } # This is called when mouse button 1 is pressed and moved in either of # the OpenGL windows. proc pbuffer::motion_event { width height x y } { .sx set [setXrot [expr 360.0 * $y / $height]] .sy set [setYrot [expr 360.0 * ($width - $x) / $width]] .o1 postredisplay .pbuf postredisplay } # This is called when a slider is changed. proc pbuffer::setAngle {axis value} { global xAngle yAngle zAngle switch -exact $axis { x {setXrot $value setXrot $value} y {setYrot $value setYrot $value} } .o1 postredisplay .pbuf postredisplay } # Execution starts here! if { [info script] == $argv0 } { ::pbuffer::setup } ================================================ FILE: ng/Togl2.1/pkgIndex.tcl.in ================================================ # # Tcl package index file # package ifneeded @PACKAGE_NAME@ @PACKAGE_VERSION@ \ [list load [file join $dir @PKG_LIB_FILE@]] ================================================ FILE: ng/Togl2.1/stereo.c ================================================ /* $Id: stereo.c,v 1.14 2009/02/07 07:04:50 gregcouch Exp $ */ /* * Togl - a Tk OpenGL widget * Copyright (C) 1996-1997 Brian Paul and Ben Bederson * Copyright (C) 2006-2009 Greg Couch * See the LICENSE file for copyright details. */ #define USE_TOGL_STUBS #include "togl.h" #include #include #undef TCL_STORAGE_CLASS #define TCL_STORAGE_CLASS DLLEXPORT static Tcl_Obj *toglFont; static double xAngle = 0, yAngle = 0, zAngle = 0; static GLfloat CornerX, CornerY, CornerZ; /* where to print strings */ static double coord_scale = 1; /* * Togl widget create callback. This is called by Tcl/Tk when the widget has * been realized. Here's where one may do some one-time context setup or * initializations. */ static int create_cb(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { Togl *togl; if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "pathName"); return TCL_ERROR; } if (Togl_GetToglFromObj(interp, objv[1], &togl) != TCL_OK) { return TCL_ERROR; } return TCL_OK; } /* * Togl widget reshape callback. This is called by Tcl/Tk when the widget * has been resized. Typically, we call glViewport and perhaps setup the * projection matrix. */ static int reshape_cb(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { int width; int height; float aspect; Togl *togl; if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "pathName"); return TCL_ERROR; } if (Togl_GetToglFromObj(interp, objv[1], &togl) != TCL_OK) { return TCL_ERROR; } width = Togl_Width(togl); height = Togl_Height(togl); aspect = (float) width / (float) height; glViewport(0, 0, width, height); /* Set up projection transform */ glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustum(-aspect, aspect, -1, 1, 1, 10); CornerX = -aspect; CornerY = -1; CornerZ = -1.1f; /* Change back to model view transform for rendering */ glMatrixMode(GL_MODELVIEW); return TCL_OK; } static void draw_eye(Togl *togl) { static GLuint cubeList = 0; Togl_Clear(togl, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_PROJECTION); glLoadIdentity(); Togl_Frustum(togl, -1, 1, -1, 1, 1, 10); glMatrixMode(GL_MODELVIEW); if (!cubeList) { cubeList = glGenLists(1); glNewList(cubeList, GL_COMPILE); /* Front face */ glBegin(GL_QUADS); glColor3f(0.4f, 0.8f, 0.4f); /* Green-ish */ glVertex3f(-1, 1, 1); glVertex3f(1, 1, 1); glVertex3f(1, -1, 1); glVertex3f(-1, -1, 1); /* Back face */ glColor3f(0.8f, 0.8f, 0.4f); /* Yellow-ish */ glVertex3f(-1, 1, -1); glVertex3f(1, 1, -1); glVertex3f(1, -1, -1); glVertex3f(-1, -1, -1); /* Top side face */ glColor3f(0.4f, 0.4f, 0.8f); /* Blue-ish */ glVertex3f(-1, 1, 1); glVertex3f(1, 1, 1); glVertex3f(1, 1, -1); glVertex3f(-1, 1, -1); /* Bottom side face */ glColor3f(0.8f, 0.4f, 0.4f); /* Red-ish */ glVertex3f(-1, -1, 1); glVertex3f(1, -1, 1); glVertex3f(1, -1, -1); glVertex3f(-1, -1, -1); glEnd(); glEndList(); } glCallList(cubeList); } /* * Togl widget display callback. This is called by Tcl/Tk when the widget's * contents have to be redrawn. Typically, we clear the color and depth * buffers, render our objects, then swap the front/back color buffers. */ static int display_cb(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { Togl *togl; if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "pathName"); return TCL_ERROR; } if (Togl_GetToglFromObj(interp, objv[1], &togl) != TCL_OK) { return TCL_ERROR; } /* setup modelview matrix */ glLoadIdentity(); /* Reset modelview matrix to the identity * matrix */ glTranslatef(0, 0, -3.0); /* Move the camera back three units */ glScaled(coord_scale, coord_scale, coord_scale); /* Zoom in and out */ glRotated(xAngle, 1, 0, 0); /* Rotate by X, Y, and Z angles */ glRotated(yAngle, 0, 1, 0); glRotated(zAngle, 0, 0, 1); glEnable(GL_DEPTH_TEST); if (Togl_NumEyes(togl) == 1) { /* single eye */ Togl_DrawBuffer(togl, GL_BACK); draw_eye(togl); } else { /* stereo left eye */ Togl_DrawBuffer(togl, GL_BACK_LEFT); draw_eye(togl); /* stereo right eye */ Togl_DrawBuffer(togl, GL_BACK_RIGHT); draw_eye(togl); } glDisable(GL_DEPTH_TEST); glLoadIdentity(); glColor3f(1, 1, 1); glRasterPos3f(CornerX, CornerY, CornerZ); Togl_SwapBuffers(togl); return TCL_OK; } static int setXrot_cb(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { Togl *togl; if (objc != 3) { Tcl_WrongNumArgs(interp, 1, objv, "pathName angle"); return TCL_ERROR; } if (Togl_GetToglFromObj(interp, objv[1], &togl) != TCL_OK) { return TCL_ERROR; } if (Tcl_GetDoubleFromObj(interp, objv[2], &xAngle) != TCL_OK) { return TCL_ERROR; } /* printf( "before %f ", xAngle ); */ if (xAngle < 0) { xAngle += 360; } else if (xAngle > 360) { xAngle -= 360; } /* printf( "after %f \n", xAngle ); */ Togl_PostRedisplay(togl); /* Let result string equal value */ Tcl_SetObjResult(interp, objv[2]); return TCL_OK; } static int setYrot_cb(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { Togl *togl; if (objc != 3) { Tcl_WrongNumArgs(interp, 1, objv, "pathName angle"); return TCL_ERROR; } if (Togl_GetToglFromObj(interp, objv[1], &togl) != TCL_OK) { return TCL_ERROR; } if (Tcl_GetDoubleFromObj(interp, objv[2], &yAngle) != TCL_OK) { return TCL_ERROR; } if (yAngle < 0) { yAngle += 360; } else if (yAngle > 360) { yAngle -= 360; } Togl_PostRedisplay(togl); /* Let result string equal value */ Tcl_SetObjResult(interp, objv[2]); return TCL_OK; } int getXrot_cb(ClientData clientData, Tcl_Interp *interp, int argc, CONST84 char *argv[]) { Tcl_SetObjResult(interp, Tcl_NewDoubleObj(xAngle)); return TCL_OK; } int getYrot_cb(ClientData clientData, Tcl_Interp *interp, int argc, CONST84 char *argv[]) { Tcl_SetObjResult(interp, Tcl_NewDoubleObj(yAngle)); return TCL_OK; } static int coord_scale_cb(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { Togl *togl; if (objc != 3) { Tcl_WrongNumArgs(interp, 1, objv, "pathName value"); return TCL_ERROR; } if (Togl_GetToglFromObj(interp, objv[1], &togl) != TCL_OK) { return TCL_ERROR; } if (Tcl_GetDoubleFromObj(interp, objv[2], &coord_scale) != TCL_OK) { return TCL_ERROR; } Togl_PostRedisplay(togl); /* Let result string equal value */ Tcl_SetObjResult(interp, objv[2]); return TCL_OK; } EXTERN int Stereo_Init(Tcl_Interp *interp) { /* * Initialize Tcl and the Togl widget module. */ if (Tcl_InitStubs(interp, "8.1", 0) == NULL || Togl_InitStubs(interp, "2.0", 0) == NULL) { return TCL_ERROR; } /* * Specify the C callback functions for widget creation, display, * and reshape. */ Tcl_CreateObjCommand(interp, "create_cb", create_cb, NULL, NULL); Tcl_CreateObjCommand(interp, "display_cb", display_cb, NULL, NULL); Tcl_CreateObjCommand(interp, "reshape_cb", reshape_cb, NULL, NULL); Tcl_CreateObjCommand(interp, "setXrot", setXrot_cb, NULL, NULL); Tcl_CreateObjCommand(interp, "setYrot", setYrot_cb, NULL, NULL); Tcl_CreateObjCommand(interp, "coord_scale", coord_scale_cb, NULL, NULL); /* * Call Tcl_CreateCommand for application-specific commands, if * they weren't already created by the init procedures called above. */ Tcl_CreateCommand(interp, "getXrot", getXrot_cb, NULL, NULL); Tcl_CreateCommand(interp, "getYrot", getYrot_cb, NULL, NULL); return TCL_OK; } ================================================ FILE: ng/Togl2.1/stereo.tcl ================================================ #!/bin/sh # the next line restarts using tclsh \ exec tclsh "$0" "$@" # $Id: stereo.tcl,v 1.13 2009/03/31 23:21:13 gregcouch Exp $ # Togl - a Tk OpenGL widget # Copyright (C) 1996 Brian Paul and Ben Bederson # Copyright (C) 2006-2009 Greg Couch # See the LICENSE file for copyright details. # add parent directory to path to find Togl's pkgIndex in current directory if { [file exists pkgIndex.tcl] } { set auto_path [linsert $auto_path 0 ..] } # following load also loads Tk and Togl packages load [file dirname [info script]]/stereo[info sharedlibextension] # create ::stereo namespace namespace eval ::stereo { } variable stereo::mode none proc stereo::setup {} { grid rowconfigure . 0 -weight 1 -minsize 200p grid columnconfigure . 1 -weight 1 -minsize 200p labelframe .c -text "Stereo mode:" grid .c -padx 2 -pady 2 -ipadx 2 -ipady 1 foreach {b} {none native sgioldstyle anaglyph cross-eye wall-eye DTI "row interleaved" "left eye" "right eye" } { set name [string map {- _ " " _} $b] radiobutton .c.b$name -text "$b" -command "::stereo::makeGraphics {$b}" -variable stereo::mode -value "$b" pack .c.b$name -padx 2 -pady 1 -anchor w } scale .sx -label {X Axis} -from 0 -to 360 -command {::stereo::setAngle x} -orient horizontal grid .sx -columnspan 2 -sticky ew scale .sy -label {Y Axis} -from 0 -to 360 -command {::stereo::setAngle y} -orient horizontal grid .sy -columnspan 2 -sticky ew if {[string first IRIX $::tcl_platform(os)] != -1} { label .irix -justify left -wraplength 250p -text "Use /usr/gfx/setmon or /usr/bin/X11/xsetmon to change video mode for native stereo (eg., 1024x768_120s) or sgioldstyle stereo (eg., str_bot) and back." grid .irix -sticky new -columnspan 2 } button .quit -text Close -command exit grid .quit -sticky se -columnspan 2 -padx 2 -pady 2 frame .f -relief groove -borderwidth 2 -bg black grid .f -row 0 -column 1 -sticky news bind . {exit} label .f.error -wraplength 100p -bg black -fg white ::stereo::makeGraphics $stereo::mode } set stereo::count 0 set stereo::gwidget "" proc stereo::makeGraphics {mode} { incr stereo::count set name .f.gr$stereo::count set width 200 set height 200 if { [catch { togl $name -width $width -height $height -rgba true -stereo "$mode" -double true -depth true -sharelist main -create create_cb -display display_cb -reshape reshape_cb -eyeseparation 0.05 -convergence 2.0 -stencil true } error] } { pack forget $stereo::gwidget .f.error configure -text "$error\n\nMake another choice from the stereo modes on the left." pack .f.error -expand 1 -fill both } else { pack forget .f.error $name configure -ident main if { "$stereo::gwidget" != "" } { destroy $stereo::gwidget } set stereo::gwidget $name pack $name -expand 1 -fill both bind $name { ::stereo::motion_event %W \ [lindex [%W config -width] 4] \ [lindex [%W config -height] 4] %x %y } } } # This is called when mouse button 1 is pressed and moved proc stereo::motion_event { widget width height x y } { setXrot $widget [expr 360.0 * $y / $height] setYrot $widget [expr 360.0 * ($width - $x) / $width] # .sx set [expr 360.0 * $y / $height] # .sy set [expr 360.0 * ($width - $x) / $width] .sx set [getXrot] .sy set [getYrot] } # This is called when a slider is changed. proc stereo::setAngle {axis value} { # catch because .f.gr might be a label instead of a Togl widget catch { switch -exact $axis { x {setXrot $stereo::gwidget $value} y {setYrot $stereo::gwidget $value} } } } if { [info script] == $argv0 } { if { $argc == 1 } { set stereo::mode [lindex $argv 0] } ::stereo::setup } ================================================ FILE: ng/Togl2.1/tclconfig/install-sh ================================================ #!/bin/sh # # install - install a program, script, or datafile # This comes from X11R5; it is not part of GNU. # # $XConsortium: install.sh,v 1.2 89/12/18 14:47:22 jim Exp $ # # This script is compatible with the BSD install script, but was written # from scratch. # # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" # put in absolute paths if you don't have them in your path; or use env. vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" instcmd="$mvprog" chmodcmd="" chowncmd="" chgrpcmd="" stripcmd="" rmcmd="$rmprog -f" mvcmd="$mvprog" src="" dst="" while [ x"$1" != x ]; do case $1 in -c) instcmd="$cpprog" shift continue;; -m) chmodcmd="$chmodprog $2" shift shift continue;; -o) chowncmd="$chownprog $2" shift shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; -s) stripcmd="$stripprog" shift continue;; *) if [ x"$src" = x ] then src=$1 else dst=$1 fi shift continue;; esac done if [ x"$src" = x ] then echo "install: no input file specified" exit 1 fi if [ x"$dst" = x ] then echo "install: no destination specified" exit 1 fi # If destination is a directory, append the input filename; if your system # does not like double slashes in filenames, you may need to add some logic if [ -d $dst ] then dst="$dst"/`basename $src` fi # Make a temp file name in the proper directory. dstdir=`dirname $dst` dsttmp=$dstdir/#inst.$$# # Move or copy the file name to the temp name $doit $instcmd $src $dsttmp # and set any options; do chmod last to preserve setuid bits if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; fi if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; fi if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; fi if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; fi # Now rename the file to the real destination. $doit $rmcmd $dst $doit $mvcmd $dsttmp $dst exit 0 ================================================ FILE: ng/Togl2.1/tclconfig/tcl.m4 ================================================ # tcl.m4 -- # # This file provides a set of autoconf macros to help TEA-enable # a Tcl extension. # # Copyright (c) 1999-2000 Ajuba Solutions. # Copyright (c) 2002-2005 ActiveState Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # # RCS: @(#) $Id: tcl.m4,v 1.12 2009/01/08 04:40:39 gregcouch Exp $ AC_PREREQ(2.57) dnl TEA extensions pass us the version of TEA they think they dnl are compatible with (must be set in TEA_INIT below) dnl TEA_VERSION="3.7" # Possible values for key variables defined: # # TEA_WINDOWINGSYSTEM - win32 aqua x11 (mirrors 'tk windowingsystem') # TEA_PLATFORM - windows unix # #------------------------------------------------------------------------ # TEA_PATH_TCLCONFIG -- # # Locate the tclConfig.sh file and perform a sanity check on # the Tcl compile flags # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --with-tcl=... # # Defines the following vars: # TCL_BIN_DIR Full path to the directory containing # the tclConfig.sh file #------------------------------------------------------------------------ AC_DEFUN([TEA_PATH_TCLCONFIG], [ dnl TEA specific: Make sure we are initialized AC_REQUIRE([TEA_INIT]) # # Ok, lets find the tcl configuration # First, look for one uninstalled. # the alternative search directory is invoked by --with-tcl # if test x"${no_tcl}" = x ; then # we reset no_tcl in case something fails here no_tcl=true AC_ARG_WITH(tcl, AC_HELP_STRING([--with-tcl], [directory containing tcl configuration (tclConfig.sh)]), with_tclconfig=${withval}) AC_MSG_CHECKING([for Tcl configuration]) AC_CACHE_VAL(ac_cv_c_tclconfig,[ # First check to see if --with-tcl was specified. if test x"${with_tclconfig}" != x ; then case ${with_tclconfig} in */tclConfig.sh ) if test -f ${with_tclconfig}; then AC_MSG_WARN([--with-tcl argument should refer to directory containing tclConfig.sh, not to tclConfig.sh itself]) with_tclconfig=`echo ${with_tclconfig} | sed 's!/tclConfig\.sh$!!'` fi ;; esac if test -f "${with_tclconfig}/tclConfig.sh" ; then ac_cv_c_tclconfig=`(cd ${with_tclconfig}; pwd)` else AC_MSG_ERROR([${with_tclconfig} directory doesn't contain tclConfig.sh]) fi fi # then check for a private Tcl installation if test x"${ac_cv_c_tclconfig}" = x ; then for i in \ ../tcl \ `ls -dr ../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../tcl[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../tcl[[8-9]].[[0-9]]* 2>/dev/null` \ ../../tcl \ `ls -dr ../../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../../tcl[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../tcl[[8-9]].[[0-9]]* 2>/dev/null` \ ../../../tcl \ `ls -dr ../../../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../../../tcl[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../../tcl[[8-9]].[[0-9]]* 2>/dev/null` ; do if test -f "$i/unix/tclConfig.sh" ; then ac_cv_c_tclconfig=`(cd $i/unix; pwd)` break fi done fi # on Darwin, check in Framework installation locations if test "`uname -s`" = "Darwin" -a x"${ac_cv_c_tclconfig}" = x ; then for i in `ls -d ~/Library/Frameworks 2>/dev/null` \ `ls -d /Library/Frameworks 2>/dev/null` \ `ls -d /Network/Library/Frameworks 2>/dev/null` \ `ls -d /System/Library/Frameworks 2>/dev/null` \ ; do if test -f "$i/Tcl.framework/tclConfig.sh" ; then ac_cv_c_tclconfig=`(cd $i/Tcl.framework; pwd)` break fi done fi # TEA specific: on Windows, check in common installation locations if test "${TEA_PLATFORM}" = "windows" \ -a x"${ac_cv_c_tclconfig}" = x ; then for i in `ls -d C:/Tcl/lib 2>/dev/null` \ `ls -d C:/Progra~1/Tcl/lib 2>/dev/null` \ ; do if test -f "$i/tclConfig.sh" ; then ac_cv_c_tclconfig=`(cd $i; pwd)` break fi done fi # check in a few common install locations if test x"${ac_cv_c_tclconfig}" = x ; then for i in `ls -d ${libdir} 2>/dev/null` \ `ls -d ${exec_prefix}/lib 2>/dev/null` \ `ls -d ${prefix}/lib 2>/dev/null` \ `ls -d /usr/local/lib 2>/dev/null` \ `ls -d /usr/contrib/lib 2>/dev/null` \ `ls -d /usr/lib 2>/dev/null` \ ; do if test -f "$i/tclConfig.sh" ; then ac_cv_c_tclconfig=`(cd $i; pwd)` break fi done fi # check in a few other private locations if test x"${ac_cv_c_tclconfig}" = x ; then for i in \ ${srcdir}/../tcl \ `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]]* 2>/dev/null` ; do if test -f "$i/unix/tclConfig.sh" ; then ac_cv_c_tclconfig=`(cd $i/unix; pwd)` break fi done fi ]) if test x"${ac_cv_c_tclconfig}" = x ; then TCL_BIN_DIR="# no Tcl configs found" AC_MSG_ERROR([Can't find Tcl configuration definitions]) else no_tcl= TCL_BIN_DIR=${ac_cv_c_tclconfig} AC_MSG_RESULT([found ${TCL_BIN_DIR}/tclConfig.sh]) fi fi ]) #------------------------------------------------------------------------ # TEA_PATH_TKCONFIG -- # # Locate the tkConfig.sh file # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --with-tk=... # # Defines the following vars: # TK_BIN_DIR Full path to the directory containing # the tkConfig.sh file #------------------------------------------------------------------------ AC_DEFUN([TEA_PATH_TKCONFIG], [ # # Ok, lets find the tk configuration # First, look for one uninstalled. # the alternative search directory is invoked by --with-tk # if test x"${no_tk}" = x ; then # we reset no_tk in case something fails here no_tk=true AC_ARG_WITH(tk, AC_HELP_STRING([--with-tk], [directory containing tk configuration (tkConfig.sh)]), with_tkconfig=${withval}) AC_MSG_CHECKING([for Tk configuration]) AC_CACHE_VAL(ac_cv_c_tkconfig,[ # First check to see if --with-tkconfig was specified. if test x"${with_tkconfig}" != x ; then case ${with_tkconfig} in */tkConfig.sh ) if test -f ${with_tkconfig}; then AC_MSG_WARN([--with-tk argument should refer to directory containing tkConfig.sh, not to tkConfig.sh itself]) with_tkconfig=`echo ${with_tkconfig} | sed 's!/tkConfig\.sh$!!'` fi ;; esac if test -f "${with_tkconfig}/tkConfig.sh" ; then ac_cv_c_tkconfig=`(cd ${with_tkconfig}; pwd)` else AC_MSG_ERROR([${with_tkconfig} directory doesn't contain tkConfig.sh]) fi fi # then check for a private Tk library if test x"${ac_cv_c_tkconfig}" = x ; then for i in \ ../tk \ `ls -dr ../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../tk[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../tk[[8-9]].[[0-9]]* 2>/dev/null` \ ../../tk \ `ls -dr ../../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../../tk[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../tk[[8-9]].[[0-9]]* 2>/dev/null` \ ../../../tk \ `ls -dr ../../../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../../../tk[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../../tk[[8-9]].[[0-9]]* 2>/dev/null` ; do if test -f "$i/unix/tkConfig.sh" ; then ac_cv_c_tkconfig=`(cd $i/unix; pwd)` break fi done fi # on Darwin, check in Framework installation locations if test "`uname -s`" = "Darwin" -a x"${ac_cv_c_tkconfig}" = x ; then for i in `ls -d ~/Library/Frameworks 2>/dev/null` \ `ls -d /Library/Frameworks 2>/dev/null` \ `ls -d /Network/Library/Frameworks 2>/dev/null` \ `ls -d /System/Library/Frameworks 2>/dev/null` \ ; do if test -f "$i/Tk.framework/tkConfig.sh" ; then ac_cv_c_tkconfig=`(cd $i/Tk.framework; pwd)` break fi done fi # check in a few common install locations if test x"${ac_cv_c_tkconfig}" = x ; then for i in `ls -d ${libdir} 2>/dev/null` \ `ls -d ${exec_prefix}/lib 2>/dev/null` \ `ls -d ${prefix}/lib 2>/dev/null` \ `ls -d /usr/local/lib 2>/dev/null` \ `ls -d /usr/contrib/lib 2>/dev/null` \ `ls -d /usr/lib 2>/dev/null` \ ; do if test -f "$i/tkConfig.sh" ; then ac_cv_c_tkconfig=`(cd $i; pwd)` break fi done fi # TEA specific: on Windows, check in common installation locations if test "${TEA_PLATFORM}" = "windows" \ -a x"${ac_cv_c_tkconfig}" = x ; then for i in `ls -d C:/Tcl/lib 2>/dev/null` \ `ls -d C:/Progra~1/Tcl/lib 2>/dev/null` \ ; do if test -f "$i/tkConfig.sh" ; then ac_cv_c_tkconfig=`(cd $i; pwd)` break fi done fi # check in a few other private locations if test x"${ac_cv_c_tkconfig}" = x ; then for i in \ ${srcdir}/../tk \ `ls -dr ${srcdir}/../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ${srcdir}/../tk[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ${srcdir}/../tk[[8-9]].[[0-9]]* 2>/dev/null` ; do if test -f "$i/unix/tkConfig.sh" ; then ac_cv_c_tkconfig=`(cd $i/unix; pwd)` break fi done fi ]) if test x"${ac_cv_c_tkconfig}" = x ; then TK_BIN_DIR="# no Tk configs found" AC_MSG_ERROR([Can't find Tk configuration definitions]) else no_tk= TK_BIN_DIR=${ac_cv_c_tkconfig} AC_MSG_RESULT([found ${TK_BIN_DIR}/tkConfig.sh]) fi fi ]) #------------------------------------------------------------------------ # TEA_LOAD_TCLCONFIG -- # # Load the tclConfig.sh file # # Arguments: # # Requires the following vars to be set: # TCL_BIN_DIR # # Results: # # Subst the following vars: # TCL_BIN_DIR # TCL_SRC_DIR # TCL_LIB_FILE # #------------------------------------------------------------------------ AC_DEFUN([TEA_LOAD_TCLCONFIG], [ AC_MSG_CHECKING([for existence of ${TCL_BIN_DIR}/tclConfig.sh]) if test -f "${TCL_BIN_DIR}/tclConfig.sh" ; then AC_MSG_RESULT([loading]) . "${TCL_BIN_DIR}/tclConfig.sh" else AC_MSG_RESULT([could not find ${TCL_BIN_DIR}/tclConfig.sh]) fi # eval is required to do the TCL_DBGX substitution eval "TCL_LIB_FILE=\"${TCL_LIB_FILE}\"" eval "TCL_STUB_LIB_FILE=\"${TCL_STUB_LIB_FILE}\"" # If the TCL_BIN_DIR is the build directory (not the install directory), # then set the common variable name to the value of the build variables. # For example, the variable TCL_LIB_SPEC will be set to the value # of TCL_BUILD_LIB_SPEC. An extension should make use of TCL_LIB_SPEC # instead of TCL_BUILD_LIB_SPEC since it will work with both an # installed and uninstalled version of Tcl. if test -f "${TCL_BIN_DIR}/Makefile" ; then TCL_LIB_SPEC=${TCL_BUILD_LIB_SPEC} TCL_STUB_LIB_SPEC=${TCL_BUILD_STUB_LIB_SPEC} TCL_STUB_LIB_PATH=${TCL_BUILD_STUB_LIB_PATH} elif test "`uname -s`" = "Darwin"; then # If Tcl was built as a framework, attempt to use the libraries # from the framework at the given location so that linking works # against Tcl.framework installed in an arbitrary location. case ${TCL_DEFS} in *TCL_FRAMEWORK*) if test -f "${TCL_BIN_DIR}/${TCL_LIB_FILE}"; then for i in "`cd ${TCL_BIN_DIR}; pwd`" \ "`cd ${TCL_BIN_DIR}/../..; pwd`"; do if test "`basename "$i"`" = "${TCL_LIB_FILE}.framework"; then TCL_LIB_SPEC="-F`dirname "$i"` -framework ${TCL_LIB_FILE}" break fi done fi if test -f "${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}"; then TCL_STUB_LIB_SPEC="-L${TCL_BIN_DIR} ${TCL_STUB_LIB_FLAG}" TCL_STUB_LIB_PATH="${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}" fi ;; esac fi # eval is required to do the TCL_DBGX substitution eval "TCL_LIB_FLAG=\"${TCL_LIB_FLAG}\"" eval "TCL_LIB_SPEC=\"${TCL_LIB_SPEC}\"" eval "TCL_STUB_LIB_FLAG=\"${TCL_STUB_LIB_FLAG}\"" eval "TCL_STUB_LIB_SPEC=\"${TCL_STUB_LIB_SPEC}\"" AC_SUBST(TCL_VERSION) AC_SUBST(TCL_BIN_DIR) AC_SUBST(TCL_SRC_DIR) AC_SUBST(TCL_LIB_FILE) AC_SUBST(TCL_LIB_FLAG) AC_SUBST(TCL_LIB_SPEC) AC_SUBST(TCL_STUB_LIB_FILE) AC_SUBST(TCL_STUB_LIB_FLAG) AC_SUBST(TCL_STUB_LIB_SPEC) # TEA specific: AC_SUBST(TCL_LIBS) AC_SUBST(TCL_DEFS) AC_SUBST(TCL_EXTRA_CFLAGS) AC_SUBST(TCL_LD_FLAGS) AC_SUBST(TCL_SHLIB_LD_LIBS) ]) #------------------------------------------------------------------------ # TEA_LOAD_TKCONFIG -- # # Load the tkConfig.sh file # # Arguments: # # Requires the following vars to be set: # TK_BIN_DIR # # Results: # # Sets the following vars that should be in tkConfig.sh: # TK_BIN_DIR #------------------------------------------------------------------------ AC_DEFUN([TEA_LOAD_TKCONFIG], [ AC_MSG_CHECKING([for existence of ${TK_BIN_DIR}/tkConfig.sh]) if test -f "${TK_BIN_DIR}/tkConfig.sh" ; then AC_MSG_RESULT([loading]) . "${TK_BIN_DIR}/tkConfig.sh" else AC_MSG_RESULT([could not find ${TK_BIN_DIR}/tkConfig.sh]) fi # eval is required to do the TK_DBGX substitution eval "TK_LIB_FILE=\"${TK_LIB_FILE}\"" eval "TK_STUB_LIB_FILE=\"${TK_STUB_LIB_FILE}\"" # If the TK_BIN_DIR is the build directory (not the install directory), # then set the common variable name to the value of the build variables. # For example, the variable TK_LIB_SPEC will be set to the value # of TK_BUILD_LIB_SPEC. An extension should make use of TK_LIB_SPEC # instead of TK_BUILD_LIB_SPEC since it will work with both an # installed and uninstalled version of Tcl. if test -f "${TK_BIN_DIR}/Makefile" ; then TK_LIB_SPEC=${TK_BUILD_LIB_SPEC} TK_STUB_LIB_SPEC=${TK_BUILD_STUB_LIB_SPEC} TK_STUB_LIB_PATH=${TK_BUILD_STUB_LIB_PATH} elif test "`uname -s`" = "Darwin"; then # If Tk was built as a framework, attempt to use the libraries # from the framework at the given location so that linking works # against Tk.framework installed in an arbitrary location. case ${TK_DEFS} in *TK_FRAMEWORK*) if test -f "${TK_BIN_DIR}/${TK_LIB_FILE}"; then for i in "`cd ${TK_BIN_DIR}; pwd`" \ "`cd ${TK_BIN_DIR}/../..; pwd`"; do if test "`basename "$i"`" = "${TK_LIB_FILE}.framework"; then TK_LIB_SPEC="-F`dirname "$i"` -framework ${TK_LIB_FILE}" break fi done fi if test -f "${TK_BIN_DIR}/${TK_STUB_LIB_FILE}"; then TK_STUB_LIB_SPEC="-L${TK_BIN_DIR} ${TK_STUB_LIB_FLAG}" TK_STUB_LIB_PATH="${TK_BIN_DIR}/${TK_STUB_LIB_FILE}" fi ;; esac fi # eval is required to do the TK_DBGX substitution eval "TK_LIB_FLAG=\"${TK_LIB_FLAG}\"" eval "TK_LIB_SPEC=\"${TK_LIB_SPEC}\"" eval "TK_STUB_LIB_FLAG=\"${TK_STUB_LIB_FLAG}\"" eval "TK_STUB_LIB_SPEC=\"${TK_STUB_LIB_SPEC}\"" # TEA specific: Ensure windowingsystem is defined if test "${TEA_PLATFORM}" = "unix" ; then case ${TK_DEFS} in *MAC_OSX_TK*) AC_DEFINE(MAC_OSX_TK, 1, [Are we building against Mac OS X TkAqua?]) TEA_WINDOWINGSYSTEM="aqua" ;; *) TEA_WINDOWINGSYSTEM="x11" ;; esac elif test "${TEA_PLATFORM}" = "windows" ; then TEA_WINDOWINGSYSTEM="win32" fi AC_SUBST(TK_VERSION) AC_SUBST(TK_BIN_DIR) AC_SUBST(TK_SRC_DIR) AC_SUBST(TK_LIB_FILE) AC_SUBST(TK_LIB_FLAG) AC_SUBST(TK_LIB_SPEC) AC_SUBST(TK_STUB_LIB_FILE) AC_SUBST(TK_STUB_LIB_FLAG) AC_SUBST(TK_STUB_LIB_SPEC) # TEA specific: AC_SUBST(TK_LIBS) AC_SUBST(TK_XINCLUDES) ]) #------------------------------------------------------------------------ # TEA_PROG_TCLSH # Determine the fully qualified path name of the tclsh executable # in the Tcl build directory or the tclsh installed in a bin # directory. This macro will correctly determine the name # of the tclsh executable even if tclsh has not yet been # built in the build directory. The tclsh found is always # associated with a tclConfig.sh file. This tclsh should be used # only for running extension test cases. It should never be # or generation of files (like pkgIndex.tcl) at build time. # # Arguments # none # # Results # Subst's the following values: # TCLSH_PROG #------------------------------------------------------------------------ AC_DEFUN([TEA_PROG_TCLSH], [ AC_MSG_CHECKING([for tclsh]) if test -f "${TCL_BIN_DIR}/Makefile" ; then # tclConfig.sh is in Tcl build directory if test "${TEA_PLATFORM}" = "windows"; then TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}${EXEEXT}" else TCLSH_PROG="${TCL_BIN_DIR}/tclsh" fi else # tclConfig.sh is in install location if test "${TEA_PLATFORM}" = "windows"; then TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}${EXEEXT}" else TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}.${TCL_MINOR_VERSION}${TCL_DBGX}" fi list="`ls -d ${TCL_BIN_DIR}/../bin 2>/dev/null` \ `ls -d ${TCL_BIN_DIR}/.. 2>/dev/null` \ `ls -d ${TCL_PREFIX}/bin 2>/dev/null`" for i in $list ; do if test -f "$i/${TCLSH_PROG}" ; then REAL_TCL_BIN_DIR="`cd "$i"; pwd`/" break fi done TCLSH_PROG="${REAL_TCL_BIN_DIR}${TCLSH_PROG}" fi AC_MSG_RESULT([${TCLSH_PROG}]) AC_SUBST(TCLSH_PROG) ]) #------------------------------------------------------------------------ # TEA_PROG_WISH # Determine the fully qualified path name of the wish executable # in the Tk build directory or the wish installed in a bin # directory. This macro will correctly determine the name # of the wish executable even if wish has not yet been # built in the build directory. The wish found is always # associated with a tkConfig.sh file. This wish should be used # only for running extension test cases. It should never be # or generation of files (like pkgIndex.tcl) at build time. # # Arguments # none # # Results # Subst's the following values: # WISH_PROG #------------------------------------------------------------------------ AC_DEFUN([TEA_PROG_WISH], [ AC_MSG_CHECKING([for wish]) if test -f "${TK_BIN_DIR}/Makefile" ; then # tkConfig.sh is in Tk build directory if test "${TEA_PLATFORM}" = "windows"; then WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}${EXEEXT}" else WISH_PROG="${TK_BIN_DIR}/wish" fi else # tkConfig.sh is in install location if test "${TEA_PLATFORM}" = "windows"; then WISH_PROG="wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}${EXEEXT}" else WISH_PROG="wish${TK_MAJOR_VERSION}.${TK_MINOR_VERSION}${TK_DBGX}" fi list="`ls -d ${TK_BIN_DIR}/../bin 2>/dev/null` \ `ls -d ${TK_BIN_DIR}/.. 2>/dev/null` \ `ls -d ${TK_PREFIX}/bin 2>/dev/null`" for i in $list ; do if test -f "$i/${WISH_PROG}" ; then REAL_TK_BIN_DIR="`cd "$i"; pwd`/" break fi done WISH_PROG="${REAL_TK_BIN_DIR}${WISH_PROG}" fi AC_MSG_RESULT([${WISH_PROG}]) AC_SUBST(WISH_PROG) ]) #------------------------------------------------------------------------ # TEA_ENABLE_SHARED -- # # Allows the building of shared libraries # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --enable-shared=yes|no # # Defines the following vars: # STATIC_BUILD Used for building import/export libraries # on Windows. # # Sets the following vars: # SHARED_BUILD Value of 1 or 0 #------------------------------------------------------------------------ AC_DEFUN([TEA_ENABLE_SHARED], [ AC_MSG_CHECKING([how to build libraries]) AC_ARG_ENABLE(shared, AC_HELP_STRING([--enable-shared], [build and link with shared libraries (default: on)]), [tcl_ok=$enableval], [tcl_ok=yes]) if test "${enable_shared+set}" = set; then enableval="$enable_shared" tcl_ok=$enableval else tcl_ok=yes fi if test "$tcl_ok" = "yes" ; then AC_MSG_RESULT([shared]) SHARED_BUILD=1 else AC_MSG_RESULT([static]) SHARED_BUILD=0 AC_DEFINE(STATIC_BUILD, 1, [Is this a static build?]) fi AC_SUBST(SHARED_BUILD) ]) #------------------------------------------------------------------------ # TEA_ENABLE_THREADS -- # # Specify if thread support should be enabled. If "yes" is specified # as an arg (optional), threads are enabled by default, "no" means # threads are disabled. "yes" is the default. # # TCL_THREADS is checked so that if you are compiling an extension # against a threaded core, your extension must be compiled threaded # as well. # # Note that it is legal to have a thread enabled extension run in a # threaded or non-threaded Tcl core, but a non-threaded extension may # only run in a non-threaded Tcl core. # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --enable-threads # # Sets the following vars: # THREADS_LIBS Thread library(s) # # Defines the following vars: # TCL_THREADS # _REENTRANT # _THREAD_SAFE # #------------------------------------------------------------------------ AC_DEFUN([TEA_ENABLE_THREADS], [ AC_ARG_ENABLE(threads, AC_HELP_STRING([--enable-threads], [build with threads]), [tcl_ok=$enableval], [tcl_ok=yes]) if test "${enable_threads+set}" = set; then enableval="$enable_threads" tcl_ok=$enableval else tcl_ok=yes fi if test "$tcl_ok" = "yes" -o "${TCL_THREADS}" = 1; then TCL_THREADS=1 if test "${TEA_PLATFORM}" != "windows" ; then # We are always OK on Windows, so check what this platform wants: # USE_THREAD_ALLOC tells us to try the special thread-based # allocator that significantly reduces lock contention AC_DEFINE(USE_THREAD_ALLOC, 1, [Do we want to use the threaded memory allocator?]) AC_DEFINE(_REENTRANT, 1, [Do we want the reentrant OS API?]) if test "`uname -s`" = "SunOS" ; then AC_DEFINE(_POSIX_PTHREAD_SEMANTICS, 1, [Do we really want to follow the standard? Yes we do!]) fi AC_DEFINE(_THREAD_SAFE, 1, [Do we want the thread-safe OS API?]) AC_CHECK_LIB(pthread,pthread_mutex_init,tcl_ok=yes,tcl_ok=no) if test "$tcl_ok" = "no"; then # Check a little harder for __pthread_mutex_init in the same # library, as some systems hide it there until pthread.h is # defined. We could alternatively do an AC_TRY_COMPILE with # pthread.h, but that will work with libpthread really doesn't # exist, like AIX 4.2. [Bug: 4359] AC_CHECK_LIB(pthread, __pthread_mutex_init, tcl_ok=yes, tcl_ok=no) fi if test "$tcl_ok" = "yes"; then # The space is needed THREADS_LIBS=" -lpthread" else AC_CHECK_LIB(pthreads, pthread_mutex_init, tcl_ok=yes, tcl_ok=no) if test "$tcl_ok" = "yes"; then # The space is needed THREADS_LIBS=" -lpthreads" else AC_CHECK_LIB(c, pthread_mutex_init, tcl_ok=yes, tcl_ok=no) if test "$tcl_ok" = "no"; then AC_CHECK_LIB(c_r, pthread_mutex_init, tcl_ok=yes, tcl_ok=no) if test "$tcl_ok" = "yes"; then # The space is needed THREADS_LIBS=" -pthread" else TCL_THREADS=0 AC_MSG_WARN([Do not know how to find pthread lib on your system - thread support disabled]) fi fi fi fi fi else TCL_THREADS=0 fi # Do checking message here to not mess up interleaved configure output AC_MSG_CHECKING([for building with threads]) if test "${TCL_THREADS}" = 1; then AC_DEFINE(TCL_THREADS, 1, [Are we building with threads enabled?]) AC_MSG_RESULT([yes (default)]) else AC_MSG_RESULT([no]) fi # TCL_THREADS sanity checking. See if our request for building with # threads is the same as the way Tcl was built. If not, warn the user. case ${TCL_DEFS} in *THREADS=1*) if test "${TCL_THREADS}" = "0"; then AC_MSG_WARN([ Building ${PACKAGE_NAME} without threads enabled, but building against Tcl that IS thread-enabled. It is recommended to use --enable-threads.]) fi ;; *) if test "${TCL_THREADS}" = "1"; then AC_MSG_WARN([ --enable-threads requested, but building against a Tcl that is NOT thread-enabled. This is an OK configuration that will also run in a thread-enabled core.]) fi ;; esac AC_SUBST(TCL_THREADS) ]) #------------------------------------------------------------------------ # TEA_ENABLE_SYMBOLS -- # # Specify if debugging symbols should be used. # Memory (TCL_MEM_DEBUG) debugging can also be enabled. # # Arguments: # none # # TEA varies from core Tcl in that C|LDFLAGS_DEFAULT receives # the value of C|LDFLAGS_OPTIMIZE|DEBUG already substituted. # Requires the following vars to be set in the Makefile: # CFLAGS_DEFAULT # LDFLAGS_DEFAULT # # Results: # # Adds the following arguments to configure: # --enable-symbols # # Defines the following vars: # CFLAGS_DEFAULT Sets to $(CFLAGS_DEBUG) if true # Sets to $(CFLAGS_OPTIMIZE) if false # LDFLAGS_DEFAULT Sets to $(LDFLAGS_DEBUG) if true # Sets to $(LDFLAGS_OPTIMIZE) if false # DBGX Formerly used as debug library extension; # always blank now. # #------------------------------------------------------------------------ AC_DEFUN([TEA_ENABLE_SYMBOLS], [ dnl TEA specific: Make sure we are initialized AC_REQUIRE([TEA_CONFIG_CFLAGS]) AC_MSG_CHECKING([for build with symbols]) AC_ARG_ENABLE(symbols, AC_HELP_STRING([--enable-symbols], [build with debugging symbols (default: off)]), [tcl_ok=$enableval], [tcl_ok=no]) DBGX="" if test "$tcl_ok" = "no"; then CFLAGS_DEFAULT="${CFLAGS_OPTIMIZE}" LDFLAGS_DEFAULT="${LDFLAGS_OPTIMIZE}" AC_MSG_RESULT([no]) else CFLAGS_DEFAULT="${CFLAGS_DEBUG}" LDFLAGS_DEFAULT="${LDFLAGS_DEBUG}" if test "$tcl_ok" = "yes"; then AC_MSG_RESULT([yes (standard debugging)]) fi fi # TEA specific: if test "${TEA_PLATFORM}" != "windows" ; then LDFLAGS_DEFAULT="${LDFLAGS}" fi AC_SUBST(CFLAGS_DEFAULT) AC_SUBST(LDFLAGS_DEFAULT) AC_SUBST(TCL_DBGX) if test "$tcl_ok" = "mem" -o "$tcl_ok" = "all"; then AC_DEFINE(TCL_MEM_DEBUG, 1, [Is memory debugging enabled?]) fi if test "$tcl_ok" != "yes" -a "$tcl_ok" != "no"; then if test "$tcl_ok" = "all"; then AC_MSG_RESULT([enabled symbols mem debugging]) else AC_MSG_RESULT([enabled $tcl_ok debugging]) fi fi ]) #------------------------------------------------------------------------ # TEA_ENABLE_LANGINFO -- # # Allows use of modern nl_langinfo check for better l10n. # This is only relevant for Unix. # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --enable-langinfo=yes|no (default is yes) # # Defines the following vars: # HAVE_LANGINFO Triggers use of nl_langinfo if defined. # #------------------------------------------------------------------------ AC_DEFUN([TEA_ENABLE_LANGINFO], [ AC_ARG_ENABLE(langinfo, AC_HELP_STRING([--enable-langinfo], [use nl_langinfo if possible to determine encoding at startup, otherwise use old heuristic (default: on)]), [langinfo_ok=$enableval], [langinfo_ok=yes]) HAVE_LANGINFO=0 if test "$langinfo_ok" = "yes"; then AC_CHECK_HEADER(langinfo.h,[langinfo_ok=yes],[langinfo_ok=no]) fi AC_MSG_CHECKING([whether to use nl_langinfo]) if test "$langinfo_ok" = "yes"; then AC_CACHE_VAL(tcl_cv_langinfo_h, [ AC_TRY_COMPILE([#include ], [nl_langinfo(CODESET);], [tcl_cv_langinfo_h=yes],[tcl_cv_langinfo_h=no])]) AC_MSG_RESULT([$tcl_cv_langinfo_h]) if test $tcl_cv_langinfo_h = yes; then AC_DEFINE(HAVE_LANGINFO, 1, [Do we have nl_langinfo()?]) fi else AC_MSG_RESULT([$langinfo_ok]) fi ]) #-------------------------------------------------------------------- # TEA_CONFIG_SYSTEM # # Determine what the system is (some things cannot be easily checked # on a feature-driven basis, alas). This can usually be done via the # "uname" command, but there are a few systems, like Next, where # this doesn't work. # # Arguments: # none # # Results: # Defines the following var: # # system - System/platform/version identification code. # #-------------------------------------------------------------------- AC_DEFUN([TEA_CONFIG_SYSTEM], [ AC_CACHE_CHECK([system version], tcl_cv_sys_version, [ # TEA specific: if test "${TEA_PLATFORM}" = "windows" ; then tcl_cv_sys_version=windows elif test -f /usr/lib/NextStep/software_version; then tcl_cv_sys_version=NEXTSTEP-`awk '/3/,/3/' /usr/lib/NextStep/software_version` else tcl_cv_sys_version=`uname -s`-`uname -r` if test "$?" -ne 0 ; then AC_MSG_WARN([can't find uname command]) tcl_cv_sys_version=unknown else # Special check for weird MP-RAS system (uname returns weird # results, and the version is kept in special file). if test -r /etc/.relid -a "X`uname -n`" = "X`uname -s`" ; then tcl_cv_sys_version=MP-RAS-`awk '{print $[3]}' /etc/.relid` fi if test "`uname -s`" = "AIX" ; then tcl_cv_sys_version=AIX-`uname -v`.`uname -r` fi fi fi ]) system=$tcl_cv_sys_version ]) #-------------------------------------------------------------------- # TEA_CONFIG_CFLAGS # # Try to determine the proper flags to pass to the compiler # for building shared libraries and other such nonsense. # # Arguments: # none # # Results: # # Defines and substitutes the following vars: # # DL_OBJS - Name of the object file that implements dynamic # loading for Tcl on this system. # DL_LIBS - Library file(s) to include in tclsh and other base # applications in order for the "load" command to work. # LDFLAGS - Flags to pass to the compiler when linking object # files into an executable application binary such # as tclsh. # LD_SEARCH_FLAGS-Flags to pass to ld, such as "-R /usr/local/tcl/lib", # that tell the run-time dynamic linker where to look # for shared libraries such as libtcl.so. Depends on # the variable LIB_RUNTIME_DIR in the Makefile. Could # be the same as CC_SEARCH_FLAGS if ${CC} is used to link. # CC_SEARCH_FLAGS-Flags to pass to ${CC}, such as "-Wl,-rpath,/usr/local/tcl/lib", # that tell the run-time dynamic linker where to look # for shared libraries such as libtcl.so. Depends on # the variable LIB_RUNTIME_DIR in the Makefile. # SHLIB_CFLAGS - Flags to pass to cc when compiling the components # of a shared library (may request position-independent # code, among other things). # SHLIB_LD - Base command to use for combining object files # into a shared library. # SHLIB_LD_LIBS - Dependent libraries for the linker to scan when # creating shared libraries. This symbol typically # goes at the end of the "ld" commands that build # shared libraries. The value of the symbol is # "${LIBS}" if all of the dependent libraries should # be specified when creating a shared library. If # dependent libraries should not be specified (as on # SunOS 4.x, where they cause the link to fail, or in # general if Tcl and Tk aren't themselves shared # libraries), then this symbol has an empty string # as its value. # SHLIB_SUFFIX - Suffix to use for the names of dynamically loadable # extensions. An empty string means we don't know how # to use shared libraries on this platform. # LIB_SUFFIX - Specifies everything that comes after the "libfoo" # in a static or shared library name, using the $VERSION variable # to put the version in the right place. This is used # by platforms that need non-standard library names. # Examples: ${VERSION}.so.1.1 on NetBSD, since it needs # to have a version after the .so, and ${VERSION}.a # on AIX, since a shared library needs to have # a .a extension whereas shared objects for loadable # extensions have a .so extension. Defaults to # ${VERSION}${SHLIB_SUFFIX}. # TCL_NEEDS_EXP_FILE - # 1 means that an export file is needed to link to a # shared library. # TCL_EXP_FILE - The name of the installed export / import file which # should be used to link to the Tcl shared library. # Empty if Tcl is unshared. # TCL_BUILD_EXP_FILE - # The name of the built export / import file which # should be used to link to the Tcl shared library. # Empty if Tcl is unshared. # CFLAGS_DEBUG - # Flags used when running the compiler in debug mode # CFLAGS_OPTIMIZE - # Flags used when running the compiler in optimize mode # CFLAGS - Additional CFLAGS added as necessary (usually 64-bit) # #-------------------------------------------------------------------- AC_DEFUN([TEA_CONFIG_CFLAGS], [ dnl TEA specific: Make sure we are initialized AC_REQUIRE([TEA_INIT]) # Step 0.a: Enable 64 bit support? AC_MSG_CHECKING([if 64bit support is requested]) AC_ARG_ENABLE(64bit, AC_HELP_STRING([--enable-64bit], [enable 64bit support (default: off)]), [do64bit=$enableval], [do64bit=no]) AC_MSG_RESULT([$do64bit]) # Step 0.b: Enable Solaris 64 bit VIS support? AC_MSG_CHECKING([if 64bit Sparc VIS support is requested]) AC_ARG_ENABLE(64bit-vis, AC_HELP_STRING([--enable-64bit-vis], [enable 64bit Sparc VIS support (default: off)]), [do64bitVIS=$enableval], [do64bitVIS=no]) AC_MSG_RESULT([$do64bitVIS]) # Force 64bit on with VIS AS_IF([test "$do64bitVIS" = "yes"], [do64bit=yes]) # Step 0.c: Check if visibility support is available. Do this here so # that platform specific alternatives can be used below if this fails. AC_CACHE_CHECK([if compiler supports visibility "hidden"], tcl_cv_cc_visibility_hidden, [ hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -Werror" AC_TRY_LINK([ extern __attribute__((__visibility__("hidden"))) void f(void); void f(void) {}], [f();], tcl_cv_cc_visibility_hidden=yes, tcl_cv_cc_visibility_hidden=no) CFLAGS=$hold_cflags]) AS_IF([test $tcl_cv_cc_visibility_hidden = yes], [ AC_DEFINE(MODULE_SCOPE, [extern __attribute__((__visibility__("hidden")))], [Compiler support for module scope symbols]) ]) # Step 0.d: Disable -rpath support? AC_MSG_CHECKING([if rpath support is requested]) AC_ARG_ENABLE(rpath, AC_HELP_STRING([--disable-rpath], [disable rpath support (default: on)]), [doRpath=$enableval], [doRpath=yes]) AC_MSG_RESULT([$doRpath]) # TEA specific: Cross-compiling options for Windows/CE builds? AS_IF([test "${TEA_PLATFORM}" = windows], [ AC_MSG_CHECKING([if Windows/CE build is requested]) AC_ARG_ENABLE(wince, AC_HELP_STRING([--enable-wince], [enable Win/CE support (where applicable)]), [doWince=$enableval], [doWince=no]) AC_MSG_RESULT([$doWince]) ]) # Step 1: set the variable "system" to hold the name and version number # for the system. TEA_CONFIG_SYSTEM # Step 2: check for existence of -ldl library. This is needed because # Linux can use either -ldl or -ldld for dynamic loading. AC_CHECK_LIB(dl, dlopen, have_dl=yes, have_dl=no) # Require ranlib early so we can override it in special cases below. AC_REQUIRE([AC_PROG_RANLIB]) # Step 3: set configuration options based on system name and version. # This is similar to Tcl's unix/tcl.m4 except that we've added a # "windows" case. do64bit_ok=no LDFLAGS_ORIG="$LDFLAGS" # When ld needs options to work in 64-bit mode, put them in # LDFLAGS_ARCH so they eventually end up in LDFLAGS even if [load] # is disabled by the user. [Bug 1016796] LDFLAGS_ARCH="" TCL_EXPORT_FILE_SUFFIX="" UNSHARED_LIB_SUFFIX="" # TEA specific: use PACKAGE_VERSION instead of VERSION TCL_TRIM_DOTS='`echo ${PACKAGE_VERSION} | tr -d .`' ECHO_VERSION='`echo ${PACKAGE_VERSION}`' TCL_LIB_VERSIONS_OK=ok CFLAGS_DEBUG=-g CFLAGS_OPTIMIZE=-O AS_IF([test "$GCC" = yes], [ # TEA specific: CFLAGS_OPTIMIZE=-O2 CFLAGS_WARNING="-Wall -Wno-implicit-int" ], [CFLAGS_WARNING=""]) TCL_NEEDS_EXP_FILE=0 TCL_BUILD_EXP_FILE="" TCL_EXP_FILE="" dnl FIXME: Replace AC_CHECK_PROG with AC_CHECK_TOOL once cross compiling is fixed. dnl AC_CHECK_TOOL(AR, ar) AC_CHECK_PROG(AR, ar, ar) STLIB_LD='${AR} cr' LD_LIBRARY_PATH_VAR="LD_LIBRARY_PATH" case $system in # TEA specific: windows) # This is a 2-stage check to make sure we have the 64-bit SDK # We have to know where the SDK is installed. # This magic is based on MS Platform SDK for Win2003 SP1 - hobbs # MACHINE is IX86 for LINK, but this is used by the manifest, # which requires x86|amd64|ia64. MACHINE="X86" if test "$do64bit" != "no" ; then if test "x${MSSDK}x" = "xx" ; then MSSDK="C:/Progra~1/Microsoft Platform SDK" fi MSSDK=`echo "$MSSDK" | sed -e 's!\\\!/!g'` PATH64="" case "$do64bit" in amd64|x64|yes) MACHINE="AMD64" ; # default to AMD64 64-bit build PATH64="${MSSDK}/Bin/Win64/x86/AMD64" ;; ia64) MACHINE="IA64" PATH64="${MSSDK}/Bin/Win64" ;; esac if test ! -d "${PATH64}" ; then AC_MSG_WARN([Could not find 64-bit $MACHINE SDK to enable 64bit mode]) AC_MSG_WARN([Ensure latest Platform SDK is installed]) do64bit="no" else AC_MSG_RESULT([ Using 64-bit $MACHINE mode]) do64bit_ok="yes" fi fi if test "$doWince" != "no" ; then if test "$do64bit" != "no" ; then AC_MSG_ERROR([Windows/CE and 64-bit builds incompatible]) fi if test "$GCC" = "yes" ; then AC_MSG_ERROR([Windows/CE and GCC builds incompatible]) fi TEA_PATH_CELIB # Set defaults for common evc4/PPC2003 setup # Currently Tcl requires 300+, possibly 420+ for sockets CEVERSION=420; # could be 211 300 301 400 420 ... TARGETCPU=ARMV4; # could be ARMV4 ARM MIPS SH3 X86 ... ARCH=ARM; # could be ARM MIPS X86EM ... PLATFORM="Pocket PC 2003"; # or "Pocket PC 2002" if test "$doWince" != "yes"; then # If !yes then the user specified something # Reset ARCH to allow user to skip specifying it ARCH= eval `echo $doWince | awk -F, '{ \ if (length([$]1)) { printf "CEVERSION=\"%s\"\n", [$]1; \ if ([$]1 < 400) { printf "PLATFORM=\"Pocket PC 2002\"\n" } }; \ if (length([$]2)) { printf "TARGETCPU=\"%s\"\n", toupper([$]2) }; \ if (length([$]3)) { printf "ARCH=\"%s\"\n", toupper([$]3) }; \ if (length([$]4)) { printf "PLATFORM=\"%s\"\n", [$]4 }; \ }'` if test "x${ARCH}" = "x" ; then ARCH=$TARGETCPU; fi fi OSVERSION=WCE$CEVERSION; if test "x${WCEROOT}" = "x" ; then WCEROOT="C:/Program Files/Microsoft eMbedded C++ 4.0" if test ! -d "${WCEROOT}" ; then WCEROOT="C:/Program Files/Microsoft eMbedded Tools" fi fi if test "x${SDKROOT}" = "x" ; then SDKROOT="C:/Program Files/Windows CE Tools" if test ! -d "${SDKROOT}" ; then SDKROOT="C:/Windows CE Tools" fi fi WCEROOT=`echo "$WCEROOT" | sed -e 's!\\\!/!g'` SDKROOT=`echo "$SDKROOT" | sed -e 's!\\\!/!g'` if test ! -d "${SDKROOT}/${OSVERSION}/${PLATFORM}/Lib/${TARGETCPU}" \ -o ! -d "${WCEROOT}/EVC/${OSVERSION}/bin"; then AC_MSG_ERROR([could not find PocketPC SDK or target compiler to enable WinCE mode [$CEVERSION,$TARGETCPU,$ARCH,$PLATFORM]]) doWince="no" else # We could PATH_NOSPACE these, but that's not important, # as long as we quote them when used. CEINCLUDE="${SDKROOT}/${OSVERSION}/${PLATFORM}/include" if test -d "${CEINCLUDE}/${TARGETCPU}" ; then CEINCLUDE="${CEINCLUDE}/${TARGETCPU}" fi CELIBPATH="${SDKROOT}/${OSVERSION}/${PLATFORM}/Lib/${TARGETCPU}" fi fi if test "$GCC" != "yes" ; then if test "${SHARED_BUILD}" = "0" ; then runtime=-MT else runtime=-MD fi if test "$do64bit" != "no" ; then # All this magic is necessary for the Win64 SDK RC1 - hobbs CC="\"${PATH64}/cl.exe\"" CFLAGS="${CFLAGS} -I\"${MSSDK}/Include\" -I\"${MSSDK}/Include/crt\" -I\"${MSSDK}/Include/crt/sys\"" RC="\"${MSSDK}/bin/rc.exe\"" lflags="-nologo -MACHINE:${MACHINE} -LIBPATH:\"${MSSDK}/Lib/${MACHINE}\"" LINKBIN="\"${PATH64}/link.exe\"" CFLAGS_DEBUG="-nologo -Zi -Od -W3 ${runtime}d" CFLAGS_OPTIMIZE="-nologo -O2 -W2 ${runtime}" # Avoid 'unresolved external symbol __security_cookie' # errors, c.f. http://support.microsoft.com/?id=894573 TEA_ADD_LIBS([bufferoverflowU.lib]) elif test "$doWince" != "no" ; then CEBINROOT="${WCEROOT}/EVC/${OSVERSION}/bin" if test "${TARGETCPU}" = "X86"; then CC="\"${CEBINROOT}/cl.exe\"" else CC="\"${CEBINROOT}/cl${ARCH}.exe\"" fi CFLAGS="$CFLAGS -I\"${CELIB_DIR}/inc\" -I\"${CEINCLUDE}\"" RC="\"${WCEROOT}/Common/EVC/bin/rc.exe\"" arch=`echo ${ARCH} | awk '{print tolower([$]0)}'` defs="${ARCH} _${ARCH}_ ${arch} PALM_SIZE _MT _WINDOWS" if test "${SHARED_BUILD}" = "1" ; then # Static CE builds require static celib as well defs="${defs} _DLL" fi for i in $defs ; do AC_DEFINE_UNQUOTED($i, 1, [WinCE def ]$i) done AC_DEFINE_UNQUOTED(_WIN32_WCE, $CEVERSION, [_WIN32_WCE version]) AC_DEFINE_UNQUOTED(UNDER_CE, $CEVERSION, [UNDER_CE version]) CFLAGS_DEBUG="-nologo -Zi -Od" CFLAGS_OPTIMIZE="-nologo -Ox" lversion=`echo ${CEVERSION} | sed -e 's/\(.\)\(..\)/\1\.\2/'` lflags="-MACHINE:${ARCH} -LIBPATH:\"${CELIBPATH}\" -subsystem:windowsce,${lversion} -nologo" LINKBIN="\"${CEBINROOT}/link.exe\"" AC_SUBST(CELIB_DIR) else RC="rc" lflags="-nologo" LINKBIN="link" CFLAGS_DEBUG="-nologo -Z7 -Od -W3 -WX ${runtime}d" CFLAGS_OPTIMIZE="-nologo -O2 -W2 ${runtime}" fi fi if test "$GCC" = "yes"; then # mingw gcc mode RC="windres" CFLAGS_DEBUG="-g" CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer" SHLIB_LD="$CC -shared" UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' LDFLAGS_CONSOLE="-wl,--subsystem,console ${lflags}" LDFLAGS_WINDOW="-wl,--subsystem,windows ${lflags}" else SHLIB_LD="${LINKBIN} -dll ${lflags}" # link -lib only works when -lib is the first arg STLIB_LD="${LINKBIN} -lib ${lflags}" UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.lib' PATHTYPE=-w # For information on what debugtype is most useful, see: # http://msdn.microsoft.com/library/en-us/dnvc60/html/gendepdebug.asp # and also # http://msdn2.microsoft.com/en-us/library/y0zzbyt4%28VS.80%29.aspx # This essentially turns it all on. LDFLAGS_DEBUG="-debug -debugtype:cv" LDFLAGS_OPTIMIZE="-release" if test "$doWince" != "no" ; then LDFLAGS_CONSOLE="-link ${lflags}" LDFLAGS_WINDOW=${LDFLAGS_CONSOLE} else LDFLAGS_CONSOLE="-link -subsystem:console ${lflags}" LDFLAGS_WINDOW="-link -subsystem:windows ${lflags}" fi fi SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".dll" SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.dll' TCL_LIB_VERSIONS_OK=nodots # Bogus to avoid getting this turned off DL_OBJS="tclLoadNone.obj" ;; AIX-*) AS_IF([test "${TCL_THREADS}" = "1" -a "$GCC" != "yes"], [ # AIX requires the _r compiler when gcc isn't being used case "${CC}" in *_r) # ok ... ;; *) CC=${CC}_r ;; esac AC_MSG_RESULT([Using $CC for compiling with threads]) ]) LIBS="$LIBS -lc" SHLIB_CFLAGS="" SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" LD_LIBRARY_PATH_VAR="LIBPATH" # Check to enable 64-bit flags for compiler/linker on AIX 4+ AS_IF([test "$do64bit" = yes -a "`uname -v`" -gt 3], [ AS_IF([test "$GCC" = yes], [ AC_MSG_WARN([64bit mode not supported with GCC on $system]) ], [ do64bit_ok=yes CFLAGS="$CFLAGS -q64" LDFLAGS_ARCH="-q64" RANLIB="${RANLIB} -X64" AR="${AR} -X64" SHLIB_LD_FLAGS="-b64" ]) ]) AS_IF([test "`uname -m`" = ia64], [ # AIX-5 uses ELF style dynamic libraries on IA-64, but not PPC SHLIB_LD="/usr/ccs/bin/ld -G -z text" # AIX-5 has dl* in libc.so DL_LIBS="" AS_IF([test "$GCC" = yes], [ CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' ], [ CC_SEARCH_FLAGS='-R${LIB_RUNTIME_DIR}' ]) LD_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' ], [ AS_IF([test "$GCC" = yes], [SHLIB_LD='${CC} -shared'], [ SHLIB_LD="/bin/ld -bhalt:4 -bM:SRE -bE:lib.exp -H512 -T512 -bnoentry" ]) SHLIB_LD="${TCL_SRC_DIR}/unix/ldAix ${SHLIB_LD} ${SHLIB_LD_FLAGS}" DL_LIBS="-ldl" CC_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} TCL_NEEDS_EXP_FILE=1 # TEA specific: use PACKAGE_VERSION instead of VERSION TCL_EXPORT_FILE_SUFFIX='${PACKAGE_VERSION}.exp' ]) # AIX v<=4.1 has some different flags than 4.2+ AS_IF([test "$system" = "AIX-4.1" -o "`uname -v`" -lt 4], [ AC_LIBOBJ([tclLoadAix]) DL_LIBS="-lld" ]) # On AIX <=v4 systems, libbsd.a has to be linked in to support # non-blocking file IO. This library has to be linked in after # the MATH_LIBS or it breaks the pow() function. The way to # insure proper sequencing, is to add it to the tail of MATH_LIBS. # This library also supplies gettimeofday. # # AIX does not have a timezone field in struct tm. When the AIX # bsd library is used, the timezone global and the gettimeofday # methods are to be avoided for timezone deduction instead, we # deduce the timezone by comparing the localtime result on a # known GMT value. AC_CHECK_LIB(bsd, gettimeofday, libbsd=yes, libbsd=no) AS_IF([test $libbsd = yes], [ MATH_LIBS="$MATH_LIBS -lbsd" AC_DEFINE(USE_DELTA_FOR_TZ, 1, [Do we need a special AIX hack for timezones?]) ]) ;; BeOS*) SHLIB_CFLAGS="-fPIC" SHLIB_LD='${CC} -nostart' SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" #----------------------------------------------------------- # Check for inet_ntoa in -lbind, for BeOS (which also needs # -lsocket, even if the network functions are in -lnet which # is always linked to, for compatibility. #----------------------------------------------------------- AC_CHECK_LIB(bind, inet_ntoa, [LIBS="$LIBS -lbind -lsocket"]) ;; BSD/OS-2.1*|BSD/OS-3*) SHLIB_CFLAGS="" SHLIB_LD="shlicc -r" SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; BSD/OS-4.*) SHLIB_CFLAGS="-export-dynamic -fPIC" SHLIB_LD='${CC} -shared' SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" LDFLAGS="$LDFLAGS -export-dynamic" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; dgux*) SHLIB_CFLAGS="-K PIC" SHLIB_LD='${CC} -G' SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; HP-UX-*.11.*) # Use updated header definitions where possible AC_DEFINE(_XOPEN_SOURCE_EXTENDED, 1, [Do we want to use the XOPEN network library?]) # TEA specific: Needed by Tcl, but not most extensions #AC_DEFINE(_XOPEN_SOURCE, 1, [Do we want to use the XOPEN network library?]) #LIBS="$LIBS -lxnet" # Use the XOPEN network library AS_IF([test "`uname -m`" = ia64], [ SHLIB_SUFFIX=".so" # Use newer C++ library for C++ extensions #if test "$GCC" != "yes" ; then # CPPFLAGS="-AA" #fi ], [ SHLIB_SUFFIX=".sl" ]) AC_CHECK_LIB(dld, shl_load, tcl_ok=yes, tcl_ok=no) AS_IF([test "$tcl_ok" = yes], [ SHLIB_CFLAGS="+z" SHLIB_LD="ld -b" SHLIB_LD_LIBS='${LIBS}' DL_OBJS="tclLoadShl.o" DL_LIBS="-ldld" LDFLAGS="$LDFLAGS -Wl,-E" CC_SEARCH_FLAGS='-Wl,+s,+b,${LIB_RUNTIME_DIR}:.' LD_SEARCH_FLAGS='+s +b ${LIB_RUNTIME_DIR}:.' LD_LIBRARY_PATH_VAR="SHLIB_PATH" ]) AS_IF([test "$GCC" = yes], [ SHLIB_LD='${CC} -shared' SHLIB_LD_LIBS='${LIBS}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} ]) # Users may want PA-RISC 1.1/2.0 portable code - needs HP cc #CFLAGS="$CFLAGS +DAportable" # Check to enable 64-bit flags for compiler/linker AS_IF([test "$do64bit" = "yes"], [ AS_IF([test "$GCC" = yes], [ case `${CC} -dumpmachine` in hppa64*) # 64-bit gcc in use. Fix flags for GNU ld. do64bit_ok=yes SHLIB_LD='${CC} -shared' SHLIB_LD_LIBS='${LIBS}' AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} ;; *) AC_MSG_WARN([64bit mode not supported with GCC on $system]) ;; esac ], [ do64bit_ok=yes CFLAGS="$CFLAGS +DD64" LDFLAGS_ARCH="+DD64" ]) ]) ;; HP-UX-*.08.*|HP-UX-*.09.*|HP-UX-*.10.*) SHLIB_SUFFIX=".sl" AC_CHECK_LIB(dld, shl_load, tcl_ok=yes, tcl_ok=no) AS_IF([test "$tcl_ok" = yes], [ SHLIB_CFLAGS="+z" SHLIB_LD="ld -b" SHLIB_LD_LIBS="" DL_OBJS="tclLoadShl.o" DL_LIBS="-ldld" LDFLAGS="$LDFLAGS -Wl,-E" CC_SEARCH_FLAGS='-Wl,+s,+b,${LIB_RUNTIME_DIR}:.' LD_SEARCH_FLAGS='+s +b ${LIB_RUNTIME_DIR}:.' LD_LIBRARY_PATH_VAR="SHLIB_PATH" ]) ;; IRIX-5.*) SHLIB_CFLAGS="" SHLIB_LD="ld -shared -rdata_shared" SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}']) ;; IRIX-6.*) SHLIB_CFLAGS="" SHLIB_LD="ld -n32 -shared -rdata_shared" SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}']) AS_IF([test "$GCC" = yes], [ CFLAGS="$CFLAGS -mabi=n32" LDFLAGS="$LDFLAGS -mabi=n32" ], [ case $system in IRIX-6.3) # Use to build 6.2 compatible binaries on 6.3. CFLAGS="$CFLAGS -n32 -D_OLD_TERMIOS" ;; *) CFLAGS="$CFLAGS -n32" ;; esac LDFLAGS="$LDFLAGS -n32" ]) ;; IRIX64-6.*) SHLIB_CFLAGS="" SHLIB_LD="ld -n32 -shared -rdata_shared" SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}']) # Check to enable 64-bit flags for compiler/linker AS_IF([test "$do64bit" = yes], [ AS_IF([test "$GCC" = yes], [ AC_MSG_WARN([64bit mode not supported by gcc]) ], [ do64bit_ok=yes SHLIB_LD="ld -64 -shared -rdata_shared" CFLAGS="$CFLAGS -64" LDFLAGS_ARCH="-64" ]) ]) ;; Linux*) SHLIB_CFLAGS="-fPIC" SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" # TEA specific: CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer" # egcs-2.91.66 on Redhat Linux 6.0 generates lots of warnings # when you inline the string and math operations. Turn this off to # get rid of the warnings. #CFLAGS_OPTIMIZE="${CFLAGS_OPTIMIZE} -D__NO_STRING_INLINES -D__NO_MATH_INLINES" # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS SHLIB_LD='${CC} -shared ${CFLAGS} ${LDFLAGS_DEFAULT}' DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" LDFLAGS="$LDFLAGS -Wl,--export-dynamic" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} AS_IF([test "`uname -m`" = "alpha"], [CFLAGS="$CFLAGS -mieee"]) AS_IF([test $do64bit = yes], [ AC_CACHE_CHECK([if compiler accepts -m64 flag], tcl_cv_cc_m64, [ hold_cflags=$CFLAGS CFLAGS="$CFLAGS -m64" AC_TRY_LINK(,, tcl_cv_cc_m64=yes, tcl_cv_cc_m64=no) CFLAGS=$hold_cflags]) AS_IF([test $tcl_cv_cc_m64 = yes], [ CFLAGS="$CFLAGS -m64" do64bit_ok=yes ]) ]) # The combo of gcc + glibc has a bug related to inlining of # functions like strtod(). The -fno-builtin flag should address # this problem but it does not work. The -fno-inline flag is kind # of overkill but it works. Disable inlining only when one of the # files in compat/*.c is being linked in. AS_IF([test x"${USE_COMPAT}" != x],[CFLAGS="$CFLAGS -fno-inline"]) ;; GNU*) SHLIB_CFLAGS="-fPIC" SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" SHLIB_LD='${CC} -shared' DL_OBJS="" DL_LIBS="-ldl" LDFLAGS="$LDFLAGS -Wl,--export-dynamic" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" AS_IF([test "`uname -m`" = "alpha"], [CFLAGS="$CFLAGS -mieee"]) ;; Lynx*) SHLIB_CFLAGS="-fPIC" SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" CFLAGS_OPTIMIZE=-02 SHLIB_LD='${CC} -shared' DL_OBJS="tclLoadDl.o" DL_LIBS="-mshared -ldl" LD_FLAGS="-Wl,--export-dynamic" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) ;; MP-RAS-02*) SHLIB_CFLAGS="-K PIC" SHLIB_LD='${CC} -G' SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; MP-RAS-*) SHLIB_CFLAGS="-K PIC" SHLIB_LD='${CC} -G' SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" LDFLAGS="$LDFLAGS -Wl,-Bexport" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; NetBSD-1.*|FreeBSD-[[1-2]].*) SHLIB_CFLAGS="-fPIC" SHLIB_LD="ld -Bshareable -x" SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}']) AC_CACHE_CHECK([for ELF], tcl_cv_ld_elf, [ AC_EGREP_CPP(yes, [ #ifdef __ELF__ yes #endif ], tcl_cv_ld_elf=yes, tcl_cv_ld_elf=no)]) AS_IF([test $tcl_cv_ld_elf = yes], [ SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so' ], [ SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so.1.0' ]) # Ancient FreeBSD doesn't handle version numbers with dots. UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' TCL_LIB_VERSIONS_OK=nodots ;; OpenBSD-*) SHLIB_CFLAGS="-fPIC" SHLIB_LD='${CC} -shared ${SHLIB_CFLAGS}' SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so.1.0' AC_CACHE_CHECK([for ELF], tcl_cv_ld_elf, [ AC_EGREP_CPP(yes, [ #ifdef __ELF__ yes #endif ], tcl_cv_ld_elf=yes, tcl_cv_ld_elf=no)]) AS_IF([test $tcl_cv_ld_elf = yes], [ LDFLAGS=-Wl,-export-dynamic ], [LDFLAGS=""]) # OpenBSD doesn't do version numbers with dots. UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' TCL_LIB_VERSIONS_OK=nodots ;; NetBSD-*|FreeBSD-*) # FreeBSD 3.* and greater have ELF. # NetBSD 2.* has ELF and can use 'cc -shared' to build shared libs SHLIB_CFLAGS="-fPIC" SHLIB_LD='${CC} -shared ${SHLIB_CFLAGS}' SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" LDFLAGS="$LDFLAGS -export-dynamic" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} AS_IF([test "${TCL_THREADS}" = "1"], [ # The -pthread needs to go in the CFLAGS, not LIBS LIBS=`echo $LIBS | sed s/-pthread//` CFLAGS="$CFLAGS -pthread" LDFLAGS="$LDFLAGS -pthread" ]) case $system in FreeBSD-3.*) # FreeBSD-3 doesn't handle version numbers with dots. UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so' TCL_LIB_VERSIONS_OK=nodots ;; esac ;; Darwin-*) CFLAGS_OPTIMIZE="-Os" SHLIB_CFLAGS="-fno-common" # To avoid discrepancies between what headers configure sees during # preprocessing tests and compiling tests, move any -isysroot and # -mmacosx-version-min flags from CFLAGS to CPPFLAGS: CPPFLAGS="${CPPFLAGS} `echo " ${CFLAGS}" | \ awk 'BEGIN {FS=" +-";ORS=" "}; {for (i=2;i<=NF;i++) \ if ([$]i~/^(isysroot|mmacosx-version-min)/) print "-"[$]i}'`" CFLAGS="`echo " ${CFLAGS}" | \ awk 'BEGIN {FS=" +-";ORS=" "}; {for (i=2;i<=NF;i++) \ if (!([$]i~/^(isysroot|mmacosx-version-min)/)) print "-"[$]i}'`" AS_IF([test $do64bit = yes], [ case `arch` in ppc) AC_CACHE_CHECK([if compiler accepts -arch ppc64 flag], tcl_cv_cc_arch_ppc64, [ hold_cflags=$CFLAGS CFLAGS="$CFLAGS -arch ppc64 -mpowerpc64 -mcpu=G5" AC_TRY_LINK(,, tcl_cv_cc_arch_ppc64=yes, tcl_cv_cc_arch_ppc64=no) CFLAGS=$hold_cflags]) AS_IF([test $tcl_cv_cc_arch_ppc64 = yes], [ CFLAGS="$CFLAGS -arch ppc64 -mpowerpc64 -mcpu=G5" do64bit_ok=yes ]);; i386) AC_CACHE_CHECK([if compiler accepts -arch x86_64 flag], tcl_cv_cc_arch_x86_64, [ hold_cflags=$CFLAGS CFLAGS="$CFLAGS -arch x86_64" AC_TRY_LINK(,, tcl_cv_cc_arch_x86_64=yes, tcl_cv_cc_arch_x86_64=no) CFLAGS=$hold_cflags]) AS_IF([test $tcl_cv_cc_arch_x86_64 = yes], [ CFLAGS="$CFLAGS -arch x86_64" do64bit_ok=yes ]);; *) AC_MSG_WARN([Don't know how enable 64-bit on architecture `arch`]);; esac ], [ # Check for combined 32-bit and 64-bit fat build AS_IF([echo "$CFLAGS " |grep -E -q -- '-arch (ppc64|x86_64) ' \ && echo "$CFLAGS " |grep -E -q -- '-arch (ppc|i386) '], [ fat_32_64=yes]) ]) # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS SHLIB_LD='${CC} -dynamiclib ${CFLAGS} ${LDFLAGS_DEFAULT}' AC_CACHE_CHECK([if ld accepts -single_module flag], tcl_cv_ld_single_module, [ hold_ldflags=$LDFLAGS LDFLAGS="$LDFLAGS -dynamiclib -Wl,-single_module" AC_TRY_LINK(, [int i;], tcl_cv_ld_single_module=yes, tcl_cv_ld_single_module=no) LDFLAGS=$hold_ldflags]) AS_IF([test $tcl_cv_ld_single_module = yes], [ SHLIB_LD="${SHLIB_LD} -Wl,-single_module" ]) # TEA specific: link shlib with current and compatibility version flags vers=`echo ${PACKAGE_VERSION} | sed -e 's/^\([[0-9]]\{1,5\}\)\(\(\.[[0-9]]\{1,3\}\)\{0,2\}\).*$/\1\2/p' -e d` SHLIB_LD="${SHLIB_LD} -current_version ${vers:-0} -compatibility_version ${vers:-0}" SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".dylib" DL_OBJS="tclLoadDyld.o" DL_LIBS="" # Don't use -prebind when building for Mac OS X 10.4 or later only: AS_IF([test "`echo "${MACOSX_DEPLOYMENT_TARGET}" | awk -F '10\\.' '{print int([$]2)}'`" -lt 4 -a \ "`echo "${CPPFLAGS}" | awk -F '-mmacosx-version-min=10\\.' '{print int([$]2)}'`" -lt 4], [ LDFLAGS="$LDFLAGS -prebind"]) LDFLAGS="$LDFLAGS -headerpad_max_install_names" AC_CACHE_CHECK([if ld accepts -search_paths_first flag], tcl_cv_ld_search_paths_first, [ hold_ldflags=$LDFLAGS LDFLAGS="$LDFLAGS -Wl,-search_paths_first" AC_TRY_LINK(, [int i;], tcl_cv_ld_search_paths_first=yes, tcl_cv_ld_search_paths_first=no) LDFLAGS=$hold_ldflags]) AS_IF([test $tcl_cv_ld_search_paths_first = yes], [ LDFLAGS="$LDFLAGS -Wl,-search_paths_first" ]) AS_IF([test "$tcl_cv_cc_visibility_hidden" != yes], [ AC_DEFINE(MODULE_SCOPE, [__private_extern__], [Compiler support for module scope symbols]) ]) CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" LD_LIBRARY_PATH_VAR="DYLD_LIBRARY_PATH" # TEA specific: for combined 32 & 64 bit fat builds of Tk # extensions, verify that 64-bit build is possible. AS_IF([test "$fat_32_64" = yes && test -n "${TK_BIN_DIR}"], [ AS_IF([test "${TEA_WINDOWINGSYSTEM}" = x11], [ AC_CACHE_CHECK([for 64-bit X11], tcl_cv_lib_x11_64, [ for v in CFLAGS CPPFLAGS LDFLAGS; do eval 'hold_'$v'="$'$v'";'$v'="`echo "$'$v' "|sed -e "s/-arch ppc / /g" -e "s/-arch i386 / /g"`"' done CPPFLAGS="$CPPFLAGS -I/usr/X11R6/include" LDFLAGS="$LDFLAGS -L/usr/X11R6/lib -lX11" AC_TRY_LINK([#include ], [XrmInitialize();], tcl_cv_lib_x11_64=yes, tcl_cv_lib_x11_64=no) for v in CFLAGS CPPFLAGS LDFLAGS; do eval $v'="$hold_'$v'"' done]) ]) # remove 64-bit arch flags from CFLAGS et al. if configuration # does not support 64-bit. AS_IF([test "${TEA_WINDOWINGSYSTEM}" = aqua -o "$tcl_cv_lib_x11_64" = no], [ AC_MSG_NOTICE([Removing 64-bit architectures from compiler & linker flags]) for v in CFLAGS CPPFLAGS LDFLAGS; do eval $v'="`echo "$'$v' "|sed -e "s/-arch ppc64 / /g" -e "s/-arch x86_64 / /g"`"' done]) ]) ;; NEXTSTEP-*) SHLIB_CFLAGS="" SHLIB_LD='${CC} -nostdlib -r' SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadNext.o" DL_LIBS="" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; OS/390-*) CFLAGS_OPTIMIZE="" # Optimizer is buggy AC_DEFINE(_OE_SOCKETS, 1, # needed in sys/socket.h [Should OS/390 do the right thing with sockets?]) ;; OSF1-1.0|OSF1-1.1|OSF1-1.2) # OSF/1 1.[012] from OSF, and derivatives, including Paragon OSF/1 SHLIB_CFLAGS="" # Hack: make package name same as library name SHLIB_LD='ld -R -export $@:' SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadOSF.o" DL_LIBS="" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; OSF1-1.*) # OSF/1 1.3 from OSF using ELF, and derivatives, including AD2 SHLIB_CFLAGS="-fPIC" AS_IF([test "$SHARED_BUILD" = 1], [SHLIB_LD="ld -shared"], [ SHLIB_LD="ld -non_shared" ]) SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; OSF1-V*) # Digital OSF/1 SHLIB_CFLAGS="" AS_IF([test "$SHARED_BUILD" = 1], [ SHLIB_LD='${CC} -shared' ], [ SHLIB_LD='${CC} -non_shared' ]) SHLIB_LD_LIBS="${LIBS}" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}']) AS_IF([test "$GCC" = yes], [CFLAGS="$CFLAGS -mieee"], [ CFLAGS="$CFLAGS -DHAVE_TZSET -std1 -ieee"]) # see pthread_intro(3) for pthread support on osf1, k.furukawa AS_IF([test "${TCL_THREADS}" = 1], [ CFLAGS="$CFLAGS -DHAVE_PTHREAD_ATTR_SETSTACKSIZE" CFLAGS="$CFLAGS -DTCL_THREAD_STACK_MIN=PTHREAD_STACK_MIN*64" LIBS=`echo $LIBS | sed s/-lpthreads//` AS_IF([test "$GCC" = yes], [ LIBS="$LIBS -lpthread -lmach -lexc" ], [ CFLAGS="$CFLAGS -pthread" LDFLAGS="$LDFLAGS -pthread" ]) ]) ;; QNX-6*) # QNX RTP # This may work for all QNX, but it was only reported for v6. SHLIB_CFLAGS="-fPIC" SHLIB_LD="ld -Bshareable -x" SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" # dlopen is in -lc on QNX DL_LIBS="" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; SCO_SV-3.2*) # Note, dlopen is available only on SCO 3.2.5 and greater. However, # this test works, since "uname -s" was non-standard in 3.2.4 and # below. AS_IF([test "$GCC" = yes], [ SHLIB_CFLAGS="-fPIC -melf" LDFLAGS="$LDFLAGS -melf -Wl,-Bexport" ], [ SHLIB_CFLAGS="-Kpic -belf" LDFLAGS="$LDFLAGS -belf -Wl,-Bexport" ]) SHLIB_LD="ld -G" SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; SINIX*5.4*) SHLIB_CFLAGS="-K PIC" SHLIB_LD='${CC} -G' SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; SunOS-4*) SHLIB_CFLAGS="-PIC" SHLIB_LD="ld" SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" CC_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} # SunOS can't handle version numbers with dots in them in library # specs, like -ltcl7.5, so use -ltcl75 instead. Also, it # requires an extra version number at the end of .so file names. # So, the library has to have a name like libtcl75.so.1.0 SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so.1.0' UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' TCL_LIB_VERSIONS_OK=nodots ;; SunOS-5.[[0-6]]) # Careful to not let 5.10+ fall into this case # Note: If _REENTRANT isn't defined, then Solaris # won't define thread-safe library routines. AC_DEFINE(_REENTRANT, 1, [Do we want the reentrant OS API?]) AC_DEFINE(_POSIX_PTHREAD_SEMANTICS, 1, [Do we really want to follow the standard? Yes we do!]) SHLIB_CFLAGS="-KPIC" # Note: need the LIBS below, otherwise Tk won't find Tcl's # symbols when dynamically loaded into tclsh. SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" AS_IF([test "$GCC" = yes], [ SHLIB_LD='${CC} -shared' CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} ], [ SHLIB_LD="/usr/ccs/bin/ld -G -z text" CC_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} ]) ;; SunOS-5*) # Note: If _REENTRANT isn't defined, then Solaris # won't define thread-safe library routines. AC_DEFINE(_REENTRANT, 1, [Do we want the reentrant OS API?]) AC_DEFINE(_POSIX_PTHREAD_SEMANTICS, 1, [Do we really want to follow the standard? Yes we do!]) SHLIB_CFLAGS="-KPIC" # Check to enable 64-bit flags for compiler/linker AS_IF([test "$do64bit" = yes], [ arch=`isainfo` AS_IF([test "$arch" = "sparcv9 sparc"], [ AS_IF([test "$GCC" = yes], [ AS_IF([test "`${CC} -dumpversion | awk -F. '{print [$]1}'`" -lt 3], [ AC_MSG_WARN([64bit mode not supported with GCC < 3.2 on $system]) ], [ do64bit_ok=yes CFLAGS="$CFLAGS -m64 -mcpu=v9" LDFLAGS="$LDFLAGS -m64 -mcpu=v9" SHLIB_CFLAGS="-fPIC" ]) ], [ do64bit_ok=yes AS_IF([test "$do64bitVIS" = yes], [ CFLAGS="$CFLAGS -xarch=v9a" LDFLAGS_ARCH="-xarch=v9a" ], [ CFLAGS="$CFLAGS -xarch=v9" LDFLAGS_ARCH="-xarch=v9" ]) # Solaris 64 uses this as well #LD_LIBRARY_PATH_VAR="LD_LIBRARY_PATH_64" ]) ], [AS_IF([test "$arch" = "amd64 i386"], [ AS_IF([test "$GCC" = yes], [ case $system in SunOS-5.1[[1-9]]*|SunOS-5.[[2-9]][[0-9]]*) do64bit_ok=yes CFLAGS="$CFLAGS -m64" LDFLAGS="$LDFLAGS -m64";; *) AC_MSG_WARN([64bit mode not supported with GCC on $system]);; esac ], [ do64bit_ok=yes case $system in SunOS-5.1[[1-9]]*|SunOS-5.[[2-9]][[0-9]]*) CFLAGS="$CFLAGS -m64" LDFLAGS="$LDFLAGS -m64";; *) CFLAGS="$CFLAGS -xarch=amd64" LDFLAGS="$LDFLAGS -xarch=amd64";; esac ]) ], [AC_MSG_WARN([64bit mode not supported for $arch])])]) ]) # Note: need the LIBS below, otherwise Tk won't find Tcl's # symbols when dynamically loaded into tclsh. SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" AS_IF([test "$GCC" = yes], [ SHLIB_LD='${CC} -shared' CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} AS_IF([test "$do64bit_ok" = yes], [ AS_IF([test "$arch" = "sparcv9 sparc"], [ # We need to specify -static-libgcc or we need to # add the path to the sparv9 libgcc. # JH: static-libgcc is necessary for core Tcl, but may # not be necessary for extensions. SHLIB_LD="$SHLIB_LD -m64 -mcpu=v9 -static-libgcc" # for finding sparcv9 libgcc, get the regular libgcc # path, remove so name and append 'sparcv9' #v9gcclibdir="`gcc -print-file-name=libgcc_s.so` | ..." #CC_SEARCH_FLAGS="${CC_SEARCH_FLAGS},-R,$v9gcclibdir" ], [AS_IF([test "$arch" = "amd64 i386"], [ # JH: static-libgcc is necessary for core Tcl, but may # not be necessary for extensions. SHLIB_LD="$SHLIB_LD -m64 -static-libgcc" ])]) ]) ], [ case $system in SunOS-5.[[1-9]][[0-9]]*) SHLIB_LD='${CC} -G -z text ${LDFLAGS}';; *) SHLIB_LD='/usr/ccs/bin/ld -G -z text';; esac CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' ]) ;; UNIX_SV* | UnixWare-5*) SHLIB_CFLAGS="-KPIC" SHLIB_LD='${CC} -G' SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" # Some UNIX_SV* systems (unixware 1.1.2 for example) have linkers # that don't grok the -Bexport option. Test that it does. AC_CACHE_CHECK([for ld accepts -Bexport flag], tcl_cv_ld_Bexport, [ hold_ldflags=$LDFLAGS LDFLAGS="$LDFLAGS -Wl,-Bexport" AC_TRY_LINK(, [int i;], tcl_cv_ld_Bexport=yes, tcl_cv_ld_Bexport=no) LDFLAGS=$hold_ldflags]) AS_IF([test $tcl_cv_ld_Bexport = yes], [ LDFLAGS="$LDFLAGS -Wl,-Bexport" ]) CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; esac AS_IF([test "$do64bit" = yes -a "$do64bit_ok" = no], [ AC_MSG_WARN([64bit support being disabled -- don't know magic for this platform]) ]) dnl # Add any CPPFLAGS set in the environment to our CFLAGS, but delay doing so dnl # until the end of configure, as configure's compile and link tests use dnl # both CPPFLAGS and CFLAGS (unlike our compile and link) but configure's dnl # preprocessing tests use only CPPFLAGS. AC_CONFIG_COMMANDS_PRE([CFLAGS="${CFLAGS} ${CPPFLAGS}"; CPPFLAGS=""]) # Step 4: disable dynamic loading if requested via a command-line switch. AC_ARG_ENABLE(load, AC_HELP_STRING([--enable-load], [allow dynamic loading and "load" command (default: on)]), [tcl_ok=$enableval], [tcl_ok=yes]) AS_IF([test "$tcl_ok" = no], [DL_OBJS=""]) AS_IF([test "x$DL_OBJS" != x], [BUILD_DLTEST="\$(DLTEST_TARGETS)"], [ AC_MSG_WARN([Can't figure out how to do dynamic loading or shared libraries on this system.]) SHLIB_CFLAGS="" SHLIB_LD="" SHLIB_SUFFIX="" DL_OBJS="tclLoadNone.o" DL_LIBS="" LDFLAGS="$LDFLAGS_ORIG" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" BUILD_DLTEST="" ]) LDFLAGS="$LDFLAGS $LDFLAGS_ARCH" # If we're running gcc, then change the C flags for compiling shared # libraries to the right flags for gcc, instead of those for the # standard manufacturer compiler. AS_IF([test "$DL_OBJS" != "tclLoadNone.o" -a "$GCC" = yes], [ case $system in AIX-*) ;; BSD/OS*) ;; IRIX*) ;; NetBSD-*|FreeBSD-*) ;; Darwin-*) ;; SCO_SV-3.2*) ;; *) SHLIB_CFLAGS="-fPIC" ;; esac]) AS_IF([test "$SHARED_LIB_SUFFIX" = ""], [ # TEA specific: use PACKAGE_VERSION instead of VERSION SHARED_LIB_SUFFIX='${PACKAGE_VERSION}${SHLIB_SUFFIX}']) AS_IF([test "$UNSHARED_LIB_SUFFIX" = ""], [ # TEA specific: use PACKAGE_VERSION instead of VERSION UNSHARED_LIB_SUFFIX='${PACKAGE_VERSION}.a']) AC_SUBST(DL_LIBS) AC_SUBST(CFLAGS_DEBUG) AC_SUBST(CFLAGS_OPTIMIZE) AC_SUBST(CFLAGS_WARNING) AC_SUBST(STLIB_LD) AC_SUBST(SHLIB_LD) AC_SUBST(SHLIB_LD_LIBS) AC_SUBST(SHLIB_CFLAGS) AC_SUBST(LD_LIBRARY_PATH_VAR) # These must be called after we do the basic CFLAGS checks and # verify any possible 64-bit or similar switches are necessary TEA_TCL_EARLY_FLAGS TEA_TCL_64BIT_FLAGS ]) #-------------------------------------------------------------------- # TEA_SERIAL_PORT # # Determine which interface to use to talk to the serial port. # Note that #include lines must begin in leftmost column for # some compilers to recognize them as preprocessor directives, # and some build environments have stdin not pointing at a # pseudo-terminal (usually /dev/null instead.) # # Arguments: # none # # Results: # # Defines only one of the following vars: # HAVE_SYS_MODEM_H # USE_TERMIOS # USE_TERMIO # USE_SGTTY # #-------------------------------------------------------------------- AC_DEFUN([TEA_SERIAL_PORT], [ AC_CHECK_HEADERS(sys/modem.h) AC_CACHE_CHECK([termios vs. termio vs. sgtty], tcl_cv_api_serial, [ AC_TRY_RUN([ #include int main() { struct termios t; if (tcgetattr(0, &t) == 0) { cfsetospeed(&t, 0); t.c_cflag |= PARENB | PARODD | CSIZE | CSTOPB; return 0; } return 1; }], tcl_cv_api_serial=termios, tcl_cv_api_serial=no, tcl_cv_api_serial=no) if test $tcl_cv_api_serial = no ; then AC_TRY_RUN([ #include int main() { struct termio t; if (ioctl(0, TCGETA, &t) == 0) { t.c_cflag |= CBAUD | PARENB | PARODD | CSIZE | CSTOPB; return 0; } return 1; }], tcl_cv_api_serial=termio, tcl_cv_api_serial=no, tcl_cv_api_serial=no) fi if test $tcl_cv_api_serial = no ; then AC_TRY_RUN([ #include int main() { struct sgttyb t; if (ioctl(0, TIOCGETP, &t) == 0) { t.sg_ospeed = 0; t.sg_flags |= ODDP | EVENP | RAW; return 0; } return 1; }], tcl_cv_api_serial=sgtty, tcl_cv_api_serial=no, tcl_cv_api_serial=no) fi if test $tcl_cv_api_serial = no ; then AC_TRY_RUN([ #include #include int main() { struct termios t; if (tcgetattr(0, &t) == 0 || errno == ENOTTY || errno == ENXIO || errno == EINVAL) { cfsetospeed(&t, 0); t.c_cflag |= PARENB | PARODD | CSIZE | CSTOPB; return 0; } return 1; }], tcl_cv_api_serial=termios, tcl_cv_api_serial=no, tcl_cv_api_serial=no) fi if test $tcl_cv_api_serial = no; then AC_TRY_RUN([ #include #include int main() { struct termio t; if (ioctl(0, TCGETA, &t) == 0 || errno == ENOTTY || errno == ENXIO || errno == EINVAL) { t.c_cflag |= CBAUD | PARENB | PARODD | CSIZE | CSTOPB; return 0; } return 1; }], tcl_cv_api_serial=termio, tcl_cv_api_serial=no, tcl_cv_api_serial=no) fi if test $tcl_cv_api_serial = no; then AC_TRY_RUN([ #include #include int main() { struct sgttyb t; if (ioctl(0, TIOCGETP, &t) == 0 || errno == ENOTTY || errno == ENXIO || errno == EINVAL) { t.sg_ospeed = 0; t.sg_flags |= ODDP | EVENP | RAW; return 0; } return 1; }], tcl_cv_api_serial=sgtty, tcl_cv_api_serial=none, tcl_cv_api_serial=none) fi]) case $tcl_cv_api_serial in termios) AC_DEFINE(USE_TERMIOS, 1, [Use the termios API for serial lines]);; termio) AC_DEFINE(USE_TERMIO, 1, [Use the termio API for serial lines]);; sgtty) AC_DEFINE(USE_SGTTY, 1, [Use the sgtty API for serial lines]);; esac ]) #-------------------------------------------------------------------- # TEA_MISSING_POSIX_HEADERS # # Supply substitutes for missing POSIX header files. Special # notes: # - stdlib.h doesn't define strtol, strtoul, or # strtod insome versions of SunOS # - some versions of string.h don't declare procedures such # as strstr # # Arguments: # none # # Results: # # Defines some of the following vars: # NO_DIRENT_H # NO_ERRNO_H # NO_VALUES_H # HAVE_LIMITS_H or NO_LIMITS_H # NO_STDLIB_H # NO_STRING_H # NO_SYS_WAIT_H # NO_DLFCN_H # HAVE_SYS_PARAM_H # # HAVE_STRING_H ? # # tkUnixPort.h checks for HAVE_LIMITS_H, so do both HAVE and # CHECK on limits.h #-------------------------------------------------------------------- AC_DEFUN([TEA_MISSING_POSIX_HEADERS], [ AC_CACHE_CHECK([dirent.h], tcl_cv_dirent_h, [ AC_TRY_LINK([#include #include ], [ #ifndef _POSIX_SOURCE # ifdef __Lynx__ /* * Generate compilation error to make the test fail: Lynx headers * are only valid if really in the POSIX environment. */ missing_procedure(); # endif #endif DIR *d; struct dirent *entryPtr; char *p; d = opendir("foobar"); entryPtr = readdir(d); p = entryPtr->d_name; closedir(d); ], tcl_cv_dirent_h=yes, tcl_cv_dirent_h=no)]) if test $tcl_cv_dirent_h = no; then AC_DEFINE(NO_DIRENT_H, 1, [Do we have ?]) fi # TEA specific: AC_CHECK_HEADER(errno.h, , [AC_DEFINE(NO_ERRNO_H, 1, [Do we have ?])]) AC_CHECK_HEADER(float.h, , [AC_DEFINE(NO_FLOAT_H, 1, [Do we have ?])]) AC_CHECK_HEADER(values.h, , [AC_DEFINE(NO_VALUES_H, 1, [Do we have ?])]) AC_CHECK_HEADER(limits.h, [AC_DEFINE(HAVE_LIMITS_H, 1, [Do we have ?])], [AC_DEFINE(NO_LIMITS_H, 1, [Do we have ?])]) AC_CHECK_HEADER(stdlib.h, tcl_ok=1, tcl_ok=0) AC_EGREP_HEADER(strtol, stdlib.h, , tcl_ok=0) AC_EGREP_HEADER(strtoul, stdlib.h, , tcl_ok=0) AC_EGREP_HEADER(strtod, stdlib.h, , tcl_ok=0) if test $tcl_ok = 0; then AC_DEFINE(NO_STDLIB_H, 1, [Do we have ?]) fi AC_CHECK_HEADER(string.h, tcl_ok=1, tcl_ok=0) AC_EGREP_HEADER(strstr, string.h, , tcl_ok=0) AC_EGREP_HEADER(strerror, string.h, , tcl_ok=0) # See also memmove check below for a place where NO_STRING_H can be # set and why. if test $tcl_ok = 0; then AC_DEFINE(NO_STRING_H, 1, [Do we have ?]) fi AC_CHECK_HEADER(sys/wait.h, , [AC_DEFINE(NO_SYS_WAIT_H, 1, [Do we have ?])]) AC_CHECK_HEADER(dlfcn.h, , [AC_DEFINE(NO_DLFCN_H, 1, [Do we have ?])]) # OS/390 lacks sys/param.h (and doesn't need it, by chance). AC_HAVE_HEADERS(sys/param.h) ]) #-------------------------------------------------------------------- # TEA_PATH_X # # Locate the X11 header files and the X11 library archive. Try # the ac_path_x macro first, but if it doesn't find the X stuff # (e.g. because there's no xmkmf program) then check through # a list of possible directories. Under some conditions the # autoconf macro will return an include directory that contains # no include files, so double-check its result just to be safe. # # This should be called after TEA_CONFIG_CFLAGS as setting the # LIBS line can confuse some configure macro magic. # # Arguments: # none # # Results: # # Sets the following vars: # XINCLUDES # XLIBSW # PKG_LIBS (appends to) # #-------------------------------------------------------------------- AC_DEFUN([TEA_PATH_X], [ if test "${TEA_WINDOWINGSYSTEM}" = "x11" ; then TEA_PATH_UNIX_X fi ]) AC_DEFUN([TEA_PATH_UNIX_X], [ AC_PATH_X not_really_there="" if test "$no_x" = ""; then if test "$x_includes" = ""; then AC_TRY_CPP([#include ], , not_really_there="yes") else if test ! -r $x_includes/X11/Intrinsic.h; then not_really_there="yes" fi fi fi if test "$no_x" = "yes" -o "$not_really_there" = "yes"; then AC_MSG_CHECKING([for X11 header files]) found_xincludes="no" AC_TRY_CPP([#include ], found_xincludes="yes", found_xincludes="no") if test "$found_xincludes" = "no"; then dirs="/usr/unsupported/include /usr/local/include /usr/X386/include /usr/X11R6/include /usr/X11R5/include /usr/include/X11R5 /usr/include/X11R4 /usr/openwin/include /usr/X11/include /usr/sww/include" for i in $dirs ; do if test -r $i/X11/Intrinsic.h; then AC_MSG_RESULT([$i]) XINCLUDES=" -I$i" found_xincludes="yes" break fi done fi else if test "$x_includes" != ""; then XINCLUDES="-I$x_includes" found_xincludes="yes" fi fi if test found_xincludes = "no"; then AC_MSG_RESULT([couldn't find any!]) fi if test "$no_x" = yes; then AC_MSG_CHECKING([for X11 libraries]) XLIBSW=nope dirs="/usr/unsupported/lib /usr/local/lib /usr/X386/lib /usr/X11R6/lib /usr/X11R5/lib /usr/lib/X11R5 /usr/lib/X11R4 /usr/openwin/lib /usr/X11/lib /usr/sww/X11/lib" for i in $dirs ; do if test -r $i/libX11.a -o -r $i/libX11.so -o -r $i/libX11.sl -o -r $i/libX11.dylib; then AC_MSG_RESULT([$i]) XLIBSW="-L$i -lX11" x_libraries="$i" break fi done else if test "$x_libraries" = ""; then XLIBSW=-lX11 else XLIBSW="-L$x_libraries -lX11" fi fi if test "$XLIBSW" = nope ; then AC_CHECK_LIB(Xwindow, XCreateWindow, XLIBSW=-lXwindow) fi if test "$XLIBSW" = nope ; then AC_MSG_RESULT([could not find any! Using -lX11.]) XLIBSW=-lX11 fi # TEA specific: if test x"${XLIBSW}" != x ; then PKG_LIBS="${PKG_LIBS} ${XLIBSW}" fi ]) #-------------------------------------------------------------------- # TEA_BLOCKING_STYLE # # The statements below check for systems where POSIX-style # non-blocking I/O (O_NONBLOCK) doesn't work or is unimplemented. # On these systems (mostly older ones), use the old BSD-style # FIONBIO approach instead. # # Arguments: # none # # Results: # # Defines some of the following vars: # HAVE_SYS_IOCTL_H # HAVE_SYS_FILIO_H # USE_FIONBIO # O_NONBLOCK # #-------------------------------------------------------------------- AC_DEFUN([TEA_BLOCKING_STYLE], [ AC_CHECK_HEADERS(sys/ioctl.h) AC_CHECK_HEADERS(sys/filio.h) TEA_CONFIG_SYSTEM AC_MSG_CHECKING([FIONBIO vs. O_NONBLOCK for nonblocking I/O]) case $system in # There used to be code here to use FIONBIO under AIX. However, it # was reported that FIONBIO doesn't work under AIX 3.2.5. Since # using O_NONBLOCK seems fine under AIX 4.*, I removed the FIONBIO # code (JO, 5/31/97). OSF*) AC_DEFINE(USE_FIONBIO, 1, [Should we use FIONBIO?]) AC_MSG_RESULT([FIONBIO]) ;; SunOS-4*) AC_DEFINE(USE_FIONBIO, 1, [Should we use FIONBIO?]) AC_MSG_RESULT([FIONBIO]) ;; *) AC_MSG_RESULT([O_NONBLOCK]) ;; esac ]) #-------------------------------------------------------------------- # TEA_TIME_HANLDER # # Checks how the system deals with time.h, what time structures # are used on the system, and what fields the structures have. # # Arguments: # none # # Results: # # Defines some of the following vars: # USE_DELTA_FOR_TZ # HAVE_TM_GMTOFF # HAVE_TM_TZADJ # HAVE_TIMEZONE_VAR # #-------------------------------------------------------------------- AC_DEFUN([TEA_TIME_HANDLER], [ AC_CHECK_HEADERS(sys/time.h) AC_HEADER_TIME AC_STRUCT_TIMEZONE AC_CHECK_FUNCS(gmtime_r localtime_r) AC_CACHE_CHECK([tm_tzadj in struct tm], tcl_cv_member_tm_tzadj, [ AC_TRY_COMPILE([#include ], [struct tm tm; tm.tm_tzadj;], tcl_cv_member_tm_tzadj=yes, tcl_cv_member_tm_tzadj=no)]) if test $tcl_cv_member_tm_tzadj = yes ; then AC_DEFINE(HAVE_TM_TZADJ, 1, [Should we use the tm_tzadj field of struct tm?]) fi AC_CACHE_CHECK([tm_gmtoff in struct tm], tcl_cv_member_tm_gmtoff, [ AC_TRY_COMPILE([#include ], [struct tm tm; tm.tm_gmtoff;], tcl_cv_member_tm_gmtoff=yes, tcl_cv_member_tm_gmtoff=no)]) if test $tcl_cv_member_tm_gmtoff = yes ; then AC_DEFINE(HAVE_TM_GMTOFF, 1, [Should we use the tm_gmtoff field of struct tm?]) fi # # Its important to include time.h in this check, as some systems # (like convex) have timezone functions, etc. # AC_CACHE_CHECK([long timezone variable], tcl_cv_timezone_long, [ AC_TRY_COMPILE([#include ], [extern long timezone; timezone += 1; exit (0);], tcl_cv_timezone_long=yes, tcl_cv_timezone_long=no)]) if test $tcl_cv_timezone_long = yes ; then AC_DEFINE(HAVE_TIMEZONE_VAR, 1, [Should we use the global timezone variable?]) else # # On some systems (eg IRIX 6.2), timezone is a time_t and not a long. # AC_CACHE_CHECK([time_t timezone variable], tcl_cv_timezone_time, [ AC_TRY_COMPILE([#include ], [extern time_t timezone; timezone += 1; exit (0);], tcl_cv_timezone_time=yes, tcl_cv_timezone_time=no)]) if test $tcl_cv_timezone_time = yes ; then AC_DEFINE(HAVE_TIMEZONE_VAR, 1, [Should we use the global timezone variable?]) fi fi ]) #-------------------------------------------------------------------- # TEA_BUGGY_STRTOD # # Under Solaris 2.4, strtod returns the wrong value for the # terminating character under some conditions. Check for this # and if the problem exists use a substitute procedure # "fixstrtod" (provided by Tcl) that corrects the error. # Also, on Compaq's Tru64 Unix 5.0, # strtod(" ") returns 0.0 instead of a failure to convert. # # Arguments: # none # # Results: # # Might defines some of the following vars: # strtod (=fixstrtod) # #-------------------------------------------------------------------- AC_DEFUN([TEA_BUGGY_STRTOD], [ AC_CHECK_FUNC(strtod, tcl_strtod=1, tcl_strtod=0) if test "$tcl_strtod" = 1; then AC_CACHE_CHECK([for Solaris2.4/Tru64 strtod bugs], tcl_cv_strtod_buggy,[ AC_TRY_RUN([ extern double strtod(); int main() { char *infString="Inf", *nanString="NaN", *spaceString=" "; char *term; double value; value = strtod(infString, &term); if ((term != infString) && (term[-1] == 0)) { exit(1); } value = strtod(nanString, &term); if ((term != nanString) && (term[-1] == 0)) { exit(1); } value = strtod(spaceString, &term); if (term == (spaceString+1)) { exit(1); } exit(0); }], tcl_cv_strtod_buggy=ok, tcl_cv_strtod_buggy=buggy, tcl_cv_strtod_buggy=buggy)]) if test "$tcl_cv_strtod_buggy" = buggy; then AC_LIBOBJ([fixstrtod]) USE_COMPAT=1 AC_DEFINE(strtod, fixstrtod, [Do we want to use the strtod() in compat?]) fi fi ]) #-------------------------------------------------------------------- # TEA_TCL_LINK_LIBS # # Search for the libraries needed to link the Tcl shell. # Things like the math library (-lm) and socket stuff (-lsocket vs. # -lnsl) are dealt with here. # # Arguments: # Requires the following vars to be set in the Makefile: # DL_LIBS # LIBS # MATH_LIBS # # Results: # # Subst's the following var: # TCL_LIBS # MATH_LIBS # # Might append to the following vars: # LIBS # # Might define the following vars: # HAVE_NET_ERRNO_H # #-------------------------------------------------------------------- AC_DEFUN([TEA_TCL_LINK_LIBS], [ #-------------------------------------------------------------------- # On a few very rare systems, all of the libm.a stuff is # already in libc.a. Set compiler flags accordingly. # Also, Linux requires the "ieee" library for math to work # right (and it must appear before "-lm"). #-------------------------------------------------------------------- AC_CHECK_FUNC(sin, MATH_LIBS="", MATH_LIBS="-lm") AC_CHECK_LIB(ieee, main, [MATH_LIBS="-lieee $MATH_LIBS"]) #-------------------------------------------------------------------- # Interactive UNIX requires -linet instead of -lsocket, plus it # needs net/errno.h to define the socket-related error codes. #-------------------------------------------------------------------- AC_CHECK_LIB(inet, main, [LIBS="$LIBS -linet"]) AC_CHECK_HEADER(net/errno.h, [ AC_DEFINE(HAVE_NET_ERRNO_H, 1, [Do we have ?])]) #-------------------------------------------------------------------- # Check for the existence of the -lsocket and -lnsl libraries. # The order here is important, so that they end up in the right # order in the command line generated by make. Here are some # special considerations: # 1. Use "connect" and "accept" to check for -lsocket, and # "gethostbyname" to check for -lnsl. # 2. Use each function name only once: can't redo a check because # autoconf caches the results of the last check and won't redo it. # 3. Use -lnsl and -lsocket only if they supply procedures that # aren't already present in the normal libraries. This is because # IRIX 5.2 has libraries, but they aren't needed and they're # bogus: they goof up name resolution if used. # 4. On some SVR4 systems, can't use -lsocket without -lnsl too. # To get around this problem, check for both libraries together # if -lsocket doesn't work by itself. #-------------------------------------------------------------------- tcl_checkBoth=0 AC_CHECK_FUNC(connect, tcl_checkSocket=0, tcl_checkSocket=1) if test "$tcl_checkSocket" = 1; then AC_CHECK_FUNC(setsockopt, , [AC_CHECK_LIB(socket, setsockopt, LIBS="$LIBS -lsocket", tcl_checkBoth=1)]) fi if test "$tcl_checkBoth" = 1; then tk_oldLibs=$LIBS LIBS="$LIBS -lsocket -lnsl" AC_CHECK_FUNC(accept, tcl_checkNsl=0, [LIBS=$tk_oldLibs]) fi AC_CHECK_FUNC(gethostbyname, , [AC_CHECK_LIB(nsl, gethostbyname, [LIBS="$LIBS -lnsl"])]) # TEA specific: Don't perform the eval of the libraries here because # DL_LIBS won't be set until we call TEA_CONFIG_CFLAGS TCL_LIBS='${DL_LIBS} ${LIBS} ${MATH_LIBS}' AC_SUBST(TCL_LIBS) AC_SUBST(MATH_LIBS) ]) #-------------------------------------------------------------------- # TEA_TCL_EARLY_FLAGS # # Check for what flags are needed to be passed so the correct OS # features are available. # # Arguments: # None # # Results: # # Might define the following vars: # _ISOC99_SOURCE # _LARGEFILE64_SOURCE # _LARGEFILE_SOURCE64 # #-------------------------------------------------------------------- AC_DEFUN([TEA_TCL_EARLY_FLAG],[ AC_CACHE_VAL([tcl_cv_flag_]translit($1,[A-Z],[a-z]), AC_TRY_COMPILE([$2], $3, [tcl_cv_flag_]translit($1,[A-Z],[a-z])=no, AC_TRY_COMPILE([[#define ]$1[ 1 ]$2], $3, [tcl_cv_flag_]translit($1,[A-Z],[a-z])=yes, [tcl_cv_flag_]translit($1,[A-Z],[a-z])=no))) if test ["x${tcl_cv_flag_]translit($1,[A-Z],[a-z])[}" = "xyes"] ; then AC_DEFINE($1, 1, [Add the ]$1[ flag when building]) tcl_flags="$tcl_flags $1" fi ]) AC_DEFUN([TEA_TCL_EARLY_FLAGS],[ AC_MSG_CHECKING([for required early compiler flags]) tcl_flags="" TEA_TCL_EARLY_FLAG(_ISOC99_SOURCE,[#include ], [char *p = (char *)strtoll; char *q = (char *)strtoull;]) TEA_TCL_EARLY_FLAG(_LARGEFILE64_SOURCE,[#include ], [struct stat64 buf; int i = stat64("/", &buf);]) TEA_TCL_EARLY_FLAG(_LARGEFILE_SOURCE64,[#include ], [char *p = (char *)open64;]) if test "x${tcl_flags}" = "x" ; then AC_MSG_RESULT([none]) else AC_MSG_RESULT([${tcl_flags}]) fi ]) #-------------------------------------------------------------------- # TEA_TCL_64BIT_FLAGS # # Check for what is defined in the way of 64-bit features. # # Arguments: # None # # Results: # # Might define the following vars: # TCL_WIDE_INT_IS_LONG # TCL_WIDE_INT_TYPE # HAVE_STRUCT_DIRENT64 # HAVE_STRUCT_STAT64 # HAVE_TYPE_OFF64_T # #-------------------------------------------------------------------- AC_DEFUN([TEA_TCL_64BIT_FLAGS], [ AC_MSG_CHECKING([for 64-bit integer type]) AC_CACHE_VAL(tcl_cv_type_64bit,[ tcl_cv_type_64bit=none # See if the compiler knows natively about __int64 AC_TRY_COMPILE(,[__int64 value = (__int64) 0;], tcl_type_64bit=__int64, tcl_type_64bit="long long") # See if we should use long anyway Note that we substitute in the # type that is our current guess for a 64-bit type inside this check # program, so it should be modified only carefully... AC_TRY_COMPILE(,[switch (0) { case 1: case (sizeof(]${tcl_type_64bit}[)==sizeof(long)): ; }],tcl_cv_type_64bit=${tcl_type_64bit})]) if test "${tcl_cv_type_64bit}" = none ; then AC_DEFINE(TCL_WIDE_INT_IS_LONG, 1, [Are wide integers to be implemented with C 'long's?]) AC_MSG_RESULT([using long]) elif test "${tcl_cv_type_64bit}" = "__int64" \ -a "${TEA_PLATFORM}" = "windows" ; then # TEA specific: We actually want to use the default tcl.h checks in # this case to handle both TCL_WIDE_INT_TYPE and TCL_LL_MODIFIER* AC_MSG_RESULT([using Tcl header defaults]) else AC_DEFINE_UNQUOTED(TCL_WIDE_INT_TYPE,${tcl_cv_type_64bit}, [What type should be used to define wide integers?]) AC_MSG_RESULT([${tcl_cv_type_64bit}]) # Now check for auxiliary declarations AC_CACHE_CHECK([for struct dirent64], tcl_cv_struct_dirent64,[ AC_TRY_COMPILE([#include #include ],[struct dirent64 p;], tcl_cv_struct_dirent64=yes,tcl_cv_struct_dirent64=no)]) if test "x${tcl_cv_struct_dirent64}" = "xyes" ; then AC_DEFINE(HAVE_STRUCT_DIRENT64, 1, [Is 'struct dirent64' in ?]) fi AC_CACHE_CHECK([for struct stat64], tcl_cv_struct_stat64,[ AC_TRY_COMPILE([#include ],[struct stat64 p; ], tcl_cv_struct_stat64=yes,tcl_cv_struct_stat64=no)]) if test "x${tcl_cv_struct_stat64}" = "xyes" ; then AC_DEFINE(HAVE_STRUCT_STAT64, 1, [Is 'struct stat64' in ?]) fi AC_CHECK_FUNCS(open64 lseek64) AC_MSG_CHECKING([for off64_t]) AC_CACHE_VAL(tcl_cv_type_off64_t,[ AC_TRY_COMPILE([#include ],[off64_t offset; ], tcl_cv_type_off64_t=yes,tcl_cv_type_off64_t=no)]) dnl Define HAVE_TYPE_OFF64_T only when the off64_t type and the dnl functions lseek64 and open64 are defined. if test "x${tcl_cv_type_off64_t}" = "xyes" && \ test "x${ac_cv_func_lseek64}" = "xyes" && \ test "x${ac_cv_func_open64}" = "xyes" ; then AC_DEFINE(HAVE_TYPE_OFF64_T, 1, [Is off64_t in ?]) AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi fi ]) ## ## Here ends the standard Tcl configuration bits and starts the ## TEA specific functions ## #------------------------------------------------------------------------ # TEA_INIT -- # # Init various Tcl Extension Architecture (TEA) variables. # This should be the first called TEA_* macro. # # Arguments: # none # # Results: # # Defines and substs the following vars: # CYGPATH # EXEEXT # Defines only: # TEA_VERSION # TEA_INITED # TEA_PLATFORM (windows or unix) # # "cygpath" is used on windows to generate native path names for include # files. These variables should only be used with the compiler and linker # since they generate native path names. # # EXEEXT # Select the executable extension based on the host type. This # is a lightweight replacement for AC_EXEEXT that doesn't require # a compiler. #------------------------------------------------------------------------ AC_DEFUN([TEA_INIT], [ # TEA extensions pass this us the version of TEA they think they # are compatible with. TEA_VERSION="3.7" AC_MSG_CHECKING([for correct TEA configuration]) if test x"${PACKAGE_NAME}" = x ; then AC_MSG_ERROR([ The PACKAGE_NAME variable must be defined by your TEA configure.in]) fi if test x"$1" = x ; then AC_MSG_ERROR([ TEA version not specified.]) elif test "$1" != "${TEA_VERSION}" ; then AC_MSG_RESULT([warning: requested TEA version "$1", have "${TEA_VERSION}"]) else AC_MSG_RESULT([ok (TEA ${TEA_VERSION})]) fi case "`uname -s`" in *win32*|*WIN32*|*CYGWIN_NT*|*CYGWIN_9*|*CYGWIN_ME*|*MINGW32_*) AC_CHECK_PROG(CYGPATH, cygpath, cygpath -w, echo) EXEEXT=".exe" TEA_PLATFORM="windows" ;; *) CYGPATH=echo EXEEXT="" TEA_PLATFORM="unix" ;; esac # Check if exec_prefix is set. If not use fall back to prefix. # Note when adjusted, so that TEA_PREFIX can correct for this. # This is needed for recursive configures, since autoconf propagates # $prefix, but not $exec_prefix (doh!). if test x$exec_prefix = xNONE ; then exec_prefix_default=yes exec_prefix=$prefix fi AC_SUBST(EXEEXT) AC_SUBST(CYGPATH) # This package name must be replaced statically for AC_SUBST to work AC_SUBST(PKG_LIB_FILE) # Substitute STUB_LIB_FILE in case package creates a stub library too. AC_SUBST(PKG_STUB_LIB_FILE) # We AC_SUBST these here to ensure they are subst'ed, # in case the user doesn't call TEA_ADD_... AC_SUBST(PKG_STUB_SOURCES) AC_SUBST(PKG_STUB_OBJECTS) AC_SUBST(PKG_TCL_SOURCES) AC_SUBST(PKG_HEADERS) AC_SUBST(PKG_INCLUDES) AC_SUBST(PKG_LIBS) AC_SUBST(PKG_CFLAGS) ]) #------------------------------------------------------------------------ # TEA_ADD_SOURCES -- # # Specify one or more source files. Users should check for # the right platform before adding to their list. # It is not important to specify the directory, as long as it is # in the generic, win or unix subdirectory of $(srcdir). # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_SOURCES # PKG_OBJECTS #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_SOURCES], [ vars="$@" for i in $vars; do case $i in [\$]*) # allow $-var names PKG_SOURCES="$PKG_SOURCES $i" PKG_OBJECTS="$PKG_OBJECTS $i" ;; *) # check for existence - allows for generic/win/unix VPATH # To add more dirs here (like 'src'), you have to update VPATH # in Makefile.in as well if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/generic/$i" \ -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ ; then AC_MSG_ERROR([could not find source file '$i']) fi PKG_SOURCES="$PKG_SOURCES $i" # this assumes it is in a VPATH dir i=`basename $i` # handle user calling this before or after TEA_SETUP_COMPILER if test x"${OBJEXT}" != x ; then j="`echo $i | sed -e 's/\.[[^.]]*$//'`.${OBJEXT}" else j="`echo $i | sed -e 's/\.[[^.]]*$//'`.\${OBJEXT}" fi PKG_OBJECTS="$PKG_OBJECTS $j" ;; esac done AC_SUBST(PKG_SOURCES) AC_SUBST(PKG_OBJECTS) ]) #------------------------------------------------------------------------ # TEA_ADD_STUB_SOURCES -- # # Specify one or more source files. Users should check for # the right platform before adding to their list. # It is not important to specify the directory, as long as it is # in the generic, win or unix subdirectory of $(srcdir). # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_STUB_SOURCES # PKG_STUB_OBJECTS #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_STUB_SOURCES], [ vars="$@" for i in $vars; do # check for existence - allows for generic/win/unix VPATH if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/generic/$i" \ -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ ; then AC_MSG_ERROR([could not find stub source file '$i']) fi PKG_STUB_SOURCES="$PKG_STUB_SOURCES $i" # this assumes it is in a VPATH dir i=`basename $i` # handle user calling this before or after TEA_SETUP_COMPILER if test x"${OBJEXT}" != x ; then j="`echo $i | sed -e 's/\.[[^.]]*$//'`.${OBJEXT}" else j="`echo $i | sed -e 's/\.[[^.]]*$//'`.\${OBJEXT}" fi PKG_STUB_OBJECTS="$PKG_STUB_OBJECTS $j" done AC_SUBST(PKG_STUB_SOURCES) AC_SUBST(PKG_STUB_OBJECTS) ]) #------------------------------------------------------------------------ # TEA_ADD_TCL_SOURCES -- # # Specify one or more Tcl source files. These should be platform # independent runtime files. # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_TCL_SOURCES #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_TCL_SOURCES], [ vars="$@" for i in $vars; do # check for existence, be strict because it is installed if test ! -f "${srcdir}/$i" ; then AC_MSG_ERROR([could not find tcl source file '${srcdir}/$i']) fi PKG_TCL_SOURCES="$PKG_TCL_SOURCES $i" done AC_SUBST(PKG_TCL_SOURCES) ]) #------------------------------------------------------------------------ # TEA_ADD_HEADERS -- # # Specify one or more source headers. Users should check for # the right platform before adding to their list. # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_HEADERS #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_HEADERS], [ vars="$@" for i in $vars; do # check for existence, be strict because it is installed if test ! -f "${srcdir}/$i" ; then AC_MSG_ERROR([could not find header file '${srcdir}/$i']) fi PKG_HEADERS="$PKG_HEADERS $i" done AC_SUBST(PKG_HEADERS) ]) #------------------------------------------------------------------------ # TEA_ADD_INCLUDES -- # # Specify one or more include dirs. Users should check for # the right platform before adding to their list. # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_INCLUDES #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_INCLUDES], [ vars="$@" for i in $vars; do PKG_INCLUDES="$PKG_INCLUDES $i" done AC_SUBST(PKG_INCLUDES) ]) #------------------------------------------------------------------------ # TEA_ADD_LIBS -- # # Specify one or more libraries. Users should check for # the right platform before adding to their list. For Windows, # libraries provided in "foo.lib" format will be converted to # "-lfoo" when using GCC (mingw). # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_LIBS #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_LIBS], [ vars="$@" for i in $vars; do if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then # Convert foo.lib to -lfoo for GCC. No-op if not *.lib i=`echo "$i" | sed -e 's/^\([[^-]].*\)\.lib[$]/-l\1/i'` fi PKG_LIBS="$PKG_LIBS $i" done AC_SUBST(PKG_LIBS) ]) #------------------------------------------------------------------------ # TEA_ADD_CFLAGS -- # # Specify one or more CFLAGS. Users should check for # the right platform before adding to their list. # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_CFLAGS #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_CFLAGS], [ PKG_CFLAGS="$PKG_CFLAGS $@" AC_SUBST(PKG_CFLAGS) ]) #------------------------------------------------------------------------ # TEA_PREFIX -- # # Handle the --prefix=... option by defaulting to what Tcl gave # # Arguments: # none # # Results: # # If --prefix or --exec-prefix was not specified, $prefix and # $exec_prefix will be set to the values given to Tcl when it was # configured. #------------------------------------------------------------------------ AC_DEFUN([TEA_PREFIX], [ if test "${prefix}" = "NONE"; then prefix_default=yes if test x"${TCL_PREFIX}" != x; then AC_MSG_NOTICE([--prefix defaulting to TCL_PREFIX ${TCL_PREFIX}]) prefix=${TCL_PREFIX} else AC_MSG_NOTICE([--prefix defaulting to /usr/local]) prefix=/usr/local fi fi if test "${exec_prefix}" = "NONE" -a x"${prefix_default}" = x"yes" \ -o x"${exec_prefix_default}" = x"yes" ; then if test x"${TCL_EXEC_PREFIX}" != x; then AC_MSG_NOTICE([--exec-prefix defaulting to TCL_EXEC_PREFIX ${TCL_EXEC_PREFIX}]) exec_prefix=${TCL_EXEC_PREFIX} else AC_MSG_NOTICE([--exec-prefix defaulting to ${prefix}]) exec_prefix=$prefix fi fi ]) #------------------------------------------------------------------------ # TEA_SETUP_COMPILER_CC -- # # Do compiler checks the way we want. This is just a replacement # for AC_PROG_CC in TEA configure.in files to make them cleaner. # # Arguments: # none # # Results: # # Sets up CC var and other standard bits we need to make executables. #------------------------------------------------------------------------ AC_DEFUN([TEA_SETUP_COMPILER_CC], [ # Don't put any macros that use the compiler (e.g. AC_TRY_COMPILE) # in this macro, they need to go into TEA_SETUP_COMPILER instead. # If the user did not set CFLAGS, set it now to keep # the AC_PROG_CC macro from adding "-g -O2". if test "${CFLAGS+set}" != "set" ; then CFLAGS="" fi AC_PROG_CC AC_PROG_CPP AC_PROG_INSTALL #-------------------------------------------------------------------- # Checks to see if the make program sets the $MAKE variable. #-------------------------------------------------------------------- AC_PROG_MAKE_SET #-------------------------------------------------------------------- # Find ranlib #-------------------------------------------------------------------- AC_PROG_RANLIB #-------------------------------------------------------------------- # Determines the correct binary file extension (.o, .obj, .exe etc.) #-------------------------------------------------------------------- AC_OBJEXT AC_EXEEXT ]) #------------------------------------------------------------------------ # TEA_SETUP_COMPILER -- # # Do compiler checks that use the compiler. This must go after # TEA_SETUP_COMPILER_CC, which does the actual compiler check. # # Arguments: # none # # Results: # # Sets up CC var and other standard bits we need to make executables. #------------------------------------------------------------------------ AC_DEFUN([TEA_SETUP_COMPILER], [ # Any macros that use the compiler (e.g. AC_TRY_COMPILE) have to go here. AC_REQUIRE([TEA_SETUP_COMPILER_CC]) #------------------------------------------------------------------------ # If we're using GCC, see if the compiler understands -pipe. If so, use it. # It makes compiling go faster. (This is only a performance feature.) #------------------------------------------------------------------------ if test -z "$no_pipe" -a -n "$GCC"; then AC_CACHE_CHECK([if the compiler understands -pipe], tcl_cv_cc_pipe, [ hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -pipe" AC_TRY_COMPILE(,, tcl_cv_cc_pipe=yes, tcl_cv_cc_pipe=no) CFLAGS=$hold_cflags]) if test $tcl_cv_cc_pipe = yes; then CFLAGS="$CFLAGS -pipe" fi fi #-------------------------------------------------------------------- # Common compiler flag setup #-------------------------------------------------------------------- AC_C_BIGENDIAN if test "${TEA_PLATFORM}" = "unix" ; then TEA_TCL_LINK_LIBS TEA_MISSING_POSIX_HEADERS # Let the user call this, because if it triggers, they will # need a compat/strtod.c that is correct. Users can also # use Tcl_GetDouble(FromObj) instead. #TEA_BUGGY_STRTOD fi ]) #------------------------------------------------------------------------ # TEA_MAKE_LIB -- # # Generate a line that can be used to build a shared/unshared library # in a platform independent manner. # # Arguments: # none # # Requires: # # Results: # # Defines the following vars: # CFLAGS - Done late here to note disturb other AC macros # MAKE_LIB - Command to execute to build the Tcl library; # differs depending on whether or not Tcl is being # compiled as a shared library. # MAKE_SHARED_LIB Makefile rule for building a shared library # MAKE_STATIC_LIB Makefile rule for building a static library # MAKE_STUB_LIB Makefile rule for building a stub library #------------------------------------------------------------------------ AC_DEFUN([TEA_MAKE_LIB], [ if test "${TEA_PLATFORM}" = "windows" -a "$GCC" != "yes"; then MAKE_STATIC_LIB="\${STLIB_LD} -out:\[$]@ \$(PKG_OBJECTS)" MAKE_SHARED_LIB="\${SHLIB_LD} \${SHLIB_LD_LIBS} \${LDFLAGS_DEFAULT} -out:\[$]@ \$(PKG_OBJECTS)" MAKE_STUB_LIB="\${STLIB_LD} -out:\[$]@ \$(PKG_STUB_OBJECTS)" else MAKE_STATIC_LIB="\${STLIB_LD} \[$]@ \$(PKG_OBJECTS)" MAKE_SHARED_LIB="\${SHLIB_LD} -o \[$]@ \$(PKG_OBJECTS) \${SHLIB_LD_LIBS}" MAKE_STUB_LIB="\${STLIB_LD} \[$]@ \$(PKG_STUB_OBJECTS)" fi if test "${SHARED_BUILD}" = "1" ; then MAKE_LIB="${MAKE_SHARED_LIB} " else MAKE_LIB="${MAKE_STATIC_LIB} " fi #-------------------------------------------------------------------- # Shared libraries and static libraries have different names. # Use the double eval to make sure any variables in the suffix is # substituted. (@@@ Might not be necessary anymore) #-------------------------------------------------------------------- if test "${TEA_PLATFORM}" = "windows" ; then if test "${SHARED_BUILD}" = "1" ; then # We force the unresolved linking of symbols that are really in # the private libraries of Tcl and Tk. SHLIB_LD_LIBS="${SHLIB_LD_LIBS} \"`${CYGPATH} ${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}`\"" if test x"${TK_BIN_DIR}" != x ; then SHLIB_LD_LIBS="${SHLIB_LD_LIBS} \"`${CYGPATH} ${TK_BIN_DIR}/${TK_STUB_LIB_FILE}`\"" fi eval eval "PKG_LIB_FILE=${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" else eval eval "PKG_LIB_FILE=${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" fi # Some packages build their own stubs libraries eval eval "PKG_STUB_LIB_FILE=${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}" if test "$GCC" = "yes"; then PKG_STUB_LIB_FILE=lib${PKG_STUB_LIB_FILE} fi # These aren't needed on Windows (either MSVC or gcc) RANLIB=: RANLIB_STUB=: else RANLIB_STUB="${RANLIB}" if test "${SHARED_BUILD}" = "1" ; then SHLIB_LD_LIBS="${SHLIB_LD_LIBS} ${TCL_STUB_LIB_SPEC}" if test x"${TK_BIN_DIR}" != x ; then SHLIB_LD_LIBS="${SHLIB_LD_LIBS} ${TK_STUB_LIB_SPEC}" fi eval eval "PKG_LIB_FILE=lib${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" RANLIB=: else eval eval "PKG_LIB_FILE=lib${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" fi # Some packages build their own stubs libraries eval eval "PKG_STUB_LIB_FILE=lib${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}" fi # These are escaped so that only CFLAGS is picked up at configure time. # The other values will be substituted at make time. CFLAGS="${CFLAGS} \${CFLAGS_DEFAULT} \${CFLAGS_WARNING}" if test "${SHARED_BUILD}" = "1" ; then CFLAGS="${CFLAGS} \${SHLIB_CFLAGS}" fi AC_SUBST(MAKE_LIB) AC_SUBST(MAKE_SHARED_LIB) AC_SUBST(MAKE_STATIC_LIB) AC_SUBST(MAKE_STUB_LIB) AC_SUBST(RANLIB_STUB) ]) #------------------------------------------------------------------------ # TEA_LIB_SPEC -- # # Compute the name of an existing object library located in libdir # from the given base name and produce the appropriate linker flags. # # Arguments: # basename The base name of the library without version # numbers, extensions, or "lib" prefixes. # extra_dir Extra directory in which to search for the # library. This location is used first, then # $prefix/$exec-prefix, then some defaults. # # Requires: # TEA_INIT and TEA_PREFIX must be called first. # # Results: # # Defines the following vars: # ${basename}_LIB_NAME The computed library name. # ${basename}_LIB_SPEC The computed linker flags. #------------------------------------------------------------------------ AC_DEFUN([TEA_LIB_SPEC], [ AC_MSG_CHECKING([for $1 library]) # Look in exec-prefix for the library (defined by TEA_PREFIX). tea_lib_name_dir="${exec_prefix}/lib" # Or in a user-specified location. if test x"$2" != x ; then tea_extra_lib_dir=$2 else tea_extra_lib_dir=NONE fi for i in \ `ls -dr ${tea_extra_lib_dir}/$1[[0-9]]*.lib 2>/dev/null ` \ `ls -dr ${tea_extra_lib_dir}/lib$1[[0-9]]* 2>/dev/null ` \ `ls -dr ${tea_lib_name_dir}/$1[[0-9]]*.lib 2>/dev/null ` \ `ls -dr ${tea_lib_name_dir}/lib$1[[0-9]]* 2>/dev/null ` \ `ls -dr /usr/lib/$1[[0-9]]*.lib 2>/dev/null ` \ `ls -dr /usr/lib/lib$1[[0-9]]* 2>/dev/null ` \ `ls -dr /usr/local/lib/$1[[0-9]]*.lib 2>/dev/null ` \ `ls -dr /usr/local/lib/lib$1[[0-9]]* 2>/dev/null ` ; do if test -f "$i" ; then tea_lib_name_dir=`dirname $i` $1_LIB_NAME=`basename $i` $1_LIB_PATH_NAME=$i break fi done if test "${TEA_PLATFORM}" = "windows"; then $1_LIB_SPEC=\"`${CYGPATH} ${$1_LIB_PATH_NAME} 2>/dev/null`\" else # Strip off the leading "lib" and trailing ".a" or ".so" tea_lib_name_lib=`echo ${$1_LIB_NAME}|sed -e 's/^lib//' -e 's/\.[[^.]]*$//' -e 's/\.so.*//'` $1_LIB_SPEC="-L${tea_lib_name_dir} -l${tea_lib_name_lib}" fi if test "x${$1_LIB_NAME}" = x ; then AC_MSG_ERROR([not found]) else AC_MSG_RESULT([${$1_LIB_SPEC}]) fi ]) #------------------------------------------------------------------------ # TEA_PRIVATE_TCL_HEADERS -- # # Locate the private Tcl include files # # Arguments: # # Requires: # TCL_SRC_DIR Assumes that TEA_LOAD_TCLCONFIG has # already been called. # # Results: # # Substs the following vars: # TCL_TOP_DIR_NATIVE # TCL_INCLUDES #------------------------------------------------------------------------ AC_DEFUN([TEA_PRIVATE_TCL_HEADERS], [ # Allow for --with-tclinclude to take effect and define ${ac_cv_c_tclh} AC_REQUIRE([TEA_PUBLIC_TCL_HEADERS]) AC_MSG_CHECKING([for Tcl private include files]) TCL_SRC_DIR_NATIVE=`${CYGPATH} ${TCL_SRC_DIR}` TCL_TOP_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}\" # Check to see if tclPort.h isn't already with the public headers # Don't look for tclInt.h because that resides with tcl.h in the core # sources, but the Port headers are in a different directory if test "${TEA_PLATFORM}" = "windows" -a \ -f "${ac_cv_c_tclh}/tclWinPort.h"; then result="private headers found with public headers" elif test "${TEA_PLATFORM}" = "unix" -a \ -f "${ac_cv_c_tclh}/tclUnixPort.h"; then result="private headers found with public headers" else TCL_GENERIC_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/generic\" if test "${TEA_PLATFORM}" = "windows"; then TCL_PLATFORM_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/win\" else TCL_PLATFORM_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/unix\" fi # Overwrite the previous TCL_INCLUDES as this should capture both # public and private headers in the same set. # We want to ensure these are substituted so as not to require # any *_NATIVE vars be defined in the Makefile TCL_INCLUDES="-I${TCL_GENERIC_DIR_NATIVE} -I${TCL_PLATFORM_DIR_NATIVE}" if test "`uname -s`" = "Darwin"; then # If Tcl was built as a framework, attempt to use # the framework's Headers and PrivateHeaders directories case ${TCL_DEFS} in *TCL_FRAMEWORK*) if test -d "${TCL_BIN_DIR}/Headers" -a \ -d "${TCL_BIN_DIR}/PrivateHeaders"; then TCL_INCLUDES="-I\"${TCL_BIN_DIR}/Headers\" -I\"${TCL_BIN_DIR}/PrivateHeaders\" ${TCL_INCLUDES}" else TCL_INCLUDES="${TCL_INCLUDES} ${TCL_INCLUDE_SPEC} `echo "${TCL_INCLUDE_SPEC}" | sed -e 's/Headers/PrivateHeaders/'`" fi ;; esac result="Using ${TCL_INCLUDES}" else if test ! -f "${TCL_SRC_DIR}/generic/tclInt.h" ; then AC_MSG_ERROR([Cannot find private header tclInt.h in ${TCL_SRC_DIR}]) fi result="Using srcdir found in tclConfig.sh: ${TCL_SRC_DIR}" fi fi AC_SUBST(TCL_TOP_DIR_NATIVE) AC_SUBST(TCL_INCLUDES) AC_MSG_RESULT([${result}]) ]) #------------------------------------------------------------------------ # TEA_PUBLIC_TCL_HEADERS -- # # Locate the installed public Tcl header files # # Arguments: # None. # # Requires: # CYGPATH must be set # # Results: # # Adds a --with-tclinclude switch to configure. # Result is cached. # # Substs the following vars: # TCL_INCLUDES #------------------------------------------------------------------------ AC_DEFUN([TEA_PUBLIC_TCL_HEADERS], [ AC_MSG_CHECKING([for Tcl public headers]) AC_ARG_WITH(tclinclude, [ --with-tclinclude directory containing the public Tcl header files], with_tclinclude=${withval}) AC_CACHE_VAL(ac_cv_c_tclh, [ # Use the value from --with-tclinclude, if it was given if test x"${with_tclinclude}" != x ; then if test -f "${with_tclinclude}/tcl.h" ; then ac_cv_c_tclh=${with_tclinclude} else AC_MSG_ERROR([${with_tclinclude} directory does not contain tcl.h]) fi else if test "`uname -s`" = "Darwin"; then # If Tcl was built as a framework, attempt to use # the framework's Headers directory case ${TCL_DEFS} in *TCL_FRAMEWORK*) list="`ls -d ${TCL_BIN_DIR}/Headers 2>/dev/null`" ;; esac fi # Look in the source dir only if Tcl is not installed, # and in that situation, look there before installed locations. if test -f "${TCL_BIN_DIR}/Makefile" ; then list="$list `ls -d ${TCL_SRC_DIR}/generic 2>/dev/null`" fi # Check order: pkg --prefix location, Tcl's --prefix location, # relative to directory of tclConfig.sh. eval "temp_includedir=${includedir}" list="$list \ `ls -d ${temp_includedir} 2>/dev/null` \ `ls -d ${TCL_PREFIX}/include 2>/dev/null` \ `ls -d ${TCL_BIN_DIR}/../include 2>/dev/null`" if test "${TEA_PLATFORM}" != "windows" -o "$GCC" = "yes"; then list="$list /usr/local/include /usr/include" if test x"${TCL_INCLUDE_SPEC}" != x ; then d=`echo "${TCL_INCLUDE_SPEC}" | sed -e 's/^-I//'` list="$list `ls -d ${d} 2>/dev/null`" fi fi for i in $list ; do if test -f "$i/tcl.h" ; then ac_cv_c_tclh=$i break fi done fi ]) # Print a message based on how we determined the include path if test x"${ac_cv_c_tclh}" = x ; then AC_MSG_ERROR([tcl.h not found. Please specify its location with --with-tclinclude]) else AC_MSG_RESULT([${ac_cv_c_tclh}]) fi # Convert to a native path and substitute into the output files. INCLUDE_DIR_NATIVE=`${CYGPATH} ${ac_cv_c_tclh}` TCL_INCLUDES=-I\"${INCLUDE_DIR_NATIVE}\" AC_SUBST(TCL_INCLUDES) ]) #------------------------------------------------------------------------ # TEA_PRIVATE_TK_HEADERS -- # # Locate the private Tk include files # # Arguments: # # Requires: # TK_SRC_DIR Assumes that TEA_LOAD_TKCONFIG has # already been called. # # Results: # # Substs the following vars: # TK_INCLUDES #------------------------------------------------------------------------ AC_DEFUN([TEA_PRIVATE_TK_HEADERS], [ # Allow for --with-tkinclude to take effect and define ${ac_cv_c_tkh} AC_REQUIRE([TEA_PUBLIC_TK_HEADERS]) AC_MSG_CHECKING([for Tk private include files]) TK_SRC_DIR_NATIVE=`${CYGPATH} ${TK_SRC_DIR}` TK_TOP_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}\" # Check to see if tkPort.h isn't already with the public headers # Don't look for tkInt.h because that resides with tk.h in the core # sources, but the Port headers are in a different directory if test "${TEA_PLATFORM}" = "windows" -a \ -f "${ac_cv_c_tkh}/tkWinPort.h"; then result="private headers found with public headers" elif test "${TEA_PLATFORM}" = "unix" -a \ -f "${ac_cv_c_tkh}/tkUnixPort.h"; then result="private headers found with public headers" else TK_GENERIC_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/generic\" TK_XLIB_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/xlib\" if test "${TEA_PLATFORM}" = "windows"; then TK_PLATFORM_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/win\" else TK_PLATFORM_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/unix\" fi # Overwrite the previous TK_INCLUDES as this should capture both # public and private headers in the same set. # We want to ensure these are substituted so as not to require # any *_NATIVE vars be defined in the Makefile TK_INCLUDES="-I${TK_GENERIC_DIR_NATIVE} -I${TK_PLATFORM_DIR_NATIVE}" # Detect and add ttk subdir if test -d "${TK_SRC_DIR}/generic/ttk"; then TK_INCLUDES="${TK_INCLUDES} -I\"${TK_SRC_DIR_NATIVE}/generic/ttk\"" fi if test "${TEA_WINDOWINGSYSTEM}" != "x11"; then TK_INCLUDES="${TK_INCLUDES} -I${TK_XLIB_DIR_NATIVE}" fi if test "${TEA_WINDOWINGSYSTEM}" = "aqua"; then TK_INCLUDES="${TK_INCLUDES} -I\"${TK_SRC_DIR_NATIVE}/macosx\"" fi if test "`uname -s`" = "Darwin"; then # If Tk was built as a framework, attempt to use # the framework's Headers and PrivateHeaders directories case ${TK_DEFS} in *TK_FRAMEWORK*) if test -d "${TK_BIN_DIR}/Headers" -a \ -d "${TK_BIN_DIR}/PrivateHeaders"; then TK_INCLUDES="-I\"${TK_BIN_DIR}/Headers\" -I\"${TK_BIN_DIR}/PrivateHeaders\" ${TK_INCLUDES}" else TK_INCLUDES="${TK_INCLUDES} ${TK_INCLUDE_SPEC} `echo "${TK_INCLUDE_SPEC}" | sed -e 's/Headers/PrivateHeaders/'`" fi ;; esac result="Using ${TK_INCLUDES}" else if test ! -f "${TK_SRC_DIR}/generic/tkInt.h" ; then AC_MSG_ERROR([Cannot find private header tkInt.h in ${TK_SRC_DIR}]) fi result="Using srcdir found in tkConfig.sh: ${TK_SRC_DIR}" fi fi AC_SUBST(TK_TOP_DIR_NATIVE) AC_SUBST(TK_XLIB_DIR_NATIVE) AC_SUBST(TK_INCLUDES) AC_MSG_RESULT([${result}]) ]) #------------------------------------------------------------------------ # TEA_PUBLIC_TK_HEADERS -- # # Locate the installed public Tk header files # # Arguments: # None. # # Requires: # CYGPATH must be set # # Results: # # Adds a --with-tkinclude switch to configure. # Result is cached. # # Substs the following vars: # TK_INCLUDES #------------------------------------------------------------------------ AC_DEFUN([TEA_PUBLIC_TK_HEADERS], [ AC_MSG_CHECKING([for Tk public headers]) AC_ARG_WITH(tkinclude, [ --with-tkinclude directory containing the public Tk header files], with_tkinclude=${withval}) AC_CACHE_VAL(ac_cv_c_tkh, [ # Use the value from --with-tkinclude, if it was given if test x"${with_tkinclude}" != x ; then if test -f "${with_tkinclude}/tk.h" ; then ac_cv_c_tkh=${with_tkinclude} else AC_MSG_ERROR([${with_tkinclude} directory does not contain tk.h]) fi else if test "`uname -s`" = "Darwin"; then # If Tk was built as a framework, attempt to use # the framework's Headers directory. case ${TK_DEFS} in *TK_FRAMEWORK*) list="`ls -d ${TK_BIN_DIR}/Headers 2>/dev/null`" ;; esac fi # Look in the source dir only if Tk is not installed, # and in that situation, look there before installed locations. if test -f "${TK_BIN_DIR}/Makefile" ; then list="$list `ls -d ${TK_SRC_DIR}/generic 2>/dev/null`" fi # Check order: pkg --prefix location, Tk's --prefix location, # relative to directory of tkConfig.sh, Tcl's --prefix location, # relative to directory of tclConfig.sh. eval "temp_includedir=${includedir}" list="$list \ `ls -d ${temp_includedir} 2>/dev/null` \ `ls -d ${TK_PREFIX}/include 2>/dev/null` \ `ls -d ${TK_BIN_DIR}/../include 2>/dev/null` \ `ls -d ${TCL_PREFIX}/include 2>/dev/null` \ `ls -d ${TCL_BIN_DIR}/../include 2>/dev/null`" if test "${TEA_PLATFORM}" != "windows" -o "$GCC" = "yes"; then list="$list /usr/local/include /usr/include" fi for i in $list ; do if test -f "$i/tk.h" ; then ac_cv_c_tkh=$i break fi done fi ]) # Print a message based on how we determined the include path if test x"${ac_cv_c_tkh}" = x ; then AC_MSG_ERROR([tk.h not found. Please specify its location with --with-tkinclude]) else AC_MSG_RESULT([${ac_cv_c_tkh}]) fi # Convert to a native path and substitute into the output files. INCLUDE_DIR_NATIVE=`${CYGPATH} ${ac_cv_c_tkh}` TK_INCLUDES=-I\"${INCLUDE_DIR_NATIVE}\" AC_SUBST(TK_INCLUDES) if test "${TEA_WINDOWINGSYSTEM}" != "x11"; then # On Windows and Aqua, we need the X compat headers AC_MSG_CHECKING([for X11 header files]) if test ! -r "${INCLUDE_DIR_NATIVE}/X11/Xlib.h"; then INCLUDE_DIR_NATIVE="`${CYGPATH} ${TK_SRC_DIR}/xlib`" TK_XINCLUDES=-I\"${INCLUDE_DIR_NATIVE}\" AC_SUBST(TK_XINCLUDES) fi AC_MSG_RESULT([${INCLUDE_DIR_NATIVE}]) fi ]) #------------------------------------------------------------------------ # TEA_PATH_CONFIG -- # # Locate the ${1}Config.sh file and perform a sanity check on # the ${1} compile flags. These are used by packages like # [incr Tk] that load *Config.sh files from more than Tcl and Tk. # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --with-$1=... # # Defines the following vars: # $1_BIN_DIR Full path to the directory containing # the $1Config.sh file #------------------------------------------------------------------------ AC_DEFUN([TEA_PATH_CONFIG], [ # # Ok, lets find the $1 configuration # First, look for one uninstalled. # the alternative search directory is invoked by --with-$1 # if test x"${no_$1}" = x ; then # we reset no_$1 in case something fails here no_$1=true AC_ARG_WITH($1, [ --with-$1 directory containing $1 configuration ($1Config.sh)], with_$1config=${withval}) AC_MSG_CHECKING([for $1 configuration]) AC_CACHE_VAL(ac_cv_c_$1config,[ # First check to see if --with-$1 was specified. if test x"${with_$1config}" != x ; then case ${with_$1config} in */$1Config.sh ) if test -f ${with_$1config}; then AC_MSG_WARN([--with-$1 argument should refer to directory containing $1Config.sh, not to $1Config.sh itself]) with_$1config=`echo ${with_$1config} | sed 's!/$1Config\.sh$!!'` fi;; esac if test -f "${with_$1config}/$1Config.sh" ; then ac_cv_c_$1config=`(cd ${with_$1config}; pwd)` else AC_MSG_ERROR([${with_$1config} directory doesn't contain $1Config.sh]) fi fi # then check for a private $1 installation if test x"${ac_cv_c_$1config}" = x ; then for i in \ ../$1 \ `ls -dr ../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \ `ls -dr ../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \ `ls -dr ../$1*[[0-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../$1*[[0-9]].[[0-9]]* 2>/dev/null` \ ../../$1 \ `ls -dr ../../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \ `ls -dr ../../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \ `ls -dr ../../$1*[[0-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../$1*[[0-9]].[[0-9]]* 2>/dev/null` \ ../../../$1 \ `ls -dr ../../../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \ `ls -dr ../../../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \ `ls -dr ../../../$1*[[0-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../../$1*[[0-9]].[[0-9]]* 2>/dev/null` \ ${srcdir}/../$1 \ `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \ `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \ `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]] 2>/dev/null` \ `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]]* 2>/dev/null` \ ; do if test -f "$i/$1Config.sh" ; then ac_cv_c_$1config=`(cd $i; pwd)` break fi if test -f "$i/unix/$1Config.sh" ; then ac_cv_c_$1config=`(cd $i/unix; pwd)` break fi done fi # check in a few common install locations if test x"${ac_cv_c_$1config}" = x ; then for i in `ls -d ${libdir} 2>/dev/null` \ `ls -d ${exec_prefix}/lib 2>/dev/null` \ `ls -d ${prefix}/lib 2>/dev/null` \ `ls -d /usr/local/lib 2>/dev/null` \ `ls -d /usr/contrib/lib 2>/dev/null` \ `ls -d /usr/lib 2>/dev/null` \ ; do if test -f "$i/$1Config.sh" ; then ac_cv_c_$1config=`(cd $i; pwd)` break fi done fi ]) if test x"${ac_cv_c_$1config}" = x ; then $1_BIN_DIR="# no $1 configs found" AC_MSG_WARN([Cannot find $1 configuration definitions]) exit 0 else no_$1= $1_BIN_DIR=${ac_cv_c_$1config} AC_MSG_RESULT([found $$1_BIN_DIR/$1Config.sh]) fi fi ]) #------------------------------------------------------------------------ # TEA_LOAD_CONFIG -- # # Load the $1Config.sh file # # Arguments: # # Requires the following vars to be set: # $1_BIN_DIR # # Results: # # Subst the following vars: # $1_SRC_DIR # $1_LIB_FILE # $1_LIB_SPEC # #------------------------------------------------------------------------ AC_DEFUN([TEA_LOAD_CONFIG], [ AC_MSG_CHECKING([for existence of ${$1_BIN_DIR}/$1Config.sh]) if test -f "${$1_BIN_DIR}/$1Config.sh" ; then AC_MSG_RESULT([loading]) . "${$1_BIN_DIR}/$1Config.sh" else AC_MSG_RESULT([file not found]) fi # # If the $1_BIN_DIR is the build directory (not the install directory), # then set the common variable name to the value of the build variables. # For example, the variable $1_LIB_SPEC will be set to the value # of $1_BUILD_LIB_SPEC. An extension should make use of $1_LIB_SPEC # instead of $1_BUILD_LIB_SPEC since it will work with both an # installed and uninstalled version of Tcl. # if test -f "${$1_BIN_DIR}/Makefile" ; then AC_MSG_WARN([Found Makefile - using build library specs for $1]) $1_LIB_SPEC=${$1_BUILD_LIB_SPEC} $1_STUB_LIB_SPEC=${$1_BUILD_STUB_LIB_SPEC} $1_STUB_LIB_PATH=${$1_BUILD_STUB_LIB_PATH} fi AC_SUBST($1_VERSION) AC_SUBST($1_BIN_DIR) AC_SUBST($1_SRC_DIR) AC_SUBST($1_LIB_FILE) AC_SUBST($1_LIB_SPEC) AC_SUBST($1_STUB_LIB_FILE) AC_SUBST($1_STUB_LIB_SPEC) AC_SUBST($1_STUB_LIB_PATH) ]) #------------------------------------------------------------------------ # TEA_PATH_CELIB -- # # Locate Keuchel's celib emulation layer for targeting Win/CE # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --with-celib=... # # Defines the following vars: # CELIB_DIR Full path to the directory containing # the include and platform lib files #------------------------------------------------------------------------ AC_DEFUN([TEA_PATH_CELIB], [ # First, look for one uninstalled. # the alternative search directory is invoked by --with-celib if test x"${no_celib}" = x ; then # we reset no_celib in case something fails here no_celib=true AC_ARG_WITH(celib,[ --with-celib=DIR use Windows/CE support library from DIR], with_celibconfig=${withval}) AC_MSG_CHECKING([for Windows/CE celib directory]) AC_CACHE_VAL(ac_cv_c_celibconfig,[ # First check to see if --with-celibconfig was specified. if test x"${with_celibconfig}" != x ; then if test -d "${with_celibconfig}/inc" ; then ac_cv_c_celibconfig=`(cd ${with_celibconfig}; pwd)` else AC_MSG_ERROR([${with_celibconfig} directory doesn't contain inc directory]) fi fi # then check for a celib library if test x"${ac_cv_c_celibconfig}" = x ; then for i in \ ../celib-palm-3.0 \ ../celib \ ../../celib-palm-3.0 \ ../../celib \ `ls -dr ../celib-*3.[[0-9]]* 2>/dev/null` \ ${srcdir}/../celib-palm-3.0 \ ${srcdir}/../celib \ `ls -dr ${srcdir}/../celib-*3.[[0-9]]* 2>/dev/null` \ ; do if test -d "$i/inc" ; then ac_cv_c_celibconfig=`(cd $i; pwd)` break fi done fi ]) if test x"${ac_cv_c_celibconfig}" = x ; then AC_MSG_ERROR([Cannot find celib support library directory]) else no_celib= CELIB_DIR=${ac_cv_c_celibconfig} CELIB_DIR=`echo "$CELIB_DIR" | sed -e 's!\\\!/!g'` AC_MSG_RESULT([found $CELIB_DIR]) fi fi ]) # Local Variables: # mode: autoconf # End: ================================================ FILE: ng/Togl2.1/texture.c ================================================ /* $Id: texture.c,v 1.14 2007/08/03 16:48:50 gregcouch Exp $ */ /* * Togl - a Tk OpenGL widget * Copyright (C) 1996-1997 Brian Paul and Ben Bederson * Copyright (C) 2006-2007 Greg Couch * See the LICENSE file for copyright details. */ /* * An example Togl program demonstrating texture mapping */ #define USE_TOGL_STUBS #include "togl.h" #include #include #if defined(TOGL_AGL) # include #else # include #endif #include "image.h" #undef TCL_STORAGE_CLASS #define TCL_STORAGE_CLASS DLLEXPORT #define CHECKER 0 #define FACE 1 #define TREE 2 static GLenum minfilter = GL_NEAREST_MIPMAP_LINEAR; static GLenum magfilter = GL_LINEAR; static GLenum swrap = GL_REPEAT; static GLenum twrap = GL_REPEAT; static GLenum envmode = GL_MODULATE; static GLubyte polycolor[4] = { 255, 255, 255, 255 }; static int teximage = CHECKER; static double coord_scale = 1; static double xrot = 0; static double yrot = 0; static double texscale = 1; static GLint width, height; static GLboolean blend = GL_FALSE; /* * Load a texture image. n is one of CHECKER, FACE or TREE. */ static void texture_image(int n) { if (n == CHECKER) { #define WIDTH 64 #define HEIGHT 64 GLubyte teximage[WIDTH * HEIGHT][4]; int i, j; for (i = 0; i < HEIGHT; i++) { for (j = 0; j < WIDTH; j++) { GLubyte value; value = ((i / 4 + j / 4) % 2) ? 0xff : 0x00; teximage[i * WIDTH + j][0] = value; teximage[i * WIDTH + j][1] = value; teximage[i * WIDTH + j][2] = value; teximage[i * WIDTH + j][3] = value; } } glEnable(GL_TEXTURE_2D); gluBuild2DMipmaps(GL_TEXTURE_2D, 4, WIDTH, HEIGHT, GL_RGBA, GL_UNSIGNED_BYTE, teximage); blend = GL_FALSE; #undef WIDTH #undef HEIGHT } else if (n == FACE) { TK_RGBImageRec *img = tkRGBImageLoad("ben.rgb"); if (img) { glEnable(GL_TEXTURE_2D); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); gluBuild2DMipmaps(GL_TEXTURE_2D, img->sizeZ, img->sizeX, img->sizeY, img->sizeZ == 3 ? GL_RGB : GL_RGBA, GL_UNSIGNED_BYTE, img->data); blend = GL_TRUE; } } else if (n == TREE) { TK_RGBImageRec *img = tkRGBImageLoad("tree2.rgba"); if (img) { glEnable(GL_TEXTURE_2D); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); gluBuild2DMipmaps(GL_TEXTURE_2D, img->sizeZ, img->sizeX, img->sizeY, img->sizeZ == 3 ? GL_RGB : GL_RGBA, GL_UNSIGNED_BYTE, img->data); blend = GL_TRUE; } } else { abort(); } } /* * Togl widget create callback. This is called by Tcl/Tk when the widget has * been realized. Here's where one may do some one-time context setup or * initializations. */ static int create_cb(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { glEnable(GL_DEPTH_TEST); /* Enable depth buffering */ texture_image(CHECKER); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magfilter); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minfilter); return TCL_OK; } /* * Togl widget reshape callback. This is called by Tcl/Tk when the widget * has been resized. Typically, we call glViewport and perhaps setup the * projection matrix. */ static int reshape_cb(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { Togl *togl; if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "pathName"); return TCL_ERROR; } if (Togl_GetToglFromObj(interp, objv[1], &togl) != TCL_OK) { return TCL_ERROR; } width = Togl_Width(togl); height = Togl_Height(togl); glViewport(0, 0, width, height); return TCL_OK; } static void check_error(char *where) { GLenum error; while (1) { error = glGetError(); if (error == GL_NO_ERROR) { break; } printf("OpenGL error near %s: %s\n", where, gluErrorString(error)); } } /* * Togl widget display callback. This is called by Tcl/Tk when the widget's * contents have to be redrawn. Typically, we clear the color and depth * buffers, render our objects, then swap the front/back color buffers. */ static int display_cb(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { float aspect = (float) width / (float) height; Togl *togl; if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "pathName"); return TCL_ERROR; } if (Togl_GetToglFromObj(interp, objv[1], &togl) != TCL_OK) { return TCL_ERROR; } check_error("begin display\n"); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); /* Draw background image */ glMatrixMode(GL_PROJECTION); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glDisable(GL_TEXTURE_2D); glDisable(GL_DEPTH_TEST); glBegin(GL_POLYGON); glColor3f(0, 0, 0.3f); glVertex2f(-1, -1); glColor3f(0, 0, 0.3f); glVertex2f(1, -1); glColor3f(0, 0, 0.9f); glVertex2f(1, 1); glColor3f(0, 0, 0.9f); glVertex2f(-1, 1); glEnd(); /* draw textured object */ glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustum(-aspect, aspect, -1, 1, 2, 10); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(0, 0, -5); glScaled(texscale, texscale, texscale); glRotated(yrot, 0, 1, 0); glRotated(xrot, 1, 0, 0); glEnable(GL_DEPTH_TEST); glEnable(GL_TEXTURE_2D); glColor4ubv(polycolor); if (blend) { glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); } glBegin(GL_POLYGON); glTexCoord2f(0, 0); glVertex2f(-1, -1); glTexCoord2d(coord_scale, 0); glVertex2f(1, -1); glTexCoord2d(coord_scale, coord_scale); glVertex2f(1, 1); glTexCoord2d(0, coord_scale); glVertex2f(-1, 1); glEnd(); glDisable(GL_BLEND); Togl_SwapBuffers(togl); return TCL_OK; } /* * Called when a magnification filter radio button is pressed. */ static int magfilter_cmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { static const char *names[] = { "GL_NEAREST", "GL_LINEAR", NULL }; static const GLenum magfilters[] = { GL_NEAREST, GL_LINEAR }; int result, index; Togl *togl; if (objc != 3) { Tcl_WrongNumArgs(interp, 1, objv, "pathName magnification-filter-type"); return TCL_ERROR; } if (Togl_GetToglFromObj(interp, objv[1], &togl) != TCL_OK) { return TCL_ERROR; } result = Tcl_GetIndexFromObj(interp, objv[2], names, "magnification filter type", 0, &index); if (result == TCL_OK) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magfilters[index]); Togl_PostRedisplay(togl); } return result; } /* * Called when a minification filter radio button is pressed. */ static int minfilter_cmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { static const char *names[] = { "GL_NEAREST", "GL_LINEAR", "GL_NEAREST_MIPMAP_NEAREST", "GL_LINEAR_MIPMAP_NEAREST", "GL_NEAREST_MIPMAP_LINEAR", "GL_LINEAR_MIPMAP_LINEAR", NULL }; static const GLenum minfilters[] = { GL_NEAREST, GL_LINEAR, GL_NEAREST_MIPMAP_NEAREST, GL_LINEAR_MIPMAP_NEAREST, GL_NEAREST_MIPMAP_LINEAR, GL_LINEAR_MIPMAP_LINEAR }; int result, index; Togl *togl; if (objc != 3) { Tcl_WrongNumArgs(interp, 1, objv, "pathName minification-filter-type"); return TCL_ERROR; } if (Togl_GetToglFromObj(interp, objv[1], &togl) != TCL_OK) { return TCL_ERROR; } result = Tcl_GetIndexFromObj(interp, objv[2], names, "minification filter type", 0, &index); if (result == TCL_OK) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minfilters[index]); Togl_PostRedisplay(togl); } return result; } static int xrot_cmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { Togl *togl; if (objc != 3) { Tcl_WrongNumArgs(interp, 1, objv, "pathName angle"); return TCL_ERROR; } if (Togl_GetToglFromObj(interp, objv[1], &togl) != TCL_OK) { return TCL_ERROR; } if (Tcl_GetDoubleFromObj(interp, objv[2], &xrot) != TCL_OK) { return TCL_ERROR; } Togl_PostRedisplay(togl); /* Let result string equal value */ Tcl_SetObjResult(interp, objv[2]); return TCL_OK; } static int yrot_cmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { Togl *togl; if (objc != 3) { Tcl_WrongNumArgs(interp, 1, objv, "pathName angle"); return TCL_ERROR; } if (Togl_GetToglFromObj(interp, objv[1], &togl) != TCL_OK) { return TCL_ERROR; } if (Tcl_GetDoubleFromObj(interp, objv[2], &yrot) != TCL_OK) { return TCL_ERROR; } Togl_PostRedisplay(togl); /* Let result string equal value */ Tcl_SetObjResult(interp, objv[2]); return TCL_OK; } static int texscale_cmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { Togl *togl; if (objc != 3) { Tcl_WrongNumArgs(interp, 1, objv, "pathName value"); return TCL_ERROR; } if (Togl_GetToglFromObj(interp, objv[1], &togl) != TCL_OK) { return TCL_ERROR; } if (Tcl_GetDoubleFromObj(interp, objv[2], &texscale) != TCL_OK) { return TCL_ERROR; } Togl_PostRedisplay(togl); /* Let result string equal value */ Tcl_SetObjResult(interp, objv[2]); return TCL_OK; } /* * Called when S texture coordinate wrapping is changed. */ static int swrap_cmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { static const char *names[] = { "GL_CLAMP", "GL_REPEAT", NULL }; static const GLenum swraps[] = { GL_CLAMP, GL_REPEAT }; int result, index; Togl *togl; if (objc != 3) { Tcl_WrongNumArgs(interp, 1, objv, "pathName wrap-mode"); return TCL_ERROR; } if (Togl_GetToglFromObj(interp, objv[1], &togl) != TCL_OK) { return TCL_ERROR; } result = Tcl_GetIndexFromObj(interp, objv[2], names, "wrap mode", 0, &index); if (result == TCL_OK) { swrap = swraps[index]; glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, swrap); Togl_PostRedisplay(togl); /* Let result string equal value */ Tcl_SetObjResult(interp, objv[2]); } return result; } /* * Called when T texture coordinate wrapping is changed. */ static int twrap_cmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { static const char *names[] = { "GL_CLAMP", "GL_REPEAT", NULL }; static const GLenum twraps[] = { GL_CLAMP, GL_REPEAT }; int result, index; Togl *togl; if (objc != 3) { Tcl_WrongNumArgs(interp, 1, objv, "pathName wrap-mode"); return TCL_ERROR; } if (Togl_GetToglFromObj(interp, objv[1], &togl) != TCL_OK) { return TCL_ERROR; } result = Tcl_GetIndexFromObj(interp, objv[2], names, "wrap mode", 0, &index); if (result == TCL_OK) { twrap = twraps[index]; glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, twrap); Togl_PostRedisplay(togl); /* Let result string equal value */ Tcl_SetObjResult(interp, objv[2]); } return result; } /* * Called when the texture environment mode is changed. */ static int envmode_cmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { static const char *names[] = { "GL_MODULATE", "GL_DECAL", "GL_BLEND", NULL }; static const GLenum envmodes[] = { GL_MODULATE, GL_DECAL, GL_BLEND }; int result, index; Togl *togl; if (objc != 3) { Tcl_WrongNumArgs(interp, 1, objv, "pathName texture-env-mode"); return TCL_ERROR; } if (Togl_GetToglFromObj(interp, objv[1], &togl) != TCL_OK) { return TCL_ERROR; } result = Tcl_GetIndexFromObj(interp, objv[2], names, "texture env mode", 0, &index); if (result == TCL_OK) { envmode = envmodes[index]; glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, envmode); Togl_PostRedisplay(togl); /* Let result string equal value */ Tcl_SetObjResult(interp, objv[2]); } return result; } /* * Called when the polygon color is changed. */ static int polycolor_cmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { Togl *togl; int r, g, b; if (objc != 5) { Tcl_WrongNumArgs(interp, 1, objv, "pathName r g b"); return TCL_ERROR; } if (Togl_GetToglFromObj(interp, objv[1], &togl) != TCL_OK) { return TCL_ERROR; } if (Tcl_GetIntFromObj(interp, objv[2], &r) != TCL_OK || Tcl_GetIntFromObj(interp, objv[3], &g) != TCL_OK || Tcl_GetIntFromObj(interp, objv[4], &b) != TCL_OK) { return TCL_ERROR; } polycolor[0] = r; polycolor[1] = g; polycolor[2] = b; Togl_PostRedisplay(togl); return TCL_OK; } /* * Called when the texture image is to be changed */ static int teximage_cmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { static const char *names[] = { "CHECKER", "FACE", "TREE", NULL }; static const GLenum teximages[] = { CHECKER, FACE, TREE }; int result, index; Togl *togl; if (objc != 3) { Tcl_WrongNumArgs(interp, 1, objv, "pathName texture-image-name"); return TCL_ERROR; } if (Togl_GetToglFromObj(interp, objv[1], &togl) != TCL_OK) { return TCL_ERROR; } result = Tcl_GetIndexFromObj(interp, objv[2], names, "texture image name", 0, &index); if (result == TCL_OK) { teximage = teximages[index]; texture_image(teximage); Togl_PostRedisplay(togl); /* Let result string equal value */ Tcl_SetObjResult(interp, objv[2]); } return result; } /* * Called when the texture coordinate scale is changed. */ static int coord_scale_cmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { double s; Togl *togl; if (objc != 3) { Tcl_WrongNumArgs(interp, 1, objv, "pathName scale"); return TCL_ERROR; } if (Togl_GetToglFromObj(interp, objv[1], &togl) != TCL_OK) { return TCL_ERROR; } if (Tcl_GetDoubleFromObj(interp, objv[2], &s) != TCL_OK) { return TCL_ERROR; } if (s > 0 && s < 10) { coord_scale = s; Togl_PostRedisplay(togl); } /* Let result string equal value */ Tcl_SetObjResult(interp, objv[2]); return TCL_OK; } EXTERN int Texture_Init(Tcl_Interp *interp) { /* * Initialize Tcl and the Togl widget module. */ if (Tcl_InitStubs(interp, "8.1", 0) == NULL || Togl_InitStubs(interp, "2.0", 0) == NULL) { return TCL_ERROR; } /* * Specify the C callback functions for widget creation, display, * and reshape. */ Tcl_CreateObjCommand(interp, "create_cb", create_cb, NULL, NULL); Tcl_CreateObjCommand(interp, "display_cb", display_cb, NULL, NULL); Tcl_CreateObjCommand(interp, "reshape_cb", reshape_cb, NULL, NULL); /* * Make a new Togl widget command so the Tcl code can set a C variable. */ Tcl_CreateObjCommand(interp, "min_filter", minfilter_cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "mag_filter", magfilter_cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "xrot", xrot_cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "yrot", yrot_cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "texscale", texscale_cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "swrap", swrap_cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "twrap", twrap_cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "envmode", envmode_cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "polycolor", polycolor_cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "teximage", teximage_cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "coord_scale", coord_scale_cmd, NULL, NULL); /* * Call Tcl_CreateCommand for application-specific commands, if * they weren't already created by the init procedures called above. */ return TCL_OK; } ================================================ FILE: ng/Togl2.1/texture.tcl ================================================ #!/bin/sh # the next line restarts using tclsh \ exec tclsh "$0" "$@" # $Id: texture.tcl,v 1.8 2007/08/03 16:48:50 gregcouch Exp $ # Togl - a Tk OpenGL widget # Copyright (C) 1996 Brian Paul and Ben Bederson # Copyright (C) 2006-2007 Greg Couch # See the LICENSE file for copyright details. # Togl texture map demo package provide texture 1.0 # add parent directory to path to find Togl's pkgIndex in current directory if { [file exists pkgIndex.tcl] } { set auto_path [linsert $auto_path 0 ..] } # following load also loads Tk and Togl packages load [file dirname [info script]]/texture[info sharedlibextension] # create ::texture namespace namespace eval ::texture { } # Called magnification filter changes proc ::texture::new_magfilter {} { global magfilter mag_filter .f1.view $magfilter } # Called minification filter changes proc ::texture::new_minfilter {} { global minfilter min_filter .f1.view $minfilter } # Called when texture image radio button changes proc ::texture::new_image {} { global image teximage .f1.view $image } # Called when texture S wrap button changes proc ::texture::new_swrap {} { global swrap swrap .f1.view $swrap } # Called when texture T wrap button changes proc ::texture::new_twrap {} { global twrap twrap .f1.view $twrap } # Called when texture environment radio button selected proc ::texture::new_env {} { global envmode envmode .f1.view $envmode } # Called when polygon color sliders change proc ::texture::new_color { foo } { global poly_red poly_green poly_blue polycolor .f1.view $poly_red $poly_green $poly_blue } proc ::texture::new_coord_scale { name element op } { global coord_scale coord_scale .f1.view $coord_scale } proc ::texture::take_photo {} { image create photo teximg .f1.view takephoto teximg teximg write image.ppm -format ppm } # Make the widgets proc ::texture::setup {} { global magfilter global minfilter global image global swrap global twrap global envmode global poly_red global poly_green global poly_blue global coord_scale global startx starty # location of mouse when button pressed global xangle yangle global xangle0 yangle0 global texscale texscale0 wm title . "Texture Map Options" ### Two frames: top half and bottom half frame .f1 frame .f2 ### The OpenGL window togl .f1.view -width 250 -height 250 -rgba true -double true -depth true -create create_cb -reshape reshape_cb -display display_cb ### Filter radio buttons frame .f1.filter -relief ridge -borderwidth 3 frame .f1.filter.mag -relief ridge -borderwidth 2 label .f1.filter.mag.label -text "Magnification Filter" -anchor w radiobutton .f1.filter.mag.nearest -text GL_NEAREST -anchor w -variable magfilter -value GL_NEAREST -command ::texture::new_magfilter radiobutton .f1.filter.mag.linear -text GL_LINEAR -anchor w -variable magfilter -value GL_LINEAR -command ::texture::new_magfilter frame .f1.filter.min -relief ridge -borderwidth 2 label .f1.filter.min.label -text "Minification Filter" -anchor w radiobutton .f1.filter.min.nearest -text GL_NEAREST -anchor w -variable minfilter -value GL_NEAREST -command ::texture::new_minfilter radiobutton .f1.filter.min.linear -text GL_LINEAR -anchor w -variable minfilter -value GL_LINEAR -command ::texture::new_minfilter radiobutton .f1.filter.min.nearest_mipmap_nearest -text GL_NEAREST_MIPMAP_NEAREST -anchor w -variable minfilter -value GL_NEAREST_MIPMAP_NEAREST -command ::texture::new_minfilter radiobutton .f1.filter.min.linear_mipmap_nearest -text GL_LINEAR_MIPMAP_NEAREST -anchor w -variable minfilter -value GL_LINEAR_MIPMAP_NEAREST -command ::texture::new_minfilter radiobutton .f1.filter.min.nearest_mipmap_linear -text GL_NEAREST_MIPMAP_LINEAR -anchor w -variable minfilter -value GL_NEAREST_MIPMAP_LINEAR -command ::texture::new_minfilter radiobutton .f1.filter.min.linear_mipmap_linear -text GL_LINEAR_MIPMAP_LINEAR -anchor w -variable minfilter -value GL_LINEAR_MIPMAP_LINEAR -command ::texture::new_minfilter pack .f1.filter.mag -fill x pack .f1.filter.mag.label -fill x pack .f1.filter.mag.nearest -side top -fill x pack .f1.filter.mag.linear -side top -fill x pack .f1.filter.min -fill both -expand true pack .f1.filter.min.label -side top -fill x pack .f1.filter.min.nearest -side top -fill x pack .f1.filter.min.linear -side top -fill x pack .f1.filter.min.nearest_mipmap_nearest -side top -fill x pack .f1.filter.min.linear_mipmap_nearest -side top -fill x pack .f1.filter.min.nearest_mipmap_linear -side top -fill x pack .f1.filter.min.linear_mipmap_linear -side top -fill x ### Texture coordinate scale and wrapping frame .f2.coord -relief ridge -borderwidth 3 frame .f2.coord.scale -relief ridge -borderwidth 2 label .f2.coord.scale.label -text "Max Texture Coord" -anchor w entry .f2.coord.scale.entry -textvariable coord_scale trace variable coord_scale w ::texture::new_coord_scale frame .f2.coord.s -relief ridge -borderwidth 2 label .f2.coord.s.label -text "GL_TEXTURE_WRAP_S" -anchor w radiobutton .f2.coord.s.repeat -text "GL_REPEAT" -anchor w -variable swrap -value GL_REPEAT -command ::texture::new_swrap radiobutton .f2.coord.s.clamp -text "GL_CLAMP" -anchor w -variable swrap -value GL_CLAMP -command ::texture::new_swrap frame .f2.coord.t -relief ridge -borderwidth 2 label .f2.coord.t.label -text "GL_TEXTURE_WRAP_T" -anchor w radiobutton .f2.coord.t.repeat -text "GL_REPEAT" -anchor w -variable twrap -value GL_REPEAT -command ::texture::new_twrap radiobutton .f2.coord.t.clamp -text "GL_CLAMP" -anchor w -variable twrap -value GL_CLAMP -command ::texture::new_twrap pack .f2.coord.scale -fill both -expand true pack .f2.coord.scale.label -side top -fill x pack .f2.coord.scale.entry -side top -fill x pack .f2.coord.s -fill x pack .f2.coord.s.label -side top -fill x pack .f2.coord.s.repeat -side top -fill x pack .f2.coord.s.clamp -side top -fill x pack .f2.coord.t -fill x pack .f2.coord.t.label -side top -fill x pack .f2.coord.t.repeat -side top -fill x pack .f2.coord.t.clamp -side top -fill x ### Texture image radio buttons (just happens to fit into the coord frame) frame .f2.env -relief ridge -borderwidth 3 frame .f2.env.image -relief ridge -borderwidth 2 label .f2.env.image.label -text "Texture Image" -anchor w radiobutton .f2.env.image.checker -text "Checker" -anchor w -variable image -value CHECKER -command ::texture::new_image radiobutton .f2.env.image.tree -text "Tree" -anchor w -variable image -value TREE -command ::texture::new_image radiobutton .f2.env.image.face -text "Face" -anchor w -variable image -value FACE -command ::texture::new_image pack .f2.env.image -fill x pack .f2.env.image.label -side top -fill x pack .f2.env.image.checker -side top -fill x pack .f2.env.image.tree -side top -fill x pack .f2.env.image.face -side top -fill x ### Texture Environment label .f2.env.label -text "GL_TEXTURE_ENV_MODE" -anchor w radiobutton .f2.env.modulate -text "GL_MODULATE" -anchor w -variable envmode -value GL_MODULATE -command ::texture::new_env radiobutton .f2.env.decal -text "GL_DECAL" -anchor w -variable envmode -value GL_DECAL -command ::texture::new_env radiobutton .f2.env.blend -text "GL_BLEND" -anchor w -variable envmode -value GL_BLEND -command ::texture::new_env pack .f2.env.label -fill x pack .f2.env.modulate -side top -fill x pack .f2.env.decal -side top -fill x pack .f2.env.blend -side top -fill x ### Polygon color frame .f2.color -relief ridge -borderwidth 3 label .f2.color.label -text "Polygon color" -anchor w scale .f2.color.red -label Red -from 0 -to 255 -orient horizontal -variable poly_red -command ::texture::new_color scale .f2.color.green -label Green -from 0 -to 255 -orient horizontal -variable poly_green -command ::texture::new_color scale .f2.color.blue -label Blue -from 0 -to 255 -orient horizontal -variable poly_blue -command ::texture::new_color pack .f2.color.label -fill x pack .f2.color.red -side top -fill x pack .f2.color.green -side top -fill x pack .f2.color.blue -side top -fill x ### Main widgets pack .f1.view -side left -fill both -expand true pack .f1.filter -side left -fill y pack .f1 -side top -fill both -expand true pack .f2.coord .f2.env -side left -fill both pack .f2.color -fill x pack .f2 -side top -fill x button .photo -text "Take Photo" -command ::texture::take_photo pack .photo -expand true -fill both button .quit -text Quit -command exit pack .quit -expand true -fill both bind .f1.view { set startx %x set starty %y set xangle0 $xangle set yangle0 $yangle } bind .f1.view { set xangle [expr $xangle0 + (%x - $startx) / 3.0 ] set yangle [expr $yangle0 + (%y - $starty) / 3.0 ] yrot .f1.view $xangle xrot .f1.view $yangle } bind .f1.view { set startx %x set starty %y set texscale0 $texscale } bind .f1.view { set q [ expr ($starty - %y) / 400.0 ] set texscale [expr $texscale0 * exp($q)] texscale .f1.view $texscale } # set default values: set minfilter GL_NEAREST_MIPMAP_LINEAR set magfilter GL_LINEAR set swrap GL_REPEAT set twrap GL_REPEAT set envmode GL_MODULATE set image CHECKER set poly_red 255 set poly_green 255 set poly_blue 255 set coord_scale 1.0 set xangle 0.0 set yangle 0.0 set texscale 1.0 } # Execution starts here! if { [info script] == $argv0 } { ::texture::setup } ================================================ FILE: ng/Togl2.1/togl.c ================================================ /* $Id: togl.c,v 1.142 2009/12/23 21:50:49 gregcouch Exp $ */ /* vi:set sw=4 expandtab: */ /* * Togl - a Tk OpenGL widget * * Copyright (C) 1996-2002 Brian Paul and Ben Bederson * Copyright (C) 2005-2009 Greg Couch * See the LICENSE file for copyright details. */ /* * Currently we support X11, Win32 and Mac OS X only */ #ifndef MODULE_SCOPE # ifdef __cplusplus # define MODULE_SCOPE extern "C" # else # define MODULE_SCOPE extern # endif #endif #pragma clang diagnostic ignored "-Wdeprecated-declarations" #define USE_TOGL_STUB_PROCS #include "togl.h" #include // don't need it on osx ??? #include #ifndef TOGL_USE_FONTS # define TOGL_USE_FONTS 1 #endif #if (TK_MAJOR_VERSION > 8 || TK_MINOR_VERSION > 4) && !defined(TOGL_WGL) /* X11 and Aqua font technology changed in 8.5 */ # undef TOGL_USE_FONTS #endif #ifndef TOGL_USE_OVERLAY # if defined(TOGL_X11) || defined(TOGL_WGL) # define TOGL_USE_OVERLAY 1 # endif #endif /* Use TCL_STUPID to cast (const char *) to (char *) where the Tcl function * prototype argument should really be const */ #define TCL_STUPID (char *) /* Use WIDGREC to cast widgRec or recordPtr arguments */ #define WIDGREC (char *) /*** Windows headers ***/ #if defined(TOGL_WGL) # define WIN32_LEAN_AND_MEAN # include # undef WIN32_LEAN_AND_MEAN # include # ifndef PFD_SUPPORT_COMPOSITION // for Vista -- not strictly needed because we don't use PFD_SUPPORT_GDI/BITMAP # define PFD_SUPPORT_COMPOSITION 0x00008000 # endif # include # include # include # ifdef _MSC_VER # include # else # ifdef UNICODE # define StringCchPrintf snwprintf # else # define StringCchPrintf snprintf # endif # endif /*** X Window System headers ***/ #elif defined(TOGL_X11) # include # include # include /* for XA_RGB_DEFAULT_MAP atom */ # if !defined(USE_SYSTEM_XMU) # include "Xmu/StdCmap.h" # else # if defined(__vms) # include /* for XmuLookupStandardColormap */ # else # include /* for XmuLookupStandardColormap */ # endif # endif # define GLX_GLXEXT_LEGACY /* include glxext.h separately */ # include /* we want the prototype typedefs from glxext.h */ # undef GLX_VERSION_1_3 # undef GLX_VERSION_1_4 # ifdef UNDEF_GET_PROC_ADDRESS # undef GLX_ARB_get_proc_address # endif # include # ifdef __sgi # include # endif # ifdef HAVE_AUTOSTEREO # include # endif /*** Mac Carbon headers ***/ #elif defined(TOGL_AGL) # define Cursor QDCursor # include # undef Cursor # include /* usa MacDrawable */ # include # define Togl_MacOSXGetDrawablePort(togl) TkMacOSXGetDrawablePort((Drawable) ((TkWindow *) togl->TkWin)->privatePtr) /*** Mac Cocoa headers ***/ #elif defined(TOGL_NSOPENGL) #undef panic # include # include /* Use NSOpenGLContext */ # include /* Use NSView */ # include /* Use NSWindow */ # include /* Use NSView setWantsBestResolutionOpenGLSurface */ # include /* Use NSEvent */ # include /* Use NSTouch */ # include /* Use NSRect */ # include /* Use MacDrawable */ # include # define Togl_MacOSXGetDrawablePort(togl) TkMacOSXGetDrawablePort((Drawable) ((TkWindow *) togl->TkWin)->privatePtr) # include # ifndef __MAC_10_7 /* Define Mac retina display routines not available prior to Mac OS 10.7 */ @interface NSView (NSOpenGLSurfaceResolution) - (BOOL)wantsBestResolutionOpenGLSurface; - (void)setWantsBestResolutionOpenGLSurface:(BOOL)flag; - (NSRect)convertRectToBacking:(NSRect)aRect; #define NSEventPhaseNone 0 @end # endif #else /* make sure only one platform defined */ # error Unsupported platform, or confused platform defines... #endif #define NC3D L"NVidia Consumer 3D Stereo" #ifndef STEREO_BUFFER_NONE /* From , but we use this constants elsewhere */ # define STEREO_BUFFER_NONE 0 # define STEREO_BUFFER_LEFT 1 # define STEREO_BUFFER_RIGHT 2 #endif /*** Standard C headers ***/ #include #include #include #ifdef TOGL_WGL # include #endif #if TK_MAJOR_VERSION < 8 # error Sorry Togl requires Tcl/Tk ver 8.0 or higher. #endif #ifdef USE_TCL_STUBS # if TK_MAJOR_VERSION < 8 || (TK_MAJOR_VERSION == 8 && TK_MINOR_VERSION < 1) # error Sorry stub support requires Tcl/Tk ver 8.1 or higher. # endif #endif #if defined(TOGL_AGL) # if TK_MAJOR_VERSION < 8 || (TK_MAJOR_VERSION == 8 && TK_MINOR_VERSION < 4) # error Sorry Mac Aqua version requires Tcl/Tk ver 8.4.0 or higher. # endif #endif /* TOGL_AGL */ // Seems to work with Apple Tcl 8.5 too.... // #if defined(TOGL_NSOPENGL) // # if TK_MAJOR_VERSION < 8 || (TK_MAJOR_VERSION == 8 && TK_MINOR_VERSION < 6) // # error Sorry Mac Cocoa version requires Tcl/Tk ver 8.6.0 or higher. // # endif // #endif /* TOGL_NSOPENGL */ #if defined(TOGL_WGL) && defined(_MSC_VER) # define snprintf _snprintf # pragma warning(disable:4995) #endif /* workaround for bug #123153 in tcl ver8.4a2 (tcl.h) */ #if defined(Tcl_InitHashTable) && defined(USE_TCL_STUBS) # undef Tcl_InitHashTable # define Tcl_InitHashTable (tclStubsPtr->tcl_InitHashTable) #endif #if TK_MAJOR_VERSION > 8 || (TK_MAJOR_VERSION == 8 && TK_MINOR_VERSION >= 4) # define HAVE_TK_SETCLASSPROCS /* pointer to Tk_SetClassProcs function in the stub table */ #if TK_MAJOR_VERSION == 8 && TK_MINOR_VERSION < 6 static void (*SetClassProcsPtr) _ANSI_ARGS_((Tk_Window, Tk_ClassProcs *, ClientData)); #else static void (*SetClassProcsPtr) _ANSI_ARGS_((Tk_Window, const Tk_ClassProcs *, ClientData)); #endif #endif /* * Copy of TkClassProcs declarations from tkInt.h * (this is needed for Tcl ver =< 8.4a3) */ typedef Window (TkClassCreateProc) _ANSI_ARGS_((Tk_Window tkwin, Window parent, ClientData instanceData)); typedef void (TkClassGeometryProc) _ANSI_ARGS_((ClientData instanceData)); typedef void (TkClassModalProc) _ANSI_ARGS_((Tk_Window tkwin, XEvent *eventPtr)); typedef struct TkClassProcs { TkClassCreateProc *createProc; TkClassGeometryProc *geometryProc; TkClassModalProc *modalProc; } TkClassProcs; /* Defaults */ #define DEFAULT_WIDTH "400" #define DEFAULT_HEIGHT "400" #define DEFAULT_IDENT "" #define DEFAULT_FONTNAME "Courier" #define DEFAULT_TIME "1" #ifdef TOGL_WGL /* Maximum size of a logical palette corresponding to a colormap in color index * mode. */ # define MAX_CI_COLORMAP_SIZE 4096 # define MAX_CI_COLORMAP_BITS 12 # if TOGL_USE_FONTS != 1 /* * copy of TkWinColormap from tkWinInt.h */ typedef struct { HPALETTE palette; /* Palette handle used when drawing. */ UINT size; /* Number of entries in the palette. */ int stale; /* 1 if palette needs to be realized, otherwise * 0. If the palette is stale, then an idle * handler is scheduled to realize the palette. */ Tcl_HashTable refCounts; /* Hash table of palette entry reference counts * indexed by pixel value. */ } TkWinColormap; # else # include # endif static LRESULT(CALLBACK *tkWinChildProc) (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) = NULL; # ifndef TK_WIN_CHILD_CLASS_NAME # define TK_WIN_CHILD_CLASS_NAME L"TkChild" # endif #endif /* TOGL_WGL */ #define MAX(a,b) (((a)>(b))?(a):(b)) #define TCL_ERR(interp, string) \ do { \ Tcl_ResetResult(interp); \ Tcl_AppendResult(interp, string, NULL); \ return TCL_ERROR; \ } while (0) #define ALL_EVENTS_MASK \ (KeyPressMask \ |KeyReleaseMask \ |ButtonPressMask \ |ButtonReleaseMask \ |EnterWindowMask \ |LeaveWindowMask \ |PointerMotionMask \ |ExposureMask \ |VisibilityChangeMask \ |FocusChangeMask \ |PropertyChangeMask \ |ColormapChangeMask) /* * The following structure contains pointers to functions used for * processing the custom "-stereo" option. Copied from tkPanedWindow.c. */ static int SetStereo(ClientData clientData, Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj **value, char *recordPtr, int internalOffset, char *oldInternalPtr, int flags); static Tcl_Obj *GetStereo(ClientData clientData, Tk_Window tkwin, char *recordPtr, int internalOffset); static void RestoreStereo(ClientData clientData, Tk_Window tkwin, char *internalPtr, char *oldInternalPtr); static Tk_ObjCustomOption stereoOption = { "stereo", /* name */ SetStereo, /* setProc */ GetStereo, /* getProc */ RestoreStereo, /* restoreProc */ NULL, /* freeProc */ 0 }; /* * The following structure contains pointers to functions used for * processing the custom "-pixelformat" option. Copied from tkPanedWindow.c. */ static int SetWideInt(ClientData clientData, Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj **value, char *recordPtr, int internalOffset, char *oldInternalPtr, int flags); static Tcl_Obj *GetWideInt(ClientData clientData, Tk_Window tkwin, char *recordPtr, int internalOffset); static void RestoreWideInt(ClientData clientData, Tk_Window tkwin, char *internalPtr, char *oldInternalPtr); static Tk_ObjCustomOption wideIntOption = { "wide int", /* name */ SetWideInt, /* setProc */ GetWideInt, /* getProc */ RestoreWideInt, /* restoreProc */ NULL, /* freeProc */ 0 }; /* * Stuff we initialize on a per package (Togl_Init) basis. * Since Tcl uses one interpreter per thread, any per-thread * data goes here. */ struct Togl_PackageGlobals { Tk_OptionTable optionTable; /* Used to parse options */ Togl *toglHead; /* Head of linked list of all Togl widgets */ int nextContextTag; /* Used to assign similar context tags */ }; typedef struct Togl_PackageGlobals Togl_PackageGlobals; extern ToglStubs toglStubs; /* should be only non-const global */ #if defined(TOGL_NSOPENGL) /* Handle window drags between retina and non-retina displays. */ @interface ToglNSView : NSView { struct Togl *togl; } - (void) setTogl: (struct Togl*)t; - (void) viewDidChangeBackingProperties; - (void) magnifyWithEvent: (NSEvent *)event; - (void) rotateWithEvent: (NSEvent *)event; - (void) scrollWheel: (NSEvent *)event; - (void)touchesBeganWithEvent:(NSEvent *)event; - (void)touchesMovedWithEvent:(NSEvent *)event; - (void)touchesEndedWithEvent:(NSEvent *)event; - (void)touchesCancelledWithEvent:(NSEvent *)event; - (void)reportEventTouches:(NSEvent *)event; @end #endif struct Togl { Togl *Next; /* next in linked list */ #if defined(TOGL_WGL) HGLRC Ctx; /* OpenGL rendering context to be made current */ HDC tglGLHdc; /* Device context of device that OpenGL calls * will be drawn on */ int CiColormapSize; /* (Maximum) size of colormap in color index * mode */ #elif defined(TOGL_X11) GLXContext Ctx; /* Normal planes GLX context */ #elif defined(TOGL_AGL) AGLContext Ctx; #elif defined(TOGL_NSOPENGL) NSOpenGLContext *Ctx; ToglNSView *nsview; #endif int contextTag; /* all contexts with same tag share display * lists */ XVisualInfo *VisInfo; /* Visual info of the current */ Display *display; /* X's token for the window's display. */ Tk_Window TkWin; /* Tk window structure */ Tcl_Interp *Interp; /* Tcl interpreter */ Tcl_Command widgetCmd; /* Token for togl's widget command */ Togl_PackageGlobals *tpg; /* Used to access globals */ #ifndef NO_TK_CURSOR Tk_Cursor Cursor; /* The widget's cursor */ #endif int Width, Height; /* Dimensions of window */ int PixelScale; /* Graphics pixels per Tk pixel. */ /* 1 for normal display. */ /* 2 for Mac retina display. */ int SetGrid; /* positive is grid size for window manager */ int TimerInterval; /* Time interval for timer in milliseconds */ Tcl_TimerToken timerHandler; /* Token for togl's timer handler */ Bool RgbaFlag; /* configuration flags (ala GLX parameters) */ int RgbaRed; int RgbaGreen; int RgbaBlue; Bool DoubleFlag; Bool DepthFlag; int DepthSize; Bool AccumFlag; int AccumRed; int AccumGreen; int AccumBlue; int AccumAlpha; Bool AlphaFlag; int AlphaSize; Bool StencilFlag; int StencilSize; Bool PrivateCmapFlag; Bool OverlayFlag; int Stereo; double EyeSeparation; double Convergence; GLuint riStencilBit; /* row interleaved stencil bit */ int AuxNumber; Bool Indirect; #if defined(TOGL_NSOPENGL) NSOpenGLPixelFormat *PixelFormat; #else Tcl_WideInt PixelFormat; #endif int SwapInterval; Bool MultisampleFlag; Bool FullscreenFlag; Bool PbufferFlag; Bool LargestPbufferFlag; #if defined(TOGL_X11) GLXFBConfig fbcfg; /* cache FBConfig for pbuffer creation */ GLXPbuffer pbuf; #elif defined(TOGL_WGL) HPBUFFERARB pbuf; int pbufferLost; #elif defined(TOGL_AGL) AGLPbuffer pbuf; #elif defined(TOGL_NSOPENGL) NSOpenGLPixelBuffer *pbuf; #endif const char *ShareList; /* name (ident) of Togl to share dlists with */ const char *ShareContext; /* name (ident) to share OpenGL context with */ const char *Ident; /* User's identification string */ ClientData Client_Data; /* Pointer to user data */ Bool UpdatePending; /* Should normal planes be redrawn? */ Tcl_Obj *CreateProc; /* Callback when widget is realized */ Tcl_Obj *DisplayProc; /* Callback when widget is redrawn */ Tcl_Obj *ReshapeProc; /* Callback when window size changes */ Tcl_Obj *DestroyProc; /* Callback when widget is destroyed */ Tcl_Obj *TimerProc; /* Callback when widget is idle */ Tcl_Obj *MagnifyProc; /* Callback for track pad pinch gesture */ Tcl_Obj *RotateProc; /* Callback for track pad rotate gesture */ Tcl_Obj *ScrollProc; /* Callback for track pad scroll gesture */ Tcl_Obj *ScrollWheelProc; /* Callback for mouse scroll wheel, not trackpad */ Tcl_Obj *TouchesProc; /* Callback for track pad touches */ /* Overlay stuff */ #if defined(TOGL_X11) GLXContext OverlayCtx; /* Overlay planes OpenGL context */ #elif defined(TOGL_WGL) HGLRC tglGLOverlayHglrc; #endif Window OverlayWindow; /* The overlay window, or 0 */ Tcl_Obj *OverlayDisplayProc; /* Overlay redraw proc */ Bool OverlayUpdatePending; /* Should overlay be redrawn? */ Colormap OverlayCmap; /* colormap for overlay is created */ int OverlayTransparentPixel; /* transparent pixel */ Bool OverlayIsMapped; GLfloat *RedMap; /* Index2RGB Maps for Color index modes */ GLfloat *GreenMap; GLfloat *BlueMap; GLint MapSize; /* = Number of indices in our Togl */ int currentStereoBuffer; #ifdef HAVE_AUTOSTEREO int as_initialized; /* for autostereo package */ ASHandle ash; /* for autostereo package */ #endif int badWindow; /* true when Togl_MakeWindow fails or should * create a dummy window */ }; int Togl_CallCallback(Togl *togl, Tcl_Obj *cmd); static int Togl_CallCallback_P(Togl *togl, Tcl_Obj *cmd, double *params, int nparams); #if defined(TOGL_NSOPENGL) static int viewPixelScale(NSView *nsview); @implementation ToglNSView - (void) setTogl: (struct Togl*)t { togl = t; } - (void) viewDidChangeBackingProperties { [super viewDidChangeBackingProperties]; if (togl && togl->ReshapeProc) { int pscale = viewPixelScale(self); if (pscale != togl->PixelScale) { togl->PixelScale = pscale; if (togl->ReshapeProc) (void) Togl_CallCallback(togl, togl->ReshapeProc); Togl_PostRedisplay(togl); } } } - (void) magnifyWithEvent: (NSEvent *)event { if (togl && togl->MagnifyProc) { double mag = [event magnification] + 1.0; (void) Togl_CallCallback_P(togl, togl->MagnifyProc, &mag, 1); } } - (void) rotateWithEvent: (NSEvent *)event { if (togl && togl->RotateProc) { double deg = [event rotation]; (void) Togl_CallCallback_P(togl, togl->RotateProc, °, 1); } } - (void) scrollWheel: (NSEvent *)event { if (togl && (togl->ScrollProc || togl->ScrollWheelProc)) { float dx = [event deltaX], dy = [event deltaY]; if (dx != 0 || dy != 0) { // float track_pad = ((([event phase] == NSEventPhaseNone) && // ([event momentumPhase] == NSEventPhaseNone)) ? 0 : 1); float track_pad = ([event subtype] == NSMouseEventSubtype ? 0 : 1); double args[3] = {dx, dy, track_pad}; if (togl->ScrollProc) (void) Togl_CallCallback_P(togl, togl->ScrollProc, args, 3); if (togl->ScrollWheelProc && !track_pad) (void) Togl_CallCallback_P(togl, togl->ScrollWheelProc, args+1, 1); } } } - (void)touchesBeganWithEvent:(NSEvent *)event { NSWindow *win = [self window]; [win makeKeyWindow]; [win makeMainWindow]; [self reportEventTouches:event]; } - (void)touchesMovedWithEvent:(NSEvent *)event { [self reportEventTouches:event]; } - (void)touchesEndedWithEvent:(NSEvent *)event { [self reportEventTouches:event]; } - (void)touchesCancelledWithEvent:(NSEvent *)event; { [self reportEventTouches:event]; } - (void)reportEventTouches: (NSEvent *)event { if (togl && togl->TouchesProc) { NSSet *touches = [event touchesMatchingPhase:NSTouchPhaseTouching inView:self]; int n = touches.count, i; double *id_xy = NULL; if (n >= 0) { id_xy = (double *)malloc(3*n*sizeof(double)); NSArray *array = [touches allObjects]; for (i = 0 ; i < n ; ++i) { NSTouch *t = [array objectAtIndex:i]; id_xy[3*i] = (long)t.identity; id_xy[3*i+1] = t.normalizedPosition.x * t.deviceSize.width; id_xy[3*i+2] = t.normalizedPosition.y * t.deviceSize.height; } (void) Togl_CallCallback_P(togl, togl->TouchesProc, id_xy, 3*n); if (id_xy) free(id_xy); } } } @end #endif /* * Prototypes for functions local to this file */ static int Togl_ObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv); static void Togl_ObjCmdDelete(ClientData clientData); static void Togl_EventProc(ClientData clientData, XEvent *eventPtr); static void Togl_RedisplayProc(ClientData clientData, XEvent *eventPtr); static Window Togl_MakeWindow(Tk_Window, Window, ClientData); static void Togl_WorldChanged(ClientData); static void Togl_SetViewPort(const struct Togl *); #ifdef MESA_COLOR_HACK static int get_free_color_cells(Display *display, int screen, Colormap colormap); static void free_default_color_cells(Display *display, Colormap colormap); #endif static void ToglCmdDeletedProc(ClientData); #if defined(TOGL_AGL) || defined(TOGL_NSOPENGL) static void SetMacBufRect(Togl *togl); #endif #if defined(TOGL_WGL) # include "toglWGL.c" #elif defined(TOGL_AGL) # include "toglAGL.c" #elif defined(TOGL_NSOPENGL) # include "toglNSOpenGL.c" #elif defined(TOGL_X11) # include "toglGLX.c" #endif /* * Setup Togl widget configuration options: */ #define GEOMETRY_MASK 0x1 /* widget geometry */ #define FORMAT_MASK 0x2 /* pixel format */ #define CURSOR_MASK 0x4 #define TIMER_MASK 0x8 #define OVERLAY_MASK 0x10 #define SWAP_MASK 0x20 #define STEREO_MASK 0x40 #define STEREO_FORMAT_MASK 0x80 static Tk_OptionSpec optionSpecs[] = { {TK_OPTION_PIXELS, TCL_STUPID "-height", "height", "Height", DEFAULT_HEIGHT, -1, Tk_Offset(Togl, Height), 0, NULL, GEOMETRY_MASK}, {TK_OPTION_PIXELS, TCL_STUPID "-width", "width", "Width", DEFAULT_WIDTH, -1, Tk_Offset(Togl, Width), 0, NULL, GEOMETRY_MASK}, {TK_OPTION_INT, TCL_STUPID "-pixelscale", "pixelscale", "PixelScale", "1", -1, Tk_Offset(Togl, PixelScale), 0, NULL, FORMAT_MASK}, {TK_OPTION_BOOLEAN, TCL_STUPID "-rgba", "rgba", "Rgba", "true", -1, Tk_Offset(Togl, RgbaFlag), 0, NULL, FORMAT_MASK}, {TK_OPTION_INT, TCL_STUPID "-redsize", "redsize", "RedSize", "1", -1, Tk_Offset(Togl, RgbaRed), 0, NULL, FORMAT_MASK}, {TK_OPTION_INT, TCL_STUPID "-greensize", "greensize", "GreenSize", "1", -1, Tk_Offset(Togl, RgbaGreen), 0, NULL, FORMAT_MASK}, {TK_OPTION_INT, TCL_STUPID "-bluesize", "bluesize", "BlueSize", "1", -1, Tk_Offset(Togl, RgbaBlue), 0, NULL, FORMAT_MASK}, {TK_OPTION_BOOLEAN, TCL_STUPID "-double", "double", "Double", "false", -1, Tk_Offset(Togl, DoubleFlag), 0, NULL, FORMAT_MASK}, {TK_OPTION_BOOLEAN, TCL_STUPID "-depth", "depth", "Depth", "false", -1, Tk_Offset(Togl, DepthFlag), 0, NULL, FORMAT_MASK}, {TK_OPTION_INT, TCL_STUPID "-depthsize", "depthsize", "DepthSize", "1", -1, Tk_Offset(Togl, DepthSize), 0, NULL, FORMAT_MASK}, {TK_OPTION_BOOLEAN, TCL_STUPID "-accum", "accum", "Accum", "false", -1, Tk_Offset(Togl, AccumFlag), 0, NULL, FORMAT_MASK}, {TK_OPTION_INT, TCL_STUPID "-accumredsize", "accumredsize", "AccumRedSize", "1", -1, Tk_Offset(Togl, AccumRed), 0, NULL, FORMAT_MASK}, {TK_OPTION_INT, TCL_STUPID "-accumgreensize", "accumgreensize", "AccumGreenSize", "1", -1, Tk_Offset(Togl, AccumGreen), 0, NULL, FORMAT_MASK}, {TK_OPTION_INT, TCL_STUPID "-accumbluesize", "accumbluesize", "AccumBlueSize", "1", -1, Tk_Offset(Togl, AccumBlue), 0, NULL, FORMAT_MASK}, {TK_OPTION_INT, TCL_STUPID "-accumalphasize", "accumalphasize", "AccumAlphaSize", "1", -1, Tk_Offset(Togl, AccumAlpha), 0, NULL, FORMAT_MASK}, {TK_OPTION_BOOLEAN, TCL_STUPID "-alpha", "alpha", "Alpha", "false", -1, Tk_Offset(Togl, AlphaFlag), 0, NULL, FORMAT_MASK}, {TK_OPTION_INT, TCL_STUPID "-alphasize", "alphasize", "AlphaSize", "1", -1, Tk_Offset(Togl, AlphaSize), 0, NULL, FORMAT_MASK}, {TK_OPTION_BOOLEAN, TCL_STUPID "-stencil", "stencil", "Stencil", "false", -1, Tk_Offset(Togl, StencilFlag), 0, NULL, FORMAT_MASK}, {TK_OPTION_INT, TCL_STUPID "-stencilsize", "stencilsize", "StencilSize", "1", -1, Tk_Offset(Togl, StencilSize), 0, NULL, FORMAT_MASK}, {TK_OPTION_INT, TCL_STUPID "-auxbuffers", "auxbuffers", "AuxBuffers", "0", -1, Tk_Offset(Togl, AuxNumber), 0, NULL, FORMAT_MASK}, {TK_OPTION_BOOLEAN, TCL_STUPID "-privatecmap", "privateCmap", "PrivateCmap", "false", -1, Tk_Offset(Togl, PrivateCmapFlag), 0, NULL, FORMAT_MASK}, {TK_OPTION_BOOLEAN, TCL_STUPID "-overlay", "overlay", "Overlay", "false", -1, Tk_Offset(Togl, OverlayFlag), 0, NULL, OVERLAY_MASK}, {TK_OPTION_CUSTOM, TCL_STUPID "-stereo", "stereo", "Stereo", "", -1, Tk_Offset(Togl, Stereo), 0, (ClientData) &stereoOption, STEREO_FORMAT_MASK}, {TK_OPTION_DOUBLE, TCL_STUPID "-eyeseparation", "eyeseparation", "EyeSeparation", "2.0", -1, Tk_Offset(Togl, EyeSeparation), 0, NULL, STEREO_MASK}, {TK_OPTION_DOUBLE, TCL_STUPID "-convergence", "convergence", "Convergence", "35.0", -1, Tk_Offset(Togl, Convergence), 0, NULL, STEREO_MASK}, #ifndef NO_TK_CURSOR {TK_OPTION_CURSOR, TCL_STUPID "-cursor", "cursor", "Cursor", "", -1, Tk_Offset(Togl, Cursor), TK_OPTION_NULL_OK, NULL, CURSOR_MASK}, #endif {TK_OPTION_INT, TCL_STUPID "-setgrid", "setGrid", "SetGrid", "0", -1, Tk_Offset(Togl, SetGrid), 0, NULL, GEOMETRY_MASK}, {TK_OPTION_INT, TCL_STUPID "-time", "time", "Time", DEFAULT_TIME, -1, Tk_Offset(Togl, TimerInterval), 0, NULL, TIMER_MASK}, {TK_OPTION_STRING, TCL_STUPID "-sharelist", "sharelist", "ShareList", NULL, -1, Tk_Offset(Togl, ShareList), 0, NULL, FORMAT_MASK}, {TK_OPTION_STRING, TCL_STUPID "-sharecontext", "sharecontext", "ShareContext", NULL, -1, Tk_Offset(Togl, ShareContext), 0, NULL, FORMAT_MASK}, {TK_OPTION_STRING, TCL_STUPID "-ident", "ident", "Ident", DEFAULT_IDENT, -1, Tk_Offset(Togl, Ident), 0, NULL, 0}, {TK_OPTION_BOOLEAN, TCL_STUPID "-indirect", "indirect", "Indirect", "false", -1, Tk_Offset(Togl, Indirect), 0, NULL, FORMAT_MASK}, {TK_OPTION_CUSTOM, TCL_STUPID "-pixelformat", "pixelFormat", "PixelFormat", "0", -1, Tk_Offset(Togl, PixelFormat), 0, (ClientData) &wideIntOption, FORMAT_MASK}, {TK_OPTION_INT, TCL_STUPID "-swapinterval", "swapInterval", "SwapInterval", "1", -1, Tk_Offset(Togl, SwapInterval), 0, NULL, SWAP_MASK}, #if 0 {TK_OPTION_BOOLEAN, TCL_STUPID "-fullscreen", "fullscreen", "Fullscreen", "false", -1, Tk_Offset(Togl, FullscreenFlag), 0, NULL, GEOMETRY_MASK|FORMAT_MASK}, #endif {TK_OPTION_BOOLEAN, TCL_STUPID "-multisample", "multisample", "Multisample", "false", -1, Tk_Offset(Togl, MultisampleFlag), 0, NULL, FORMAT_MASK}, {TK_OPTION_BOOLEAN, TCL_STUPID "-pbuffer", "pbuffer", "Pbuffer", "false", -1, Tk_Offset(Togl, PbufferFlag), 0, NULL, FORMAT_MASK}, {TK_OPTION_BOOLEAN, TCL_STUPID "-largestpbuffer", "largestpbuffer", "LargestPbuffer", "false", -1, Tk_Offset(Togl, LargestPbufferFlag), 0, NULL, 0}, {TK_OPTION_STRING, TCL_STUPID "-createcommand", "createCommand", "CallbackCommand", NULL, Tk_Offset(Togl, CreateProc), -1, TK_OPTION_NULL_OK, NULL, 0}, {TK_OPTION_SYNONYM, TCL_STUPID "-create", NULL, NULL, NULL, -1, -1, 0, (ClientData) "-createcommand", 0}, {TK_OPTION_STRING, TCL_STUPID "-displaycommand", "displayCommand", "CallbackCommand", NULL, Tk_Offset(Togl, DisplayProc), -1, TK_OPTION_NULL_OK, NULL, 0}, {TK_OPTION_SYNONYM, TCL_STUPID "-display", NULL, NULL, NULL, -1, -1, 0, (ClientData) "-displaycommand", 0}, {TK_OPTION_STRING, TCL_STUPID "-reshapecommand", "reshapeCommand", "CallbackCommand", NULL, Tk_Offset(Togl, ReshapeProc), -1, TK_OPTION_NULL_OK, NULL, 0}, {TK_OPTION_SYNONYM, TCL_STUPID "-reshape", NULL, NULL, NULL, -1, -1, 0, (ClientData) "-reshapecommand", 0}, {TK_OPTION_STRING, TCL_STUPID "-destroycommand", "destroyCommand", "CallbackCommand", NULL, Tk_Offset(Togl, DestroyProc), -1, TK_OPTION_NULL_OK, NULL, 0}, {TK_OPTION_SYNONYM, TCL_STUPID "-destroy", NULL, NULL, NULL, -1, -1, 0, (ClientData) "-destroycommand", 0}, {TK_OPTION_STRING, TCL_STUPID "-timercommand", "timerCommand", "CallabckCommand", NULL, Tk_Offset(Togl, TimerProc), -1, TK_OPTION_NULL_OK, NULL, 0}, {TK_OPTION_SYNONYM, TCL_STUPID "-timer", NULL, NULL, NULL, -1, -1, 0, (ClientData) "-timercommand", 0}, {TK_OPTION_STRING, TCL_STUPID "-overlaydisplaycommand", "overlaydisplayCommand", "CallbackCommand", NULL, Tk_Offset(Togl, OverlayDisplayProc), -1, TK_OPTION_NULL_OK, NULL, OVERLAY_MASK}, {TK_OPTION_SYNONYM, TCL_STUPID "-overlaydisplay", NULL, NULL, NULL, -1, -1, 0, (ClientData) "-overlaydisplaycommand", 0}, {TK_OPTION_STRING, TCL_STUPID "-magnifycommand", "magnifyCommand", "CallbackCommand", NULL, Tk_Offset(Togl, MagnifyProc), -1, TK_OPTION_NULL_OK, NULL, 0}, {TK_OPTION_STRING, TCL_STUPID "-rotatecommand", "rotateCommand", "CallbackCommand", NULL, Tk_Offset(Togl, RotateProc), -1, TK_OPTION_NULL_OK, NULL, 0}, {TK_OPTION_STRING, TCL_STUPID "-scrollcommand", "scrollCommand", "CallbackCommand", NULL, Tk_Offset(Togl, ScrollProc), -1, TK_OPTION_NULL_OK, NULL, 0}, {TK_OPTION_STRING, TCL_STUPID "-scrollwheelcommand", "scrollWheelCommand", "CallbackCommand", NULL, Tk_Offset(Togl, ScrollWheelProc), -1, TK_OPTION_NULL_OK, NULL, 0}, {TK_OPTION_STRING, TCL_STUPID "-touchescommand", "touchesCommand", "CallbackCommand", NULL, Tk_Offset(Togl, TouchesProc), -1, TK_OPTION_NULL_OK, NULL, 0}, /* Tcl3D backwards compatibility */ {TK_OPTION_SYNONYM, TCL_STUPID "-createproc", NULL, NULL, NULL, -1, -1, 0, (ClientData) "-createcommand", 0}, {TK_OPTION_SYNONYM, TCL_STUPID "-displayproc", NULL, NULL, NULL, -1, -1, 0, (ClientData) "-displaycommand", 0}, {TK_OPTION_SYNONYM, TCL_STUPID "-reshapeproc", NULL, NULL, NULL, -1, -1, 0, (ClientData) "-reshapecommand", 0}, /* end Tcl3D compatibility */ {TK_OPTION_END, NULL, NULL, NULL, NULL, -1, -1, 0, NULL, 0} }; /* * Add given togl widget to linked list. */ static void AddToList(Togl *t) { t->Next = t->tpg->toglHead; t->tpg->toglHead = t; } /* * Remove given togl widget from linked list. */ static void RemoveFromList(Togl *t) { Togl *prev; Togl *cur; for (cur = t->tpg->toglHead, prev = NULL; cur; prev = cur, cur = cur->Next) { if (t != cur) continue; if (prev) { prev->Next = cur->Next; } else { t->tpg->toglHead = cur->Next; } break; } if (cur) cur->Next = NULL; } /* * Return pointer to togl widget given a user identifier string. */ static Togl * FindTogl(Togl *togl, const char *ident) { Togl *t; if (ident[0] != '.') { for (t = togl->tpg->toglHead; t; t = t->Next) { if (strcmp(t->Ident, ident) == 0) break; } } else { for (t = togl->tpg->toglHead; t; t = t->Next) { const char *pathname = Tk_PathName(t->TkWin); if (strcmp(pathname, ident) == 0) break; } } return t; } /* * Return pointer to another togl widget with same OpenGL context. */ static Togl * FindToglWithSameContext(const Togl *togl) { Togl *t; for (t = togl->tpg->toglHead; t != NULL; t = t->Next) { if (t == togl) continue; if (t->Ctx == togl->Ctx) { return t; } } return NULL; } #if TOGL_USE_OVERLAY /* * Return pointer to another togl widget with same OpenGL overlay context. */ static Togl * FindToglWithSameOverlayContext(const Togl *togl) { Togl *t; for (t = togl->tpg->toglHead; t != NULL; t = t->Next) { if (t == togl) continue; # if defined(TOGL_X11) if (t->OverlayCtx == togl->OverlayCtx) # elif defined(TOGL_WGL) if (t->tglGLOverlayHglrc == togl->tglGLOverlayHglrc) # endif { return t; } } return NULL; } #endif #if defined(TOGL_X11) /* * Return an X colormap to use for OpenGL RGB-mode rendering. * Input: dpy - the X display * scrnum - the X screen number * visinfo - the XVisualInfo as returned by glXChooseVisual() * Return: an X Colormap or 0 if there's a _serious_ error. */ static Colormap get_rgb_colormap(Display *dpy, int scrnum, const XVisualInfo *visinfo, Tk_Window tkwin) { Atom hp_cr_maps; Status status; int numCmaps; int i; XStandardColormap *standardCmaps; Window root = XRootWindow(dpy, scrnum); Bool using_mesa; /* * First check if visinfo's visual matches the default/root visual. */ if (visinfo->visual == Tk_Visual(tkwin)) { /* use the default/root colormap */ Colormap cmap; cmap = Tk_Colormap(tkwin); # ifdef MESA_COLOR_HACK (void) get_free_color_cells(dpy, scrnum, cmap); # endif return cmap; } /* * Check if we're using Mesa. */ if (strstr(glXQueryServerString(dpy, scrnum, GLX_VERSION), "Mesa")) { using_mesa = True; } else { using_mesa = False; } /* * Next, if we're using Mesa and displaying on an HP with the "Color * Recovery" feature and the visual is 8-bit TrueColor, search for a * special colormap initialized for dithering. Mesa will know how to * dither using this colormap. */ if (using_mesa) { hp_cr_maps = XInternAtom(dpy, "_HP_RGB_SMOOTH_MAP_LIST", True); if (hp_cr_maps # ifdef __cplusplus && visinfo->visual->c_class == TrueColor # else && visinfo->visual->class == TrueColor # endif && visinfo->depth == 8) { status = XGetRGBColormaps(dpy, root, &standardCmaps, &numCmaps, hp_cr_maps); if (status) { for (i = 0; i < numCmaps; i++) { if (standardCmaps[i].visualid == visinfo->visual->visualid) { Colormap cmap = standardCmaps[i].colormap; (void) XFree(standardCmaps); return cmap; } } (void) XFree(standardCmaps); } } } /* * Next, try to find a standard X colormap. */ # if !HP && !SUN # ifndef SOLARIS_BUG status = XmuLookupStandardColormap(dpy, visinfo->screen, visinfo->visualid, visinfo->depth, XA_RGB_DEFAULT_MAP, /* replace */ False, /* retain */ True); if (status == 1) { status = XGetRGBColormaps(dpy, root, &standardCmaps, &numCmaps, XA_RGB_DEFAULT_MAP); if (status == 1) { for (i = 0; i < numCmaps; i++) { if (standardCmaps[i].visualid == visinfo->visualid) { Colormap cmap = standardCmaps[i].colormap; (void) XFree(standardCmaps); return cmap; } } (void) XFree(standardCmaps); } } # endif # endif /* * If we get here, give up and just allocate a new colormap. */ return XCreateColormap(dpy, root, visinfo->visual, AllocNone); } #elif defined(TOGL_WGL) /* Code to create RGB palette is taken from the GENGL sample program of Win32 * SDK */ static const unsigned char threeto8[8] = { 0, 0111 >> 1, 0222 >> 1, 0333 >> 1, 0444 >> 1, 0555 >> 1, 0666 >> 1, 0377 }; static const unsigned char twoto8[4] = { 0, 0x55, 0xaa, 0xff }; static const unsigned char oneto8[2] = { 0, 255 }; static const int defaultOverride[13] = { 0, 3, 24, 27, 64, 67, 88, 173, 181, 236, 247, 164, 91 }; static const PALETTEENTRY defaultPalEntry[20] = { {0, 0, 0, 0}, {0x80, 0, 0, 0}, {0, 0x80, 0, 0}, {0x80, 0x80, 0, 0}, {0, 0, 0x80, 0}, {0x80, 0, 0x80, 0}, {0, 0x80, 0x80, 0}, {0xC0, 0xC0, 0xC0, 0}, {192, 220, 192, 0}, {166, 202, 240, 0}, {255, 251, 240, 0}, {160, 160, 164, 0}, {0x80, 0x80, 0x80, 0}, {0xFF, 0, 0, 0}, {0, 0xFF, 0, 0}, {0xFF, 0xFF, 0, 0}, {0, 0, 0xFF, 0}, {0xFF, 0, 0xFF, 0}, {0, 0xFF, 0xFF, 0}, {0xFF, 0xFF, 0xFF, 0} }; static unsigned char ComponentFromIndex(int i, UINT nbits, UINT shift) { unsigned char val; val = (unsigned char) (i >> shift); switch (nbits) { case 1: val &= 0x1; return oneto8[val]; case 2: val &= 0x3; return twoto8[val]; case 3: val &= 0x7; return threeto8[val]; default: return 0; } } static Colormap Win32CreateRgbColormap(PIXELFORMATDESCRIPTOR pfd) { TkWinColormap *cmap = (TkWinColormap *) ckalloc(sizeof (TkWinColormap)); LOGPALETTE *pPal; int n, i; n = 1 << pfd.cColorBits; pPal = (PLOGPALETTE) LocalAlloc(LMEM_FIXED, sizeof (LOGPALETTE) + n * sizeof (PALETTEENTRY)); pPal->palVersion = 0x300; pPal->palNumEntries = n; for (i = 0; i < n; i++) { pPal->palPalEntry[i].peRed = ComponentFromIndex(i, pfd.cRedBits, pfd.cRedShift); pPal->palPalEntry[i].peGreen = ComponentFromIndex(i, pfd.cGreenBits, pfd.cGreenShift); pPal->palPalEntry[i].peBlue = ComponentFromIndex(i, pfd.cBlueBits, pfd.cBlueShift); pPal->palPalEntry[i].peFlags = 0; } /* fix up the palette to include the default GDI palette */ if ((pfd.cColorBits == 8) && (pfd.cRedBits == 3) && (pfd.cRedShift == 0) && (pfd.cGreenBits == 3) && (pfd.cGreenShift == 3) && (pfd.cBlueBits == 2) && (pfd.cBlueShift == 6)) { for (i = 1; i <= 12; i++) pPal->palPalEntry[defaultOverride[i]] = defaultPalEntry[i]; } cmap->palette = CreatePalette(pPal); LocalFree(pPal); cmap->size = n; cmap->stale = 0; /* Since this is a private colormap of a fix size, we do not need a valid * hash table, but a dummy one */ Tcl_InitHashTable(&cmap->refCounts, TCL_ONE_WORD_KEYS); return (Colormap) cmap; } static Colormap Win32CreateCiColormap(Togl *togl) { /* Create a colormap with size of togl->CiColormapSize and set all entries * to black */ LOGPALETTE logPalette; TkWinColormap *cmap = (TkWinColormap *) ckalloc(sizeof (TkWinColormap)); logPalette.palVersion = 0x300; logPalette.palNumEntries = 1; logPalette.palPalEntry[0].peRed = 0; logPalette.palPalEntry[0].peGreen = 0; logPalette.palPalEntry[0].peBlue = 0; logPalette.palPalEntry[0].peFlags = 0; cmap->palette = CreatePalette(&logPalette); cmap->size = togl->CiColormapSize; ResizePalette(cmap->palette, cmap->size); /* sets new entries to black */ cmap->stale = 0; /* Since this is a private colormap of a fix size, we do not need a valid * hash table, but a dummy one */ Tcl_InitHashTable(&cmap->refCounts, TCL_ONE_WORD_KEYS); return (Colormap) cmap; } /* ErrorExit is from */ static void ErrorExit(LPTSTR lpszFunction) { /* Retrieve the system error message for the last-error code */ LPTSTR lpMsgBuf; LPTSTR lpDisplayBuf; DWORD err = GetLastError(); if (err == 0) { /* The function said it failed, but GetLastError says it didn't, so * pretend it didn't. */ return; } FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL); /* Display the error message and exit the process */ lpDisplayBuf = (LPTSTR) LocalAlloc(LMEM_ZEROINIT, (lstrlen(lpMsgBuf) + lstrlen(lpszFunction) + 40) * sizeof (TCHAR)); StringCchPrintf(lpDisplayBuf, LocalSize(lpDisplayBuf), TEXT("%s failed with error %ld: %s"), lpszFunction, err, lpMsgBuf); MessageBox(NULL, lpDisplayBuf, TEXT("Error"), MB_OK); LocalFree(lpMsgBuf); LocalFree(lpDisplayBuf); ExitProcess(err); } #endif /* * Togl_Init * * Called upon system startup to create togl command. */ int Togl_Init(Tcl_Interp *interp) { int major, minor, patchLevel, releaseType; #ifdef USE_TCL_STUBS if (Tcl_InitStubs(interp, "8.1", 0) == NULL) { return TCL_ERROR; } #endif #ifdef USE_TK_STUBS if (Tk_InitStubs(interp, TCL_STUPID "8.1", 0) == NULL) { return TCL_ERROR; } #endif Tcl_GetVersion(&major, &minor, &patchLevel, &releaseType); #ifdef HAVE_TK_SETCLASSPROCS if (major > 8 || (major == 8 && (minor > 4 || (minor == 4 && (releaseType > 0 || patchLevel >= 2))))) { # ifdef USE_TK_STUBS SetClassProcsPtr = tkStubsPtr->tk_SetClassProcs; # else SetClassProcsPtr = Tk_SetClassProcs; # endif } else { SetClassProcsPtr = NULL; } #else if (major > 8 || (major == 8 && (minor > 4 || (minor == 4 && (releaseType > 0 || patchLevel >= 2))))) { TCL_ERR(interp, "Sorry, this instance of Togl was not compiled to work with Tcl/Tk 8.4a2 or higher."); } #endif if (Tcl_CreateObjCommand(interp, "togl", Togl_ObjCmd, NULL, Togl_ObjCmdDelete) == NULL) { return TCL_ERROR; } if (Tcl_PkgProvideEx(interp, "Togl", TOGL_VERSION, &toglStubs) != TCL_OK) { return TCL_ERROR; } return TCL_OK; } /* * Togl_CallCallback * * Call command with togl widget as only argument */ int Togl_CallCallback(Togl *togl, Tcl_Obj *cmd) { int result; Tcl_Obj *objv[3]; if (cmd == NULL || togl->widgetCmd == NULL) return TCL_OK; objv[0] = cmd; Tcl_IncrRefCount(objv[0]); objv[1] = Tcl_NewStringObj(Tcl_GetCommandName(togl->Interp, togl->widgetCmd), -1); Tcl_IncrRefCount(objv[1]); objv[2] = NULL; result = Tcl_EvalObjv(togl->Interp, 2, objv, TCL_EVAL_GLOBAL); Tcl_DecrRefCount(objv[1]); Tcl_DecrRefCount(objv[0]); if (result != TCL_OK) Tcl_BackgroundError(togl->Interp); return result; } static int Togl_CallCallback_P(Togl *togl, Tcl_Obj *cmd, double *params, int nparams) { int result, i; Tcl_Obj **objv = (Tcl_Obj **)malloc((3+nparams)*sizeof(Tcl_Obj *)); if (cmd == NULL || togl->widgetCmd == NULL) return TCL_OK; objv[0] = cmd; Tcl_IncrRefCount(objv[0]); objv[1] = Tcl_NewStringObj(Tcl_GetCommandName(togl->Interp, togl->widgetCmd), -1); Tcl_IncrRefCount(objv[1]); for (i = 0 ; i < nparams ; ++i) { objv[2+i] = Tcl_NewDoubleObj(params[i]); Tcl_IncrRefCount(objv[2+i]); } objv[2+nparams] = NULL; result = Tcl_EvalObjv(togl->Interp, 2+nparams, objv, TCL_EVAL_GLOBAL); for (i = 1+nparams ; i >= 0 ; --i) Tcl_DecrRefCount(objv[i]); free(objv); if (result != TCL_OK) Tcl_BackgroundError(togl->Interp); return result; } /* * Togl_Timer * * Gets called from Tk_CreateTimerHandler. */ static void Togl_Timer(ClientData clientData) { Togl *togl = (Togl *) clientData; if (togl->TimerProc) { if (Togl_CallCallback(togl, togl->TimerProc) != TCL_OK) { togl->timerHandler = NULL; return; } /* * Re-register this callback since Tcl/Tk timers are "one-shot". * That is, after the timer callback is called it not normally * called again. That's not the behavior we want for Togl. */ togl->timerHandler = Tcl_CreateTimerHandler(togl->TimerInterval, Togl_Timer, (ClientData) togl); } } /* * Togl_MakeCurrent * * Bind the OpenGL rendering context to the specified * Togl widget. If given a NULL argument, then the * OpenGL context is released without assigning a new one. */ void Togl_MakeCurrent(const Togl *togl) { #if defined(TOGL_WGL) int res = TRUE; if (togl == NULL) { HDC hdc = wglGetCurrentDC(); if (hdc != NULL) res = wglMakeCurrent(hdc, NULL); } else { if (togl->pbufferLost) { Bool keepContext = FindToglWithSameContext(togl) != NULL; Togl *t = (Togl *) togl; /* conceptually const */ if (!keepContext) { wglDeleteContext(t->Ctx); } togl_destroyPbuffer(t); t->pbuf = togl_createPbuffer(t); if (!keepContext) { t->Ctx = wglCreateContext(t->tglGLHdc); } } res = wglMakeCurrent(togl->tglGLHdc, togl->Ctx); } if (!res) { ErrorExit(TEXT("wglMakeCurrent")); } #elif defined(TOGL_X11) Display *display = togl ? togl->display : glXGetCurrentDisplay(); if (display) { GLXDrawable drawable; if (!togl) drawable = None; else if (togl->PbufferFlag) drawable = togl->pbuf; else if (togl->TkWin) drawable = Tk_WindowId(togl->TkWin); else drawable = None; (void) glXMakeCurrent(display, drawable, drawable ? togl->Ctx : NULL); } #elif defined(TOGL_AGL) if (togl == NULL || togl->Ctx == NULL) { (void) aglSetCurrentContext(NULL); } else { (void) aglSetCurrentContext(togl->Ctx); if (FindToglWithSameContext(togl) != NULL) { if (!togl->PbufferFlag) { AGLDrawable d = Togl_MacOSXGetDrawablePort(togl); aglSetDrawable(togl->Ctx, d); } else { GLint virtualScreen = aglGetVirtualScreen(togl->Ctx); aglSetPBuffer(togl->Ctx, togl->pbuf, 0, 0, virtualScreen); } } } #elif defined(TOGL_NSOPENGL) if (togl != NULL && togl->Ctx != NULL) { [togl->Ctx makeCurrentContext]; if (FindToglWithSameContext(togl) != NULL) { if (!togl->PbufferFlag) { [togl->Ctx setView:togl->nsview]; } else { GLint virtualScreen = [togl->Ctx currentVirtualScreen]; [togl->Ctx setPixelBuffer:togl->pbuf cubeMapFace:0 mipMapLevel:0 currentVirtualScreen:virtualScreen]; } } } #endif } /* * Togl_TakePhoto * * Take a photo image of the current OpenGL window. May have problems * if window is partially obscured, either by other windows or by the * edges of the display. */ int Togl_TakePhoto(Togl *togl, Tk_PhotoHandle photo) { GLubyte *buffer; Tk_PhotoImageBlock photoBlock; int y, midy; unsigned char *cp; int width = togl->Width, height = togl->Height; /* * TIP #116 altered Tk_PhotoPutBlock API to add interp arg that 8.4 * doesn't have. * We need to remove that for compiling with 8.4. */ #if (TK_MAJOR_VERSION == 8) && (TK_MINOR_VERSION < 5) # define TK_PHOTOPUTBLOCK(interp, hdl, blk, x, y, w, h, cr) \ Tk_PhotoPutBlock(hdl, blk, x, y, w, h, cr) #else # define TK_PHOTOPUTBLOCK Tk_PhotoPutBlock #endif buffer = (GLubyte *) ckalloc(width * height * 4); photoBlock.pixelPtr = buffer; photoBlock.width = width; photoBlock.height = height; photoBlock.pitch = width * 4; photoBlock.pixelSize = 4; photoBlock.offset[0] = 0; photoBlock.offset[1] = 1; photoBlock.offset[2] = 2; photoBlock.offset[3] = 3; if (!togl->RgbaFlag) { #if defined(TOGL_WGL) /* Due to the lack of a unique inverse mapping from the frame buffer to * the logical palette we need a translation map from the complete * logical palette. */ int n, i; TkWinColormap *cmap = (TkWinColormap *) Tk_Colormap(togl->TkWin); LPPALETTEENTRY entry = (LPPALETTEENTRY) malloc(togl->MapSize * sizeof (PALETTEENTRY)); n = GetPaletteEntries(cmap->palette, 0, togl->MapSize, entry); for (i = 0; i < n; i++) { togl->RedMap[i] = (GLfloat) (entry[i].peRed / 255.0); togl->GreenMap[i] = (GLfloat) (entry[i].peGreen / 255.0); togl->BlueMap[i] = (GLfloat) (entry[i].peBlue / 255.0); } free(entry); #endif /* TOGL_WGL */ glPixelMapfv(GL_PIXEL_MAP_I_TO_R, togl->MapSize, togl->RedMap); glPixelMapfv(GL_PIXEL_MAP_I_TO_G, togl->MapSize, togl->GreenMap); glPixelMapfv(GL_PIXEL_MAP_I_TO_B, togl->MapSize, togl->BlueMap); } glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT); glPixelStorei(GL_PACK_ALIGNMENT, 4); /* guarantee performance */ glPixelStorei(GL_PACK_SWAP_BYTES, GL_FALSE); glPixelStorei(GL_PACK_SKIP_PIXELS, 0); #if 1 glPixelStorei(GL_PACK_ROW_LENGTH, 0); glPixelStorei(GL_PACK_SKIP_ROWS, 0); glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer); /* Some OpenGL drivers are buggy and return zero for Alpha instead of one * for RGB pixel formats. If that is happening to you, upgrade your * graphics driver. */ /* OpenGL's origin is bottom-left, Tk Photo image's is top-left, so mirror * the rows around the middle row. */ midy = height / 2; cp = buffer; for (y = 0; y < midy; ++y) { int m_y = height - 1 - y; /* mirror y */ unsigned char *m_cp = buffer + m_y * photoBlock.pitch; int x; for (x = 0; x < photoBlock.pitch; ++x) { unsigned char c = *cp; *cp++ = *m_cp; *m_cp++ = c; } } #else /* OpenGL's origin is bottom-left, Tk Photo image's is top-left, so save * rows in reverse order. */ glPixelStorei(GL_PACK_ROW_LENGTH, width); glPixelStorei(GL_PACK_SKIP_ROWS, -1); glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer + width * (height - 1) * 4); #endif TK_PHOTOPUTBLOCK(togl->Interp, photo, &photoBlock, 0, 0, width, height, TK_PHOTO_COMPOSITE_SET); glPopClientAttrib(); /* restore PACK_ALIGNMENT */ ckfree((char *) buffer); return TCL_OK; } Bool Togl_SwapInterval(const Togl *togl, int interval) { #ifdef TOGL_AGL GLint swapInterval = interval; return aglSetInteger(togl->Ctx, AGL_SWAP_INTERVAL, &swapInterval); #endif #ifdef TOGL_NSOPENGL GLint swapInterval = interval; [togl->Ctx setValues:&swapInterval forParameter:NSOpenGLCPSwapInterval]; return True; #endif #ifdef TOGL_WGL typedef BOOL (WINAPI *BOOLFuncInt) (int); typedef const char *(WINAPI *StrFuncHDC) (HDC); static BOOLFuncInt swapInterval = NULL; static BOOL initialized = False; if (!initialized) { const char *extensions; StrFuncHDC getExtensionsString; getExtensionsString = (StrFuncHDC) wglGetProcAddress("wglGetExtensionsStringARB"); if (getExtensionsString == NULL) getExtensionsString = (StrFuncHDC) wglGetProcAddress("wglGetExtensionsStringEXT"); if (getExtensionsString) { extensions = getExtensionsString(togl->tglGLHdc); if (strstr(extensions, "WGL_EXT_swap_control") != NULL) { swapInterval = (BOOLFuncInt) wglGetProcAddress("wglSwapIntervalEXT"); } } initialized = True; } if (swapInterval) return swapInterval(interval); return False; #endif #ifdef TOGL_X11 typedef int (*IntFuncInt) (int); static IntFuncInt swapInterval = NULL; static int initialized = False; if (!initialized) { const char *extensions = glXQueryExtensionsString(togl->display, Tk_ScreenNumber(togl->TkWin)); if (strstr(extensions, "GLX_SGI_swap_control") != NULL) { swapInterval = (IntFuncInt) Togl_GetProcAddr("glXSwapIntervalSGI"); } else if (strstr(extensions, "GLX_MESA_swap_control") != NULL) { swapInterval = (IntFuncInt) Togl_GetProcAddr("glXSwapIntervalMESA"); } initialized = True; } if (swapInterval) return swapInterval(interval) == 0; return False; #endif } #if defined(TOGL_AGL) /* tell OpenGL which part of the Mac window to render to */ static void SetMacBufRect(Togl *togl) { GLint wrect[4]; Rect r; MacDrawable *d = ((TkWindow *) togl->TkWin)->privatePtr; /* set wrect[0,1] to lower left corner of widget */ wrect[2] = Tk_Width(togl->TkWin); wrect[3] = Tk_Height(togl->TkWin); wrect[0] = d->xOff; GetPortBounds(Togl_MacOSXGetDrawablePort(togl), &r); wrect[1] = r.bottom - wrect[3] - d->yOff; if (togl->FullscreenFlag) { aglEnable(togl->Ctx, AGL_FS_CAPTURE_SINGLE); aglSetFullScreen(togl->Ctx, 0, 0, 0, 0); } else { aglUpdateContext(togl->Ctx); } aglSetInteger(togl->Ctx, AGL_BUFFER_RECT, wrect); aglEnable(togl->Ctx, AGL_BUFFER_RECT); } static void ReconfigureCB(CGDirectDisplayID display, CGDisplayChangeSummaryFlags flags, void *closure) { /* Display reconfiguration callback. Documented as needed by Apple QA1209. * Updated for 10.3 (and later) to use * CGDisplayRegisterReconfigurationCallback. */ Togl *togl = (Togl *) closure; if (0 != (flags & kCGDisplayBeginConfigurationFlag)) return; /* wait until display is reconfigured */ SetMacBufRect(togl); Togl_MakeCurrent(togl); if (togl->Ctx) { if (togl->ReshapeProc) { Togl_CallCallback(togl, togl->ReshapeProc); } else { Togl_SetViewPort(togl); } } } #endif #if defined(TOGL_NSOPENGL) /* TODO: It appears that Tk only makes an NSView for toplevel windows. Also it looks like NSOpenGL does not have the equivalent of AGL_BUFFER_RECT that allows opengl drawing to just part of an NSView. So we might need to create our own NSView for controlling the opengl bounds. Look at TkMacOSXMakeRealWindowExist() in tkMacOSXWm.c. */ /* tell OpenGL which part of the Mac window to render to */ static void SetMacBufRect(Togl *togl) { Rect r, rt; NSRect rect; TkWindow *w = (TkWindow *) togl->TkWin; TkWindow *t = w->privatePtr->toplevel->winPtr; TkMacOSXWinBounds(w, &r); TkMacOSXWinBounds(t, &rt); rect.origin.x = r.left - rt.left; rect.origin.y = rt.bottom - r.bottom; rect.size.width = r.right - r.left; rect.size.height = r.bottom - r.top; [togl->nsview setFrame:rect]; [togl->Ctx update]; /* TODO: Support full screen. */ } static void ReconfigureCB(CGDirectDisplayID display, CGDisplayChangeSummaryFlags flags, void *closure) { /* Display reconfiguration callback. Documented as needed by Apple QA1209. * Updated for 10.3 (and later) to use * CGDisplayRegisterReconfigurationCallback. */ Togl *togl = (Togl *) closure; if (0 != (flags & kCGDisplayBeginConfigurationFlag)) return; /* wait until display is reconfigured */ SetMacBufRect(togl); Togl_MakeCurrent(togl); if (togl->Ctx) { if (togl->ReshapeProc) { Togl_CallCallback(togl, togl->ReshapeProc); } else { Togl_SetViewPort(togl); } } } #endif /* * Called when the widget's contents must be redrawn. Basically, we * just call the user's render callback function. * * Note that the parameter type is ClientData so this function can be * passed to Tk_DoWhenIdle(). */ static void Togl_Render(ClientData clientData) { Togl *togl = (Togl *) clientData; if (togl->DisplayProc) { Togl_MakeCurrent(togl); Togl_CallCallback(togl, togl->DisplayProc); } togl->UpdatePending = False; } static void Togl_RenderOverlay(ClientData clientData) { Togl *togl = (Togl *) clientData; if (togl->OverlayFlag && togl->OverlayDisplayProc) { #if defined(TOGL_WGL) int res = wglMakeCurrent(togl->tglGLHdc, togl->tglGLOverlayHglrc); if (!res) { ErrorExit(TEXT("wglMakeCurrent overlay")); } #elif defined(TOGL_X11) (void) glXMakeCurrent(Tk_Display(togl->TkWin), togl->OverlayWindow, togl->OverlayCtx); #endif /* TOGL_WGL */ Togl_CallCallback(togl, togl->OverlayDisplayProc); } togl->OverlayUpdatePending = False; } static int Togl_EnterStereo(Togl *togl) { if (togl->Stereo == TOGL_STEREO_ROW_INTERLEAVED) { GLint stencil_bits; Tk_Window top; Togl_MakeCurrent(togl); glGetIntegerv(GL_STENCIL_BITS, &stencil_bits); if (stencil_bits == 0) { Tcl_SetResult(togl->Interp, TCL_STUPID "need stencil buffer for row interleaved stereo", TCL_STATIC); return False; } togl->riStencilBit = 1u << (stencil_bits - 1); glEnable(GL_STENCIL_TEST); /* Need to redraw window when moved between odd and even scanlines, so * bind to top level window so we're notified when that happens. */ top = togl->TkWin; while (!Tk_IsTopLevel(top)) { top = Tk_Parent(top); if (top == NULL) break; } if (top) { Tk_CreateEventHandler(top, StructureNotifyMask, Togl_RedisplayProc, (ClientData) togl); } } return True; } static void Togl_LeaveStereo(Togl *togl, int oldStereo) { switch (oldStereo) { default: break; #ifdef HAVE_AUTOSTEREO case TOGL_STEREO_NATIVE: if (togl->ash != -1) { ASClosedStereoWindow(togl->ash); togl->ash = -1; } break; #endif #ifdef __sgi case TOGL_STEREO_SGIOLDSTYLE: togl->currentStereoBuffer = STEREO_BUFFER_NONE; glXWaitGL(); /* sync with GL command stream before calling X */ XSGISetStereoBuffer(togl->display, Tk_WindowId(togl->TkWin), togl->currentStereoBuffer); glXWaitX(); /* sync with X command stream before calling GL */ break; #endif case TOGL_STEREO_ROW_INTERLEAVED: if (togl->riStencilBit) { Tk_Window top; glDisable(GL_STENCIL_TEST); /* need to remove previously added top level event handler */ top = togl->TkWin; while (!Tk_IsTopLevel(top)) { top = Tk_Parent(top); if (top == NULL) break; } if (top) { Tk_DeleteEventHandler(top, StructureNotifyMask, Togl_RedisplayProc, (ClientData) togl); } } break; } } /* * See domentation about what can't be changed */ static int Togl_ObjConfigure(Tcl_Interp *interp, Togl *togl, int objc, Tcl_Obj *const *objv) { Tk_SavedOptions savedOptions; int error, mask; int undoMask = 0; Tcl_Obj *errorResult = NULL; int oldStereo = togl->Stereo; int oldWidth = togl->Width; int oldHeight = togl->Height; for (error = 0; error <= 1; ++error, mask = undoMask) { if (error == 0) { /* * Tk_SetOptions parses the command arguments * and looks for defaults in the resource database. */ if (Tk_SetOptions(interp, WIDGREC togl, togl->tpg->optionTable, objc, objv, togl->TkWin, &savedOptions, &mask) != TCL_OK) { /* previous values are restored, so nothing to do */ return TCL_ERROR; } } else { /* * Restore options from saved values */ errorResult = Tcl_GetObjResult(interp); Tcl_IncrRefCount(errorResult); Tk_RestoreSavedOptions(&savedOptions); } if (togl->Ident && togl->Ident[0] == '.') { Tcl_AppendResult(interp, "Can not set ident to a window path name", NULL); continue; } if (togl->FullscreenFlag) { /* override width and height */ togl->Width = WidthOfScreen(Tk_Screen(togl->TkWin)); togl->Height = HeightOfScreen(Tk_Screen(togl->TkWin)); undoMask |= GEOMETRY_MASK; } if (mask & GEOMETRY_MASK) { if (!togl->PbufferFlag) { Togl_WorldChanged((ClientData) togl); /* Reset width and height so ConfigureNotify * event will call reshape callback */ togl->Width = oldWidth; togl->Height = oldHeight; undoMask |= GEOMETRY_MASK; } } if (mask & OVERLAY_MASK) { #if !TOGL_USE_OVERLAY if (togl->OverlayFlag) { Tcl_AppendResult(interp, "Sorry, overlay was disabled", NULL); continue; } #else # if defined(TOGL_X11) if (togl->OverlayCtx) # elif defined(TOGL_WGL) if (togl->tglGLOverlayHglrc) # endif { /* * Trying to change existing pixel format/graphics context */ Tcl_AppendResult(interp, "Unable to change overlay pixel format", NULL); continue; } #endif } if (mask & SWAP_MASK) { if (togl->Ctx) { /* * Change existing swap interval */ Togl_MakeCurrent(togl); /* TODO: needed? */ Togl_SwapInterval(togl, togl->SwapInterval); undoMask |= SWAP_MASK; } } if (error == 0 && (mask & STEREO_FORMAT_MASK) != 0) { if (oldStereo == TOGL_STEREO_NATIVE || togl->Stereo == TOGL_STEREO_NATIVE) { /* only native stereo affects the visual format */ mask |= FORMAT_MASK; } if (togl->Stereo == TOGL_STEREO_SGIOLDSTYLE) { #ifndef __sgi Tcl_AppendResult(interp, "sgioldstyle: only available on SGI computers", NULL); continue; #else int event, error; /* Make sure Display supports SGIStereo */ if (XSGIStereoQueryExtension(Tk_Display(togl->TkWin), &event, &error) == False) { Tcl_AppendResult(interp, "sgioldstyle: SGIStereo X extension is missing", NULL); continue; } /* Make sure Window (Screen) supports SGIStereo */ if (XSGIQueryStereoMode(Tk_Display(togl->TkWin), Tk_WindowId(Tk_Parent(togl->TkWin))) == X_STEREO_UNSUPPORTED) { Tcl_AppendResult(interp, "sgioldstyle: unsupported by screen", NULL); continue; } #endif } } if (mask & FORMAT_MASK) { if (togl->Ctx) { /* * Trying to change existing pixel format/graphics context * TODO: (re)create graphics context * * save old graphics context * try to create new one and share display lists * if failure, then restore old one */ Tcl_AppendResult(interp, "Unable to change pixel format", NULL); continue; } if (togl->ShareContext && togl->ShareList) { Tcl_AppendResult(interp, "only one of -sharelist and -sharecontext allowed", NULL); continue; } if (togl->PbufferFlag && togl->Stereo) { Tcl_AppendResult(interp, "pbuffer not supported with stereo", NULL); continue; } if (togl->PbufferFlag && togl->OverlayFlag) { Tcl_AppendResult(interp, "pbuffer not supported with overlay", NULL); continue; } if (togl->FullscreenFlag) { #if defined(TOGL_NSOPENGL) Tcl_AppendResult(interp, "Fullscreen not supported with Cocoa Tk", NULL); continue; #endif #ifndef TOGL_AGL # if TK_MAJOR_VERSION < 8 || (TK_MAJOR_VERSION == 8 && TK_MINOR_VERSION < 5) Tcl_AppendResult(interp, "Need Tk 8.5 or later for fullscreen support", NULL); continue; # endif #endif } /* Whether or not the format is okay is figured out when togl tries * to create the window. */ #ifdef MESA_COLOR_HACK free_default_color_cells(Tk_Display(togl->TkWin), Tk_Colormap(togl->TkWin)); #endif undoMask |= FORMAT_MASK; } if (togl->Ctx) { if (oldStereo != togl->Stereo) { /* leaving stereo */ Togl_LeaveStereo(togl, oldStereo); if (togl->Stereo && !Togl_EnterStereo(togl)) continue; } } if (mask & TIMER_MASK) { if (togl->timerHandler != NULL) { Tcl_DeleteTimerHandler(togl->timerHandler); } if (togl->TimerProc) { togl->timerHandler = Tcl_CreateTimerHandler(togl->TimerInterval, Togl_Timer, (ClientData) togl); } undoMask |= TIMER_MASK; } break; } if (error == 0) { Tk_FreeSavedOptions(&savedOptions); return TCL_OK; } else { Tcl_SetObjResult(interp, errorResult); Tcl_DecrRefCount(errorResult); return TCL_ERROR; } } static int Togl_ObjWidget(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { Togl *togl = (Togl *) clientData; const char *commands[] = { "cget", "configure", "extensions", "postredisplay", "render", "swapbuffers", "makecurrent", "takephoto", "loadbitmapfont", "unloadbitmapfont", "write", "uselayer", "showoverlay", "hideoverlay", "postredisplayoverlay", "renderoverlay", "existsoverlay", "ismappedoverlay", "getoverlaytransparentvalue", "drawbuffer", "clear", "frustum", "ortho", "numeyes", "contexttag", "copycontextto", "maketopfortrackpadevents", NULL }; enum command { TOGL_CGET, TOGL_CONFIGURE, TOGL_EXTENSIONS, TOGL_POSTREDISPLAY, TOGL_RENDER, TOGL_SWAPBUFFERS, TOGL_MAKECURRENT, TOGL_TAKEPHOTO, TOGL_LOADBITMAPFONT, TOGL_UNLOADBITMAPFONT, TOGL_WRITE, TOGL_USELAYER, TOGL_SHOWOVERLAY, TOGL_HIDEOVERLAY, TOGL_POSTREDISPLAYOVERLAY, TOGL_RENDEROVERLAY, TOGL_EXISTSOVERLAY, TOGL_ISMAPPEDOVERLAY, TOGL_GETOVERLAYTRANSPARENTVALUE, TOGL_DRAWBUFFER, TOGL_CLEAR, TOGL_FRUSTUM, TOGL_ORTHO, TOGL_NUMEYES, TOGL_CONTEXTTAG, TOGL_COPYCONTEXTTO, TOGL_MAKETOPFORTRACKPADEVENTS }; int result = TCL_OK; Tcl_Obj *objPtr; int index; if (objc < 2) { Tcl_WrongNumArgs(interp, 1, objv, "command ?arg arg ...?"); return TCL_ERROR; } Tk_Preserve((ClientData) togl); result = Tcl_GetIndexFromObj(interp, objv[1], commands, "option", 0, &index); switch (index) { case TOGL_CGET: if (objc != 3) { Tcl_WrongNumArgs(interp, 2, objv, "option"); result = TCL_ERROR; break; } objPtr = Tk_GetOptionValue(interp, WIDGREC togl, togl->tpg->optionTable, (objc == 3) ? objv[2] : NULL, togl->TkWin); if (objPtr == NULL) { result = TCL_ERROR; break; } Tcl_SetObjResult(interp, objPtr); break; case TOGL_CONFIGURE: if (objc <= 3) { /* * Return one item if the option is given, * or return all configuration information */ objPtr = Tk_GetOptionInfo(interp, WIDGREC togl, togl->tpg->optionTable, (objc == 3) ? objv[2] : NULL, togl->TkWin); if (objPtr == NULL) { result = TCL_ERROR; } else { Tcl_SetObjResult(interp, objPtr); } } else { /* Execute a configuration change */ result = Togl_ObjConfigure(interp, togl, objc - 2, objv + 2); } break; case TOGL_EXTENSIONS: /* Return a list of OpenGL extensions available */ /* TODO: -glu for glu extensions, -platform for glx/wgl extensions */ if (objc == 2) { const char *extensions; Tcl_Obj *objPtr; int length = -1; extensions = (const char *) glGetString(GL_EXTENSIONS); objPtr = Tcl_NewStringObj(extensions, -1); /* convert to list by asking for its length */ (void) Tcl_ListObjLength(interp, objPtr, &length); Tcl_SetObjResult(interp, objPtr); } else { Tcl_WrongNumArgs(interp, 2, objv, NULL); result = TCL_ERROR; } break; case TOGL_POSTREDISPLAY: /* schedule the widget to be redrawn */ if (objc == 2) { Togl_PostRedisplay(togl); } else { Tcl_WrongNumArgs(interp, 2, objv, NULL); result = TCL_ERROR; } break; case TOGL_RENDER: /* force the widget to be redrawn */ if (objc == 2) { Togl_Render((ClientData) togl); } else { Tcl_WrongNumArgs(interp, 2, objv, NULL); result = TCL_ERROR; } break; case TOGL_SWAPBUFFERS: /* force the widget to be redrawn */ if (objc == 2) { Togl_SwapBuffers(togl); } else { Tcl_WrongNumArgs(interp, 2, objv, NULL); result = TCL_ERROR; } break; case TOGL_MAKECURRENT: /* force the widget to be redrawn */ if (objc == 2) { Togl_MakeCurrent(togl); } else { Tcl_WrongNumArgs(interp, 2, objv, NULL); result = TCL_ERROR; } break; case TOGL_TAKEPHOTO: { /* force the widget to be redrawn */ if (objc != 3) { Tcl_WrongNumArgs(interp, 2, objv, "name"); result = TCL_ERROR; } else { const char *name; Tk_PhotoHandle photo; name = Tcl_GetStringFromObj(objv[2], NULL); photo = Tk_FindPhoto(interp, name); if (photo == NULL) { Tcl_AppendResult(interp, "image \"", name, "\" doesn't exist or is not a photo image", NULL); result = TCL_ERROR; break; } glPushAttrib(GL_PIXEL_MODE_BIT); if (togl->DoubleFlag) { glReadBuffer(GL_FRONT); } Togl_TakePhoto(togl, photo); glPopAttrib(); /* restore glReadBuffer */ } break; } case TOGL_LOADBITMAPFONT: #if TOGL_USE_FONTS != 1 Tcl_AppendResult(interp, "unsupported", NULL); result = TCL_ERROR; #else if (objc >= 3) { Tcl_Obj *font, *list; list = Tcl_NewListObj(objc - 2, objv + 2); Tcl_IncrRefCount(list); font = Togl_LoadBitmapFont(togl, Tcl_GetString(list)); Tcl_DecrRefCount(list); if (font) { Tcl_SetObjResult(interp, font); result = TCL_OK; } else { Tcl_AppendResult(interp, "Could not allocate font", NULL); result = TCL_ERROR; } } else { Tcl_WrongNumArgs(interp, 2, objv, "fontname"); result = TCL_ERROR; } #endif break; case TOGL_UNLOADBITMAPFONT: #if TOGL_USE_FONTS != 1 Tcl_AppendResult(interp, "unsupported", NULL); result = TCL_ERROR; #else if (objc == 3) { result = Togl_UnloadBitmapFont(togl, objv[2]); } else { Tcl_WrongNumArgs(interp, 2, objv, "toglfont"); result = TCL_ERROR; } #endif break; case TOGL_WRITE:{ #if TOGL_USE_FONTS != 1 Tcl_AppendResult(interp, "unsupported", NULL); result = TCL_ERROR; #else /* Tcl_Obj *toglfont = objv[2]; */ int wobjc = objc - 3; Tcl_Obj *const *wobjv = objv + 3; while (wobjc > 1) { const char *name = Tcl_GetStringFromObj(wobjv[0], NULL); int oc, i; Tcl_Obj **ov; double args[4]; if (Tcl_ListObjGetElements(NULL, wobjv[1], &oc, &ov) != TCL_OK) { oc = 0; } else if (oc <= 4) { for (i = 0; i < oc; ++i) { if (Tcl_GetDoubleFromObj(NULL, ov[i], &args[i]) != TCL_OK) { } } } if (strcmp(name, "-color") == 0) { if (oc == 4) glColor4d(args[0], args[1], args[2], args[3]); else if (oc == 3) glColor3d(args[0], args[1], args[2]); else goto write_usage; } else if (strcmp(name, "-pos") == 0) { if (oc == 4) glRasterPos4d(args[0], args[1], args[2], args[3]); else if (oc == 3) glRasterPos3d(args[0], args[1], args[2]); else if (oc == 2) glRasterPos2d(args[0], args[1]); else goto write_usage; } else goto write_usage; wobjc -= 2; wobjv += 2; } if (wobjc != 1) goto write_usage; result = Togl_WriteObj(togl, objv[2], wobjv[0]); if (result != -1) result = TCL_OK; else { Tcl_AppendResult(interp, "togl write failed", NULL); result = TCL_ERROR; } break; write_usage: Tcl_WrongNumArgs(interp, 2, objv, "[-pos {x y [z [w]]}]" " [-color {r g b [a]}" " string"); result = TCL_ERROR; #endif break; } case TOGL_USELAYER: if (objc == 3) { int layer; result = Tcl_GetIntFromObj(interp, objv[2], &layer); if (result == TCL_OK) { Togl_UseLayer(togl, layer); } } else { Tcl_WrongNumArgs(interp, 2, objv, "layer"); result = TCL_ERROR; } break; case TOGL_SHOWOVERLAY: if (objc == 2) { Togl_ShowOverlay(togl); } else { Tcl_WrongNumArgs(interp, 2, objv, NULL); result = TCL_ERROR; } break; case TOGL_HIDEOVERLAY: if (objc == 2) { Togl_HideOverlay(togl); } else { Tcl_WrongNumArgs(interp, 2, objv, NULL); result = TCL_ERROR; } break; case TOGL_POSTREDISPLAYOVERLAY: if (objc == 2) { Togl_PostOverlayRedisplay(togl); } else { Tcl_WrongNumArgs(interp, 2, objv, NULL); result = TCL_ERROR; } break; case TOGL_RENDEROVERLAY: /* force the overlay to be redrawn */ if (objc == 2) { Togl_RenderOverlay((ClientData) togl); } else { Tcl_WrongNumArgs(interp, 2, objv, NULL); result = TCL_ERROR; } break; case TOGL_EXISTSOVERLAY: if (objc == 2) { Tcl_SetObjResult(interp, Tcl_NewIntObj(Togl_ExistsOverlay(togl))); } else { Tcl_WrongNumArgs(interp, 2, objv, NULL); result = TCL_ERROR; } break; case TOGL_ISMAPPEDOVERLAY: if (objc == 2) { Tcl_SetObjResult(interp, Tcl_NewIntObj(Togl_IsMappedOverlay(togl))); } else { Tcl_WrongNumArgs(interp, 2, objv, NULL); result = TCL_ERROR; } break; case TOGL_GETOVERLAYTRANSPARENTVALUE: if (objc == 2) { Tcl_SetObjResult(interp, Tcl_NewIntObj(Togl_GetOverlayTransparentValue(togl))); } else { Tcl_WrongNumArgs(interp, 2, objv, NULL); result = TCL_ERROR; } break; case TOGL_DRAWBUFFER: if (objc != 3) { Tcl_WrongNumArgs(interp, 2, objv, "mode"); result = TCL_ERROR; } else { int mask; result = Tcl_GetIntFromObj(interp, objv[2], &mask); if (result == TCL_ERROR) break; Togl_DrawBuffer(togl, (GLenum) mask); } break; case TOGL_CLEAR: if (objc != 3) { Tcl_WrongNumArgs(interp, 2, objv, "mask"); result = TCL_ERROR; } else { int mask; result = Tcl_GetIntFromObj(interp, objv[2], &mask); if (result == TCL_ERROR) break; Togl_Clear(togl, (GLbitfield) mask); } break; case TOGL_FRUSTUM: if (objc != 8) { Tcl_WrongNumArgs(interp, 2, objv, "left right bottom top near far"); result = TCL_ERROR; } else { double left, right, bottom, top, zNear, zFar; if (Tcl_GetDoubleFromObj(interp, objv[2], &left) == TCL_ERROR || Tcl_GetDoubleFromObj(interp, objv[3], &right) == TCL_ERROR || Tcl_GetDoubleFromObj(interp, objv[4], &bottom) == TCL_ERROR || Tcl_GetDoubleFromObj(interp, objv[5], &top) == TCL_ERROR || Tcl_GetDoubleFromObj(interp, objv[6], &zNear) == TCL_ERROR || Tcl_GetDoubleFromObj(interp, objv[7], &zFar) == TCL_ERROR) { result = TCL_ERROR; break; } Togl_Frustum(togl, left, right, bottom, top, zNear, zFar); } break; case TOGL_ORTHO: if (objc != 8) { Tcl_WrongNumArgs(interp, 2, objv, "left right bottom top near far"); result = TCL_ERROR; } else { double left, right, bottom, top, zNear, zFar; if (Tcl_GetDoubleFromObj(interp, objv[2], &left) == TCL_ERROR || Tcl_GetDoubleFromObj(interp, objv[3], &right) == TCL_ERROR || Tcl_GetDoubleFromObj(interp, objv[4], &bottom) == TCL_ERROR || Tcl_GetDoubleFromObj(interp, objv[5], &top) == TCL_ERROR || Tcl_GetDoubleFromObj(interp, objv[6], &zNear) == TCL_ERROR || Tcl_GetDoubleFromObj(interp, objv[7], &zFar) == TCL_ERROR) { result = TCL_ERROR; break; } Togl_Ortho(togl, left, right, bottom, top, zNear, zFar); } break; case TOGL_NUMEYES: if (objc == 2) { Tcl_SetObjResult(interp, Tcl_NewIntObj(Togl_NumEyes(togl))); } else { Tcl_WrongNumArgs(interp, 2, objv, NULL); result = TCL_ERROR; } break; case TOGL_CONTEXTTAG: if (objc == 2) { Tcl_SetObjResult(interp, Tcl_NewIntObj(Togl_ContextTag(togl))); } else { Tcl_WrongNumArgs(interp, 2, objv, NULL); result = TCL_ERROR; } break; case TOGL_COPYCONTEXTTO: if (objc != 4) { Tcl_WrongNumArgs(interp, 2, objv, NULL); result = TCL_ERROR; } else { Togl *to; unsigned int mask; if (Togl_GetToglFromObj(togl->Interp, objv[2], &to) == TCL_ERROR || Tcl_GetIntFromObj(togl->Interp, objv[3], (int *) &mask) == TCL_ERROR) { result = TCL_ERROR; break; } result = Togl_CopyContext(togl, to, mask); } #ifdef TOGL_NSOPENGL case TOGL_MAKETOPFORTRACKPADEVENTS: if (objc == 2) { // This hack places the Togl NSView at the top of sibling views so that it receives // trackpad events. The hierarchy is not used for drawing, nor for mouse event dispatching. [togl->nsview retain]; [togl->nsview removeFromSuperview]; MacDrawable *d = ((TkWindow *) togl->TkWin)->privatePtr; NSView *topview = d->toplevel->view; [topview addSubview:togl->nsview]; [togl->nsview release]; } else { Tcl_WrongNumArgs(interp, 2, objv, NULL); result = TCL_ERROR; } break; #endif } Tk_Release((ClientData) togl); return result; } /* * Togl_ObjCmdDelete * * Called when togl command is removed from interpreter. */ static void Togl_ObjCmdDelete(ClientData clientData) { if (clientData != NULL) { Togl_PackageGlobals *tpg = (Togl_PackageGlobals *) clientData; Tk_DeleteOptionTable(tpg->optionTable); ckfree((char *) clientData); } } /* * Togl_ObjCmd * * Called when Togl is executed - creation of a Togl widget. * * Creates a new window * * Creates an 'Togl' data structure * * Creates an event handler for this window * * Creates a command that handles this object * * Configures this Togl for the given arguments */ int Togl_ObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { Togl_PackageGlobals *tpg; Togl *togl; Tk_Window tkwin; Tcl_SavedResult saveError; if (objc <= 1) { Tcl_WrongNumArgs(interp, 1, objv, "pathName ?options?"); return TCL_ERROR; } tpg = (Togl_PackageGlobals *) clientData; if (tpg == NULL) { Tcl_CmdInfo info; const char *name; /* * Initialize the Togl_PackageGlobals for this widget the * first time a Togl widget is created. The globals are * saved as our client data. */ tpg = (Togl_PackageGlobals *) ckalloc(sizeof (Togl_PackageGlobals)); if (tpg == NULL) { return TCL_ERROR; } tpg->nextContextTag = 0; tpg->optionTable = Tk_CreateOptionTable(interp, optionSpecs); tpg->toglHead = NULL; name = Tcl_GetString(objv[0]); Tcl_GetCommandInfo(interp, name, &info); info.objClientData = (ClientData) tpg; Tcl_SetCommandInfo(interp, name, &info); } /* Create the window. */ tkwin = Tk_CreateWindowFromPath(interp, Tk_MainWindow(interp), Tcl_GetString(objv[1]), NULL); if (tkwin == NULL) { return TCL_ERROR; } Tk_SetClass(tkwin, "Togl"); /* Create Togl data structure */ togl = (Togl *) ckalloc(sizeof (Togl)); if (togl == NULL) { return TCL_ERROR; } /* initialize Togl data structures values */ togl->Next = NULL; togl->Ctx = NULL; #if defined(TOGL_WGL) togl->tglGLHdc = NULL; togl->tglGLOverlayHglrc = NULL; #elif defined(TOGL_X11) togl->OverlayCtx = NULL; #endif togl->contextTag = 0; togl->display = Tk_Display(tkwin); togl->TkWin = tkwin; togl->Interp = interp; togl->VisInfo = NULL; togl->OverlayWindow = None; togl->OverlayCmap = None; togl->OverlayTransparentPixel = 0; togl->OverlayIsMapped = False; togl->UpdatePending = False; togl->OverlayUpdatePending = False; togl->tpg = tpg; togl->Client_Data = NULL; /* for color index mode photos */ togl->RedMap = togl->GreenMap = togl->BlueMap = NULL; togl->MapSize = 0; #ifndef NO_TK_CURSOR togl->Cursor = None; #endif togl->Width = 0; togl->Height = 0; togl->PixelScale = 1; togl->SetGrid = 0; togl->TimerInterval = 0; togl->RgbaFlag = True; togl->RgbaRed = 1; togl->RgbaGreen = 1; togl->RgbaBlue = 1; togl->DoubleFlag = False; togl->DepthFlag = False; togl->DepthSize = 1; togl->AccumFlag = False; togl->AccumRed = 1; togl->AccumGreen = 1; togl->AccumBlue = 1; togl->AccumAlpha = 1; togl->AlphaFlag = False; togl->AlphaSize = 1; togl->StencilFlag = False; togl->StencilSize = 1; togl->OverlayFlag = False; togl->Stereo = TOGL_STEREO_NONE; togl->EyeSeparation = 0; togl->Convergence = 0; togl->riStencilBit = 0; togl->AuxNumber = 0; togl->Indirect = False; togl->PixelFormat = 0; togl->SwapInterval = 1; togl->MultisampleFlag = False; togl->FullscreenFlag = False; togl->PbufferFlag = False; togl->LargestPbufferFlag = False; #if defined(TOGL_X11) togl->fbcfg = None; togl->pbuf = None; #elif defined(TOGL_WGL) togl->pbuf = None; togl->pbufferLost = 0; #elif defined(TOGL_AGL) togl->pbuf = NULL; #elif defined(TOGL_NSOPENGL) togl->pbuf = NULL; #endif togl->CreateProc = NULL; togl->DisplayProc = NULL; togl->ReshapeProc = NULL; togl->DestroyProc = NULL; togl->TimerProc = NULL; togl->timerHandler = NULL; togl->OverlayDisplayProc = NULL; togl->MagnifyProc = NULL; togl->RotateProc = NULL; togl->ScrollProc = NULL; togl->ScrollWheelProc = NULL; togl->TouchesProc = NULL; togl->ShareList = NULL; togl->ShareContext = NULL; togl->Ident = NULL; togl->PrivateCmapFlag = False; togl->currentStereoBuffer = STEREO_BUFFER_NONE; #ifdef HAVE_AUTOSTEREO togl->as_initialized = False; togl->ash = -1; #endif togl->badWindow = False; /* Create command event handler */ togl->widgetCmd = Tcl_CreateObjCommand(interp, Tk_PathName(tkwin), Togl_ObjWidget, (ClientData) togl, ToglCmdDeletedProc); /* * Setup the Tk_ClassProcs callbacks to point at our own window creation * function * * We need to check at runtime if we should use the new Tk_SetClassProcs() * API or if we need to modify the window structure directly */ #ifdef HAVE_TK_SETCLASSPROCS if (SetClassProcsPtr != NULL) { /* use public API (Tk 8.4+) */ Tk_ClassProcs *procsPtr; procsPtr = (Tk_ClassProcs *) ckalloc(sizeof (Tk_ClassProcs)); procsPtr->size = sizeof (Tk_ClassProcs); procsPtr->createProc = Togl_MakeWindow; procsPtr->worldChangedProc = Togl_WorldChanged; procsPtr->modalProc = NULL; /* Tk_SetClassProcs(togl->TkWin, procsPtr, (ClientData) togl); */ (SetClassProcsPtr) (togl->TkWin, procsPtr, (ClientData) togl); } else #endif { /* use private API */ /* * We need to set these fields in the Tk_FakeWin structure: dummy17 = * classProcsPtr dummy18 = instanceData */ TkClassProcs *procsPtr; Tk_FakeWin *winPtr = (Tk_FakeWin *) (togl->TkWin); procsPtr = (TkClassProcs *) ckalloc(sizeof (TkClassProcs)); procsPtr->createProc = Togl_MakeWindow; procsPtr->geometryProc = Togl_WorldChanged; procsPtr->modalProc = NULL; winPtr->dummy17 = (char *) procsPtr; winPtr->dummy18 = (ClientData) togl; } Tk_CreateEventHandler(tkwin, ExposureMask | StructureNotifyMask, Togl_EventProc, (ClientData) togl); /* Configure Togl widget */ if (Tk_InitOptions(interp, WIDGREC togl, tpg->optionTable, tkwin) != TCL_OK || Togl_ObjConfigure(interp, togl, objc - 2, objv + 2) != TCL_OK) { goto error; } /* * If OpenGL window wasn't already created by Togl_ObjConfigure() we * create it now. We can tell by checking if the OpenGL context has * been initialized. */ if (!togl->Ctx) { Tk_MakeWindowExist(togl->TkWin); if (togl->badWindow) { goto error; } } Togl_MakeCurrent(togl); if (togl->contextTag == 0) togl->contextTag = ++tpg->nextContextTag; (void) Togl_SwapInterval(togl, togl->SwapInterval); /* If defined, call create callback */ if (togl->CreateProc) { if (Togl_CallCallback(togl, togl->CreateProc) != TCL_OK) { goto error; } } #if defined(TOGL_AGL) || defined(TOGL_NSOPENGL) if (!togl->PbufferFlag) SetMacBufRect(togl); #endif /* If defined, call reshape proc */ if (togl->ReshapeProc) { if (Togl_CallCallback(togl, togl->ReshapeProc) != TCL_OK) { goto error; } } else { Togl_SetViewPort(togl); #if defined(TOGL_X11) if (togl->OverlayFlag) { Togl_UseLayer(togl, TOGL_OVERLAY); Togl_SetViewPort(togl); Togl_UseLayer(togl, TOGL_NORMAL); } #endif } if (togl->Stereo && !Togl_EnterStereo(togl)) goto error; Tcl_AppendResult(interp, Tk_PathName(tkwin), NULL); /* Add to linked list */ AddToList(togl); return TCL_OK; error: Tcl_SaveResult(interp, &saveError); togl->badWindow = True; (void) Tcl_DeleteCommandFromToken(interp, togl->widgetCmd); Tcl_RestoreResult(interp, &saveError); Tcl_AppendResult(interp, "\nCouldn't configure togl widget", NULL); return TCL_ERROR; } #if TOGL_USE_OVERLAY /* * Do all the setup for overlay planes * Return: TCL_OK or TCL_ERROR */ static int SetupOverlay(Togl *togl) { # if defined(TOGL_X11) # ifdef GLX_TRANSPARENT_TYPE_EXT static int ovAttributeList[] = { GLX_BUFFER_SIZE, 2, GLX_LEVEL, 1, GLX_TRANSPARENT_TYPE_EXT, GLX_TRANSPARENT_INDEX_EXT, None }; # else static int ovAttributeList[] = { GLX_BUFFER_SIZE, 2, GLX_LEVEL, 1, None }; # endif XVisualInfo *visinfo; TkWindow *winPtr = (TkWindow *) togl->TkWin; XSetWindowAttributes swa; Tcl_HashEntry *hPtr; int new_flag; visinfo = glXChooseVisual(togl->display, Tk_ScreenNumber(winPtr), ovAttributeList); if (!visinfo) { Tcl_AppendResult(togl->Interp, Tk_PathName(winPtr), ": No suitable overlay index visual available", NULL); togl->OverlayCtx = NULL; togl->OverlayWindow = 0; togl->OverlayCmap = 0; return TCL_ERROR; } # ifdef GLX_TRANSPARENT_INDEX_EXT { int fail = glXGetConfig(togl->display, visinfo, GLX_TRANSPARENT_INDEX_VALUE_EXT, &togl->OverlayTransparentPixel); if (fail) togl->OverlayTransparentPixel = 0; /* maybe, maybe ... */ } # else togl->OverlayTransparentPixel = 0; /* maybe, maybe ... */ # endif /* share display lists with normal layer context */ togl->OverlayCtx = glXCreateContext(togl->display, visinfo, togl->Ctx, !togl->Indirect); swa.colormap = XCreateColormap(togl->display, XRootWindow(togl->display, visinfo->screen), visinfo->visual, AllocNone); togl->OverlayCmap = swa.colormap; swa.border_pixel = 0; swa.event_mask = ALL_EVENTS_MASK; togl->OverlayWindow = XCreateWindow(togl->display, Tk_WindowId(togl->TkWin), 0, 0, togl->Width, togl->Height, 0, visinfo->depth, InputOutput, visinfo->visual, CWBorderPixel | CWColormap | CWEventMask, &swa); hPtr = Tcl_CreateHashEntry(&winPtr->dispPtr->winTable, (const char *) togl->OverlayWindow, &new_flag); Tcl_SetHashValue(hPtr, winPtr); /* XMapWindow(togl->display, togl->OverlayWindow); */ togl->OverlayIsMapped = False; /* Make sure window manager installs our colormap */ XSetWMColormapWindows(togl->display, togl->OverlayWindow, &togl->OverlayWindow, 1); return TCL_OK; # elif defined(TOGL_WGL) || defined(TOGL_AGL) || defined(TOGL_NSOPENGL) /* not yet implemented on these */ return TCL_ERROR; # endif } #endif /* TOGL_USE_OVERLAY */ #ifdef TOGL_WGL # define TOGL_CLASS_NAME "Togl Class" static Bool ToglClassInitialized = False; static LRESULT CALLBACK Win32WinProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { LONG result; Togl *togl = (Togl *) GetWindowLongPtr(hwnd, 0); WNDCLASS childClass; switch (message) { case WM_WINDOWPOSCHANGED: /* Should be processed by DefWindowProc, otherwise a double buffered * context is not properly resized when the corresponding window is * resized. */ break; case WM_DESTROY: if (togl && togl->TkWin != NULL) { if (togl->SetGrid > 0) { Tk_UnsetGrid(togl->TkWin); } (void) Tcl_DeleteCommandFromToken(togl->Interp, togl->widgetCmd); } break; case WM_ERASEBKGND: /* We clear our own window */ return 1; case WM_DISPLAYCHANGE: if (togl->PbufferFlag && hasARBPbuffer && !togl->pbufferLost) { queryPbuffer(togl->pbuf, WGL_PBUFFER_LOST_ARB, &togl->pbufferLost); } /* FALLTHROUGH */ default: # if USE_STATIC_LIB return TkWinChildProc(hwnd, message, wParam, lParam); # else /* * OK, since TkWinChildProc is not explicitly exported in the * dynamic libraries, we have to retrieve it from the class info * registered with windows. * */ if (tkWinChildProc == NULL) { GetClassInfo(Tk_GetHINSTANCE(), TK_WIN_CHILD_CLASS_NAME, &childClass); tkWinChildProc = childClass.lpfnWndProc; } return tkWinChildProc(hwnd, message, wParam, lParam); # endif } result = DefWindowProc(hwnd, message, wParam, lParam); Tcl_ServiceAll(); return result; } #endif /* TOGL_WGL */ /* * Togl_MakeWindow * * Window creation function, invoked as a callback from Tk_MakeWindowExist. * This is called instead of TkpMakeWindow and must always succeed. */ static Window Togl_MakeWindow(Tk_Window tkwin, Window parent, ClientData instanceData) { Togl *togl = (Togl *) instanceData; Display *dpy; Colormap cmap; int scrnum; Window window = None; #if defined(TOGL_X11) Bool directCtx = True; XSetWindowAttributes swa; int width, height; #elif defined(TOGL_WGL) HWND hwnd, parentWin; DWORD style; HINSTANCE hInstance; PIXELFORMATDESCRIPTOR pfd; int width, height; Bool createdPbufferDC = False; #elif defined(TOGL_AGL) #endif if (togl->badWindow) { TkWindow *winPtr = (TkWindow *) tkwin; return TkpMakeWindow(winPtr, parent); } /* for color index mode photos */ if (togl->RedMap) free(togl->RedMap); if (togl->GreenMap) free(togl->GreenMap); if (togl->BlueMap) free(togl->BlueMap); togl->RedMap = togl->GreenMap = togl->BlueMap = NULL; togl->MapSize = 0; dpy = Tk_Display(tkwin); scrnum = Tk_ScreenNumber(tkwin); /* * Windows and Mac OS X need the window created before OpenGL context * is created. So do that now and set the window variable. */ #if defined(TOGL_AGL) || defined(TOGL_NSOPENGL) { TkWindow *winPtr = (TkWindow *) tkwin; window = TkpMakeWindow(winPtr, parent); if (!togl->PbufferFlag) (void) XMapWindow(dpy, window); } #elif defined(TOGL_WGL) hInstance = Tk_GetHINSTANCE(); if (!ToglClassInitialized) { WNDCLASS ToglClass; ToglClassInitialized = True; ToglClass.style = CS_HREDRAW | CS_VREDRAW; ToglClass.cbClsExtra = 0; ToglClass.cbWndExtra = sizeof (LONG_PTR); /* to save Togl* */ ToglClass.hInstance = hInstance; ToglClass.hbrBackground = NULL; ToglClass.lpszMenuName = NULL; ToglClass.lpszClassName = TOGL_CLASS_NAME; ToglClass.lpfnWndProc = Win32WinProc; ToglClass.hIcon = NULL; ToglClass.hCursor = NULL; if (!RegisterClass(&ToglClass)) { Tcl_SetResult(togl->Interp, TCL_STUPID "unable register Togl window class", TCL_STATIC); goto error; } } /* duplicate tkpMakeWindow logic from tk8.[45]/win/tkWinWindow.c */ if (parent != None) { parentWin = Tk_GetHWND(parent); style = WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS; } else { parentWin = NULL; style = WS_POPUP | WS_CLIPCHILDREN; } if (togl->PbufferFlag) { width = height = 1; /* TODO: demo code mishaves when set to 1000 */ } else { width = togl->Width; height = togl->Height; } hwnd = CreateWindowEx(WS_EX_NOPARENTNOTIFY, TOGL_CLASS_NAME, NULL, style, 0, 0, width, height, parentWin, NULL, hInstance, NULL); SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); window = Tk_AttachHWND(tkwin, hwnd); SetWindowLongPtr(hwnd, 0, (LONG_PTR) togl); if (togl->PbufferFlag) { ShowWindow(hwnd, SW_HIDE); /* make sure it's hidden */ } #endif /* * Figure out which OpenGL context to use */ #ifdef TOGL_WGL togl->tglGLHdc = GetDC(hwnd); #endif if (togl->PixelFormat) { #if defined(TOGL_X11) XVisualInfo template; int count = 0; template.visualid = togl->PixelFormat; togl->VisInfo = XGetVisualInfo(dpy, VisualIDMask, &template, &count); if (togl->VisInfo == NULL) { Tcl_SetResult(togl->Interp, TCL_STUPID "missing visual information", TCL_STATIC); goto error; } #endif if (!togl_describePixelFormat(togl)) { Tcl_SetResult(togl->Interp, TCL_STUPID "couldn't choose pixel format", TCL_STATIC); goto error; } } else { #if defined(TOGL_X11) togl->VisInfo = togl_pixelFormat(togl, scrnum); if (togl->VisInfo == NULL) #elif defined(TOGL_WGL) || defined(TOGL_AGL) || defined(TOGL_NSOPENGL) # ifdef TOGL_WGL togl->PixelFormat = togl_pixelFormat(togl, hwnd); # elif defined(TOGL_NSOPENGL) togl->PixelFormat = (void *)togl_pixelFormat(togl); # else togl->PixelFormat = (Tcl_WideInt)togl_pixelFormat(togl); # endif if (togl->PixelFormat == 0) #endif { goto error; } } #ifdef TOGL_WGL if (togl->PbufferFlag) { togl->pbuf = togl_createPbuffer(togl); if (togl->pbuf == NULL) { Tcl_SetResult(togl->Interp, TCL_STUPID "couldn't create pbuffer", TCL_STATIC); goto error; } ReleaseDC(hwnd, togl->tglGLHdc); togl->tglGLHdc = getPbufferDC(togl->pbuf); createdPbufferDC = True; } else if (SetPixelFormat(togl->tglGLHdc, (int) togl->PixelFormat, NULL) == FALSE) { Tcl_SetResult(togl->Interp, TCL_STUPID "couldn't set pixel format", TCL_STATIC); goto error; } #endif #if defined(TOGL_WGL) || defined(TOGL_AGL) || defined(TOGL_NSOPENGL) if (togl->VisInfo == NULL) { /* * Create a new OpenGL rendering context. And check to share lists. */ Visual *visual; /* Just for portability, define the simplest visinfo */ visual = DefaultVisual(dpy, scrnum); togl->VisInfo = (XVisualInfo *) calloc(1, sizeof (XVisualInfo)); togl->VisInfo->screen = scrnum; togl->VisInfo->visual = visual; togl->VisInfo->visualid = visual->visualid; # if defined(__cplusplus) || defined(c_plusplus) togl->VisInfo->c_class = visual->c_class; # else togl->VisInfo->class = visual->class; # endif togl->VisInfo->depth = visual->bits_per_rgb; } #endif #if defined(TOGL_X11) if (togl->Indirect) { directCtx = False; } #endif /* * Create a new OpenGL rendering context. */ #if defined(TOGL_X11) if (togl->ShareList) { /* share display lists with existing togl widget */ Togl *shareWith = FindTogl(togl, togl->ShareList); GLXContext shareCtx; int error_code; if (shareWith) { shareCtx = shareWith->Ctx; togl->contextTag = shareWith->contextTag; } else { shareCtx = None; } if (shareCtx) { togl_SetupXErrorHandler(); } togl->Ctx = glXCreateContext(dpy, togl->VisInfo, shareCtx, directCtx); if (shareCtx && (error_code = togl_CheckForXError(togl))) { char buf[256]; togl->Ctx = NULL; XGetErrorText(dpy, error_code, buf, sizeof buf); Tcl_AppendResult(togl->Interp, "unable to share display lists: ", buf, NULL); goto error; } } else { if (togl->ShareContext && FindTogl(togl, togl->ShareContext)) { /* share OpenGL context with existing Togl widget */ Togl *shareWith = FindTogl(togl, togl->ShareContext); if (togl->VisInfo->visualid != shareWith->VisInfo->visualid) { Tcl_SetResult(togl->Interp, TCL_STUPID "unable to share OpenGL context", TCL_STATIC); goto error; } togl->Ctx = shareWith->Ctx; } else { /* don't share display lists */ togl->ShareContext = False; togl->Ctx = glXCreateContext(dpy, togl->VisInfo, None, directCtx); } } #elif defined(TOGL_WGL) if (togl->ShareContext && FindTogl(togl, togl->ShareContext)) { /* share OpenGL context with existing Togl widget */ Togl *shareWith = FindTogl(togl, togl->ShareContext); if (togl->PixelFormat != shareWith->PixelFormat) { Tcl_SetResult(togl->Interp, TCL_STUPID "unable to share OpenGL context", TCL_STATIC); goto error; } togl->Ctx = shareWith->Ctx; } else { togl->Ctx = wglCreateContext(togl->tglGLHdc); } if (togl->ShareList) { /* share display lists with existing togl widget */ Togl *shareWith = FindTogl(togl, togl->ShareList); if (shareWith) { if (!wglShareLists(shareWith->Ctx, togl->Ctx)) { # if 0 LPVOID lpMsgBuf; DWORD err = GetLastError(); FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL); fprintf(stderr, "unable to share display lists: %d: %s\n", err, lpMsgBuf); LocalFree(lpMsgBuf); # endif Tcl_SetResult(togl->Interp, TCL_STUPID "unable to share display lists", TCL_STATIC); goto error; } togl->contextTag = shareWith->contextTag; } } #elif defined(TOGL_AGL) AGLContext shareCtx = NULL; if (togl->ShareList) { /* share display lists with existing togl widget */ Togl *shareWith = FindTogl(togl, togl->ShareList); if (shareWith) { shareCtx = shareWith->Ctx; togl->contextTag = shareWith->contextTag; } } if (togl->ShareContext && FindTogl(togl, togl->ShareContext)) { /* share OpenGL context with existing Togl widget */ Togl *shareWith = FindTogl(togl, togl->ShareContext); if (togl->PixelFormat != shareWith->PixelFormat) { Tcl_SetResult(togl->Interp, TCL_STUPID "unable to share OpenGL context", TCL_STATIC); goto error; } togl->Ctx = shareWith->Ctx; } else if ((togl->Ctx = aglCreateContext((AGLPixelFormat) togl->PixelFormat, shareCtx)) == NULL) { GLenum err = aglGetError(); aglDestroyPixelFormat((AGLPixelFormat) togl->PixelFormat); togl->PixelFormat = 0; if (err == AGL_BAD_MATCH) Tcl_SetResult(togl->Interp, TCL_STUPID "unable to share display lists" ": shared context doesn't match", TCL_STATIC); else if (err == AGL_BAD_CONTEXT) Tcl_SetResult(togl->Interp, TCL_STUPID "unable to share display lists" ": bad shared context", TCL_STATIC); else if (err == AGL_BAD_PIXELFMT) Tcl_SetResult(togl->Interp, TCL_STUPID "could not create rendering context" ": bad pixel format", TCL_STATIC); else Tcl_SetResult(togl->Interp, TCL_STUPID "could not create rendering context" ": unknown reason", TCL_STATIC); goto error; } if (!togl->PbufferFlag && !aglSetDrawable(togl->Ctx, Togl_MacOSXGetDrawablePort(togl))) { /* aglSetDrawable is deprecated in OS X 10.5 */ aglDestroyContext(togl->Ctx); togl->Ctx = NULL; aglDestroyPixelFormat((AGLPixelFormat) togl->PixelFormat); togl->PixelFormat = 0; Tcl_SetResult(togl->Interp, TCL_STUPID "couldn't set drawable", TCL_STATIC); goto error; } #elif defined(TOGL_NSOPENGL) NSOpenGLContext *shareCtx = NULL; if (togl->ShareList) { /* share display lists with existing togl widget */ Togl *shareWith = FindTogl(togl, togl->ShareList); if (shareWith) { shareCtx = shareWith->Ctx; togl->contextTag = shareWith->contextTag; } } if (togl->ShareContext && FindTogl(togl, togl->ShareContext)) { /* share OpenGL context with existing Togl widget */ Tcl_SetResult(togl->Interp, TCL_STUPID "unable to share NSOpenGL context", TCL_STATIC); goto error; /* Togl *shareWith = FindTogl(togl, togl->ShareContext); if (togl->PixelFormat != shareWith->PixelFormat) { Tcl_SetResult(togl->Interp, TCL_STUPID "unable to share OpenGL context", TCL_STATIC); goto error; } togl->Ctx = [[NSOpenGLContext alloc] initWithCGLContextObj:shareWith->Ctx]; */ /* initWithCGLContextObj requires Mac OS 10.6 */ } else { togl->Ctx = [NSOpenGLContext alloc]; if ([togl->Ctx initWithFormat:togl->PixelFormat shareContext:shareCtx] == nil) { [togl->PixelFormat release]; togl->PixelFormat = 0; Tcl_SetResult(togl->Interp, TCL_STUPID "Could not obtain OpenGL context", TCL_STATIC); goto error; } } if (!togl->PbufferFlag) { togl->nsview = [[ToglNSView alloc] initWithFrame:NSZeroRect]; [togl->nsview setTogl:togl]; if ([togl->nsview respondsToSelector:@selector(setWantsBestResolutionOpenGLSurface:)]) { [togl->nsview setWantsBestResolutionOpenGLSurface:YES]; } [togl->nsview setAcceptsTouchEvents:YES]; MacDrawable *d = ((TkWindow *) togl->TkWin)->privatePtr; NSView *topview = d->toplevel->view; [topview addSubview:togl->nsview]; /* TODO: Appears setView has to be deferred until window mapped. * or it gives "invalid drawable" error. But MapNotify doesn't happen. * I think toplevel is already mapped. Iconifying and uniconifying * main window makes the graphics work. */ /* [togl->Ctx setView:togl->nsview];*/ } #endif if (togl->Ctx == NULL) { Tcl_SetResult(togl->Interp, TCL_STUPID "could not create rendering context", TCL_STATIC); goto error; } #if defined(TOGL_AGL) || defined(TOGL_NSOPENGL) CGDisplayRegisterReconfigurationCallback(ReconfigureCB, togl); #endif if (togl->PbufferFlag) { /* Don't need a colormap, nor overlay, nor be displayed */ #if defined(TOGL_X11) || defined(TOGL_AGL) || defined(TOGL_NSOPENGL) togl->pbuf = togl_createPbuffer(togl); if (!togl->pbuf) { /* tcl result set in togl_createPbuffer */ # ifdef TOGL_AGL if (!togl->ShareContext) { aglDestroyContext(togl->Ctx); aglDestroyPixelFormat((AGLPixelFormat) togl->PixelFormat); } togl->Ctx = NULL; togl->PixelFormat = 0; # endif # ifdef TOGL_NSOPENGL if (!togl->ShareContext) { [togl->Ctx release]; [togl->PixelFormat release]; } togl->Ctx = NULL; togl->PixelFormat = 0; # endif goto error; } # ifdef TOGL_X11 window = TkpMakeWindow((TkWindow *) tkwin, parent); # endif #endif return window; } #ifdef TOGL_WGL DescribePixelFormat(togl->tglGLHdc, (int) togl->PixelFormat, sizeof (pfd), &pfd); #endif /* * find a colormap */ if (togl->RgbaFlag) { /* Colormap for RGB mode */ #if defined(TOGL_X11) cmap = get_rgb_colormap(dpy, scrnum, togl->VisInfo, tkwin); #elif defined(TOGL_WGL) if (pfd.dwFlags & PFD_NEED_PALETTE) { cmap = Win32CreateRgbColormap(pfd); } else { cmap = DefaultColormap(dpy, scrnum); } #elif defined(TOGL_AGL) || defined(TOGL_NSOPENGL) cmap = DefaultColormap(dpy, scrnum); #endif } else { /* Colormap for CI mode */ #ifdef TOGL_WGL /* this logic is to overcome a combination driver/compiler bug: (1) * cColorBits may be unusually large (e.g., 32 instead of 8 or 12) and * (2) 1 << 32 might be 1 instead of zero (gcc for ia32) */ if (pfd.cColorBits >= MAX_CI_COLORMAP_BITS) { togl->CiColormapSize = MAX_CI_COLORMAP_SIZE; } else { togl->CiColormapSize = 1 << pfd.cColorBits; if (togl->CiColormapSize >= MAX_CI_COLORMAP_SIZE) togl->CiColormapSize = MAX_CI_COLORMAP_SIZE; } #endif if (togl->PrivateCmapFlag) { /* need read/write colormap so user can store own color entries */ #if defined(TOGL_X11) cmap = XCreateColormap(dpy, XRootWindow(dpy, togl->VisInfo->screen), togl->VisInfo->visual, AllocAll); #elif defined(TOGL_WGL) cmap = Win32CreateCiColormap(togl); #elif defined(TOGL_AGL) || defined(TOGL_NSOPENGL) /* need to figure out how to do this correctly on Mac... */ cmap = DefaultColormap(dpy, scrnum); #endif } else { if (togl->VisInfo->visual == DefaultVisual(dpy, scrnum)) { /* share default/root colormap */ cmap = Tk_Colormap(tkwin); } else { /* make a new read-only colormap */ cmap = XCreateColormap(dpy, XRootWindow(dpy, togl->VisInfo->screen), togl->VisInfo->visual, AllocNone); } } } /* Make sure Tk knows to switch to the new colormap when the cursor is over * this window when running in color index mode. */ (void) Tk_SetWindowVisual(tkwin, togl->VisInfo->visual, togl->VisInfo->depth, cmap); #ifdef TOGL_WGL /* Install the colormap */ SelectPalette(togl->tglGLHdc, ((TkWinColormap *) cmap)->palette, TRUE); RealizePalette(togl->tglGLHdc); #endif #if defined(TOGL_X11) swa.background_pixmap = None; swa.border_pixel = 0; swa.colormap = cmap; swa.event_mask = ALL_EVENTS_MASK; if (togl->PbufferFlag) { width = height = 1; } else { width = togl->Width; height = togl->Height; } window = XCreateWindow(dpy, parent, 0, 0, width, height, 0, togl->VisInfo->depth, InputOutput, togl->VisInfo->visual, CWBackPixmap | CWBorderPixel | CWColormap | CWEventMask, &swa); /* Make sure window manager installs our colormap */ (void) XSetWMColormapWindows(dpy, window, &window, 1); if (!togl->DoubleFlag) { int dbl_flag; /* See if we requested single buffering but had to accept a double * buffered visual. If so, set the GL draw buffer to be the front * buffer to simulate single buffering. */ if (glXGetConfig(dpy, togl->VisInfo, GLX_DOUBLEBUFFER, &dbl_flag)) { if (dbl_flag) { glXMakeCurrent(dpy, window, togl->Ctx); glDrawBuffer(GL_FRONT); glReadBuffer(GL_FRONT); } } } #elif defined(TOGL_WGL) if (!togl->DoubleFlag) { /* See if we requested single buffering but had to accept a double * buffered visual. If so, set the GL draw buffer to be the front * buffer to simulate single buffering. */ if (getPixelFormatAttribiv == NULL) { /* pfd is already set */ if ((pfd.dwFlags & PFD_DOUBLEBUFFER) != 0) { wglMakeCurrent(togl->tglGLHdc, togl->Ctx); glDrawBuffer(GL_FRONT); glReadBuffer(GL_FRONT); } } else { static int attribs[] = { WGL_DOUBLE_BUFFER_ARB, }; # define NUM_ATTRIBS (sizeof attribs / sizeof attribs[0]) int info[NUM_ATTRIBS]; getPixelFormatAttribiv(togl->tglGLHdc, (int) togl->PixelFormat, 0, NUM_ATTRIBS, attribs, info); # undef NUM_ATTRIBS if (info[0]) { wglMakeCurrent(togl->tglGLHdc, togl->Ctx); glDrawBuffer(GL_FRONT); glReadBuffer(GL_FRONT); } } } #endif #if TOGL_USE_OVERLAY if (togl->OverlayFlag) { if (SetupOverlay(togl) == TCL_ERROR) { fprintf(stderr, "Warning: couldn't setup overlay.\n"); togl->OverlayFlag = False; } } #endif #if !defined(TOGL_AGL) /* Request the X window to be displayed */ (void) XMapWindow(dpy, window); #endif if (!togl->RgbaFlag) { int index_size; #if defined(TOGL_X11) || defined(TOGL_AGL) || defined(TOGL_NSOPENGL) GLint index_bits; glGetIntegerv(GL_INDEX_BITS, &index_bits); index_size = 1 << index_bits; #elif defined(TOGL_WGL) index_size = togl->CiColormapSize; #endif if (togl->MapSize != index_size) { if (togl->RedMap) free(togl->RedMap); if (togl->GreenMap) free(togl->GreenMap); if (togl->BlueMap) free(togl->BlueMap); togl->MapSize = index_size; togl->RedMap = (GLfloat *) calloc(index_size, sizeof (GLfloat)); togl->GreenMap = (GLfloat *) calloc(index_size, sizeof (GLfloat)); togl->BlueMap = (GLfloat *) calloc(index_size, sizeof (GLfloat)); } } #ifdef HAVE_AUTOSTEREO if (togl->Stereo == TOGL_STEREO_NATIVE) { if (!togl->as_initialized) { const char *autostereod; togl->as_initialized = True; if ((autostereod = getenv("AUTOSTEREOD")) == NULL) autostereod = AUTOSTEREOD; if (autostereod && *autostereod) { if (ASInitialize(togl->display, autostereod) == Success) { togl->ash = ASCreatedStereoWindow(dpy); } } } else { togl->ash = ASCreatedStereoWindow(dpy); } } #endif return window; error: togl->badWindow = True; #if defined(TOGL_X11) if (window == None) { TkWindow *winPtr = (TkWindow *) tkwin; window = TkpMakeWindow(winPtr, parent); } #elif defined(TOGL_WGL) if (togl->tglGLHdc) { if (createdPbufferDC) releasePbufferDC(togl->pbuf, togl->tglGLHdc); else ReleaseDC(hwnd, togl->tglGLHdc); togl->tglGLHdc = NULL; } #endif return window; } /* * Togl_WorldChanged * * Add support for setgrid option. */ static void Togl_WorldChanged(ClientData instanceData) { Togl *togl = (Togl *) instanceData; int width; int height; if (togl->PbufferFlag) width = height = 1; else { width = togl->Width; height = togl->Height; } Tk_GeometryRequest(togl->TkWin, width, height); Tk_SetInternalBorder(togl->TkWin, 0); if (togl->SetGrid > 0) { Tk_SetGrid(togl->TkWin, width / togl->SetGrid, height / togl->SetGrid, togl->SetGrid, togl->SetGrid); } else { Tk_UnsetGrid(togl->TkWin); } } static void Togl_SetViewPort(const struct Togl *togl) { glViewport(0, 0, togl->Width*togl->PixelScale, togl->Height*togl->PixelScale); } /* * ToglFree * * Wrap the ckfree macro. */ static void ToglFree(char *clientData) { ckfree(clientData); } /* * ToglCmdDeletedProc * * This procedure is invoked when a widget command is deleted. If * the widget isn't already in the process of being destroyed, * this command destroys it. * * Results: * None. * * Side effects: * The widget is destroyed. * *---------------------------------------------------------------------- */ static void ToglCmdDeletedProc(ClientData clientData) { Togl *togl = (Togl *) clientData; Tk_Window tkwin = togl->TkWin; /* * This procedure could be invoked either because the window was * destroyed and the command was then deleted (in which case tkwin * is NULL) or because the command was deleted, and then this procedure * destroys the widget. */ if (tkwin) { Tk_DeleteEventHandler(tkwin, ExposureMask | StructureNotifyMask, Togl_EventProc, (ClientData) togl); } Tk_Preserve((ClientData) togl); Tcl_EventuallyFree((ClientData) togl, ToglFree); Togl_LeaveStereo(togl, togl->Stereo); if (togl->DestroyProc) { /* call user's cleanup code */ Togl_CallCallback(togl, togl->DestroyProc); } if (togl->TimerProc != NULL) { Tcl_DeleteTimerHandler(togl->timerHandler); togl->timerHandler = NULL; } if (togl->UpdatePending) { Tcl_CancelIdleCall(Togl_Render, (ClientData) togl); togl->UpdatePending = False; } #ifndef NO_TK_CURSOR if (togl->Cursor != None) { Tk_FreeCursor(togl->display, togl->Cursor); togl->Cursor = None; } #endif /* remove from linked list */ RemoveFromList(togl); togl->TkWin = NULL; if (tkwin != NULL) { if (togl->Ctx) { if (FindToglWithSameContext(togl) == NULL) { #if defined(TOGL_X11) glXDestroyContext(togl->display, togl->Ctx); #elif defined(TOGL_WGL) wglDeleteContext(togl->Ctx); #elif defined(TOGL_AGL) aglDestroyContext(togl->Ctx); CGDisplayRemoveReconfigurationCallback(ReconfigureCB, togl); #elif defined(TOGL_NSOPENGL) [togl->Ctx release]; togl->Ctx = nil; [togl->nsview setTogl:nil]; [togl->nsview release]; togl->nsview = nil; CGDisplayRemoveReconfigurationCallback(ReconfigureCB, togl); #endif #if defined(TOGL_X11) XFree(togl->VisInfo); #else free(togl->VisInfo); #endif } #if defined(TOGL_WGL) if (togl->tglGLHdc) { if (togl->PbufferFlag) { releasePbufferDC(togl->pbuf, togl->tglGLHdc); } else { HWND hwnd = Tk_GetHWND(Tk_WindowId(tkwin)); ReleaseDC(hwnd, togl->tglGLHdc); } togl->tglGLHdc = NULL; } #endif if (togl->PbufferFlag && togl->pbuf) { togl_destroyPbuffer(togl); togl->pbuf = 0; } togl->Ctx = NULL; togl->VisInfo = NULL; } #if defined(TOGL_X11) # if TOGL_USE_OVERLAY if (togl->OverlayCtx) { Tcl_HashEntry *entryPtr; TkWindow *winPtr = (TkWindow *) tkwin; if (winPtr) { entryPtr = Tcl_FindHashEntry(&winPtr->dispPtr->winTable, (const char *) togl->OverlayWindow); Tcl_DeleteHashEntry(entryPtr); } if (FindToglWithSameOverlayContext(togl) == NULL) glXDestroyContext(togl->display, togl->OverlayCtx); togl->OverlayCtx = NULL; } # endif /* TOGL_USE_OVERLAY */ #endif if (togl->SetGrid > 0) { Tk_UnsetGrid(tkwin); } Tk_DestroyWindow(tkwin); } Tk_Release((ClientData) togl); } /* * This gets called to track top level position changes for * row interleaved stereo. */ static void Togl_RedisplayProc(ClientData clientData, XEvent *eventPtr) { Togl *togl = (Togl *) clientData; switch (eventPtr->type) { case ConfigureNotify: Togl_PostRedisplay(togl); break; } } #if defined(TOGL_AGL) || defined(TOGL_NSOPENGL) static int viewPixelScale(NSView *nsview) { int pixelScale = 1; if ([nsview respondsToSelector:@selector(convertRectToBacking:)]) { NSRect wbounds = [nsview bounds]; NSRect gbounds = [nsview convertRectToBacking:wbounds]; pixelScale = (wbounds.size.width > 0 ? gbounds.size.width / wbounds.size.width : 1); } return pixelScale; } #endif /* * This gets called to handle Togl window configuration events */ static void Togl_EventProc(ClientData clientData, XEvent *eventPtr) { Togl *togl = (Togl *) clientData; switch (eventPtr->type) { case Expose: #if defined(TOGL_NSOPENGL) if (!Tk_IsMapped(togl->TkWin)) /* Tk Cocoa generates expose events for unmapped windows! */ break; #endif if (eventPtr->xexpose.count == 0) { if (!togl->UpdatePending && eventPtr->xexpose.window == Tk_WindowId(togl->TkWin)) { Togl_PostRedisplay(togl); } #if defined(TOGL_X11) if (!togl->OverlayUpdatePending && togl->OverlayFlag && togl->OverlayIsMapped && eventPtr->xexpose.window == togl->OverlayWindow) { Togl_PostOverlayRedisplay(togl); } #endif #if defined(TOGL_NSOPENGL) [togl->Ctx setView:togl->nsview]; SetMacBufRect(togl); #endif } break; case ConfigureNotify: if (togl->PbufferFlag) break; #if defined(TOGL_AGL) || defined(TOGL_NSOPENGL) int pixelScale = viewPixelScale(togl->nsview); if (togl->Width == Tk_Width(togl->TkWin) && togl->Height == Tk_Height(togl->TkWin) && togl->PixelScale == pixelScale) { // Even though the size hasn't changed, // it's position on the screen may have. if (Tk_IsMapped(togl->TkWin)) SetMacBufRect(togl); break; } #endif togl->Width = Tk_Width(togl->TkWin); togl->Height = Tk_Height(togl->TkWin); #if defined(TOGL_AGL) || defined(TOGL_NSOPENGL) togl->PixelScale = pixelScale; #endif (void) XResizeWindow(Tk_Display(togl->TkWin), Tk_WindowId(togl->TkWin), togl->Width, togl->Height); #if defined(TOGL_X11) if (togl->OverlayFlag) { (void) XResizeWindow(Tk_Display(togl->TkWin), togl->OverlayWindow, togl->Width, togl->Height); (void) XRaiseWindow(Tk_Display(togl->TkWin), togl->OverlayWindow); } #endif #if defined(TOGL_AGL) || defined(TOGL_NSOPENGL) SetMacBufRect(togl); #endif Togl_MakeCurrent(togl); if (togl->ReshapeProc) { Togl_SetViewPort(togl); (void) Togl_CallCallback(togl, togl->ReshapeProc); } else { Togl_SetViewPort(togl); #if defined(TOGL_X11) if (togl->OverlayFlag) { Togl_UseLayer(togl, TOGL_OVERLAY); Togl_SetViewPort(togl); Togl_UseLayer(togl, TOGL_NORMAL); } #endif } break; case MapNotify: #if defined(TOGL_AGL) if (!togl->PbufferFlag) { /* * See comment for the UnmapNotify case below. */ AGLDrawable d = Togl_MacOSXGetDrawablePort(togl); /* aglSetDrawable is deprecated in OS X 10.5 */ aglSetDrawable(togl->Ctx, d); SetMacBufRect(togl); } #endif #if defined(TOGL_NSOPENGL) if (!togl->PbufferFlag) { /* * See comment for the UnmapNotify case below. */ [togl->Ctx setView:togl->nsview]; SetMacBufRect(togl); } #endif break; case UnmapNotify: #if defined(TOGL_AGL) if (!togl->PbufferFlag) { /* * For Mac OS X Aqua, Tk subwindows are not implemented as * separate Aqua windows. They are just different regions of * a single Aqua window. To unmap them they are just not drawn. * Have to disconnect the AGL context otherwise they will continue * to be displayed directly by Aqua. */ /* aglSetDrawable is deprecated in OS X 10.5 */ aglSetDrawable(togl->Ctx, NULL); } #endif #if defined(TOGL_NSOPENGL) if (!togl->PbufferFlag) { /* * For Mac OS X Aqua, Tk subwindows are not implemented as * separate Aqua windows. They are just different regions of * a single Aqua window. To unmap them they are just not drawn. * Have to disconnect the NSView otherwise they will continue * to be displayed directly by Aqua. */ [togl->Ctx clearDrawable]; } #endif break; case DestroyNotify: if (togl->TkWin != NULL) { #ifdef TOGL_WGL HWND hwnd = Tk_GetHWND(Tk_WindowId(togl->TkWin)); /* Prevent Win32WinProc from calling Tcl_DeleteCommandFromToken * a second time */ SetWindowLongPtr(hwnd, 0, (LONG_PTR) 0); #endif if (togl->SetGrid > 0) { Tk_UnsetGrid(togl->TkWin); } (void) Tcl_DeleteCommandFromToken(togl->Interp, togl->widgetCmd); } break; default: /* nothing */ ; } } void Togl_PostRedisplay(Togl *togl) { if (!togl->UpdatePending) { togl->UpdatePending = True; Tk_DoWhenIdle(Togl_Render, (ClientData) togl); } } Bool Togl_UpdatePending(const Togl *togl) { return togl->UpdatePending; } void Togl_SwapBuffers(const Togl *togl) { if (togl->DoubleFlag) { #if defined(TOGL_WGL) int res = SwapBuffers(togl->tglGLHdc); if (!res) { ErrorExit(TEXT("SwapBuffers")); } #elif defined(TOGL_X11) glXSwapBuffers(Tk_Display(togl->TkWin), Tk_WindowId(togl->TkWin)); #elif defined(TOGL_AGL) aglSwapBuffers(togl->Ctx); #elif defined(TOGL_NSOPENGL) [togl->Ctx flushBuffer]; #endif } else { glFlush(); } } const char * Togl_Ident(const Togl *togl) { return togl->Ident; } int Togl_Width(const Togl *togl) { return togl->Width; } int Togl_Height(const Togl *togl) { return togl->Height; } int Togl_PixelScale(const Togl *togl) { return togl->PixelScale; } Tcl_Interp * Togl_Interp(const Togl *togl) { return togl->Interp; } Tk_Window Togl_TkWin(const Togl *togl) { return togl->TkWin; } const char * Togl_CommandName(const Togl *togl) { return Tcl_GetCommandName(togl->Interp, togl->widgetCmd); } int Togl_ContextTag(const Togl *togl) { return togl->contextTag; } Bool Togl_HasRGBA(const Togl *togl) { return togl->RgbaFlag; } Bool Togl_IsDoubleBuffered(const Togl *togl) { return togl->DoubleFlag; } Bool Togl_HasDepthBuffer(const Togl *togl) { return togl->DepthFlag; } Bool Togl_HasAccumulationBuffer(const Togl *togl) { return togl->AccumFlag; } Bool Togl_HasDestinationAlpha(const Togl *togl) { return togl->AlphaFlag; } Bool Togl_HasStencilBuffer(const Togl *togl) { return togl->StencilFlag; } int Togl_StereoMode(const Togl *togl) { return togl->Stereo; } Bool Togl_HasMultisample(const Togl *togl) { return togl->MultisampleFlag; } #if defined(TOGL_X11) /* * A replacement for XAllocColor. This function should never * fail to allocate a color. When XAllocColor fails, we return * the nearest matching color. If we have to allocate many colors * this function isn't too efficient; the XQueryColors() could be * done just once. * Written by Michael Pichler, Brian Paul, Mark Kilgard * Input: dpy - X display * cmap - X colormap * cmapSize - size of colormap * In/Out: color - the XColor struct * Output: exact - 1=exact color match, 0=closest match */ static void noFaultXAllocColor(Display *dpy, Colormap cmap, int cmapSize, XColor *color, int *exact) { XColor *ctable, subColor; int i, bestmatch; double mindist; /* 3*2^16^2 exceeds long int precision. */ /* First try just using XAllocColor. */ if (XAllocColor(dpy, cmap, color)) { *exact = 1; return; } /* Retrieve color table entries. */ /* XXX alloca candidate. */ ctable = (XColor *) ckalloc(cmapSize * sizeof (XColor)); for (i = 0; i < cmapSize; i++) { ctable[i].pixel = i; } (void) XQueryColors(dpy, cmap, ctable, cmapSize); /* Find best match. */ bestmatch = -1; mindist = 0; for (i = 0; i < cmapSize; i++) { double dr = (double) color->red - (double) ctable[i].red; double dg = (double) color->green - (double) ctable[i].green; double db = (double) color->blue - (double) ctable[i].blue; double dist = dr * dr + dg * dg + db * db; if (bestmatch < 0 || dist < mindist) { bestmatch = i; mindist = dist; } } /* Return result. */ subColor.red = ctable[bestmatch].red; subColor.green = ctable[bestmatch].green; subColor.blue = ctable[bestmatch].blue; ckfree((char *) ctable); /* Try to allocate the closest match color. This should only fail if the * cell is read/write. Otherwise, we're incrementing the cell's reference * count. */ if (!XAllocColor(dpy, cmap, &subColor)) { /* do this to work around a problem reported by Frank Ortega */ subColor.pixel = (unsigned long) bestmatch; subColor.red = ctable[bestmatch].red; subColor.green = ctable[bestmatch].green; subColor.blue = ctable[bestmatch].blue; subColor.flags = DoRed | DoGreen | DoBlue; } *color = subColor; } #elif defined(TOGL_WGL) static UINT Win32AllocColor(const Togl *togl, float red, float green, float blue) { /* Modified version of XAllocColor emulation of Tk. - returns index, * instead of color itself - allocates logical palette entry even for * non-palette devices */ TkWinColormap *cmap = (TkWinColormap *) Tk_Colormap(togl->TkWin); UINT index; COLORREF newColor, closeColor; PALETTEENTRY entry, closeEntry; int isNew, refCount; Tcl_HashEntry *entryPtr; entry.peRed = (unsigned char) (red * 255 + .5); entry.peGreen = (unsigned char) (green * 255 + .5); entry.peBlue = (unsigned char) (blue * 255 + .5); entry.peFlags = 0; /* * Find the nearest existing palette entry. */ newColor = RGB(entry.peRed, entry.peGreen, entry.peBlue); index = GetNearestPaletteIndex(cmap->palette, newColor); GetPaletteEntries(cmap->palette, index, 1, &closeEntry); closeColor = RGB(closeEntry.peRed, closeEntry.peGreen, closeEntry.peBlue); /* * If this is not a duplicate and colormap is not full, allocate a new entry. */ if (newColor != closeColor) { if (cmap->size == (unsigned int) togl->CiColormapSize) { entry = closeEntry; } else { cmap->size++; ResizePalette(cmap->palette, cmap->size); index = cmap->size - 1; SetPaletteEntries(cmap->palette, index, 1, &entry); SelectPalette(togl->tglGLHdc, cmap->palette, TRUE); RealizePalette(togl->tglGLHdc); } } newColor = PALETTERGB(entry.peRed, entry.peGreen, entry.peBlue); entryPtr = Tcl_CreateHashEntry(&cmap->refCounts, (CONST char *) newColor, &isNew); if (isNew) { refCount = 1; } else { refCount = ((int) Tcl_GetHashValue(entryPtr)) + 1; } Tcl_SetHashValue(entryPtr, (ClientData) refCount); /* for color index mode photos */ togl->RedMap[index] = (GLfloat) (entry.peRed / 255.0); togl->GreenMap[index] = (GLfloat) (entry.peGreen / 255.0); togl->BlueMap[index] = (GLfloat) (entry.peBlue / 255.0); return index; } static void Win32FreeColor(const Togl *togl, unsigned long index) { TkWinColormap *cmap = (TkWinColormap *) Tk_Colormap(togl->TkWin); COLORREF cref; UINT count, refCount; PALETTEENTRY entry, *entries; Tcl_HashEntry *entryPtr; if (index >= cmap->size) { panic("Tried to free a color that isn't allocated."); } GetPaletteEntries(cmap->palette, index, 1, &entry); cref = PALETTERGB(entry.peRed, entry.peGreen, entry.peBlue); entryPtr = Tcl_FindHashEntry(&cmap->refCounts, (CONST char *) cref); if (!entryPtr) { panic("Tried to free a color that isn't allocated."); } refCount = (int) Tcl_GetHashValue(entryPtr) - 1; if (refCount == 0) { count = cmap->size - index; entries = (PALETTEENTRY *) ckalloc(sizeof (PALETTEENTRY) * count); GetPaletteEntries(cmap->palette, index + 1, count, entries); SetPaletteEntries(cmap->palette, index, count, entries); SelectPalette(togl->tglGLHdc, cmap->palette, TRUE); RealizePalette(togl->tglGLHdc); ckfree((char *) entries); cmap->size--; Tcl_DeleteHashEntry(entryPtr); } else { Tcl_SetHashValue(entryPtr, (ClientData) refCount); } } static void Win32SetColor(const Togl *togl, unsigned long index, float red, float green, float blue) { TkWinColormap *cmap = (TkWinColormap *) Tk_Colormap(togl->TkWin); PALETTEENTRY entry; entry.peRed = (unsigned char) (red * 255 + .5); entry.peGreen = (unsigned char) (green * 255 + .5); entry.peBlue = (unsigned char) (blue * 255 + .5); entry.peFlags = 0; SetPaletteEntries(cmap->palette, index, 1, &entry); SelectPalette(togl->tglGLHdc, cmap->palette, TRUE); RealizePalette(togl->tglGLHdc); /* for color index mode photos */ togl->RedMap[index] = (GLfloat) (entry.peRed / 255.0); togl->GreenMap[index] = (GLfloat) (entry.peGreen / 255.0); togl->BlueMap[index] = (GLfloat) (entry.peBlue / 255.0); } #endif /* TOGL_X11 */ unsigned long Togl_AllocColor(const Togl *togl, float red, float green, float blue) { if (togl->RgbaFlag) { (void) fprintf(stderr, "Error: Togl_AllocColor illegal in RGBA mode.\n"); return 0; } /* TODO: maybe not... */ if (togl->PrivateCmapFlag) { (void) fprintf(stderr, "Error: Togl_AllocColor illegal with private colormap\n"); return 0; } #if defined(TOGL_X11) { XColor xcol; int exact; xcol.red = (short) (red * 65535.0); xcol.green = (short) (green * 65535.0); xcol.blue = (short) (blue * 65535.0); noFaultXAllocColor(Tk_Display(togl->TkWin), Tk_Colormap(togl->TkWin), Tk_Visual(togl->TkWin)->map_entries, &xcol, &exact); /* for color index mode photos */ togl->RedMap[xcol.pixel] = (float) xcol.red / 65535.0; togl->GreenMap[xcol.pixel] = (float) xcol.green / 65535.0; togl->BlueMap[xcol.pixel] = (float) xcol.blue / 65535.0; return xcol.pixel; } #elif defined(TOGL_WGL) return Win32AllocColor(togl, red, green, blue); #elif defined(TOGL_AGL) || defined(TOGL_NSOPENGL) /* still need to implement this on Mac... */ return 0; #endif } void Togl_FreeColor(const Togl *togl, unsigned long pixel) { if (togl->RgbaFlag) { (void) fprintf(stderr, "Error: Togl_FreeColor illegal in RGBA mode.\n"); return; } /* TODO: maybe not... */ if (togl->PrivateCmapFlag) { (void) fprintf(stderr, "Error: Togl_FreeColor illegal with private colormap\n"); return; } #if defined(TOGL_X11) (void) XFreeColors(Tk_Display(togl->TkWin), Tk_Colormap(togl->TkWin), &pixel, 1, 0); #elif defined(TOGL_WGL) Win32FreeColor(togl, pixel); #endif } void Togl_SetColor(const Togl *togl, unsigned long index, float red, float green, float blue) { if (togl->RgbaFlag) { (void) fprintf(stderr, "Error: Togl_SetColor illegal in RGBA mode.\n"); return; } if (!togl->PrivateCmapFlag) { (void) fprintf(stderr, "Error: Togl_SetColor requires a private colormap\n"); return; } #if defined(TOGL_X11) { XColor xcol; xcol.pixel = index; xcol.red = (short) (red * 65535.0); xcol.green = (short) (green * 65535.0); xcol.blue = (short) (blue * 65535.0); xcol.flags = DoRed | DoGreen | DoBlue; (void) XStoreColor(Tk_Display(togl->TkWin), Tk_Colormap(togl->TkWin), &xcol); /* for color index mode photos */ togl->RedMap[xcol.pixel] = (float) xcol.red / 65535.0; togl->GreenMap[xcol.pixel] = (float) xcol.green / 65535.0; togl->BlueMap[xcol.pixel] = (float) xcol.blue / 65535.0; } #elif defined(TOGL_WGL) Win32SetColor(togl, index, red, green, blue); #endif } #if TOGL_USE_FONTS == 1 # include "toglFont.c" #else Tcl_Obj * Togl_LoadBitmapFont(const Togl *togl, const char *fontname) { return NULL; } int Togl_UnloadBitmapFont(const Togl *togl, Tcl_Obj *bitmapfont) { return TCL_OK; } int Togl_WriteObj(const Togl *togl, const Tcl_Obj *toglfont, Tcl_Obj *obj) { return -1; } int Togl_WriteChars(const Togl *togl, const Tcl_Obj *toglfont, const char *str, int len) { return -1; } #endif /* TOGL_USE_FONTS */ /* * Overlay functions */ void Togl_UseLayer(Togl *togl, int layer) { if (layer == TOGL_NORMAL) { #if defined(TOGL_WGL) int res = wglMakeCurrent(togl->tglGLHdc, togl->Ctx); if (!res) { ErrorExit(TEXT("wglMakeCurrent")); } #elif defined(TOGL_X11) (void) glXMakeCurrent(Tk_Display(togl->TkWin), Tk_WindowId(togl->TkWin), togl->Ctx); #elif defined(TOGL_AGL) (void) aglSetCurrentContext(togl->Ctx); #elif defined(TOGL_NSOPENGL) [togl->Ctx makeCurrentContext]; #endif } else if (layer == TOGL_OVERLAY && togl->OverlayWindow) { #if defined(TOGL_WGL) int res = wglMakeCurrent(togl->tglGLHdc, togl->tglGLOverlayHglrc); if (!res) { ErrorExit(TEXT("wglMakeCurrent overlay")); } #elif defined(TOGL_X11) (void) glXMakeCurrent(Tk_Display(togl->TkWin), togl->OverlayWindow, togl->OverlayCtx); #elif defined(TOGL_AGL) || defined(TOGL_NSOPENGL) #endif } else { /* error */ } } void Togl_ShowOverlay(Togl *togl) { #if defined(TOGL_X11) /* not yet implemented on Windows */ if (togl->OverlayWindow) { (void) XMapWindow(Tk_Display(togl->TkWin), togl->OverlayWindow); (void) XInstallColormap(Tk_Display(togl->TkWin), togl->OverlayCmap); togl->OverlayIsMapped = True; } #endif } void Togl_HideOverlay(Togl *togl) { if (togl->OverlayWindow && togl->OverlayIsMapped) { (void) XUnmapWindow(Tk_Display(togl->TkWin), togl->OverlayWindow); togl->OverlayIsMapped = False; } } void Togl_PostOverlayRedisplay(Togl *togl) { if (!togl->OverlayUpdatePending && togl->OverlayWindow && togl->OverlayDisplayProc) { Tk_DoWhenIdle(Togl_RenderOverlay, (ClientData) togl); togl->OverlayUpdatePending = True; } } int Togl_ExistsOverlay(const Togl *togl) { return togl->OverlayFlag; } int Togl_GetOverlayTransparentValue(const Togl *togl) { return togl->OverlayTransparentPixel; } int Togl_IsMappedOverlay(const Togl *togl) { return togl->OverlayFlag && togl->OverlayIsMapped; } unsigned long Togl_AllocColorOverlay(const Togl *togl, float red, float green, float blue) { #if defined(TOGL_X11) /* not yet implemented on Windows */ if (togl->OverlayFlag && togl->OverlayCmap) { XColor xcol; xcol.red = (short) (red * 65535.0); xcol.green = (short) (green * 65535.0); xcol.blue = (short) (blue * 65535.0); if (!XAllocColor(Tk_Display(togl->TkWin), togl->OverlayCmap, &xcol)) return (unsigned long) -1; return xcol.pixel; } #endif /* TOGL_X11 */ return (unsigned long) -1; } void Togl_FreeColorOverlay(const Togl *togl, unsigned long pixel) { #if defined(TOGL_X11) /* not yet implemented on Windows */ if (togl->OverlayFlag && togl->OverlayCmap) { (void) XFreeColors(Tk_Display(togl->TkWin), togl->OverlayCmap, &pixel, 1, 0); } #endif /* TOGL_X11 */ } /* * User client data */ ClientData Togl_GetClientData(const Togl *togl) { return togl->Client_Data; } void Togl_SetClientData(Togl *togl, ClientData clientData) { togl->Client_Data = clientData; } int Togl_CopyContext(const Togl *from, const Togl *to, unsigned mask) { #ifdef TOGL_X11 int error_code; int same = (glXGetCurrentContext() == to->Ctx); if (same) (void) glXMakeCurrent(to->display, None, NULL); togl_SetupXErrorHandler(); glXCopyContext(from->display, from->Ctx, to->Ctx, mask); if (error_code = togl_CheckForXError(from)) { char buf[256]; XGetErrorText(from->display, error_code, buf, sizeof buf); Tcl_AppendResult(from->Interp, "unable to copy context: ", buf, NULL); return TCL_ERROR; } #elif defined(TOGL_WGL) int same = (wglGetCurrentContext() == to->Ctx); if (same) (void) wglMakeCurrent(to->tglGLHdc, NULL); if (!wglCopyContext(from->Ctx, to->Ctx, mask)) { char buf[256]; snprintf(buf, sizeof buf, "unable to copy context: %d", GetLastError()); Tcl_AppendElement(from->Interp, buf); return TCL_ERROR; } #elif defined(TOGL_AGL) int same = (aglGetCurrentContext() == to->Ctx); if (same) (void) aglSetCurrentContext(NULL); if (!aglCopyContext(from->Ctx, to->Ctx, mask)) { Tcl_AppendResult(from->Interp, "unable to copy context: ", aglErrorString(aglGetError()), NULL); return TCL_ERROR; } #elif defined(TOGL_NSOPENGL) int same = (from->Ctx == to->Ctx); if (same) { [NSOpenGLContext clearCurrentContext]; } [to->Ctx copyAttributesFromContext:from->Ctx withMask:mask]; #endif if (same) Togl_MakeCurrent(to); return TCL_OK; } #ifdef MESA_COLOR_HACK /* * Let's know how many free colors do we have */ # define RLEVELS 5 # define GLEVELS 9 # define BLEVELS 5 /* to free dithered_rgb_colormap pixels allocated by Mesa */ static unsigned long *ToglMesaUsedPixelCells = NULL; static int ToglMesaUsedFreeCells = 0; static int get_free_color_cells(Display *display, int screen, Colormap colormap) { if (!ToglMesaUsedPixelCells) { XColor xcol; int i; int colorsfailed, ncolors = XDisplayCells(display, screen); long r, g, b; ToglMesaUsedPixelCells = (unsigned long *) ckalloc(ncolors * sizeof (unsigned long)); /* Allocate X colors and initialize color_table[], red_table[], etc */ /* de Mesa 2.1: xmesa1.c setup_dithered_(...) */ i = colorsfailed = 0; for (r = 0; r < RLEVELS; r++) for (g = 0; g < GLEVELS; g++) for (b = 0; b < BLEVELS; b++) { int exact; xcol.red = (r * 65535) / (RLEVELS - 1); xcol.green = (g * 65535) / (GLEVELS - 1); xcol.blue = (b * 65535) / (BLEVELS - 1); noFaultXAllocColor(display, colormap, ncolors, &xcol, &exact); ToglMesaUsedPixelCells[i++] = xcol.pixel; if (!exact) { colorsfailed++; } } ToglMesaUsedFreeCells = i; XFreeColors(display, colormap, ToglMesaUsedPixelCells, ToglMesaUsedFreeCells, 0x00000000); } return ToglMesaUsedFreeCells; } static void free_default_color_cells(Display *display, Colormap colormap) { if (ToglMesaUsedPixelCells) { XFreeColors(display, colormap, ToglMesaUsedPixelCells, ToglMesaUsedFreeCells, 0x00000000); ckfree((char *) ToglMesaUsedPixelCells); ToglMesaUsedPixelCells = NULL; ToglMesaUsedFreeCells = 0; } } #endif /* * Original stereo code contributed by Ben Evans (Ben.Evans@anusf.anu.edu.au) * and was based on SGI's /usr/share/src/OpenGL/teach/stereo/glwstereo.c, * which is identical to the 1997/12/1 glwstereo.c code in the CrystalEyes * Software Development Kit. */ int Togl_NumEyes(const Togl *togl) { if (togl->Stereo > TOGL_STEREO_ONE_EYE_MAX) return 2; return 1; } /* call instead of glDrawBuffer */ void Togl_DrawBuffer(Togl *togl, GLenum mode) { if (togl->Stereo <= TOGL_STEREO_ONE_EYE_MAX) { /* Only drawing a single eye */ if (togl->currentStereoBuffer != STEREO_BUFFER_NONE) { Togl_SetViewPort(togl); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); togl->currentStereoBuffer = STEREO_BUFFER_NONE; } switch (mode) { case GL_FRONT: case GL_BACK: case GL_FRONT_AND_BACK: break; case GL_LEFT: case GL_FRONT_LEFT: case GL_RIGHT: case GL_FRONT_RIGHT: mode = GL_FRONT; break; case GL_BACK_LEFT: case GL_BACK_RIGHT: mode = GL_BACK; break; default: break; } glDrawBuffer(mode); return; } /* called once for each eye */ switch (mode) { case GL_FRONT: case GL_BACK: case GL_FRONT_AND_BACK: /* ** Simultaneous drawing to both left and right buffers isn't ** really possible if we don't have a stereo capable visual. ** For now just fall through and use the left buffer. */ case GL_LEFT: case GL_FRONT_LEFT: case GL_BACK_LEFT: togl->currentStereoBuffer = STEREO_BUFFER_LEFT; break; case GL_RIGHT: case GL_FRONT_RIGHT: case GL_BACK_RIGHT: togl->currentStereoBuffer = STEREO_BUFFER_RIGHT; break; default: break; } if (togl->Stereo != TOGL_STEREO_NATIVE) { switch (mode) { default: mode = GL_FRONT; break; case GL_BACK: case GL_BACK_LEFT: case GL_BACK_RIGHT: mode = GL_BACK; break; } } int w = togl->Width*togl->PixelScale, h = togl->Height*togl->PixelScale; switch (togl->Stereo) { default: break; #ifdef __sgi case TOGL_STEREO_SGIOLDSTYLE: glXWaitGL(); /* sync with GL command stream before calling X */ XSGISetStereoBuffer(togl->display, Tk_WindowId(togl->TkWin), togl->currentStereoBuffer); glXWaitX(); /* sync with X command stream before calling GL */ break; #endif case TOGL_STEREO_ANAGLYPH: if (togl->currentStereoBuffer == STEREO_BUFFER_LEFT) glColorMask(GL_TRUE, GL_FALSE, GL_FALSE, GL_TRUE); else glColorMask(GL_FALSE, GL_TRUE, GL_TRUE, GL_TRUE); glViewport(0, 0, w, h); break; case TOGL_STEREO_CROSS_EYE: if (togl->currentStereoBuffer == STEREO_BUFFER_LEFT) glViewport(w / 2 + 1, 0, w / 2, h); else glViewport(0, 0, w / 2, h); break; case TOGL_STEREO_WALL_EYE: if (togl->currentStereoBuffer == STEREO_BUFFER_LEFT) glViewport(0, 0, w / 2, h); else glViewport(w / 2 + 1, 0, w / 2, h); break; case TOGL_STEREO_DTI: if (togl->currentStereoBuffer == STEREO_BUFFER_LEFT) glViewport(0, 0, w / 2, h); else glViewport(w / 2 + 1, 0, w / 2, h); break; case TOGL_STEREO_ROW_INTERLEAVED: glViewport(0, 0, w, h); break; } glDrawBuffer(mode); } /* call instead of glClear */ void Togl_Clear(const Togl *togl, GLbitfield mask) { GLint stencil_write_mask = 0; GLint stencil_clear_value = 0; switch (togl->Stereo) { default: break; case TOGL_STEREO_CROSS_EYE: case TOGL_STEREO_WALL_EYE: case TOGL_STEREO_DTI: if (togl->currentStereoBuffer != STEREO_BUFFER_LEFT) { /* Since glViewport does not affect what is cleared (unlike * glScissor), only clear in left eye */ return; } break; case TOGL_STEREO_ROW_INTERLEAVED: if (togl->currentStereoBuffer == STEREO_BUFFER_LEFT) { if ((mask & GL_STENCIL_BUFFER_BIT) == 0) { mask |= GL_STENCIL_BUFFER_BIT; glStencilMask(~0u); glClearStencil(0); } else { glGetIntegerv(GL_STENCIL_WRITEMASK, &stencil_write_mask); glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &stencil_clear_value); glStencilMask(stencil_write_mask | togl->riStencilBit); glClearStencil(stencil_clear_value & ~togl->riStencilBit); } } else { mask &= ~(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } break; } #if 0 /* only needed if we wish to support multi-eye clears */ if (togl->Stereo > TOGL_STEREO_ONE_EYE_MAX) { GLenum drawBuffer = togl->currentDrawBuffer; switch (drawBuffer) { case GL_FRONT: Togl_DrawBuffer(togl, GL_FRONT_RIGHT); glClear(mask); Togl_DrawBuffer(togl, drawBuffer); break; case GL_BACK: Togl_DrawBuffer(togl, GL_BACK_RIGHT); glClear(mask); Togl_DrawBuffer(togl, drawBuffer); break; case GL_FRONT_AND_BACK: Togl_DrawBuffer(togl, GL_RIGHT); glClear(mask); Togl_DrawBuffer(togl, drawBuffer); break; case GL_LEFT: case GL_FRONT_LEFT: case GL_BACK_LEFT: case GL_RIGHT: case GL_FRONT_RIGHT: case GL_BACK_RIGHT: default: break; } } #endif if (mask != 0) glClear(mask); if (togl->Stereo == TOGL_STEREO_ROW_INTERLEAVED) { int x, y; if (togl->currentStereoBuffer == STEREO_BUFFER_LEFT) { int i; /* initialize stencil buffer mask */ glPushAttrib(GL_COLOR_BUFFER_BIT | GL_ENABLE_BIT | GL_LINE_BIT | GL_VIEWPORT_BIT); // 2d projection Togl_SetViewPort(togl); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glOrtho(0, togl->Width, 0, togl->Height, -1, 1); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); glTranslatef(0.375f, 0.375f, 0); glDisable(GL_ALPHA_TEST); glDisable(GL_COLOR_LOGIC_OP); glDisable(GL_DEPTH_TEST); glDisable(GL_DITHER); glDisable(GL_INDEX_LOGIC_OP); glDisable(GL_LIGHTING); glDisable(GL_LINE_SMOOTH); glDisable(GL_MULTISAMPLE); glLineWidth(1); glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); glStencilFunc(GL_ALWAYS, togl->riStencilBit, togl->riStencilBit); glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE); glBegin(GL_LINES); for (i = 0; i < togl->Height; i += 2) { glVertex2i(0, i); glVertex2i(togl->Width, i); } glEnd(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); glPopAttrib(); if (stencil_write_mask) { glStencilMask(stencil_write_mask & ~togl->riStencilBit); } else { glStencilMask(~togl->riStencilBit); } Tk_GetRootCoords(togl->TkWin, &x, &y); if ((y + togl->Height) % 2) { glStencilFunc(GL_NOTEQUAL, togl->riStencilBit, togl->riStencilBit); } else { glStencilFunc(GL_EQUAL, togl->riStencilBit, togl->riStencilBit); } } else { Tk_GetRootCoords(togl->TkWin, &x, &y); if ((y + togl->Height) % 2) { glStencilFunc(GL_EQUAL, togl->riStencilBit, togl->riStencilBit); } else { glStencilFunc(GL_NOTEQUAL, togl->riStencilBit, togl->riStencilBit); } } } } /* * Togl_Frustum and Togl_Ortho: * * eyeOffset is the distance from the center line * and is negative for the left eye and positive for right eye. * eyeDist and eyeOffset need to be in the same units as your model space. * In physical space, eyeDist might be 30 inches from the screen * and eyeDist would be +/- 1.25 inch (for a total interocular distance * of 2.5 inches). */ void Togl_Frustum(const Togl *togl, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar) { GLdouble eyeOffset = 0, eyeShift = 0; if (togl->Stereo == TOGL_STEREO_LEFT_EYE || togl->currentStereoBuffer == STEREO_BUFFER_LEFT) eyeOffset = -togl->EyeSeparation / 2; /* for left eye */ else if (togl->Stereo == TOGL_STEREO_RIGHT_EYE || togl->currentStereoBuffer == STEREO_BUFFER_RIGHT) eyeOffset = togl->EyeSeparation / 2; /* for right eye */ eyeShift = (togl->Convergence - zNear) * (eyeOffset / togl->Convergence); /* compensate for altered viewports */ switch (togl->Stereo) { default: break; case TOGL_STEREO_SGIOLDSTYLE: case TOGL_STEREO_DTI: /* squished image is expanded, nothing needed */ break; case TOGL_STEREO_CROSS_EYE: case TOGL_STEREO_WALL_EYE:{ GLdouble delta = (top - bottom) / 2; top += delta; bottom -= delta; break; } } glFrustum(left + eyeShift, right + eyeShift, bottom, top, zNear, zFar); glTranslated(-eyeShift, 0, 0); } void Togl_Ortho(const Togl *togl, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar) { /* TODO: debug this */ GLdouble eyeOffset = 0, eyeShift = 0; if (togl->currentStereoBuffer == STEREO_BUFFER_LEFT) eyeOffset = -togl->EyeSeparation / 2; /* for left eye */ else if (togl->currentStereoBuffer == STEREO_BUFFER_RIGHT) eyeOffset = togl->EyeSeparation / 2; /* for right eye */ eyeShift = (togl->Convergence - zNear) * (eyeOffset / togl->Convergence); /* compensate for altered viewports */ switch (togl->Stereo) { default: break; case TOGL_STEREO_SGIOLDSTYLE: case TOGL_STEREO_DTI: /* squished image is expanded, nothing needed */ break; case TOGL_STEREO_CROSS_EYE: case TOGL_STEREO_WALL_EYE:{ GLdouble delta = (top - bottom) / 2; top += delta; bottom -= delta; break; } } glOrtho(left + eyeShift, right + eyeShift, bottom, top, zNear, zFar); glTranslated(-eyeShift, 0, 0); } int Togl_GetToglFromObj(Tcl_Interp *interp, Tcl_Obj *obj, Togl **toglPtr) { Tcl_Command toglCmd; Tcl_CmdInfo info; toglCmd = Tcl_GetCommandFromObj(interp, obj); if (Tcl_GetCommandInfoFromToken(toglCmd, &info) == 0 || info.objProc != Togl_ObjWidget) { Tcl_AppendResult(interp, "expected togl command argument", NULL); return TCL_ERROR; } *toglPtr = (Togl *) info.objClientData; return TCL_OK; } int Togl_GetToglFromName(Tcl_Interp *interp, const char *cmdName, Togl **toglPtr) { Tcl_CmdInfo info; if (Tcl_GetCommandInfo(interp, cmdName, &info) == 0 || info.objProc != Togl_ObjWidget) { Tcl_AppendResult(interp, "expected togl command argument", NULL); return TCL_ERROR; } *toglPtr = (Togl *) info.objClientData; return TCL_OK; } static int ObjectIsEmpty(Tcl_Obj *objPtr); /* *---------------------------------------------------------------------- * * GetStereo - * * Converts an internal int into a Tcl string obj. * * Results: * Tcl_Obj containing the string representation of the stereo value. * * Side effects: * Creates a new Tcl_Obj. * *---------------------------------------------------------------------- */ static Tcl_Obj * GetStereo(ClientData clientData, Tk_Window tkwin, char *recordPtr, int internalOffset) /* recordPtr is a pointer to widget record. */ /* internalOffset is the offset within *recordPtr containing the stereo * value. */ { int stereo = *(int *) (recordPtr + internalOffset); const char *name = "unknown"; switch (stereo) { case TOGL_STEREO_NONE: name = ""; break; case TOGL_STEREO_LEFT_EYE: name = "left eye"; break; case TOGL_STEREO_RIGHT_EYE: name = "right eye"; break; case TOGL_STEREO_NATIVE: name = "native"; break; case TOGL_STEREO_SGIOLDSTYLE: name = "sgioldstyle"; break; case TOGL_STEREO_ANAGLYPH: name = "anaglyph"; break; case TOGL_STEREO_CROSS_EYE: name = "cross-eye"; break; case TOGL_STEREO_WALL_EYE: name = "wall-eye"; break; case TOGL_STEREO_DTI: name = "dti"; break; case TOGL_STEREO_ROW_INTERLEAVED: name = "row interleaved"; break; } return Tcl_NewStringObj(name, -1); } /* *---------------------------------------------------------------------- * * SetStereo -- * * Converts a Tcl_Obj representing a widgets stereo into an * integer value. * * Results: * Standard Tcl result. * * Side effects: * May store the integer value into the internal representation * pointer. May change the pointer to the Tcl_Obj to NULL to indicate * that the specified string was empty and that is acceptable. * *---------------------------------------------------------------------- */ static int SetStereo(ClientData clientData, Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj **value, char *recordPtr, int internalOffset, char *oldInternalPtr, int flags) /* interp is the current interp; may be used for errors. */ /* tkwin is the Window for which option is being set. */ /* value is a pointer to the pointer to the value object. We use a pointer * to the pointer because we may need to return a value (NULL). */ /* recordPtr is a pointer to storage for the widget record. */ /* internalOffset is the offset within *recordPtr at which the internal * value is to be stored. */ /* oldInternalPtr is a pointer to storage for the old value. */ /* flags are the flags for the option, set Tk_SetOptions. */ { int stereo = 0; char *string, *internalPtr; internalPtr = (internalOffset > 0) ? recordPtr + internalOffset : NULL; if ((flags & TK_OPTION_NULL_OK) && ObjectIsEmpty(*value)) { *value = NULL; } else { /* * Convert the stereo specifier into an integer value. */ if (Tcl_GetBooleanFromObj(NULL, *value, &stereo) == TCL_OK) { stereo = stereo ? TOGL_STEREO_NATIVE : TOGL_STEREO_NONE; } else { string = Tcl_GetString(*value); if (strcmp(string, "") == 0 || strcasecmp(string, "none") == 0) { stereo = TOGL_STEREO_NONE; } else if (strcasecmp(string, "native") == 0) { stereo = TOGL_STEREO_NATIVE; /* check if available when creating visual */ } else if (strcasecmp(string, "left eye") == 0) { stereo = TOGL_STEREO_LEFT_EYE; } else if (strcasecmp(string, "right eye") == 0) { stereo = TOGL_STEREO_RIGHT_EYE; } else if (strcasecmp(string, "sgioldstyle") == 0) { stereo = TOGL_STEREO_SGIOLDSTYLE; } else if (strcasecmp(string, "anaglyph") == 0) { stereo = TOGL_STEREO_ANAGLYPH; } else if (strcasecmp(string, "cross-eye") == 0) { stereo = TOGL_STEREO_CROSS_EYE; } else if (strcasecmp(string, "wall-eye") == 0) { stereo = TOGL_STEREO_WALL_EYE; } else if (strcasecmp(string, "dti") == 0) { stereo = TOGL_STEREO_DTI; } else if (strcasecmp(string, "row interleaved") == 0) { stereo = TOGL_STEREO_ROW_INTERLEAVED; } else { Tcl_ResetResult(interp); Tcl_AppendResult(interp, "bad stereo value \"", Tcl_GetString(*value), "\"", NULL); return TCL_ERROR; } } } if (internalPtr != NULL) { *((int *) oldInternalPtr) = *((int *) internalPtr); *((int *) internalPtr) = stereo; } return TCL_OK; } /* *---------------------------------------------------------------------- * RestoreStereo -- * * Restore a stereo option value from a saved value. * * Results: * None. * * Side effects: * Restores the old value. * *---------------------------------------------------------------------- */ static void RestoreStereo(ClientData clientData, Tk_Window tkwin, char *internalPtr, char *oldInternalPtr) { *(int *) internalPtr = *(int *) oldInternalPtr; } /* *---------------------------------------------------------------------- * * GetWideInt - * * Converts an internal wide integer into a Tcl WideInt obj. * * Results: * Tcl_Obj containing the wide int value. * * Side effects: * Creates a new Tcl_Obj. * *---------------------------------------------------------------------- */ static Tcl_Obj * GetWideInt(ClientData clientData, Tk_Window tkwin, char *recordPtr, int internalOffset) /* recordPtr is a pointer to widget record. */ /* internalOffset is the offset within *recordPtr containing the wide int * value. */ { Tcl_WideInt wi = *(Tcl_WideInt *) (recordPtr + internalOffset); return Tcl_NewWideIntObj(wi); } /* *---------------------------------------------------------------------- * * SetWideInt -- * * Converts a Tcl_Obj representing a Tcl_WideInt. * * Results: * Standard Tcl result. * * Side effects: * May store the wide int value into the internal representation * pointer. May change the pointer to the Tcl_Obj to NULL to indicate * that the specified string was empty and that is acceptable. * *---------------------------------------------------------------------- */ static int SetWideInt(ClientData clientData, Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj **value, char *recordPtr, int internalOffset, char *oldInternalPtr, int flags) /* interp is the current interp; may be used for errors. */ /* tkwin is the Window for which option is being set. */ /* value is a pointer to the pointer to the value object. We use a pointer * to the pointer because we may need to return a value (NULL). */ /* recordPtr is a pointer to storage for the widget record. */ /* internalOffset is the offset within *recordPtr at which the internal * value is to be stored. */ /* oldInternalPtr is a pointer to storage for the old value. */ /* flags are the flags for the option, set Tk_SetOptions. */ { char *internalPtr; Tcl_WideInt w; internalPtr = (internalOffset > 0) ? recordPtr + internalOffset : NULL; if ((flags & TK_OPTION_NULL_OK) && ObjectIsEmpty(*value)) { *value = NULL; w = 0; } else { if (Tcl_GetWideIntFromObj(interp, *value, &w) != TCL_OK) { return TCL_ERROR; } } if (internalPtr != NULL) { *((Tcl_WideInt *) oldInternalPtr) = *((Tcl_WideInt *) internalPtr); *((Tcl_WideInt *) internalPtr) = w; } return TCL_OK; } /* *---------------------------------------------------------------------- * RestoreWideInt -- * * Restore a wide int option value from a saved value. * * Results: * None. * * Side effects: * Restores the old value. * *---------------------------------------------------------------------- */ static void RestoreWideInt(ClientData clientData, Tk_Window tkwin, char *internalPtr, char *oldInternalPtr) { *(Tcl_WideInt *) internalPtr = *(Tcl_WideInt *) oldInternalPtr; } /* *---------------------------------------------------------------------- * * ObjectIsEmpty -- * * This procedure tests whether the string value of an object is * empty. * * Results: * The return value is 1 if the string value of objPtr has length * zero, and 0 otherwise. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int ObjectIsEmpty(Tcl_Obj *objPtr) /* objPtr = Object to test. May be NULL. */ { int length; if (objPtr == NULL) { return 1; } if (objPtr->bytes != NULL) { return (objPtr->length == 0); } Tcl_GetStringFromObj(objPtr, &length); return (length == 0); } ================================================ FILE: ng/Togl2.1/togl.decls ================================================ library togl interface togl # Declare each of the functions in the public Togl interface. Note that # the an index should never be reused for a different function in order # to preserve backwards compatibility. # package initialization declare 0 generic { int Togl_Init(Tcl_Interp *interp) } # Miscellaneous declare 1 generic { void Togl_MakeCurrent(const Togl *togl) } declare 2 generic { void Togl_PostRedisplay(Togl *togl) } declare 3 generic { void Togl_SwapBuffers(const Togl *togl) } declare 33 generic { Bool Togl_SwapInterval(const Togl *togl, int interval) } declare 48 generic { int Togl_CopyContext(const Togl *from, const Togl *to, unsigned int mask) } # Query functions declare 4 generic { const char *Togl_Ident(const Togl *togl) } declare 5 generic { int Togl_Width(const Togl *togl) } declare 6 generic { int Togl_Height(const Togl *togl) } declare 7 generic { Tcl_Interp *Togl_Interp(const Togl *togl) } declare 8 generic { Tk_Window Togl_TkWin(const Togl *togl) } declare 9 generic { const char *Togl_CommandName(const Togl *togl) } declare 36 generic { int Togl_ContextTag(const Togl *togl) } declare 37 generic { Bool Togl_UpdatePending(const Togl *togl) } declare 40 generic { Bool Togl_HasRGBA(const Togl *togl) } declare 41 generic { Bool Togl_IsDoubleBuffered(const Togl *togl) } declare 42 generic { Bool Togl_HasDepthBuffer(const Togl *togl) } declare 43 generic { Bool Togl_HasAccumulationBuffer(const Togl *togl) } declare 44 generic { Bool Togl_HasDestinationAlpha(const Togl *togl) } declare 45 generic { Bool Togl_HasStencilBuffer(const Togl *togl) } declare 46 generic { int Togl_StereoMode(const Togl *togl) } declare 47 generic { Bool Togl_HasMultisample(const Togl *togl) } declare 49 generic { int Togl_PixelScale(const Togl *togl) } # Color Index mode declare 10 generic { unsigned long Togl_AllocColor(const Togl *togl, float red, float green, float blue) } declare 11 generic { void Togl_FreeColor(const Togl *togl, unsigned long index) } declare 12 generic { void Togl_SetColor(const Togl *togl, unsigned long index, float red, float green, float blue) } # Bitmap fonts declare 13 generic { Tcl_Obj *Togl_LoadBitmapFont(const Togl *togl, const char *fontname) } declare 14 generic { int Togl_UnloadBitmapFont(const Togl *togl, Tcl_Obj *toglfont) } declare 38 generic { int Togl_WriteObj(const Togl *togl, const Tcl_Obj *toglfont, Tcl_Obj *obj) } declare 39 generic { int Togl_WriteChars(const Togl *togl, const Tcl_Obj *toglfont, const char *str, int len) } # Overlay functions declare 15 generic { void Togl_UseLayer(Togl *togl, int layer) } declare 16 generic { void Togl_ShowOverlay(Togl *togl) } declare 17 generic { void Togl_HideOverlay(Togl *togl) } declare 18 generic { void Togl_PostOverlayRedisplay(Togl *togl) } declare 19 generic { int Togl_ExistsOverlay(const Togl *togl) } declare 20 generic { int Togl_GetOverlayTransparentValue(const Togl *togl) } declare 21 generic { int Togl_IsMappedOverlay(const Togl *togl) } declare 22 generic { unsigned long Togl_AllocColorOverlay(const Togl *togl, float red, float green, float blue) } declare 23 generic { void Togl_FreeColorOverlay(const Togl *togl, unsigned long index) } # User client data declare 24 generic { ClientData Togl_GetClientData(const Togl *togl) } declare 25 generic { void Togl_SetClientData(Togl *togl, ClientData clientData) } # Stereo support declare 26 generic { void Togl_DrawBuffer(Togl *togl, GLenum mode) } declare 27 generic { void Togl_Clear(const Togl *togl, GLbitfield mask) } declare 28 generic { void Togl_Frustum(const Togl *togl, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near, GLdouble far) } declare 34 generic { void Togl_Ortho(const Togl *togl, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near, GLdouble far) } declare 35 generic { int Togl_NumEyes(const Togl *togl) } # save current contents of OpenGL window into photo image declare 30 generic { int Togl_TakePhoto(Togl *togl, Tk_PhotoHandle photo) } # platform-independent lookup of OpenGL functions declare 31 generic { Togl_FuncPtr Togl_GetProcAddr(const char *funcname) } # Return the Togl data associated with pathName declare 29 generic { int Togl_GetToglFromObj(Tcl_Interp *interp, Tcl_Obj *obj, Togl **toglPtr) } declare 32 generic { int Togl_GetToglFromName(Tcl_Interp *interp, const char *cmdName, Togl **toglPtr) } ================================================ FILE: ng/Togl2.1/togl.h ================================================ /* $Id: togl.h,v 1.39 2009/03/31 23:21:13 gregcouch Exp $ */ /* vi:set sw=4: */ /* * Togl - a Tk OpenGL widget * * Copyright (C) 1996-2002 Brian Paul and Ben Bederson * Copyright (C) 2005-2009 Greg Couch * See the LICENSE file for copyright details. */ #ifndef TOGL_H # define TOGL_H //# include "togl_ws.h" # ifdef TOGL_WGL # define WIN32_LEAN_AND_MEAN # include # undef WIN32_LEAN_AND_MEAN # if defined(_MSC_VER) # define DllEntryPoint DllMain # endif # endif # if defined(TOGL_AGL) || defined(TOGL_NSOPENGL) # ifndef MAC_OSX_TCL # define MAC_OSX_TCL 1 # endif # ifndef MAC_OSX_TK # define MAC_OSX_TK 1 # endif # endif # ifdef USE_TOGL_STUBS # ifndef USE_TCL_STUBS # define USE_TCL_STUBS # endif # ifndef USE_TK_STUBS # define USE_TK_STUBS # endif # endif # include # include # if defined(TOGL_AGL) # include # elif defined(TOGL_NSOPENGL) #define GL_SILENCE_DEPRECATION # include # include # else # include # endif # ifdef BUILD_togl # undef TCL_STORAGE_CLASS # define TCL_STORAGE_CLASS DLLEXPORT # endif # ifndef CONST84 # define CONST84 # endif # ifndef NULL # define NULL 0 # endif # ifndef EXTERN # define EXTERN extern # endif # ifdef __cplusplus /* *INDENT-OFF* */ extern "C" { /* *INDENT-ON* */ # endif # define TOGL_VERSION "2.1" # define TOGL_MAJOR_VERSION 2 # define TOGL_MINOR_VERSION 1 /* * "Standard" fonts which can be specified to Togl_LoadBitmapFont() * Deprecated. Use the Tk font name or description instead. */ # define TOGL_BITMAP_8_BY_13 "8x13" # define TOGL_BITMAP_9_BY_15 "9x15" # define TOGL_BITMAP_TIMES_ROMAN_10 "Times 10" # define TOGL_BITMAP_TIMES_ROMAN_24 "Times 24" # define TOGL_BITMAP_HELVETICA_10 "Helvetica 10" # define TOGL_BITMAP_HELVETICA_12 "Helvetica 12" # define TOGL_BITMAP_HELVETICA_18 "Helvetica 18" /* * Normal and overlay plane constants */ # define TOGL_NORMAL 1 # define TOGL_OVERLAY 2 /* * Stereo techniques: * Only the native method uses OpenGL quad-buffered stereo. * All need the eye offset and eye distance set properly. */ /* These versions need one eye drawn */ # define TOGL_STEREO_NONE 0 # define TOGL_STEREO_LEFT_EYE 1 /* just the left eye */ # define TOGL_STEREO_RIGHT_EYE 2 /* just the right eye */ # define TOGL_STEREO_ONE_EYE_MAX 127 /* These versions need both eyes drawn */ # define TOGL_STEREO_NATIVE 128 # define TOGL_STEREO_SGIOLDSTYLE 129 /* interlaced, SGI API */ # define TOGL_STEREO_ANAGLYPH 130 # define TOGL_STEREO_CROSS_EYE 131 # define TOGL_STEREO_WALL_EYE 132 # define TOGL_STEREO_DTI 133 /* dti3d.com */ # define TOGL_STEREO_ROW_INTERLEAVED 134 /* www.vrex.com/developer/interleave.htm */ struct Togl; typedef struct Togl Togl; typedef void (*Togl_FuncPtr) (); const char *Togl_InitStubs _ANSI_ARGS_((Tcl_Interp *interp, const char *version, int exact)); # ifndef USE_TOGL_STUBS # define Togl_InitStubs(interp, version, exact) \ Tcl_PkgRequire(interp, "Togl", version, exact) # endif /* * Platform independent exported functions */ # include "toglDecls.h" # ifdef __cplusplus /* *INDENT-OFF* */ } /* *INDENT-ON* */ # endif #endif ================================================ FILE: ng/Togl2.1/toglAGL.c ================================================ /* $Id: toglAGL.c,v 1.7 2009/10/22 00:06:41 gregcouch Exp $ */ /* vi:set sw=4 expandtab: */ /* * Togl - a Tk OpenGL widget * * Copyright (C) 1996-2002 Brian Paul and Ben Bederson * Copyright (C) 2005-2009 Greg Couch * See the LICENSE file for copyright details. */ struct FBInfo { GLint acceleration; GLint colors; GLint depth; GLint samples; AGLPixelFormat pix; }; typedef struct FBInfo FBInfo; static int FBInfoCmp(const void *a, const void *b) { /* * 1. full acceleration is better * 2. greater color bits is better * 3. greater depth bits is better * 4. more multisampling is better */ const FBInfo *x = (const FBInfo *) a; const FBInfo *y = (const FBInfo *) b; if (x->acceleration != y->acceleration) return y->acceleration - x->acceleration; if (x->colors != y->colors) return y->colors - x->colors; if (x->depth != y->depth) return y->depth - x->depth; if (x->samples != y->samples) return y->samples - x->samples; return 0; } static AGLPixelFormat togl_pixelFormat(Togl *togl) { GLint attribs[32]; int na = 0; AGLPixelFormat pix; GDHandle display = NULL; FBInfo *info = NULL; int count; #if 0 if (togl->MultisampleFlag && !hasMultisampling) { Tcl_SetResult(togl->Interp, TCL_STUPID "multisampling not supported", TCL_STATIC); return NULL; } #endif if (togl->PbufferFlag && !togl->RgbaFlag) { Tcl_SetResult(togl->Interp, TCL_STUPID "puffer must be RGB[A]", TCL_STATIC); return NULL; } attribs[na++] = AGL_MINIMUM_POLICY; /* ask for hardware-accelerated onscreen */ attribs[na++] = AGL_ACCELERATED; attribs[na++] = AGL_NO_RECOVERY; if (togl->RgbaFlag) { /* RGB[A] mode */ attribs[na++] = AGL_RGBA; attribs[na++] = AGL_RED_SIZE; attribs[na++] = togl->RgbaRed; attribs[na++] = AGL_GREEN_SIZE; attribs[na++] = togl->RgbaGreen; attribs[na++] = AGL_BLUE_SIZE; attribs[na++] = togl->RgbaBlue; if (togl->AlphaFlag) { attribs[na++] = AGL_ALPHA_SIZE; attribs[na++] = togl->AlphaSize; } } else { /* Color index mode */ attribs[na++] = AGL_BUFFER_SIZE; attribs[na++] = 8; } if (togl->DepthFlag) { attribs[na++] = AGL_DEPTH_SIZE; attribs[na++] = togl->DepthSize; } if (togl->DoubleFlag) { attribs[na++] = AGL_DOUBLEBUFFER; } if (togl->StencilFlag) { attribs[na++] = AGL_STENCIL_SIZE; attribs[na++] = togl->StencilSize; } if (togl->AccumFlag) { attribs[na++] = AGL_ACCUM_RED_SIZE; attribs[na++] = togl->AccumRed; attribs[na++] = AGL_ACCUM_GREEN_SIZE; attribs[na++] = togl->AccumGreen; attribs[na++] = AGL_ACCUM_BLUE_SIZE; attribs[na++] = togl->AccumBlue; if (togl->AlphaFlag) { attribs[na++] = AGL_ACCUM_ALPHA_SIZE; attribs[na++] = togl->AccumAlpha; } } if (togl->MultisampleFlag) { attribs[na++] = AGL_MULTISAMPLE; #ifdef AGL_SAMPLES_ARB /* OS X 10.2 and later */ attribs[na++] = AGL_SAMPLE_BUFFERS_ARB; attribs[na++] = 1; attribs[na++] = AGL_SAMPLES_ARB; attribs[na++] = 2; #endif } if (togl->AuxNumber != 0) { attribs[na++] = AGL_AUX_BUFFERS; attribs[na++] = togl->AuxNumber; } if (togl->Stereo == TOGL_STEREO_NATIVE) { attribs[na++] = AGL_STEREO; } if (togl->FullscreenFlag) { attribs[na++] = AGL_FULLSCREEN; /* TODO: convert Tk screen to display device */ display = GetMainDevice(); } attribs[na++] = AGL_NONE; if ((pix = aglChoosePixelFormat(&display, togl->FullscreenFlag ? 1 : 0, attribs)) == NULL) { Tcl_SetResult(togl->Interp, TCL_STUPID "couldn't choose pixel format", TCL_STATIC); return NULL; } /* TODO: since we aglDestroyPixelFormat elsewhere, this code may leak * memory if the pixel format chosen is not the original (because * aglDestroyPixelFormat will give an error). */ count = 0; do { info = (FBInfo *) realloc(info, (count + 1) * sizeof (FBInfo)); info[count].pix = pix; aglDescribePixelFormat(pix, AGL_ACCELERATED, &info[count].acceleration); aglDescribePixelFormat(pix, AGL_BUFFER_SIZE, &info[count].colors); aglDescribePixelFormat(pix, AGL_DEPTH_SIZE, &info[count].depth); #ifdef AGL_SAMPLES_ARB aglDescribePixelFormat(pix, AGL_SAMPLES_ARB, &info[count].samples); #else info[count].samples = 0; #endif ++count; } while (pix = aglNextPixelFormat(pix)); qsort(info, count, sizeof info[0], FBInfoCmp); pix = info[0].pix; free(info); return pix; } static int togl_describePixelFormat(Togl *togl) { AGLPixelFormat pixelformat; /* fill in RgbaFlag, DoubleFlag, and Stereo */ pixelformat = (AGLPixelFormat) togl->PixelFormat; GLint has_rgba, has_doublebuf, has_depth, has_accum, has_alpha, has_stencil, has_stereo, has_multisample; if (aglDescribePixelFormat(pixelformat, AGL_RGBA, &has_rgba) && aglDescribePixelFormat(pixelformat, AGL_DOUBLEBUFFER, &has_doublebuf) && aglDescribePixelFormat(pixelformat, AGL_DEPTH_SIZE, &has_depth) && aglDescribePixelFormat(pixelformat, AGL_ACCUM_RED_SIZE, &has_accum) && aglDescribePixelFormat(pixelformat, AGL_ALPHA_SIZE, &has_alpha) && aglDescribePixelFormat(pixelformat, AGL_STENCIL_SIZE, &has_stencil) && aglDescribePixelFormat(pixelformat, AGL_STEREO, &has_stereo) #ifdef AGL_SAMPLES_ARB && aglDescribePixelFormat(pixelformat, AGL_SAMPLES_ARB, &has_multisample) #endif ) { togl->RgbaFlag = (has_rgba != 0); togl->DoubleFlag = (has_doublebuf != 0); togl->DepthFlag = (has_depth != 0); togl->AccumFlag = (has_accum != 0); togl->AlphaFlag = (has_alpha != 0); togl->StencilFlag = (has_stencil != 0); togl->Stereo = (has_stereo ? TOGL_STEREO_NATIVE : TOGL_STEREO_NONE); #ifdef AGL_SAMPLES_ARB togl->MultisampleFlag = (has_multisample != 0); #else togl->MultisampleFlag = False; #endif return True; } else { Tcl_SetResult(togl->Interp, TCL_STUPID "failed querying pixel format attributes", TCL_STATIC); return False; } } #define isPow2(x) (((x) & ((x) - 1)) == 0) static AGLPbuffer togl_createPbuffer(Togl *togl) { GLint min_size[2], max_size[2]; Bool hasPbuffer; const char *extensions; GLboolean good; GLint target; GLint virtualScreen; AGLPbuffer pbuf; extensions = (const char *) glGetString(GL_EXTENSIONS); hasPbuffer = (strstr(extensions, "GL_APPLE_pixel_buffer") != NULL); if (!hasPbuffer) { Tcl_SetResult(togl->Interp, TCL_STUPID "pbuffers are not supported", TCL_STATIC); return NULL; } glGetIntegerv(GL_MIN_PBUFFER_VIEWPORT_DIMS_APPLE, min_size); glGetIntegerv(GL_MAX_VIEWPORT_DIMS, max_size); virtualScreen = aglGetVirtualScreen(togl->Ctx); for (;;) { /* make sure we don't exceed the maximum size because if we do, * aglCreatePbuffer may succeed and later uses of the pbuffer fail */ if (togl->Width < min_size[0]) togl->Width = min_size[0]; else if (togl->Width > max_size[0]) { if (togl->LargestPbufferFlag) togl->Width = max_size[0]; else { Tcl_SetResult(togl->Interp, TCL_STUPID "pbuffer too large", TCL_STATIC); return NULL; } } if (togl->Height < min_size[1]) togl->Height = min_size[1]; else if (togl->Height > max_size[1]) { if (togl->LargestPbufferFlag) togl->Height = max_size[1]; else { Tcl_SetResult(togl->Interp, TCL_STUPID "pbuffer too large", TCL_STATIC); return NULL; } } if (isPow2(togl->Width) && isPow2(togl->Height)) target = GL_TEXTURE_2D; else target = GL_TEXTURE_RECTANGLE_ARB; good = aglCreatePBuffer(togl->Width, togl->Height, target, togl->AlphaFlag ? GL_RGBA : GL_RGB, 0, &pbuf); if (good) { /* aglSetPbuffer allocates the framebuffer space */ if (aglSetPBuffer(togl->Ctx, pbuf, 0, 0, virtualScreen)) { return pbuf; } } if (!togl->LargestPbufferFlag || togl->Width == min_size[0] || togl->Height == min_size[1]) { Tcl_SetResult(togl->Interp, TCL_STUPID "unable to create pbuffer", TCL_STATIC); return NULL; } /* largest unavailable, try something smaller */ togl->Width = togl->Width / 2 + togl->Width % 2; togl->Height = togl->Width / 2 + togl->Height % 2; } } static void togl_destroyPbuffer(Togl *togl) { aglDestroyPBuffer(togl->pbuf); } ================================================ FILE: ng/Togl2.1/toglDecls.h ================================================ #ifndef ToglDecls_H # define ToglDecls_H /* * Togl - a Tk OpenGL widget * * Copyright (C) 1996-2002 Brian Paul and Ben Bederson * Copyright (C) 2005-2009 Greg Couch * See the LICENSE file for copyright details. */ /* !BEGIN!: Do not edit below this line. */ /* * Exported function declarations: */ #ifndef Togl_Init_TCL_DECLARED #define Togl_Init_TCL_DECLARED /* 0 */ EXTERN int Togl_Init(Tcl_Interp *interp); #endif #ifndef Togl_MakeCurrent_TCL_DECLARED #define Togl_MakeCurrent_TCL_DECLARED /* 1 */ EXTERN void Togl_MakeCurrent(const Togl *togl); #endif #ifndef Togl_PostRedisplay_TCL_DECLARED #define Togl_PostRedisplay_TCL_DECLARED /* 2 */ EXTERN void Togl_PostRedisplay(Togl *togl); #endif #ifndef Togl_SwapBuffers_TCL_DECLARED #define Togl_SwapBuffers_TCL_DECLARED /* 3 */ EXTERN void Togl_SwapBuffers(const Togl *togl); #endif #ifndef Togl_Ident_TCL_DECLARED #define Togl_Ident_TCL_DECLARED /* 4 */ EXTERN const char * Togl_Ident(const Togl *togl); #endif #ifndef Togl_Width_TCL_DECLARED #define Togl_Width_TCL_DECLARED /* 5 */ EXTERN int Togl_Width(const Togl *togl); #endif #ifndef Togl_Height_TCL_DECLARED #define Togl_Height_TCL_DECLARED /* 6 */ EXTERN int Togl_Height(const Togl *togl); #endif #ifndef Togl_PixelScale_TCL_DECLARED #define Togl_PixelScale_TCL_DECLARED /* 6 */ EXTERN int Togl_PixelScale(const Togl *togl); #endif #ifndef Togl_Interp_TCL_DECLARED #define Togl_Interp_TCL_DECLARED /* 7 */ EXTERN Tcl_Interp * Togl_Interp(const Togl *togl); #endif #ifndef Togl_TkWin_TCL_DECLARED #define Togl_TkWin_TCL_DECLARED /* 8 */ EXTERN Tk_Window Togl_TkWin(const Togl *togl); #endif #ifndef Togl_CommandName_TCL_DECLARED #define Togl_CommandName_TCL_DECLARED /* 9 */ EXTERN const char * Togl_CommandName(const Togl *togl); #endif #ifndef Togl_AllocColor_TCL_DECLARED #define Togl_AllocColor_TCL_DECLARED /* 10 */ EXTERN unsigned long Togl_AllocColor(const Togl *togl, float red, float green, float blue); #endif #ifndef Togl_FreeColor_TCL_DECLARED #define Togl_FreeColor_TCL_DECLARED /* 11 */ EXTERN void Togl_FreeColor(const Togl *togl, unsigned long index); #endif #ifndef Togl_SetColor_TCL_DECLARED #define Togl_SetColor_TCL_DECLARED /* 12 */ EXTERN void Togl_SetColor(const Togl *togl, unsigned long index, float red, float green, float blue); #endif #ifndef Togl_LoadBitmapFont_TCL_DECLARED #define Togl_LoadBitmapFont_TCL_DECLARED /* 13 */ EXTERN Tcl_Obj * Togl_LoadBitmapFont(const Togl *togl, const char *fontname); #endif #ifndef Togl_UnloadBitmapFont_TCL_DECLARED #define Togl_UnloadBitmapFont_TCL_DECLARED /* 14 */ EXTERN int Togl_UnloadBitmapFont(const Togl *togl, Tcl_Obj *toglfont); #endif #ifndef Togl_UseLayer_TCL_DECLARED #define Togl_UseLayer_TCL_DECLARED /* 15 */ EXTERN void Togl_UseLayer(Togl *togl, int layer); #endif #ifndef Togl_ShowOverlay_TCL_DECLARED #define Togl_ShowOverlay_TCL_DECLARED /* 16 */ EXTERN void Togl_ShowOverlay(Togl *togl); #endif #ifndef Togl_HideOverlay_TCL_DECLARED #define Togl_HideOverlay_TCL_DECLARED /* 17 */ EXTERN void Togl_HideOverlay(Togl *togl); #endif #ifndef Togl_PostOverlayRedisplay_TCL_DECLARED #define Togl_PostOverlayRedisplay_TCL_DECLARED /* 18 */ EXTERN void Togl_PostOverlayRedisplay(Togl *togl); #endif #ifndef Togl_ExistsOverlay_TCL_DECLARED #define Togl_ExistsOverlay_TCL_DECLARED /* 19 */ EXTERN int Togl_ExistsOverlay(const Togl *togl); #endif #ifndef Togl_GetOverlayTransparentValue_TCL_DECLARED #define Togl_GetOverlayTransparentValue_TCL_DECLARED /* 20 */ EXTERN int Togl_GetOverlayTransparentValue(const Togl *togl); #endif #ifndef Togl_IsMappedOverlay_TCL_DECLARED #define Togl_IsMappedOverlay_TCL_DECLARED /* 21 */ EXTERN int Togl_IsMappedOverlay(const Togl *togl); #endif #ifndef Togl_AllocColorOverlay_TCL_DECLARED #define Togl_AllocColorOverlay_TCL_DECLARED /* 22 */ EXTERN unsigned long Togl_AllocColorOverlay(const Togl *togl, float red, float green, float blue); #endif #ifndef Togl_FreeColorOverlay_TCL_DECLARED #define Togl_FreeColorOverlay_TCL_DECLARED /* 23 */ EXTERN void Togl_FreeColorOverlay(const Togl *togl, unsigned long index); #endif #ifndef Togl_GetClientData_TCL_DECLARED #define Togl_GetClientData_TCL_DECLARED /* 24 */ EXTERN ClientData Togl_GetClientData(const Togl *togl); #endif #ifndef Togl_SetClientData_TCL_DECLARED #define Togl_SetClientData_TCL_DECLARED /* 25 */ EXTERN void Togl_SetClientData(Togl *togl, ClientData clientData); #endif #ifndef Togl_DrawBuffer_TCL_DECLARED #define Togl_DrawBuffer_TCL_DECLARED /* 26 */ EXTERN void Togl_DrawBuffer(Togl *togl, GLenum mode); #endif #ifndef Togl_Clear_TCL_DECLARED #define Togl_Clear_TCL_DECLARED /* 27 */ EXTERN void Togl_Clear(const Togl *togl, GLbitfield mask); #endif #ifndef Togl_Frustum_TCL_DECLARED #define Togl_Frustum_TCL_DECLARED /* 28 */ EXTERN void Togl_Frustum(const Togl *togl, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near, GLdouble far); #endif #ifndef Togl_GetToglFromObj_TCL_DECLARED #define Togl_GetToglFromObj_TCL_DECLARED /* 29 */ EXTERN int Togl_GetToglFromObj(Tcl_Interp *interp, Tcl_Obj *obj, Togl **toglPtr); #endif #ifndef Togl_TakePhoto_TCL_DECLARED #define Togl_TakePhoto_TCL_DECLARED /* 30 */ EXTERN int Togl_TakePhoto(Togl *togl, Tk_PhotoHandle photo); #endif #ifndef Togl_GetProcAddr_TCL_DECLARED #define Togl_GetProcAddr_TCL_DECLARED /* 31 */ EXTERN Togl_FuncPtr Togl_GetProcAddr(const char *funcname); #endif #ifndef Togl_GetToglFromName_TCL_DECLARED #define Togl_GetToglFromName_TCL_DECLARED /* 32 */ EXTERN int Togl_GetToglFromName(Tcl_Interp *interp, const char *cmdName, Togl **toglPtr); #endif #ifndef Togl_SwapInterval_TCL_DECLARED #define Togl_SwapInterval_TCL_DECLARED /* 33 */ EXTERN Bool Togl_SwapInterval(const Togl *togl, int interval); #endif #ifndef Togl_Ortho_TCL_DECLARED #define Togl_Ortho_TCL_DECLARED /* 34 */ EXTERN void Togl_Ortho(const Togl *togl, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near, GLdouble far); #endif #ifndef Togl_NumEyes_TCL_DECLARED #define Togl_NumEyes_TCL_DECLARED /* 35 */ EXTERN int Togl_NumEyes(const Togl *togl); #endif #ifndef Togl_ContextTag_TCL_DECLARED #define Togl_ContextTag_TCL_DECLARED /* 36 */ EXTERN int Togl_ContextTag(const Togl *togl); #endif #ifndef Togl_UpdatePending_TCL_DECLARED #define Togl_UpdatePending_TCL_DECLARED /* 37 */ EXTERN Bool Togl_UpdatePending(const Togl *togl); #endif #ifndef Togl_WriteObj_TCL_DECLARED #define Togl_WriteObj_TCL_DECLARED /* 38 */ EXTERN int Togl_WriteObj(const Togl *togl, const Tcl_Obj *toglfont, Tcl_Obj *obj); #endif #ifndef Togl_WriteChars_TCL_DECLARED #define Togl_WriteChars_TCL_DECLARED /* 39 */ EXTERN int Togl_WriteChars(const Togl *togl, const Tcl_Obj *toglfont, const char *str, int len); #endif #ifndef Togl_HasRGBA_TCL_DECLARED #define Togl_HasRGBA_TCL_DECLARED /* 40 */ EXTERN Bool Togl_HasRGBA(const Togl *togl); #endif #ifndef Togl_IsDoubleBuffered_TCL_DECLARED #define Togl_IsDoubleBuffered_TCL_DECLARED /* 41 */ EXTERN Bool Togl_IsDoubleBuffered(const Togl *togl); #endif #ifndef Togl_HasDepthBuffer_TCL_DECLARED #define Togl_HasDepthBuffer_TCL_DECLARED /* 42 */ EXTERN Bool Togl_HasDepthBuffer(const Togl *togl); #endif #ifndef Togl_HasAccumulationBuffer_TCL_DECLARED #define Togl_HasAccumulationBuffer_TCL_DECLARED /* 43 */ EXTERN Bool Togl_HasAccumulationBuffer(const Togl *togl); #endif #ifndef Togl_HasDestinationAlpha_TCL_DECLARED #define Togl_HasDestinationAlpha_TCL_DECLARED /* 44 */ EXTERN Bool Togl_HasDestinationAlpha(const Togl *togl); #endif #ifndef Togl_HasStencilBuffer_TCL_DECLARED #define Togl_HasStencilBuffer_TCL_DECLARED /* 45 */ EXTERN Bool Togl_HasStencilBuffer(const Togl *togl); #endif #ifndef Togl_StereoMode_TCL_DECLARED #define Togl_StereoMode_TCL_DECLARED /* 46 */ EXTERN int Togl_StereoMode(const Togl *togl); #endif #ifndef Togl_HasMultisample_TCL_DECLARED #define Togl_HasMultisample_TCL_DECLARED /* 47 */ EXTERN Bool Togl_HasMultisample(const Togl *togl); #endif #ifndef Togl_CopyContext_TCL_DECLARED #define Togl_CopyContext_TCL_DECLARED /* 48 */ EXTERN int Togl_CopyContext(const Togl *from, const Togl *to, unsigned int mask); #endif typedef struct ToglStubs { int magic; const struct ToglStubHooks *hooks; int (*togl_Init) (Tcl_Interp *interp); /* 0 */ void (*togl_MakeCurrent) (const Togl *togl); /* 1 */ void (*togl_PostRedisplay) (Togl *togl); /* 2 */ void (*togl_SwapBuffers) (const Togl *togl); /* 3 */ const char * (*togl_Ident) (const Togl *togl); /* 4 */ int (*togl_Width) (const Togl *togl); /* 5 */ int (*togl_Height) (const Togl *togl); /* 6 */ Tcl_Interp * (*togl_Interp) (const Togl *togl); /* 7 */ Tk_Window (*togl_TkWin) (const Togl *togl); /* 8 */ const char * (*togl_CommandName) (const Togl *togl); /* 9 */ unsigned long (*togl_AllocColor) (const Togl *togl, float red, float green, float blue); /* 10 */ void (*togl_FreeColor) (const Togl *togl, unsigned long index); /* 11 */ void (*togl_SetColor) (const Togl *togl, unsigned long index, float red, float green, float blue); /* 12 */ Tcl_Obj * (*togl_LoadBitmapFont) (const Togl *togl, const char *fontname); /* 13 */ int (*togl_UnloadBitmapFont) (const Togl *togl, Tcl_Obj *toglfont); /* 14 */ void (*togl_UseLayer) (Togl *togl, int layer); /* 15 */ void (*togl_ShowOverlay) (Togl *togl); /* 16 */ void (*togl_HideOverlay) (Togl *togl); /* 17 */ void (*togl_PostOverlayRedisplay) (Togl *togl); /* 18 */ int (*togl_ExistsOverlay) (const Togl *togl); /* 19 */ int (*togl_GetOverlayTransparentValue) (const Togl *togl); /* 20 */ int (*togl_IsMappedOverlay) (const Togl *togl); /* 21 */ unsigned long (*togl_AllocColorOverlay) (const Togl *togl, float red, float green, float blue); /* 22 */ void (*togl_FreeColorOverlay) (const Togl *togl, unsigned long index); /* 23 */ ClientData (*togl_GetClientData) (const Togl *togl); /* 24 */ void (*togl_SetClientData) (Togl *togl, ClientData clientData); /* 25 */ void (*togl_DrawBuffer) (Togl *togl, GLenum mode); /* 26 */ void (*togl_Clear) (const Togl *togl, GLbitfield mask); /* 27 */ void (*togl_Frustum) (const Togl *togl, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near, GLdouble far); /* 28 */ int (*togl_GetToglFromObj) (Tcl_Interp *interp, Tcl_Obj *obj, Togl **toglPtr); /* 29 */ int (*togl_TakePhoto) (Togl *togl, Tk_PhotoHandle photo); /* 30 */ Togl_FuncPtr (*togl_GetProcAddr) (const char *funcname); /* 31 */ int (*togl_GetToglFromName) (Tcl_Interp *interp, const char *cmdName, Togl **toglPtr); /* 32 */ Bool (*togl_SwapInterval) (const Togl *togl, int interval); /* 33 */ void (*togl_Ortho) (const Togl *togl, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near, GLdouble far); /* 34 */ int (*togl_NumEyes) (const Togl *togl); /* 35 */ int (*togl_ContextTag) (const Togl *togl); /* 36 */ Bool (*togl_UpdatePending) (const Togl *togl); /* 37 */ int (*togl_WriteObj) (const Togl *togl, const Tcl_Obj *toglfont, Tcl_Obj *obj); /* 38 */ int (*togl_WriteChars) (const Togl *togl, const Tcl_Obj *toglfont, const char *str, int len); /* 39 */ Bool (*togl_HasRGBA) (const Togl *togl); /* 40 */ Bool (*togl_IsDoubleBuffered) (const Togl *togl); /* 41 */ Bool (*togl_HasDepthBuffer) (const Togl *togl); /* 42 */ Bool (*togl_HasAccumulationBuffer) (const Togl *togl); /* 43 */ Bool (*togl_HasDestinationAlpha) (const Togl *togl); /* 44 */ Bool (*togl_HasStencilBuffer) (const Togl *togl); /* 45 */ int (*togl_StereoMode) (const Togl *togl); /* 46 */ Bool (*togl_HasMultisample) (const Togl *togl); /* 47 */ int (*togl_CopyContext) (const Togl *from, const Togl *to, unsigned int mask); /* 48 */ } ToglStubs; #if defined(USE_TOGL_STUBS) && !defined(USE_TOGL_STUB_PROCS) extern const ToglStubs *toglStubsPtr; #endif /* defined(USE_TOGL_STUBS) && !defined(USE_TOGL_STUB_PROCS) */ #if defined(USE_TOGL_STUBS) && !defined(USE_TOGL_STUB_PROCS) /* * Inline function declarations: */ #ifndef Togl_Init #define Togl_Init \ (toglStubsPtr->togl_Init) /* 0 */ #endif #ifndef Togl_MakeCurrent #define Togl_MakeCurrent \ (toglStubsPtr->togl_MakeCurrent) /* 1 */ #endif #ifndef Togl_PostRedisplay #define Togl_PostRedisplay \ (toglStubsPtr->togl_PostRedisplay) /* 2 */ #endif #ifndef Togl_SwapBuffers #define Togl_SwapBuffers \ (toglStubsPtr->togl_SwapBuffers) /* 3 */ #endif #ifndef Togl_Ident #define Togl_Ident \ (toglStubsPtr->togl_Ident) /* 4 */ #endif #ifndef Togl_Width #define Togl_Width \ (toglStubsPtr->togl_Width) /* 5 */ #endif #ifndef Togl_Height #define Togl_Height \ (toglStubsPtr->togl_Height) /* 6 */ #endif #ifndef Togl_Interp #define Togl_Interp \ (toglStubsPtr->togl_Interp) /* 7 */ #endif #ifndef Togl_TkWin #define Togl_TkWin \ (toglStubsPtr->togl_TkWin) /* 8 */ #endif #ifndef Togl_CommandName #define Togl_CommandName \ (toglStubsPtr->togl_CommandName) /* 9 */ #endif #ifndef Togl_AllocColor #define Togl_AllocColor \ (toglStubsPtr->togl_AllocColor) /* 10 */ #endif #ifndef Togl_FreeColor #define Togl_FreeColor \ (toglStubsPtr->togl_FreeColor) /* 11 */ #endif #ifndef Togl_SetColor #define Togl_SetColor \ (toglStubsPtr->togl_SetColor) /* 12 */ #endif #ifndef Togl_LoadBitmapFont #define Togl_LoadBitmapFont \ (toglStubsPtr->togl_LoadBitmapFont) /* 13 */ #endif #ifndef Togl_UnloadBitmapFont #define Togl_UnloadBitmapFont \ (toglStubsPtr->togl_UnloadBitmapFont) /* 14 */ #endif #ifndef Togl_UseLayer #define Togl_UseLayer \ (toglStubsPtr->togl_UseLayer) /* 15 */ #endif #ifndef Togl_ShowOverlay #define Togl_ShowOverlay \ (toglStubsPtr->togl_ShowOverlay) /* 16 */ #endif #ifndef Togl_HideOverlay #define Togl_HideOverlay \ (toglStubsPtr->togl_HideOverlay) /* 17 */ #endif #ifndef Togl_PostOverlayRedisplay #define Togl_PostOverlayRedisplay \ (toglStubsPtr->togl_PostOverlayRedisplay) /* 18 */ #endif #ifndef Togl_ExistsOverlay #define Togl_ExistsOverlay \ (toglStubsPtr->togl_ExistsOverlay) /* 19 */ #endif #ifndef Togl_GetOverlayTransparentValue #define Togl_GetOverlayTransparentValue \ (toglStubsPtr->togl_GetOverlayTransparentValue) /* 20 */ #endif #ifndef Togl_IsMappedOverlay #define Togl_IsMappedOverlay \ (toglStubsPtr->togl_IsMappedOverlay) /* 21 */ #endif #ifndef Togl_AllocColorOverlay #define Togl_AllocColorOverlay \ (toglStubsPtr->togl_AllocColorOverlay) /* 22 */ #endif #ifndef Togl_FreeColorOverlay #define Togl_FreeColorOverlay \ (toglStubsPtr->togl_FreeColorOverlay) /* 23 */ #endif #ifndef Togl_GetClientData #define Togl_GetClientData \ (toglStubsPtr->togl_GetClientData) /* 24 */ #endif #ifndef Togl_SetClientData #define Togl_SetClientData \ (toglStubsPtr->togl_SetClientData) /* 25 */ #endif #ifndef Togl_DrawBuffer #define Togl_DrawBuffer \ (toglStubsPtr->togl_DrawBuffer) /* 26 */ #endif #ifndef Togl_Clear #define Togl_Clear \ (toglStubsPtr->togl_Clear) /* 27 */ #endif #ifndef Togl_Frustum #define Togl_Frustum \ (toglStubsPtr->togl_Frustum) /* 28 */ #endif #ifndef Togl_GetToglFromObj #define Togl_GetToglFromObj \ (toglStubsPtr->togl_GetToglFromObj) /* 29 */ #endif #ifndef Togl_TakePhoto #define Togl_TakePhoto \ (toglStubsPtr->togl_TakePhoto) /* 30 */ #endif #ifndef Togl_GetProcAddr #define Togl_GetProcAddr \ (toglStubsPtr->togl_GetProcAddr) /* 31 */ #endif #ifndef Togl_GetToglFromName #define Togl_GetToglFromName \ (toglStubsPtr->togl_GetToglFromName) /* 32 */ #endif #ifndef Togl_SwapInterval #define Togl_SwapInterval \ (toglStubsPtr->togl_SwapInterval) /* 33 */ #endif #ifndef Togl_Ortho #define Togl_Ortho \ (toglStubsPtr->togl_Ortho) /* 34 */ #endif #ifndef Togl_NumEyes #define Togl_NumEyes \ (toglStubsPtr->togl_NumEyes) /* 35 */ #endif #ifndef Togl_ContextTag #define Togl_ContextTag \ (toglStubsPtr->togl_ContextTag) /* 36 */ #endif #ifndef Togl_UpdatePending #define Togl_UpdatePending \ (toglStubsPtr->togl_UpdatePending) /* 37 */ #endif #ifndef Togl_WriteObj #define Togl_WriteObj \ (toglStubsPtr->togl_WriteObj) /* 38 */ #endif #ifndef Togl_WriteChars #define Togl_WriteChars \ (toglStubsPtr->togl_WriteChars) /* 39 */ #endif #ifndef Togl_HasRGBA #define Togl_HasRGBA \ (toglStubsPtr->togl_HasRGBA) /* 40 */ #endif #ifndef Togl_IsDoubleBuffered #define Togl_IsDoubleBuffered \ (toglStubsPtr->togl_IsDoubleBuffered) /* 41 */ #endif #ifndef Togl_HasDepthBuffer #define Togl_HasDepthBuffer \ (toglStubsPtr->togl_HasDepthBuffer) /* 42 */ #endif #ifndef Togl_HasAccumulationBuffer #define Togl_HasAccumulationBuffer \ (toglStubsPtr->togl_HasAccumulationBuffer) /* 43 */ #endif #ifndef Togl_HasDestinationAlpha #define Togl_HasDestinationAlpha \ (toglStubsPtr->togl_HasDestinationAlpha) /* 44 */ #endif #ifndef Togl_HasStencilBuffer #define Togl_HasStencilBuffer \ (toglStubsPtr->togl_HasStencilBuffer) /* 45 */ #endif #ifndef Togl_StereoMode #define Togl_StereoMode \ (toglStubsPtr->togl_StereoMode) /* 46 */ #endif #ifndef Togl_HasMultisample #define Togl_HasMultisample \ (toglStubsPtr->togl_HasMultisample) /* 47 */ #endif #ifndef Togl_CopyContext #define Togl_CopyContext \ (toglStubsPtr->togl_CopyContext) /* 48 */ #endif #endif /* defined(USE_TOGL_STUBS) && !defined(USE_TOGL_STUB_PROCS) */ /* !END!: Do not edit above this line. */ #endif ================================================ FILE: ng/Togl2.1/toglFont.c ================================================ /* $Id: toglFont.c,v 1.8 2009/05/22 00:18:36 gregcouch Exp $ */ /* vi:set sw=4 expandtab: */ /* * Togl - a Tk OpenGL widget * * Copyright (C) 1996-2002 Brian Paul and Ben Bederson * Copyright (C) 2005-2008 Greg Couch * See the LICENSE file for copyright details. */ /* * Togl Bitmap Font support * * If bitmap font support is requested, then this file is included into * togl.c. Parts of this file are based on , * "Creating and Using Tcl Handles in C Extensions". * * Neither the Tk public nor the internal interface give enough information * to reuse the font in OpenGL, so we copy the private structures here to * access what we need. * * Globals needed by the font module are in togl.c */ #include struct Togl_BitmapFontInfo { GLuint base; GLuint first; GLuint last; int contextTag; /* TODO: keep original font and/or encoding */ }; typedef struct Togl_BitmapFontInfo Togl_BitmapFontInfo; #define BITMAP_FONT_INFO(obj) \ ((Togl_BitmapFontInfo *) (obj)->internalRep.otherValuePtr) #define SET_BITMAP_FONT_INFO(obj) \ (obj)->internalRep.otherValuePtr static void Togl_FontFree(Tcl_Obj *obj); static void Togl_FontDup(Tcl_Obj *src, Tcl_Obj *dup); static void Togl_FontString(Tcl_Obj *obj); static int Togl_FontSet(Tcl_Interp *interp, Tcl_Obj *obj); static Tcl_ObjType Togl_BitmapFontType = { "Togl BitmapFont", /* name */ Togl_FontFree, /* free internal rep */ Togl_FontDup, /* dup internal rep */ Togl_FontString, /* update string from internal rep */ Togl_FontSet /* set internal rep from string */ }; static int Togl_FontSet(Tcl_Interp *interp, Tcl_Obj *obj) { if (interp) Tcl_AppendResult(interp, "cannot (re)build object of type \"", Togl_BitmapFontType.name, "\"", NULL); return TCL_ERROR; } static void Togl_FontFree(Tcl_Obj *obj) { Togl_BitmapFontInfo *bfi = BITMAP_FONT_INFO(obj); ckfree((char *) bfi); } static void Togl_FontString(Tcl_Obj *obj) { /* assert(obj->bytes == NULL) */ static char buf[256]; register unsigned len; Togl_BitmapFontInfo *bfi = BITMAP_FONT_INFO(obj); #if !defined(TOGL_AGL) && !defined(TOGL_NSOPENGL) snprintf(buf, sizeof buf - 1, "{{%s} %d %d %d}", Togl_BitmapFontType.name, bfi->base, bfi->first, bfi->last); #else /* unlike every other platform, on Aqua, GLint is long */ snprintf(buf, sizeof buf - 1, "{{%s} %ld %ld %ld}", Togl_BitmapFontType.name, bfi->base, bfi->first, bfi->last); #endif buf[sizeof buf - 1] = '\0'; len = strlen(buf); obj->bytes = (char *) ckalloc(len + 1); strcpy(obj->bytes, buf); obj->length = len; } static void Togl_FontDup(Tcl_Obj *src, Tcl_Obj *dup) { /* * When duplicated, lose the font-ness and just be a string. * So don't copy the internal representation and don't set * dup->typePtr. */ } #if defined(TOGL_X11) /* From tkUnixFont.c */ /* * The following structure encapsulates an individual screen font. A font * object is made up of however many SubFonts are necessary to display a * stream of multilingual characters. */ typedef struct FontFamily FontFamily; typedef struct SubFont { char **fontMap; /* Pointer to font map from the FontFamily, * cached here to save a dereference. */ XFontStruct *fontStructPtr; /* The specific screen font that will be used * when displaying/measuring chars belonging to * the FontFamily. */ FontFamily *familyPtr; /* The FontFamily for this SubFont. */ } SubFont; /* * The following structure represents Unix's implementation of a font * object. */ # define SUBFONT_SPACE 3 # define BASE_CHARS 256 typedef struct UnixFont { TkFont font; /* Stuff used by generic font package. Must be * first in structure. */ SubFont staticSubFonts[SUBFONT_SPACE]; /* Builtin space for a limited number of SubFonts. */ int numSubFonts; /* Length of following array. */ SubFont *subFontArray; /* Array of SubFonts that have been loaded in * order to draw/measure all the characters * encountered by this font so far. All fonts * start off with one SubFont initialized by * AllocFont() from the original set of font * attributes. Usually points to * staticSubFonts, but may point to malloced * space if there are lots of SubFonts. */ SubFont controlSubFont; /* Font to use to display control-character * expansions. */ # if 0 Display *display; /* Display that owns font. */ int pixelSize; /* Original pixel size used when font was * constructed. */ TkXLFDAttributes xa; /* Additional attributes that specify the * preferred foundry and encoding to use when * constructing additional SubFonts. */ int widths[BASE_CHARS]; /* Widths of first 256 chars in the base font, * for handling common case. */ int underlinePos; /* Offset from baseline to origin of underline * bar (used when drawing underlined font) * (pixels). */ int barHeight; /* Height of underline or overstrike bar (used * when drawing underlined or strikeout font) * (pixels). */ # endif } UnixFont; #elif defined(TOGL_WGL) # include /* From tkWinFont.c */ typedef struct FontFamily FontFamily; /* * The following structure encapsulates an individual screen font. A font * object is made up of however many SubFonts are necessary to display a * stream of multilingual characters. */ typedef struct SubFont { char **fontMap; /* Pointer to font map from the FontFamily, * cached here to save a dereference. */ HFONT hFont; /* The specific screen font that will be used * when displaying/measuring chars belonging to * the FontFamily. */ FontFamily *familyPtr; /* The FontFamily for this SubFont. */ } SubFont; /* * The following structure represents Windows' implementation of a font * object. */ # define SUBFONT_SPACE 3 # define BASE_CHARS 128 typedef struct WinFont { TkFont font; /* Stuff used by generic font package. Must be * first in structure. */ SubFont staticSubFonts[SUBFONT_SPACE]; /* Builtin space for a limited number of SubFonts. */ int numSubFonts; /* Length of following array. */ SubFont *subFontArray; /* Array of SubFonts that have been loaded in * order to draw/measure all the characters * encountered by this font so far. All fonts * start off with one SubFont initialized by * AllocFont() from the original set of font * attributes. Usually points to * staticSubFonts, but may point to malloced * space if there are lots of SubFonts. */ HWND hwnd; /* Toplevel window of application that owns * this font, used for getting HDC for * offscreen measurements. */ int pixelSize; /* Original pixel size used when font was * constructed. */ int widths[BASE_CHARS]; /* Widths of first 128 chars in the base font, * for handling common case. The base font is * always used to draw characters between * 0x0000 and 0x007f. */ } WinFont; #elif defined(TOGL_AGL) typedef struct FontFamily { struct FontFamily *nextPtr; /* Next in list of all known font families. */ int refCount; /* How many SubFonts are referring to this * FontFamily. When the refCount drops to * zero, this FontFamily may be freed. */ /* * Key. */ FMFontFamily faceNum; /* Unique face number key for this FontFamily. */ /* * Derived properties. */ Tcl_Encoding encoding; /* Encoding for this font family. */ # if 0 int isSymbolFont; /* Non-zero if this is a symbol family. */ int isMultiByteFont; /* Non-zero if this is a multi-byte family. */ char typeTable[256]; /* Table that identfies all lead bytes for a * multi-byte family, used when measuring * chars. If a byte is a lead byte, the value * at the corresponding position in the * typeTable is 1, otherwise 0. If this is a * single-byte font, all entries are 0. */ char *fontMap[FONTMAP_PAGES]; /* Two-level sparse table used to determine quickly if the specified * character exists. As characters are encountered, more pages in this * table are dynamically added. The contents of each page is a bitmask * consisting of FONTMAP_BITSPERPAGE bits, representing whether this font * can be used to display the given character at the corresponding bit * position. The high bits of the character are used to pick which page of * the table is used. */ # endif } FontFamily; /* * The following structure encapsulates an individual screen font. A font * object is made up of however many SubFonts are necessary to display a * stream of multilingual characters. */ typedef struct SubFont { char **fontMap; /* Pointer to font map from the FontFamily, * cached here to save a dereference. */ FontFamily *familyPtr; /* The FontFamily for this SubFont. */ } SubFont; /* * The following structure represents Macintosh's implementation of a font * object. */ # define SUBFONT_SPACE 3 typedef struct MacFont { TkFont font; /* Stuff used by generic font package. Must be * first in structure. */ SubFont staticSubFonts[SUBFONT_SPACE]; /* Builtin space for a limited number of SubFonts. */ int numSubFonts; /* Length of following array. */ SubFont *subFontArray; /* Array of SubFonts that have been loaded in * order to draw/measure all the characters * encountered by this font so far. All fonts * start off with one SubFont initialized by * AllocFont() from the original set of font * attributes. Usually points to * staticSubFonts, but may point to malloced * space if there are lots of SubFonts. */ short size; /* Font size in pixels, constructed from font * attributes. */ short style; /* Style bits, constructed from font * attributes. */ } MacFont; #endif /* * Load the named bitmap font as a sequence of bitmaps in a display list. * fontname may be any font recognized by Tk_GetFont. */ Tcl_Obj * Togl_LoadBitmapFont(const Togl *togl, const char *fontname) { Tk_Font font; Togl_BitmapFontInfo *bfi; Tcl_Obj *obj; #if defined(TOGL_X11) UnixFont *unixfont; XFontStruct *fontinfo; #elif defined(TOGL_WGL) WinFont *winfont; HFONT oldFont; TEXTMETRIC tm; #elif defined(TOGL_AGL) || defined(TOGL_NSOPENGL) MacFont *macfont; #endif int first, last, count; GLuint fontbase; if (!fontname) { fontname = DEFAULT_FONTNAME; } font = Tk_GetFont(togl->Interp, togl->TkWin, fontname); if (!font) { return NULL; } #if defined(TOGL_X11) unixfont = (UnixFont *) font; fontinfo = unixfont->subFontArray->fontStructPtr; first = fontinfo->min_char_or_byte2; last = fontinfo->max_char_or_byte2; #elif defined(TOGL_WGL) winfont = (WinFont *) font; oldFont = (HFONT) SelectObject(togl->tglGLHdc, winfont->subFontArray->hFont); GetTextMetrics(togl->tglGLHdc, &tm); first = tm.tmFirstChar; last = tm.tmLastChar; #elif defined(TOGL_AGL) || defined(TOGL_NSOPENGL) macfont = (MacFont *) font; first = 10; /* don't know how to determine font range on * Mac... */ last = 255; #endif if (last > 255) last = 255; /* no unicode support */ count = last - first + 1; fontbase = glGenLists((GLuint) (last + 1)); if (fontbase == 0) { #ifdef TOGL_WGL SelectObject(togl->tglGLHdc, oldFont); #endif Tk_FreeFont(font); return NULL; } #if defined(TOGL_WGL) wglUseFontBitmaps(togl->tglGLHdc, first, count, fontbase + first); SelectObject(togl->tglGLHdc, oldFont); #elif defined(TOGL_X11) glXUseXFont(fontinfo->fid, first, count, (int) fontbase + first); #elif defined(TOGL_AGL) /* deprecated in OS X 10.5 */ aglUseFont(togl->Ctx, macfont->subFontArray->familyPtr->faceNum, macfont->style, macfont->size, first, count, fontbase + first); #elif defined(TOGL_NSOPENGL) /* No NSOpenGL equivalent to aglUseFont(). */ #endif Tk_FreeFont(font); bfi = (Togl_BitmapFontInfo *) ckalloc(sizeof (Togl_BitmapFontInfo)); bfi->base = fontbase; bfi->first = first; bfi->last = last; bfi->contextTag = togl->contextTag; obj = Tcl_NewObj(); SET_BITMAP_FONT_INFO(obj) = bfi; obj->typePtr = &Togl_BitmapFontType; return obj; } /* * Release the display lists which were generated by Togl_LoadBitmapFont(). */ int Togl_UnloadBitmapFont(const Togl *togl, Tcl_Obj *toglfont) { Togl_BitmapFontInfo *bfi; if (toglfont == NULL || toglfont->typePtr != &Togl_BitmapFontType) { Tcl_Interp *interp = Togl_Interp(togl); Tcl_AppendResult(interp, "font not found", NULL); return TCL_ERROR; } bfi = BITMAP_FONT_INFO(toglfont); glDeleteLists(bfi->base, bfi->last + 1); /* match glGenLists */ return TCL_OK; } int Togl_WriteObj(const Togl *togl, const Tcl_Obj *toglfont, Tcl_Obj *obj) { const char *str; int len; str = Tcl_GetStringFromObj(obj, &len); return Togl_WriteChars(togl, toglfont, str, len); } int Togl_WriteChars(const Togl *togl, const Tcl_Obj *toglfont, const char *str, int len) { /* TODO: assume utf8 encoding and convert to font encoding */ Togl_BitmapFontInfo *bfi; if (toglfont == NULL || toglfont->typePtr != &Togl_BitmapFontType) return -1; bfi = BITMAP_FONT_INFO(toglfont); if (Togl_ContextTag(togl) != bfi->contextTag) return -1; if (len == 0) len = strlen(str); glListBase(bfi->base); glCallLists(len, GL_UNSIGNED_BYTE, str); return len; } ================================================ FILE: ng/Togl2.1/toglGLX.c ================================================ /* $Id: toglGLX.c,v 1.12 2009/10/22 20:40:52 gregcouch Exp $ */ /* vi:set sw=4 expandtab: */ /* * Togl - a Tk OpenGL widget * * Copyright (C) 1996-2002 Brian Paul and Ben Bederson * Copyright (C) 2005-2009 Greg Couch * See the LICENSE file for copyright details. */ /* TODO: fullscreen support */ #undef DEBUG_GLX static PFNGLXCHOOSEFBCONFIGPROC chooseFBConfig = NULL; static PFNGLXGETFBCONFIGATTRIBPROC getFBConfigAttrib = NULL; static PFNGLXGETVISUALFROMFBCONFIGPROC getVisualFromFBConfig = NULL; static PFNGLXCREATEPBUFFERPROC createPbuffer = NULL; static PFNGLXCREATEGLXPBUFFERSGIXPROC createPbufferSGIX = NULL; static PFNGLXDESTROYPBUFFERPROC destroyPbuffer = NULL; static PFNGLXQUERYDRAWABLEPROC queryPbuffer = NULL; static Bool hasMultisampling = False; static Bool hasPbuffer = False; struct FBInfo { int acceleration; int samples; int depth; int colors; GLXFBConfig fbcfg; XVisualInfo *visInfo; }; typedef struct FBInfo FBInfo; static int FBInfoCmp(const void *a, const void *b) { /* * 1. full acceleration is better * 2. greater color bits is better * 3. greater depth bits is better * 4. more multisampling is better */ const FBInfo *x = (const FBInfo *) a; const FBInfo *y = (const FBInfo *) b; if (x->acceleration != y->acceleration) return y->acceleration - x->acceleration; if (x->colors != y->colors) return y->colors - x->colors; if (x->depth != y->depth) return y->depth - x->depth; if (x->samples != y->samples) return y->samples - x->samples; return 0; } #ifdef DEBUG_GLX static int fatal_error(Display *dpy, XErrorEvent * event) { char buf[256]; XGetErrorText(dpy, event->error_code, buf, sizeof buf); fprintf(stderr, "%s\n", buf); abort(); } #endif static XVisualInfo * togl_pixelFormat(Togl *togl, int scrnum) { int attribs[256]; int na = 0; int i; XVisualInfo *visinfo; FBInfo *info; static int loadedOpenGL = False; if (!loadedOpenGL) { int dummy; int major, minor; const char *extensions; /* Make sure OpenGL's GLX extension supported */ if (!glXQueryExtension(togl->display, &dummy, &dummy)) { Tcl_SetResult(togl->Interp, TCL_STUPID "X server is missing OpenGL GLX extension", TCL_STATIC); return NULL; } loadedOpenGL = True; #ifdef DEBUG_GLX (void) XSetErrorHandler(fatal_error); #endif glXQueryVersion(togl->display, &major, &minor); extensions = glXQueryExtensionsString(togl->display, scrnum); if (major > 1 || (major == 1 && minor >= 3)) { chooseFBConfig = (PFNGLXCHOOSEFBCONFIGPROC) Togl_GetProcAddr("glXChooseFBConfig"); getFBConfigAttrib = (PFNGLXGETFBCONFIGATTRIBPROC) Togl_GetProcAddr("glXGetFBConfigAttrib"); getVisualFromFBConfig = (PFNGLXGETVISUALFROMFBCONFIGPROC) Togl_GetProcAddr("glXGetVisualFromFBConfig"); createPbuffer = (PFNGLXCREATEPBUFFERPROC) Togl_GetProcAddr("glXCreatePbuffer"); destroyPbuffer = (PFNGLXDESTROYPBUFFERPROC) Togl_GetProcAddr("glXDestroyPbuffer"); queryPbuffer = (PFNGLXQUERYDRAWABLEPROC) Togl_GetProcAddr("glXQueryDrawable"); if (createPbuffer && destroyPbuffer && queryPbuffer) { hasPbuffer = True; } else { createPbuffer = NULL; destroyPbuffer = NULL; queryPbuffer = NULL; } } if (major == 1 && minor == 2) { chooseFBConfig = (PFNGLXCHOOSEFBCONFIGPROC) Togl_GetProcAddr("glXChooseFBConfigSGIX"); getFBConfigAttrib = (PFNGLXGETFBCONFIGATTRIBPROC) Togl_GetProcAddr("glXGetFBConfigAttribSGIX"); getVisualFromFBConfig = (PFNGLXGETVISUALFROMFBCONFIGPROC) Togl_GetProcAddr("glXGetVisualFromFBConfigSGIX"); if (strstr(extensions, "GLX_SGIX_pbuffer") != NULL) { createPbufferSGIX = (PFNGLXCREATEGLXPBUFFERSGIXPROC) Togl_GetProcAddr("glXCreateGLXPbufferSGIX"); destroyPbuffer = (PFNGLXDESTROYPBUFFERPROC) Togl_GetProcAddr("glXDestroyGLXPbufferSGIX"); queryPbuffer = (PFNGLXQUERYDRAWABLEPROC) Togl_GetProcAddr("glXQueryGLXPbufferSGIX"); if (createPbufferSGIX && destroyPbuffer && queryPbuffer) { hasPbuffer = True; } else { createPbufferSGIX = NULL; destroyPbuffer = NULL; queryPbuffer = NULL; } } } if (chooseFBConfig) { /* verify that chooseFBConfig works (workaround Mesa 6.5 bug) */ int n = 0; GLXFBConfig *cfgs; attribs[n++] = GLX_RENDER_TYPE; attribs[n++] = GLX_RGBA_BIT; attribs[n++] = None; cfgs = chooseFBConfig(togl->display, scrnum, attribs, &n); if (cfgs == NULL || n == 0) { chooseFBConfig = NULL; } XFree(cfgs); } if (chooseFBConfig == NULL || getFBConfigAttrib == NULL || getVisualFromFBConfig == NULL) { chooseFBConfig = NULL; getFBConfigAttrib = NULL; getVisualFromFBConfig = NULL; } if (hasPbuffer && !chooseFBConfig) { hasPbuffer = False; } if ((major > 1 || (major == 1 && minor >= 4)) || strstr(extensions, "GLX_ARB_multisample") != NULL || strstr(extensions, "GLX_SGIS_multisample") != NULL) { /* Client GLX supports multisampling, but does the server? Well, we * can always ask. */ hasMultisampling = True; } } if (togl->MultisampleFlag && !hasMultisampling) { Tcl_SetResult(togl->Interp, TCL_STUPID "multisampling not supported", TCL_STATIC); return NULL; } if (togl->PbufferFlag && !hasPbuffer) { Tcl_SetResult(togl->Interp, TCL_STUPID "pbuffers are not supported", TCL_STATIC); return NULL; } /* * Only use the newer glXGetFBConfig if there's an explicit need for it * because it is buggy on many systems: * (1) NVidia 96.43.07 on Linux, single-buffered windows don't work * (2) Mesa 6.5.X and earlier fail */ if (chooseFBConfig) { /* have new glXGetFBConfig! */ int count; GLXFBConfig *cfgs; attribs[na++] = GLX_RENDER_TYPE; if (togl->RgbaFlag) { /* RGB[A] mode */ attribs[na++] = GLX_RGBA_BIT; attribs[na++] = GLX_RED_SIZE; attribs[na++] = togl->RgbaRed; attribs[na++] = GLX_GREEN_SIZE; attribs[na++] = togl->RgbaGreen; attribs[na++] = GLX_BLUE_SIZE; attribs[na++] = togl->RgbaBlue; if (togl->AlphaFlag) { attribs[na++] = GLX_ALPHA_SIZE; attribs[na++] = togl->AlphaSize; } } else { /* Color index mode */ attribs[na++] = GLX_COLOR_INDEX_BIT; attribs[na++] = GLX_BUFFER_SIZE; attribs[na++] = 1; } if (togl->DepthFlag) { attribs[na++] = GLX_DEPTH_SIZE; attribs[na++] = togl->DepthSize; } if (togl->DoubleFlag) { attribs[na++] = GLX_DOUBLEBUFFER; attribs[na++] = True; } if (togl->StencilFlag) { attribs[na++] = GLX_STENCIL_SIZE; attribs[na++] = togl->StencilSize; } if (togl->AccumFlag) { attribs[na++] = GLX_ACCUM_RED_SIZE; attribs[na++] = togl->AccumRed; attribs[na++] = GLX_ACCUM_GREEN_SIZE; attribs[na++] = togl->AccumGreen; attribs[na++] = GLX_ACCUM_BLUE_SIZE; attribs[na++] = togl->AccumBlue; if (togl->AlphaFlag) { attribs[na++] = GLX_ACCUM_ALPHA_SIZE; attribs[na++] = togl->AccumAlpha; } } if (togl->Stereo == TOGL_STEREO_NATIVE) { attribs[na++] = GLX_STEREO; attribs[na++] = True; } if (togl->MultisampleFlag) { attribs[na++] = GLX_SAMPLE_BUFFERS_ARB; attribs[na++] = 1; attribs[na++] = GLX_SAMPLES_ARB; attribs[na++] = 2; } if (togl->PbufferFlag) { attribs[na++] = GLX_DRAWABLE_TYPE; attribs[na++] = GLX_WINDOW_BIT | GLX_PBUFFER_BIT; } if (togl->AuxNumber != 0) { attribs[na++] = GLX_AUX_BUFFERS; attribs[na++] = togl->AuxNumber; } attribs[na++] = None; cfgs = chooseFBConfig(togl->display, scrnum, attribs, &count); if (cfgs == NULL || count == 0) { Tcl_SetResult(togl->Interp, TCL_STUPID "couldn't choose pixel format", TCL_STATIC); return NULL; } /* * Pick best format */ info = (FBInfo *) malloc(count * sizeof (FBInfo)); for (i = 0; i != count; ++i) { info[i].visInfo = getVisualFromFBConfig(togl->display, cfgs[i]); info[i].fbcfg = cfgs[i]; getFBConfigAttrib(togl->display, cfgs[i], GLX_CONFIG_CAVEAT, &info[i].acceleration); getFBConfigAttrib(togl->display, cfgs[i], GLX_BUFFER_SIZE, &info[i].colors); getFBConfigAttrib(togl->display, cfgs[i], GLX_DEPTH_SIZE, &info[i].depth); getFBConfigAttrib(togl->display, cfgs[i], GLX_SAMPLES, &info[i].samples); /* revise attributes so larger is better */ info[i].acceleration = -(info[i].acceleration - GLX_NONE); if (!togl->DepthFlag) info[i].depth = -info[i].depth; if (!togl->MultisampleFlag) info[i].samples = -info[i].samples; } qsort(info, count, sizeof info[0], FBInfoCmp); togl->fbcfg = info[0].fbcfg; visinfo = info[0].visInfo; for (i = 1; i != count; ++i) XFree(info[i].visInfo); free(info); XFree(cfgs); return visinfo; } /* use original glXChooseVisual */ attribs[na++] = GLX_USE_GL; if (togl->RgbaFlag) { /* RGB[A] mode */ attribs[na++] = GLX_RGBA; attribs[na++] = GLX_RED_SIZE; attribs[na++] = togl->RgbaRed; attribs[na++] = GLX_GREEN_SIZE; attribs[na++] = togl->RgbaGreen; attribs[na++] = GLX_BLUE_SIZE; attribs[na++] = togl->RgbaBlue; if (togl->AlphaFlag) { attribs[na++] = GLX_ALPHA_SIZE; attribs[na++] = togl->AlphaSize; } } else { /* Color index mode */ attribs[na++] = GLX_BUFFER_SIZE; attribs[na++] = 1; } if (togl->DepthFlag) { attribs[na++] = GLX_DEPTH_SIZE; attribs[na++] = togl->DepthSize; } if (togl->DoubleFlag) { attribs[na++] = GLX_DOUBLEBUFFER; } if (togl->StencilFlag) { attribs[na++] = GLX_STENCIL_SIZE; attribs[na++] = togl->StencilSize; } if (togl->AccumFlag) { attribs[na++] = GLX_ACCUM_RED_SIZE; attribs[na++] = togl->AccumRed; attribs[na++] = GLX_ACCUM_GREEN_SIZE; attribs[na++] = togl->AccumGreen; attribs[na++] = GLX_ACCUM_BLUE_SIZE; attribs[na++] = togl->AccumBlue; if (togl->AlphaFlag) { attribs[na++] = GLX_ACCUM_ALPHA_SIZE; attribs[na++] = togl->AccumAlpha; } } if (togl->Stereo == TOGL_STEREO_NATIVE) { attribs[na++] = GLX_STEREO; } if (togl->AuxNumber != 0) { attribs[na++] = GLX_AUX_BUFFERS; attribs[na++] = togl->AuxNumber; } attribs[na++] = None; visinfo = glXChooseVisual(togl->display, scrnum, attribs); if (visinfo == NULL) { Tcl_SetResult(togl->Interp, TCL_STUPID "couldn't choose pixel format", TCL_STATIC); return NULL; } return visinfo; } static int togl_describePixelFormat(Togl *togl) { int tmp = 0; /* fill in flags normally passed in that affect behavior */ (void) glXGetConfig(togl->display, togl->VisInfo, GLX_RGBA, &togl->RgbaFlag); (void) glXGetConfig(togl->display, togl->VisInfo, GLX_DOUBLEBUFFER, &togl->DoubleFlag); (void) glXGetConfig(togl->display, togl->VisInfo, GLX_DEPTH_SIZE, &tmp); togl->DepthFlag = (tmp != 0); (void) glXGetConfig(togl->display, togl->VisInfo, GLX_ACCUM_RED_SIZE, &tmp); togl->AccumFlag = (tmp != 0); (void) glXGetConfig(togl->display, togl->VisInfo, GLX_ALPHA_SIZE, &tmp); togl->AlphaFlag = (tmp != 0); (void) glXGetConfig(togl->display, togl->VisInfo, GLX_STENCIL_SIZE, &tmp); togl->StencilFlag = (tmp != 0); (void) glXGetConfig(togl->display, togl->VisInfo, GLX_STEREO, &tmp); togl->Stereo = tmp ? TOGL_STEREO_NATIVE : TOGL_STEREO_NONE; if (hasMultisampling) { (void) glXGetConfig(togl->display, togl->VisInfo, GLX_SAMPLES, &tmp); togl->MultisampleFlag = (tmp != 0); } return True; } static Tcl_ThreadDataKey togl_XError; struct ErrorData { int error_code; XErrorHandler prevHandler; }; typedef struct ErrorData ErrorData; static int togl_HandleXError(Display *dpy, XErrorEvent * event) { ErrorData *data = Tcl_GetThreadData(&togl_XError, (int) sizeof (ErrorData)); data->error_code = event->error_code; return 0; } static void togl_SetupXErrorHandler() { ErrorData *data = Tcl_GetThreadData(&togl_XError, (int) sizeof (ErrorData)); data->error_code = Success; /* 0 */ data->prevHandler = XSetErrorHandler(togl_HandleXError); } static int togl_CheckForXError(const Togl *togl) { ErrorData *data = Tcl_GetThreadData(&togl_XError, (int) sizeof (ErrorData)); XSync(togl->display, False); (void) XSetErrorHandler(data->prevHandler); return data->error_code; } static GLXPbuffer togl_createPbuffer(Togl *togl) { int attribs[32]; int na = 0; GLXPbuffer pbuf; togl_SetupXErrorHandler(); if (togl->LargestPbufferFlag) { attribs[na++] = GLX_LARGEST_PBUFFER; attribs[na++] = True; } attribs[na++] = GLX_PRESERVED_CONTENTS; attribs[na++] = True; if (createPbuffer) { attribs[na++] = GLX_PBUFFER_WIDTH; attribs[na++] = togl->Width; attribs[na++] = GLX_PBUFFER_HEIGHT; attribs[na++] = togl->Width; attribs[na++] = None; pbuf = createPbuffer(togl->display, togl->fbcfg, attribs); } else { attribs[na++] = None; pbuf = createPbufferSGIX(togl->display, togl->fbcfg, togl->Width, togl->Height, attribs); } if (togl_CheckForXError(togl) || pbuf == None) { Tcl_SetResult(togl->Interp, TCL_STUPID "unable to allocate pbuffer", TCL_STATIC); return None; } if (pbuf && togl->LargestPbufferFlag) { int tmp; queryPbuffer(togl->display, pbuf, GLX_WIDTH, &tmp); if (tmp != 0) togl->Width = tmp; queryPbuffer(togl->display, pbuf, GLX_HEIGHT, &tmp); if (tmp != 0) togl->Height = tmp; } return pbuf; } static void togl_destroyPbuffer(Togl *togl) { destroyPbuffer(togl->display, togl->pbuf); } ================================================ FILE: ng/Togl2.1/toglNSOpenGL.c ================================================ /* $Id: toglNSOpenGL.c,v 1.7 2009/10/22 00:06:41 gregcouch Exp $ */ /* vi:set sw=4 expandtab: */ /* * Togl - a Tk OpenGL widget * * Copyright (C) 1996-2002 Brian Paul and Ben Bederson * Copyright (C) 2005-2009 Greg Couch * See the LICENSE file for copyright details. */ static NSOpenGLPixelFormat * togl_pixelFormat(Togl *togl) { NSOpenGLPixelFormatAttribute attribs[32]; int na = 0; NSOpenGLPixelFormat *pix; #if 0 if (togl->MultisampleFlag && !hasMultisampling) { Tcl_SetResult(togl->Interp, TCL_STUPID "multisampling not supported", TCL_STATIC); return NULL; } #endif if (togl->PbufferFlag && !togl->RgbaFlag) { Tcl_SetResult(togl->Interp, TCL_STUPID "puffer must be RGB[A]", TCL_STATIC); return NULL; } attribs[na++] = NSOpenGLPFAMinimumPolicy; /* ask for hardware-accelerated onscreen */ attribs[na++] = NSOpenGLPFAAccelerated; attribs[na++] = NSOpenGLPFANoRecovery; if (togl->RgbaFlag) { /* RGB[A] mode */ attribs[na++] = NSOpenGLPFAColorSize; attribs[na++] = togl->RgbaRed + togl->RgbaGreen + togl->RgbaBlue; /* NSOpenGL does not take separate red,green,blue sizes. */ if (togl->AlphaFlag) { attribs[na++] = NSOpenGLPFAAlphaSize; attribs[na++] = togl->AlphaSize; } } else { /* Color index mode */ Tcl_SetResult(togl->Interp, TCL_STUPID "Color index mode not supported", TCL_STATIC); return NULL; } if (togl->DepthFlag) { attribs[na++] = NSOpenGLPFADepthSize; attribs[na++] = togl->DepthSize; } if (togl->DoubleFlag) { attribs[na++] = NSOpenGLPFADoubleBuffer; } if (togl->StencilFlag) { attribs[na++] = NSOpenGLPFAStencilSize; attribs[na++] = togl->StencilSize; } if (togl->AccumFlag) { attribs[na++] = NSOpenGLPFAAccumSize; attribs[na++] = togl->AccumRed + togl->AccumGreen + togl->AccumBlue + (togl->AlphaFlag ? togl->AccumAlpha : 0); } if (togl->MultisampleFlag) { attribs[na++] = NSOpenGLPFAMultisample; attribs[na++] = NSOpenGLPFASampleBuffers; attribs[na++] = 1; attribs[na++] = NSOpenGLPFASamples; attribs[na++] = 2; } if (togl->AuxNumber != 0) { attribs[na++] = NSOpenGLPFAAuxBuffers; attribs[na++] = togl->AuxNumber; } if (togl->Stereo == TOGL_STEREO_NATIVE) { attribs[na++] = NSOpenGLPFAStereo; } if (togl->FullscreenFlag) { attribs[na++] = NSOpenGLPFAFullScreen; } attribs[na++] = 0; /* End of attributes. */ pix = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs]; if (pix == nil) { Tcl_SetResult(togl->Interp, TCL_STUPID "couldn't choose pixel format", TCL_STATIC); return NULL; } return pix; } static int togl_describePixelFormat(Togl *togl) { NSOpenGLPixelFormat *pfmt = togl->PixelFormat; /* fill in RgbaFlag, DoubleFlag, and Stereo */ GLint has_rgba, has_doublebuf, has_depth, has_accum, has_alpha, has_stencil, has_stereo, has_multisample; GLint vscr = 0; [pfmt getValues:&has_rgba forAttribute:NSOpenGLPFAColorSize forVirtualScreen:vscr]; [pfmt getValues:&has_doublebuf forAttribute:NSOpenGLPFADoubleBuffer forVirtualScreen:vscr]; [pfmt getValues:&has_depth forAttribute:NSOpenGLPFADepthSize forVirtualScreen:vscr]; [pfmt getValues:&has_accum forAttribute:NSOpenGLPFAAccumSize forVirtualScreen:vscr]; [pfmt getValues:&has_alpha forAttribute:NSOpenGLPFAAlphaSize forVirtualScreen:vscr]; [pfmt getValues:&has_stencil forAttribute:NSOpenGLPFAStencilSize forVirtualScreen:vscr]; [pfmt getValues:&has_stereo forAttribute:NSOpenGLPFAStereo forVirtualScreen:vscr]; [pfmt getValues:&has_multisample forAttribute:NSOpenGLPFASampleBuffers forVirtualScreen:vscr]; togl->RgbaFlag = (has_rgba != 0); togl->DoubleFlag = (has_doublebuf != 0); togl->DepthFlag = (has_depth != 0); togl->AccumFlag = (has_accum != 0); togl->AlphaFlag = (has_alpha != 0); togl->StencilFlag = (has_stencil != 0); togl->Stereo = (has_stereo ? TOGL_STEREO_NATIVE : TOGL_STEREO_NONE); togl->MultisampleFlag = (has_multisample != 0); return True; } #define isPow2(x) (((x) & ((x) - 1)) == 0) static NSOpenGLPixelBuffer * togl_createPbuffer(Togl *togl) { GLint min_size[2], max_size[2]; Bool hasPbuffer; const char *extensions; GLint target; GLint virtualScreen; NSOpenGLPixelBuffer *pbuf; extensions = (const char *) glGetString(GL_EXTENSIONS); hasPbuffer = (strstr(extensions, "GL_APPLE_pixel_buffer") != NULL); if (!hasPbuffer) { Tcl_SetResult(togl->Interp, TCL_STUPID "pbuffers are not supported", TCL_STATIC); return NULL; } glGetIntegerv(GL_MIN_PBUFFER_VIEWPORT_DIMS_APPLE, min_size); glGetIntegerv(GL_MAX_VIEWPORT_DIMS, max_size); virtualScreen = [togl->Ctx currentVirtualScreen]; for (;;) { /* make sure we don't exceed the maximum size because if we do, * NSOpenGLPixelBuffer allocationmay succeed and later uses of * the pbuffer fail */ if (togl->Width < min_size[0]) togl->Width = min_size[0]; else if (togl->Width > max_size[0]) { if (togl->LargestPbufferFlag) togl->Width = max_size[0]; else { Tcl_SetResult(togl->Interp, TCL_STUPID "pbuffer too large", TCL_STATIC); return NULL; } } if (togl->Height < min_size[1]) togl->Height = min_size[1]; else if (togl->Height > max_size[1]) { if (togl->LargestPbufferFlag) togl->Height = max_size[1]; else { Tcl_SetResult(togl->Interp, TCL_STUPID "pbuffer too large", TCL_STATIC); return NULL; } } if (isPow2(togl->Width) && isPow2(togl->Height)) target = GL_TEXTURE_2D; else target = GL_TEXTURE_RECTANGLE_ARB; pbuf = [[NSOpenGLPixelBuffer alloc] initWithTextureTarget:target textureInternalFormat:(togl->AlphaFlag ? GL_RGBA : GL_RGB) textureMaxMipMapLevel:0 pixelsWide:togl->Width pixelsHigh:togl->Height]; if (pbuf != nil) { /* setPixelBuffer allocates the framebuffer space */ [togl->Ctx setPixelBuffer:pbuf cubeMapFace:0 mipMapLevel:0 currentVirtualScreen:virtualScreen]; return pbuf; } if (!togl->LargestPbufferFlag || togl->Width == min_size[0] || togl->Height == min_size[1]) { Tcl_SetResult(togl->Interp, TCL_STUPID "unable to create pbuffer", TCL_STATIC); return NULL; } /* largest unavailable, try something smaller */ togl->Width = togl->Width / 2 + togl->Width % 2; togl->Height = togl->Width / 2 + togl->Height % 2; } } static void togl_destroyPbuffer(Togl *togl) { [togl->pbuf release]; } ================================================ FILE: ng/Togl2.1/toglProcAddr.c ================================================ /* $Id */ /* vi:set sw=4: */ /* * Togl - a Tk OpenGL widget * * Copyright (C) 1996-2002 Brian Paul and Ben Bederson * Copyright (C) 2005-2009 Greg Couch * See the LICENSE file for copyright details. */ #pragma clang diagnostic ignored "-Wdeprecated-declarations" #include "togl.h" #if defined(TOGL_OSMESA) || defined(TOGL_WGL) /* nothing extra to include */ #elif defined(__APPLE__) # include #else # if !defined(TOGL_X11) || !defined(GLX_VERSION_1_4) # include # endif #endif Togl_FuncPtr Togl_GetProcAddr(const char *funcname) { #if defined(TOGL_OSMESA) return (Togl_FuncPtr) OSMesaGetProcAddress(funcname); #elif defined(TOGL_WGL) return (Togl_FuncPtr) wglGetProcAddress(funcname); #elif defined(__APPLE__) char buf[256]; snprintf(buf, sizeof buf - 1, "_%s", funcname); buf[sizeof buf - 1] = '\0'; if (NSIsSymbolNameDefined(buf)) { NSSymbol nssym; nssym = NSLookupAndBindSymbol(buf); if (nssym) return (Togl_FuncPtr) NSAddressOfSymbol(nssym); } return NULL; #else # if defined(TOGL_X11) && defined(GLX_VERSION_1_4) /* Strictly speaking, we can only call glXGetProcAddress if glXQueryVersion * says we're using version 1.4 or later. */ return (Togl_FuncPtr) glXGetProcAddress(funcname); # else /* Linux, IRIX, OSF/1, ? */ static void *dlHandle = NULL; if (dlHandle == NULL) dlHandle = dlopen(NULL, RTLD_LAZY); /* Strictly speaking, the following cast of a data pointer to a function * pointer is not legal in ISO C, but we don't have any choice. */ return (Togl_FuncPtr) dlsym(dlHandle, funcname); # endif #endif } ================================================ FILE: ng/Togl2.1/toglStubInit.c ================================================ /* * Togl - a Tk OpenGL widget * * Copyright (C) 1996-2002 Brian Paul and Ben Bederson * Copyright (C) 2005-2009 Greg Couch * See the LICENSE file for copyright details. */ #include "togl.h" extern const ToglStubs toglStubs; /* !BEGIN!: Do not edit below this line. */ const ToglStubs toglStubs = { TCL_STUB_MAGIC, NULL, Togl_Init, /* 0 */ Togl_MakeCurrent, /* 1 */ Togl_PostRedisplay, /* 2 */ Togl_SwapBuffers, /* 3 */ Togl_Ident, /* 4 */ Togl_Width, /* 5 */ Togl_Height, /* 6 */ Togl_Interp, /* 7 */ Togl_TkWin, /* 8 */ Togl_CommandName, /* 9 */ Togl_AllocColor, /* 10 */ Togl_FreeColor, /* 11 */ Togl_SetColor, /* 12 */ Togl_LoadBitmapFont, /* 13 */ Togl_UnloadBitmapFont, /* 14 */ Togl_UseLayer, /* 15 */ Togl_ShowOverlay, /* 16 */ Togl_HideOverlay, /* 17 */ Togl_PostOverlayRedisplay, /* 18 */ Togl_ExistsOverlay, /* 19 */ Togl_GetOverlayTransparentValue, /* 20 */ Togl_IsMappedOverlay, /* 21 */ Togl_AllocColorOverlay, /* 22 */ Togl_FreeColorOverlay, /* 23 */ Togl_GetClientData, /* 24 */ Togl_SetClientData, /* 25 */ Togl_DrawBuffer, /* 26 */ Togl_Clear, /* 27 */ Togl_Frustum, /* 28 */ Togl_GetToglFromObj, /* 29 */ Togl_TakePhoto, /* 30 */ Togl_GetProcAddr, /* 31 */ Togl_GetToglFromName, /* 32 */ Togl_SwapInterval, /* 33 */ Togl_Ortho, /* 34 */ Togl_NumEyes, /* 35 */ Togl_ContextTag, /* 36 */ Togl_UpdatePending, /* 37 */ Togl_WriteObj, /* 38 */ Togl_WriteChars, /* 39 */ Togl_HasRGBA, /* 40 */ Togl_IsDoubleBuffered, /* 41 */ Togl_HasDepthBuffer, /* 42 */ Togl_HasAccumulationBuffer, /* 43 */ Togl_HasDestinationAlpha, /* 44 */ Togl_HasStencilBuffer, /* 45 */ Togl_StereoMode, /* 46 */ Togl_HasMultisample, /* 47 */ Togl_CopyContext, /* 48 */ }; /* !END!: Do not edit above this line. */ ================================================ FILE: ng/Togl2.1/toglStubLib.c ================================================ #ifndef USE_TCL_STUBS # define USE_TCL_STUBS #endif #undef USE_TCL_STUB_PROCS #ifndef USE_TK_STUBS # define USE_TK_STUBS #endif #undef USE_TK_STUB_PROCS #include "togl.h" const ToglStubs *toglStubsPtr; /* ** Ensure that Togl_InitStubs is built as an exported symbol. The other stub ** functions should be built as non-exported symbols. */ #undef TCL_STORAGE_CLASS #define TCL_STORAGE_CLASS DLLEXPORT /* * Togl_InitStubs -- * * Checks that the correct version of Togl is loaded and that it * supports stubs. It then initialises the stub table pointers. * * Results: * The actual version of Togl that satisfies the request, or * NULL to indicate that an error occurred. * * Side effects: * sets the stub table pointer. * */ #ifdef Togl_InitStubs # undef Togl_InitStubs #endif const char * Togl_InitStubs(Tcl_Interp *interp, const char *version, int exact) { const char *actualVersion; actualVersion = Tcl_PkgRequireEx(interp, "Togl", version, exact, (ClientData *) &toglStubsPtr); if (!actualVersion) { return NULL; } if (!toglStubsPtr) { Tcl_SetResult(interp, "This implementation of Togl does not support stubs", TCL_STATIC); return NULL; } return actualVersion; } ================================================ FILE: ng/Togl2.1/toglWGL.c ================================================ /* $Id: toglWGL.c,v 1.8 2009/12/23 21:50:49 gregcouch Exp $ */ /* vi:set sw=4 expandtab: */ /* * Togl - a Tk OpenGL widget * * Copyright (C) 1996-2002 Brian Paul and Ben Bederson * Copyright (C) 2005-2009 Greg Couch * See the LICENSE file for copyright details. */ /* TODO: fullscreen support */ #include #include #include #include #include #include #ifndef PFD_SUPPORT_COMPOSITION /* for Vista -- not needed because we don't use PFD_SUPPORT_GDI/BITMAP */ # define PFD_SUPPORT_COMPOSITION 0x00008000 #endif /* TODO: move these statics into global structure */ static PFNWGLGETEXTENSIONSSTRINGARBPROC getExtensionsString = NULL; static PFNWGLCHOOSEPIXELFORMATARBPROC choosePixelFormat; static PFNWGLGETPIXELFORMATATTRIBIVARBPROC getPixelFormatAttribiv; static PFNWGLCREATEPBUFFERARBPROC createPbuffer = NULL; static PFNWGLDESTROYPBUFFERARBPROC destroyPbuffer = NULL; static PFNWGLGETPBUFFERDCARBPROC getPbufferDC = NULL; static PFNWGLRELEASEPBUFFERDCARBPROC releasePbufferDC = NULL; static PFNWGLQUERYPBUFFERARBPROC queryPbuffer = NULL; static int hasMultisampling = FALSE; static int hasPbuffer = FALSE; static int hasARBPbuffer = FALSE; static HWND toglCreateTestWindow(HWND parent) { static char ClassName[] = "ToglTestWindow"; WNDCLASS wc; HINSTANCE instance = GetModuleHandle(NULL); HWND wnd; HDC dc; PIXELFORMATDESCRIPTOR pfd; int pixelFormat; wc.style = CS_OWNDC; wc.lpfnWndProc = DefWindowProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = instance; wc.hIcon = LoadIcon(NULL, IDI_WINLOGO); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = NULL; wc.lpszMenuName = NULL; wc.lpszClassName = ClassName; if (!RegisterClass(&wc)) { DWORD err = GetLastError(); if (err != ERROR_CLASS_ALREADY_EXISTS) { fprintf(stderr, "Unable to register Togl Test Window class\n"); return NULL; } } wnd = CreateWindow(ClassName, "test OpenGL capabilities", WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0, 0, 1, 1, parent, NULL, instance, NULL); if (wnd == NULL) { fprintf(stderr, "Unable to create temporary OpenGL window\n"); return NULL; } dc = GetDC(wnd); memset(&pfd, 0, sizeof pfd); pfd.nSize = sizeof pfd; pfd.nVersion = 1; pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; pfd.iPixelType = PFD_TYPE_RGBA; pfd.cColorBits = 3; pfd.iLayerType = PFD_MAIN_PLANE; pixelFormat = ChoosePixelFormat(dc, &pfd); if (pixelFormat == 0) { fprintf(stderr, "Unable to choose simple pixel format\n"); ReleaseDC(wnd, dc); return NULL; } if (!SetPixelFormat(dc, pixelFormat, &pfd)) { fprintf(stderr, "Unable to set simple pixel format\n"); ReleaseDC(wnd, dc); return NULL; } ShowWindow(wnd, SW_HIDE); // make sure it's hidden ReleaseDC(wnd, dc); return wnd; } struct FBInfo { int stereo; int acceleration; int colors; int depth; int samples; int pixelFormat; }; typedef struct FBInfo FBInfo; static int FBAttribs[] = { /* must match order in FBInfo structure */ WGL_STEREO_ARB, WGL_ACCELERATION_ARB, WGL_COLOR_BITS_ARB, WGL_DEPTH_BITS_ARB, WGL_SAMPLES_ARB, }; #define NUM_FBAttribs (sizeof FBAttribs / sizeof FBAttribs[0]) static int FBInfoCmp(const void *a, const void *b) { /* * 1. stereo is better * 2. full acceleration is better * 3. greater color bits is better * 4. greater depth bits is better * 5. more multisampling is better */ const FBInfo *x = (const FBInfo *) a; const FBInfo *y = (const FBInfo *) b; if (x->stereo != y->stereo) return y->stereo - x->stereo; if (x->acceleration != y->acceleration) return y->acceleration - x->acceleration; if (x->colors != y->colors) return y->colors - x->colors; if (x->depth != y->depth) return y->depth - x->depth; if (x->samples != y->samples) return y->samples - x->samples; return 0; } static int togl_pixelFormat(Togl *togl, HWND hwnd) { /* return 0 when pixel format is unavailable. */ int pixelformat = 0; static int loadedOpenGL = FALSE; int formats[256]; UINT numFormats; FBInfo *info; UINT i; int attribs[128]; int na = 0; if (!loadedOpenGL) { HWND test = NULL; HDC dc; HGLRC rc; if (wglGetCurrentContext() != NULL) { dc = wglGetCurrentDC(); } else { /* HWND hwnd = Tk_GetHWND(Tk_WindowId(togl->TkWin)); */ test = toglCreateTestWindow(hwnd); if (test == NULL) { Tcl_SetResult(togl->Interp, TCL_STUPID "can't create dummy OpenGL window", TCL_STATIC); return 0; } dc = GetDC(test); rc = wglCreateContext(dc); wglMakeCurrent(dc, rc); } loadedOpenGL = TRUE; /* * Now that we have an OpenGL window, we can initialize all * OpenGL information and figure out if multisampling is supported. */ getExtensionsString = (PFNWGLGETEXTENSIONSSTRINGARBPROC) wglGetProcAddress("wglGetExtensionsStringARB"); if (getExtensionsString == NULL) getExtensionsString = (PFNWGLGETEXTENSIONSSTRINGARBPROC) wglGetProcAddress("wglGetExtensionsStringEXT"); if (getExtensionsString) { const char *extensions = getExtensionsString(dc); if (strstr(extensions, "WGL_ARB_multisample") != NULL || strstr(extensions, "WGL_EXT_multisample") != NULL) hasMultisampling = TRUE; if (strstr(extensions, "WGL_ARB_pixel_format") != NULL) { choosePixelFormat = (PFNWGLCHOOSEPIXELFORMATARBPROC) wglGetProcAddress("wglChoosePixelFormatARB"); getPixelFormatAttribiv = (PFNWGLGETPIXELFORMATATTRIBIVARBPROC) wglGetProcAddress("wglGetPixelFormatAttribivARB"); if (choosePixelFormat == NULL || getPixelFormatAttribiv == NULL) { choosePixelFormat = NULL; getPixelFormatAttribiv = NULL; } } if (choosePixelFormat == NULL && strstr(extensions, "WGL_EXT_pixel_format") != NULL) { choosePixelFormat = (PFNWGLCHOOSEPIXELFORMATARBPROC) wglGetProcAddress("wglChoosePixelFormatEXT"); getPixelFormatAttribiv = (PFNWGLGETPIXELFORMATATTRIBIVARBPROC) wglGetProcAddress("wglGetPixelFormatAttribivEXT"); if (choosePixelFormat == NULL || getPixelFormatAttribiv == NULL) { choosePixelFormat = NULL; getPixelFormatAttribiv = NULL; } } if (createPbuffer == NULL && strstr(extensions, "WGL_ARB_pbuffer") != NULL) { createPbuffer = (PFNWGLCREATEPBUFFERARBPROC) wglGetProcAddress("wglCreatePbufferARB"); destroyPbuffer = (PFNWGLDESTROYPBUFFERARBPROC) wglGetProcAddress("wglDestroyPbufferARB"); getPbufferDC = (PFNWGLGETPBUFFERDCARBPROC) wglGetProcAddress("wglGetPbufferDCARB"); releasePbufferDC = (PFNWGLRELEASEPBUFFERDCARBPROC) wglGetProcAddress("wglReleasePbufferDCARB"); queryPbuffer = (PFNWGLQUERYPBUFFERARBPROC) wglGetProcAddress("wglQueryPbufferARB"); if (createPbuffer == NULL || destroyPbuffer == NULL || getPbufferDC == NULL || releasePbufferDC == NULL || queryPbuffer == NULL) { createPbuffer = NULL; destroyPbuffer = NULL; getPbufferDC = NULL; releasePbufferDC = NULL; queryPbuffer = NULL; } else { hasPbuffer = TRUE; hasARBPbuffer = TRUE; } } if (createPbuffer == NULL && strstr(extensions, "WGL_EXT_pbuffer") != NULL) { createPbuffer = (PFNWGLCREATEPBUFFERARBPROC) wglGetProcAddress("wglCreatePbufferEXT"); destroyPbuffer = (PFNWGLDESTROYPBUFFERARBPROC) wglGetProcAddress("wglDestroyPbufferEXT"); getPbufferDC = (PFNWGLGETPBUFFERDCARBPROC) wglGetProcAddress("wglGetPbufferDCEXT"); releasePbufferDC = (PFNWGLRELEASEPBUFFERDCARBPROC) wglGetProcAddress("wglReleasePbufferDCEXT"); queryPbuffer = (PFNWGLQUERYPBUFFERARBPROC) wglGetProcAddress("wglQueryPbufferEXT"); if (createPbuffer == NULL || destroyPbuffer == NULL || getPbufferDC == NULL || releasePbufferDC == NULL || queryPbuffer == NULL) { createPbuffer = NULL; destroyPbuffer = NULL; getPbufferDC = NULL; releasePbufferDC = NULL; queryPbuffer = NULL; } else { hasPbuffer = TRUE; } } } /* No need to confirm multisampling is in glGetString(GL_EXTENSIONS) * because OpenGL driver is local */ if (test != NULL) { /* cleanup by removing temporary OpenGL window */ wglMakeCurrent(NULL, NULL); wglDeleteContext(rc); ReleaseDC(test, dc); DestroyWindow(test); } } if (togl->MultisampleFlag && !hasMultisampling) { Tcl_SetResult(togl->Interp, TCL_STUPID "multisampling not supported", TCL_STATIC); return 0; } if (togl->PbufferFlag && !hasPbuffer) { Tcl_SetResult(togl->Interp, TCL_STUPID "pbuffers are not supported", TCL_STATIC); return 0; } if (choosePixelFormat == NULL) { PIXELFORMATDESCRIPTOR pfd; /* Don't have the great wglChoosePixelFormatARB() function, so do it * the old way. */ if (togl->MultisampleFlag) { Tcl_SetResult(togl->Interp, TCL_STUPID "multisampling not supported", TCL_STATIC); return 0; } memset(&pfd, 0, sizeof pfd); pfd.nSize = sizeof pfd; pfd.nVersion = 1; pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_SUPPORT_COMPOSITION; if (togl->DoubleFlag) { pfd.dwFlags |= PFD_DOUBLEBUFFER; } if (togl->Stereo == TOGL_STEREO_NATIVE) { pfd.dwFlags |= PFD_STEREO; } pfd.iPixelType = togl->RgbaFlag ? PFD_TYPE_RGBA : PFD_TYPE_COLORINDEX; pfd.cColorBits = togl->RgbaRed + togl->RgbaGreen + togl->RgbaBlue; /* Alpha bitplanes are not supported in the current generic OpenGL * implementation, but may be supported by specific hardware devices. */ pfd.cAlphaBits = togl->AlphaFlag ? togl->AlphaSize : 0; pfd.cAccumBits = togl->AccumFlag ? (togl->AccumRed + togl->AccumGreen + togl->AccumBlue + togl->AccumAlpha) : 0; pfd.cDepthBits = togl->DepthFlag ? togl->DepthSize : 0; pfd.cStencilBits = togl->StencilFlag ? togl->StencilSize : 0; /* Auxiliary buffers are not supported in the current generic OpenGL * implementation, but may be supported by specific hardware devices. */ pfd.cAuxBuffers = togl->AuxNumber; pfd.iLayerType = PFD_MAIN_PLANE; if ((pixelformat = ChoosePixelFormat(togl->tglGLHdc, &pfd)) == 0) { Tcl_SetResult(togl->Interp, TCL_STUPID "couldn't choose pixel format", TCL_STATIC); return 0; } /* double check that we got the stereo format we requested */ if (togl->Stereo == TOGL_STEREO_NATIVE) { DescribePixelFormat(togl->tglGLHdc, pixelformat, sizeof (pfd), &pfd); if ((pfd.dwFlags & PFD_STEREO) == 0) { Tcl_SetResult(togl->Interp, TCL_STUPID "couldn't choose stereo pixel format", TCL_STATIC); return 0; } } return pixelformat; } // We have the new wglChoosePixelFormat!! if (togl->MultisampleFlag && !hasMultisampling) { Tcl_SetResult(togl->Interp, TCL_STUPID "multisampling not supported", TCL_STATIC); return 0; } if (togl->PbufferFlag) attribs[na++] = WGL_DRAW_TO_PBUFFER_ARB; else attribs[na++] = WGL_DRAW_TO_WINDOW_ARB; attribs[na++] = GL_TRUE; attribs[na++] = WGL_SUPPORT_OPENGL_ARB; attribs[na++] = GL_TRUE; attribs[na++] = WGL_PIXEL_TYPE_ARB; if (!togl->RgbaFlag) { attribs[na++] = WGL_TYPE_COLORINDEX_ARB; } else { attribs[na++] = WGL_TYPE_RGBA_ARB; attribs[na++] = WGL_RED_BITS_ARB; attribs[na++] = togl->RgbaRed; attribs[na++] = WGL_GREEN_BITS_ARB; attribs[na++] = togl->RgbaGreen; attribs[na++] = WGL_BLUE_BITS_ARB; attribs[na++] = togl->RgbaBlue; if (togl->AlphaFlag) { attribs[na++] = WGL_ALPHA_BITS_ARB; attribs[na++] = togl->AlphaSize; } } if (togl->DepthFlag) { attribs[na++] = WGL_DEPTH_BITS_ARB; attribs[na++] = togl->DepthSize; } if (togl->DoubleFlag) { attribs[na++] = WGL_DOUBLE_BUFFER_ARB; attribs[na++] = GL_TRUE; } if (togl->StencilFlag) { attribs[na++] = WGL_STENCIL_BITS_ARB; attribs[na++] = togl->StencilSize; } if (togl->AccumFlag) { attribs[na++] = WGL_ACCUM_RED_BITS_ARB; attribs[na++] = togl->AccumRed; attribs[na++] = WGL_ACCUM_GREEN_BITS_ARB; attribs[na++] = togl->AccumGreen; attribs[na++] = WGL_ACCUM_BLUE_BITS_ARB; attribs[na++] = togl->AccumBlue; if (togl->AlphaFlag) { attribs[na++] = WGL_ACCUM_ALPHA_BITS_ARB; attribs[na++] = togl->AccumAlpha; } } if (togl->Stereo == TOGL_STEREO_NATIVE) { attribs[na++] = WGL_STEREO_ARB; attribs[na++] = GL_TRUE; } if (togl->MultisampleFlag) { attribs[na++] = WGL_SAMPLE_BUFFERS_ARB; attribs[na++] = 1; attribs[na++] = WGL_SAMPLES_ARB; attribs[na++] = 2; } if (togl->AuxNumber) { attribs[na++] = WGL_AUX_BUFFERS_ARB; attribs[na++] = togl->AuxNumber; } attribs[na++] = 0; // must be last if (!choosePixelFormat(togl->tglGLHdc, &attribs[0], NULL, 256, formats, &numFormats) || numFormats == 0) { Tcl_SetResult(togl->Interp, TCL_STUPID "couldn't choose pixel format", TCL_STATIC); return 0; } /* * Pick best format */ info = (FBInfo *) malloc(numFormats * sizeof (FBInfo)); for (i = 0; i != numFormats; ++i) { info[i].pixelFormat = formats[i]; getPixelFormatAttribiv(togl->tglGLHdc, formats[i], 0, NUM_FBAttribs, FBAttribs, &info[i].stereo); /* revise attributes so larger is better */ if (!togl->DepthFlag) info[i].depth = -info[i].depth; if (!togl->MultisampleFlag) info[i].samples = -info[i].samples; if (togl->Stereo != TOGL_STEREO_NATIVE) info[i].stereo = -info[i].stereo; } qsort(info, numFormats, sizeof info[0], FBInfoCmp); pixelformat = info[0].pixelFormat; /* double check that we got the stereo format we requested */ if (togl->Stereo == TOGL_STEREO_NATIVE && !info[0].stereo) { Tcl_SetResult(togl->Interp, TCL_STUPID "couldn't choose stereo pixel format", TCL_STATIC); free(info); return 0; } free(info); return pixelformat; } static int togl_describePixelFormat(Togl *togl) { if (getPixelFormatAttribiv == NULL) { PIXELFORMATDESCRIPTOR pfd; DescribePixelFormat(togl->tglGLHdc, (int) togl->PixelFormat, sizeof (pfd), &pfd); /* fill in flags normally passed in that affect behavior */ togl->RgbaFlag = pfd.iPixelType == PFD_TYPE_RGBA; togl->DoubleFlag = (pfd.dwFlags & PFD_DOUBLEBUFFER) != 0; togl->DepthFlag = (pfd.cDepthBits != 0); togl->AccumFlag = (pfd.cAccumBits != 0); togl->AlphaFlag = (pfd.cAlphaBits != 0); togl->StencilFlag = (pfd.cStencilBits != 0); if ((pfd.dwFlags & PFD_STEREO) != 0) togl->Stereo = TOGL_STEREO_NATIVE; else togl->Stereo = TOGL_STEREO_NONE; } else { static int attribs[] = { WGL_PIXEL_TYPE_ARB, WGL_DOUBLE_BUFFER_ARB, WGL_DEPTH_BITS_ARB, WGL_ACCUM_RED_BITS_ARB, WGL_ALPHA_BITS_ARB, WGL_STENCIL_BITS_ARB, WGL_STEREO_ARB, WGL_SAMPLES_ARB }; #define NUM_ATTRIBS (sizeof attribs / sizeof attribs[0]) int info[NUM_ATTRIBS]; getPixelFormatAttribiv(togl->tglGLHdc, (int) togl->PixelFormat, 0, NUM_ATTRIBS, attribs, info); #undef NUM_ATTRIBS togl->RgbaFlag = info[0]; togl->DoubleFlag = info[1]; togl->DepthFlag = (info[2] != 0); togl->AccumFlag = (info[3] != 0); togl->AlphaFlag = (info[4] != 0); togl->StencilFlag = (info[5] != 0); togl->Stereo = info[6] ? TOGL_STEREO_NATIVE : TOGL_STEREO_NONE; togl->MultisampleFlag = (info[7] != 0); } return True; } static HPBUFFERARB togl_createPbuffer(Togl *togl) { int attribs[32]; int na = 0; HPBUFFERARB pbuf; if (togl->LargestPbufferFlag) { attribs[na++] = WGL_PBUFFER_LARGEST_ARB; attribs[na++] = 1; } attribs[na] = 0; pbuf = createPbuffer(togl->tglGLHdc, (int) togl->PixelFormat, togl->Width, togl->Height, attribs); if (pbuf && togl->LargestPbufferFlag) { queryPbuffer(pbuf, WGL_PBUFFER_WIDTH_ARB, &togl->Width); queryPbuffer(pbuf, WGL_PBUFFER_HEIGHT_ARB, &togl->Height); } return pbuf; } static void togl_destroyPbuffer(Togl *togl) { destroyPbuffer(togl->pbuf); } #if 0 // From nvidia.com Multisampling requires WGL_ARB_extension_string and WGL_ARB_pixel_format wglGetProcAddress("wglGetExtensionsStringARB") // From msdn.microsoft.com, various ways to enumerate PixelFormats void CPixForm::OnClickedLastPfd() { COpenGL gl; PIXELFORMATDESCRIPTOR pfd; // // Get the hwnd of the view window. // HWND hwndview = GetViewHwnd(); // // Get a DC associated with the view window. // HDC dc =::GetDC(hwndview); int nID = (m_nNextID > 1) ? m_nNextID-- : 1; // // Get a description of the pixel format. If it is valid, then go and // update the controls in the dialog box, otherwise do nothing. // if (gl.DescribePixelFormat(dc, nID, sizeof (PIXELFORMATDESCRIPTOR), &pfd)) UpdateDlg(&pfd); // // Release the DC. // ::ReleaseDC(hwndview, dc); } ---------------------- // local variables int iMax; PIXELFORMATDESCRIPTOR pfd; int iPixelFormat; // initialize a pixel format index variable iPixelFormat = 1; // keep obtaining and examining pixel format data... do { // try to obtain some pixel format data iMax = DescribePixelFormat(dc, iPixelFormat, sizeof (pfd), &pfd); // if there was some problem with that... if (iMax == 0) // return indicating failure return (FALSE); // we have successfully obtained pixel format data // let's examine the pixel format data... myPixelFormatExaminer(&pfd); } // ...until we've looked at all the device context's pixel formats while (++iPixelFormat <= iMax); #endif ================================================ FILE: ng/Togl2.1/togl_ws.h.in ================================================ #ifndef TOGL_WS_H # define TOGL_WS_H /* define windowing system togl is compiled with */ # define @TOGL_WINDOWINGSYSTEM@ #endif ================================================ FILE: ng/Togl2.1/toglpy.h ================================================ /* * getToglFromWidget: * * Given a Python widget, get the corresponding Togl pointer. * and should be included before this. If included into a C file, * there should be a static keyword just before the include. * * There should be one copy of getToglFromWidget per-shared library so that * the library's Tcl/Tk/Togl stub pointers are properly initialized. * * Copyright (C) 2006 Greg Couch * See the LICENSE file for copyright details. */ Togl * getToglFromWidget(PyObject *widget) { PyObject *cmdNameObj, *tk, *interpAddr; const char *cmdName; Tcl_Interp *interp; Togl *curTogl; #ifdef USE_TOGL_STUBS static int didOnce = 0; #endif /* Python: cmdName = widget._w */ /* Python: interpAddr = widget.tk.interpaddr() */ cmdNameObj = PyObject_GetAttrString(widget, "_w"); tk = PyObject_GetAttrString(widget, "tk"); if (cmdNameObj == NULL || !PyString_Check(cmdNameObj) || tk == NULL) { Py_XDECREF(cmdNameObj); Py_XDECREF(tk); #ifdef __cplusplus throw std::invalid_argument("not a Tk widget"); #else return NULL; #endif } interpAddr = PyEval_CallMethod(tk, "interpaddr", "()"); if (interpAddr == NULL || !PyInt_Check(interpAddr)) { Py_DECREF(cmdNameObj); Py_DECREF(tk); Py_XDECREF(interpAddr); #ifdef __cplusplus throw std::invalid_argument("not a Tk widget"); #else return NULL; #endif } cmdName = PyString_AsString(cmdNameObj); interp = (Tcl_Interp *) PyInt_AsLong(interpAddr); #ifdef USE_TOGL_STUBS if (!didOnce) { /* make sure stubs are initialized before calling a Togl function. */ if (Tcl_InitStubs(interp, TCL_VERSION, 0) == NULL || Tk_InitStubs(interp, TK_VERSION, 0) == NULL || Togl_InitStubs(interp, TOGL_VERSION, 0) == NULL) # ifdef __cplusplus throw std::runtime_error("unable to initialize Togl"); # else return NULL; # endif didOnce = 1; } #endif if (Togl_GetToglFromName(interp, cmdName, &curTogl) != TCL_OK) curTogl = NULL; Py_DECREF(cmdNameObj); Py_DECREF(tk); Py_DECREF(interpAddr); #ifdef __cplusplus if (curTogl == NULL) throw std::invalid_argument("not a Togl widget"); #endif return curTogl; } ================================================ FILE: ng/acisgeom.tcl ================================================ if { [Ng_ACISCommand isACISavailable] == "yes" } { .ngmenu.geometry add command -label "ACIS Topology Explorer..." \ -command { acisdialog; } .ngmenu.geometry add command -label "ACIS combine all" \ -command { Ng_ACISCommand combineall } .ngmenu.geometry add command -label "ACIS Create CT" \ -command { Ng_ACISCommand createct } } ================================================ FILE: ng/csgeom.tcl ================================================ .ngmenu.geometry add command -label "Scan CSG Geometry" -command { Ng_ParseGeometry } .ngmenu.geometry add command -label "CSG Options..." -command geometryoptionsdialog # only intern version ! # .ngmenu.geometry add separator # .ngmenu.geometry add command -label "New Primitive" \ # -command newprimitivedialog -accelerator "

" # .ngmenu.geometry add command -label "Edit Primitive" \ # -command editprimitivedialog -accelerator "

" # .ngmenu.geometry add command -label "Edit Solid" \ # -command newsoliddialog -accelerator "" # .ngmenu.geometry add command -label "Choose Top Level " \ # -command topleveldialog # .ngmenu.geometry add command -label "Identify" \ # -command identifydialog .ngmenu.geometry add command -label "CSG Properties..." \ -command topleveldialog2 proc geometryoptionsdialog { } { set w .geometry_dlg if {[winfo exists .geometry_dlg] == 1} { wm withdraw $w wm deiconify $w focus $w } { toplevel $w global geooptions Ng_GeometryOptions get checkbutton $w.drawcsg -text "Draw Geometry" \ -variable geooptions.drawcsg pack $w.drawcsg frame $w.fac pack $w.fac -pady 5 ttk::label $w.fac.lab -text "Facets:"; entry $w.fac.ent -width 8 -relief sunken \ -textvariable geooptions.facets pack $w.fac.lab $w.fac.ent -side left frame $w.det pack $w.det -pady 5 ttk::label $w.det.lab -text "Detail:"; entry $w.det.ent -width 8 -relief sunken \ -textvariable geooptions.detail pack $w.det.lab $w.det.ent -side left frame $w.cox pack $w.cox -pady 5 ttk::label $w.cox.lab -text "min/max x:"; entry $w.cox.ent1 -width 8 -relief sunken \ -textvariable geooptions.minx entry $w.cox.ent2 -width 8 -relief sunken \ -textvariable geooptions.maxx pack $w.cox.lab $w.cox.ent1 \ $w.cox.ent2 -side left frame $w.coy pack $w.coy -pady 5 ttk::label $w.coy.lab -text "min/max y:"; entry $w.coy.ent1 -width 8 -relief sunken \ -textvariable geooptions.miny entry $w.coy.ent2 -width 8 -relief sunken \ -textvariable geooptions.maxy pack $w.coy.lab $w.coy.ent1 \ $w.coy.ent2 -side left frame $w.coz pack $w.coz -pady 5 ttk::label $w.coz.lab -text "min/max z:"; entry $w.coz.ent1 -width 8 -relief sunken \ -textvariable geooptions.minz entry $w.coz.ent2 -width 8 -relief sunken \ -textvariable geooptions.maxz pack $w.coz.lab $w.coz.ent1 \ $w.coz.ent2 -side left # tixButtonBox $w.bbox -orientation horizontal # $w.bbox add ok -text Apply -underline 0 -width 5 \ # -command { Ng_GeometryOptions set } # $w.bbox add close -text Done -underline 0 -width 5 \ # -command { # Ng_GeometryOptions set # destroy .geometry_dlg # } # pack $w.bbox -side bottom -fill x frame $w.bu pack $w.bu -fill x -ipady 3 ttk::button $w.bu.app -text "Apply" -command { Ng_GeometryOptions set } ttk::button $w.bu.ok -text "Done" -command { Ng_GeometryOptions set destroy .geometry_dlg } pack $w.bu.app $w.bu.ok -side left -expand yes wm withdraw $w wm geom $w +100+100 wm deiconify $w wm title $w "Geometry options" focus $w } } # # # Edit primitive # # proc editprimitivedialog2 { name } { global w classname set w .ep_dlg toplevel .$w Ng_GetPrimitiveData $name classname valuelist ttk::label $w.lab1 -text "Primitive Name: $name"; ttk::label $w.lab2 -text "Primitive Class: $classname"; pack $w.lab1 $w.lab2 -fill x -pady 1m -padx 5m frame $w.specific -relief groove global spec set spec(sphere) { cx cy cz rad } set spec(cylinder) { ax ay az bx by bz rad } set spec(plane) { px py pz nx ny nz } set spec(cone) { ax ay az bx by bz ra rb } set spec(brick) { p1x p1y p1z p2x p2y p2z p3x p3y p3z p4x p4y p4z } set cnt 0 foreach field $spec($classname) { frame $w.specific.f$cnt pack $w.specific.f$cnt -side top -anchor ne ttk::label $w.specific.f$cnt.lab -text "$field" entry $w.specific.f$cnt.ent -textvariable dataval($cnt) \ -width 6 -relief sunken pack $w.specific.f$cnt.ent $w.specific.f$cnt.lab -side right $w.specific.f$cnt.ent delete 0 end $w.specific.f$cnt.ent insert 0 [lindex $valuelist $cnt] set cnt [expr $cnt + 1] } pack $w.specific ttk::button $w.cancel -text "cancel" -command { destroy $w } ttk::button $w.ok -text "ok" -command { set valuelist "" set cnt 0 foreach field $spec($classname) { lappend valuelist $dataval($cnt) set cnt [expr $cnt + 1] } Ng_SetPrimitiveData $name $valuelist destroy $w } pack $w.cancel $w.ok -side left -expand yes bind $w { $w.ok invoke} bind $w { $w.cancel invoke} wm withdraw $w wm geom $w +100+100 wm deiconify $w # grab $w focus $w.specific.f0.ent } # # # Select primitive to edit # # proc editprimitivedialog { } { global w set w .ep_dlg toplevel $w frame $w.frame -borderwidth 5m pack $w.frame -side top -expand yes -fill y listbox $w.frame.list -yscroll "$w.frame.scroll set" -setgrid 1 -height 12 scrollbar $w.frame.scroll -command "$w.frame.list yview" pack $w.frame.scroll -side right -fill y pack $w.frame.list -side left -expand 1 -fill both Ng_GetPrimitiveList primlist foreach el $primlist { $w.frame.list insert end $el } ttk::button $w.cancel -text "cancel" -command { destroy $w } ttk::button $w.ok -text "ok" -command { set name [.ep_dlg.frame.list get active] puts "name=($name)" destroy $w if { $name != "" } { editprimitivedialog2 $name } } bind $w { $w.cancel invoke } bind $w { $w.ok invoke } pack $w.cancel $w.ok -side left -expand yes wm withdraw $w wm geom $w +100+100 wm deiconify $w # grab $w focus $w.frame.list } # # # Create new primitive # # proc newprimitivedialog { } { global w name set w .ap_dlg toplevel $w set name "" frame $w.f1 pack $w.f1 -pady 2m ttk::label $w.f1.lab -text "Primitive Name: "; entry $w.f1.ent -width 5 -relief sunken \ -textvariable name pack $w.f1.lab $w.f1.ent -side left frame $w.frame -borderwidth .5c pack $w.frame -side top -expand yes -fill y listbox $w.frame.list -yscroll "$w.frame.scroll set" -setgrid 1 -height 8 scrollbar $w.frame.scroll -command "$w.frame.list yview" pack $w.frame.scroll -side right -fill y pack $w.frame.list -side left -expand 1 -fill both $w.frame.list insert 0 sphere cylinder plane cone brick $w.frame.list activate 0 ttk::button $w.ok -text "ok" -command { Ng_CreatePrimitive [$w.frame.list get active] $name destroy $w editprimitivedialog2 $name } ttk::button $w.cancel -text "cancel" -command { destroy $w } pack $w.cancel $w.ok -side left -expand yes -pady 2m bind $w { $w.cancel invoke } bind $w { $w.ok invoke } wm withdraw $w wm geom $w +100+100 wm deiconify $w # grab $w focus $w.f1.ent } proc newsoliddialog { } { global w name val sollist set w .ns_dlg toplevel $w set name "" frame $w.f1 ttk::label $w.f1.lab -text "Solid Name: "; entry $w.f1.ent -width 5 -relief sunken \ -textvariable name $w.f1.ent delete 0 end ttk::button $w.f1.getsel -text "Get Selected" -command { $w.f1.ent delete 0 end $w.f1.ent insert 0 [$w.f3.list get active] $w.bu.get invoke } pack $w.f1.getsel -side bottom pack $w.f1.ent $w.f1.lab -side right frame $w.f3 -borderwidth .5c listbox $w.f3.list -yscroll "$w.f3.scroll set" -setgrid 1 -height 12 scrollbar $w.f3.scroll -command "$w.f3.list yview" pack $w.f3.scroll -side right -fill y pack $w.f3.list -side left -expand 1 -fill both Ng_GetSolidList sollist foreach el $sollist { $w.f3.list insert end $el } frame $w.f2 ttk::label $w.f2.lab -text "Solid Description: "; pack $w.f2.lab entry $w.f2.ent -width 100 -relief sunken \ -textvariable val -xscrollcommand "$w.f2.scr set" scrollbar $w.f2.scr -relief sunken -orient horiz -command \ "$w.f2.ent xview" $w.f2.ent delete 0 end pack $w.f2.ent $w.f2.scr -fill x frame $w.bu ttk::button $w.bu.close -text "close" -command { destroy $w } ttk::button $w.bu.get -text "get data" -command { Ng_GetSolidData $name val } ttk::button $w.bu.set -text "set data" -command { Ng_SetSolidData $name $val } pack $w.bu.get $w.bu.set $w.bu.close -side left pack $w.bu -pady 5 -side bottom ;# buttons pack $w.f2 -pady 5 -side bottom ;# edit field pack $w.f1 -pady 5 -side left ;# name pack $w.f3 -side left -expand yes -fill y ;# listbox bind $w { $w.bu.close invoke } wm withdraw $w wm geom $w +100+100 wm deiconify $w # grab $w focus $w } # # Edit top level objects # # proc toplevelproperties { w solname surfname } { global properties Ng_TopLevel getprop $solname $surfname properties set w .tlprop_dlg if {[winfo exists $w] == 1} { wm withdraw $w wm deiconify $w focus $w } { toplevel $w ttk::label $w.lab1 -text "Red" scale $w.scale1 -orient horizontal -length 300 -from 0 -to 1 \ -resolution 0.01 -tickinterval 0.2 \ -command { Ng_TopLevel setprop $solname $surfname properties; redraw } -variable properties(red) ttk::label $w.lab2 -text "Green" scale $w.scale2 -orient horizontal -length 300 -from 0 -to 1 \ -resolution 0.01 -tickinterval 0.2 \ -command { Ng_TopLevel setprop $solname $surfname properties; redraw } -variable properties(green) ttk::label $w.lab3 -text "Blue" scale $w.scale3 -orient horizontal -length 300 -from 0 -to 1 \ -resolution 0.01 -tickinterval 0.2 \ -command { Ng_TopLevel setprop $solname $surfname properties; redraw } -variable properties(blue) pack $w.lab1 $w.scale1 $w.lab2 $w.scale2 $w.lab3 $w.scale3 checkbutton $w.cb4 -text "Visible" \ -command { Ng_TopLevel setprop $solname $surfname properties; redraw } \ -variable properties(visible) checkbutton $w.cb5 -text "Transparent" \ -command { Ng_TopLevel setprop $solname $surfname properties; redraw } \ -variable properties(transp) pack $w.cb4 $w.cb5 frame $w.bu pack $w.bu -fill x ttk::button $w.bu.ok -text "Ok" -command "destroy .tlprop_dlg" pack $w.bu.ok -expand yes wm withdraw $w wm geom $w +100+100 wm deiconify $w focus $w } wm title $w "Properties $solname $surfname" } proc topleveldialog { } { global w name val sollist set w .tl_dlg toplevel $w frame $w.sol -borderwidth .5c listbox $w.sol.list -yscroll "$w.sol.scroll set" -setgrid 1 -height 12 scrollbar $w.sol.scroll -command "$w.sol.list yview" pack $w.sol.scroll -side right -fill y pack $w.sol.list -side left -expand 1 -fill both Ng_GetSolidList sollist foreach el $sollist { $w.sol.list insert end $el } Ng_GetPrimitiveList sollist foreach el $sollist { $w.sol.list insert end $el } frame $w.sul -borderwidth .5c listbox $w.sul.list -yscroll "$w.sul.scroll set" -setgrid 1 -height 12 scrollbar $w.sul.scroll -command "$w.sul.list yview" pack $w.sul.scroll -side right -fill y pack $w.sul.list -side left -expand 1 -fill both Ng_GetSurfaceList sollist foreach el $sollist { $w.sul.list insert end $el } frame $w.topl -borderwidth .5c listbox $w.topl.list -yscroll "$w.topl.scroll set" -setgrid 1 -height 12 \ -command { puts hi } scrollbar $w.topl.scroll -command "$w.topl.list yview" pack $w.topl.scroll -side right -fill y pack $w.topl.list -side left -expand 1 -fill both Ng_TopLevel getlist sollist puts $sollist foreach el $sollist { set hel "[ lindex $el 0 ]" if { [ llength $el ] == 2 } { set hel "[ lindex $el 1 ] on [ lindex $el 0 ]" } $w.topl.list insert end $hel } frame $w.bu ttk::button $w.bu.close -text "close" -command { destroy $w } ttk::button $w.bu.addsol -text "Add Solid" -command { set solname [$w.sol.list get active] Ng_TopLevel set $solname "" Ng_ParseGeometry $w.topl.list insert end $solname } ttk::button $w.bu.addsurf -text "Add Surface" -command { set solname [$w.sol.list get active] set surfname [$w.sul.list get active] Ng_TopLevel set $solname $surfname Ng_ParseGeometry puts "$solname on $surfname" $w.topl.list insert end "$surfname on $solname" } ttk::button $w.bu.remsol -text "Remove" -command { set solname [$w.topl.list get active] set surfname "" if { [llength $solname] == 3 } { set surfname [lindex $solname 0] set solname [lindex $solname 2] } Ng_TopLevel remove $solname $surfname Ng_ParseGeometry $w.topl.list delete active } ttk::button $w.bu.prop -text "Properties" -command { set solname [$w.topl.list get active] set surfname "" if { [llength $solname] == 3 } { set surfname [lindex $solname 0] set solname [lindex $solname 2] } toplevelproperties tlp $solname $surfname } pack $w.bu.close $w.bu.addsol $w.bu.addsurf $w.bu.remsol $w.bu.prop -side left pack $w.bu -side bottom pack $w.sol -side left -expand yes -fill y ;# listbox pack $w.sul -side left -expand yes -fill y ;# listbox pack $w.topl -side left -expand yes -fill y ;# listbox bind $w { $w.bu.close invoke } wm withdraw $w wm geom $w +100+100 wm deiconify $w # grab $w focus $w } proc topleveldialog2 { } { set w .tl2_dlg if {[winfo exists .tl2_dlg] == 1} { wm withdraw $w wm deiconify $w focus $w } { toplevel $w global name val sollist frame $w.topl -borderwidth .5c listbox $w.topl.list -yscroll "$w.topl.scroll set" -setgrid 1 -height 12 scrollbar $w.topl.scroll -command "$w.topl.list yview" pack $w.topl.scroll -side right -fill y pack $w.topl.list -side left -expand 1 -fill both Ng_TopLevel getlist sollist puts $sollist set i 1 foreach el $sollist { set hel "$i: [ lindex $el 0 ]" if { [ llength $el ] == 2 } { set hel "$i: [ lindex $el 1 ] on [ lindex $el 0 ]" } incr i $w.topl.list insert end $hel } frame $w.bu ttk::button $w.bu.close -text "close" -command { destroy .tl2_dlg } ttk::button $w.bu.prop -text "Properties" -command { set solname [.tl2_dlg.topl.list get active] set surfname "" if { [llength $solname] == 2 } { set solname [lindex $solname 1] } if { [llength $solname] == 4 } { set surfname [lindex $solname 1] set solname [lindex $solname 3] } toplevelproperties tlp $solname $surfname } pack $w.bu.close $w.bu.prop -side left pack $w.bu -side bottom pack $w.topl -side left -expand yes -fill y ;# listbox bind .tl2_dlg.topl.list { set solname [.tl2_dlg.topl.list get @%x,%y] set surfname "" if { [llength $solname] == 2 } { set solname [lindex $solname 1] } if { [llength $solname] == 4 } { set surfname [lindex $solname 1] set solname [lindex $solname 3] } toplevelproperties tlp $solname $surfname } bind .tl2_dlg { .tl2_dlg.bu.close invoke } wm withdraw $w wm geom $w +100+100 wm deiconify $w wm title $w "Top-Level Options" focus $w } } ================================================ FILE: ng/demoview.cpp ================================================ /*********************************************************************/ /* File: demoview.cpp */ /* Author: Robert, Joachim */ /* Date: 6. Mar. 2003 */ /*********************************************************************/ #include //#include #include #include #include #include #include #include #include #include "inctcl.hpp" #include namespace netgen { #include "demoview.hpp" /* static demokwstruct defkw[] = { { TOK_TIME, "t" }, { TOK_CAMPOS, "camerapos" }, { TOK_CAMPOINT, "camerapointto" }, { TOK_CAMUP, "cameraup" } }; */ static demoview_kwstruct demoview_defkw[] = { { DTOK_TIME, "t" }, { DTOK_CAMPOS, "camerapos" }, { DTOK_CAMPOINT, "camerapointto" }, { DTOK_CAMUP, "cameraup" } }; DemoScanner :: DemoScanner (ifstream & ascanin) { scanin = &ascanin; token = DTOK_END; num_value = 0; linenum = 1; } void DemoScanner :: ReadNext () { char ch; // whitespaces ueberspringen do { scanin->get(ch); if (ch == '\n') linenum++; // end of file reached if (scanin->eof()) { token = DTOK_END; return; } // skip comment line if (ch == '#') { while (ch != '\n') { scanin->get(ch); if (scanin->eof()) { token = DTOK_END; return; } } linenum++; } } while (isspace(ch)); switch (ch) { case '(': case ')': case '[': case ']': case '-': case ':': case '=': case ',': case ';': case '+': { token = DEMOVIEW_TOKEN_TYPE (ch); break; } default: { if (isdigit (ch) || ch == '.') { scanin->putback (ch); (*scanin) >> num_value; token = DTOK_NUM; return; } if (isalpha (ch)) { string_value = string (1, ch); scanin->get(ch); while (isalnum(ch)) { string_value += ch; scanin->get(ch); } scanin->putback (ch); } int nr = 0; while (demoview_defkw[nr].kw) { if (string_value == demoview_defkw[nr].name) { token = demoview_defkw[nr].kw; return; } nr++; } token = DTOK_STRING; } } } void DemoScanner :: Error (const string & err) { stringstream errstr; errstr << "Parsing error in line " << linenum << ": " << endl << err << endl; throw string(errstr.str()); } void ParseChar (DemoScanner & scan, char ch) { char str[2]; str[0] = ch; str[1] = 0; if (scan.GetToken() != DEMOVIEW_TOKEN_TYPE(ch)) scan.Error (string ("token '") + string(str) + string("' expected")); scan.ReadNext(); } double ParseNumber(DemoScanner & scan) { if (scan.GetToken() == '-') { scan.ReadNext(); return -ParseNumber (scan); } if (scan.GetToken() != DTOK_NUM) scan.Error ("number expected"); double val = scan.GetNumValue(); scan.ReadNext(); return val; } Vec<3> ParseVector (DemoScanner & scan) { Vec<3> s; s(0) = ParseNumber (scan); ParseChar (scan, ','); s(1) = ParseNumber (scan); ParseChar (scan, ','); s(2) = ParseNumber (scan); return s; } void ParseConstLineOrSpline (DemoScanner & scan, double * t, Vec<3> * s) { int np = 1; scan.ReadNext(); ParseChar (scan, '('); t[0] = ParseNumber (scan)*1000; ParseChar (scan, ':'); s[0] = ParseVector (scan); if (scan.GetToken() != DTOK_RP && scan.GetToken() != DTOK_SEMICOLON) scan.Error (") or ; expected"); if (scan.GetToken() == DTOK_SEMICOLON) { np++; scan.ReadNext(); t[1] = ParseNumber (scan)*1000; ParseChar (scan, ':'); s[1] = ParseVector (scan); if (scan.GetToken() != DTOK_RP && scan.GetToken() != DTOK_SEMICOLON) scan.Error (") or ; expected"); if (scan.GetToken() == DTOK_SEMICOLON) { np++; scan.ReadNext(); t[2] = ParseNumber (scan)*1000; ParseChar (scan, ':'); s[2] = ParseVector (scan); ParseChar (scan, ')'); ParseChar (scan, ';'); } else if (scan.GetToken() == DTOK_RP) { scan.ReadNext(); ParseChar (scan, ';'); } } else if (scan.GetToken() == DTOK_RP) { scan.ReadNext(); ParseChar (scan, ';'); } if (np == 1) // constant spline { t[1] = t[2] = t[0]; s[1] = s[2] = s[0]; } if (np == 2) // linear spline { t[2] = t[1]; t[1] = 0.5*(t[0] + t[2]); s[2] = s[1]; s[1] = 0.5*(s[0] + s[2]); } } template void InterpolationSpline :: AddSpline(double t1, double t2, double t3, S s1, S s2, S s3) { int pos, i, j; // find pos to insert interpotation point for (pos = 0; pos < ip.Size() && ip[pos][0].GetT() < t1; pos++) ; ip.SetSize( ip.Size()+1 ); for (i = ip.Size()-2; i >= pos; i--) for (j = 0; j < 3; j++) ip[i+1][j] = ip[i][j]; ip[pos][0].SetTS (t1, s1); ip[pos][1].SetTS (t2, s2); ip[pos][2].SetTS (t3, s3); } template S InterpolationSpline :: Evaluate (double t) { if (t < ip[0][0].GetT()) return (ip[0][0].GetS()); if (t > ip[ip.Size()-1][2].GetT()) { finished = 1; return (ip[ip.Size()-1][2].GetS()); } int pos; for (pos = 0; pos < ip.Size() && t >= ip[pos][0].GetT(); pos++) ; pos--; if (t >= ip[pos][0].GetT() && t <= ip[pos][2].GetT()) { double t0 = ip[pos][0].GetT(); double t1 = ip[pos][2].GetT(); double t01 = (t-t0)/(t1-t0); double b1, b2, b3, w; b1 = (1-t01)*(1-t01); b2 = sqrt(2.0) * t01 * (1-t01); b3 = t01 * t01; w = b1 + b2 + b3; return ( (1/w) * (b1 * ip[pos][0].GetS() + b2 * ip[pos][1].GetS() + b3 * ip[pos][2].GetS()) ); } else return (ip[pos][2].GetS()); } DemoView :: DemoView (const char * filename) : campos( Vec<3>(5,0,0) ), campoint ( Vec<3>(0,0,0) ), camup ( Vec<3>(0,0,1) ) { double time = 0; ifstream istr; istr.open(filename); DemoScanner scan(istr); double t[3]; Vec<3> s[3]; scan.ReadNext(); try { while (1) { if (scan.GetToken() == DTOK_END) break; if (scan.GetToken() == DTOK_CAMPOS) { ParseConstLineOrSpline (scan, &t[0], &s[0]); campos.AddSpline (time+t[0], time+t[1], time+t[2], s[0], s[1], s[2]); } else if (scan.GetToken() == DTOK_CAMUP) { ParseConstLineOrSpline (scan, &t[0], &s[0]); camup.AddSpline (time+t[0], time+t[1], time+t[2], s[0], s[1], s[2]); } else if (scan.GetToken() == DTOK_CAMPOINT) { ParseConstLineOrSpline (scan, &t[0], &s[0]); campoint.AddSpline (time+t[0], time+t[1], time+t[2], s[0], s[1], s[2]); } else if (scan.GetToken() == DTOK_TIME) { scan.ReadNext(); if (scan.GetToken() != DTOK_EQU && scan.GetToken() != DTOK_PLUS) scan.Error ("= or += expected"); if (scan.GetToken() == DTOK_EQU) { scan.ReadNext(); time = ParseNumber (scan)*1000; ParseChar (scan, ';'); } else if (scan.GetToken() == DTOK_PLUS) { scan.ReadNext(); ParseChar (scan, '='); time += ParseNumber (scan)*1000; ParseChar (scan, ';'); } } else { cout << "read unidentified token " << scan.GetToken() << " string = " << scan.GetStringValue() << endl; scan.ReadNext(); } } } catch (string errstr) { cout << "caught error " << errstr << endl; } } DemoView :: ~DemoView () { ; } int DemoView :: SetTime (double time) { /* cout << "time = " << time << endl; cout << "campos : " << campos.Evaluate (time) << endl; cout << "campoint: " << campoint.Evaluate (time) << endl; cout << "camup : " << camup.Evaluate (time) << endl; */ visual_scene -> LookAt ( Point<3>( campos.Evaluate (time)), Point<3>(campoint.Evaluate (time)), Point<3>( camup.Evaluate (time)) ); if (campos.IsFinished() && campoint.IsFinished() && camup.IsFinished()) { return -1; } return 0; } } ================================================ FILE: ng/demoview.hpp ================================================ #ifndef FILE_DEMOVIEW #define FILE_DEMOVIEW /*********************************************************************/ /* File: demoview.hpp */ /* Author: Robert, Joachim */ /* Date: 6. Mar. 2003 */ /*********************************************************************/ using namespace netgen; enum DEMOVIEW_TOKEN_TYPE { DTOK_MINUS = '-', DTOK_LP = '(', DTOK_RP = ')', DTOK_LSP = '[', DTOK_RSP = ']', DTOK_EQU = '=', DTOK_COMMA = ',', DTOK_SEMICOLON = ';', DTOK_COLON = ':', DTOK_PLUS = '+', DTOK_NUM = 100, DTOK_STRING, DTOK_TIME, DTOK_CAMPOS, DTOK_CAMPOINT, DTOK_CAMUP, DTOK_END }; struct demoview_kwstruct { DEMOVIEW_TOKEN_TYPE kw; const char * name; }; class DemoScanner { DEMOVIEW_TOKEN_TYPE token; double num_value; string string_value; int linenum; ifstream * scanin; public: DemoScanner (ifstream & ascanin); DEMOVIEW_TOKEN_TYPE GetToken() const { return token; } double GetNumValue() const { return num_value; } const string & GetStringValue() const { return string_value; } void ReadNext(); void Error (const string & err); }; void ParseChar (DemoScanner & scan, char ch); double ParseNumber(DemoScanner & scan); Vec<3> ParseVector (DemoScanner & scan); template class InterpolationPoint { double t; S s; public: InterpolationPoint() {}; ~InterpolationPoint() {}; double GetT() const { return t; }; S GetS() const { return s; }; void SetTS(double at, S as) { t = at; s = as; }; InterpolationPoint & operator= (const InterpolationPoint & ip2) { SetTS (ip2.t, ip2.s); return (*this); }; }; template class InterpolationSpline { protected: // NgArray < InterpolationPoint[3] > ip; class intpts { public: InterpolationPoint pts[3]; InterpolationPoint & operator[](int i) { return pts[i]; } }; NgArray < intpts > ip; int finished; public: InterpolationSpline() : finished(0) {}; InterpolationSpline( S s1 ) : finished(0) { AddSpline (-1e99, -1e99, -1e99, s1, s1, s1); // InterpolationSpline(); } ~InterpolationSpline() {}; void AddSpline(double t1, double t2, double t3, S s1, S s2, S s3); S Evaluate (double t); int IsFinished() const { return finished; } }; class DemoView { InterpolationSpline< Vec<3> > campos; InterpolationSpline< Vec<3> > campoint; InterpolationSpline< Vec<3> > camup; public: DemoView (const char * filename); ~DemoView (); int SetTime (double time); }; #endif ================================================ FILE: ng/dialog.tcl ================================================ proc meshingoptionsdialog { } { set w .options_dlg if {[winfo exists .options_dlg] == 1} { wm withdraw $w wm deiconify $w focus $w } { toplevel $w #wm resizable $w 0 0 # global options.meshsize pack [ttk::notebook $w.nb] -fill both -side top $w.nb add [ttk::frame $w.nb.general] -text "General" -underline 0 $w.nb add [ttk::frame $w.nb.meshsize] -text "Mesh Size" -underline 0 $w.nb add [ttk::frame $w.nb.chartopt] -text "STL Charts" -underline 0 $w.nb add [ttk::frame $w.nb.optimizer] -text "Optimizer" -underline 0 # $w.nb add [ttk::frame $w.nb.insider] -text "Insider" -underline 0 $w.nb add [ttk::frame $w.nb.debug] -text "Debug" -underline 0 # tixNoteBook $w.nbold -ipadx 6 -ipady 6 # $w.nbold add general -label "General" -underline 0 # $w.nbold add meshsize -label "Mesh Size" -underline 0 # $w.nbold add chartopt -label "STL Charts" -underline 0 # $w.nbold add optimizer -label "Optimizer" -underline 0 # $w.nbold add insider -label "Insider" -underline 0 # $w.nbold add debug -label "Debug" -underline 0 # pack $w.nb -expand yes -fill both -padx 5 -pady 5 -side top # ############################################################ # General meshing options # ############################################################ set f $w.nb.general ttk::frame $f.background pack $f.background -fill both set f $f.background ttk::labelframe $f.f2 -relief groove -borderwidth 3 -text "General meshing options" pack $f.f2 -pady 15 -fill x set f $f.f2 set finevals { 1 2 3 4 5 6 } set finelabs(1) "very coarse" set finelabs(2) "coarse" set finelabs(3) "moderate" set finelabs(4) "fine" set finelabs(5) "very fine" set finelabs(6) "user defined" #tixOptionMenu $f.fine -label "Mesh granularity : " \ -options { # label.width 19 # label.anchor e # menubutton.width 15 # } #foreach finev $finevals { # $f.fine add command $finev -label $finelabs($finev) #} #$f.fine config -variable meshoptions.fineness #$f.fine config -command { setgranularity } #global meshoptions.fineness #setgranularity ${meshoptions.fineness} #pack $f.fine global meshoptions.fineness ttk::label $f.fine2l -text "Mesh granularity: " ttk::menubutton $f.fine2c -menu $f.fine2m -text "coarse" -width 16 menu $f.fine2m -tearoff 0 foreach finev { 1 2 3 4 5 6 } { $f.fine2m add command -label $finelabs($finev) \ -command "set meshoptions.fineness $finev ; setgranularity $finev; $f.fine2c configure -text \"$finelabs($finev)\"" } $f.fine2m invoke $finelabs(${meshoptions.fineness}) grid $f.fine2l $f.fine2c -sticky nw set mgsteps { ag me ms os mv ov } set mgsteplabel(ag) "Analyze Geometry" set mgsteplabel(me) "Mesh Edges" set mgsteplabel(ms) "Mesh Surface" set mgsteplabel(os) "Optimize Surface" set mgsteplabel(mv) "Mesh Volume" set mgsteplabel(ov) "Optimize Volume" global meshoptions.firststep ttk::label $f.first2l -text "First Step: " # ttk::menubutton $f.first2.c -menu $f.first2.m -text "Analyze Geometry" -width 12 ttk::menubutton $f.first2c -menu $f.first2m -width 16 menu $f.first2m -tearoff 0 foreach i $mgsteps { $f.first2m add command -label $mgsteplabel($i) -command "set meshoptions.firststep $i ; $f.first2c configure -text \"$mgsteplabel($i)\"" } $f.first2m invoke $mgsteplabel(${meshoptions.firststep}) grid $f.first2l $f.first2c -sticky nw global meshoptions.laststep ttk::label $f.last2l -text "Last Step: " ttk::menubutton $f.last2c -menu $f.last2m -width 16 menu $f.last2m -tearoff 0 foreach i $mgsteps { $f.last2m add command -label $mgsteplabel($i) -command "set meshoptions.laststep $i ; $f.last2c configure -text \"$mgsteplabel($i)\"" } $f.last2m invoke $mgsteplabel(${meshoptions.laststep}) grid $f.last2l $f.last2c -sticky nw grid anchor $f center # tixOptionMenu $f.first -label "First Step : " \ # -options { # label.width 19 # label.anchor e # menubutton.width 15 # } # tixOptionMenu $f.last -label "Last Step : " \ # -options { # label.width 19 # label.anchor e # menubutton.width 15 # } # foreach step $mgsteps { # $f.first add command $step -label $mgsteplabel($step) # $f.last add command $step -label $mgsteplabel($step) # } # $f.first config -variable meshoptions.firststep # $f.last config -variable meshoptions.laststep # pack $f.first $f.last set msg(0) "None" set msg(1) "Least" set msg(2) "Little" set msg(3) "Moderate" set msg(4) "Much" set msg(5) "Most" #tixOptionMenu $f.msg -label "Print Messages : " \ -options { # label.width 19 # label.anchor e # menubutton.width 15 # } #foreach step {0 1 2 3 4 5 } { # $f.msg add command $step -label $msg($step) #} #$f.msg config -variable options.printmsg # pack $f.msg global options.printmsg #ttk::frame $f.msg2 ttk::label $f.msg2l -text "Print Messages: " menu $f.msg2m -tearoff 0 ttk::menubutton $f.msg2c -menu $f.msg2m -width 16 foreach step {0 1 2 3 4 5 } { $f.msg2m add command -label $msg($step) -command "set options.printmsg $step ; $f.msg2c configure -text $msg($step)" # if { ${options.printmsg} == $step } { $f.msg2.c configure -text $msg($step) } } $f.msg2m invoke ${options.printmsg} grid $f.msg2l $f.msg2c -sticky nw set f $w.nb.general ttk::labelframe $f.bts -borderwidth 3 -relief groove -text "Additional meshing options" pack $f.bts -fill x -pady 15 ttk::frame $f.bts.btnframe ttk::checkbutton $f.bts.btnframe.parthread -text "Separate meshing thread" \ -variable options.parthread ttk::checkbutton $f.bts.btnframe.second -text "Second order elements" \ -variable options.secondorder ttk::checkbutton $f.bts.btnframe.quad -text "Quad dominated" \ -variable options.quad -command { if { ${options.quad} } { set meshoptions.laststep os } } ttk::checkbutton $f.bts.btnframe.invtets -text "Invert volume elements" \ -variable options.inverttets ttk::checkbutton $f.bts.btnframe.invtrigs -text "Invert surface elements" \ -variable options.inverttrigs ttk::checkbutton $f.bts.btnframe.azref -text "Automatic Z-refinement" \ -variable options.autozrefine pack $f.bts.btnframe -anchor center pack $f.bts.btnframe.parthread $f.bts.btnframe.second $f.bts.btnframe.quad $f.bts.btnframe.invtets $f.bts.btnframe.invtrigs $f.bts.btnframe.azref -anchor w # tixControl $f.elementorder -label "Element order: " -integer true \ # -variable options.elementorder -min 1 -max 20 \ # -options { # entry.width 2 # label.width 20 # label.anchor e # } # pack $f.elementorder #ttk::frame $f.bts.sbox #pack $f.bts.sbox -anchor w -pady 10 ttk::frame $f.bts.btnframe.elorder ttk::label $f.bts.btnframe.elorder.l -text "Element order" ttk::spinbox $f.bts.btnframe.elorder.elementorder2 -from 1 -to 20 -textvariable options.elementorder -width 2 pack $f.bts.btnframe.elorder -fill x pack $f.bts.btnframe.elorder.elementorder2 $f.bts.btnframe.elorder.l -anchor w -side left ttk::frame $f.bts.btnframe.pm ttk::checkbutton $f.bts.btnframe.pm.parallel_meshing -text "Parallel meshing" \ -variable options.parallel_meshing pack $f.bts.btnframe.pm -fill x -pady 5 pack $f.bts.btnframe.pm.parallel_meshing -anchor w ttk::label $f.bts.btnframe.pm.lnthreads -text "Number of meshing threads" ttk::spinbox $f.bts.btnframe.pm.nthreads -from 1 -to 128 -textvariable options.nthreads -width 2 pack $f.bts.btnframe.pm.nthreads $f.bts.btnframe.pm.lnthreads -anchor w -side left # ############################################################ # Mesh - Size options # ############################################################ set f $w.nb.meshsize ttk::frame $f.f2 pack $f.f2 -pady 10 # # ttk::style configure Tframe -background red # puts "********************" # puts "found these themes:" # puts [ttk::themes] # ttk::setTheme classic # ttk::setTheme aqua # puts "style Tframe foreground = " # puts [ttk::style lookup Tframe -foreground] # puts "f2 style:" # puts [$f.f2 cget -style] # puts [winfo class $f.f2] # puts "style element names gives:" # puts [ttk::style element names] set f $f.f2 ttk::frame $f.meshsize ttk::label $f.meshsize.l -text "max mesh-size" ttk::spinbox $f.meshsize.s -from 1e-9 -to 1e9 -textvariable options.meshsize -width 5 -validate focus -validatecommand "my_validatespinbox %W %P 10" \ -invalidcommand "my_invalidspinbox %W" pack $f.meshsize -fill x pack $f.meshsize.s $f.meshsize.l -side right ttk::frame $f.minmeshsize ttk::label $f.minmeshsize.l -text "min mesh-size" ttk::spinbox $f.minmeshsize.s -from 0 -to 1e9 -textvariable options.minmeshsize -width 5 -validate focus -validatecommand "my_validatespinbox %W %P 10" \ -invalidcommand "my_invalidspinbox %W" pack $f.minmeshsize -fill x pack $f.minmeshsize.s $f.minmeshsize.l -side right ttk::frame $f.grading ttk::label $f.grading.l -text "mesh-size grading" ttk::spinbox $f.grading.s -from 0.1 -to 1.0 -textvariable options.grading -width 5 -increment 0.1 -validate focus -validatecommand "my_validatespinbox %W %P 3" \ -invalidcommand "my_invalidspinbox %W" pack $f.grading -fill x pack $f.grading.s $f.grading.l -side right # tixControl $f.meshsize -label "max mesh-size: " -integer false \ # -variable options.meshsize -min 1e-9 -max 1e6 \ # -options { # entry.width 6 # label.width 25 # label.anchor e # } # tixControl $f.minmeshsize -label "min mesh-size: " -integer false \ # -variable options.minmeshsize -min 0 -max 1e6 \ # -options { # entry.width 6 # label.width 25 # label.anchor e # } # tixControl $f.grading -label "mesh-size grading: " -integer false \ # -variable options.grading -min 0.1 -max 1 -step 0.1 \ # -options { # entry.width 6 # label.width 25 # label.anchor e # } # pack $f.meshsize $f.minmeshsize $f.grading set f $w.nb.meshsize ttk::labelframe $f.msf -text "mesh-size file:" -relief groove -borderwidth 3 pack $f.msf # tixLabelEntry $f.msf.ent -label "mesh-size file: " \ # -labelside top \ # -options { # entry.textVariable options.meshsizefilename # entry.width 35 # label.width 25 # label.anchor w # } ttk::entry $f.msf.ent -textvariable options.meshsizefilename -width 30 ttk::button $f.msf.btn -text "Browse" -command { global options.meshsizefilename set types { {"Meshsize file" {.msz} } } set options.meshsizefilename [tk_getOpenFile -filetypes $types -initialfile ${options.meshsizefilename}] } pack $f.msf.ent -side left -expand yes -fill x -anchor s -padx 4 -pady 4 pack $f.msf.btn -side left -anchor s -padx 4 -pady 4 ttk::label $f.lab -text "Additional mesh size restrictions:" #csg-meshsize options ttk::labelframe $f.csg -relief groove -borderwidth 3 -text "CSG mesh-size" pack $f.csg -fill x proc test {a} {puts $a} #ttk::frame $f.csg.curv #pack $f.csg.curv -fill x -anchor center ttk::scale $f.csg.curvsc -orient horizontal -length 150 -from 0.2 -to 5 \ -variable options.curvaturesafety -takefocus 0 -command "roundscale $f.csg.curvsc 1" # -resolution 0.1 ttk::entry $f.csg.curve -textvariable options.curvaturesafety -width 3 \ -validatecommand "my_validate %W [$f.csg.curvsc cget -from] [$f.csg.curvsc cget -to] %P 1" \ -invalidcommand "my_invalid %W" -validate focus ttk::label $f.csg.curvla -text "Elements per curvature radius" grid $f.csg.curvsc $f.csg.curve $f.csg.curvla -sticky nw -padx 4 #ttk::frame $f.csg.elen #pack $f.csg.elen -fill x -anchor center ttk::scale $f.csg.elensc -orient horizontal -length 150 -from 0.2 -to 5 \ -variable options.segmentsperedge -takefocus 0 -command "roundscale $f.csg.elensc 1" # -resolution 0.1 ttk::entry $f.csg.elene -textvariable options.segmentsperedge -width 3 \ -validatecommand "my_validate %W [$f.csg.elensc cget -from] [$f.csg.elensc cget -to] %P 1" \ -invalidcommand "my_invalid %W" -validate focus ttk::label $f.csg.elenla -text "Elements per edge" grid $f.csg.elensc $f.csg.elene $f.csg.elenla -sticky nw -padx 4 grid anchor $f.csg center #stl-meshsize options ttk::labelframe $f.stl -relief groove -borderwidth 3 -text "STL mesh-size" pack $f.stl -fill x #ttk::frame $f.stl.r2 #pack $f.stl.r2 -fill x ttk::scale $f.stl.r2sc -orient horizontal -length 150 -from 0.2 -to 5 \ -variable stloptions.resthchartdistfac -takefocus 0 -command "roundscale $f.stl.r2sc 1" ttk::entry $f.stl.r2e -textvariable stloptions.resthchartdistfac -width 3 \ -validatecommand "my_validate %W [$f.stl.r2sc cget -from] [$f.stl.r2sc cget -to] %P 1" \ -invalidcommand "my_invalid %W" -validate focus ttk::checkbutton $f.stl.r2bu -text "STL - chart distance" \ -variable stloptions.resthchartdistenable grid $f.stl.r2sc $f.stl.r2e $f.stl.r2bu -sticky nw -padx 4 #ttk::frame $f.stl.r6 #pack $f.stl.r6 -anchor w ttk::scale $f.stl.r6sc -orient horizontal -length 150 -from 0.2 -to 5 \ -variable stloptions.resthlinelengthfac -takefocus 0 -command "roundscale $f.stl.r6sc 1" ttk::entry $f.stl.r6e -textvariable stloptions.resthlinelengthfac -width 3 \ -validatecommand "my_validate %W [$f.stl.r6sc cget -from] [$f.stl.r6sc cget -to] %P 1" \ -invalidcommand "my_invalid %W" -validate focus ttk::checkbutton $f.stl.r6bu -text "STL - line length" \ -variable stloptions.resthlinelengthenable grid $f.stl.r6sc $f.stl.r6e $f.stl.r6bu -sticky nw -padx 4 #ttk::frame $f.stl.r3 #pack $f.stl.r3 -anchor w ttk::scale $f.stl.r3sc -orient horizontal -length 150 -from 0.2 -to 8 \ -variable stloptions.resthcloseedgefac -takefocus 0 -command "roundscale $f.stl.r3sc 1" ttk::entry $f.stl.r3e -textvariable stloptions.resthcloseedgefac -width 3 \ -validatecommand "my_validate %W [$f.stl.r3sc cget -from] [$f.stl.r3sc cget -to] %P 1" \ -invalidcommand "my_invalid %W" -validate focus ttk::checkbutton $f.stl.r3bu -text "STL/IGES/STEP - close edges" \ -variable stloptions.resthcloseedgeenable grid $f.stl.r3sc $f.stl.r3e $f.stl.r3bu -sticky nw -padx 4 #ttk::frame $f.stl.r1 #pack $f.stl.r1 -anchor w ttk::scale $f.stl.r1sc -orient horizontal -length 150 -from 0.2 -to 5 \ -variable stloptions.resthsurfcurvfac -takefocus 0 -command "roundscale $f.stl.r1sc 1" ttk::entry $f.stl.r1e -textvariable stloptions.resthsurfcurvfac -width 3 \ -validatecommand "my_validate %W [$f.stl.r1sc cget -from] [$f.stl.r1sc cget -to] %P 1" \ -invalidcommand "my_invalid %W" -validate focus ttk::checkbutton $f.stl.r1bu -text "STL - surface curvature" \ -variable stloptions.resthsurfcurvenable grid $f.stl.r1sc $f.stl.r1e $f.stl.r1bu -sticky nw -padx 4 #ttk::frame $f.stl.r3b #pack $f.stl.r3b -anchor w ttk::scale $f.stl.r3bsc -orient horizontal -length 150 -from 0.2 -to 5 \ -variable stloptions.resthedgeanglefac -takefocus 0 -command "roundscale $f.stl.r3bsc 1" ttk::entry $f.stl.r3be -textvariable stloptions.resthedgeanglefac -width 3 \ -validatecommand "my_validate %W [$f.stl.r3bsc cget -from] [$f.stl.r3bsc cget -to] %P 1" \ -invalidcommand "my_invalid %W" -validate focus ttk::checkbutton $f.stl.r3bbu -text "STL - edge angle" \ -variable stloptions.resthedgeangleenable grid $f.stl.r3bsc $f.stl.r3be $f.stl.r3bbu -sticky nw -padx 4 #ttk::frame $f.stl.r5 #pack $f.stl.r5 -anchor w ttk::scale $f.stl.r5sc -orient horizontal -length 150 -from 0.2 -to 5 \ -variable stloptions.resthsurfmeshcurvfac -takefocus 0 -command "roundscale $f.stl.r5sc 1" ttk::entry $f.stl.r5e -textvariable stloptions.resthsurfmeshcurvfac -width 3 \ -validatecommand "my_validate %W [$f.stl.r5sc cget -from] [$f.stl.r5sc cget -to] %P 1" \ -invalidcommand "my_invalid %W" -validate focus ttk::checkbutton $f.stl.r5bu -text "STL - surface mesh curv" \ -variable stloptions.resthsurfmeshcurvenable grid $f.stl.r5sc $f.stl.r5e $f.stl.r5bu -sticky nw -padx 4 ttk::checkbutton $f.stl.recalch -text "STL - Recalc mesh size for surface optimization" \ -variable stloptions.recalchopt grid $f.stl.recalch -sticky n -columnspan 3 -column 0 ttk::button $f.stl.calch -text "Calc New H" -command { redraw; Ng_STLCalcLocalH } grid $f.stl.calch -columnspan 3 -column 0 grid anchor $f.stl center # set f [$w.nb subwidget chartopt] # round ttk::scale values to n_digits proc roundscale {w n_digits args} { set val [$w get] global [$w cget -variable] if {$n_digits == 0 } { set [$w cget -variable] [tcl::mathfunc::round $val] } else { set [$w cget -variable] [format "%.[append n_digits "f"]" $val] } } # validate ttk::entry which are linked to ttk::scales widgets global last_accepted_sc proc my_validate {w mini maxi val n_digits} { global last_accepted_sc [$w cget -textvariable] if {[string length $val] == 0} {return 0} if {[string is double $val] == 1} { if { $n_digits == 0 } { set val [tcl::mathfunc::max $mini [tcl::mathfunc::min $maxi [tcl::mathfunc::round $val]]] } else { if { $n_digits < 9 } { set val [tcl::mathfunc::max $mini [tcl::mathfunc::min $maxi [format "%.[append n_digits "f"]" $val]]] } } set last_accepted_sc $val set [$w cget -textvariable] $val return 1 } else { return 0 } } # if my_validate returns 0, this function gets called proc my_invalid {w} { global last_accepted_sc [$w cget -textvariable] set [$w cget -textvariable] $last_accepted_sc } set f $w.nb.chartopt ttk::labelframe $f.mainframe -text "STL angles" -relief groove -borderwidth 3 pack $f.mainframe -fill x -pady 15 set f $f.mainframe #ttk::frame $f.f1 ttk::label $f.labYangles -text "Yellow Edges Angle ()" ttk::scale $f.scale1 -orient horizontal -length 150 -from 0 -to 90 -variable stloptions.yangle -takefocus 0 -command "roundscale $f.scale1 1" ttk::entry $f.entry1 -textvariable stloptions.yangle -width 5 -validate focus -takefocus 0 -validatecommand "my_validate %W [$f.scale1 cget -from] [$f.scale1 cget -to] %P 1" \ -invalidcommand "my_invalid %W" #pack $f.f1 -anchor center grid $f.scale1 $f.entry1 $f.labYangles -sticky nw -padx 4 -pady 6 #ttk::frame $f.f21 ttk::label $f.labEangles -text "Edge Corner Angle ()" ttk::scale $f.scale2 -orient horizontal -length 150 -from 0 -to 180 -variable stloptions.edgecornerangle -takefocus 0 -command "roundscale $f.scale2 1" ttk::entry $f.entry2 -textvariable stloptions.edgecornerangle -width 5 -validate focus -takefocus 0 -validatecommand "my_validate %W [$f.scale2 cget -from] [$f.scale2 cget -to] %P 1" \ -invalidcommand "my_invalid %W" #pack $f.f21 -anchor center grid $f.scale2 $f.entry2 $f.labEangles -sticky nw -padx 4 -pady 6 #ttk::frame $f.f31 ttk::label $f.lab31 -text "Chart Angle ()" ttk::scale $f.scale3 -orient horizontal -length 150 -from 0 -to 180 -variable stloptions.chartangle -takefocus 0 -command "roundscale $f.scale3 1" ttk::entry $f.entry3 -textvariable stloptions.chartangle -width 5 -validate focus -takefocus 0 -validatecommand "my_validate %W [$f.scale3 cget -from] [$f.scale3 cget -to] %P 1" \ -invalidcommand "my_invalid %W" #pack $f.f31 -anchor center grid $f.scale3 $f.entry3 $f.lab31 -sticky nw -padx 4 -pady 6 #ttk::frame $f.f41 ttk::label $f.lab41 -text "Outer Chart Angle ()" ttk::scale $f.scale4 -orient horizontal -length 150 -from 0 -to 180 -variable stloptions.outerchartangle -takefocus 0 -command "roundscale $f.scale4 1" ttk::entry $f.entry4 -textvariable stloptions.outerchartangle -width 5 -validate focus -takefocus 0 -validatecommand "my_validate %W [$f.scale4 cget -from] [$f.scale4 cget -to] %P 1" \ -invalidcommand "my_invalid %W" #pack $f.f41 -anchor center grid $f.scale4 $f.entry4 $f.lab41 -sticky nw -padx 4 -pady 6 grid anchor $f center # Optimization options global last_accepted_sp # Used to validate the entries linked with a ttk::spinbox widget proc my_validatespinbox {w val n_digits} { global last_accepted_sp if {[string length $val] == 0} {return 0} if {[string is double $val] == 1} { if { $n_digits == 0 } { if { $n_digits < 9 } { set val [tcl::mathfunc::round $val] } else { set val [format "%.[append n_digits "f"]" $val] } } $w set [tcl::mathfunc::max [$w cget -from] [tcl::mathfunc::min [$w cget -to] $val]] set last_accepted_sp $val return 1 } else { return 0 } } proc my_invalidspinbox {w} { global last_accepted_sp $w set $last_accepted_sp } # set f [$w.nb subwidget optimizer] set f $w.nb.optimizer ttk::labelframe $f.optframe -text "Optimization settings" -relief groove -borderwidth 3 pack $f.optframe -fill x -pady 15 #ttk::frame $f.optframe.sos ttk::label $f.optframe.sosl -text "Surface opt steps" ttk::spinbox $f.optframe.soss -from 0 -to 99 -textvariable options.optsteps2d -width 5 -increment 1 -validate focus -validatecommand "my_validatespinbox %W %P 0" \ -invalidcommand "my_invalidspinbox %W" #pack $f.optframe.sos -anchor center grid $f.optframe.sosl $f.optframe.soss -sticky nw;# -side right -fill x -pady 2 #ttk::frame $f.optframe.vos ttk::label $f.optframe.vosl -text "Volume opt steps" ttk::spinbox $f.optframe.voss -from 0 -to 99 -textvariable options.optsteps3d -width 5 -increment 1 -validate focus -validatecommand "my_validatespinbox %W %P 0" \ -invalidcommand "my_invalidspinbox %W" #pack $f.optframe.vos -anchor center grid $f.optframe.vosl $f.optframe.voss -sticky nw;# -side right -fill x -pady 2 #ttk::frame $f.optframe.esw ttk::label $f.optframe.eswl -text "Element size weight" ttk::spinbox $f.optframe.esws -from 0 -to 1 -textvariable options.elsizeweight -width 5 -increment 0.1 -validate focus -validatecommand "my_validatespinbox %W %P 1" \ -invalidcommand "my_invalidspinbox %W" #pack $f.optframe.esw -anchor center grid $f.optframe.eswl $f.optframe.esws -sticky nw;# -side right -fill x -pady 2 #ttk::frame $f.optframe.wem ttk::label $f.optframe.weml -text "Worst element measure" ttk::spinbox $f.optframe.wems -from 1 -to 10 -textvariable options.opterrpow -width 5 -increment 1 -validate focus -validatecommand "my_validatespinbox %W %P 0" \ -invalidcommand "my_invalidspinbox %W" #pack $f.optframe.wem -anchor e grid $f.optframe.weml $f.optframe.wems -sticky nw;# -side right -fill x -pady 2 grid anchor $f.optframe center # These functions are needed due to a bug within the aqua theme # if a ttk::scale widget has a from value larger than 100. proc roundscale_helper_osx {w val} { global [$w cget -variable] options.badellimit set [$w cget -variable] [tcl::mathfunc::round $val] set options.badellimit [expr [tcl::mathfunc::round $val]+160] } proc my_validate_helper_osx {w val} { if {[string length $val] == 0} {return 0} if {[string is double $val] == 1} { set scale_loc [lindex [winfo children [winfo parent $w]] [lsearch [winfo children [winfo parent $w]] *scale]] global [$scale_loc cget -variable] options.badellimit set [$scale_loc cget -variable] [tcl::mathfunc::max [$scale_loc cget -from] [tcl::mathfunc::min [$scale_loc cget -to] [expr [tcl::mathfunc::round $val]-160]]] set options.badellimit [tcl::mathfunc::max [expr [$scale_loc cget -from]+160] [tcl::mathfunc::min [expr [$scale_loc cget -to]+160] [tcl::mathfunc::round $val]]] return 1 } else { return 0 } } proc my_invalid_helper_osx {w} { global options.badellimit set scale_loc [lindex [winfo children [winfo parent $w]] [lsearch [winfo children [winfo parent $w]] *scale]] global [$scale_loc cget -variable] set [$scale_loc cget -variable] [tcl::mathfunc::round [$scale_loc get]] set options.badellimit [expr [tcl::mathfunc::round [$scale_loc get]]+160] } global dummy_badellimit set dummy_badellimit 15 ttk::labelframe $f.optframe2 -text "Bad elements" -relief groove -borderwidth 3 pack $f.optframe2 -fill x -pady 15 -ipady 5 ttk::frame $f.optframe2.badellimit ttk::label $f.optframe2.lab -text "bad element criterion"; ttk::scale $f.optframe2.scale -orient horizontal -length 100 -from 00 -to 20 -variable dummy_badellimit -takefocus 0 -command "roundscale_helper_osx $f.optframe2.scale" ttk::entry $f.optframe2.entry -textvariable options.badellimit -width 3 -validate focusout -takefocus 0 -validatecommand "my_validate_helper_osx %W %P" \ -invalidcommand "my_invalid_helper_osx %W" #pack $f.optframe2.badellimit -anchor center grid $f.optframe2.scale $f.optframe2.entry $f.optframe2.lab -padx 4 -sticky nw grid anchor $f.optframe2 center # insider options # set f [$w.nb subwidget insider] set f $w.nb.debug ttk::labelframe $f.f2 -text "Advanced options" -borderwidth 3 -relief groove pack $f.f2 -fill x -pady 15 #ttk::frame $f.f2.frame #pack $f.f2.frame set f $f.f2 ttk::checkbutton $f.localh -text "Use Local Meshsize" \ -variable options.localh ttk::checkbutton $f.delauney -text "Use Delaunay" \ -variable options.delaunay ttk::checkbutton $f.checkoverlap -text "Check Overlapping" \ -variable options.checkoverlap ttk::checkbutton $f.checkcb -text "Check Chart Boundary" \ -variable options.checkchartboundary ttk::checkbutton $f.blockfill -text "Do Blockfilling" \ -variable options.blockfill grid $f.localh $f.delauney -sticky nw grid $f.checkoverlap $f.blockfill -sticky nw grid $f.checkcb -sticky nw grid anchor $f center # debugging options set f $w.nb.debug # enable / disable ttk::entry widgets linked to ttk::checkbuttons proc enable_cb {w1 w2 w3} { Ng_SetDebugParameters if {[string match *selected* [$w1 state]] == 1 } { $w2 configure -state normal $w3 configure -state normal } else { $w2 configure -state disabled $w3 configure -state disabled } } ttk::labelframe $f.cb1 -text "Debugging options" -borderwidth 3 -relief groove pack $f.cb1 -fill x -pady 15 #frame $f.cb1.cb0 #pack $f.cb1.cb0 -fill x ttk::checkbutton $f.cb1.slowchecks -text "Slow checks" \ -variable debug.slowchecks -command { Ng_SetDebugParameters } ttk::checkbutton $f.cb1.debugoutput -text "Debugging output" \ -variable debug.debugoutput -command { Ng_SetDebugParameters } ttk::checkbutton $f.cb1.haltexline -text "Halt on existing line" \ -variable debug.haltexistingline -command { Ng_SetDebugParameters } ttk::checkbutton $f.cb1.haltoverlap -text "Halt on Overlap" \ -variable debug.haltoverlap -command { Ng_SetDebugParameters } ttk::checkbutton $f.cb1.haltsuc -text "Halt on success" \ -variable debug.haltsuccess -command { Ng_SetDebugParameters } ttk::checkbutton $f.cb1.haltnosuc -text "Halt on no success" \ -variable debug.haltnosuccess -command { Ng_SetDebugParameters } ttk::checkbutton $f.cb1.haltlargequal -text "Halt on large quality class" \ -variable debug.haltlargequalclass -command { Ng_SetDebugParameters } ttk::checkbutton $f.cb1.haltseg -text "Halt on Segment:" \ -variable debug.haltsegment -command { Ng_SetDebugParameters } ttk::checkbutton $f.cb1.haltnode -text "Halt on Node:" \ -variable debug.haltnode -command { Ng_SetDebugParameters } ttk::frame $f.cb1.fr ttk::checkbutton $f.cb1.fr.cb -text "Halt on Face:" \ -variable debug.haltface -command { Ng_SetDebugParameters } ttk::entry $f.cb1.fr.ent -textvariable debug.haltfacenr -width 3 pack $f.cb1.fr.cb $f.cb1.fr.ent -side left ttk::frame $f.cb1.segs ttk::label $f.cb1.segs.lab1 -text "P1:" ttk::entry $f.cb1.segs.ent1 -width 6 \ -textvariable debug.haltsegmentp1 ttk::label $f.cb1.segs.lab2 -text "P2:" ttk::entry $f.cb1.segs.ent2 -width 6 \ -textvariable debug.haltsegmentp2 pack $f.cb1.segs.lab1 $f.cb1.segs.ent1 $f.cb1.segs.lab2 $f.cb1.segs.ent2 -side left grid $f.cb1.slowchecks $f.cb1.debugoutput -sticky nw grid $f.cb1.haltexline $f.cb1.haltoverlap -sticky nw grid $f.cb1.haltsuc $f.cb1.haltnosuc -sticky nw grid $f.cb1.haltlargequal $f.cb1.fr -sticky nw grid $f.cb1.haltnode -sticky nw grid $f.cb1.haltseg -stick nw grid $f.cb1.segs -stick w -row 4 -rowspan 2 -column 1 grid rowconfigure $f.cb1 3 -pad 8 grid anchor $f.cb1 center ttk::checkbutton $f.cb1.showactivechart -text "Show Active Meshing-Chart" -variable stloptions.showactivechart -command { Ng_SetVisParameters; redraw } grid $f.cb1.showactivechart grid rowconfigure $f.cb1 3 -pad 8 grid rowconfigure $f.cb1 5 -pad 8 set f $w.nb.debug ttk::labelframe $f.cont -relief groove -borderwidth 3 -text "Debugging visualization" pack $f.cont -fill x -pady 15 #ttk::frame $f.cont.f #pack $f.cont.f ttk::checkbutton $f.cont.multidrawing -text "Draw Meshing" -variable multithread_drawing ttk::checkbutton $f.cont.multitestmode -text "Meshing Testmode" -variable multithread_testmode ttk::button $f.cont.goon -text "Go On" -command { set multithread_pause 0 } grid $f.cont.multidrawing -sticky nw grid $f.cont.multitestmode -sticky nw grid $f.cont.goon -row 0 -rowspan 2 -column 1 -sticky w grid columnconfigure $f.cont 0 -pad 30 grid columnconfigure $f.cont 1 -pad 20 grid anchor $f.cont center global userlevel if { $userlevel < 3} { $w.nb delete insider $w.nb delete debug } # tixButtonBox $w.bbox -orientation horizontal # $w.bbox add ok -text Apply -underline 0 -width 5 \ # -command { # [.options_dlg.nb subwidget meshsize].meshsize invoke # [.options_dlg.nb subwidget meshsize].grading invoke # [.options_dlg.nb subwidget optimizer].os2d invoke # [.options_dlg.nb subwidget optimizer].os3d invoke # [.options_dlg.nb subwidget optimizer].elw invoke # [.options_dlg.nb subwidget optimizer].wem invoke # Ng_SetMeshingParameters # } # $w.bbox add close -text Done -underline 0 -width 5 \ # -command { # [.options_dlg.nb subwidget meshsize].meshsize invoke # [.options_dlg.nb subwidget meshsize].grading invoke # [.options_dlg.nb subwidget optimizer].os2d invoke # [.options_dlg.nb subwidget optimizer].os3d invoke # [.options_dlg.nb subwidget optimizer].elw invoke # [.options_dlg.nb subwidget optimizer].wem invoke # Ng_SetMeshingParameters # destroy .options_dlg # } # pack $w.bbox -side bottom -fill x ttk::frame $w.bu pack $w.bu -fill x -ipady 3 ttk::button $w.bu.apl -text "Apply" -command { Ng_SetMeshingParameters Ng_SetDebugParameters } ttk::button $w.bu.ok -text "Done" -command { Ng_SetMeshingParameters Ng_SetDebugParameters wm withdraw .options_dlg # destroy .options_dlg } pack $w.bu.apl $w.bu.ok -side left -expand yes wm withdraw $w wm geom $w +100+100 wm deiconify $w wm title $w "Meshing Options" focus .options_dlg } } meshingoptionsdialog wm withdraw .options_dlg # # # Viewing dialog # # proc viewingoptionsdialog { } { global userlevel set w .viewopts_dlg if {[winfo exists .viewopts_dlg] == 1} { wm withdraw $w wm deiconify $w focus $w } { toplevel $w #wm resizable $w 0 0 pack [ttk::notebook $w.nb] -fill both -fill both -side top $w.nb add [ttk::frame $w.nb.general] -text "General" -underline 0 $w.nb add [ttk::frame $w.nb.stl] -text "STL" -underline 0 $w.nb add [ttk::frame $w.nb.occ] -text "IGES/STEP" -underline 0 $w.nb add [ttk::frame $w.nb.mesh] -text "Mesh" -underline 0 $w.nb add [ttk::frame $w.nb.light] -text "Light" -underline 0 $w.nb add [ttk::frame $w.nb.edges] -text "Edges" -underline 0 $w.nb add [ttk::frame $w.nb.misc] -text "Misc." -underline 3 # tixNoteBook $w.nb -ipadx 6 -ipady 6 # $w.nb add general -label "General" -underline 0 # $w.nb add stl -label "STL" -underline 0 # $w.nb add occ -label "IGES/STEP" -underline 0 # $w.nb add mesh -label "Mesh" -underline 0 # $w.nb add light -label "Light" -underline 0 # $w.nb add edges -label "Edges" -underline 0 # $w.nb add misc -label "Misc." -underline 3 # pack $w.nb -expand yes -fill both -padx 5 -pady 5 -side top # general set f $w.nb.general ttk::labelframe $f.gvop -text "General viewing options" -relief groove -borderwidth 3 pack $f.gvop -fill x -pady 15 set f $f.gvop ttk::checkbutton $f.backcol -text "White Background" \ -variable viewoptions.whitebackground \ -command { Ng_SetVisParameters; redraw } ttk::checkbutton $f.cross -text "Draw Coordinate Cross" \ -variable viewoptions.drawcoordinatecross \ -command { Ng_SetVisParameters; redraw } ttk::checkbutton $f.color -text "Draw Color-bar" \ -variable viewoptions.drawcolorbar \ -command { Ng_SetVisParameters; redraw } ttk::checkbutton $f.netgen -text "Draw Netgen-logo" \ -variable viewoptions.drawnetgenlogo \ -command { Ng_SetVisParameters; redraw } grid $f.backcol -sticky nw grid $f.cross -stick nw grid $f.color -sticky nw grid $f.netgen -sticky nw # checkbutton $f.stereo -text "Stereo View" \ # -variable viewoptions.stereo \ # -command { Ng_SetVisParameters; redraw } # pack $f.stereo menu $f.stylemenu ttk::menubutton $f.style -menu $f.stylemenu -width 10 -text [ttk::style theme use] grid $f.style -sticky nw grid anchor $f center foreach theme [ttk::themes] { $f.stylemenu add command -label $theme \ -command " $f.style configure -text $theme; puts $theme ; ttk::setTheme $theme" } # stl geometry set f $w.nb.stl ttk::labelframe $f.show -relief groove -borderwidth 3 -text "STL viewing options" pack $f.show -fill x -pady 15 ttk::checkbutton $f.show.showtrias -text "Show STL-Triangles" \ -variable stloptions.showtrias -command { Ng_SetVisParameters; redraw } #grid $f.show.showtrias -stick nw ttk::checkbutton $f.show.showfilledtrias -text "Show Filled Triangles" \ -variable stloptions.showfilledtrias -command { Ng_SetVisParameters; redraw } grid $f.show.showtrias $f.show.showfilledtrias -sticky nw ttk::checkbutton $f.show.showactivechart -text "Show Active Meshing-Chart" \ -variable stloptions.showactivechart -command { Ng_SetVisParameters; redraw } #grid $f.show.showactivechart -sticky nw ttk::checkbutton $f.show.showedges -text "Show Edges" \ -variable stloptions.showedges -command { Ng_SetVisParameters; redraw } grid $f.show.showactivechart $f.show.showedges -sticky nw grid anchor $f.show center #frame $f.special -relief groove -borderwidth 3 #pack $f.special ttk::checkbutton $f.show.showmarktrias -text "Show Chart Triangles" \ -variable stloptions.showmarktrias \ -command {set stldoctor.showfaces 0; Ng_STLDoctor; Ng_SetVisParameters; redraw } #pack $f.show.showmarktrias -side left ttk::checkbutton $f.show.showfaces -text "Show Faces" \ -variable stldoctor.showfaces \ -command {set stloptions.showmarktrias 0; Ng_STLDoctor; Ng_SetVisParameters; redraw} #pack $f.show.showfaces -side left grid $f.show.showmarktrias $f.show.showfaces -sticky nw ttk::labelframe $f.fn -relief groove -borderwidth 3 -text "Chart/Face number" pack $f.fn -fill x ttk::label $f.fn.lab3 -text "Chart/Face number" ttk::scale $f.fn.scale3 -orient horizontal -length 150 -from 0 -to 200 \ -variable stloptions.chartnumber -command "Ng_SetVisParameters; redraw;roundscale $f.fn.scale3 0" ttk::entry $f.fn.ent3 -textvariable stloptions.chartnumber -width 3 -validate focus -takefocus 0 \ -validatecommand "Ng_SetVisParameters; redraw;my_validate %W [$f.fn.scale3 cget -from] [$f.fn.scale3 cget -to] %P 0" \ -invalidcommand "my_invalid %W;Ng_SetVisParameters; redraw;" grid $f.fn.scale3 $f.fn.ent3 $f.fn.lab3 -sticky nw -padx 4 #frame $f.fo -relief groove -borderwidth 3 #pack $f.fo tk::label $f.fn.lab -text "Chart/Face Offset:"; ttk::entry $f.fn.ent -width 3 \ -textvariable stloptions.chartnumberoffset -validate focus -takefocus 0 \ -validatecommand "my_validate %W 0 1e9 %P 0" \ -invalidcommand "my_invalid %W" ttk::button $f.fn.btn_write_chart -text "Write selected chart to chart.stlb" -command { Ng_STLDoctor writechart } grid $f.fn.lab -sticky ne -padx 4 grid $f.fn.ent -sticky nw -padx 4 -row 1 -column 1 grid $f.fn.btn_write_chart -padx 4 -row 2 -column 1 grid anchor $f.fn center ttk::labelframe $f.advstl -text "Advanced STL options" -relief groove -borderwidth 3 pack $f.advstl -fill x -pady 15 #frame $f.mt #pack $f.mt -fill x ttk::checkbutton $f.advstl.bu1 -text "Show Marked (Dirty) Triangles" \ -variable stldoctor.showmarkedtrigs \ -command {Ng_STLDoctor; redraw} #pack $f.mt.bu #frame $f.ep #pack $f.ep -fill x ttk::checkbutton $f.advstl.bu2 -text "show edge corner points" \ -variable stldoctor.showedgecornerpoints \ -command {Ng_STLDoctor; redraw} #pack $f.ep.bu #frame $f.stt #pack $f.stt -fill x ttk::checkbutton $f.advstl.bu3 -text "show touched triangle chart" \ -variable stldoctor.showtouchedtrigchart \ -command {set stldoctor.showfaces 0; set stloptions.showmarktrias 1; \ Ng_STLDoctor; Ng_SetVisParameters; redraw} #pack $f.stt.bu #frame $f.sml #pack $f.sml -fill x ttk::checkbutton $f.advstl.bu4 -text "draw meshed edges" \ -variable stldoctor.drawmeshededges \ -command {Ng_STLDoctor;} #pack $f.sml.bu #frame $f.sm #pack $f.sm -fill x ttk::checkbutton $f.advstl.bu5 -text "select with mouse" \ -variable stldoctor.selectwithmouse #pack $f.sm.bu grid $f.advstl.bu1 -stick nw grid $f.advstl.bu2 -sticky nw grid $f.advstl.bu3 -stick nw grid $f.advstl.bu4 -stick nw grid $f.advstl.bu5 -stick nw grid anchor $f.advstl center ttk::frame $f.advstl.tbn ttk::label $f.advstl.tbn.lab -text "Select triangle by number"; ttk::entry $f.advstl.tbn.ent -width 5 \ -textvariable stldoctor.selecttrig pack $f.advstl.tbn.lab $f.advstl.tbn.ent -padx 4 -side left grid $f.advstl.tbn -sticky nw grid anchor $f.advstl center grid rowconfigure $f.advstl 4 -pad 8 ttk::labelframe $f.vc -relief groove -borderwidth 3 -text "Vicinity options" pack $f.vc -fill x -pady 15 ttk::checkbutton $f.vc.bu -text "show vicinity" \ -variable stldoctor.showvicinity \ -command {Ng_STLDoctor vicinity; redraw} ttk::label $f.vc.lab -text "vicinity size"; ttk::scale $f.vc.scale -orient horizontal -length 150 -from 0 -to 200 \ -variable stldoctor.vicinity \ -takefocus 0 \ -command "roundscale $f.vc.scale 0; Ng_STLDoctor vicinity; redraw" #-command { Ng_STLDoctor vicinity; redraw } ttk::entry $f.vc.ent -width 4 -textvariable stldoctor.vicinity -validate focus \ -takefocus 0 -validatecommand "Ng_STLDoctor vicinity; redraw;my_validate %W [$f.vc.scale cget -from] [$f.vc.scale cget -to] %P 0" \ -invalidcommand "my_invalid %W;Ng_STLDoctor vicinity; redraw" #pack $f.vc.bu $f.vc.lab $f.vc.sc -expand yes grid $f.vc.bu -stick nw -columnspan 3 -column 0 grid $f.vc.scale $f.vc.ent $f.vc.lab -sticky nw -padx 4 grid anchor $f.vc center # IGES/STEP set f $w.nb.occ ttk::labelframe $f.occframe -text "IGES/STEP options" -relief groove -borderwidth 3 pack $f.occframe -fill x -pady 15 -ipady 8 #set f $f.occframe ttk::checkbutton $f.occframe.occshowsurfaces -text "Show surfaces " \ -variable occoptions.showsurfaces \ -command { Ng_SetOCCVisParameters; redraw } ttk::checkbutton $f.occframe.occshowedges -text "Show edges " \ -variable occoptions.showedges \ -command { Ng_SetOCCVisParameters; redraw } grid $f.occframe.occshowsurfaces $f.occframe.occshowedges -sticky nw -padx 4 grid anchor $f.occframe center #ttk::frame $f.deflection -relief groove -borderwidth 3 #pack $f.occframe.deflection -fill x ttk::button $f.occframe.btn -text "Rebuild visualization data" \ -command { Ng_SetOCCVisParameters Ng_OCCCommand buildvisualizationmesh redraw } #tixControl $f.occframe.ent -label "Visualization smoothness" -integer false \ -variable occoptions.deflection -min 0.1 -max 3 -step 0.1 \ -options { entry.width 3 } \ -command { Ng_SetOCCVisParameters } ttk::frame $f.occframe.vssm ttk::label $f.occframe.vssm.lab -text "Visulization smoothness" ttk::spinbox $f.occframe.vssm.sp -textvariable occoptions.deflection \ -from 0.1 -to 3 -increment 0.1 -width 4 -command { catch Ng_SetOCCVisParameters } \ -validate focus -validatecommand "my_validatespinbox %W %P 0" \ -invalidcommand "my_invalidspinbox %W" pack $f.occframe.vssm.lab $f.occframe.vssm.sp -side left -padx 4 grid $f.occframe.vssm -sticky nw -columnspan 2 -column 0 -pady 8 grid $f.occframe.btn -columnspan 2 -column 0 -sticky n #grid $f.occframe.ent $f.occframe.lab -sticky nw # ACIS visualization / construction ttk::labelframe $f.occframe1 -relief groove -borderwidth 3 -text "ACIS visulization / construction" pack $f.occframe1 -fill x -pady 15 -ipady 8 #ttk::frame $f.occframe1.shso ttk::label $f.occframe1.lab1 -text "Show solid (0 for all)" ttk::spinbox $f.occframe1.sp1 -textvariable occoptions.showsolidnr \ -from 0 -to 999 -increment 1 -width 4 -command { catch Ng_SetOCCVisParameters;redraw } \ -validate focus -validatecommand "my_validatespinbox %W %P 0" \ -invalidcommand "my_invalidspinbox %W" #pack $f.occframe1.shso.lab $f.occframe1.shso.sp -side left -padx 4 #ttk::frame $f.occframe1.shso2 ttk::label $f.occframe1.lab2 -text "Show solid 2" ttk::spinbox $f.occframe1.sp2 -textvariable occoptions.showsolidnr2 \ -from 0 -to 999 -increment 1 -width 4 -command { catch Ng_SetOCCVisParameters;redraw } \ -validate focus -validatecommand "my_validatespinbox %W %P 0" \ -invalidcommand "my_invalidspinbox %W" #pack $f.occframe1.shso2.lab $f.occframe1.shso2.sp -side left -padx 4 #tixControl $f.showsolid -label "Show solid (0 for all)" -integer true \ -variable occoptions.showsolidnr -min 0 -max 999 \ -options { entry.width 3 } \ -command { Ng_SetOCCVisParameters; redraw } #tixControl $f.showsolid2 -label "Show solid 2" -integer true \ -variable occoptions.showsolidnr2 -min 0 -max 999 \ -options { entry.width 3 } \ -command { Ng_SetOCCVisParameters; redraw } ttk::button $f.occframe1.subtract -text "Subtract (2 minus 1)" \ -command { Ng_ACISCommand subtract ${occoptions.showsolidnr} ${occoptions.showsolidnr2} redraw } ttk::button $f.occframe1.combine -text "Combine all" \ -command { Ng_ACISCommand combineall redraw } #pack $f.showsolid $f.showsolid2 $f.subtract $f.combine;# -sticky nw grid $f.occframe1.lab1 -row 0 -column 0 -sticky ne grid $f.occframe1.sp1 -row 0 -column 1 -sticky nw grid $f.occframe1.lab2 -row 1 -column 0 -sticky ne grid $f.occframe1.sp2 -row 1 -column 1 -sticky nw grid $f.occframe1.combine -columnspan 2 -column 0 -sticky n grid anchor $f.occframe1 center # mesh options set f $w.nb.mesh ttk::labelframe $f.center -relief groove -borderwidth 3 -text "how shall i name you?" pack $f.center -fill x -pady 15 ttk::button $f.center.lab1 -text "Set Center Point" \ -command { Ng_SetVisParameters; Ng_Center; redraw } ttk::entry $f.center.ent1 -width 5 \ -textvariable viewoptions.centerpoint -validate focus \ -validatecommand "my_validate %W 0 1e9 %P 0" \ -invalidcommand "my_invalid %W" grid $f.center.ent1 $f.center.lab1 -padx 4 -pady 4 -sticky nw #ttk::frame $f.drawel -relief groove -borderwidth 3 #pack $f.drawel -fill x ttk::button $f.center.lab2 -text "Draw Element" \ -command { Ng_SetVisParameters; Ng_ZoomAll; redraw } ttk::entry $f.center.ent2 -width 5 \ -textvariable viewoptions.drawelement -validate focus \ -validatecommand "my_validate %W 0 1e9 %P 0" \ -invalidcommand "my_invalid %W" grid $f.center.ent2 $f.center.lab2 -padx 4 -pady 4 -sticky nw grid anchor $f.center center ttk::labelframe $f.meshframe -text "Mesh visualization options" -relief groove -borderwidth 3 pack $f.meshframe -fill x -pady 15 set f $f.meshframe ttk::checkbutton $f.showcolor -text "Meshsize Visualization" \ -variable viewoptions.colormeshsize \ -command { Ng_SetVisParameters;redraw; } ttk::checkbutton $f.showfilledtrigs -text "Show filled triangles" \ -variable viewoptions.drawfilledtrigs \ -command { Ng_SetVisParameters; redraw } ttk::checkbutton $f.showedges -text "Show edges" \ -variable viewoptions.drawedges \ -command { Ng_SetVisParameters; redraw } ttk::checkbutton $f.showoutline -text "Show Triangle Outline" \ -variable viewoptions.drawoutline \ -command { Ng_SetVisParameters; redraw } ttk::checkbutton $f.showbadels -text "Show bad elements" \ -variable viewoptions.drawbadels \ -command { Ng_SetVisParameters; redraw } ttk::checkbutton $f.showprisms -text "Show prisms" \ -variable viewoptions.drawprisms \ -command { Ng_SetVisParameters; redraw } ttk::checkbutton $f.showpyramids -text "Show pyramids" \ -variable viewoptions.drawpyramids \ -command { Ng_SetVisParameters; redraw } ttk::checkbutton $f.showhexes -text "Show hexes" \ -variable viewoptions.drawhexes \ -command { Ng_SetVisParameters; redraw } ttk::checkbutton $f.showidentified -text "Show identified points" \ -variable viewoptions.drawidentified \ -command { Ng_SetVisParameters; redraw } ttk::checkbutton $f.showmetispartition -text "Show METIS Partition" \ -variable viewoptions.drawmetispartition \ -command { Ng_SetVisParameters; redraw } ttk::checkbutton $f.showpointnumbers -text "Show Point-numbers" \ -variable viewoptions.drawpointnumbers \ -command { Ng_SetVisParameters; redraw } ttk::checkbutton $f.showedgenumbers -text "Show Edge-numbers" \ -variable viewoptions.drawedgenumbers \ -command { Ng_SetVisParameters; redraw } ttk::checkbutton $f.showfacenumbers -text "Show Face-numbers" \ -variable viewoptions.drawfacenumbers \ -command { Ng_SetVisParameters; redraw } ttk::checkbutton $f.showelementnumbers -text "Show Element-numbers" \ -variable viewoptions.drawelementnumbers \ -command { Ng_SetVisParameters; redraw } ttk::checkbutton $f.showsegmentnumbers -text "Show Segment-numbers" \ -variable viewoptions.drawsegmentnumbers \ -command { Ng_SetVisParameters; redraw } ttk::checkbutton $f.showsurfaceelementnumbers -text "Show Surfaceelement-numbers" \ -variable viewoptions.drawsurfaceelementnumbers \ -command { Ng_SetVisParameters; redraw } # label $f.showdomainlab -text "Domain Surface" # scale $f.showdomain -orient horizontal -length 100 -from 0 -to 50 \ -resolution 1 -variable viewoptions.drawdomainsurf \ -command { Ng_SetVisParameters; redraw } \ -label "Domain Surface" #pack $f.showfilledtrigs #pack $f.showoutline $f.subdiv $f.showedges $f.showbadels ## pack $f.showdomainlab #pack $f.showdomain #pack $f.showpointnumbers #pack $f.showedgenumbers $f.showfacenumbers $f.showelementnumbers #pack $f.showmetispartition ttk::frame $f.frametets ttk::checkbutton $f.frametets.showtets -text "" \ -variable viewoptions.drawtets \ -command { Ng_SetVisParameters; redraw } ttk::label $f.frametets.label -text "\Show Tets\rin domain" ttk::spinbox $f.frametets.showtetsdomain -from 0 -to 500 -increment 1 -width 3 \ -textvariable viewoptions.drawtetsdomain -validate focus \ -command "Ng_SetVisParameters; redraw;" \ -validatecommand "my_validatespinbox %W %P 0" \ -invalidcommand "my_invalidspinbox %W" #ttk::frame $f.frametets ttk::label $f.frametets.label1 -text "Subdivision" ttk::spinbox $f.frametets.subdiv -from 0 -to 8 -increment 1 -width 3 \ -textvariable visoptions.subdivisions -validate focus \ -command { Ng_SetVisParameters; Ng_Vis_Set parameters; Ng_SetNextTimeStamp; redraw } \ -validatecommand "my_validatespinbox %W %P 0" \ -invalidcommand "my_invalidspinbox %W" ttk::label $f.frametets.label2 -text "Show surface\rof domain" ttk::spinbox $f.frametets.showdomain -from 0 -to 50 -increment 1 -width 3 \ -textvariable viewoptions.drawdomainsurf -validate focus \ -command { Ng_SetVisParameters; Ng_Vis_Set parameters; redraw } \ -validatecommand "my_validatespinbox %W %P 0" \ -invalidcommand "my_invalidspinbox %W" #tixControl $f.showdomain -label "Show surface\rof domain" -integer true \ -variable viewoptions.drawdomainsurf -min 0 -max 50 \ -options { entry.width 2 } \ -command { Ng_SetVisParameters; Ng_Vis_Set parameters; redraw } #tixControl $f.subdiv -label "Subdivision" -integer true \ # -variable visoptions.subdivisions -min 0 -max 8 \ -options { entry.width 2 } \ -command { Ng_SetVisParameters; Ng_Vis_Set parameters; Ng_SetNextTimeStamp; redraw } #tixControl $f.frametets.showtetsdomain -label "" -integer true \ -variable viewoptions.drawtetsdomain -min 0 -max 500 \ -options { entry.width 2 } \ -command { Ng_SetVisParameters; redraw } #pack $f.frametets grid $f.frametets.showtets $f.frametets.label $f.frametets.showtetsdomain -sticky w grid x $f.frametets.label2 $f.frametets.showdomain -stick w grid x $f.frametets.label1 $f.frametets.subdiv -sticky w grid $f.showfilledtrigs $f.showoutline -sticky nw grid $f.showedges $f.showbadels -sticky nw grid $f.showpointnumbers $f.showedgenumbers -sticky nw grid $f.showfacenumbers $f.showelementnumbers -sticky nw grid $f.showsurfaceelementnumbers $f.showsegmentnumbers -sticky nw grid $f.showmetispartition $f.showidentified -sticky nw grid $f.showcolor $f.showpyramids -sticky nw grid $f.showprisms $f.showhexes -sticky nw grid $f.frametets -sticky n -columnspan 2 -column 0 -pady 8 #grid $f.showdomain -stick ne;# -columnspan 3 -column 0 -pady 6 #grid $f.framesubdiv -sticky nw;# -columnspan 3 -column 0 -pady 6 grid anchor $f center set f $w.nb.mesh ttk::labelframe $f.fshrink -text "Element visualization" -relief groove -borderwidth 3 ttk::label $f.fshrink.lab -text "Shrink elements" #scale $f.fshrink.scale -orient horizontal -length 200 -from 0 -to 1.0001 \ -resolution 0.01 -tickinterval 0.25 \ -command { Ng_SetVisParameters; after idle redraw } \ -variable viewoptions.shrink ttk::scale $f.fshrink.scale -orient horizontal -length 200 -from 0 -to 1.0001 \ -command "roundscale $f.fshrink.scale 2;Ng_SetVisParameters; after idle redraw" \ -variable viewoptions.shrink ttk::entry $f.fshrink.entry -textvariable viewoptions.shrink -width 4 -validate focus \ -takefocus 0 -validatecommand "Ng_SetVisParameters; after idle redraw;my_validate %W [$f.fshrink.scale cget -from] [$f.fshrink.scale cget -to] %P 2" \ -invalidcommand "my_invalid %W;Ng_SetVisParameters; after idle redraw;" pack $f.fshrink -fill x -ipady 8 grid $f.fshrink.scale $f.fshrink.entry $f.fshrink.lab -padx 4 grid anchor $f.fshrink center # if {$userlevel == 3} { # frame $f.framecurveproj # checkbutton $f.framecurveproj.showcurveproj -text "Show curved edge projection " \ -variable viewoptions.drawcurveproj \ -command { Ng_SetVisParameters; redraw } # tixControl $f.framecurveproj.showcurveprojedge -label "" -integer true \ -variable viewoptions.drawcurveprojedge -min 1 -max 99999 \ -options { entry.width 5 } \ -command { Ng_SetVisParameters; redraw } # pack $f.framecurveproj # pack $f.framecurveproj.showcurveproj $f.framecurveproj.showcurveprojedge -side left # } # light options set f $w.nb.light ttk::labelframe $f.main -text "Lighting options" -relief groove -borderwidth 3 pack $f.main -fill x -pady 15 set f $f.main ttk::label $f.lab1 -text "Ambient Light" ttk::scale $f.scale1 -orient horizontal -length 200 -from 0 -to 1 \ -command "roundscale $f.scale1 2; Ng_SetVisParameters; redraw" \ -variable viewoptions.light.amb ttk::entry $f.ent1 -textvariable viewoptions.light.amb -validate focus -width 4 \ -validatecommand " Ng_SetVisParameters; redraw;my_validate %W [$f.scale1 cget -from] [$f.scale1 cget -to] %P 2" \ -invalidcommand "my_invalid %W;Ng_SetVisParameters; redraw;" ttk::label $f.lab2 -text "Diffuse Light" ttk::scale $f.scale2 -orient horizontal -length 200 -from 0 -to 1 \ -command "roundscale $f.scale2 2; Ng_SetVisParameters; redraw " \ -variable viewoptions.light.diff ttk::entry $f.ent2 -textvariable viewoptions.light.diff -validate focus -width 4 \ -validatecommand " Ng_SetVisParameters; redraw;my_validate %W [$f.scale2 cget -from] [$f.scale2 cget -to] %P 2" \ -invalidcommand "my_invalid %W;Ng_SetVisParameters; redraw;" ttk::label $f.lab3 -text "Specular Light" ttk::scale $f.scale3 -orient horizontal -length 200 -from 0 -to 1 \ -command "roundscale $f.scale3 2; Ng_SetVisParameters; redraw " \ -variable viewoptions.light.spec ttk::entry $f.ent3 -textvariable viewoptions.light.spec -validate focus -width 4 \ -validatecommand " Ng_SetVisParameters; redraw;my_validate %W [$f.scale3 cget -from] [$f.scale3 cget -to] %P 2" \ -invalidcommand "my_invalid %W;Ng_SetVisParameters; redraw;" grid $f.scale1 $f.ent1 $f.lab1 -sticky nw -padx 4 -pady 8 grid $f.scale2 $f.ent2 $f.lab2 -sticky nw -padx 4 -pady 8 grid $f.scale3 $f.ent3 $f.lab3 -sticky nw -padx 4 -pady 8 grid anchor $f center set f $w.nb.light ttk::labelframe $f.main1 -text "Material options" -relief groove -borderwidth 3 pack $f.main1 -fill x -pady 15 set f $f.main1 ttk::label $f.lab4 -text "Material Shininess" ttk::scale $f.scale4 -orient horizontal -length 200 -from 0 -to 128 \ -command "roundscale $f.scale4 0; Ng_SetVisParameters; redraw " \ -variable viewoptions.mat.shininess ttk::entry $f.ent4 -textvariable viewoptions.mat.shininess -validate focus -width 4 \ -validatecommand " Ng_SetVisParameters; redraw;my_validate %W [$f.scale4 cget -from] [$f.scale4 cget -to] %P 0" \ -invalidcommand "my_invalid %W;Ng_SetVisParameters; redraw;" ttk::label $f.lab5 -text "Material Transparency" ttk::scale $f.scale5 -orient horizontal -length 200 -from 0 -to 1 \ -command "roundscale $f.scale5 2; Ng_SetVisParameters; redraw " \ -variable viewoptions.mat.transp ttk::entry $f.ent5 -textvariable viewoptions.mat.transp -validate focus -width 4 \ -validatecommand " Ng_SetVisParameters; redraw;my_validate %W [$f.scale5 cget -from] [$f.scale5 cget -to] %P 2" \ -invalidcommand "my_invalid %W;Ng_SetVisParameters; redraw;" grid $f.scale4 $f.ent4 $f.lab4 -sticky nw -padx 4 -pady 8 grid $f.scale5 $f.ent5 $f.lab5 -sticky nw -padx 4 -pady 8 grid anchor $f center #$f.lab2 $f.scale2 $f.lab3 $f.scale3 $f.lab4 $f.scale4 $f.lab5 $f.scale5 # edges options set f $w.nb.edges ttk::labelframe $f.main -text "Edge viewing options" -relief groove -borderwidth 3 pack $f.main -fill x -pady 15 set f $f.main ttk::frame $f.helper pack $f.helper -anchor center set f $f.helper ttk::checkbutton $f.showedges -text "Show Edges" \ -variable viewoptions.drawededges \ -command { Ng_SetVisParameters; redraw } ttk::checkbutton $f.showpoints -text "Show Points" \ -variable viewoptions.drawedpoints \ -command { Ng_SetVisParameters; redraw } ttk::checkbutton $f.showpointnrs -text "Show Points Nrs" \ -variable viewoptions.drawedpointnrs \ -command { Ng_SetVisParameters; redraw } ttk::checkbutton $f.showtang -text "Show CP Tangents" \ -variable viewoptions.drawedtangents \ -command { Ng_SetVisParameters; redraw } ttk::checkbutton $f.drawedgenrs -text "Show Edge Nrs" \ -variable viewoptions.drawededgenrs \ -command { Ng_SetVisParameters; redraw } pack $f.showedges $f.showpoints $f.showpointnrs $f.showtang $f.drawedgenrs -anchor w set f $w.nb.edges ttk::labelframe $f.main1 -text "Center point" -relief groove -borderwidth 3 pack $f.main1 -fill x -pady 15 set f $f.main1 ttk::frame $f.center pack $f.center -anchor center ttk::button $f.center.btn -text "Set Center Point" \ -command { Ng_SetVisParameters; Ng_Center; redraw } ttk::entry $f.center.ent -width 5 -textvariable viewoptions.centerpoint -validate focus \ -validatecommand "my_validate %W 0 1e9 %P 0" \ -invalidcommand "my_invalid %W" grid $f.center.ent $f.center.btn -sticky nw -padx 4 #ttk::frame $f.f1 #pack $f.f1 -pady 5 -anchor center ttk::label $f.center.lab1 -text "SpecPoint Veclen" ttk::entry $f.center.ent1 -width 5 -textvariable viewoptions.specpointvlen -validate focus \ -validatecommand "my_validate %W 0 1e9 %P 4" \ -invalidcommand "my_invalid %W" grid $f.center.ent1 $f.center.lab1 -sticky nw -padx 4 # misc options set f $w.nb.misc ttk::labelframe $f.point -relief groove -borderwidth 3 -text "Special point" ttk::frame $f.point.dp ttk::checkbutton $f.point.dp.drawpoint -text "Draw Point" \ -variable viewoptions.drawspecpoint \ -command { Ng_SetVisParameters; redraw } ttk::entry $f.point.dp.px -width 8 -textvariable viewoptions.specpointx -validate focus \ -validatecommand "my_validate %W -1e9 1e9 %P 10" \ -invalidcommand "my_invalid %W" ttk::entry $f.point.dp.py -width 8 -textvariable viewoptions.specpointy -validate focus \ -validatecommand "my_validate %W -1e9 1e9 %P 10" \ -invalidcommand "my_invalid %W" ttk::entry $f.point.dp.pz -width 8 -textvariable viewoptions.specpointz -validate focus \ -validatecommand "my_validate %W -1e9 1e9 %P 10" \ -invalidcommand "my_invalid %W" grid $f.point.dp.drawpoint $f.point.dp.px $f.point.dp.py $f.point.dp.pz -sticky nw -padx 4;# -side left ttk::checkbutton $f.point.dp.center -text "Use as Center" \ -variable viewoptions.usecentercoords \ -command { if { ${viewoptions.usecentercoords} } { set viewoptions.centerx ${viewoptions.specpointx} set viewoptions.centery ${viewoptions.specpointy} set viewoptions.centerz ${viewoptions.specpointz} Ng_SetVisParameters; Ng_Center redraw } { Ng_SetVisParameters } } grid $f.point.dp.center -sticky nw -padx 4 pack $f.point.dp pack $f.point -fill x -ipady 3 -pady 15 ttk::frame $w.bu pack $w.bu -fill x -ipady 3 ttk::button $w.bu.done -text "Done" -command { Ng_SetVisParameters; redraw destroy .viewopts_dlg } ttk::button $w.bu.apply -text "Apply" -command { Ng_SetVisParameters; redraw } pack $w.bu.apply $w.bu.done -expand yes -side left wm withdraw $w wm geom $w +100+100 wm deiconify $w wm title $w "Viewing options" focus $w } } proc clipplanecommand { { optionalvar 0 } } { Ng_SetVisParameters after idle redraw } set clippingdialog_pop1 0 set clippingdialog_pop2 0 set clippingdialog_pop3 0 set clippingdialog_pop4 0 # # # clipping dialog # # proc clippingdialog { } { global clippingdialog_pop1 global clippingdialog_pop2 global clippingdialog_pop3 global clippingdialog_pop4 set clippingdialog_pop1 1 set clippingdialog_pop2 1 set clippingdialog_pop3 1 set clippingdialog_pop4 1 set w .clipping_dlg if {[winfo exists .clipping_dlg] == 1} { wm withdraw $w wm deiconify $w focus $w } { toplevel $w ttk::frame $w.background pack $w.background -fill x -fill y set w $w.background ttk::labelframe $w.main -text "Visual clipping" -relief groove -borderwidth 3 pack $w.main -fill x -pady 15 set w $w.main ttk::label $w.lab1 -text "Normal x" ttk::scale $w.scale1 -orient horizontal -length 300 -from -1 -to 1 \ -variable viewoptions.clipping.nx \ -command "roundscale $w.scale1 2; clipplanecommand " ttk::entry $w.entry1 -width 5 -textvariable viewoptions.clipping.nx \ -validate focus -validatecommand " clipplanecommand;my_validate %W [$w.scale1 cget -from] [$w.scale1 cget -to] %P 2" \ -invalidcommand "my_invalid %W; clipplanecommand" ttk::label $w.lab2 -text "Normal y" ttk::scale $w.scale2 -orient horizontal -length 300 -from -1 -to 1 \ -variable viewoptions.clipping.ny \ -command "roundscale $w.scale2 2; clipplanecommand " ttk::entry $w.entry2 -width 5 -textvariable viewoptions.clipping.ny \ -validate focus -validatecommand " clipplanecommand;my_validate %W [$w.scale2 cget -from] [$w.scale2 cget -to] %P 2" \ -invalidcommand "my_invalid $w.entry2;clipplanecommand" ttk::label $w.lab3 -text "Normal z" ttk::scale $w.scale3 -orient horizontal -length 300 -from -1 -to 1 \ -variable viewoptions.clipping.nz \ -command "roundscale $w.scale3 2; clipplanecommand " ttk::entry $w.entry3 -width 5 -textvariable viewoptions.clipping.nz \ -validate focus -validatecommand " clipplanecommand;my_validate %W [$w.scale3 cget -from] [$w.scale3 cget -to] %P 2" \ -invalidcommand "my_invalid %W;clipplanecommand" ttk::label $w.lab4 -text "Distance" ttk::scale $w.scale4 -orient horizontal -length 300 -from -1 -to 1.001 \ -variable viewoptions.clipping.dist \ -command "roundscale $w.scale4 3; clipplanecommand " ttk::entry $w.entry4 -width 5 -textvariable viewoptions.clipping.dist \ -validate focus -validatecommand " clipplanecommand;my_validate %W [$w.scale4 cget -from] [$w.scale4 cget -to] %P 3" \ -invalidcommand "my_invalid %W;clipplanecommand" proc my_Press {w x y} { set inc [expr {([$w get $x $y] <= [$w get]) ? -1 : 1}] ttk::Repeatedly ttk::scale::Increment $w [expr 0.001*$inc] } bind $w.scale4 { if { [string match *slider [%W identify %x %y]] == 0 } { my_Press %W %x %y;break } } bind $w.scale4 {ttk::scale::Release %W %x %y} ttk::label $w.lab5 -text "Additional\rDistance" ttk::scale $w.scale5 -orient horizontal -length 300 -from -1 -to 1.001 \ -variable viewoptions.clipping.dist2 \ -command "roundscale $w.scale5 3; clipplanecommand " ttk::entry $w.entry5 -width 5 -textvariable viewoptions.clipping.dist2 \ -validate focus -validatecommand " clipplanecommand;my_validate %W [$w.scale5 cget -from] [$w.scale5 cget -to] %P 3" \ -invalidcommand "my_invalid %W;clipplanecommand" bind $w.scale5 { if { [string match *slider [%W identify %x %y]] == 0 } { my_Press %W %x %y;break } } bind $w.scale5 {ttk::scale::Release %W %x %y} ttk::label $w.clipdomainlabel -text "Clip only domain" ttk::spinbox $w.clipdomainspinb -from 0 -to 500 -increment 1 -width 3 \ -textvariable viewoptions.clipping.onlydomain -validate focus \ -command {clipplanecommand;} \ -validatecommand "my_validatespinbox %W %P 0" \ -invalidcommand "my_invalidspinbox %W" ttk::label $w.donotclipdomainlabel -text "Do not clip domain" ttk::spinbox $w.donotclipdomainspinb -from 0 -to 500 -increment 1 -width 3 \ -textvariable viewoptions.clipping.notdomain -validate focus \ -command "clipplanecommand" \ -validatecommand "my_validatespinbox %W %P 0" \ -invalidcommand "my_invalidspinbox %W" #tixControl $w.clipdomain -label "Clip only domain" -integer true \ -variable viewoptions.clipping.onlydomain -min 0 -max 50 \ -options { entry.width 2 } \ -command { clipplanecommand; } # -command { Ng_SetVisParameters; redraw } #tixControl $w.donotclipdomain -label "Do not clip domain" -integer true \ -variable viewoptions.clipping.notdomain -min 0 -max 50 \ -options { entry.width 2 } \ -command { clipplanecommand; } # -command { Ng_SetVisParameters; redraw } grid $w.scale1 $w.entry1 $w.lab1 -sticky nw -padx 4 -pady 14 grid $w.scale2 $w.entry2 $w.lab2 -sticky nw -padx 4 -pady 14 grid $w.scale3 $w.entry3 $w.lab3 -sticky nw -padx 4 -pady 14 grid $w.scale4 $w.entry4 $w.lab4 -sticky nw -padx 4 -pady 14 grid $w.scale5 $w.entry5 $w.lab5 -sticky w -padx 4 -pady 14 grid $w.clipdomainlabel -sticky ne -padx 4 -pady 14 grid $w.clipdomainspinb -sticky nw -padx 4 -pady 14 -column 1 -row 5 grid $w.donotclipdomainlabel -sticky ne -padx 4 -pady 14 grid $w.donotclipdomainspinb -sticky nw -padx 4 -pady 14 -column 1 -row 6 grid anchor $w center #pack $w.lab2 $w.scale2 $w.lab3 $w.scale3 $w.lab4 $w.scale4 $w.lab5 $w.scale5 $w.clipdomain $w.donotclipdomain set w .clipping_dlg.background.main ttk::checkbutton $w.cb1 -text "Enable clipping" \ -variable viewoptions.clipping.enable \ -command { Ng_SetVisParameters; redraw } grid $w.cb1 -columnspan 2 -sticky ne ttk::frame $w.bu # pack $w.bu -fill x grid $w.bu;# -fill x -ipady 3 ttk::button $w.cancle -text "Done" -command "destroy .clipping_dlg" grid $w.cancle -columnspan 3 -pady 16 set w .clipping_dlg wm withdraw $w wm geom $w +100+100 wm deiconify $w wm title $w "Clipping Plane" # grab $w focus $w # $w.scale1 configure -command { puts "call1b"; Ng_SetVisParameters; redraw } # puts "after" clipplanecommand } } # # refinement dialog # # proc refinementdialog { } { set w .refinement_dlg if {[winfo exists .refinement_dlg] == 1} { wm withdraw $w wm deiconify $w focus $w } { toplevel $w #ttk::labelframe $w.main -text "Refinement options" -relief groove -borderwidth 3 #pack $w.main -fill x -pady 15 #set w $w.main # tixControl $w.meshsize -label "max mesh-size: " -integer false \ # -variable options.meshize -min 1e-6 -max 1e6 \ # -options { # entry.width 6 # label.width 25 # label.anchor e # } # pack $w.meshsize -anchor e global localh set localh 1 # tixControl $w.loch -label "local mesh-size: " -integer false \ # -variable localh -min 1e-6 -max 1e6 \ # -options { # entry.width 6 # label.width 25 # label.anchor e # } # pack $w.loch -anchor e ttk::frame $w.meshsize ttk::label $w.meshsize.l1 -text "max mesh-size: " ttk::spinbox $w.meshsize.sp1 -from 1e-6 -to 1e6 -textvariable options.meshsize -validate focus -validatecommand "my_validatespinbox %W %P 4" \ -invalidcommand "my_invalidspinbox %W" -width 6 -increment 0.1 #pack $w.meshsize.l1 $w.meshsize.sp1 -fill x -side left ttk::frame $w.meshsizeloc #pack $w.meshsize -anchor e #pack $w.meshsizeloc -anchor e ttk::label $w.meshsizeloc.l1 -text "local mesh-size: " ttk::spinbox $w.meshsizeloc.sp1 -from 1e-6 -to 1e6 -textvariable localh -validate focus -validatecommand "my_validatespinbox %W %P 4" \ -invalidcommand "my_invalidspinbox %W" -width 6 -increment 0.1 #pack $w.meshsizeloc.l1 $w.meshsizeloc.sp1 -expand yes -fill x pack $w.meshsize pack $w.meshsizeloc grid $w.meshsize.l1 $w.meshsize.sp1 grid $w.meshsizeloc.l1 $w.meshsizeloc.sp1 ttk::button $w.restface -text "Restrict H at face" \ -command { .refinement_dlg.meshsize invoke .refinement_dlg.loch invoke Ng_RestrictH face $localh } ttk::button $w.restedge -text "Restrict H at edge" \ -command { .refinement_dlg.meshsize invoke .refinement_dlg.loch invoke Ng_RestrictH edge $localh } ttk::button $w.restelement -text "Restrict H at element" \ -command { .refinement_dlg.meshsize invoke .refinement_dlg.loch invoke Ng_RestrictH element $localh } ttk::button $w.restpoint -text "Restrict H at point" \ -command { .refinement_dlg.meshsize invoke .refinement_dlg.loch invoke Ng_RestrictH point $localh } pack $w.restface $w.restedge $w.restelement $w.restpoint ttk::button $w.anisoedge -text "Declare Anisotropic edge" \ -command { Ng_Anisotropy edge } pack $w.anisoedge frame $w.bu pack $w.bu -fill x -ipady 3 ttk::button $w.bu.cancle -text "Done" -command "destroy .refinement_dlg" ttk::button $w.bu.refine -text "Refine" \ -command { # Ng_BisectCopyMesh; set oldnp 0; set newnp $status_np; while { $oldnp < $newnp } { set level [expr $level+1] Ng_Bisect; Ng_HighOrder ${options.elementorder} Ng_ReadStatus; redraw; set oldnp $newnp set newnp $status_np puts "oldnp $oldnp newnp $newnp" } } ttk::button $w.bu.zrefine -text "Z-Refine" \ -command { Ng_ZRefinement; Ng_ReadStatus; redraw; } pack $w.bu.zrefine $w.bu.refine $w.bu.cancle -expand yes -side left wm withdraw $w wm geom $w +100+100 wm deiconify $w wm title $w "Select Refinement" focus $w } } # # boundcondessing dialog # # proc bcpropdialog { } { set w .bcprop_dlg if {[winfo exists .bcprop_dlg] == 1} { wm withdraw $w wm deiconify $w } { toplevel $w ttk::frame $w.face -borderwidth 3 pack $w.face -fill x ttk::label $w.face.lab -text "face index:" ttk::label $w.face.ent -text 1 ttk::button $w.face.next -text "next" -command { set w .bcprop_dlg; set facenr [$w.face.ent cget -text] if {$facenr == [Ng_BCProp getnfd]} { set facenr 1 } { set facenr [expr $facenr + 1] } $w.face.ent configure -text $facenr Ng_BCProp setactive $facenr set bcnr [Ng_BCProp getbc $facenr] $w.bc.ent delete 0 end $w.bc.ent insert 0 $bcnr redraw } ttk::button $w.face.prev -text "prev" -command { set w .bcprop_dlg; set facenr [$w.face.ent cget -text] if {$facenr == 1} { set facenr [Ng_BCProp getnfd] } { set facenr [expr $facenr - 1] } $w.face.ent configure -text $facenr Ng_BCProp setactive $facenr set bcnr [Ng_BCProp getbc $facenr] $w.bc.ent delete 0 end $w.bc.ent insert 0 $bcnr redraw } pack $w.face.lab $w.face.ent $w.face.prev $w.face.next -side left ttk::frame $w.bc -borderwidth 3 pack $w.bc -fill x ttk::label $w.bc.lab -text "bc property:" entry $w.bc.ent -width 5 -relief sunken ttk::button $w.bc.but -text "change" -command { set w .bcprop_dlg; Ng_BCProp setbc [$w.face.ent cget -text] [$w.bc.ent get]; } ttk::button $w.bc.but2 -text "all" -command { set w .bcprop_dlg; Ng_BCProp setall [$w.bc.ent get]; } pack $w.bc.lab $w.bc.ent $w.bc.but $w.bc.but2 -side left -expand yes ttk::frame $w.bcname -borderwidth 3 pack $w.bcname -fill x ttk::label $w.bcname.lab -text "bc name:" ttk::label $w.bcname.ent -text "-" pack $w.bcname.lab $w.bcname.ent -side left -expand yes ttk::frame $w.bu pack $w.bu -fill x -ipady 3 ttk::button $w.bu.close -text "Close" -command { destroy .bcprop_dlg } pack $w.bu.close -expand yes -side left wm withdraw $w wm geom $w +100+100 wm deiconify $w wm title $w "Boundary Conditions" } focus $w set facenr [Ng_BCProp getactive] $w.face.ent configure -text $facenr set bcnr [Ng_BCProp getbc $facenr] $w.bc.ent delete 0 end $w.bc.ent insert 0 $bcnr set bcname [Ng_BCProp getbcname $facenr] $w.bcname.ent configure -text $bcname } # # Philippose - 25/07/2010 # Display the face colours currently # available in the mesh # proc currmeshcoloursdialog { } { set w .currmeshcolours_dlg if {[winfo exists .currmeshcolours_dlg] == 1} { wm withdraw $w wm deiconify $w focus $w } { toplevel $w global facecolslist frame $w.facecols -borderwidth 3 listbox $w.facecols.list -yscroll "$w.facecols.scroll set" -selectmode single -setgrid 1 -width 32 -height 12 scrollbar $w.facecols.scroll -command "$w.facecols.list yview" pack $w.facecols.scroll -side right -fill y pack $w.facecols.list -side left -expand yes -fill both Ng_CurrentFaceColours getcolours facecolslist set i 1 foreach el $facecolslist { set hel [format "%d: (%.4f %.4f %.4f)" $i [ lindex $el 0 ] [ lindex $el 1 ] [ lindex $el 2 ]] incr i $w.facecols.list insert end $hel } frame $w.bu1 -borderwidth 3 ttk::button $w.bu1.showonly -text "show only" -command { Ng_CurrentFaceColours showonly [.currmeshcolours_dlg.facecols.list curselection] redraw } ttk::button $w.bu1.hideonly -text "hide only" -command { Ng_CurrentFaceColours hideonly [.currmeshcolours_dlg.facecols.list curselection] redraw } ttk::button $w.bu1.showalso -text "show" -command { Ng_CurrentFaceColours showalso [.currmeshcolours_dlg.facecols.list curselection] redraw } ttk::button $w.bu1.hidealso -text "hide" -command { Ng_CurrentFaceColours hidealso [.currmeshcolours_dlg.facecols.list curselection] redraw } pack $w.bu1.showonly $w.bu1.hideonly $w.bu1.showalso $w.bu1.hidealso -expand yes -fill x -padx 2 -pady 2 -side left frame $w.bu2 ttk::button $w.bu2.showall -text "show all" -command { Ng_CurrentFaceColours showall redraw } ttk::button $w.bu2.hideall -text "hide all" -command { Ng_CurrentFaceColours hideall redraw } pack $w.bu2.showall $w.bu2.hideall -expand yes -fill x -padx 2 -pady 2 -side left frame $w.bu3 ttk::button $w.bu3.close -text "close" -command { destroy .currmeshcolours_dlg } pack $w.bu3.close -expand yes -fill x -pady 3 -side right pack $w.facecols -side top -expand yes -fill x -fill y pack $w.bu3 -side bottom pack $w.bu2 -side bottom pack $w.bu1 -expand yes -fill x -side left wm withdraw $w wm geom $w +100+100 wm deiconify $w wm title $w "Inspect Mesh Colours" focus $w } } # # Philippose - 30/01/2009 # Local Surface Mesh Size Selection # (Currently only supports OCC Geometry) # # proc surfacemeshsizedialog { } { set w .surfacemeshsize_dlg if {[winfo exists .surfacemeshsize_dlg] == 1} { wm withdraw $w wm deiconify $w } { toplevel $w frame $w.face -borderwidth 3 pack $w.face -fill x -padx 5 ttk::label $w.face.lab -text "face index:" ttk::label $w.face.ent -text 1 ttk::button $w.face.next -text "next" -command { set w .surfacemeshsize_dlg; set facenr [$w.face.ent cget -text] if {$facenr == [Ng_SurfaceMeshSize getnfd]} { set facenr 1 } { set facenr [expr $facenr + 1] } $w.face.ent configure -text $facenr Ng_SurfaceMeshSize setactive $facenr set surfms [Ng_SurfaceMeshSize getsurfms $facenr] $w.sms.ent delete 0 end $w.sms.ent insert 0 $surfms redraw } ttk::button $w.face.prev -text "prev" -command { set w .surfacemeshsize_dlg; set facenr [$w.face.ent cget -text] if {$facenr == 1} { set facenr [Ng_SurfaceMeshSize getnfd] } { set facenr [expr $facenr - 1] } $w.face.ent configure -text $facenr Ng_SurfaceMeshSize setactive $facenr set surfms [Ng_SurfaceMeshSize getsurfms $facenr] $w.sms.ent delete 0 end $w.sms.ent insert 0 $surfms redraw } pack $w.face.lab $w.face.ent $w.face.prev $w.face.next -side left frame $w.sms -borderwidth 3 pack $w.sms -fill x ttk::label $w.sms.lab -text "max mesh size:" entry $w.sms.ent -width 8 -relief sunken ttk::button $w.sms.but -text "change" -command { set w .surfacemeshsize_dlg; Ng_SurfaceMeshSize setsurfms [$w.face.ent cget -text] [$w.sms.ent get]; } ttk::button $w.sms.but2 -text "all" -command { set w .surfacemeshsize_dlg; Ng_SurfaceMeshSize setall [$w.sms.ent get]; } pack $w.sms.lab $w.sms.ent $w.sms.but $w.sms.but2 -side left -padx 5 -expand yes frame $w.bu pack $w.bu -fill x -ipady 3 ttk::button $w.bu.close -text "Close" -command { destroy .surfacemeshsize_dlg } pack $w.bu.close -expand yes -side left wm withdraw $w wm geom $w +100+100 wm deiconify $w wm title $w "Edit Surface Mesh Size" } focus $w set facenr [Ng_SurfaceMeshSize getactive] $w.face.ent configure -text $facenr set surfms [Ng_SurfaceMeshSize getsurfms $facenr] $w.sms.ent delete 0 end $w.sms.ent insert 0 $surfms } # # METIS dialog # # proc METISdialog { } { set w .metis_dlg set w.parts 64 if {[winfo exists .metis_dlg] == 1} { wm withdraw $w wm deiconify $w } { toplevel $w frame $w.a -borderwidth 0 frame $w.b -borderwidth 0 pack $w.a $w.b ttk::label $w.a.lab -text "Number of partitions:" entry $w.a.ent -textvariable w.parts -width 4 -relief sunken ttk::button $w.b.start -text "Start METIS" -command { Ng_Metis ${w.parts} redraw } ttk::button $w.b.cancel -text "Cancel" -command { destroy .metis_dlg } pack $w.a.lab $w.a.ent -side left -expand yes pack $w.b.start $w.b.cancel -side left wm withdraw $w wm geom $w +100+100 wm deiconify $w wm title $w "METIS Partitioning" focus $w } } # # STL dialog # proc stloptionsdialog { } { set w .stlopts_dlg if {[winfo exists .stlopts_dlg] == 1} { wm withdraw $w wm deiconify $w focus $w } { toplevel $w pack [ttk::notebook $w.nb] -fill both -fill both -side top # tixNoteBook $w.nb -ipadx 6 -ipady 6 # $w config -bg gray # $w.nb subwidget nbframe config -backpagecolor gray # Create the two tabs on the notebook. The -underline option # puts a underline on the first character of the labels of the tabs. # Keyboard accelerators will be defined automatically according # to the underlined character. # # $w.nb add chartopt -label "Chart Options" -underline 0 # #$w.nb add meshsize -label "Mesh Size" -underline 0 # pack $w.nb -expand yes -fill both -padx 5 -pady 5 -side top # set f [$w.nb subwidget chartopt] # label $f.lab1 -text "Yellow Edges Angle ()" # scale $f.scale1 -orient horizontal -length 300 \ # -from 0 -to 90 -resolution 1 -tickinterval 10 \ # -variable stloptions.yangle # pack $f.lab1 $f.scale1 # label $f.lab2e -text "Edge Corner Angle ()" # scale $f.scale2e -orient horizontal -length 360 -from 0 -to 180 \ # -resolution 1 -tickinterval 20 \ # -variable stloptions.edgecornerangle # pack $f.lab2e $f.scale2e # label $f.lab2 -text "Chart Angle ()" # scale $f.scale2 -orient horizontal -length 360 -from 0 -to 180 \ # -resolution 1 -tickinterval 20 \ # -variable stloptions.chartangle # pack $f.lab2 $f.scale2 # label $f.lab2b -text "Outer Chart Angle ()" # scale $f.scale2b -orient horizontal -length 360 -from 0 -to 180 \ # -resolution 1 -tickinterval 20 \ # -variable stloptions.outerchartangle # pack $f.lab2b $f.scale2b # frame $f.r4 # pack $f.r4 -anchor w # scale $f.r4.sc -orient horizontal -length 200 -from 0.1 -to 10 \ # -resolution 0.1 -variable stloptions.resthatlasfac # checkbutton $f.r4.bu -text "Restrict h for Calc Atlas (Faster)" \ # -variable stloptions.resthatlasenable # pack $f.r4.sc $f.r4.bu -side left #set f [$w.nb subwidget meshsize] # checkbutton $w.seat -text "Use Searchtrees" \ # -variable stloptions.usesearchtree # pack $w.seat frame $w.bu # pack $w.bu pack $w.bu -fill x -ipady 3 # -fill x ttk::button $w.bu.apply -text "Apply" -command { redraw; Ng_GenerateMesh 1 2} ttk::button $w.bu.cancle -text "Done" -command { destroy .stlopts_dlg } pack $w.bu.cancle $w.bu.apply -side left -expand yes wm withdraw $w wm geom $w +100+100 wm deiconify $w wm title $w "STL Options" # grab $w focus $w } } proc stldoctordialog { } { Ng_STLDoctor set wd .stldoctor_dlg if {[winfo exists .stldoctor_dlg] == 1} { wm withdraw $wd wm deiconify $wd focus $wd } { toplevel $wd pack [ttk::notebook $wd.nb] -fill both -fill both -side top $wd.nb add [ttk::frame $wd.nb.general] -text "General" -underline 0 $wd.nb add [ttk::frame $wd.nb.topology] -text "Edit Topology" -underline 5 $wd.nb add [ttk::frame $wd.nb.edges] -text "Edit Edges" -underline 5 $wd.nb add [ttk::frame $wd.nb.normals] -text "Edit Normals" -underline 5 $wd.nb add [ttk::frame $wd.nb.advanced] -text "Advanced" -underline 0 # tixNoteBook $wd.nb -ipadx 6 -ipady 6 # $wd.nb add general -label "General" -underline 0 # $wd.nb add topology -label "Edit Topology" -underline 5 # $wd.nb add edges -label "Edit Edges" -underline 5 # $wd.nb add normals -label "Edit Normals" -underline 5 # $wd.nb add advanced -label "Advanced" -underline 0 # pack $wd.nb -expand yes -fill both -padx 5 -pady 5 -side top # GENERAL ***************************** set f $wd.nb.general ttk::frame $f.selectframe -borderwidth 0 #ttk::frame $f.show #pack $f.show -fill x ttk::checkbutton $f.selectframe.showtrias -text "Show STL-Triangles" \ -variable stloptions.showtrias -command { Ng_SetVisParameters; redraw } #pack $f.selectframe.showtrias -anchor w ttk::checkbutton $f.selectframe.showfilledtrias -text "Show Filled Triangles" \ -variable stloptions.showfilledtrias -command { Ng_SetVisParameters; redraw } #pack $f.show.showfilledtrias -anchor w set selmodevals { 0 1 2 3 4 } set selmodelabs(0) "triangle" set selmodelabs(1) "edge" set selmodelabs(2) "point" set selmodelabs(3) "line" set selmodelabs(4) "line cluster" # tixOptionMenu $f.selmode -label "Double Click selects :" \ # -options { # label.width 19 # label.anchor e # menubutton.width 15 # } # foreach selmodev $selmodevals { # $f.selmode add command $selmodev -label $selmodelabs($selmodev) # } # $f.selmode config -variable stldoctor.selectmode # $f.selmode config -command { Ng_STLDoctor } global stldoctor.selectmode # pack $f.selmode ttk::label $f.selectframe.dblcsellab -text "Double Click selects : " ttk::menubutton $f.selectframe.dblcselbut -menu $f.selectframe.dblcselmen -text "triangle" -width 16 menu $f.selectframe.dblcselmen -tearoff 0 foreach selmode { 0 1 2 3 4 } { $f.selectframe.dblcselmen add command -label $selmodelabs($selmode) \ -command "set stldoctor.selectmode $selmode ; Ng_STLDoctor ; $f.selectframe.dblcselbut configure -text \"$selmodelabs($selmode)\"" } $f.selectframe.dblcselmen invoke $selmodelabs(${stldoctor.selectmode}) pack $f.selectframe grid $f.selectframe.showtrias -sticky nw grid $f.selectframe.showfilledtrias -sticky nw grid $f.selectframe.dblcsellab $f.selectframe.dblcselbut -sticky nw ttk::frame $f.sm pack $f.sm -fill x ttk::checkbutton $f.sm.bu -text "select with mouse" \ -variable stldoctor.selectwithmouse pack $f.sm.bu ttk::frame $f.st -relief groove -borderwidth 3 pack $f.st -fill x ttk::label $f.st.lab -text "Select triangle by number"; ttk::entry $f.st.ent -width 5 \ -textvariable stldoctor.selecttrig pack $f.st.ent $f.st.lab -side left -expand yes ttk::frame $f.vc -relief groove -borderwidth 3 pack $f.vc -fill x ttk::checkbutton $f.vc.bu -text "show vicinity" \ -variable stldoctor.showvicinity \ -command {Ng_STLDoctor vicinity; redraw} ttk::label $f.vc.lab -text "vicinity size"; #scale $f.vc.sc -orient horizontal -length 200 -from 0 -to 200 \ -resolution 1 -variable stldoctor.vicinity \ -command { Ng_STLDoctor vicinity; redraw } ttk::frame $f.vc.sc ttk::scale $f.vc.sc.scale -orient horizontal -length 200 -from 0 -to 200 \ -variable stldoctor.vicinity -takefocus 0 -command "Ng_STLDoctor vicinity; redraw; roundscale $f.vc.sc.scale 0" ttk::entry $f.vc.sc.entry -textvariable stldoctor.vicinity -width 3 \ -validatecommand "Ng_STLDoctor vicinity; redraw; my_validate %W [$f.vc.sc.scale cget -from] [$f.vc.sc.scale cget -to] %P 0" \ -invalidcommand "my_invalid %W;Ng_STLDoctor vicinity; redraw;" -validate focus ttk::label $f.vc.sc.lab -text "vicinity size" grid $f.vc.sc.scale $f.vc.sc.entry $f.vc.sc.lab -sticky nw -padx 4 pack $f.vc.bu $f.vc.lab $f.vc.sc -expand yes ttk::frame $f.ge -relief groove -borderwidth 0 pack $f.ge -expand yes ttk::button $f.ge.neighbourangles -text "calc neighbourangles" -command {Ng_STLDoctor neighbourangles} ttk::button $f.ge.showcoords -text "show coords of touched triangle" -command {Ng_STLDoctor showcoords} ttk::button $f.ge.moveptm -text "move point to middle of trianglepoints" -command {Ng_STLDoctor movepointtomiddle; redraw} ttk::button $f.ge.destroy0trigs -text "destroy 0-volume triangles" -command {Ng_STLDoctor destroy0trigs} grid $f.ge.neighbourangles -sticky nw -padx 4 -pady 4 grid $f.ge.showcoords -sticky nw -padx 4 -pady 4 grid $f.ge.moveptm -sticky nw -padx 4 -pady 4 grid $f.ge.destroy0trigs -sticky nw -padx 4 -pady 4 ttk::button $f.ge.cancle -text "Done" -command {destroy .stldoctor_dlg } grid $f.ge.cancle -sticky nw # TOPOLOGY ******************** set f $wd.nb.topology ttk::frame $f.oc -relief groove -borderwidth 3 pack $f.oc -pady 3 -ipady 3 -fill y -fill x ttk::frame $f.oc.oc1 -borderwidth 0 pack $f.oc.oc1 ttk::button $f.oc.oc1.bu -text "invert orientation \n of selected trig" -command {Ng_STLDoctor invertselectedtrig; redraw } ttk::button $f.oc.oc1.bu2 -text "orient after \n selected trig" -command {Ng_STLDoctor orientafterselectedtrig; redraw } ttk::button $f.oc.oc1.toperr -text "mark inconsistent triangles" -command {Ng_STLDoctor marktoperrortrigs; redraw } ttk::button $f.oc.oc1.deltrig -text "delete selected triangle" -command {Ng_STLDoctor deleteselectedtrig; redraw } ttk::button $f.oc.oc1.geosmooth -text "geometric smoothing" -command {Ng_STLDoctor smoothgeometry; redraw } grid $f.oc.oc1.bu x $f.oc.oc1.bu2 -sticky nw -padx 4 -pady 4 grid $f.oc.oc1.toperr - x -sticky nw -padx 4 -pady 4 grid $f.oc.oc1.deltrig - x -sticky nw -padx 4 -pady 4 grid $f.oc.oc1.geosmooth - x -sticky nw -padx 4 -pady 4 # EDGES *********************** set f $wd.nb.edges ttk::frame $f.be -relief groove -borderwidth 3 pack $f.be -fill x #scale $f.be.sc -orient horizontal -length 200 -from 0 -to 100 \ #-resolution 0.5 ttk::frame $f.be.frame pack $f.be.frame -ipady 4 -pady 4 ttk::label $f.be.frame.lab -text "build edges with yellow angle:"; ttk::scale $f.be.frame.scale -orient horizontal -length 200 -from 0 -to 200 \ -variable stloptions.yangle -takefocus 0 -command "roundscale $f.be.frame.scale 1; Ng_SetSTLParameters; Ng_STLDoctor buildedges; redraw" ttk::entry $f.be.frame.entry -textvariable stloptions.yangle -width 5 \ -validatecommand "Ng_SetSTLParameters; Ng_STLDoctor buildedges; redraw;my_validate %W [$f.be.frame.scale cget -from] [$f.be.frame.scale cget -to] %P 1" \ -invalidcommand "my_invalid %W;Ng_SetSTLParameters; Ng_STLDoctor buildedges; redraw" -validate focus grid $f.be.frame.lab - -sticky nw -padx 4 grid $f.be.frame.scale $f.be.frame.entry -sticky nw -padx 4 #$f.be.sc config -variable stloptions.yangle #$f.be.sc config -command { Ng_SetSTLParameters; Ng_STLDoctor buildedges; redraw } ttk::label $f.be.frame.lab2 -text "continue edges with yellow angle:"; # scale $f.be.sc2 -orient horizontal -length 200 -from 0 -to 100 \ -resolution 0.5 ttk::scale $f.be.frame.scale2 -orient horizontal -length 200 -from 0 -to 100 \ -variable stloptions.contyangle -takefocus 0 -command "roundscale $f.be.frame.scale2 1; Ng_SetSTLParameters; Ng_STLDoctor buildedges; redraw" ttk::entry $f.be.frame.entry2 -textvariable stloptions.contyangle -width 5 \ -validatecommand "Ng_SetSTLParameters; Ng_STLDoctor buildedges; redraw;my_validate %W [$f.be.frame.scale2 cget -from] [$f.be.frame.scale2 cget -to] %P 1" \ -invalidcommand "my_invalid %W;Ng_SetSTLParameters; Ng_STLDoctor buildedges; redraw" -validate focus grid $f.be.frame.lab2 - -sticky nw -padx 4 grid $f.be.frame.scale2 $f.be.frame.entry2 -sticky nw -padx 4 #$f.be.sc2 config -variable stloptions.contyangle #$f.be.sc2 config -command { Ng_SetSTLParameters; Ng_STLDoctor buildedges; redraw } ttk::button $f.be.frame.buildedges -text "Build Edges" -command {Ng_STLDoctor buildedges; redraw} grid $f.be.frame.buildedges - -sticky n -padx 4 -pady 4 #pack $f.be.lab $f.be.sc $f.be.lab2 $f.be.sc2 $f.be.buildedges -expand yes ttk::frame $f.se -relief groove -borderwidth 3 pack $f.se -fill x ttk::checkbutton $f.se.bu -text "show excluded" \ -variable stldoctor.showexcluded \ -command {Ng_STLDoctor; redraw} pack $f.se.bu # edgeselectmode ****** set edgeselmodevals { 0 1 2 3 4 } set edgeselmodelabs(0) "no change" set edgeselmodelabs(1) "undefined" set edgeselmodelabs(2) "confirmed" set edgeselmodelabs(3) "candidate" set edgeselmodelabs(4) "excluded" # tixOptionMenu $f.edgeselmode -label "Double Click sets edge :" \ # -options { # label.width 19 # label.anchor e # menubutton.width 15 # } # foreach edgeselmodev $edgeselmodevals { # $f.edgeselmode add command $edgeselmodev -label $edgeselmodelabs($edgeselmodev) # } # $f.edgeselmode config -variable stldoctor.edgeselectmode # $f.edgeselmode config -command { Ng_STLDoctor } global stldoctor.edgeselectmode # pack $f.edgeselmode ttk::frame $f.scaleframe -relief groove -borderwidth 0 pack $f.scaleframe -ipadx 4 -pady 4 -expand yes ttk::label $f.scaleframe.dblcedgelab -text "Double Click sets edge :" ttk::menubutton $f.scaleframe.dblcledgebut -menu $f.scaleframe.dblcledgem -text "coarse" -width 16 menu $f.scaleframe.dblcledgem -tearoff 0 foreach selectmode { 0 1 2 3 4 } { $f.scaleframe.dblcledgem add command -label $edgeselmodelabs($selectmode) \ -command "set stldoctor.edgeselectmode $selectmode ; $f.scaleframe.dblcledgebut configure -text \"$edgeselmodelabs($selectmode)\"" } $f.scaleframe.dblcledgem invoke $edgeselmodelabs(${stldoctor.edgeselectmode}) grid $f.scaleframe.dblcedgelab $f.scaleframe.dblcledgebut -sticky n -ipadx 4 # edge buttons ttk::frame $f.edg -relief groove -borderwidth 3 pack $f.edg -fill x -ipadx 4 -ipady 4 # checkbutton $f.edg.bu -text "use external edges" \ # -variable stldoctor.useexternaledges \ # -command {Ng_STLDoctor; redraw} # pack $f.edg.bu -expand yes ttk::frame $f.edg.f0 pack $f.edg.f0 ttk::button $f.edg.f0.confirmedge -text "confirm" -command {Ng_STLDoctor confirmedge; redraw} ttk::button $f.edg.f0.candidateedge -text "candidate" -command {Ng_STLDoctor candidateedge; redraw} ttk::button $f.edg.f0.excludeedge -text "exclude" -command {Ng_STLDoctor excludeedge; redraw} ttk::button $f.edg.f0.undefinededge -text "undefined" -command {Ng_STLDoctor undefinededge; redraw} pack $f.edg.f0.confirmedge $f.edg.f0.candidateedge $f.edg.f0.excludeedge $f.edg.f0.undefinededge -side left ttk::frame $f.edg.fa pack $f.edg.fa ttk::button $f.edg.fa.setallundefined -text "all undefined" -command {Ng_STLDoctor setallundefinededges; redraw} ttk::button $f.edg.fa.erasecandidates -text "candidates to undefined" -command {Ng_STLDoctor erasecandidateedges; redraw} pack $f.edg.fa.setallundefined $f.edg.fa.erasecandidates -side left ttk::frame $f.edg.fb pack $f.edg.fb ttk::button $f.edg.fb.confirmcandidates -text "candidates to confirmed" -command {Ng_STLDoctor confirmcandidateedges; redraw} ttk::button $f.edg.fb.confirmedtocandidates -text "confirmed to candidates" -command {Ng_STLDoctor confirmedtocandidateedges; redraw} pack $f.edg.fb.confirmcandidates $f.edg.fb.confirmedtocandidates -side left ttk::frame $f.edg.f1 ttk::frame $f.edg.f2 ttk::frame $f.edg.f3 ttk::frame $f.edg.f4 pack $f.edg.f1 $f.edg.f2 $f.edg.f3 $f.edg.f4 ttk::button $f.edg.f1.exportedges -text "export edges" -command {Ng_STLDoctor exportedges} ttk::button $f.edg.f1.importedges -text "import edges" -command {Ng_STLDoctor importedges; redraw} ttk::button $f.edg.f1.saveedgedata -text "save edgedata" \ -command { set types { {"Netgen Edgedata" {.ned} } } set file [tk_getSaveFile -filetypes $types -defaultextension ".ned"] if {$file != ""} { Ng_STLDoctor saveedgedata $file } } ttk::button $f.edg.f1.loadedgedata -text "load edgedata" \ -command { set types { {"Netgen Edgedata" {.ned} } } set file [tk_getOpenFile -filetypes $types -defaultextension ".ned"] if {$file != ""} { Ng_STLDoctor loadedgedata $file puts "loading done" redraw # wm title . [concat "NETGEN - " $file] } } ttk::button $f.edg.f1.importAVLedges -text "import AVL edges" \ -command { set types {{"Edge file" {.edg }}} set file [tk_getOpenFile -filetypes $types -defaultextension ".edg"] if {$file != ""} { Ng_STLDoctor importexternaledges $file; } } pack $f.edg.f1.importAVLedges $f.edg.f1.loadedgedata $f.edg.f1.saveedgedata -side left # button $f.edg.f1.buildedges -text "build external edges" -command {Ng_STLDoctor buildexternaledges; redraw} ttk::frame $f.edg2 -relief groove -borderwidth 3 pack $f.edg2 -fill x # button $f.edg2.addlonglines -text "make long lines candidates (% of diam)" -command {Ng_STLDoctor addlonglines; redraw} ttk::label $f.edg2.lab -text "length (%):" scale $f.edg2.sc -orient horizontal -length 200 -from 0 -to 100 \ -resolution 0.5 \ -variable stldoctor.longlinefact # button $f.edg2.deletedirtyedges -text "make dirty edges candidates" -command {Ng_STLDoctor deletedirtyedges; redraw} ttk::button $f.edg2.undoedge -text "undo last edge change" -command {Ng_STLDoctor undoedgechange; redraw} # pack $f.edg2.addlonglines $f.edg2.deletedirtyedges -expand yes # pack $f.edg2.lab $f.edg2.sc -side left pack $f.edg2.undoedge -expand yes # NORMALS *********************** set f $wd.nb.normals ttk::frame $f.dt -relief groove -borderwidth 3 pack $f.dt -fill x ttk::label $f.dt.lab -text "dirty triangle factor"; ttk::entry $f.dt.ent -width 5 \ -textvariable stldoctor.dirtytrigfact -validatecommand "Ng_SetSTLParameters;my_validate %W -1e9 1e9 %P 3" \ -invalidcommand "my_invalid %W;Ng_SetSTLParameters" -validate focus pack $f.dt.ent $f.dt.lab -side left -expand yes -pady 8 ttk::frame $f.srt -relief groove -borderwidth 3 pack $f.srt -fill x ttk::button $f.srt.bu -text "smooth reverted triangles geometric" -command {Ng_STLDoctor smoothrevertedtrigs; redraw } ttk::entry $f.srt.ent -width 5 \ -textvariable stldoctor.smoothangle -validatecommand "Ng_SetSTLParameters;my_validate %W -1e9 1e9 %P 2" \ -invalidcommand "my_invalid %W;Ng_SetSTLParameters" -validate focus pack $f.srt.ent $f.srt.bu -side left -expand yes -pady 8 ttk::frame $f.bdt -relief groove -borderwidth 3 pack $f.bdt -fill x ttk::button $f.bdt.bu -text "mark dirty triangles" -command {Ng_STLDoctor markdirtytrigs; redraw } ttk::button $f.bdt.bu2 -text "smooth dirty triangles normal" -command {Ng_STLDoctor smoothdirtytrigs; redraw } pack $f.bdt.bu $f.bdt.bu2 -side left -expand yes -pady 8 ttk::frame $f.sno -relief groove -borderwidth 3 pack $f.sno -fill x ttk::frame $f.sno.snoframe -borderwidth 0 #ttk::label $f.sno.labrough -text "rough" #scale $f.sno.scsmooth -orient horizontal -length 100 -from 0 -to 0.8 \ -resolution 0.01 -variable stldoctor.smoothnormalsweight \ -command { Ng_SetSTLParameters } #ttk::label $f.sno.labsmooth -text "smooth" ttk::button $f.sno.smoothnormals -text "smooth normals" -command { Ng_STLDoctor smoothnormals; redraw} ttk::scale $f.sno.snoframe.scale -orient horizontal -length 100 -from 0.0 -to 0.8 \ -variable stldoctor.smoothnormalsweight -takefocus 0 -command "roundscale $f.sno.snoframe.scale 2;Ng_SetSTLParameters" ttk::entry $f.sno.snoframe.entry -textvariable stldoctor.smoothnormalsweight -width 4 \ -validatecommand "Ng_SetSTLParameters;my_validate %W [$f.sno.snoframe.scale cget -from] [$f.sno.snoframe.scale cget -to] %P 2" \ -invalidcommand "my_invalid %W;Ng_SetSTLParameters" -validate focus ttk::label $f.sno.snoframe.labrough -text "rough" ttk::label $f.sno.snoframe.labsmooth -text "smooth" grid $f.sno.snoframe.labrough $f.sno.snoframe.scale $f.sno.snoframe.labsmooth $f.sno.snoframe.entry -sticky nw -padx 4 #pack $f.sno.labrough $f.sno.scsmooth $f.sno.labsmooth $f.sno.smoothnormals -side left -padx 5 pack $f.sno.snoframe $f.sno.smoothnormals -side left -padx 5 -pady 8 ttk::frame $f.no -relief groove -borderwidth 3 pack $f.no -fill x ttk::button $f.no.marknonsmoothnormals -text "mark non-smooth triangles" -command {Ng_STLDoctor marknonsmoothnormals; redraw} ttk::button $f.no.calcnormals -text "calculate normals from geometry" -command {Ng_STLDoctor calcnormals; redraw} pack $f.no.marknonsmoothnormals $f.no.calcnormals -expand yes -pady 8 # ADVANCED ************************** set f $wd.nb.advanced ttk::frame $f.sc pack $f.sc -fill x ttk::checkbutton $f.sc.bu -text "spiral check" \ -variable stldoctor.spiralcheck \ -command {Ng_STLDoctor;} ttk::checkbutton $f.sc.bu2 -text "cone check" \ -variable stldoctor.conecheck \ -command {Ng_STLDoctor;} pack $f.sc.bu $f.sc.bu2 #tixControl $f.gtol -label "load-geometry tolerance factor" -integer false \ # -variable stldoctor.geom_tol_fact \ # -options { # entry.width 8 # label.width 30 # label.anchor e #} ttk::label $f.gtol_lbl -text "LoadSTL tolerance factor" ttk::spinbox $f.gtol -from 1e-15 -to 0.001 -textvariable stldoctor.geom_tol_fact -width 8 pack $f.gtol_lbl $f.gtol ttk::button $f.adap -text "Apply" -command { Ng_STLDoctor; } pack $f.adap -expand yes # frame $f.gtol -relief groove -borderwidth 3 # pack $f.gtol -fill x # label $f.gtol.lab -text "Geometry-Load-Tolerance-Factor"; # entry $f.gtol.ent -width 5 -relief sunken \ # -textvariable stldoctor.geom_tol_fact # pack $f.gtol.lab $f.gtol.ent -side left -expand yes #******************************* wm withdraw $wd wm geom $wd +100+100 wm deiconify $wd wm title $wd "STL Doctor" focus $wd } } proc meshdoctordialog { } { set w .meshdoc_dlg global meshdoctor.active if {[winfo exists .meshdoc_dlg] == 1} { wm withdraw $w wm deiconify $w focus $w } { toplevel $w set meshdoctor.active 1 Ng_MeshDoctor; ttk::frame $w.vis -relief groove -borderwidth 3 pack $w.vis ttk::checkbutton $w.vis.showfilledtrigs -text "Show filled triangles" \ -variable viewoptions.drawfilledtrigs \ -command { Ng_SetVisParameters; redraw } ttk::checkbutton $w.vis.showedges -text "Show edges" \ -variable viewoptions.drawedges \ -command { Ng_SetVisParameters; redraw } ttk::checkbutton $w.vis.showoutline -text "Show Triangle Outline" \ -variable viewoptions.drawoutline \ -command { Ng_SetVisParameters; redraw } pack $w.vis.showfilledtrigs $w.vis.showoutline $w.vis.showedges ttk::frame $w.markedgedist ttk::label $w.markedgedist.l -text "Mark edge dist: " ttk::spinbox $w.markedgedist.s -from 0 -to 999 -width 5 -increment 1 -validate focus -validatecommand "my_validatespinbox %W %P 0" \ -invalidcommand "my_invalidspinbox %W" -command {Ng_MeshDoctor markedgedist ${meshdoc.markedgedist};redraw} -textvariable meshdoc.markedgedist #pack $f.grading -fill x pack $w.markedgedist.l $w.markedgedist.s -side left # tixControl $w.markedgedist -label "Mark edge dist: " -integer true \ # -min 0 -max 999 \ # -variable meshdoc.markedgedist \ # -options { # entry.width 3 # label.width 20 # label.anchor e # } \ # -command { # Ng_MeshDoctor markedgedist ${meshdoc.markedgedist} # redraw # } pack $w.markedgedist ttk::button $w.deledge -text "Delete marked segments" -command { Ng_MeshDoctor deletemarkedsegments redraw } pack $w.deledge ttk::button $w.close -text "Close" -command { set meshdoctor.active 0; Ng_MeshDoctor; destroy .meshdoc_dlg } pack $w.close -expand yes wm withdraw $w wm geom $w +100+100 wm deiconify $w wm title $w "Mesh Doctor" } } # # Quality viewer # proc qualityviewdialog { show } { set w .qualityview_dlg if {[winfo exists .qualityview_dlg] == 1} { if { $show == 1 } { wm withdraw .qualityview_dlg wm deiconify $w focus $w } { wm withdraw $w } } { toplevel $w set c $w.c canvas $c -relief raised -width 450 -height 300 pack $w.c -side top -fill x set plotFont {Helvetica 12} set smallFont {Helvetica 12} $c create line 100 250 400 250 -width 2 $c create line 100 250 100 50 -width 2 for {set i 0} {$i <= 10} {incr i} { set x [expr {100 + ($i*30)}] $c create line $x 250 $x 245 -width 2 if { [expr {$i % 2}] == 0 } { $c create text $x 254 -text [format %1.1f [expr 0.1*$i]] -anchor n -font $plotFont } } global qualbar global qualbarnull global qualbaraxis for {set i 0} {$i <= 5} {incr i} { set y [expr {250 - ($i*40)}] $c create line 100 $y 105 $y -width 2 # global qualbaraxis($i) set qualbaraxis($i) \ [$c create text 96 $y -text [expr $i*50].0 -anchor e -font $plotFont] } for {set i 0} {$i < 20} {incr i} { set x1 [expr {100 + ($i*15) + 2}] set x2 [expr {$x1+10}] set y [expr {250 - 10 * $i}] # global qualbar($i) set qualbar($i) [$c create rectangle $x1 250 $x2 245 -fill blue] set qualbarnull($i) [$c create text [expr {($x1+$x2)/2}] 245 -text 0 -anchor s -font $smallFont -fill blue] } frame $w.bu pack $w.bu # -fill x ttk::button $w.close -text "Close" \ -command { wm withdraw .qualityview_dlg set viewqualityplot 0 } pack $w.close if { $show == 1 } { wm withdraw $w wm geom $w +100+100 wm deiconify $w wm title $w "Mesh Quality" focus $w } } } # # Quality viewer # proc memusedialog { show } { set w .memuse_dlg if {[winfo exists .memuse_dlg] == 1} { if { $show == 1 } { wm withdraw .memuse_dlg wm deiconify $w focus $w } { wm withdraw $w } } { toplevel $w set c $w.c canvas $c -relief raised -width 600 -height 300 pack $w.c -side top -fill x set plotFont {Helvetica 18} set smallFont {Helvetica 12} global memmark for {set i 0} {$i < 512} { incr i } { set memmark($i) [$c create line [expr 50+$i] 50 [expr 50+$i] 70 -fill blue] } set plotFont {Helvetica 18} set smallFont {Helvetica 12} $c create text 50 90 -text "0 GB" -anchor n -font $plotFont $c create text 178 90 -text "1 GB" -anchor n -font $plotFont $c create text 306 90 -text "2 GB" -anchor n -font $plotFont $c create text 434 90 -text "3 GB" -anchor n -font $plotFont $c create text 562 90 -text "4 GB" -anchor n -font $plotFont ttk::frame $w.bu pack $w.bu # -fill x ttk::button $w.close -text "Close" \ -command { wm withdraw .memuse_dlg set memuseplot 0 } pack $w.close if { $show == 1 } { wm withdraw $w wm geom $w +100+100 wm deiconify $w wm title $w "Memory Usage" focus $w } } } # # STL INFO dialog # proc STLinfodialog { show } { set w .STLinfo_dlg if {[winfo exists .STLinfo_dlg] == 1} { if { $show == 1 } { wm withdraw .STLinfo_dlg wm deiconify $w focus $w } { wm withdraw $w } } { toplevel $w set c $w.c canvas $c -relief raised -width 450 -height 300 pack $w.c -side top -fill x set plotFont {Helvetica 18} set smallFont {Helvetica 12} $c create line 100 250 400 250 -width 2 $c create line 100 250 100 50 -width 2 ttk::frame $w.bu pack $w.bu # -fill x ttk::button $w.close -text "Close" \ -command { wm withdraw .STLinfo_dlg #set STLinfoopen 0 } pack $w.close if { $show == 1 } { wm withdraw $w wm geom $w +100+100 wm deiconify $w wm title $w "STL Geometry Info" focus $w } } } proc logwindow { } { set w .logwindow if {[winfo exists .logwindow] == 1} { wm withdraw $w wm deiconify $w focus $w } { toplevel $w text $w.edit -yscroll "$w.scrolly set" -setgrid 1 -height 12 scrollbar $w.scrolly -command "$w.edit yview" pack $w.edit -side left -fill both -expand 1 pack $w.scrolly -side left -fill both -expand 0 .logwindow.edit insert end "Netgen Log Window\n" wm withdraw $w wm geom $w +100+100 wm deiconify $w wm title $w "Netgen Log" focus $w } } # logwindow # Opens a window with a table. tablevar is a list, the first entry is the title, the second the number of rows, the third the number of columns, # then the entries follow. proc printtable { tablevar } { set w newtcltable while {[winfo exists .$w] == 1} {set w 1$w} set w .$w toplevel $w for {set i 0} {$i < [lindex $tablevar 2]} { incr i } { frame $w.col$i for {set j 0} {$j < [lindex $tablevar 1]} { incr j } { frame $w.col$i.row$j message $w.col$i.row$j.txt -aspect 10000000 -text [lindex $tablevar [expr 3+[lindex $tablevar 2]*$j+$i]] pack $w.col$i.row$j.txt pack $w.col$i.row$j -side top } pack $w.col$i -side left } wm withdraw $w wm geom $w +200+100; wm deiconify $w wm title $w [lindex $tablevar 0] focus $w } set latestwarning 0 proc printwarning { textvar } { global latestwarning set latestwarning $textvar set w warning while {[winfo exists .$w] == 1} {set w 1$w} set w .$w toplevel $w message $w.mes -aspect 2000 -text "WARNING:\n$textvar" ttk::button $w.done -text "Done" -command "destroy $w" pack $w.mes pack $w.done wm withdraw $w wm deiconify $w wm title $w "Warning" focus $w } proc printlatestwarning { } { global latestwarning if {$latestwarning != 0} {printwarning $latestwarning} } # proc runtestdialog { } { # source $::ngdir/ngshell.tcl # set w .runtest_dlg # if {[winfo exists .runtest_dlg] == 1} { # wm withdraw $w # wm deiconify $w # focus $w # } { # toplevel $w # # in2d testing # # frame $w.in2dframe # pack $w.in2dframe # set in2dlogfile "" # tixLabelEntry $w.in2dframe.ent -label "in2d log-file: console if empty" \ # -labelside top \ # -options { # entry.textVariable in2dlogfile # entry.width 35 # label.width 25 # label.anchor w # } # button $w.in2dframe.btn -text "Browse" -command { # set types { { "Log file" {.log} } } # set in2dlogfile [tk_getOpenFile -filetypes $types -initialfile $in2dlogfile] # } # button $w.in2dframe.test -text "Test in2d meshing" -command { ngtest in2d $in2dlogfile } # pack $w.in2dframe.test -side left -anchor s -padx 4 -pady 4 # pack $w.in2dframe.ent -side left -expand yes -fill x -anchor s -padx 4 -pady 4 # pack $w.in2dframe.btn -side left -anchor s -padx 4 -pady 4 # # geo testing # # frame $w.geoframe # pack $w.geoframe # set geologfile "" # tixLabelEntry $w.geoframe.ent -label "geo log-file: console if empty" \ # -labelside top \ # -options { # entry.textVariable geologfile # entry.width 35 # label.width 25 # label.anchor w # } # button $w.geoframe.btn -text "Browse" -command { # set types { { "Log file" {.log} } } # set geologfile [tk_getOpenFile -filetypes $types -initialfile $geologfile] # } # button $w.geoframe.test -text "Test geo meshing" -command { ngtest geo $geologfile } # pack $w.geoframe.test -side left -anchor s -padx 4 -pady 4 # pack $w.geoframe.ent -side left -expand yes -fill x -anchor s -padx 4 -pady 4 # pack $w.geoframe.btn -side left -anchor s -padx 4 -pady 4 # # stl testing # # frame $w.stlframe # pack $w.stlframe # set stllogfile "" # tixLabelEntry $w.stlframe.ent -label "stl log-file: console if empty" \ # -labelside top \ # -options { # entry.textVariable stllogfile # entry.width 35 # label.width 25 # label.anchor w # } # button $w.stlframe.btn -text "Browse" -command { # set types { { "Log file" {.log} } } # set stllogfile [tk_getOpenFile -filetypes $types -initialfile $stllogfile] # } # button $w.stlframe.test -text "Test stl meshing" -command { ngtest stl $stllogfile } # pack $w.stlframe.test -side left -anchor s -padx 4 -pady 4 # pack $w.stlframe.ent -side left -expand yes -fill x -anchor s -padx 4 -pady 4 # pack $w.stlframe.btn -side left -anchor s -padx 4 -pady 4 # # pde testing # # frame $w.pdeframe # pack $w.pdeframe # set pdelogfile "" # tixLabelEntry $w.pdeframe.ent -label "pde log-file: console if empty" \ # -labelside top \ # -options { # entry.textVariable pdelogfile # entry.width 35 # label.width 25 # label.anchor w # } # button $w.pdeframe.btn -text "Browse" -command { # set types { { "Log file" {.log} } } # set pdelogfile [tk_getOpenFile -filetypes $types -initialfile $pdelogfile] # } # button $w.pdeframe.test -text "Test ngsolve pde's" -command { ngtest pde $pdelogfile } # pack $w.pdeframe.test -side left -anchor s -padx 4 -pady 4 # pack $w.pdeframe.ent -side left -expand yes -fill x -anchor s -padx 4 -pady 4 # pack $w.pdeframe.btn -side left -anchor s -padx 4 -pady 4 # wm title $w "Testing" # focus .runtest_dlg # } # } ================================================ FILE: ng/drawing.tcl ================================================ # # Creates a drawing frame, and binds mouse events # set oldmousex 0 set oldmousey 0 # # if { 1 } { # use this one for Togl 2.0 #if {[catch {togl .ndraw -width 400 -height 300 -rgba true -double true -depth true -privatecmap false -stereo false -indirect false }] } { # if {[catch {togl .ndraw -width 400 -height 300 -rgba true -double true -depth true -privatecmap false -stereo false -indirect false -create init -display draw -reshape reshape }] } { # puts "no OpenGL" # } { set toglversion [Ng_GetToglVersion] puts "togl-version : $toglversion" set toglok 0 if { [Ng_GetToglVersion] == 2 } { # Togl 2.x if {[catch {togl .ndraw -width 400 -height 300 -rgba true -double true -depth true -privatecmap false -stereo false -indirect false -create init -display draw -reshape reshape }] } { puts "no OpenGL" } { # puts "have Togl 2.1" set toglok 1 } } if { $toglok == 1} { # pack .ndraw -expand true -fill both -padx 0 -pady 0 catch { tkdnd::drop_target register .ndraw DND_Files } # bind .ndraw { set oldmousex %x; set oldmousey %y; } bind .ndraw { set oldmousex %x; set oldmousey %y; } bind .ndraw { set oldmousex %x; set oldmousey %y; } bind .ndraw { Ng_MouseMove $oldmousex $oldmousey %x %y $drawmode .ndraw render set oldmousex %x; set oldmousey %y; } bind .ndraw { Ng_MouseDblClick %x %y .ndraw render if { [winfo exists .bcprop_dlg] } { bcpropdialog } if { [winfo exists .surfacemeshsize_dlg] } { surfacemeshsizedialog } if { [winfo exists .fieldlines_dlg] } { fieldlinesdialog } } bind .ndraw { Ng_MouseMove $oldmousex $oldmousey %x %y move .ndraw render set oldmousex %x; set oldmousey %y; } bind .ndraw { if { $tcl_platform(os) == "Darwin" } { Ng_MouseMove $oldmousex $oldmousey %x %y move } { Ng_MouseMove $oldmousex $oldmousey %x %y zoom } .ndraw render set oldmousex %x; set oldmousey %y; } bind .ndraw { Ng_MouseMove $oldmousex $oldmousey %x %y Move2d .ndraw render set oldmousex %x; set oldmousey %y; } bind .ndraw { Ng_MouseMove $oldmousex $oldmousey %x %y Zoom2d .ndraw render set oldmousex %x; set oldmousey %y; } } proc popupcheckredraw { vari { x 0 } } { upvar $vari varname if { $varname == 1 } { set varname 0 } { # puts "popup-redraw $vari" Ng_Vis_Set parameters redraw } } proc popupcheckredraw2 { vari boolvar { x 0 } } { upvar $vari varname if { $varname == 1 } { set varname 0 } { Ng_SetVisParameters Ng_Vis_Set parameters if { $boolvar == 1 } { redraw } Ng_SetVisParameters } } proc popupcheckredraw3 { vari { x 0 } } { upvar $vari varname if { $varname == 1 } { set varname 0 } { Ng_Vis_Set parameters } } proc redraw { {x 0} } { if {[winfo exists .ndraw]} { .ndraw render } } bind . { Ng_MouseMove 0 0 -10 0 rotate; redraw } bind . { Ng_MouseMove 0 0 10 0 rotate; redraw } bind . { Ng_MouseMove 0 0 0 -10 rotate; redraw } bind . { Ng_MouseMove 0 0 0 10 rotate; redraw } bind . { Ng_MouseMove 0 0 -10 0 move; redraw } bind . { Ng_MouseMove 0 0 10 0 move; redraw } bind . { Ng_MouseMove 0 0 0 -10 move; redraw } bind . { Ng_MouseMove 0 0 0 10 move; redraw } bind . { Ng_MouseMove 0 0 0 -10 zoom; redraw } bind . { Ng_MouseMove 0 0 0 10 zoom; redraw } bind . \ {event generate [focus -displayof %W] -delta 120} bind . \ {event generate [focus -displayof %W] -delta -120} bind . { Ng_MouseMove 0 0 0 [expr {%D/-5}] zoom; redraw } # Drop callbacks: bind .ndraw <> { #tk_messageBox -message "Dropped files: \"[join %D {, }]\"" set filename [join %D " "] #%W state !active set index [string last . $filename] #tk_messageBox -message $index set type [string range $filename $index+1 end] # tk_messageBox -message $type set ispde [string match -nocase $type "pde"] set isgeo [expr max([string match -nocase $type "geo"],[string match -nocase $type "in2d"])] set ismesh [expr max([string match -nocase $type "vol"],[string match -nocase $type "vol.gz"])] set ispy [string match -nocase $type "py"] if {$ispde == 1} { AddRecentNGSFile $filename; NGS_LoadPDE $filename; SetNumProcHelpMenu set selectvisual mesh; Ng_SetVisParameters } if {$ispy == 1} { AddRecentPYNGSFile $filename; NGS_LoadPy $filename; } if {$isgeo == 1} { AddRecentFile $filename; Ng_LoadGeometry $filename; Ng_ParseGeometry set selectvisual geometry Ng_SetVisParameters redraw wm title . [concat "$progname - " $filename] set dirname [file dirname $filename] set basefilename [file tail [file rootname $filename]] } if {$ismesh == 1} { AddRecentMeshFile $filename; Ng_LoadMesh $filename; set selectvisual mesh Ng_SetVisParameters redraw Ng_ReadStatus; wm title . [concat "$progname - " %D] set dirname [file dirname %D] set basefilename [file tail [file rootname %D]] } return %A } ================================================ FILE: ng/drawing_togl17.tcl ================================================ # # Creates a drawing frame, and binds mouse events # set oldmousex 0 set oldmousey 0 # # if { 1 } { if {[catch {togl .ndraw -width 400 -height 300 -rgba true -double true -depth true -privatecmap false -stereo false -indirect false }] } { puts "no OpenGL" } { # pack .ndraw -expand true -fill both -padx 10 -pady 10 catch { tkdnd::drop_target register .ndraw DND_Files } # bind .ndraw { set oldmousex %x; set oldmousey %y; } bind .ndraw { set oldmousex %x; set oldmousey %y; } bind .ndraw { set oldmousex %x; set oldmousey %y; } bind .ndraw { Ng_MouseMove $oldmousex $oldmousey %x %y $drawmode .ndraw render set oldmousex %x; set oldmousey %y; } bind .ndraw { Ng_MouseDblClick %x %y .ndraw render if { [winfo exists .bcprop_dlg] } { bcpropdialog } if { [winfo exists .surfacemeshsize_dlg] } { surfacemeshsizedialog } if { [winfo exists .fieldlines_dlg] } { fieldlinesdialog } } bind .ndraw { Ng_MouseMove $oldmousex $oldmousey %x %y move .ndraw render set oldmousex %x; set oldmousey %y; } bind .ndraw { if { $tcl_platform(os) == "Darwin" } { Ng_MouseMove $oldmousex $oldmousey %x %y move } { Ng_MouseMove $oldmousex $oldmousey %x %y zoom } .ndraw render set oldmousex %x; set oldmousey %y; } bind .ndraw { Ng_MouseMove $oldmousex $oldmousey %x %y Move2d .ndraw render set oldmousex %x; set oldmousey %y; } bind .ndraw { Ng_MouseMove $oldmousex $oldmousey %x %y Zoom2d .ndraw render set oldmousex %x; set oldmousey %y; } } proc popupcheckredraw { vari { x 0 } } { upvar $vari varname if { $varname == 1 } { set varname 0 } { # puts "popup-redraw $vari" Ng_Vis_Set parameters redraw } } proc popupcheckredraw2 { vari boolvar { x 0 } } { upvar $vari varname if { $varname == 1 } { set varname 0 } { Ng_SetVisParameters Ng_Vis_Set parameters if { $boolvar == 1 } { redraw } Ng_SetVisParameters } } proc popupcheckredraw3 { vari { x 0 } } { upvar $vari varname if { $varname == 1 } { set varname 0 } { Ng_Vis_Set parameters } } proc redraw { {x 0} } { if {[winfo exists .ndraw]} { .ndraw render } } bind . { Ng_MouseMove 0 0 -10 0 rotate; redraw } bind . { Ng_MouseMove 0 0 10 0 rotate; redraw } bind . { Ng_MouseMove 0 0 0 -10 rotate; redraw } bind . { Ng_MouseMove 0 0 0 10 rotate; redraw } bind . { Ng_MouseMove 0 0 -10 0 move; redraw } bind . { Ng_MouseMove 0 0 10 0 move; redraw } bind . { Ng_MouseMove 0 0 0 -10 move; redraw } bind . { Ng_MouseMove 0 0 0 10 move; redraw } bind . { Ng_MouseMove 0 0 0 -10 zoom; redraw } bind . { Ng_MouseMove 0 0 0 10 zoom; redraw } bind . \ {event generate [focus -displayof %W] -delta 120} bind . \ {event generate [focus -displayof %W] -delta -120} bind . { Ng_MouseMove 0 0 0 [expr {%D/-5}] zoom; redraw } # Drop callbacks: bind .ndraw <> { #tk_messageBox -message "Dropped files: \"[join %D {, }]\"" #%W state !active set index [string first . %D end-6] #tk_messageBox -message $index set type [string range %D $index+1 end] # tk_messageBox -message $type set ispde [string match -nocase $type "pde"] set isgeo [expr max([string match -nocase $type "geo"],[string match -nocase $type "in2d"])] set ismesh [expr max([string match -nocase $type "vol"],[string match -nocase $type "vol.gz"])] set ispy [string match -nocase $type "py"] if {$ispde == 1} { AddRecentNGSFile %D; NGS_LoadPDE %D; SetNumProcHelpMenu set selectvisual mesh; Ng_SetVisParameters } if {$ispy == 1} { AddRecentPYNGSFile %D; NGS_LoadPy %D; } if {$isgeo == 1} { AddRecentFile %D; Ng_LoadGeometry %D; Ng_ParseGeometry set selectvisual geometry Ng_SetVisParameters redraw wm title . [concat "$progname - " %D] set dirname [file dirname %D] set basefilename [file tail [file rootname %D]] } if {$ismesh == 1} { AddRecentMeshFile %D; Ng_LoadMesh %D; set selectvisual mesh Ng_SetVisParameters redraw Ng_ReadStatus; wm title . [concat "$progname - " %D] set dirname [file dirname %D] set basefilename [file tail [file rootname %D]] } return %A } ================================================ FILE: ng/encoding.hpp ================================================ #ifndef ENCODING_HPP_INCLUDED__ #define ENCODING_HPP_INCLUDED__ #ifdef FFMPEG extern "C" { #include #include #include #include #include #include #include #include #include #include } constexpr int BITRATE = 50000000; class Mpeg { private: bool is_started =false; int framerate = 25; AVOutputFormat *fmt; AVFormatContext *oc; AVStream *st; AVCodecContext *enc; AVFrame *frame; AVFrame *rgb_frame; uint8_t *rgb_buffer; struct SwsContext *sws_ctx; AVFrame *alloc_picture(enum AVPixelFormat pix_fmt) { AVFrame *picture; picture = av_frame_alloc(); if (!picture) return NULL; picture->format = pix_fmt; picture->width = width; picture->height = height; av_frame_get_buffer(picture, 32); return picture; } public: int width; int height; bool IsStarted() { return is_started; } int AddFrame() { int ret; int got_packet = 0; AVPacket pkt = { 0 }; glReadPixels (0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, rgb_buffer); av_image_fill_arrays(rgb_frame->data, rgb_frame->linesize, rgb_buffer, AV_PIX_FMT_RGB24, width, height, 1); if (av_frame_make_writable(frame) < 0) return 1; // The picture is upside down - flip it: auto data = rgb_frame->data[0] + 3*width*height; uint8_t *flipped_data[4] = { data, data, data, data }; int flipped_stride[4] = { -rgb_frame->linesize[0], -rgb_frame->linesize[1], -rgb_frame->linesize[2], -rgb_frame->linesize[3] }; sws_scale(sws_ctx, flipped_data, flipped_stride, 0, enc->height, frame->data, frame->linesize); av_init_packet(&pkt); got_packet = 0; ret = avcodec_send_frame(enc, frame); if (ret < 0) { cerr << "Error encoding video frame: " << endl; return(1); } ret = avcodec_receive_packet(enc, &pkt); if (!ret) got_packet = 1; if (ret == AVERROR(EAGAIN)) return 0; if (ret < 0) { cerr << "Error encoding video frame: " << endl; return 1; } if (got_packet) { /* rescale output packet timestamp values from codec to stream timebase */ av_packet_rescale_ts(&pkt, enc->time_base, st->time_base); pkt.stream_index = st->index; /* Write the compressed frame to the media file. */ ret = av_interleaved_write_frame(oc, &pkt); } else { ret = 0; } if (ret < 0) { cerr << "Error while writing video frame: " << endl; return(1); } return 0; } int Start(string filename) { AVCodec *video_codec; if(is_started) { cerr << "Stream already started" << endl; return 1; } is_started = true; GLint dims[4] = {0}; glGetIntegerv(GL_VIEWPORT, dims); width = dims[2]; height= dims[3]; width = int((width+1)/4)*4+4; height = 2 * (height/2); int ret; int i; // av_register_all(); avformat_alloc_output_context2(&oc, NULL, NULL, filename.c_str()); // oc->preload= (int)(0.5*AV_TIME_BASE); oc->max_delay= (int)(0.7*AV_TIME_BASE); fmt = (AVOutputFormat*) oc->oformat; if (fmt->video_codec != AV_CODEC_ID_NONE) { /* find the encoder */ video_codec = (AVCodec*) avcodec_find_encoder(fmt->video_codec); if (!(video_codec)) { cerr << "Could not find encoder for '" << avcodec_get_name(fmt->video_codec) << "'" << endl; return 1; } st = avformat_new_stream(oc, NULL); if (!st) { cerr << "Could not allocate stream\n"; return 1; } st->id = oc->nb_streams-1; enc = avcodec_alloc_context3(video_codec); if (!enc) { cerr << "Could not alloc an encoding context\n"; return 1; } enc->codec_id = fmt->video_codec; enc->bit_rate = BITRATE; enc->width = width; enc->height = height; AVRational tb; tb.num=1; tb.den=framerate; st->time_base = tb; enc->time_base = st->time_base; enc->gop_size = 200; enc->pix_fmt = AV_PIX_FMT_YUV420P; if (enc->codec_id == AV_CODEC_ID_MPEG2VIDEO) { enc->max_b_frames = 3; } if (enc->codec_id == AV_CODEC_ID_MPEG1VIDEO) { enc->mb_decision = 2; } if (oc->oformat->flags & AVFMT_GLOBALHEADER) enc->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; // enc->flags |= CODEC_FLAG_QSCALE; // enc->global_quality = 1180; } else { cerr << "could not init codecs!" << endl; return 1; } AVDictionary *opt = NULL; /* open the codec */ ret = avcodec_open2(enc, video_codec, &opt); av_dict_free(&opt); if (ret < 0) { cerr << "Could not open video codec" << endl; return 1; } /* allocate and init a re-usable frame */ frame = alloc_picture(enc->pix_fmt); if (!frame) { cerr << "Could not allocate video frame\n"; return 1; } /* copy the stream parameters to the muxer */ ret = avcodec_parameters_from_context(st->codecpar, enc); if (ret < 0) { cerr << "Could not copy the stream parameters\n"; return 1; } av_dump_format(oc, 0, filename.c_str(), 1); if (!(fmt->flags & AVFMT_NOFILE)) { ret = avio_open(&oc->pb, filename.c_str(), AVIO_FLAG_WRITE); if (ret < 0) { cerr << "Could not open " << filename << " : " << endl; return 1; } } ret = avformat_write_header(oc, &opt); if (ret < 0) { cerr << "Error occurred when opening output file: " << endl;; return 1; } rgb_frame = alloc_picture(AV_PIX_FMT_RGB24); rgb_buffer = new uint8_t[width*height*4]; sws_ctx = sws_getContext( width, height, AV_PIX_FMT_RGB24, width, height, AV_PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL ); return 0; } void Stop() { av_write_trailer(oc); avcodec_free_context(&enc); av_frame_free(&frame); sws_freeContext(sws_ctx); if (!(fmt->flags & AVFMT_NOFILE)) avio_closep(&oc->pb); avformat_free_context(oc); delete [] rgb_buffer; is_started = false; } }; #endif // FFMPEG #endif // ENCODING_HPP_INCLUDED__ ================================================ FILE: ng/fonts.hpp ================================================ #define font12_width 591 #define font12_height 12 static unsigned char font12_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x00, 0xA1, 0x28, 0x84, 0x44, 0x10, 0x88, 0x00, 0x00, 0x00, 0x00, 0x40, 0x0E, 0xE1, 0x38, 0xD0, 0xE7, 0x7C, 0x8E, 0x03, 0x00, 0x00, 0x00, 0x38, 0x8E, 0xF3, 0x38, 0xC7, 0xF7, 0x39, 0x91, 0xC3, 0x45, 0x41, 0x14, 0x39, 0x8F, 0xF3, 0x38, 0x5F, 0x14, 0x45, 0x51, 0xF4, 0x39, 0x82, 0xA3, 0x00, 0x00, 0x10, 0x00, 0x10, 0x80, 0x01, 0x01, 0x01, 0x09, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x60, 0x84, 0x51, 0x01, 0x00, 0x00, 0x00, 0xA1, 0x28, 0x4E, 0xA5, 0x10, 0x04, 0x01, 0x00, 0x00, 0x00, 0x40, 0x91, 0x11, 0x45, 0x58, 0x10, 0x40, 0x51, 0x04, 0x00, 0x10, 0x20, 0x44, 0x51, 0x14, 0x45, 0x49, 0x10, 0x44, 0x11, 0x81, 0x24, 0xC1, 0x16, 0x45, 0x51, 0x14, 0x45, 0x44, 0x14, 0x45, 0x51, 0x04, 0x09, 0x02, 0x12, 0x01, 0x00, 0x10, 0x00, 0x10, 0x40, 0x00, 0x01, 0x00, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x10, 0x04, 0x92, 0x00, 0x00, 0x00, 0x00, 0x01, 0x7C, 0x95, 0xA2, 0x00, 0x02, 0xA2, 0x10, 0x00, 0x00, 0x20, 0x19, 0x11, 0x41, 0x54, 0x10, 0x40, 0x51, 0x44, 0x10, 0xC8, 0x47, 0x44, 0x59, 0x14, 0x05, 0x51, 0x10, 0x04, 0x11, 0x81, 0x14, 0x41, 0x35, 0x45, 0x51, 0x14, 0x05, 0x44, 0x14, 0x45, 0x8A, 0x82, 0x08, 0x04, 0x02, 0x00, 0x80, 0xF3, 0x38, 0x9E, 0xE3, 0x78, 0x8F, 0x81, 0x49, 0xC4, 0xF3, 0x38, 0x8F, 0xD7, 0x79, 0x4E, 0x14, 0x45, 0x51, 0xF4, 0x11, 0x04, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x28, 0x05, 0x42, 0x00, 0x02, 0x42, 0x10, 0x00, 0x00, 0x20, 0x15, 0x01, 0x31, 0xD2, 0xF3, 0x20, 0x4E, 0x44, 0x10, 0x04, 0x80, 0x20, 0x55, 0xF4, 0x04, 0xD1, 0xF3, 0x04, 0x1F, 0x81, 0x0C, 0x41, 0x55, 0x45, 0x51, 0x14, 0x39, 0x44, 0xA4, 0x44, 0x84, 0x42, 0x08, 0x04, 0x02, 0x00, 0x00, 0x14, 0x45, 0x51, 0x44, 0x44, 0x11, 0x01, 0x29, 0x44, 0x15, 0x45, 0x51, 0x34, 0x04, 0x44, 0x14, 0x45, 0x4A, 0x84, 0x08, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x28, 0x0E, 0x61, 0x01, 0x02, 0xF2, 0x7D, 0xC0, 0x07, 0x10, 0x13, 0x81, 0x40, 0x11, 0x14, 0x21, 0x91, 0x07, 0x00, 0x02, 0x00, 0x11, 0xD5, 0x17, 0x05, 0x51, 0x10, 0x74, 0x11, 0x81, 0x0C, 0x41, 0x94, 0x45, 0x4F, 0xF4, 0x40, 0x44, 0xA4, 0x54, 0x04, 0x21, 0x08, 0x08, 0x02, 0x00, 0x80, 0x17, 0x05, 0xD1, 0x47, 0x44, 0x11, 0x01, 0x19, 0x44, 0x15, 0x45, 0x51, 0x14, 0x38, 0x44, 0xA4, 0x54, 0x44, 0x44, 0x10, 0x04, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x14, 0x95, 0x00, 0x02, 0x42, 0x10, 0x00, 0x00, 0x10, 0x11, 0x41, 0x40, 0x1F, 0x14, 0x11, 0x11, 0x04, 0x00, 0xC4, 0x87, 0x00, 0x59, 0x14, 0x05, 0x51, 0x10, 0x44, 0x11, 0x91, 0x14, 0x41, 0x14, 0x45, 0x41, 0x54, 0x40, 0x44, 0xA4, 0x54, 0x0A, 0x11, 0x08, 0x08, 0x02, 0x00, 0x40, 0x14, 0x05, 0x51, 0x40, 0x44, 0x11, 0x01, 0x19, 0x44, 0x15, 0x45, 0x51, 0x14, 0x40, 0x44, 0xA4, 0x54, 0x44, 0x24, 0x10, 0x04, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x28, 0x95, 0x9A, 0x00, 0x04, 0xA1, 0x10, 0x04, 0x40, 0x08, 0x11, 0x21, 0x44, 0x50, 0x14, 0x11, 0x11, 0x44, 0x10, 0x08, 0x40, 0x10, 0x41, 0x14, 0x45, 0x49, 0x10, 0x44, 0x11, 0x91, 0x24, 0x41, 0x14, 0x45, 0x41, 0x95, 0x44, 0x44, 0x44, 0x6C, 0x11, 0x11, 0x08, 0x10, 0x02, 0x00, 0x40, 0x14, 0x45, 0x51, 0x40, 0x44, 0x11, 0x01, 0x29, 0x44, 0x15, 0x45, 0x51, 0x14, 0x40, 0x44, 0x44, 0x54, 0x4A, 0x14, 0x10, 0x04, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x28, 0x8E, 0x64, 0x01, 0x88, 0x00, 0x00, 0x04, 0x40, 0x08, 0x8E, 0xF3, 0x39, 0x90, 0xE3, 0x10, 0x8E, 0x43, 0x10, 0x10, 0x20, 0x10, 0x5E, 0xF4, 0x38, 0xC7, 0x17, 0x38, 0x91, 0x63, 0x44, 0x5F, 0x14, 0x39, 0x81, 0x13, 0x39, 0x84, 0x43, 0x44, 0x11, 0xF1, 0x39, 0x90, 0x03, 0x00, 0x80, 0xF7, 0x38, 0x9E, 0x47, 0x78, 0x91, 0x03, 0x49, 0x4E, 0x15, 0x39, 0x8F, 0x17, 0x3C, 0x98, 0x47, 0x38, 0x91, 0xF7, 0x61, 0x84, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x20, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; #define font14_width 789 #define font14_height 14 static unsigned char font14_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x00, 0x08, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x66, 0x36, 0x08, 0x66, 0x1C, 0x18, 0x30, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x3E, 0x18, 0x3E, 0x3E, 0x60, 0x7F, 0x3C, 0x7F, 0x3E, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x3E, 0x3E, 0x3F, 0x3E, 0x1F, 0x7F, 0x7F, 0x3E, 0x63, 0x3C, 0x78, 0x63, 0x03, 0x41, 0x63, 0x3E, 0x3F, 0x3E, 0x3F, 0x3E, 0xFF, 0x63, 0x63, 0x63, 0x63, 0xC3, 0x7F, 0x3C, 0x06, 0x3C, 0x3C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x60, 0x00, 0x78, 0x00, 0x03, 0x18, 0x60, 0x03, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x18, 0x0E, 0xDB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x66, 0x36, 0x3E, 0x6B, 0x36, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x63, 0x1C, 0x63, 0x63, 0x70, 0x03, 0x06, 0x60, 0x63, 0x63, 0x00, 0x00, 0x60, 0x00, 0x06, 0x63, 0x63, 0x63, 0x63, 0x63, 0x33, 0x03, 0x03, 0x63, 0x63, 0x18, 0x30, 0x63, 0x03, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x18, 0x63, 0x63, 0x63, 0x63, 0xC3, 0x60, 0x0C, 0x06, 0x30, 0x66, 0x00, 0x00, 0x00, 0x03, 0x00, 0x60, 0x00, 0x0C, 0x00, 0x03, 0x18, 0x60, 0x03, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x18, 0x18, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x36, 0x6B, 0x36, 0x36, 0x00, 0x0C, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x63, 0x1E, 0x63, 0x63, 0x78, 0x03, 0x03, 0x60, 0x63, 0x63, 0x00, 0x00, 0x30, 0x00, 0x0C, 0x63, 0x73, 0x63, 0x63, 0x63, 0x63, 0x03, 0x03, 0x63, 0x63, 0x18, 0x30, 0x33, 0x03, 0x77, 0x63, 0x63, 0x63, 0x63, 0x63, 0x03, 0x18, 0x63, 0x63, 0x63, 0x36, 0x66, 0x60, 0x0C, 0x0C, 0x30, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x60, 0x00, 0x0C, 0x00, 0x03, 0x00, 0x00, 0x03, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x7F, 0x0B, 0x30, 0x1C, 0x00, 0x0C, 0x30, 0x36, 0x18, 0x00, 0x00, 0x00, 0x30, 0x73, 0x18, 0x60, 0x60, 0x6C, 0x03, 0x03, 0x30, 0x63, 0x63, 0x18, 0x18, 0x18, 0x7F, 0x18, 0x63, 0x6B, 0x63, 0x63, 0x03, 0x63, 0x03, 0x03, 0x03, 0x63, 0x18, 0x30, 0x1B, 0x03, 0x7F, 0x67, 0x63, 0x63, 0x63, 0x63, 0x03, 0x18, 0x63, 0x63, 0x63, 0x36, 0x66, 0x30, 0x0C, 0x0C, 0x30, 0x00, 0x00, 0x00, 0x3E, 0x3F, 0x3E, 0x7E, 0x3E, 0x3F, 0x7E, 0x3F, 0x1C, 0x70, 0x63, 0x18, 0x3F, 0x3F, 0x3E, 0x3F, 0x7E, 0x7B, 0x7E, 0x3F, 0x63, 0x63, 0x63, 0x63, 0x63, 0x7F, 0x0C, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x36, 0x0B, 0x18, 0x6E, 0x00, 0x0C, 0x30, 0x1C, 0x18, 0x00, 0x00, 0x00, 0x18, 0x7B, 0x18, 0x30, 0x3C, 0x66, 0x3F, 0x3F, 0x30, 0x3E, 0x63, 0x18, 0x18, 0x0C, 0x00, 0x30, 0x30, 0x6B, 0x63, 0x3F, 0x03, 0x63, 0x1F, 0x1F, 0x03, 0x7F, 0x18, 0x30, 0x0F, 0x03, 0x6B, 0x6F, 0x63, 0x63, 0x63, 0x63, 0x3E, 0x18, 0x63, 0x63, 0x63, 0x1C, 0x3C, 0x18, 0x0C, 0x18, 0x30, 0x00, 0x00, 0x00, 0x60, 0x63, 0x63, 0x63, 0x63, 0x0C, 0x63, 0x63, 0x18, 0x60, 0x33, 0x18, 0x6B, 0x63, 0x63, 0x63, 0x63, 0x0F, 0x03, 0x0C, 0x63, 0x63, 0x63, 0x63, 0x63, 0x30, 0x06, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x36, 0x3E, 0x18, 0x3B, 0x00, 0x0C, 0x30, 0x7F, 0x7E, 0x00, 0x7F, 0x00, 0x18, 0x6F, 0x18, 0x18, 0x60, 0x63, 0x60, 0x63, 0x18, 0x63, 0x7E, 0x00, 0x00, 0x06, 0x00, 0x60, 0x18, 0x6B, 0x7F, 0x63, 0x03, 0x63, 0x03, 0x03, 0x7B, 0x63, 0x18, 0x30, 0x0F, 0x03, 0x63, 0x7B, 0x63, 0x3F, 0x63, 0x3F, 0x60, 0x18, 0x63, 0x36, 0x6B, 0x1C, 0x18, 0x0C, 0x0C, 0x18, 0x30, 0x00, 0x00, 0x00, 0x7E, 0x63, 0x03, 0x63, 0x63, 0x0C, 0x63, 0x63, 0x18, 0x60, 0x1B, 0x18, 0x6B, 0x63, 0x63, 0x63, 0x63, 0x07, 0x03, 0x0C, 0x63, 0x63, 0x6B, 0x36, 0x63, 0x18, 0x0C, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x7F, 0x68, 0x0C, 0x33, 0x00, 0x0C, 0x30, 0x1C, 0x18, 0x00, 0x00, 0x00, 0x0C, 0x67, 0x18, 0x0C, 0x60, 0x7F, 0x60, 0x63, 0x18, 0x63, 0x60, 0x00, 0x00, 0x0C, 0x7F, 0x30, 0x18, 0x6B, 0x63, 0x63, 0x03, 0x63, 0x03, 0x03, 0x63, 0x63, 0x18, 0x30, 0x1B, 0x03, 0x63, 0x73, 0x63, 0x03, 0x63, 0x0F, 0x60, 0x18, 0x63, 0x36, 0x7F, 0x36, 0x18, 0x06, 0x0C, 0x30, 0x30, 0x00, 0x00, 0x00, 0x63, 0x63, 0x03, 0x63, 0x7F, 0x0C, 0x63, 0x63, 0x18, 0x60, 0x0F, 0x18, 0x6B, 0x63, 0x63, 0x63, 0x63, 0x03, 0x3E, 0x0C, 0x63, 0x36, 0x6B, 0x1C, 0x63, 0x0C, 0x0C, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x68, 0x6C, 0x33, 0x00, 0x0C, 0x30, 0x36, 0x18, 0x00, 0x00, 0x00, 0x0C, 0x63, 0x18, 0x06, 0x63, 0x60, 0x60, 0x63, 0x0C, 0x63, 0x60, 0x00, 0x00, 0x18, 0x00, 0x18, 0x00, 0x73, 0x63, 0x63, 0x63, 0x63, 0x03, 0x03, 0x63, 0x63, 0x18, 0x33, 0x33, 0x03, 0x63, 0x63, 0x63, 0x03, 0x63, 0x1B, 0x63, 0x18, 0x63, 0x36, 0x77, 0x36, 0x18, 0x03, 0x0C, 0x30, 0x30, 0x00, 0x00, 0x00, 0x63, 0x63, 0x03, 0x63, 0x03, 0x0C, 0x63, 0x63, 0x18, 0x60, 0x1B, 0x18, 0x6B, 0x63, 0x63, 0x63, 0x63, 0x03, 0x60, 0x0C, 0x63, 0x36, 0x6B, 0x36, 0x63, 0x06, 0x0C, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x36, 0x6B, 0xD6, 0x3B, 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x00, 0x18, 0x06, 0x63, 0x18, 0x03, 0x63, 0x60, 0x63, 0x63, 0x0C, 0x63, 0x30, 0x18, 0x18, 0x30, 0x00, 0x0C, 0x18, 0x03, 0x63, 0x63, 0x63, 0x33, 0x03, 0x03, 0x63, 0x63, 0x18, 0x33, 0x63, 0x03, 0x63, 0x63, 0x63, 0x03, 0x7B, 0x33, 0x63, 0x18, 0x63, 0x1C, 0x63, 0x63, 0x18, 0x03, 0x0C, 0x60, 0x30, 0x00, 0x00, 0x00, 0x63, 0x63, 0x63, 0x63, 0x03, 0x0C, 0x63, 0x63, 0x18, 0x60, 0x33, 0x18, 0x6B, 0x63, 0x63, 0x63, 0x63, 0x03, 0x60, 0x0C, 0x63, 0x1C, 0x6B, 0x63, 0x63, 0x03, 0x0C, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x36, 0x3E, 0x66, 0x6E, 0x00, 0x30, 0x0C, 0x00, 0x00, 0x18, 0x00, 0x18, 0x06, 0x3E, 0x7E, 0x7F, 0x3E, 0x60, 0x3E, 0x3E, 0x0C, 0x3E, 0x1E, 0x18, 0x18, 0x60, 0x00, 0x06, 0x18, 0x7E, 0x63, 0x3F, 0x3E, 0x1F, 0x7F, 0x03, 0x3E, 0x63, 0x3C, 0x1E, 0x63, 0x7F, 0x63, 0x63, 0x3E, 0x03, 0x3E, 0x63, 0x3E, 0x18, 0x3E, 0x1C, 0x41, 0x63, 0x18, 0x7F, 0x3C, 0x60, 0x3C, 0x00, 0x00, 0x00, 0x7E, 0x3F, 0x3E, 0x7E, 0x3E, 0x0C, 0x7E, 0x63, 0x3C, 0x66, 0x63, 0x3C, 0x6B, 0x63, 0x3E, 0x3F, 0x7E, 0x03, 0x3F, 0x78, 0x7E, 0x1C, 0x3E, 0x63, 0x7E, 0x7F, 0x38, 0x18, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; #define font16_width 789 #define font16_height 16 static unsigned char font16_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x00, 0x08, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x66, 0x36, 0x08, 0x66, 0x1C, 0x18, 0x30, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x3E, 0x18, 0x3E, 0x3E, 0x60, 0x7F, 0x3C, 0x7F, 0x3E, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x3E, 0x3E, 0x3F, 0x3E, 0x1F, 0x7F, 0x7F, 0x3E, 0x63, 0x3C, 0x78, 0x63, 0x03, 0x41, 0x63, 0x3E, 0x3F, 0x3E, 0x3F, 0x3E, 0xFF, 0x63, 0x63, 0x63, 0x63, 0xC3, 0x7F, 0x3C, 0x06, 0x3C, 0x3C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x60, 0x00, 0x78, 0x00, 0x03, 0x18, 0x60, 0x03, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x18, 0x0E, 0xDB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x66, 0x36, 0x3E, 0x6B, 0x36, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x63, 0x1C, 0x63, 0x63, 0x70, 0x03, 0x06, 0x60, 0x63, 0x63, 0x00, 0x00, 0x60, 0x00, 0x06, 0x63, 0x63, 0x63, 0x63, 0x63, 0x33, 0x03, 0x03, 0x63, 0x63, 0x18, 0x30, 0x63, 0x03, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x18, 0x63, 0x63, 0x63, 0x63, 0xC3, 0x60, 0x0C, 0x06, 0x30, 0x66, 0x00, 0x00, 0x00, 0x03, 0x00, 0x60, 0x00, 0x0C, 0x00, 0x03, 0x18, 0x60, 0x03, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x18, 0x18, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x36, 0x6B, 0x36, 0x36, 0x00, 0x0C, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x63, 0x1E, 0x63, 0x63, 0x78, 0x03, 0x03, 0x60, 0x63, 0x63, 0x00, 0x00, 0x30, 0x00, 0x0C, 0x63, 0x73, 0x63, 0x63, 0x63, 0x63, 0x03, 0x03, 0x63, 0x63, 0x18, 0x30, 0x33, 0x03, 0x77, 0x63, 0x63, 0x63, 0x63, 0x63, 0x03, 0x18, 0x63, 0x63, 0x63, 0x36, 0x66, 0x60, 0x0C, 0x0C, 0x30, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x60, 0x00, 0x0C, 0x00, 0x03, 0x00, 0x00, 0x03, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x7F, 0x0B, 0x30, 0x1C, 0x00, 0x0C, 0x30, 0x36, 0x18, 0x00, 0x00, 0x00, 0x30, 0x73, 0x18, 0x60, 0x60, 0x6C, 0x03, 0x03, 0x30, 0x63, 0x63, 0x18, 0x18, 0x18, 0x7F, 0x18, 0x63, 0x6B, 0x63, 0x63, 0x03, 0x63, 0x03, 0x03, 0x03, 0x63, 0x18, 0x30, 0x1B, 0x03, 0x7F, 0x67, 0x63, 0x63, 0x63, 0x63, 0x03, 0x18, 0x63, 0x63, 0x63, 0x36, 0x66, 0x30, 0x0C, 0x0C, 0x30, 0x00, 0x00, 0x00, 0x3E, 0x3F, 0x3E, 0x7E, 0x3E, 0x3F, 0x7E, 0x3F, 0x1C, 0x70, 0x63, 0x18, 0x3F, 0x3F, 0x3E, 0x3F, 0x7E, 0x7B, 0x7E, 0x3F, 0x63, 0x63, 0x63, 0x63, 0x63, 0x7F, 0x0C, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x36, 0x0B, 0x18, 0x6E, 0x00, 0x0C, 0x30, 0x1C, 0x18, 0x00, 0x00, 0x00, 0x18, 0x7B, 0x18, 0x30, 0x3C, 0x66, 0x3F, 0x3F, 0x30, 0x3E, 0x63, 0x18, 0x18, 0x0C, 0x00, 0x30, 0x30, 0x6B, 0x63, 0x3F, 0x03, 0x63, 0x1F, 0x1F, 0x03, 0x7F, 0x18, 0x30, 0x0F, 0x03, 0x6B, 0x6F, 0x63, 0x63, 0x63, 0x63, 0x3E, 0x18, 0x63, 0x63, 0x63, 0x1C, 0x3C, 0x18, 0x0C, 0x18, 0x30, 0x00, 0x00, 0x00, 0x60, 0x63, 0x63, 0x63, 0x63, 0x0C, 0x63, 0x63, 0x18, 0x60, 0x33, 0x18, 0x6B, 0x63, 0x63, 0x63, 0x63, 0x0F, 0x03, 0x0C, 0x63, 0x63, 0x63, 0x63, 0x63, 0x30, 0x06, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x36, 0x3E, 0x18, 0x3B, 0x00, 0x0C, 0x30, 0x7F, 0x7E, 0x00, 0x7F, 0x00, 0x18, 0x6F, 0x18, 0x18, 0x60, 0x63, 0x60, 0x63, 0x18, 0x63, 0x7E, 0x00, 0x00, 0x06, 0x00, 0x60, 0x18, 0x6B, 0x7F, 0x63, 0x03, 0x63, 0x03, 0x03, 0x7B, 0x63, 0x18, 0x30, 0x0F, 0x03, 0x63, 0x7B, 0x63, 0x3F, 0x63, 0x3F, 0x60, 0x18, 0x63, 0x36, 0x6B, 0x1C, 0x18, 0x0C, 0x0C, 0x18, 0x30, 0x00, 0x00, 0x00, 0x7E, 0x63, 0x03, 0x63, 0x63, 0x0C, 0x63, 0x63, 0x18, 0x60, 0x1B, 0x18, 0x6B, 0x63, 0x63, 0x63, 0x63, 0x07, 0x03, 0x0C, 0x63, 0x63, 0x6B, 0x36, 0x63, 0x18, 0x0C, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x7F, 0x68, 0x0C, 0x33, 0x00, 0x0C, 0x30, 0x1C, 0x18, 0x00, 0x00, 0x00, 0x0C, 0x67, 0x18, 0x0C, 0x60, 0x7F, 0x60, 0x63, 0x18, 0x63, 0x60, 0x00, 0x00, 0x0C, 0x7F, 0x30, 0x18, 0x6B, 0x63, 0x63, 0x03, 0x63, 0x03, 0x03, 0x63, 0x63, 0x18, 0x30, 0x1B, 0x03, 0x63, 0x73, 0x63, 0x03, 0x63, 0x0F, 0x60, 0x18, 0x63, 0x36, 0x7F, 0x36, 0x18, 0x06, 0x0C, 0x30, 0x30, 0x00, 0x00, 0x00, 0x63, 0x63, 0x03, 0x63, 0x7F, 0x0C, 0x63, 0x63, 0x18, 0x60, 0x0F, 0x18, 0x6B, 0x63, 0x63, 0x63, 0x63, 0x03, 0x3E, 0x0C, 0x63, 0x36, 0x6B, 0x1C, 0x63, 0x0C, 0x0C, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x68, 0x6C, 0x33, 0x00, 0x0C, 0x30, 0x36, 0x18, 0x00, 0x00, 0x00, 0x0C, 0x63, 0x18, 0x06, 0x63, 0x60, 0x60, 0x63, 0x0C, 0x63, 0x60, 0x00, 0x00, 0x18, 0x00, 0x18, 0x00, 0x73, 0x63, 0x63, 0x63, 0x63, 0x03, 0x03, 0x63, 0x63, 0x18, 0x33, 0x33, 0x03, 0x63, 0x63, 0x63, 0x03, 0x63, 0x1B, 0x63, 0x18, 0x63, 0x36, 0x77, 0x36, 0x18, 0x03, 0x0C, 0x30, 0x30, 0x00, 0x00, 0x00, 0x63, 0x63, 0x03, 0x63, 0x03, 0x0C, 0x63, 0x63, 0x18, 0x60, 0x1B, 0x18, 0x6B, 0x63, 0x63, 0x63, 0x63, 0x03, 0x60, 0x0C, 0x63, 0x36, 0x6B, 0x36, 0x63, 0x06, 0x0C, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x36, 0x6B, 0xD6, 0x3B, 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x00, 0x18, 0x06, 0x63, 0x18, 0x03, 0x63, 0x60, 0x63, 0x63, 0x0C, 0x63, 0x30, 0x18, 0x18, 0x30, 0x00, 0x0C, 0x18, 0x03, 0x63, 0x63, 0x63, 0x33, 0x03, 0x03, 0x63, 0x63, 0x18, 0x33, 0x63, 0x03, 0x63, 0x63, 0x63, 0x03, 0x7B, 0x33, 0x63, 0x18, 0x63, 0x1C, 0x63, 0x63, 0x18, 0x03, 0x0C, 0x60, 0x30, 0x00, 0x00, 0x00, 0x63, 0x63, 0x63, 0x63, 0x03, 0x0C, 0x63, 0x63, 0x18, 0x60, 0x33, 0x18, 0x6B, 0x63, 0x63, 0x63, 0x63, 0x03, 0x60, 0x0C, 0x63, 0x1C, 0x6B, 0x63, 0x63, 0x03, 0x0C, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x36, 0x3E, 0x66, 0x6E, 0x00, 0x30, 0x0C, 0x00, 0x00, 0x18, 0x00, 0x18, 0x06, 0x3E, 0x7E, 0x7F, 0x3E, 0x60, 0x3E, 0x3E, 0x0C, 0x3E, 0x1E, 0x18, 0x18, 0x60, 0x00, 0x06, 0x18, 0x7E, 0x63, 0x3F, 0x3E, 0x1F, 0x7F, 0x03, 0x3E, 0x63, 0x3C, 0x1E, 0x63, 0x7F, 0x63, 0x63, 0x3E, 0x03, 0x3E, 0x63, 0x3E, 0x18, 0x3E, 0x1C, 0x41, 0x63, 0x18, 0x7F, 0x3C, 0x60, 0x3C, 0x00, 0x00, 0x00, 0x7E, 0x3F, 0x3E, 0x7E, 0x3E, 0x0C, 0x7E, 0x63, 0x3C, 0x60, 0x63, 0x3C, 0x6B, 0x63, 0x3E, 0x3F, 0x7E, 0x03, 0x3F, 0x78, 0x7E, 0x1C, 0x3E, 0x63, 0x7E, 0x7F, 0x38, 0x18, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; #define font18_width 987 #define font18_height 18 static unsigned char font18_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x0C, 0x00, 0x30, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xC0, 0x0C, 0x33, 0x30, 0x38, 0xC3, 0x03, 0x0C, 0x60, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0xFC, 0xC0, 0xC0, 0x0F, 0x3F, 0x80, 0xF9, 0x87, 0x8F, 0x7F, 0xFC, 0xF0, 0x03, 0x00, 0x00, 0xC0, 0x00, 0x60, 0x00, 0x1E, 0xFE, 0xF0, 0xE3, 0x0F, 0x3F, 0x7E, 0xF8, 0xE7, 0x1F, 0x3F, 0x86, 0xE1, 0x01, 0x9E, 0x61, 0x06, 0x04, 0x64, 0x18, 0x3F, 0xFE, 0xF0, 0xE3, 0x0F, 0x3F, 0xFE, 0x19, 0x66, 0xD8, 0x60, 0x86, 0x19, 0xE6, 0x1F, 0x1E, 0x06, 0xE0, 0xC1, 0x0C, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x80, 0x01, 0x00, 0x1E, 0x00, 0x06, 0xC0, 0x00, 0x8C, 0x01, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x30, 0x70, 0x60, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xC0, 0x0C, 0x33, 0xFC, 0x28, 0x63, 0x06, 0x0C, 0x30, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x86, 0xE1, 0x60, 0x98, 0x61, 0xC0, 0x19, 0xC0, 0x80, 0x61, 0x86, 0x19, 0x06, 0x00, 0x00, 0x60, 0x00, 0xC0, 0x00, 0x33, 0x83, 0x19, 0x66, 0x98, 0x61, 0xC6, 0x18, 0x60, 0x80, 0x61, 0x86, 0xC1, 0x00, 0x8C, 0x61, 0x06, 0x0C, 0x66, 0x98, 0x61, 0x86, 0x19, 0x66, 0x98, 0x61, 0x30, 0x18, 0x66, 0xD8, 0x60, 0x86, 0x19, 0x06, 0x18, 0x06, 0x06, 0x80, 0x61, 0x18, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x80, 0x01, 0x00, 0x03, 0x00, 0x06, 0xC0, 0x00, 0x8C, 0x01, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x30, 0xC0, 0x60, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x33, 0xB6, 0xB9, 0x61, 0x06, 0x00, 0x30, 0xC0, 0x60, 0x0C, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x18, 0x86, 0xF1, 0x60, 0x98, 0x61, 0xE0, 0x19, 0x60, 0x80, 0x61, 0x86, 0x19, 0x06, 0x00, 0x00, 0x30, 0x00, 0x80, 0x81, 0x61, 0x83, 0x19, 0x66, 0x98, 0x61, 0x86, 0x19, 0x60, 0x80, 0x61, 0x86, 0xC1, 0x00, 0x8C, 0x31, 0x06, 0x1C, 0x67, 0x98, 0x61, 0x86, 0x19, 0x66, 0x98, 0x61, 0x30, 0x18, 0x66, 0xD8, 0x60, 0xCC, 0x18, 0x06, 0x18, 0x06, 0x0C, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x80, 0x01, 0x00, 0x03, 0x00, 0x06, 0x00, 0x00, 0x80, 0x01, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x30, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x80, 0x7F, 0x36, 0x80, 0x61, 0x06, 0x00, 0x18, 0x80, 0xC1, 0x06, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x18, 0xC6, 0xC1, 0x60, 0x18, 0x60, 0xB0, 0x19, 0x60, 0x00, 0x60, 0x86, 0x19, 0x06, 0x03, 0x0C, 0x18, 0xF8, 0x07, 0x83, 0x61, 0xF3, 0x19, 0x66, 0x98, 0x01, 0x86, 0x19, 0x60, 0x80, 0x01, 0x86, 0xC1, 0x00, 0x8C, 0x19, 0x06, 0xBC, 0xE7, 0x98, 0x61, 0x86, 0x19, 0x66, 0x98, 0x01, 0x30, 0x18, 0x66, 0xD8, 0x60, 0xCC, 0x30, 0x03, 0x0C, 0x06, 0x0C, 0x80, 0x01, 0x00, 0x00, 0x00, 0xF0, 0xE3, 0x0F, 0x3F, 0xFC, 0xF1, 0xC3, 0x0F, 0x7F, 0xFE, 0xE0, 0x00, 0x8E, 0x61, 0x30, 0xF8, 0xE3, 0x0F, 0x3F, 0xFE, 0xF0, 0x67, 0x1F, 0x3F, 0x7E, 0x18, 0x66, 0x98, 0x61, 0x86, 0x19, 0xE6, 0x1F, 0x0C, 0x30, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x33, 0x36, 0xC0, 0xC0, 0x03, 0x00, 0x18, 0x80, 0x81, 0x03, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x0C, 0xE6, 0xC1, 0x00, 0x18, 0x60, 0x98, 0x19, 0x60, 0x00, 0x30, 0x86, 0x19, 0x06, 0x03, 0x0C, 0x0C, 0x00, 0x00, 0x06, 0x60, 0x9B, 0x19, 0x66, 0x98, 0x01, 0x86, 0x19, 0x60, 0x80, 0x01, 0x86, 0xC1, 0x00, 0x8C, 0x0D, 0x06, 0xEC, 0xE6, 0x99, 0x61, 0x86, 0x19, 0x66, 0x98, 0x01, 0x30, 0x18, 0xC6, 0xCC, 0x60, 0x78, 0x30, 0x03, 0x06, 0x06, 0x18, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x66, 0x98, 0x61, 0x86, 0x19, 0x06, 0x83, 0x61, 0x86, 0xC1, 0x00, 0x8C, 0x31, 0x30, 0xD8, 0x66, 0x98, 0x61, 0x86, 0x19, 0xE6, 0x81, 0x61, 0x18, 0x18, 0x66, 0x98, 0x61, 0x86, 0x19, 0x06, 0x18, 0x0C, 0x30, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x33, 0x36, 0xC0, 0xC0, 0x19, 0x00, 0x18, 0x80, 0xF1, 0x9F, 0x7F, 0x00, 0xF8, 0x07, 0x00, 0x0C, 0xB6, 0xC1, 0x00, 0x0C, 0x3E, 0x8C, 0xF9, 0xE3, 0x0F, 0x30, 0xFC, 0x18, 0x06, 0x00, 0x00, 0x06, 0x00, 0x00, 0x0C, 0x30, 0x9B, 0x19, 0xE6, 0x8F, 0x01, 0x86, 0xF9, 0xE1, 0x87, 0x01, 0xFE, 0xC1, 0x00, 0x8C, 0x07, 0x06, 0x4C, 0x66, 0x9B, 0x61, 0x86, 0x19, 0x66, 0x18, 0x3F, 0x30, 0x18, 0xC6, 0xCC, 0x60, 0x30, 0xE0, 0x01, 0x03, 0x06, 0x18, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x66, 0x98, 0x01, 0x86, 0x19, 0x06, 0x83, 0x61, 0x86, 0xC1, 0x00, 0x8C, 0x19, 0x30, 0xD8, 0x66, 0x98, 0x61, 0x86, 0x19, 0xE6, 0x80, 0x01, 0x18, 0x18, 0x66, 0x98, 0x61, 0xCC, 0x18, 0x06, 0x0C, 0x07, 0x30, 0x80, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x33, 0xFC, 0x60, 0x60, 0x1B, 0x00, 0x18, 0x80, 0x81, 0x03, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x06, 0x9E, 0xC1, 0x00, 0x06, 0x60, 0x86, 0x01, 0x66, 0x18, 0x18, 0x86, 0xF1, 0x07, 0x00, 0x00, 0x06, 0x00, 0x00, 0x0C, 0x18, 0x9B, 0xF9, 0x67, 0x98, 0x01, 0x86, 0x19, 0x60, 0x80, 0x79, 0x86, 0xC1, 0x00, 0x8C, 0x07, 0x06, 0x0C, 0x66, 0x9E, 0x61, 0xFE, 0x18, 0xE6, 0x0F, 0x60, 0x30, 0x18, 0xC6, 0xCC, 0x64, 0x30, 0xC0, 0x80, 0x01, 0x06, 0x30, 0x80, 0x01, 0x00, 0x00, 0x00, 0xF0, 0x67, 0x98, 0x01, 0x86, 0x19, 0x06, 0x83, 0x61, 0x86, 0xC1, 0x00, 0x8C, 0x0D, 0x30, 0xD8, 0x66, 0x98, 0x61, 0x86, 0x19, 0x66, 0x80, 0x01, 0x18, 0x18, 0xC6, 0x8C, 0x6D, 0x78, 0x18, 0x06, 0x06, 0x0C, 0x30, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x33, 0xB0, 0x61, 0x30, 0x0E, 0x00, 0x18, 0x80, 0xC1, 0x06, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x06, 0x8E, 0xC1, 0x00, 0x03, 0x60, 0x86, 0x01, 0x66, 0x18, 0x18, 0x86, 0x01, 0x06, 0x00, 0x00, 0x0C, 0xF8, 0x07, 0x06, 0x0C, 0x9B, 0x19, 0x66, 0x98, 0x01, 0x86, 0x19, 0x60, 0x80, 0x61, 0x86, 0xC1, 0x00, 0x8C, 0x0D, 0x06, 0x0C, 0x66, 0x9C, 0x61, 0x06, 0x18, 0xE6, 0x01, 0x60, 0x30, 0x18, 0xC6, 0xCC, 0x6E, 0x78, 0xC0, 0xC0, 0x00, 0x06, 0x30, 0x80, 0x01, 0x00, 0x00, 0x00, 0x18, 0x66, 0x98, 0x01, 0x86, 0xF9, 0x07, 0x83, 0x61, 0x86, 0xC1, 0x00, 0x8C, 0x07, 0x30, 0xD8, 0x66, 0x98, 0x61, 0x86, 0x19, 0x66, 0x00, 0x3F, 0x18, 0x18, 0xC6, 0x8C, 0x6D, 0x30, 0x18, 0x06, 0x03, 0x0C, 0x30, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x7F, 0xB0, 0x31, 0x30, 0x0C, 0x00, 0x18, 0x80, 0x61, 0x0C, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x03, 0x86, 0xC1, 0x80, 0x01, 0x60, 0xFE, 0x01, 0x66, 0x18, 0x0C, 0x86, 0x01, 0x06, 0x00, 0x00, 0x18, 0x00, 0x00, 0x03, 0x0C, 0xF3, 0x19, 0x66, 0x98, 0x01, 0x86, 0x19, 0x60, 0x80, 0x61, 0x86, 0xC1, 0x60, 0x8C, 0x19, 0x06, 0x0C, 0x66, 0x98, 0x61, 0x06, 0x18, 0x66, 0x03, 0x60, 0x30, 0x18, 0x86, 0xC7, 0x7B, 0xCC, 0xC0, 0x60, 0x00, 0x06, 0x60, 0x80, 0x01, 0x00, 0x00, 0x00, 0x18, 0x66, 0x98, 0x01, 0x86, 0x19, 0x00, 0x83, 0x61, 0x86, 0xC1, 0x00, 0x8C, 0x0D, 0x30, 0xD8, 0x66, 0x98, 0x61, 0x86, 0x19, 0x66, 0x00, 0x60, 0x18, 0x18, 0xC6, 0x8C, 0x6D, 0x78, 0x18, 0x86, 0x01, 0x0C, 0x30, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0xB0, 0xB1, 0x33, 0x0C, 0x00, 0x30, 0xC0, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x03, 0x86, 0xC1, 0xC0, 0x80, 0x61, 0x80, 0x19, 0x66, 0x18, 0x0C, 0x86, 0x01, 0x06, 0x03, 0x0C, 0x30, 0x00, 0x80, 0x01, 0x00, 0x03, 0x18, 0x66, 0x98, 0x61, 0x86, 0x19, 0x60, 0x80, 0x61, 0x86, 0xC1, 0x60, 0x8C, 0x31, 0x06, 0x0C, 0x66, 0x98, 0x61, 0x06, 0x18, 0x66, 0x86, 0x61, 0x30, 0x18, 0x86, 0xC7, 0x71, 0xCC, 0xC0, 0x60, 0x00, 0x06, 0x60, 0x80, 0x01, 0x00, 0x00, 0x00, 0x18, 0x66, 0x98, 0x01, 0x86, 0x19, 0x00, 0x83, 0x61, 0x86, 0xC1, 0x00, 0x8C, 0x19, 0x30, 0xD8, 0x66, 0x98, 0x61, 0x86, 0x19, 0x66, 0x00, 0x60, 0x18, 0x18, 0x86, 0x87, 0x6D, 0xCC, 0x18, 0xC6, 0x00, 0x0C, 0x30, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x33, 0xB6, 0x99, 0x62, 0x1E, 0x00, 0x30, 0xC0, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x83, 0x01, 0x86, 0xC1, 0x60, 0x80, 0x61, 0x80, 0x19, 0x66, 0x18, 0x0C, 0x86, 0x01, 0x03, 0x03, 0x0C, 0x60, 0x00, 0xC0, 0x00, 0x0C, 0x03, 0x18, 0x66, 0x98, 0x61, 0xC6, 0x18, 0x60, 0x80, 0x61, 0x86, 0xC1, 0x60, 0x8C, 0x61, 0x06, 0x0C, 0x66, 0x98, 0x61, 0x06, 0x98, 0x67, 0x8C, 0x61, 0x30, 0x18, 0x06, 0xC3, 0x60, 0x86, 0xC1, 0x60, 0x00, 0x06, 0xC0, 0x80, 0x01, 0x00, 0x00, 0x00, 0x18, 0x66, 0x98, 0x61, 0x86, 0x19, 0x06, 0x83, 0x61, 0x86, 0xC1, 0x00, 0x8C, 0x31, 0x30, 0xD8, 0x66, 0x98, 0x61, 0x86, 0x19, 0x66, 0x80, 0x61, 0x18, 0x18, 0x06, 0x83, 0x6D, 0x86, 0x19, 0x66, 0x00, 0x0C, 0x30, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x33, 0xFC, 0x98, 0xC3, 0x1B, 0x00, 0x60, 0x60, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x83, 0x01, 0xFC, 0xF0, 0xE3, 0x1F, 0x3F, 0x80, 0xF1, 0xC3, 0x0F, 0x0C, 0xFC, 0xF0, 0x01, 0x00, 0x0C, 0xC0, 0x00, 0x60, 0x00, 0x0C, 0xFE, 0x19, 0xE6, 0x0F, 0x3F, 0x7E, 0xF8, 0x67, 0x00, 0x3F, 0x86, 0xE1, 0xC1, 0x87, 0x61, 0xFE, 0x0D, 0x66, 0x18, 0x3F, 0x06, 0xF0, 0x63, 0x18, 0x3F, 0x30, 0xF0, 0x03, 0x43, 0x40, 0x86, 0xC1, 0xE0, 0x1F, 0x1E, 0xC0, 0xE0, 0x01, 0x00, 0x00, 0x00, 0xF0, 0xE7, 0x0F, 0x3F, 0xFC, 0xF1, 0x03, 0x03, 0x7F, 0x86, 0xE1, 0x01, 0x8C, 0x61, 0x78, 0xD8, 0x66, 0x18, 0x3F, 0xFE, 0xF0, 0x67, 0x00, 0x3F, 0xF0, 0xF0, 0x07, 0x03, 0x3F, 0x86, 0xF1, 0xE7, 0x1F, 0x38, 0x30, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0xC0, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0xC0, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; #define font20_width 987 #define font20_height 20 static unsigned char font20_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x0C, 0x00, 0x30, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xC0, 0x0C, 0x33, 0x30, 0x00, 0xC0, 0x03, 0x0C, 0x60, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xC0, 0xC0, 0x0F, 0x3F, 0x80, 0xF9, 0x87, 0x8F, 0x7F, 0xFC, 0xF0, 0x03, 0x00, 0x00, 0x80, 0x01, 0x60, 0x00, 0x1E, 0xFE, 0xF0, 0xE3, 0x0F, 0x3F, 0x7E, 0xF8, 0xE7, 0x1F, 0x3F, 0x86, 0xE1, 0x01, 0x9E, 0x61, 0x06, 0x04, 0x64, 0x18, 0x3F, 0xFE, 0xF0, 0xE3, 0x0F, 0x3F, 0xFE, 0x19, 0x66, 0xD8, 0x60, 0x86, 0x19, 0xE6, 0x1F, 0x1E, 0x00, 0xE0, 0xC1, 0x0C, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x80, 0x01, 0x00, 0x1E, 0x00, 0x06, 0xC0, 0x00, 0x8C, 0x01, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x30, 0x70, 0x60, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xC0, 0x0C, 0x33, 0xFC, 0x38, 0x63, 0x06, 0x0C, 0x30, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x86, 0xE1, 0x60, 0x98, 0x61, 0xC0, 0x19, 0xC0, 0x80, 0x61, 0x86, 0x19, 0x06, 0x00, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0x33, 0x83, 0x19, 0x66, 0x98, 0x61, 0xC6, 0x18, 0x60, 0x80, 0x61, 0x86, 0xC1, 0x00, 0x8C, 0x61, 0x06, 0x0C, 0x66, 0x98, 0x61, 0x86, 0x19, 0x66, 0x98, 0x61, 0x30, 0x18, 0x66, 0xD8, 0x60, 0x86, 0x19, 0x06, 0x18, 0x06, 0x06, 0x80, 0x61, 0x18, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x80, 0x01, 0x00, 0x03, 0x00, 0x06, 0xC0, 0x00, 0x8C, 0x01, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x30, 0xC0, 0x60, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x33, 0xB6, 0x29, 0x63, 0x06, 0x00, 0x30, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x86, 0xF1, 0x60, 0x98, 0x61, 0xE0, 0x19, 0x60, 0x80, 0x61, 0x86, 0x19, 0x06, 0x00, 0x00, 0x60, 0x00, 0x80, 0x81, 0x61, 0x83, 0x19, 0x66, 0x98, 0x61, 0x86, 0x19, 0x60, 0x80, 0x61, 0x86, 0xC1, 0x00, 0x8C, 0x31, 0x06, 0x1C, 0x67, 0x98, 0x61, 0x86, 0x19, 0x66, 0x98, 0x61, 0x30, 0x18, 0x66, 0xD8, 0x60, 0x86, 0x19, 0x06, 0x18, 0x06, 0x06, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x80, 0x01, 0x00, 0x03, 0x00, 0x06, 0x00, 0x00, 0x80, 0x01, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x30, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x33, 0x36, 0xB8, 0x61, 0x06, 0x00, 0x18, 0x80, 0x61, 0x0C, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x18, 0x86, 0xC1, 0x60, 0x18, 0x60, 0xB0, 0x19, 0x60, 0x00, 0x60, 0x86, 0x19, 0x06, 0x00, 0x00, 0x30, 0x00, 0x00, 0x83, 0x61, 0xF3, 0x19, 0x66, 0x98, 0x01, 0x86, 0x19, 0x60, 0x80, 0x01, 0x86, 0xC1, 0x00, 0x8C, 0x19, 0x06, 0xBC, 0x67, 0x98, 0x61, 0x86, 0x19, 0x66, 0x98, 0x01, 0x30, 0x18, 0x66, 0xD8, 0x60, 0xCC, 0x30, 0x03, 0x18, 0x06, 0x0C, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x80, 0x01, 0x00, 0x03, 0x00, 0x06, 0x00, 0x00, 0x80, 0x01, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x30, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x80, 0x7F, 0x36, 0x80, 0xC1, 0x03, 0x00, 0x18, 0x80, 0xC1, 0x06, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x18, 0xC6, 0xC1, 0x00, 0x18, 0x60, 0x98, 0x19, 0x60, 0x00, 0x30, 0x86, 0x19, 0x06, 0x03, 0x0C, 0x18, 0xF8, 0x07, 0x06, 0x60, 0x9B, 0x19, 0x66, 0x98, 0x01, 0x86, 0x19, 0x60, 0x80, 0x01, 0x86, 0xC1, 0x00, 0x8C, 0x0D, 0x06, 0xEC, 0xE6, 0x98, 0x61, 0x86, 0x19, 0x66, 0x98, 0x01, 0x30, 0x18, 0x66, 0xD8, 0x60, 0xCC, 0x30, 0x03, 0x0C, 0x06, 0x0C, 0x80, 0x01, 0x00, 0x00, 0x00, 0xF0, 0xE3, 0x0F, 0x3F, 0xFC, 0xF1, 0xC3, 0x0F, 0x7F, 0xFE, 0xE0, 0x00, 0x8E, 0x61, 0x30, 0xF8, 0xE3, 0x0F, 0x3F, 0xFE, 0xF0, 0x67, 0x1F, 0x3F, 0x7E, 0x18, 0x66, 0x98, 0x61, 0x86, 0x19, 0xE6, 0x1F, 0x0C, 0x30, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x33, 0x36, 0xC0, 0x80, 0x01, 0x00, 0x18, 0x80, 0x81, 0x03, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x0C, 0xE6, 0xC1, 0x00, 0x18, 0x60, 0x8C, 0xF9, 0xE3, 0x0F, 0x30, 0x86, 0x19, 0x06, 0x03, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x30, 0x9B, 0x19, 0xE6, 0x8F, 0x01, 0x86, 0x19, 0x60, 0x80, 0x01, 0x86, 0xC1, 0x00, 0x8C, 0x07, 0x06, 0x4C, 0xE6, 0x99, 0x61, 0x86, 0x19, 0x66, 0x98, 0x01, 0x30, 0x18, 0xC6, 0xCC, 0x60, 0x78, 0x30, 0x03, 0x06, 0x06, 0x18, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x66, 0x98, 0x61, 0x86, 0x19, 0x06, 0x83, 0x61, 0x86, 0xC1, 0x00, 0x8C, 0x31, 0x30, 0xD8, 0x66, 0x98, 0x61, 0x86, 0x19, 0xE6, 0x81, 0x61, 0x18, 0x18, 0x66, 0x98, 0x61, 0x86, 0x19, 0x06, 0x18, 0x0C, 0x30, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x33, 0xFC, 0xC0, 0xC0, 0x19, 0x00, 0x18, 0x80, 0xF1, 0x9F, 0x7F, 0x00, 0xF8, 0x07, 0x00, 0x0C, 0xB6, 0xC1, 0x00, 0x0C, 0x3E, 0x86, 0x01, 0x66, 0x18, 0x18, 0xFC, 0x18, 0x06, 0x00, 0x00, 0x06, 0x00, 0x00, 0x18, 0x18, 0x9B, 0xF9, 0x67, 0x98, 0x01, 0x86, 0xF9, 0xE1, 0x87, 0x79, 0xFE, 0xC1, 0x00, 0x8C, 0x03, 0x06, 0x0C, 0x66, 0x9B, 0x61, 0xFE, 0x18, 0xE6, 0x0F, 0x3F, 0x30, 0x18, 0xC6, 0xCC, 0x60, 0x30, 0xE0, 0x01, 0x03, 0x06, 0x18, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x66, 0x98, 0x01, 0x86, 0x19, 0x06, 0x83, 0x61, 0x86, 0xC1, 0x00, 0x8C, 0x19, 0x30, 0xD8, 0x66, 0x98, 0x61, 0x86, 0x19, 0xE6, 0x80, 0x01, 0x18, 0x18, 0x66, 0x98, 0x61, 0xCC, 0x18, 0x06, 0x0C, 0x07, 0x30, 0x80, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x33, 0xB0, 0x61, 0x60, 0x1B, 0x00, 0x18, 0x80, 0x81, 0x03, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x06, 0x9E, 0xC1, 0x00, 0x06, 0x60, 0x86, 0x01, 0x66, 0x18, 0x18, 0x86, 0xF1, 0x07, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x9B, 0x19, 0x66, 0x98, 0x01, 0x86, 0x19, 0x60, 0x80, 0x61, 0x86, 0xC1, 0x00, 0x8C, 0x07, 0x06, 0x0C, 0x66, 0x9E, 0x61, 0x06, 0x18, 0xE6, 0x01, 0x60, 0x30, 0x18, 0xC6, 0xCC, 0x64, 0x78, 0xC0, 0x80, 0x01, 0x06, 0x30, 0x80, 0x01, 0x00, 0x00, 0x00, 0xF0, 0x67, 0x98, 0x01, 0x86, 0x19, 0x06, 0x83, 0x61, 0x86, 0xC1, 0x00, 0x8C, 0x0D, 0x30, 0xD8, 0x66, 0x98, 0x61, 0x86, 0x19, 0x66, 0x80, 0x01, 0x18, 0x18, 0xC6, 0x8C, 0x6D, 0x78, 0x18, 0x06, 0x06, 0x0C, 0x30, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x80, 0x7F, 0xB0, 0x61, 0x30, 0x0E, 0x00, 0x18, 0x80, 0xC1, 0x06, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x06, 0x8E, 0xC1, 0x00, 0x03, 0x60, 0x86, 0x01, 0x66, 0x18, 0x0C, 0x86, 0x01, 0x06, 0x00, 0x00, 0x18, 0xF8, 0x07, 0x06, 0x0C, 0x9B, 0x19, 0x66, 0x98, 0x01, 0x86, 0x19, 0x60, 0x80, 0x61, 0x86, 0xC1, 0x00, 0x8C, 0x0D, 0x06, 0x0C, 0x66, 0x9C, 0x61, 0x06, 0x18, 0x66, 0x03, 0x60, 0x30, 0x18, 0xC6, 0xCC, 0x6E, 0xCC, 0xC0, 0xC0, 0x00, 0x06, 0x30, 0x80, 0x01, 0x00, 0x00, 0x00, 0x18, 0x66, 0x98, 0x01, 0x86, 0xF9, 0x07, 0x83, 0x61, 0x86, 0xC1, 0x00, 0x8C, 0x07, 0x30, 0xD8, 0x66, 0x98, 0x61, 0x86, 0x19, 0x66, 0x00, 0x3F, 0x18, 0x18, 0xC6, 0x8C, 0x6D, 0x30, 0x18, 0x06, 0x03, 0x0C, 0x30, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0xB0, 0x31, 0x30, 0x0C, 0x00, 0x18, 0x80, 0x61, 0x0C, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x03, 0x86, 0xC1, 0x80, 0x01, 0x60, 0xFE, 0x01, 0x66, 0x18, 0x0C, 0x86, 0x01, 0x06, 0x00, 0x00, 0x30, 0x00, 0x00, 0x03, 0x00, 0xF3, 0x19, 0x66, 0x98, 0x01, 0x86, 0x19, 0x60, 0x80, 0x61, 0x86, 0xC1, 0x60, 0x8C, 0x19, 0x06, 0x0C, 0x66, 0x98, 0x61, 0x06, 0x18, 0x66, 0x06, 0x60, 0x30, 0x18, 0x86, 0xC7, 0x7B, 0xCC, 0xC0, 0x60, 0x00, 0x06, 0x60, 0x80, 0x01, 0x00, 0x00, 0x00, 0x18, 0x66, 0x98, 0x01, 0x86, 0x19, 0x00, 0x83, 0x61, 0x86, 0xC1, 0x00, 0x8C, 0x0D, 0x30, 0xD8, 0x66, 0x98, 0x61, 0x86, 0x19, 0x66, 0x00, 0x60, 0x18, 0x18, 0xC6, 0x8C, 0x6D, 0x78, 0x18, 0x86, 0x01, 0x0C, 0x30, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0xB6, 0xB1, 0x33, 0x0C, 0x00, 0x30, 0xC0, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x03, 0x86, 0xC1, 0xC0, 0x80, 0x61, 0x80, 0x19, 0x66, 0x18, 0x0C, 0x86, 0x01, 0x06, 0x03, 0x0C, 0x60, 0x00, 0x80, 0x01, 0x00, 0x03, 0x18, 0x66, 0x98, 0x61, 0x86, 0x19, 0x60, 0x80, 0x61, 0x86, 0xC1, 0x60, 0x8C, 0x31, 0x06, 0x0C, 0x66, 0x98, 0x61, 0x06, 0x18, 0x66, 0x8C, 0x61, 0x30, 0x18, 0x86, 0xC7, 0x71, 0x86, 0xC1, 0x60, 0x00, 0x06, 0x60, 0x80, 0x01, 0x00, 0x00, 0x00, 0x18, 0x66, 0x98, 0x01, 0x86, 0x19, 0x00, 0x83, 0x61, 0x86, 0xC1, 0x00, 0x8C, 0x19, 0x30, 0xD8, 0x66, 0x98, 0x61, 0x86, 0x19, 0x66, 0x00, 0x60, 0x18, 0x18, 0x86, 0x87, 0x6D, 0xCC, 0x18, 0xC6, 0x00, 0x0C, 0x30, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x33, 0xFC, 0x98, 0x62, 0x1E, 0x00, 0x30, 0xC0, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x83, 0x01, 0x86, 0xC1, 0x60, 0x80, 0x61, 0x80, 0x19, 0x66, 0x18, 0x0C, 0x86, 0x01, 0x03, 0x03, 0x0C, 0xC0, 0x00, 0xC0, 0x00, 0x0C, 0x03, 0x18, 0x66, 0x98, 0x61, 0xC6, 0x18, 0x60, 0x80, 0x61, 0x86, 0xC1, 0x60, 0x8C, 0x61, 0x06, 0x0C, 0x66, 0x98, 0x61, 0x06, 0x98, 0x67, 0x98, 0x61, 0x30, 0x18, 0x06, 0xC3, 0x60, 0x86, 0xC1, 0x60, 0x00, 0x06, 0xC0, 0x80, 0x01, 0x00, 0x00, 0x00, 0x18, 0x66, 0x98, 0x61, 0x86, 0x19, 0x06, 0x83, 0x61, 0x86, 0xC1, 0x00, 0x8C, 0x31, 0x30, 0xD8, 0x66, 0x98, 0x61, 0x86, 0x19, 0x66, 0x80, 0x61, 0x18, 0x18, 0x06, 0x83, 0x6D, 0x86, 0x19, 0x66, 0x00, 0x0C, 0x30, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x33, 0x30, 0x98, 0xC3, 0x1B, 0x00, 0x60, 0x60, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x83, 0x01, 0xFC, 0xF0, 0xE3, 0x1F, 0x3F, 0x80, 0xF1, 0xC3, 0x0F, 0x0C, 0xFC, 0xF0, 0x01, 0x00, 0x0C, 0x80, 0x01, 0x60, 0x00, 0x0C, 0xFE, 0x19, 0xE6, 0x0F, 0x3F, 0x7E, 0xF8, 0x67, 0x00, 0x3F, 0x86, 0xE1, 0xC1, 0x87, 0x61, 0xFE, 0x0D, 0x66, 0x18, 0x3F, 0x06, 0xF0, 0x63, 0x18, 0x3F, 0x30, 0xF0, 0x03, 0x43, 0x40, 0x86, 0xC1, 0xE0, 0x1F, 0x1E, 0xC0, 0xE0, 0x01, 0x00, 0x00, 0x00, 0xF0, 0xE7, 0x0F, 0x3F, 0xFC, 0xF1, 0x03, 0x03, 0x7F, 0x86, 0xE1, 0x01, 0x8C, 0x61, 0x78, 0xD8, 0x66, 0x18, 0x3F, 0xFE, 0xF0, 0x67, 0x00, 0x3F, 0xF0, 0xF0, 0x07, 0x03, 0x3F, 0x86, 0xF1, 0xE7, 0x1F, 0x38, 0x30, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0xC0, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0xC0, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; #define font22_width 1086 #define font22_height 22 static unsigned char font22_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD8, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x33, 0x98, 0x01, 0x03, 0xC7, 0xF0, 0x01, 0x06, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0xF8, 0x00, 0x03, 0x3E, 0xF0, 0x01, 0x30, 0xFF, 0xE1, 0xC7, 0x7F, 0xF8, 0xC0, 0x07, 0x00, 0x00, 0x00, 0x18, 0x00, 0x18, 0x00, 0x1F, 0xFC, 0xC0, 0x87, 0x3F, 0xF0, 0xE1, 0x0F, 0xFF, 0xF9, 0x0F, 0x1F, 0x06, 0xE3, 0x07, 0xF8, 0x0D, 0x66, 0x80, 0x00, 0x19, 0x0C, 0x1F, 0xFE, 0xC0, 0x87, 0x3F, 0xF0, 0xF1, 0x3F, 0x83, 0x19, 0x6C, 0x60, 0x06, 0x1B, 0x98, 0xFF, 0xF0, 0x61, 0x00, 0x7C, 0x60, 0x03, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x30, 0x00, 0x80, 0x0F, 0x00, 0x06, 0x00, 0x03, 0x60, 0x18, 0x80, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0x03, 0x0E, 0x98, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x33, 0x98, 0xC1, 0x8F, 0xCD, 0x18, 0x03, 0x06, 0x60, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x8C, 0x81, 0x03, 0x63, 0x18, 0x03, 0x38, 0x03, 0x30, 0xC0, 0x60, 0x8C, 0x61, 0x0C, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x30, 0x80, 0x31, 0x86, 0x61, 0x8C, 0x61, 0x18, 0x63, 0x18, 0x03, 0x18, 0x80, 0x31, 0x06, 0x83, 0x01, 0x60, 0x0C, 0x66, 0x80, 0x81, 0x19, 0x8C, 0x31, 0x86, 0x61, 0x8C, 0x61, 0x18, 0x03, 0x03, 0x83, 0x19, 0x6C, 0x60, 0x06, 0x1B, 0x18, 0xC0, 0x30, 0x60, 0x00, 0x60, 0x30, 0x06, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x30, 0x00, 0xC0, 0x00, 0x00, 0x06, 0x00, 0x03, 0x60, 0x18, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x03, 0x18, 0x18, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x33, 0x98, 0x61, 0x9B, 0x6D, 0x18, 0x03, 0x06, 0x30, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x06, 0xC3, 0x83, 0xC1, 0x0C, 0x06, 0x3C, 0x03, 0x18, 0xC0, 0x60, 0x06, 0x33, 0x18, 0x00, 0x00, 0x00, 0x06, 0x00, 0x60, 0xC0, 0x60, 0x03, 0x33, 0x98, 0xC1, 0x0C, 0x66, 0x30, 0x03, 0x18, 0xC0, 0x60, 0x06, 0x83, 0x01, 0x60, 0x0C, 0x63, 0x80, 0xC3, 0x19, 0xCC, 0x60, 0x06, 0x33, 0x98, 0xC1, 0x0C, 0x06, 0x03, 0x83, 0x19, 0x6C, 0x60, 0x8C, 0x31, 0x0C, 0xC0, 0x30, 0xC0, 0x00, 0x60, 0x18, 0x0C, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x30, 0x00, 0xC0, 0x00, 0x00, 0x06, 0x00, 0x03, 0x60, 0x18, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x03, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x98, 0x31, 0x33, 0x67, 0x18, 0x03, 0x00, 0x30, 0x00, 0x83, 0x61, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x06, 0x63, 0x83, 0xC1, 0x00, 0x06, 0x36, 0x03, 0x18, 0x00, 0x60, 0x06, 0x33, 0x18, 0x0C, 0x60, 0x00, 0x03, 0x00, 0xC0, 0xC0, 0x60, 0xE3, 0x33, 0x98, 0xC1, 0x0C, 0x66, 0x30, 0x03, 0x18, 0xC0, 0x60, 0x06, 0x83, 0x01, 0x60, 0x8C, 0x61, 0x80, 0xE7, 0x19, 0xCC, 0x60, 0x06, 0x33, 0x98, 0xC1, 0x0C, 0x00, 0x03, 0x83, 0x19, 0x6C, 0x60, 0x8C, 0x31, 0x0C, 0xC0, 0x30, 0xC0, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x30, 0x00, 0xC0, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x18, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x03, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0xFE, 0x37, 0x03, 0x30, 0xB0, 0x01, 0x00, 0x18, 0x00, 0x06, 0x33, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x86, 0x03, 0x83, 0xC1, 0x00, 0x06, 0x33, 0x03, 0x18, 0x00, 0x30, 0x06, 0x33, 0x18, 0x0C, 0x60, 0x80, 0x01, 0xFF, 0x81, 0x01, 0x60, 0x33, 0x33, 0x98, 0xC1, 0x0C, 0x60, 0x30, 0x03, 0x18, 0xC0, 0x00, 0x06, 0x83, 0x01, 0x60, 0xCC, 0x60, 0x80, 0xBD, 0x39, 0xCC, 0x60, 0x06, 0x33, 0x98, 0xC1, 0x0C, 0x00, 0x03, 0x83, 0x19, 0x6C, 0x60, 0xD8, 0x60, 0x06, 0x60, 0x30, 0x80, 0x01, 0x60, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x87, 0x3F, 0xF0, 0x81, 0x3F, 0x7C, 0xF8, 0x07, 0x7F, 0xFE, 0xC0, 0x03, 0x78, 0x18, 0x06, 0x86, 0x7F, 0xF8, 0x03, 0x1F, 0xFE, 0xC0, 0x9F, 0xF9, 0xF8, 0xE3, 0x1F, 0x83, 0x19, 0x6C, 0x60, 0x06, 0x33, 0x98, 0xFF, 0x60, 0x00, 0x03, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x98, 0x31, 0x03, 0x30, 0xE0, 0x00, 0x00, 0x18, 0x00, 0x06, 0x1E, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0xC6, 0x03, 0x03, 0xC0, 0x00, 0x83, 0x31, 0x7F, 0xF8, 0x03, 0x30, 0x8C, 0x31, 0x18, 0x0C, 0x60, 0xC0, 0x00, 0x00, 0x00, 0x03, 0x30, 0x1B, 0x33, 0x98, 0x61, 0x0C, 0x60, 0x30, 0x03, 0x18, 0xC0, 0x00, 0x06, 0x83, 0x01, 0x60, 0x6C, 0x60, 0x80, 0x99, 0x79, 0xCC, 0x60, 0x06, 0x33, 0x98, 0xC1, 0x18, 0x00, 0x03, 0x83, 0x31, 0x66, 0x60, 0xD8, 0x60, 0x06, 0x30, 0x30, 0x80, 0x01, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8C, 0x61, 0x18, 0xC3, 0x30, 0xC6, 0xC0, 0x80, 0x61, 0x86, 0x01, 0x03, 0x60, 0x18, 0x03, 0x86, 0xD9, 0x18, 0x86, 0x31, 0x86, 0x61, 0x98, 0x0D, 0x0C, 0x06, 0x03, 0x83, 0x19, 0x6C, 0x60, 0x06, 0x33, 0x18, 0xC0, 0x60, 0x00, 0x03, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x98, 0x61, 0x03, 0x18, 0xF0, 0x00, 0x00, 0x18, 0x00, 0x06, 0x0C, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x66, 0x03, 0x03, 0x60, 0xE0, 0xC1, 0x30, 0xC0, 0x18, 0x06, 0x18, 0xF8, 0x30, 0x18, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x06, 0x18, 0x1B, 0x33, 0x98, 0x3F, 0x0C, 0x60, 0x30, 0x7F, 0xF8, 0xC3, 0x00, 0xFE, 0x83, 0x01, 0x60, 0x3C, 0x60, 0x80, 0x81, 0xD9, 0xCC, 0x60, 0x86, 0x31, 0x98, 0x61, 0xF0, 0x01, 0x03, 0x83, 0x31, 0x66, 0x60, 0x70, 0xC0, 0x03, 0x18, 0x30, 0x00, 0x03, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0xC1, 0x0C, 0x66, 0x30, 0x83, 0xC1, 0xC0, 0x60, 0x06, 0x03, 0x03, 0x60, 0x98, 0x01, 0x86, 0x99, 0x19, 0xCC, 0x60, 0x06, 0x33, 0x98, 0x07, 0x0C, 0x00, 0x03, 0x83, 0x19, 0x6C, 0x60, 0x8C, 0x31, 0x18, 0x60, 0x38, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x98, 0xC1, 0x0F, 0x18, 0x98, 0x0D, 0x00, 0x18, 0x00, 0xC6, 0xFF, 0xFE, 0x07, 0x00, 0xFF, 0x01, 0x00, 0x06, 0x36, 0x03, 0x03, 0x30, 0x00, 0x63, 0x30, 0x80, 0x19, 0x0C, 0x18, 0x8C, 0x61, 0x18, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x06, 0x0C, 0x1B, 0xF3, 0x9F, 0x61, 0x0C, 0x60, 0x30, 0x03, 0x18, 0xC0, 0x7C, 0x06, 0x83, 0x01, 0x60, 0x3C, 0x60, 0x80, 0x81, 0x99, 0xCD, 0x60, 0xFE, 0x30, 0x98, 0x3F, 0x00, 0x03, 0x03, 0x83, 0x31, 0x66, 0x66, 0x70, 0xC0, 0x03, 0x0C, 0x30, 0x00, 0x03, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0xC1, 0x0C, 0x60, 0x30, 0x83, 0xC1, 0xC0, 0x60, 0x06, 0x03, 0x03, 0x60, 0xD8, 0x00, 0x86, 0x99, 0x19, 0xCC, 0x60, 0x06, 0x33, 0x98, 0x03, 0x0C, 0x00, 0x03, 0x83, 0x31, 0x66, 0x66, 0xD8, 0x30, 0x18, 0x30, 0x60, 0x00, 0x03, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x98, 0x01, 0x1B, 0x0C, 0x0C, 0x0F, 0x00, 0x18, 0x00, 0x06, 0x0C, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x1E, 0x03, 0x03, 0x18, 0x00, 0x66, 0x30, 0x80, 0x19, 0x0C, 0x0C, 0x06, 0xC3, 0x1F, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x03, 0x0C, 0x1B, 0x33, 0x98, 0xC1, 0x0C, 0x60, 0x30, 0x03, 0x18, 0xC0, 0x60, 0x06, 0x83, 0x01, 0x60, 0x6C, 0x60, 0x80, 0x81, 0x19, 0xCF, 0x60, 0x06, 0x30, 0x98, 0x07, 0x00, 0x06, 0x03, 0x83, 0x31, 0x66, 0x66, 0xD8, 0x80, 0x01, 0x06, 0x30, 0x00, 0x06, 0x60, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x9F, 0xC1, 0x0C, 0x60, 0x30, 0xFF, 0xC1, 0xC0, 0x60, 0x06, 0x03, 0x03, 0x60, 0x78, 0x00, 0x86, 0x99, 0x19, 0xCC, 0x60, 0x06, 0x33, 0x98, 0x01, 0xF8, 0x03, 0x03, 0x83, 0x31, 0x66, 0x66, 0x70, 0x30, 0x18, 0x18, 0x60, 0x00, 0x03, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x07, 0x33, 0x0C, 0x0C, 0x06, 0x00, 0x18, 0x00, 0x06, 0x1E, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0E, 0x03, 0x03, 0x0C, 0x00, 0x66, 0x30, 0x80, 0x19, 0x0C, 0x0C, 0x06, 0x03, 0x18, 0x00, 0x00, 0x80, 0x01, 0xFF, 0x81, 0x01, 0x00, 0x33, 0x33, 0x98, 0xC1, 0x0C, 0x60, 0x30, 0x03, 0x18, 0xC0, 0x60, 0x06, 0x83, 0x81, 0x61, 0xCC, 0x60, 0x80, 0x81, 0x19, 0xCE, 0x60, 0x06, 0x30, 0x98, 0x0D, 0x00, 0x06, 0x03, 0x83, 0x61, 0x63, 0x6F, 0xD8, 0x80, 0x01, 0x03, 0x30, 0x00, 0x06, 0x60, 0x00, 0x00, 0x00, 0x00, 0x30, 0x98, 0xC1, 0x0C, 0x60, 0x30, 0x03, 0xC0, 0xC0, 0x60, 0x06, 0x03, 0x03, 0x60, 0x78, 0x00, 0x86, 0x99, 0x19, 0xCC, 0x60, 0x06, 0x33, 0x98, 0x01, 0x00, 0x06, 0x03, 0x83, 0x31, 0x66, 0x66, 0x70, 0x30, 0x18, 0x0C, 0x60, 0x00, 0x03, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x01, 0x33, 0xE6, 0x0C, 0x06, 0x00, 0x30, 0x00, 0x03, 0x33, 0x60, 0x00, 0x03, 0x00, 0x00, 0x80, 0x01, 0x06, 0x03, 0x03, 0x06, 0x00, 0xE6, 0x3F, 0x83, 0x19, 0x0C, 0x06, 0x06, 0x03, 0x18, 0x0C, 0x60, 0x00, 0x03, 0x00, 0xC0, 0x00, 0x00, 0xE3, 0x33, 0x98, 0xC1, 0x0C, 0x66, 0x30, 0x03, 0x18, 0xC0, 0x60, 0x06, 0x83, 0x81, 0x61, 0x8C, 0x61, 0x80, 0x81, 0x19, 0xCC, 0x60, 0x06, 0x30, 0x98, 0x19, 0x00, 0x06, 0x03, 0x83, 0x61, 0xE3, 0x79, 0x8C, 0x81, 0x81, 0x01, 0x30, 0x00, 0x0C, 0x60, 0x00, 0x00, 0x00, 0x00, 0x30, 0x98, 0xC1, 0x0C, 0x60, 0x30, 0x03, 0xC0, 0xC0, 0x60, 0x06, 0x03, 0x03, 0x60, 0xD8, 0x00, 0x86, 0x99, 0x19, 0xCC, 0x60, 0x06, 0x33, 0x98, 0x01, 0x00, 0x06, 0x03, 0x83, 0x61, 0x63, 0x66, 0xD8, 0x30, 0x18, 0x06, 0x60, 0x00, 0x03, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x98, 0x31, 0x33, 0xB6, 0x0D, 0x06, 0x00, 0x30, 0x00, 0x83, 0x61, 0x60, 0x00, 0x03, 0x00, 0xC0, 0x80, 0x01, 0x06, 0x03, 0x03, 0x03, 0x0C, 0x06, 0x30, 0x83, 0x19, 0x0C, 0x06, 0x06, 0x03, 0x18, 0x0C, 0x60, 0x00, 0x06, 0x00, 0x60, 0x00, 0x0C, 0x03, 0x30, 0x98, 0xC1, 0x0C, 0x66, 0x30, 0x03, 0x18, 0xC0, 0x60, 0x06, 0x83, 0x81, 0x61, 0x0C, 0x63, 0x80, 0x81, 0x19, 0xCC, 0x60, 0x06, 0x30, 0x98, 0x31, 0x0C, 0x06, 0x03, 0x83, 0xC1, 0xE1, 0x70, 0x8C, 0x81, 0x81, 0x01, 0x30, 0x00, 0x0C, 0x60, 0x00, 0x00, 0x00, 0x00, 0x30, 0x98, 0xC1, 0x0C, 0x66, 0x30, 0x03, 0xC0, 0xC0, 0x60, 0x06, 0x03, 0x03, 0x60, 0x98, 0x01, 0x86, 0x99, 0x19, 0xCC, 0x60, 0x06, 0x33, 0x98, 0x01, 0x00, 0x06, 0x03, 0x83, 0x61, 0x63, 0x66, 0x8C, 0x31, 0x18, 0x03, 0x60, 0x00, 0x03, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x98, 0x61, 0x1B, 0xB3, 0x19, 0x0F, 0x00, 0x60, 0x80, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0xC0, 0xC0, 0x00, 0x8C, 0x01, 0x83, 0x01, 0x18, 0x03, 0x30, 0xC6, 0x30, 0x06, 0x06, 0x8C, 0x01, 0x0C, 0x0C, 0x60, 0x00, 0x0C, 0x00, 0x30, 0x00, 0x0C, 0x06, 0x30, 0x98, 0x61, 0x18, 0x63, 0x18, 0x03, 0x18, 0x80, 0x31, 0x06, 0x83, 0x01, 0x33, 0x0C, 0x66, 0x80, 0x81, 0x19, 0x8C, 0x31, 0x06, 0x60, 0x8F, 0x61, 0x18, 0x03, 0x03, 0xC6, 0xC0, 0x61, 0x60, 0x06, 0x83, 0x81, 0x01, 0x30, 0x00, 0x18, 0x60, 0x00, 0x00, 0x00, 0x00, 0x30, 0x98, 0x61, 0x18, 0xC3, 0x30, 0x86, 0xC1, 0x80, 0x61, 0x06, 0x03, 0x03, 0x60, 0x18, 0x03, 0x86, 0x99, 0x19, 0x8C, 0x31, 0x86, 0x61, 0x98, 0x01, 0x0C, 0x06, 0x03, 0x86, 0xC1, 0x61, 0x66, 0x06, 0x63, 0x98, 0x01, 0xC0, 0x00, 0x03, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x98, 0xC1, 0x0F, 0xE3, 0xF0, 0x0D, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0xC0, 0xC0, 0x00, 0xF8, 0xE0, 0x9F, 0xFF, 0xF0, 0x01, 0x30, 0x7C, 0xE0, 0x03, 0x06, 0xF8, 0xE0, 0x07, 0x00, 0x60, 0x00, 0x18, 0x00, 0x18, 0x00, 0x0C, 0xFC, 0x33, 0x98, 0x3F, 0xF0, 0xE1, 0x0F, 0xFF, 0x19, 0x00, 0x1F, 0x06, 0xE3, 0x07, 0x1E, 0x0C, 0xE6, 0xBF, 0x81, 0x19, 0x0C, 0x1F, 0x06, 0xC0, 0x87, 0xC1, 0xF0, 0x01, 0x03, 0x7C, 0xC0, 0x21, 0x40, 0x06, 0x83, 0x81, 0xFF, 0xF0, 0x01, 0x18, 0x7C, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x9F, 0x3F, 0xF0, 0x81, 0x3F, 0xFC, 0xC0, 0x00, 0x7F, 0x06, 0xC3, 0x0F, 0x60, 0x18, 0x86, 0x9F, 0x99, 0x19, 0x0C, 0x1F, 0xFE, 0xC0, 0x9F, 0x01, 0xF8, 0x03, 0x3E, 0xFC, 0xC1, 0xC1, 0x3F, 0x06, 0xC3, 0x9F, 0xFF, 0x80, 0x03, 0x03, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x1F, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; #define font24_width 1185 #define font24_height 24 static unsigned char font24_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x01, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x98, 0x81, 0x19, 0x60, 0x00, 0x00, 0x70, 0x00, 0x06, 0xC0, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x01, 0x06, 0xF8, 0x81, 0x1F, 0x00, 0xE6, 0x7F, 0xF8, 0xE3, 0x7F, 0xF8, 0x81, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x06, 0x80, 0x1F, 0xFC, 0x81, 0x1F, 0xFE, 0x81, 0x1F, 0xFE, 0xE1, 0x7F, 0xFE, 0x87, 0x1F, 0x06, 0x86, 0x1F, 0xC0, 0x6F, 0x60, 0x06, 0x10, 0x40, 0x06, 0x86, 0x1F, 0xFE, 0x81, 0x1F, 0xFE, 0x81, 0x1F, 0xFE, 0x67, 0x60, 0x06, 0x36, 0x60, 0x06, 0x66, 0x60, 0xFE, 0x87, 0x0F, 0x00, 0x80, 0x0F, 0x98, 0x01, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0xC0, 0x07, 0x00, 0x06, 0x00, 0x06, 0x00, 0xC3, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x60, 0xC0, 0x01, 0x66, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x98, 0x81, 0x19, 0xF8, 0xC1, 0x31, 0xD8, 0x00, 0x06, 0x60, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0C, 0x03, 0x07, 0x0C, 0xC3, 0x30, 0x00, 0x67, 0x00, 0x0C, 0x60, 0x60, 0x0C, 0xC3, 0x30, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x0C, 0xC0, 0x30, 0x06, 0xC3, 0x30, 0x06, 0xC3, 0x30, 0x06, 0x63, 0x00, 0x06, 0xC0, 0x30, 0x06, 0x06, 0x06, 0x00, 0x63, 0x30, 0x06, 0x30, 0x60, 0x06, 0xC6, 0x30, 0x06, 0xC3, 0x30, 0x06, 0xC3, 0x30, 0x60, 0x60, 0x60, 0x06, 0x36, 0x60, 0x06, 0x66, 0x60, 0x00, 0x86, 0x01, 0x0C, 0x00, 0x0C, 0x0C, 0x03, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x60, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00, 0xC3, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x60, 0x00, 0x03, 0xC6, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x98, 0x81, 0x19, 0x6C, 0x63, 0x33, 0x8C, 0x01, 0x06, 0x30, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x06, 0x86, 0x07, 0x06, 0x66, 0x60, 0x80, 0x67, 0x00, 0x06, 0x60, 0x60, 0x06, 0x66, 0x60, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x18, 0x60, 0x60, 0x03, 0x66, 0x60, 0x06, 0x66, 0x60, 0x06, 0x66, 0x00, 0x06, 0x60, 0x60, 0x06, 0x06, 0x06, 0x00, 0x63, 0x18, 0x06, 0x70, 0x70, 0x06, 0x66, 0x60, 0x06, 0x66, 0x60, 0x06, 0x66, 0x60, 0x60, 0x60, 0x60, 0x06, 0x36, 0x60, 0x0C, 0xC3, 0x30, 0x00, 0x86, 0x01, 0x0C, 0x00, 0x0C, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x60, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00, 0xC3, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x60, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x80, 0x19, 0x66, 0x66, 0x1B, 0x8C, 0x01, 0x00, 0x30, 0x00, 0x06, 0x06, 0x03, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x06, 0xC6, 0x06, 0x06, 0x06, 0x60, 0xC0, 0x66, 0x00, 0x06, 0x00, 0x60, 0x06, 0x66, 0x60, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x30, 0x60, 0x60, 0xC3, 0x67, 0x60, 0x06, 0x66, 0x60, 0x06, 0x66, 0x00, 0x06, 0x60, 0x60, 0x06, 0x06, 0x06, 0x00, 0x63, 0x0C, 0x06, 0xF0, 0x78, 0x06, 0x66, 0x60, 0x06, 0x66, 0x60, 0x06, 0x66, 0x00, 0x60, 0x60, 0x60, 0x06, 0x36, 0x60, 0x0C, 0xC3, 0x30, 0x00, 0x86, 0x01, 0x18, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x60, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x60, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0xE0, 0x7F, 0x66, 0xC0, 0x19, 0x8C, 0x01, 0x00, 0x18, 0x00, 0x0C, 0x8C, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x06, 0x07, 0x06, 0x06, 0x06, 0x60, 0x60, 0x66, 0x00, 0x06, 0x00, 0x30, 0x06, 0x66, 0x60, 0x60, 0x00, 0x06, 0x30, 0x00, 0x00, 0x60, 0x60, 0x60, 0x63, 0x66, 0x60, 0x06, 0x66, 0x00, 0x06, 0x66, 0x00, 0x06, 0x60, 0x00, 0x06, 0x06, 0x06, 0x00, 0x63, 0x06, 0x06, 0xB0, 0x6D, 0x0E, 0x66, 0x60, 0x06, 0x66, 0x60, 0x06, 0x66, 0x00, 0x60, 0x60, 0x60, 0x0C, 0x33, 0x60, 0x98, 0x81, 0x19, 0x00, 0x83, 0x01, 0x18, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x1F, 0xFE, 0x81, 0x1F, 0xF8, 0x87, 0x1F, 0xFC, 0x83, 0x7F, 0xFE, 0x81, 0x07, 0xC0, 0xC3, 0x60, 0x60, 0xE0, 0x1F, 0xFE, 0x81, 0x1F, 0xFE, 0x81, 0x7F, 0xE6, 0xC7, 0x3F, 0xFE, 0x61, 0x60, 0x06, 0x66, 0x60, 0x06, 0x66, 0x60, 0xFE, 0x07, 0x03, 0x60, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x80, 0x19, 0x66, 0x00, 0x0C, 0xD8, 0x00, 0x00, 0x18, 0x00, 0x0C, 0xD8, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x86, 0x07, 0x06, 0x00, 0x06, 0x60, 0x30, 0x66, 0x00, 0x06, 0x00, 0x30, 0x06, 0x66, 0x60, 0x60, 0x00, 0x06, 0x18, 0xE0, 0x7F, 0xC0, 0x00, 0x30, 0x33, 0x66, 0x60, 0x06, 0x63, 0x00, 0x06, 0x66, 0x00, 0x06, 0x60, 0x00, 0x06, 0x06, 0x06, 0x00, 0x63, 0x03, 0x06, 0x30, 0x67, 0x1E, 0x66, 0x60, 0x06, 0x66, 0x60, 0x06, 0x66, 0x00, 0x60, 0x60, 0x60, 0x0C, 0x33, 0x60, 0x98, 0x81, 0x19, 0x80, 0x81, 0x01, 0x30, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x06, 0xC3, 0x30, 0x0C, 0xC6, 0x30, 0x60, 0xC0, 0x60, 0x06, 0x03, 0x06, 0x00, 0xC3, 0x30, 0x60, 0x60, 0x36, 0x06, 0xC3, 0x30, 0x06, 0xC3, 0x60, 0x36, 0x60, 0x60, 0x30, 0x60, 0x60, 0x06, 0x66, 0x60, 0x06, 0x66, 0x60, 0x00, 0x06, 0x03, 0x60, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x80, 0x19, 0x6C, 0x00, 0x0C, 0x70, 0x00, 0x00, 0x18, 0x00, 0x0C, 0x70, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0xC6, 0x06, 0x06, 0x00, 0x03, 0x30, 0x18, 0xE6, 0x1F, 0xFE, 0x01, 0x18, 0x0C, 0x63, 0x60, 0x60, 0x00, 0x06, 0x0C, 0x00, 0x00, 0x80, 0x01, 0x18, 0x33, 0x66, 0x60, 0xFE, 0x61, 0x00, 0x06, 0x66, 0x00, 0x06, 0x60, 0x00, 0x06, 0x06, 0x06, 0x00, 0xE3, 0x01, 0x06, 0x30, 0x62, 0x36, 0x66, 0x60, 0x06, 0x63, 0x60, 0x06, 0xC3, 0x00, 0x60, 0x60, 0x60, 0x0C, 0x33, 0x60, 0xF0, 0x00, 0x0F, 0xC0, 0x80, 0x01, 0x30, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x06, 0x66, 0x60, 0x06, 0x66, 0x60, 0x60, 0x60, 0x60, 0x06, 0x06, 0x06, 0x00, 0xC3, 0x18, 0x60, 0x60, 0x66, 0x06, 0x66, 0x60, 0x06, 0x66, 0x60, 0x1E, 0x60, 0x00, 0x30, 0x60, 0x60, 0x06, 0x66, 0x60, 0x0C, 0x63, 0x60, 0x00, 0x03, 0x03, 0x60, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x80, 0x19, 0xF8, 0x01, 0x06, 0x78, 0x06, 0x00, 0x18, 0x00, 0x0C, 0xFF, 0xE7, 0x7F, 0x00, 0xE0, 0x7F, 0x00, 0x00, 0x06, 0x66, 0x06, 0x06, 0x80, 0x01, 0x1F, 0x0C, 0x06, 0x30, 0x06, 0x03, 0x18, 0xF8, 0xC1, 0x60, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x03, 0x0C, 0x33, 0x66, 0x60, 0x06, 0x63, 0x00, 0x06, 0xE6, 0x1F, 0xFE, 0x61, 0x7C, 0xFE, 0x07, 0x06, 0x00, 0xE3, 0x00, 0x06, 0x30, 0x60, 0x66, 0x66, 0x60, 0xFE, 0x61, 0x60, 0xFE, 0x81, 0x1F, 0x60, 0x60, 0x60, 0x0C, 0x33, 0x60, 0x60, 0x00, 0x0F, 0x60, 0x80, 0x01, 0x60, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x06, 0x66, 0x00, 0x06, 0x66, 0x60, 0x60, 0x60, 0x60, 0x06, 0x06, 0x06, 0x00, 0xC3, 0x0C, 0x60, 0x60, 0x66, 0x06, 0x66, 0x60, 0x06, 0x66, 0x60, 0x0E, 0x60, 0x00, 0x30, 0x60, 0x60, 0x0C, 0x63, 0x60, 0x98, 0x61, 0x60, 0x80, 0xC1, 0x01, 0x60, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x80, 0x19, 0x60, 0x03, 0x06, 0xCC, 0x06, 0x00, 0x18, 0x00, 0x0C, 0x70, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x36, 0x06, 0x06, 0xC0, 0x00, 0x30, 0x06, 0x06, 0x60, 0x06, 0x06, 0x0C, 0x0C, 0x83, 0x7F, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x80, 0x01, 0x06, 0x33, 0xE6, 0x7F, 0x06, 0x66, 0x00, 0x06, 0x66, 0x00, 0x06, 0x60, 0x60, 0x06, 0x06, 0x06, 0x00, 0xE3, 0x01, 0x06, 0x30, 0x60, 0xC6, 0x66, 0x60, 0x06, 0x60, 0x60, 0x1E, 0x00, 0x30, 0x60, 0x60, 0x60, 0x98, 0x31, 0x62, 0xF0, 0x00, 0x06, 0x30, 0x80, 0x01, 0x60, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x80, 0x7F, 0x06, 0x66, 0x00, 0x06, 0x66, 0x60, 0x60, 0x60, 0x60, 0x06, 0x06, 0x06, 0x00, 0xC3, 0x06, 0x60, 0x60, 0x66, 0x06, 0x66, 0x60, 0x06, 0x66, 0x60, 0x06, 0x60, 0x00, 0x30, 0x60, 0x60, 0x0C, 0x63, 0x66, 0xF0, 0x60, 0x60, 0xC0, 0x00, 0x03, 0x60, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x80, 0x19, 0x60, 0x06, 0x03, 0x86, 0x03, 0x00, 0x18, 0x00, 0x0C, 0xD8, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x1E, 0x06, 0x06, 0x60, 0x00, 0x60, 0x06, 0x06, 0x60, 0x06, 0x06, 0x0C, 0x06, 0x06, 0x60, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0xC0, 0x00, 0x06, 0x33, 0x66, 0x60, 0x06, 0x66, 0x00, 0x06, 0x66, 0x00, 0x06, 0x60, 0x60, 0x06, 0x06, 0x06, 0x00, 0x63, 0x03, 0x06, 0x30, 0x60, 0x86, 0x67, 0x60, 0x06, 0x60, 0x60, 0x36, 0x00, 0x60, 0x60, 0x60, 0x60, 0x98, 0x31, 0x67, 0x98, 0x01, 0x06, 0x18, 0x80, 0x01, 0xC0, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x60, 0x06, 0x66, 0x00, 0x06, 0xE6, 0x7F, 0x60, 0x60, 0x60, 0x06, 0x06, 0x06, 0x00, 0xC3, 0x03, 0x60, 0x60, 0x66, 0x06, 0x66, 0x60, 0x06, 0x66, 0x60, 0x06, 0xC0, 0x3F, 0x30, 0x60, 0x60, 0x98, 0x61, 0x66, 0x60, 0x60, 0x60, 0x60, 0x00, 0x03, 0x60, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x7F, 0x60, 0x06, 0x03, 0x06, 0x03, 0x00, 0x18, 0x00, 0x0C, 0x8C, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0E, 0x06, 0x06, 0x30, 0x00, 0x60, 0x06, 0x06, 0x60, 0x06, 0x06, 0x06, 0x06, 0x06, 0x60, 0x00, 0x00, 0x00, 0x30, 0xE0, 0x7F, 0x60, 0x00, 0x00, 0x63, 0x66, 0x60, 0x06, 0x66, 0x00, 0x06, 0x66, 0x00, 0x06, 0x60, 0x60, 0x06, 0x06, 0x06, 0x06, 0x63, 0x06, 0x06, 0x30, 0x60, 0x06, 0x67, 0x60, 0x06, 0x60, 0x60, 0x66, 0x00, 0x60, 0x60, 0x60, 0x60, 0x98, 0xB1, 0x6D, 0x98, 0x01, 0x06, 0x0C, 0x80, 0x01, 0xC0, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x60, 0x60, 0x06, 0x66, 0x00, 0x06, 0x66, 0x00, 0x60, 0x60, 0x60, 0x06, 0x06, 0x06, 0x00, 0xC3, 0x06, 0x60, 0x60, 0x66, 0x06, 0x66, 0x60, 0x06, 0x66, 0x60, 0x06, 0x00, 0x60, 0x30, 0x60, 0x60, 0x98, 0x61, 0x66, 0xF0, 0x60, 0x60, 0x30, 0x00, 0x03, 0x60, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x19, 0x66, 0x86, 0x39, 0x06, 0x03, 0x00, 0x30, 0x00, 0x06, 0x06, 0x03, 0x06, 0x60, 0x00, 0x00, 0x00, 0x80, 0x01, 0x06, 0x06, 0x06, 0x18, 0x00, 0x60, 0xFE, 0x07, 0x60, 0x06, 0x06, 0x06, 0x06, 0x06, 0x60, 0x60, 0x00, 0x06, 0x60, 0x00, 0x00, 0x30, 0x00, 0x00, 0xC3, 0x67, 0x60, 0x06, 0x66, 0x60, 0x06, 0x66, 0x00, 0x06, 0x60, 0x60, 0x06, 0x06, 0x06, 0x06, 0x63, 0x0C, 0x06, 0x30, 0x60, 0x06, 0x66, 0x60, 0x06, 0x60, 0x60, 0xC6, 0x00, 0x60, 0x60, 0x60, 0x60, 0xF0, 0xF0, 0x78, 0x0C, 0x03, 0x06, 0x06, 0x80, 0x01, 0x80, 0x01, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x60, 0x60, 0x06, 0x66, 0x00, 0x06, 0x66, 0x00, 0x60, 0x60, 0x60, 0x06, 0x06, 0x06, 0x00, 0xC3, 0x0C, 0x60, 0x60, 0x66, 0x06, 0x66, 0x60, 0x06, 0x66, 0x60, 0x06, 0x00, 0x60, 0x30, 0x60, 0x60, 0xF0, 0x60, 0x66, 0x98, 0x61, 0x60, 0x18, 0x00, 0x03, 0x60, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x80, 0x19, 0x6C, 0x83, 0x6D, 0x86, 0x03, 0x00, 0x30, 0x00, 0x06, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x60, 0x80, 0x01, 0x06, 0x06, 0x06, 0x0C, 0x60, 0x60, 0x00, 0x66, 0x60, 0x06, 0x06, 0x06, 0x06, 0x06, 0x60, 0x60, 0x00, 0x06, 0xC0, 0x00, 0x00, 0x18, 0x00, 0x06, 0x03, 0x60, 0x60, 0x06, 0x66, 0x60, 0x06, 0x66, 0x00, 0x06, 0x60, 0x60, 0x06, 0x06, 0x06, 0x06, 0x63, 0x18, 0x06, 0x30, 0x60, 0x06, 0x66, 0x60, 0x06, 0x60, 0x66, 0x86, 0x61, 0x60, 0x60, 0x60, 0x60, 0xF0, 0x70, 0x70, 0x0C, 0x03, 0x06, 0x06, 0x80, 0x01, 0x80, 0x01, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x60, 0x60, 0x06, 0x66, 0x60, 0x06, 0x66, 0x00, 0x60, 0x60, 0x60, 0x06, 0x06, 0x06, 0x00, 0xC3, 0x18, 0x60, 0x60, 0x66, 0x06, 0x66, 0x60, 0x06, 0x66, 0x60, 0x06, 0x00, 0x60, 0x30, 0x60, 0x60, 0xF0, 0x60, 0x66, 0x0C, 0x63, 0x60, 0x0C, 0x00, 0x03, 0x60, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x80, 0x19, 0xF8, 0xC1, 0x6C, 0xCC, 0x06, 0x00, 0x60, 0x00, 0x03, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x60, 0xC0, 0x00, 0x0C, 0x03, 0x06, 0x06, 0xC0, 0x30, 0x00, 0xC6, 0x30, 0x0C, 0x03, 0x06, 0x0C, 0x03, 0x30, 0x60, 0x00, 0x06, 0x80, 0x01, 0x00, 0x0C, 0x00, 0x06, 0x06, 0x60, 0x60, 0x06, 0xC3, 0x30, 0x06, 0x63, 0x00, 0x06, 0xC0, 0x30, 0x06, 0x06, 0x06, 0x8C, 0x61, 0x30, 0x06, 0x30, 0x60, 0x06, 0xC6, 0x30, 0x06, 0xC0, 0x3C, 0x06, 0xC3, 0x30, 0x60, 0xC0, 0x30, 0x60, 0x30, 0x60, 0x06, 0x06, 0x06, 0x06, 0x80, 0x01, 0x00, 0x03, 0x0C, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x60, 0x06, 0xC3, 0x30, 0x0C, 0xC6, 0x60, 0x60, 0xC0, 0x70, 0x06, 0x06, 0x06, 0x00, 0xC3, 0x30, 0x60, 0x60, 0x66, 0x06, 0xC6, 0x30, 0x06, 0xC3, 0x60, 0x06, 0x60, 0x60, 0x30, 0xC0, 0x60, 0x60, 0x60, 0x66, 0x06, 0xC6, 0x70, 0x06, 0x00, 0x06, 0x60, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x80, 0x19, 0x60, 0xC0, 0x38, 0x78, 0x06, 0x00, 0xC0, 0x80, 0x01, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x60, 0xC0, 0x00, 0xF8, 0xC1, 0x3F, 0xFE, 0x87, 0x1F, 0x00, 0x86, 0x1F, 0xF8, 0x01, 0x06, 0xF8, 0xC1, 0x1F, 0x00, 0x00, 0x06, 0x00, 0x03, 0x00, 0x06, 0x00, 0x06, 0xFC, 0x67, 0x60, 0xFE, 0x81, 0x1F, 0xFE, 0xE1, 0x7F, 0x06, 0x80, 0x1F, 0x06, 0x86, 0x1F, 0xF8, 0x60, 0x60, 0xFE, 0x37, 0x60, 0x06, 0x86, 0x1F, 0x06, 0x80, 0x1F, 0x06, 0x86, 0x1F, 0x60, 0x80, 0x1F, 0x60, 0x10, 0x40, 0x06, 0x06, 0x06, 0xFE, 0x87, 0x0F, 0x00, 0x83, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x80, 0x7F, 0xFE, 0x81, 0x1F, 0xF8, 0x87, 0x3F, 0x60, 0x80, 0x7F, 0x06, 0x86, 0x1F, 0x00, 0xC3, 0x60, 0xF8, 0x61, 0x66, 0x06, 0x86, 0x1F, 0xFE, 0x81, 0x7F, 0x06, 0xC0, 0x3F, 0xE0, 0x83, 0x7F, 0x60, 0xC0, 0x3F, 0x06, 0x86, 0x7F, 0xFE, 0x07, 0x1C, 0x60, 0xC0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x0C, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x0C, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x98, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x1F, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; #define font28_width 1383 #define font28_height 28 static unsigned char font28_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x31, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xC3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x31, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xC7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x80, 0x31, 0x60, 0x0C, 0xC0, 0x00, 0x0F, 0x03, 0x0F, 0x00, 0x03, 0x80, 0x01, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0xF8, 0x03, 0x30, 0x80, 0x3F, 0xE0, 0x0F, 0x00, 0x8C, 0xFF, 0x83, 0x7F, 0xF8, 0x3F, 0xF8, 0x03, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x0F, 0xF8, 0x07, 0xFE, 0xE0, 0x3F, 0xE0, 0x0F, 0xFE, 0x80, 0xFF, 0xE3, 0xFF, 0xE0, 0x0F, 0x06, 0x0C, 0xFC, 0x00, 0xF8, 0x19, 0x30, 0x06, 0x80, 0x01, 0x66, 0xC0, 0xE0, 0x0F, 0xFE, 0x03, 0xFE, 0xE0, 0x3F, 0xE0, 0x0F, 0xFE, 0x9F, 0x01, 0x63, 0xC0, 0x18, 0x60, 0x06, 0x8C, 0x01, 0xE6, 0xFF, 0xC0, 0x0F, 0x0C, 0x00, 0xFC, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x06, 0x00, 0x30, 0x00, 0x60, 0x30, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0xC0, 0x00, 0x0E, 0x60, 0xCE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x80, 0x31, 0x60, 0x0C, 0xF8, 0x87, 0x1F, 0x83, 0x1F, 0x00, 0x03, 0xC0, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0xFC, 0x07, 0x38, 0xC0, 0x7F, 0xF0, 0x1F, 0x00, 0x8E, 0xFF, 0xC3, 0x7F, 0xF8, 0x3F, 0xFC, 0x07, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0xE0, 0x00, 0xF0, 0x1F, 0xFC, 0x0F, 0xFF, 0xE1, 0x7F, 0xF0, 0x1F, 0xFE, 0x83, 0xFF, 0xE3, 0xFF, 0xF0, 0x1F, 0x06, 0x0C, 0xFC, 0x00, 0xF8, 0x19, 0x38, 0x06, 0x80, 0x01, 0x66, 0xC0, 0xF0, 0x1F, 0xFE, 0x07, 0xFF, 0xE1, 0x7F, 0xF0, 0x1F, 0xFE, 0x9F, 0x01, 0x63, 0xC0, 0x18, 0x60, 0x06, 0x8C, 0x01, 0xE6, 0xFF, 0xC0, 0x0F, 0x0C, 0x00, 0xFC, 0x80, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x06, 0x00, 0x30, 0x00, 0x60, 0x30, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xC0, 0x00, 0x1E, 0x60, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x80, 0x31, 0x60, 0x0C, 0xFC, 0x8F, 0x99, 0xC1, 0x39, 0x00, 0x03, 0x60, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0E, 0x0E, 0x3C, 0xE0, 0xE0, 0x38, 0x38, 0x00, 0x8F, 0x01, 0xE0, 0x00, 0x18, 0x30, 0x0E, 0x8E, 0x83, 0x03, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0xC0, 0x01, 0x38, 0x38, 0x0E, 0x9C, 0x83, 0x63, 0xE0, 0x38, 0x38, 0x06, 0x87, 0x01, 0x60, 0x00, 0x38, 0x38, 0x06, 0x0C, 0x30, 0x00, 0x60, 0x18, 0x1C, 0x06, 0x80, 0x03, 0x67, 0xC0, 0x38, 0x38, 0x06, 0x8E, 0x83, 0x63, 0xE0, 0x38, 0x38, 0xC0, 0x80, 0x01, 0x63, 0xC0, 0x18, 0x60, 0x0C, 0x06, 0x03, 0x03, 0xC0, 0xC0, 0x00, 0x18, 0x00, 0xC0, 0xC0, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x06, 0x00, 0x00, 0x06, 0x00, 0x30, 0x00, 0x60, 0x30, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0xC0, 0x00, 0x38, 0x60, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x80, 0x31, 0x60, 0x0C, 0xCE, 0x9C, 0x9F, 0xC1, 0x30, 0x00, 0x03, 0x60, 0x00, 0x30, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x06, 0x0C, 0x3E, 0x60, 0xC0, 0x18, 0x30, 0x80, 0x8F, 0x01, 0x60, 0x00, 0x18, 0x30, 0x06, 0x8C, 0x01, 0x03, 0x00, 0x00, 0x00, 0x80, 0x03, 0x00, 0x80, 0x03, 0x18, 0x30, 0x06, 0x98, 0x01, 0x63, 0xC0, 0x18, 0x30, 0x06, 0x86, 0x01, 0x60, 0x00, 0x18, 0x30, 0x06, 0x0C, 0x30, 0x00, 0x60, 0x18, 0x0E, 0x06, 0x80, 0x87, 0x67, 0xC0, 0x18, 0x30, 0x06, 0x8C, 0x01, 0x63, 0xC0, 0x18, 0x30, 0xC0, 0x80, 0x01, 0x63, 0xC0, 0x18, 0x60, 0x0C, 0x06, 0x03, 0x03, 0xC0, 0xC0, 0x00, 0x18, 0x00, 0xC0, 0xE0, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x06, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0xF8, 0x3F, 0xC6, 0x18, 0xCF, 0xC0, 0x30, 0x00, 0x00, 0x30, 0x00, 0x60, 0xC0, 0x71, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x06, 0x0E, 0x30, 0x60, 0xC0, 0x00, 0x30, 0xC0, 0x8D, 0x01, 0x60, 0x00, 0x18, 0x30, 0x06, 0x8C, 0x01, 0x03, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x07, 0x18, 0x30, 0x86, 0x9F, 0x01, 0x63, 0xC0, 0x18, 0x30, 0x06, 0x8C, 0x01, 0x60, 0x00, 0x18, 0x30, 0x06, 0x0C, 0x30, 0x00, 0x60, 0x18, 0x07, 0x06, 0x80, 0xCF, 0xE7, 0xC0, 0x18, 0x30, 0x06, 0x8C, 0x01, 0x63, 0xC0, 0x18, 0x00, 0xC0, 0x80, 0x01, 0xC3, 0x60, 0x18, 0x60, 0x18, 0x03, 0x86, 0x01, 0xE0, 0xC0, 0x00, 0x30, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x06, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0xF8, 0x3F, 0xC6, 0x00, 0xC0, 0xC0, 0x39, 0x00, 0x00, 0x30, 0x00, 0x60, 0x80, 0x3B, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x06, 0x0F, 0x30, 0x60, 0xC0, 0x00, 0x30, 0xE0, 0x8C, 0x01, 0x60, 0x00, 0x00, 0x18, 0x06, 0x8C, 0x01, 0x03, 0x0C, 0x00, 0x03, 0xE0, 0x80, 0xFF, 0x03, 0x0E, 0x18, 0x30, 0xC6, 0x9F, 0x01, 0x63, 0xC0, 0x18, 0x00, 0x06, 0x8C, 0x01, 0x60, 0x00, 0x18, 0x00, 0x06, 0x0C, 0x30, 0x00, 0x60, 0x98, 0x03, 0x06, 0x80, 0xFD, 0xE6, 0xC1, 0x18, 0x30, 0x06, 0x8C, 0x01, 0x63, 0xC0, 0x18, 0x00, 0xC0, 0x80, 0x01, 0xC3, 0x60, 0x18, 0x60, 0x18, 0x03, 0x86, 0x01, 0x70, 0xC0, 0x00, 0x30, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xE0, 0x3F, 0xE0, 0x0F, 0xF8, 0x0F, 0xFE, 0xC0, 0x3F, 0xE0, 0x3F, 0xFE, 0x03, 0x3C, 0x00, 0x78, 0x30, 0x38, 0xC0, 0x80, 0xFF, 0xE1, 0x3F, 0xE0, 0x0F, 0xFE, 0x03, 0xFE, 0x63, 0xFE, 0xE0, 0x0F, 0xFC, 0x83, 0x01, 0x63, 0xC0, 0x18, 0x60, 0x06, 0x8C, 0x01, 0xE3, 0xFF, 0x80, 0x01, 0xC0, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x60, 0x0C, 0xC6, 0x00, 0x60, 0x80, 0x1F, 0x00, 0x00, 0x30, 0x00, 0x60, 0x00, 0x1F, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x86, 0x0F, 0x30, 0x00, 0xC0, 0x00, 0x30, 0x70, 0x8C, 0x01, 0x60, 0x00, 0x00, 0x18, 0x06, 0x8C, 0x01, 0x03, 0x0C, 0x00, 0x03, 0x70, 0x80, 0xFF, 0x03, 0x1C, 0x00, 0x38, 0xE6, 0x98, 0x01, 0x63, 0x60, 0x18, 0x00, 0x06, 0x8C, 0x01, 0x60, 0x00, 0x18, 0x00, 0x06, 0x0C, 0x30, 0x00, 0x60, 0xD8, 0x01, 0x06, 0x80, 0x79, 0xE6, 0xC3, 0x18, 0x30, 0x06, 0x8C, 0x01, 0x63, 0xC0, 0x18, 0x00, 0xC0, 0x80, 0x01, 0xC3, 0x60, 0x18, 0x60, 0xB0, 0x01, 0xCC, 0x00, 0x38, 0xC0, 0x00, 0x60, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xE1, 0x7F, 0xF0, 0x1F, 0xFC, 0x0F, 0xFF, 0xC1, 0x3F, 0xF0, 0x3F, 0xFE, 0x07, 0x3C, 0x00, 0x78, 0x30, 0x1C, 0xC0, 0x80, 0xFF, 0xE3, 0x7F, 0xF0, 0x1F, 0xFE, 0x07, 0xFF, 0x63, 0xFF, 0xF0, 0x1F, 0xFC, 0x83, 0x01, 0x63, 0xC0, 0x18, 0x60, 0x06, 0x8C, 0x01, 0xE3, 0xFF, 0x80, 0x01, 0xC0, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x60, 0x0C, 0xCE, 0x00, 0x60, 0x00, 0x0F, 0x00, 0x00, 0x30, 0x00, 0x60, 0x00, 0x0E, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0xC6, 0x0D, 0x30, 0x00, 0xE0, 0x00, 0x38, 0x38, 0x8C, 0xFF, 0xE0, 0x3F, 0x00, 0x0C, 0x0E, 0x8E, 0x01, 0x03, 0x0C, 0x00, 0x03, 0x38, 0x00, 0x00, 0x00, 0x38, 0x00, 0x1C, 0x66, 0x98, 0x01, 0xE3, 0x3F, 0x18, 0x00, 0x06, 0x8C, 0x01, 0x60, 0x00, 0x18, 0x00, 0x06, 0x0C, 0x30, 0x00, 0x60, 0xF8, 0x00, 0x06, 0x80, 0x31, 0x66, 0xC7, 0x18, 0x30, 0x06, 0x8C, 0x01, 0x63, 0xC0, 0x38, 0x00, 0xC0, 0x80, 0x01, 0xC3, 0x60, 0x18, 0x60, 0xB0, 0x01, 0xCC, 0x00, 0x1C, 0xC0, 0x00, 0x60, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x63, 0xE0, 0x38, 0x38, 0x0E, 0x8C, 0x83, 0x03, 0x06, 0x38, 0x30, 0x06, 0x0E, 0x30, 0x00, 0x60, 0x30, 0x0E, 0xC0, 0x80, 0x31, 0x67, 0xE0, 0x38, 0x38, 0x06, 0x8E, 0x03, 0xE3, 0x03, 0x38, 0x38, 0x60, 0x80, 0x01, 0x63, 0xC0, 0x18, 0x60, 0x0E, 0x8E, 0x01, 0x03, 0xE0, 0x80, 0x01, 0xC0, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x60, 0x0C, 0xFC, 0x07, 0x30, 0x00, 0x07, 0x00, 0x00, 0x30, 0x00, 0x60, 0xE0, 0xFF, 0xF8, 0x7F, 0x00, 0x80, 0xFF, 0x03, 0x00, 0x00, 0x03, 0xE6, 0x0C, 0x30, 0x00, 0x70, 0xC0, 0x1F, 0x1C, 0x8C, 0xFF, 0xE1, 0x7F, 0x00, 0x0C, 0xFC, 0x87, 0x03, 0x03, 0x0C, 0x00, 0x03, 0x1C, 0x00, 0x00, 0x00, 0x70, 0x00, 0x0E, 0x66, 0x98, 0x01, 0xE3, 0x3F, 0x18, 0x00, 0x06, 0x8C, 0x7F, 0xE0, 0x1F, 0x18, 0x3F, 0xFE, 0x0F, 0x30, 0x00, 0x60, 0x78, 0x00, 0x06, 0x80, 0x01, 0x66, 0xCE, 0x18, 0x30, 0x06, 0x8E, 0x01, 0x63, 0xE0, 0xF0, 0x0F, 0xC0, 0x80, 0x01, 0x83, 0x31, 0x18, 0x60, 0xE0, 0x00, 0x78, 0x00, 0x0E, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0xC0, 0x18, 0x00, 0x06, 0x8C, 0x01, 0x03, 0x06, 0x18, 0x30, 0x06, 0x0C, 0x30, 0x00, 0x60, 0x30, 0x07, 0xC0, 0x80, 0x31, 0x66, 0xC0, 0x18, 0x30, 0x06, 0x8C, 0x01, 0xE3, 0x01, 0x18, 0x00, 0x60, 0x80, 0x01, 0xC3, 0x60, 0x18, 0x60, 0x1C, 0x87, 0x01, 0x03, 0x70, 0xE0, 0x00, 0xC0, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x60, 0x0C, 0xF8, 0x0F, 0x30, 0x80, 0x8F, 0x01, 0x00, 0x30, 0x00, 0x60, 0xE0, 0xFF, 0xF8, 0x7F, 0x00, 0x80, 0xFF, 0x03, 0x00, 0x00, 0x03, 0x76, 0x0C, 0x30, 0x00, 0x38, 0xC0, 0x1F, 0x0E, 0x0C, 0x80, 0x63, 0xE0, 0x00, 0x06, 0xFC, 0x07, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x07, 0x66, 0x98, 0xFF, 0x63, 0x60, 0x18, 0x00, 0x06, 0x8C, 0x7F, 0xE0, 0x1F, 0x18, 0x3F, 0xFE, 0x0F, 0x30, 0x00, 0x60, 0x78, 0x00, 0x06, 0x80, 0x01, 0x66, 0xDC, 0x18, 0x30, 0xFE, 0x87, 0x01, 0xE3, 0x7F, 0xE0, 0x1F, 0xC0, 0x80, 0x01, 0x83, 0x31, 0x18, 0x60, 0xE0, 0x00, 0x78, 0x00, 0x07, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x63, 0xC0, 0x18, 0x00, 0x06, 0x8C, 0x01, 0x03, 0x06, 0x18, 0x30, 0x06, 0x0C, 0x30, 0x00, 0x60, 0xB0, 0x03, 0xC0, 0x80, 0x31, 0x66, 0xC0, 0x18, 0x30, 0x06, 0x8C, 0x01, 0xE3, 0x00, 0x38, 0x00, 0x60, 0x80, 0x01, 0xC3, 0x60, 0x18, 0x63, 0xB8, 0x83, 0x01, 0x03, 0x38, 0xE0, 0x00, 0xC0, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x60, 0x0C, 0xC0, 0x1C, 0x18, 0xC0, 0xDD, 0x01, 0x00, 0x30, 0x00, 0x60, 0x00, 0x0E, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x3E, 0x0C, 0x30, 0x00, 0x1C, 0x00, 0x38, 0x06, 0x0C, 0x00, 0x63, 0xC0, 0x00, 0x06, 0x0E, 0x0E, 0xFE, 0x03, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x70, 0x00, 0x03, 0x66, 0x98, 0xFF, 0x63, 0xC0, 0x18, 0x00, 0x06, 0x8C, 0x01, 0x60, 0x00, 0x18, 0x30, 0x06, 0x0C, 0x30, 0x00, 0x60, 0xF8, 0x00, 0x06, 0x80, 0x01, 0x66, 0xF8, 0x18, 0x30, 0xFE, 0x83, 0x01, 0xE3, 0x3F, 0x00, 0x38, 0xC0, 0x80, 0x01, 0x83, 0x31, 0x18, 0x63, 0xB0, 0x01, 0x30, 0x80, 0x03, 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x63, 0xC0, 0x18, 0x00, 0x06, 0x8C, 0xFF, 0x03, 0x06, 0x18, 0x30, 0x06, 0x0C, 0x30, 0x00, 0x60, 0xF0, 0x01, 0xC0, 0x80, 0x31, 0x66, 0xC0, 0x18, 0x30, 0x06, 0x8C, 0x01, 0x63, 0x00, 0xF0, 0x0F, 0x60, 0x80, 0x01, 0xC3, 0x60, 0x18, 0x63, 0xF0, 0x81, 0x01, 0x03, 0x1C, 0x80, 0x01, 0xC0, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x60, 0x0C, 0xC0, 0x18, 0x18, 0xE0, 0xF8, 0x00, 0x00, 0x30, 0x00, 0x60, 0x00, 0x1F, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x1E, 0x0C, 0x30, 0x00, 0x0E, 0x00, 0x30, 0x06, 0x0C, 0x00, 0x63, 0xC0, 0x00, 0x03, 0x06, 0x0C, 0x00, 0x03, 0x00, 0x00, 0x00, 0x38, 0x80, 0xFF, 0x03, 0x38, 0x00, 0x03, 0xE6, 0x98, 0x01, 0x63, 0xC0, 0x18, 0x00, 0x06, 0x8C, 0x01, 0x60, 0x00, 0x18, 0x30, 0x06, 0x0C, 0x30, 0x00, 0x60, 0xD8, 0x01, 0x06, 0x80, 0x01, 0x66, 0xF0, 0x18, 0x30, 0x06, 0x80, 0x01, 0xE3, 0x03, 0x00, 0x30, 0xC0, 0x80, 0x01, 0x83, 0x31, 0x98, 0x67, 0xB0, 0x01, 0x30, 0xC0, 0x01, 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0x63, 0xC0, 0x18, 0x00, 0x06, 0x8C, 0xFF, 0x03, 0x06, 0x18, 0x30, 0x06, 0x0C, 0x30, 0x00, 0x60, 0xF0, 0x00, 0xC0, 0x80, 0x31, 0x66, 0xC0, 0x18, 0x30, 0x06, 0x8C, 0x01, 0x63, 0x00, 0xE0, 0x1F, 0x60, 0x80, 0x01, 0x83, 0x31, 0x18, 0x63, 0xE0, 0x80, 0x01, 0x03, 0x0E, 0x80, 0x01, 0xC0, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x3F, 0xC0, 0x18, 0x0C, 0x60, 0x70, 0x00, 0x00, 0x30, 0x00, 0x60, 0x80, 0x3B, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x0E, 0x0C, 0x30, 0x00, 0x07, 0x00, 0x30, 0xFE, 0x0F, 0x00, 0x63, 0xC0, 0x00, 0x03, 0x06, 0x0C, 0x00, 0x03, 0x00, 0x00, 0x00, 0x70, 0x80, 0xFF, 0x03, 0x1C, 0x00, 0x00, 0xC6, 0x9F, 0x01, 0x63, 0xC0, 0x18, 0x00, 0x06, 0x8C, 0x01, 0x60, 0x00, 0x18, 0x30, 0x06, 0x0C, 0x30, 0x60, 0x60, 0x98, 0x03, 0x06, 0x80, 0x01, 0x66, 0xE0, 0x18, 0x30, 0x06, 0x80, 0x01, 0x63, 0x07, 0x00, 0x30, 0xC0, 0x80, 0x01, 0x03, 0x1B, 0xD8, 0x6F, 0x18, 0x03, 0x30, 0xE0, 0x00, 0xC0, 0x00, 0x00, 0x03, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x63, 0xC0, 0x18, 0x00, 0x06, 0x8C, 0x01, 0x00, 0x06, 0x18, 0x30, 0x06, 0x0C, 0x30, 0x00, 0x60, 0xF0, 0x01, 0xC0, 0x80, 0x31, 0x66, 0xC0, 0x18, 0x30, 0x06, 0x8C, 0x01, 0x63, 0x00, 0x00, 0x38, 0x60, 0x80, 0x01, 0x83, 0x31, 0x18, 0x63, 0xF0, 0x81, 0x01, 0x03, 0x07, 0x80, 0x01, 0xC0, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x3F, 0xC6, 0x18, 0xCC, 0x63, 0x70, 0x00, 0x00, 0x30, 0x00, 0x60, 0xC0, 0x71, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x06, 0x0C, 0x30, 0x80, 0x03, 0x00, 0x30, 0xFE, 0x0F, 0x00, 0x63, 0xC0, 0x00, 0x03, 0x06, 0x0C, 0x00, 0x03, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x86, 0x97, 0x01, 0x63, 0xC0, 0x18, 0x30, 0x06, 0x8C, 0x01, 0x60, 0x00, 0x18, 0x30, 0x06, 0x0C, 0x30, 0x60, 0x60, 0x18, 0x07, 0x06, 0x80, 0x01, 0x66, 0xC0, 0x18, 0x30, 0x06, 0x80, 0x01, 0x63, 0x0E, 0x00, 0x30, 0xC0, 0x80, 0x01, 0x03, 0x1B, 0xF8, 0x7C, 0x18, 0x03, 0x30, 0x60, 0x00, 0xC0, 0x00, 0x00, 0x03, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x63, 0xC0, 0x18, 0x00, 0x06, 0x8C, 0x01, 0x00, 0x06, 0x18, 0x30, 0x06, 0x0C, 0x30, 0x00, 0x60, 0xB0, 0x03, 0xC0, 0x80, 0x31, 0x66, 0xC0, 0x18, 0x30, 0x06, 0x8C, 0x01, 0x63, 0x00, 0x00, 0x30, 0x60, 0x80, 0x01, 0x83, 0x31, 0x18, 0x63, 0xB8, 0x83, 0x01, 0x83, 0x03, 0x80, 0x01, 0xC0, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x60, 0x0C, 0xCE, 0x1C, 0xE6, 0x67, 0x70, 0x00, 0x00, 0x60, 0x00, 0x30, 0x00, 0x00, 0x00, 0x03, 0xC0, 0x00, 0x00, 0x00, 0x0C, 0x60, 0x00, 0x06, 0x0C, 0x30, 0xC0, 0x01, 0x18, 0x30, 0x00, 0x8C, 0x01, 0x63, 0xC0, 0x00, 0x03, 0x06, 0x0C, 0x00, 0x03, 0x0C, 0x00, 0x03, 0xC0, 0x01, 0x00, 0x00, 0x07, 0x00, 0x03, 0x06, 0x80, 0x01, 0x63, 0xC0, 0x18, 0x30, 0x06, 0x86, 0x01, 0x60, 0x00, 0x18, 0x30, 0x06, 0x0C, 0x30, 0x60, 0x60, 0x18, 0x0E, 0x06, 0x80, 0x01, 0x66, 0xC0, 0x18, 0x30, 0x06, 0x80, 0x71, 0x63, 0x1C, 0x18, 0x30, 0xC0, 0x80, 0x01, 0x03, 0x1B, 0x78, 0x78, 0x0C, 0x06, 0x30, 0x60, 0x00, 0xC0, 0x00, 0x00, 0x06, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x63, 0xC0, 0x18, 0x00, 0x06, 0x8C, 0x01, 0x00, 0x06, 0x18, 0x30, 0x06, 0x0C, 0x30, 0x00, 0x60, 0x30, 0x07, 0xC0, 0x80, 0x31, 0x66, 0xC0, 0x18, 0x30, 0x06, 0x8C, 0x01, 0x63, 0x00, 0x00, 0x30, 0x60, 0x80, 0x01, 0x03, 0x1B, 0x18, 0x63, 0x1C, 0x87, 0x01, 0xC3, 0x01, 0x80, 0x01, 0xC0, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x60, 0x0C, 0xFC, 0x0F, 0x66, 0xE6, 0xF8, 0x00, 0x00, 0x60, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x0C, 0x60, 0x00, 0x0E, 0x0E, 0x30, 0xE0, 0x00, 0x38, 0x38, 0x00, 0x8C, 0x83, 0xE3, 0xE0, 0x00, 0x03, 0x0E, 0x0E, 0x80, 0x03, 0x0C, 0x00, 0x03, 0x80, 0x03, 0x00, 0x80, 0x03, 0x00, 0x03, 0x0E, 0x80, 0x01, 0x63, 0xE0, 0x38, 0x38, 0x06, 0x87, 0x01, 0x60, 0x00, 0x38, 0x38, 0x06, 0x0C, 0x30, 0xE0, 0x70, 0x18, 0x1C, 0x06, 0x80, 0x01, 0x66, 0xC0, 0x38, 0x38, 0x06, 0x80, 0xE3, 0x63, 0x38, 0x38, 0x38, 0xC0, 0x80, 0x83, 0x03, 0x0E, 0x38, 0x70, 0x0C, 0x06, 0x30, 0x60, 0x00, 0xC0, 0x00, 0x00, 0x06, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0x63, 0xE0, 0x38, 0x38, 0x0E, 0x8C, 0x83, 0x03, 0x06, 0x38, 0x30, 0x06, 0x0C, 0x30, 0x00, 0x60, 0x30, 0x0E, 0xC0, 0x80, 0x31, 0x66, 0xC0, 0x38, 0x38, 0x06, 0x8E, 0x03, 0x63, 0x00, 0x38, 0x38, 0x60, 0x80, 0x03, 0x03, 0x1B, 0x38, 0x73, 0x0E, 0x8E, 0x03, 0xE3, 0x00, 0x80, 0x03, 0xC0, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x60, 0x0C, 0xF8, 0x07, 0xE3, 0xC7, 0xDF, 0x01, 0x00, 0xC0, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x0C, 0x30, 0x00, 0xFC, 0x07, 0xFE, 0xE1, 0xFF, 0xF0, 0x1F, 0x00, 0x0C, 0xFF, 0xC1, 0x7F, 0x00, 0x03, 0xFC, 0x07, 0xFF, 0x01, 0x0C, 0x00, 0x03, 0x00, 0x07, 0x00, 0xC0, 0x01, 0x00, 0x03, 0xFC, 0x9F, 0x01, 0xE3, 0x7F, 0xF0, 0x1F, 0xFE, 0x83, 0xFF, 0x63, 0x00, 0xF0, 0x1F, 0x06, 0x0C, 0xFC, 0xC0, 0x3F, 0x18, 0x38, 0xFE, 0x8F, 0x01, 0x66, 0xC0, 0xF0, 0x1F, 0x06, 0x00, 0xFF, 0x61, 0x70, 0xF0, 0x1F, 0xC0, 0x00, 0xFF, 0x01, 0x0E, 0x18, 0x60, 0x06, 0x0C, 0x30, 0xE0, 0xFF, 0xC0, 0x0F, 0x00, 0x0C, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE3, 0x7F, 0xF0, 0x1F, 0xFC, 0x0F, 0xFF, 0x01, 0x06, 0xF0, 0x3F, 0x06, 0x0C, 0xFC, 0x00, 0x60, 0x30, 0x1C, 0xF0, 0x83, 0x31, 0x66, 0xC0, 0xF0, 0x1F, 0xFE, 0x07, 0xFF, 0x63, 0x00, 0xF0, 0x1F, 0xE0, 0x07, 0xFF, 0x03, 0x0E, 0xF0, 0x3F, 0x06, 0x0C, 0xFF, 0xE3, 0xFF, 0x00, 0x0F, 0xC0, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x60, 0x0C, 0xC0, 0x00, 0xC3, 0x83, 0x8F, 0x01, 0x00, 0x80, 0x01, 0x0C, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x0C, 0x30, 0x00, 0xF8, 0x03, 0xFE, 0xE1, 0xFF, 0xE0, 0x0F, 0x00, 0x0C, 0xFE, 0x80, 0x3F, 0x00, 0x03, 0xF8, 0x03, 0xFF, 0x00, 0x0C, 0x00, 0x03, 0x00, 0x0E, 0x00, 0xE0, 0x00, 0x00, 0x03, 0xF8, 0x9F, 0x01, 0xE3, 0x3F, 0xE0, 0x0F, 0xFE, 0x80, 0xFF, 0x63, 0x00, 0xE0, 0x0F, 0x06, 0x0C, 0xFC, 0x80, 0x1F, 0x18, 0x30, 0xFE, 0x8F, 0x01, 0x66, 0xC0, 0xE0, 0x0F, 0x06, 0x00, 0xFE, 0x61, 0xE0, 0xE0, 0x0F, 0xC0, 0x00, 0xFE, 0x00, 0x0E, 0x18, 0x60, 0x06, 0x0C, 0x30, 0xE0, 0xFF, 0xC0, 0x0F, 0x00, 0x0C, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xE3, 0x3F, 0xE0, 0x0F, 0xF8, 0x0F, 0xFE, 0x00, 0x06, 0xE0, 0x3F, 0x06, 0x0C, 0xFC, 0x00, 0x60, 0x30, 0x38, 0xF0, 0x83, 0x31, 0x66, 0xC0, 0xE0, 0x0F, 0xFE, 0x03, 0xFE, 0x63, 0x00, 0xE0, 0x0F, 0xC0, 0x07, 0xFE, 0x03, 0x0E, 0xE0, 0x1F, 0x06, 0x0C, 0xFE, 0xE3, 0xFF, 0x00, 0x0E, 0xC0, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0xC0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0xC0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0xC0, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x1F, 0x00, 0x00, 0x00, 0x80, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; #define font32_width 1581 #define font32_height 32 static unsigned char font32_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x0E, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x0E, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x38, 0x0E, 0x38, 0x0E, 0xC0, 0x01, 0xF8, 0x38, 0xF0, 0x03, 0xC0, 0x01, 0x00, 0x07, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0xF8, 0x0F, 0xC0, 0x01, 0xF8, 0x0F, 0xF8, 0x0F, 0x00, 0x38, 0xFE, 0x3F, 0xF8, 0x1F, 0xFE, 0x3F, 0xF8, 0x0F, 0xF8, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x1C, 0x00, 0xF8, 0x0F, 0xF8, 0x1F, 0xF8, 0x0F, 0xFE, 0x0F, 0xF8, 0x0F, 0xFE, 0x03, 0xFE, 0x3F, 0xFE, 0x3F, 0xF8, 0x0F, 0x0E, 0x38, 0xF0, 0x07, 0x00, 0x7F, 0x0E, 0x30, 0x0E, 0x00, 0x0E, 0x70, 0x0E, 0x38, 0xF8, 0x0F, 0xFE, 0x0F, 0xF8, 0x0F, 0xFE, 0x0F, 0xF8, 0x0F, 0xFE, 0x3F, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x70, 0x0E, 0x38, 0x0E, 0x38, 0xFE, 0x3F, 0xF0, 0x0F, 0x1C, 0x00, 0xF0, 0x0F, 0x70, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x0E, 0x00, 0xC0, 0x01, 0x00, 0x1C, 0x1C, 0x00, 0xF0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0F, 0xC0, 0x01, 0x7C, 0x00, 0xEE, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x38, 0x0E, 0x38, 0x0E, 0xF8, 0x0F, 0xFC, 0x39, 0xF8, 0x07, 0xC0, 0x01, 0x80, 0x03, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0xFC, 0x1F, 0xE0, 0x01, 0xFC, 0x1F, 0xFC, 0x1F, 0x00, 0x3C, 0xFE, 0x3F, 0xFC, 0x1F, 0xFE, 0x3F, 0xFC, 0x1F, 0xFC, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x38, 0x00, 0xFC, 0x1F, 0xFC, 0x3F, 0xFC, 0x1F, 0xFE, 0x1F, 0xFC, 0x1F, 0xFE, 0x0F, 0xFE, 0x3F, 0xFE, 0x3F, 0xFC, 0x1F, 0x0E, 0x38, 0xF0, 0x07, 0x00, 0x7F, 0x0E, 0x38, 0x0E, 0x00, 0x0E, 0x70, 0x0E, 0x38, 0xFC, 0x1F, 0xFE, 0x1F, 0xFC, 0x1F, 0xFE, 0x1F, 0xFC, 0x1F, 0xFE, 0x3F, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x70, 0x0E, 0x38, 0x0E, 0x38, 0xFE, 0x3F, 0xF0, 0x0F, 0x1C, 0x00, 0xF0, 0x0F, 0x38, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x80, 0x7F, 0x00, 0x00, 0x0E, 0x00, 0xC0, 0x01, 0x00, 0x1C, 0x1C, 0x00, 0xF0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x0F, 0xC0, 0x01, 0xFC, 0x00, 0xCE, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x38, 0x0E, 0x38, 0x0E, 0xFC, 0x1F, 0xDC, 0x1D, 0x1C, 0x0E, 0xC0, 0x01, 0xC0, 0x01, 0xC0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x1E, 0x3C, 0xF0, 0x01, 0x1E, 0x3C, 0x1E, 0x3C, 0x00, 0x3E, 0x0E, 0x00, 0x1E, 0x00, 0x0E, 0x38, 0x1E, 0x3C, 0x1E, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x70, 0x00, 0x1E, 0x3C, 0x1E, 0x70, 0x1E, 0x3C, 0x0E, 0x3C, 0x1E, 0x3C, 0x0E, 0x1E, 0x0E, 0x00, 0x0E, 0x00, 0x1E, 0x3C, 0x0E, 0x38, 0xC0, 0x01, 0x00, 0x1C, 0x0E, 0x1C, 0x0E, 0x00, 0x1E, 0x78, 0x0E, 0x38, 0x1E, 0x3C, 0x0E, 0x3C, 0x1E, 0x3C, 0x0E, 0x3C, 0x1E, 0x3C, 0xC0, 0x01, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x70, 0x1C, 0x1C, 0x0E, 0x38, 0x00, 0x38, 0x70, 0x00, 0x38, 0x00, 0x00, 0x0E, 0x1C, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0xC0, 0x03, 0x00, 0x00, 0x0E, 0x00, 0xC0, 0x01, 0x00, 0x1C, 0x1C, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x01, 0xC0, 0x01, 0xE0, 0x01, 0x8E, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x38, 0x0E, 0x38, 0x0E, 0xDE, 0x3D, 0xDC, 0x1D, 0x1C, 0x0E, 0xC0, 0x01, 0xE0, 0x00, 0x80, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x0E, 0x38, 0xF8, 0x01, 0x0E, 0x38, 0x0E, 0x38, 0x00, 0x3F, 0x0E, 0x00, 0x0E, 0x00, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0xE0, 0x00, 0x0E, 0x38, 0x0E, 0x60, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x1C, 0x0E, 0x00, 0x0E, 0x00, 0x0E, 0x38, 0x0E, 0x38, 0xC0, 0x01, 0x00, 0x1C, 0x0E, 0x0E, 0x0E, 0x00, 0x3E, 0x7C, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x38, 0xC0, 0x01, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x70, 0x1C, 0x1C, 0x1C, 0x1C, 0x00, 0x38, 0x70, 0x00, 0x38, 0x00, 0x00, 0x0E, 0x0E, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x0E, 0x00, 0xC0, 0x01, 0x00, 0x1C, 0x1C, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x00, 0xC0, 0x01, 0xC0, 0x01, 0x0E, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x38, 0x0E, 0xCE, 0x39, 0xFC, 0x0F, 0x1C, 0x0E, 0x00, 0x00, 0xE0, 0x00, 0x80, 0x03, 0x1C, 0x1C, 0xC0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x0E, 0x38, 0xF8, 0x01, 0x0E, 0x38, 0x0E, 0x38, 0x80, 0x3B, 0x0E, 0x00, 0x0E, 0x00, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x38, 0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0xC0, 0x01, 0x0E, 0x38, 0x8E, 0x7F, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x00, 0x0E, 0x00, 0x0E, 0x38, 0x0E, 0x38, 0xC0, 0x01, 0x00, 0x1C, 0x0E, 0x07, 0x0E, 0x00, 0x7E, 0x7E, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x38, 0xC0, 0x01, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x70, 0x38, 0x0E, 0x1C, 0x1C, 0x00, 0x38, 0x70, 0x00, 0x70, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x00, 0xC0, 0x01, 0xC0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0xFE, 0x3F, 0xCE, 0x01, 0xF8, 0x0E, 0x1C, 0x0E, 0x00, 0x00, 0x70, 0x00, 0x00, 0x07, 0x38, 0x0E, 0xC0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x0E, 0x3C, 0xC0, 0x01, 0x0E, 0x38, 0x00, 0x38, 0xC0, 0x39, 0x0E, 0x00, 0x0E, 0x00, 0x0E, 0x1C, 0x0E, 0x38, 0x0E, 0x38, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x80, 0x03, 0x0E, 0x38, 0xCE, 0x7F, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x00, 0x0E, 0x38, 0x0E, 0x00, 0x0E, 0x00, 0x0E, 0x00, 0x0E, 0x38, 0xC0, 0x01, 0x00, 0x1C, 0x8E, 0x03, 0x0E, 0x00, 0x7E, 0x7E, 0x1E, 0x38, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x00, 0xC0, 0x01, 0x0E, 0x38, 0x1C, 0x1C, 0x0E, 0x70, 0x38, 0x0E, 0x38, 0x0E, 0x00, 0x1C, 0x70, 0x00, 0x70, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x00, 0xC0, 0x01, 0xC0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0xFE, 0x3F, 0xCE, 0x01, 0x00, 0x07, 0x1C, 0x0E, 0x00, 0x00, 0x70, 0x00, 0x00, 0x07, 0x70, 0x07, 0xC0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x0E, 0x3E, 0xC0, 0x01, 0x0E, 0x38, 0x00, 0x38, 0xE0, 0x38, 0x0E, 0x00, 0x0E, 0x00, 0x00, 0x1C, 0x0E, 0x38, 0x0E, 0x38, 0xC0, 0x01, 0xC0, 0x01, 0xE0, 0x00, 0xFE, 0x3F, 0x00, 0x07, 0x0E, 0x38, 0xEE, 0x71, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x00, 0x0E, 0x38, 0x0E, 0x00, 0x0E, 0x00, 0x0E, 0x00, 0x0E, 0x38, 0xC0, 0x01, 0x00, 0x1C, 0xCE, 0x01, 0x0E, 0x00, 0xEE, 0x77, 0x3E, 0x38, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x00, 0xC0, 0x01, 0x0E, 0x38, 0x1C, 0x1C, 0x0E, 0x70, 0x70, 0x07, 0x38, 0x0E, 0x00, 0x0E, 0x70, 0x00, 0xE0, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x0F, 0xFE, 0x0F, 0xF8, 0x0F, 0xF8, 0x3F, 0xF8, 0x0F, 0xFC, 0x1F, 0xF8, 0x3F, 0xFE, 0x0F, 0xF0, 0x01, 0x00, 0x1F, 0x1C, 0x38, 0xC0, 0x01, 0xFE, 0x0F, 0xFE, 0x0F, 0xF8, 0x0F, 0xFE, 0x0F, 0xF8, 0x3F, 0xCE, 0x3F, 0xF8, 0x0F, 0xFE, 0x0F, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x38, 0xFE, 0x3F, 0xE0, 0x00, 0xC0, 0x01, 0xC0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x38, 0x0E, 0xCE, 0x01, 0x00, 0x07, 0x38, 0x07, 0x00, 0x00, 0x70, 0x00, 0x00, 0x07, 0xE0, 0x03, 0xC0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x0E, 0x3F, 0xC0, 0x01, 0x00, 0x38, 0x00, 0x38, 0x70, 0x38, 0x0E, 0x00, 0x0E, 0x00, 0x00, 0x0E, 0x0E, 0x38, 0x0E, 0x38, 0xC0, 0x01, 0xC0, 0x01, 0x70, 0x00, 0xFE, 0x3F, 0x00, 0x0E, 0x00, 0x1C, 0xEE, 0x70, 0x0E, 0x38, 0x0E, 0x1C, 0x0E, 0x00, 0x0E, 0x38, 0x0E, 0x00, 0x0E, 0x00, 0x0E, 0x00, 0x0E, 0x38, 0xC0, 0x01, 0x00, 0x1C, 0xEE, 0x00, 0x0E, 0x00, 0xCE, 0x73, 0x7E, 0x38, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x00, 0xC0, 0x01, 0x0E, 0x38, 0x1C, 0x1C, 0x0E, 0x70, 0x70, 0x07, 0x70, 0x07, 0x00, 0x07, 0x70, 0x00, 0xE0, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x1F, 0xFE, 0x1F, 0xFC, 0x1F, 0xFC, 0x3F, 0xFC, 0x1F, 0xFC, 0x1F, 0xFC, 0x3F, 0xFE, 0x1F, 0xF0, 0x01, 0x00, 0x1F, 0x1C, 0x1C, 0xC0, 0x01, 0xFE, 0x1F, 0xFE, 0x1F, 0xFC, 0x1F, 0xFE, 0x1F, 0xFC, 0x3F, 0xEE, 0x3F, 0xFC, 0x1F, 0xFE, 0x0F, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x38, 0xFE, 0x3F, 0xE0, 0x00, 0xC0, 0x01, 0xC0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x38, 0x0E, 0xDE, 0x01, 0x80, 0x03, 0xF0, 0x03, 0x00, 0x00, 0x70, 0x00, 0x00, 0x07, 0xC0, 0x01, 0xC0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0x8E, 0x3B, 0xC0, 0x01, 0x00, 0x1C, 0x00, 0x3C, 0x38, 0x38, 0xFE, 0x0F, 0xFE, 0x0F, 0x00, 0x0E, 0x1E, 0x3C, 0x0E, 0x38, 0xC0, 0x01, 0xC0, 0x01, 0x38, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x0E, 0xEE, 0x70, 0x0E, 0x38, 0xFE, 0x0F, 0x0E, 0x00, 0x0E, 0x38, 0x0E, 0x00, 0x0E, 0x00, 0x0E, 0x00, 0x0E, 0x38, 0xC0, 0x01, 0x00, 0x1C, 0x7E, 0x00, 0x0E, 0x00, 0xCE, 0x73, 0xEE, 0x38, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x38, 0x1E, 0x00, 0xC0, 0x01, 0x0E, 0x38, 0x1C, 0x1C, 0x0E, 0x70, 0xE0, 0x03, 0x70, 0x07, 0x80, 0x03, 0x70, 0x00, 0xC0, 0x01, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x0E, 0x3C, 0x1E, 0x3C, 0x1E, 0x38, 0x1E, 0x3C, 0xC0, 0x01, 0x1E, 0x38, 0x0E, 0x3C, 0xC0, 0x01, 0x00, 0x1C, 0x1C, 0x0E, 0xC0, 0x01, 0xCE, 0x3D, 0x0E, 0x3C, 0x1E, 0x3C, 0x0E, 0x3C, 0x1E, 0x38, 0x7E, 0x00, 0x1E, 0x3C, 0xE0, 0x00, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x38, 0x00, 0x1C, 0xE0, 0x00, 0xC0, 0x01, 0xC0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x38, 0x0E, 0xFC, 0x0F, 0x80, 0x03, 0xF0, 0x01, 0x00, 0x00, 0x70, 0x00, 0x00, 0x07, 0xFE, 0x3F, 0xFE, 0x3F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0x80, 0x03, 0xCE, 0x39, 0xC0, 0x01, 0x00, 0x0E, 0xF0, 0x1F, 0x1C, 0x38, 0xFE, 0x1F, 0xFE, 0x1F, 0x00, 0x07, 0xFC, 0x1F, 0x1E, 0x38, 0xC0, 0x01, 0xC0, 0x01, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x07, 0xEE, 0x70, 0x0E, 0x38, 0xFE, 0x0F, 0x0E, 0x00, 0x0E, 0x38, 0xFE, 0x07, 0xFE, 0x07, 0x8E, 0x3F, 0xFE, 0x3F, 0xC0, 0x01, 0x00, 0x1C, 0x3E, 0x00, 0x0E, 0x00, 0x8E, 0x71, 0xCE, 0x39, 0x0E, 0x38, 0x0E, 0x3C, 0x0E, 0x38, 0x0E, 0x3C, 0xFC, 0x0F, 0xC0, 0x01, 0x0E, 0x38, 0x1C, 0x1C, 0x0E, 0x70, 0xE0, 0x03, 0xE0, 0x03, 0xC0, 0x01, 0x70, 0x00, 0xC0, 0x01, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x38, 0xC0, 0x01, 0x0E, 0x38, 0x0E, 0x38, 0xC0, 0x01, 0x00, 0x1C, 0x1C, 0x07, 0xC0, 0x01, 0xCE, 0x39, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x38, 0x3E, 0x00, 0x0E, 0x00, 0xE0, 0x00, 0x0E, 0x38, 0x1C, 0x1C, 0x0E, 0x38, 0x1C, 0x1C, 0x0E, 0x38, 0x00, 0x0E, 0x7C, 0x00, 0xC0, 0x01, 0x80, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x38, 0x0E, 0xF8, 0x1F, 0xC0, 0x01, 0xF8, 0x73, 0x00, 0x00, 0x70, 0x00, 0x00, 0x07, 0xFE, 0x3F, 0xFE, 0x3F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xC0, 0x01, 0xEE, 0x38, 0xC0, 0x01, 0x00, 0x07, 0xF0, 0x1F, 0x0E, 0x38, 0x00, 0x3C, 0x0E, 0x3C, 0x00, 0x07, 0xFC, 0x1F, 0xFC, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x38, 0x80, 0x03, 0xEE, 0x70, 0xFE, 0x3F, 0x0E, 0x1C, 0x0E, 0x00, 0x0E, 0x38, 0xFE, 0x07, 0xFE, 0x07, 0x8E, 0x3F, 0xFE, 0x3F, 0xC0, 0x01, 0x00, 0x1C, 0x3E, 0x00, 0x0E, 0x00, 0x0E, 0x70, 0x8E, 0x3B, 0x0E, 0x38, 0xFE, 0x1F, 0x0E, 0x38, 0xFE, 0x1F, 0xF8, 0x1F, 0xC0, 0x01, 0x0E, 0x38, 0x38, 0x0E, 0x8E, 0x71, 0xE0, 0x03, 0xE0, 0x03, 0xE0, 0x00, 0x70, 0x00, 0x80, 0x03, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x0E, 0x38, 0x0E, 0x00, 0x0E, 0x38, 0x0E, 0x38, 0xC0, 0x01, 0x0E, 0x38, 0x0E, 0x38, 0xC0, 0x01, 0x00, 0x1C, 0x9C, 0x03, 0xC0, 0x01, 0xCE, 0x39, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x38, 0x1E, 0x00, 0x0E, 0x00, 0xE0, 0x00, 0x0E, 0x38, 0x1C, 0x1C, 0xCE, 0x39, 0x38, 0x0E, 0x0E, 0x38, 0x00, 0x07, 0x7C, 0x00, 0xC0, 0x01, 0x80, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x38, 0x0E, 0xC0, 0x3D, 0xC0, 0x01, 0x1C, 0x77, 0x00, 0x00, 0x70, 0x00, 0x00, 0x07, 0xC0, 0x01, 0xC0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x7E, 0x38, 0xC0, 0x01, 0x80, 0x03, 0x00, 0x3C, 0x0E, 0x38, 0x00, 0x38, 0x0E, 0x38, 0x80, 0x03, 0x1E, 0x3C, 0xF8, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x1C, 0xC0, 0x01, 0xEE, 0x70, 0xFE, 0x3F, 0x0E, 0x38, 0x0E, 0x00, 0x0E, 0x38, 0x0E, 0x00, 0x0E, 0x00, 0x0E, 0x38, 0x0E, 0x38, 0xC0, 0x01, 0x00, 0x1C, 0x7E, 0x00, 0x0E, 0x00, 0x0E, 0x70, 0x0E, 0x3F, 0x0E, 0x38, 0xFE, 0x0F, 0x0E, 0x38, 0xFE, 0x0F, 0x00, 0x3C, 0xC0, 0x01, 0x0E, 0x38, 0x38, 0x0E, 0xCE, 0x73, 0xE0, 0x03, 0xC0, 0x01, 0x70, 0x00, 0x70, 0x00, 0x80, 0x03, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x3F, 0x0E, 0x38, 0x0E, 0x00, 0x0E, 0x38, 0x0E, 0x38, 0xC0, 0x01, 0x0E, 0x38, 0x0E, 0x38, 0xC0, 0x01, 0x00, 0x1C, 0xDC, 0x01, 0xC0, 0x01, 0xCE, 0x39, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x00, 0x1E, 0x00, 0xE0, 0x00, 0x0E, 0x38, 0x1C, 0x1C, 0xCE, 0x39, 0x70, 0x07, 0x0E, 0x38, 0x80, 0x03, 0xE0, 0x00, 0xC0, 0x01, 0xC0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x38, 0x0E, 0xC0, 0x39, 0xE0, 0x00, 0x0E, 0x3E, 0x00, 0x00, 0x70, 0x00, 0x00, 0x07, 0xE0, 0x03, 0xC0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x3E, 0x38, 0xC0, 0x01, 0xC0, 0x01, 0x00, 0x38, 0x0E, 0x38, 0x00, 0x38, 0x0E, 0x38, 0x80, 0x03, 0x0E, 0x38, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0xFE, 0x3F, 0x00, 0x0E, 0xC0, 0x01, 0xEE, 0x70, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x00, 0x0E, 0x38, 0x0E, 0x00, 0x0E, 0x00, 0x0E, 0x38, 0x0E, 0x38, 0xC0, 0x01, 0x00, 0x1C, 0xEE, 0x00, 0x0E, 0x00, 0x0E, 0x70, 0x0E, 0x3E, 0x0E, 0x38, 0x0E, 0x00, 0x0E, 0x38, 0x7E, 0x00, 0x00, 0x38, 0xC0, 0x01, 0x0E, 0x38, 0x38, 0x0E, 0xCE, 0x73, 0x70, 0x07, 0xC0, 0x01, 0x38, 0x00, 0x70, 0x00, 0x00, 0x07, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x3F, 0x0E, 0x38, 0x0E, 0x00, 0x0E, 0x38, 0xFE, 0x3F, 0xC0, 0x01, 0x0E, 0x38, 0x0E, 0x38, 0xC0, 0x01, 0x00, 0x1C, 0xFC, 0x00, 0xC0, 0x01, 0xCE, 0x39, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x00, 0xFC, 0x0F, 0xE0, 0x00, 0x0E, 0x38, 0x38, 0x0E, 0xCE, 0x39, 0xE0, 0x03, 0x0E, 0x38, 0xC0, 0x01, 0xE0, 0x00, 0xC0, 0x01, 0xC0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x3F, 0xC0, 0x39, 0xE0, 0x00, 0x0E, 0x1C, 0x00, 0x00, 0x70, 0x00, 0x00, 0x07, 0x70, 0x07, 0xC0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x1E, 0x38, 0xC0, 0x01, 0xE0, 0x00, 0x00, 0x38, 0xFE, 0x3F, 0x00, 0x38, 0x0E, 0x38, 0xC0, 0x01, 0x0E, 0x38, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x00, 0xFE, 0x3F, 0x00, 0x07, 0xC0, 0x01, 0xEE, 0x79, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x00, 0x0E, 0x38, 0x0E, 0x00, 0x0E, 0x00, 0x0E, 0x38, 0x0E, 0x38, 0xC0, 0x01, 0x00, 0x1C, 0xCE, 0x01, 0x0E, 0x00, 0x0E, 0x70, 0x0E, 0x3C, 0x0E, 0x38, 0x0E, 0x00, 0x0E, 0x38, 0xEE, 0x00, 0x00, 0x38, 0xC0, 0x01, 0x0E, 0x38, 0x38, 0x0E, 0xEE, 0x77, 0x70, 0x07, 0xC0, 0x01, 0x1C, 0x00, 0x70, 0x00, 0x00, 0x07, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x38, 0x0E, 0x38, 0x0E, 0x00, 0x0E, 0x38, 0xFE, 0x3F, 0xC0, 0x01, 0x0E, 0x38, 0x0E, 0x38, 0xC0, 0x01, 0x00, 0x1C, 0xFC, 0x00, 0xC0, 0x01, 0xCE, 0x39, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x00, 0xF8, 0x1F, 0xE0, 0x00, 0x0E, 0x38, 0x38, 0x0E, 0xCE, 0x39, 0xE0, 0x03, 0x0E, 0x38, 0xE0, 0x00, 0xE0, 0x00, 0xC0, 0x01, 0xC0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x3F, 0xC0, 0x39, 0x70, 0x1F, 0x0E, 0x1C, 0x00, 0x00, 0x70, 0x00, 0x00, 0x07, 0x38, 0x0E, 0xC0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x0E, 0x38, 0xC0, 0x01, 0x70, 0x00, 0x00, 0x38, 0xFE, 0x3F, 0x00, 0x38, 0x0E, 0x38, 0xC0, 0x01, 0x0E, 0x38, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0xCE, 0x7F, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x00, 0x0E, 0x38, 0x0E, 0x00, 0x0E, 0x00, 0x0E, 0x38, 0x0E, 0x38, 0xC0, 0x01, 0x0E, 0x1C, 0x8E, 0x03, 0x0E, 0x00, 0x0E, 0x70, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x00, 0x0E, 0x38, 0xCE, 0x01, 0x00, 0x38, 0xC0, 0x01, 0x0E, 0x38, 0x70, 0x07, 0x7E, 0x7E, 0x38, 0x0E, 0xC0, 0x01, 0x0E, 0x00, 0x70, 0x00, 0x00, 0x0E, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x00, 0x0E, 0x38, 0x0E, 0x00, 0xC0, 0x01, 0x0E, 0x38, 0x0E, 0x38, 0xC0, 0x01, 0x00, 0x1C, 0xDC, 0x01, 0xC0, 0x01, 0xCE, 0x39, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x00, 0x00, 0x3C, 0xE0, 0x00, 0x0E, 0x38, 0x38, 0x0E, 0xCE, 0x39, 0x70, 0x07, 0x0E, 0x38, 0x70, 0x00, 0xE0, 0x00, 0xC0, 0x01, 0xC0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x0E, 0xCE, 0x39, 0xF0, 0x3F, 0x0E, 0x1C, 0x00, 0x00, 0xE0, 0x00, 0x80, 0x03, 0x1C, 0x1C, 0xC0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x0E, 0x38, 0xC0, 0x01, 0x38, 0x00, 0x0E, 0x38, 0x00, 0x38, 0x00, 0x38, 0x0E, 0x38, 0xC0, 0x01, 0x0E, 0x38, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x8E, 0x6F, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x00, 0x0E, 0x00, 0x0E, 0x38, 0x0E, 0x38, 0xC0, 0x01, 0x0E, 0x1C, 0x0E, 0x07, 0x0E, 0x00, 0x0E, 0x70, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x00, 0x0E, 0x38, 0x8E, 0x03, 0x0E, 0x38, 0xC0, 0x01, 0x0E, 0x38, 0x70, 0x07, 0x7E, 0x7E, 0x38, 0x0E, 0xC0, 0x01, 0x0E, 0x00, 0x70, 0x00, 0x00, 0x0E, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x00, 0x0E, 0x38, 0x0E, 0x00, 0xC0, 0x01, 0x0E, 0x38, 0x0E, 0x38, 0xC0, 0x01, 0x00, 0x1C, 0x9C, 0x03, 0xC0, 0x01, 0xCE, 0x39, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x00, 0x00, 0x38, 0xE0, 0x00, 0x0E, 0x38, 0x70, 0x07, 0xCE, 0x39, 0x38, 0x0E, 0x0E, 0x38, 0x38, 0x00, 0xE0, 0x00, 0xC0, 0x01, 0xC0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x38, 0x0E, 0xDE, 0x3D, 0xB8, 0x3B, 0x0E, 0x1C, 0x00, 0x00, 0xE0, 0x00, 0x80, 0x03, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0xC0, 0x01, 0x38, 0x00, 0x0E, 0x38, 0xC0, 0x01, 0x1C, 0x00, 0x0E, 0x38, 0x00, 0x38, 0x0E, 0x38, 0x0E, 0x38, 0xC0, 0x01, 0x0E, 0x38, 0x00, 0x38, 0xC0, 0x01, 0xC0, 0x01, 0x00, 0x07, 0x00, 0x00, 0xE0, 0x00, 0xC0, 0x01, 0x0E, 0x00, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x1C, 0x0E, 0x00, 0x0E, 0x00, 0x0E, 0x38, 0x0E, 0x38, 0xC0, 0x01, 0x0E, 0x1C, 0x0E, 0x0E, 0x0E, 0x00, 0x0E, 0x70, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x00, 0xCE, 0x39, 0x0E, 0x07, 0x0E, 0x38, 0xC0, 0x01, 0x0E, 0x38, 0x70, 0x07, 0x3E, 0x7C, 0x1C, 0x1C, 0xC0, 0x01, 0x0E, 0x00, 0x70, 0x00, 0x00, 0x1C, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x00, 0xC0, 0x01, 0x0E, 0x38, 0x0E, 0x38, 0xC0, 0x01, 0x00, 0x1C, 0x1C, 0x07, 0xC0, 0x01, 0xCE, 0x39, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x38, 0x0E, 0x00, 0x00, 0x38, 0xE0, 0x00, 0x0E, 0x38, 0x70, 0x07, 0xCE, 0x39, 0x1C, 0x1C, 0x0E, 0x38, 0x1C, 0x00, 0xE0, 0x00, 0xC0, 0x01, 0xC0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x38, 0x0E, 0xFC, 0x1F, 0xB8, 0x3B, 0x1E, 0x3E, 0x00, 0x00, 0xC0, 0x01, 0xC0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0xC0, 0x01, 0x38, 0x00, 0x1E, 0x3C, 0xC0, 0x01, 0x0E, 0x00, 0x1E, 0x3C, 0x00, 0x38, 0x1E, 0x38, 0x1E, 0x3C, 0xC0, 0x01, 0x1E, 0x3C, 0x00, 0x3C, 0xC0, 0x01, 0xC0, 0x01, 0x00, 0x0E, 0x00, 0x00, 0x70, 0x00, 0xC0, 0x01, 0x1E, 0x00, 0x0E, 0x38, 0x0E, 0x3C, 0x1E, 0x3C, 0x0E, 0x1E, 0x0E, 0x00, 0x0E, 0x00, 0x1E, 0x3C, 0x0E, 0x38, 0xC0, 0x01, 0x1E, 0x1E, 0x0E, 0x1C, 0x0E, 0x00, 0x0E, 0x70, 0x0E, 0x38, 0x1E, 0x3C, 0x0E, 0x00, 0x9E, 0x3F, 0x0E, 0x0E, 0x1E, 0x3C, 0xC0, 0x01, 0x1E, 0x3C, 0xE0, 0x03, 0x1E, 0x78, 0x1C, 0x1C, 0xC0, 0x01, 0x0E, 0x00, 0x70, 0x00, 0x00, 0x1C, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x38, 0x0E, 0x3C, 0x1E, 0x3C, 0x1E, 0x38, 0x1E, 0x38, 0xC0, 0x01, 0x1E, 0x38, 0x0E, 0x38, 0xC0, 0x01, 0x00, 0x1C, 0x1C, 0x0E, 0xC0, 0x01, 0xCE, 0x39, 0x0E, 0x38, 0x1E, 0x3C, 0x0E, 0x3C, 0x1E, 0x38, 0x0E, 0x00, 0x1E, 0x3C, 0xE0, 0x01, 0x1E, 0x38, 0xE0, 0x03, 0xDE, 0x3D, 0x0E, 0x38, 0x1E, 0x38, 0x0E, 0x00, 0xE0, 0x01, 0xC0, 0x01, 0xE0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x38, 0x0E, 0xF8, 0x0F, 0x9C, 0x3F, 0xFC, 0x77, 0x00, 0x00, 0x80, 0x03, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0xC0, 0x01, 0x1C, 0x00, 0xFC, 0x1F, 0xF8, 0x0F, 0xFE, 0x3F, 0xFC, 0x1F, 0x00, 0x38, 0xFC, 0x1F, 0xFC, 0x1F, 0xC0, 0x01, 0xFC, 0x1F, 0xFC, 0x1F, 0xC0, 0x01, 0xC0, 0x01, 0x00, 0x1C, 0x00, 0x00, 0x38, 0x00, 0xC0, 0x01, 0xFC, 0x7F, 0x0E, 0x38, 0xFE, 0x1F, 0xFC, 0x1F, 0xFE, 0x0F, 0xFE, 0x3F, 0x0E, 0x00, 0xFC, 0x1F, 0x0E, 0x38, 0xF0, 0x07, 0xFC, 0x0F, 0x0E, 0x38, 0xFE, 0x3F, 0x0E, 0x70, 0x0E, 0x38, 0xFC, 0x1F, 0x0E, 0x00, 0xFC, 0x1F, 0x0E, 0x1C, 0xFC, 0x1F, 0xC0, 0x01, 0xFC, 0x1F, 0xE0, 0x03, 0x0E, 0x70, 0x0E, 0x38, 0xC0, 0x01, 0xFE, 0x3F, 0xF0, 0x0F, 0x00, 0x38, 0xF0, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x3F, 0xFE, 0x1F, 0xFC, 0x1F, 0xFC, 0x3F, 0xFC, 0x3F, 0xC0, 0x01, 0xFC, 0x3F, 0x0E, 0x38, 0xF0, 0x07, 0x00, 0x1C, 0x1C, 0x1C, 0xF0, 0x07, 0xCE, 0x39, 0x0E, 0x38, 0xFC, 0x1F, 0xFE, 0x1F, 0xFC, 0x3F, 0x0E, 0x00, 0xFC, 0x1F, 0xC0, 0x3F, 0xFC, 0x3F, 0xE0, 0x03, 0xFC, 0x1F, 0x0E, 0x38, 0xFC, 0x3F, 0xFE, 0x3F, 0xC0, 0x0F, 0xC0, 0x01, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x38, 0x0E, 0xC0, 0x01, 0x1C, 0x1F, 0xF8, 0x73, 0x00, 0x00, 0x00, 0x07, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0xC0, 0x01, 0x1C, 0x00, 0xF8, 0x0F, 0xF8, 0x0F, 0xFE, 0x3F, 0xF8, 0x0F, 0x00, 0x38, 0xF8, 0x0F, 0xF8, 0x0F, 0xC0, 0x01, 0xF8, 0x0F, 0xFC, 0x0F, 0xC0, 0x01, 0xC0, 0x01, 0x00, 0x38, 0x00, 0x00, 0x1C, 0x00, 0xC0, 0x01, 0xF8, 0x7F, 0x0E, 0x38, 0xFE, 0x0F, 0xF8, 0x0F, 0xFE, 0x03, 0xFE, 0x3F, 0x0E, 0x00, 0xF8, 0x0F, 0x0E, 0x38, 0xF0, 0x07, 0xF8, 0x07, 0x0E, 0x30, 0xFE, 0x3F, 0x0E, 0x70, 0x0E, 0x38, 0xF8, 0x0F, 0x0E, 0x00, 0xF8, 0x0F, 0x0E, 0x38, 0xF8, 0x0F, 0xC0, 0x01, 0xF8, 0x0F, 0xE0, 0x03, 0x0E, 0x70, 0x0E, 0x38, 0xC0, 0x01, 0xFE, 0x3F, 0xF0, 0x0F, 0x00, 0x38, 0xF0, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x3F, 0xFE, 0x0F, 0xF8, 0x0F, 0xF8, 0x3F, 0xF8, 0x1F, 0xC0, 0x01, 0xF8, 0x3F, 0x0E, 0x38, 0xF0, 0x07, 0x00, 0x1C, 0x1C, 0x38, 0xF0, 0x07, 0xCE, 0x39, 0x0E, 0x38, 0xF8, 0x0F, 0xFE, 0x0F, 0xF8, 0x3F, 0x0E, 0x00, 0xF8, 0x0F, 0x80, 0x3F, 0xF8, 0x3F, 0xE0, 0x03, 0xF8, 0x0F, 0x0E, 0x38, 0xF8, 0x3F, 0xFE, 0x3F, 0x80, 0x0F, 0xC0, 0x01, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; namespace netgen { class Font { // opengl display list index (-1 if not initialized) int list_base; // width and height of font in pixels int w; int h; // raw data to draw for opengl unsigned char *char_bitmaps; // size of one character in bitmap (in bytes) int char_length; int char_w; int char_h; // first and last+1 character in bitmap font static constexpr char char_first = ' '; static constexpr char char_next = '~'+1; void setBit( char c, int x, int y) { unsigned char *cbits = getCharBitmap(c); int offset = x/8+(h-1-y)*char_w; int bit_nr = 7-x%8; cbits[offset] |= 1UL<-1) glDeleteLists(list_base, char_next-char_first); delete[] char_bitmaps; } unsigned char *getCharBitmap(char c) { return char_bitmaps + (c-char_first)*char_length; } int getDisplayListsBase() { // already initialized if(list_base>-1) return list_base; list_base = glGenLists(char_next-char_first) - char_first; for (char c=char_first; c #include #include #include using std::string; using std::endl; using std::cout; using std::cerr; namespace netgen { NGCORE_API_EXPORT Flags parameters; } NGCORE_API_EXPORT bool nodisplay = false; extern "C" int Ng_Init (Tcl_Interp * interp); extern "C" int Ng_Vis_Init (Tcl_Interp * interp); extern "C" void Ng_TclCmd(string); // tcl package dynamic load extern "C" int NGCORE_API_EXPORT Gui_Init (Tcl_Interp * interp) { Tcl_InitStubs( interp, TCL_VERSION, 0 ); Tk_InitStubs( interp, TK_VERSION, 0 ); if (Ng_Init(interp) == TCL_ERROR) { cerr << "Problem in Ng_Init: " << endl; cout << "result = " << Tcl_GetStringResult (interp) << endl; return TCL_ERROR; } if (!nodisplay && Ng_Vis_Init(interp) == TCL_ERROR) { cerr << "Problem in Ng_Vis_Init: " << endl; cout << "result = " << Tcl_GetStringResult (interp) << endl; return TCL_ERROR; } return TCL_OK; } ================================================ FILE: ng/menustat.tcl ================================================ if { $tcl_platform(os) eq "Linux" && [tk scaling] > 1.5 } { # On some Linux systems, the scaling setting is only applied after # overwriting some default font settings. # This is a workaround to scale up fonts on high resolution displays. font create ngFont -family Helvetica option add *font ngFont ttk::style configure "." -font ngFont } # netgen menus: menu .ngmenu -tearoff 0 -relief raised -bd 2 . configure -menu .ngmenu .ngmenu add cascade -label "File" -menu .ngmenu.file -underline 0 .ngmenu add cascade -label "Geometry" -menu .ngmenu.geometry -underline 0 .ngmenu add cascade -label "Mesh" -menu .ngmenu.mesh -underline 0 .ngmenu add cascade -label "View" -menu .ngmenu.view -underline 0 .ngmenu add cascade -label "Refinement" -menu .ngmenu.meshsize -underline 5 if { $userlevel == 3} { .ngmenu add cascade -label "Special" -menu .ngmenu.special -underline 3 } .ngmenu add cascade -label "Help" -menu .ngmenu.help -underline 0 ##################################################### # # # Menu File # # # ##################################################### menu .ngmenu.file .ngmenu.file add command -label "Load Geometry..." -accelerator "" \ -command { set types { {"All Geometry types" { .stl .stlb .step .stp .geo .in2d .igs .iges .brep .sat} } {"IGES Geometry" {.igs .iges} } {"BREP OpenCascade Geometry" {.brep} } {"STL Geometry" {.stl} } {"Binary STL Geometry" {.stlb} } {"STEP Geometry" {.step .stp} } {"Geometry file" {.geo} } {"2D Geometry" {.in2d } } } set ACISavailable [Ng_ACISCommand isACISavailable] if {$ACISavailable == "yes" } { lappend types {"ACIS Geometry" {.sat} } } if {[catch { set file [tk_getOpenFile -filetypes $types -initialdir $dirname -typevariable loadgeomtypevar] }]} { set file [tk_getOpenFile -filetypes $types -initialdir $dirname] } if {$file != ""} { AddRecentFile $file Ng_LoadGeometry $file Ng_ParseGeometry # if { [Ng_STLInfo status]=="ERROR" } { # tk_messageBox -message "STL ERROR: \n [Ng_STLInfo statustext]" -type ok # } set selectvisual geometry Ng_SetVisParameters redraw wm title . [concat "$progname - " $file] set dirname [file dirname $file] set basefilename [file tail [file rootname $file]] if { $hasocc == "yes" } { rebuildoccdialog } } } .ngmenu.file add command -label "Save Geometry..." \ -command { set occgeometryloaded [Ng_OCCCommand isoccgeometryloaded] puts $occgeometryloaded if {$occgeometryloaded == 1 } { set types { {"IGES Geometry file" {.igs} } {"STEP Geometry file" {.stp} } {"STL Geometry file" {.stl} } {"STL BIN Geometry file" {.stlb} } } } { set types { {"STL Geometry file" {.stl} } {"STL BIN Geometry file" {.stlb} } } } set ACISavailable [Ng_ACISCommand isACISavailable] puts $ACISavailable if {$ACISavailable == "yes" } { lappend types {"ACIS Geometry" {.sat} } } set file [tk_getSaveFile -filetypes $types -initialdir $dirname -initialfile $basefilename ] if {$file != ""} { Ng_SaveGeometry $file } } .ngmenu.file add cascade -label "Recent Files" -menu .ngmenu.file.recent menu .ngmenu.file.recent -tearoff 0 proc AddRecentFile { filename } { global progname global dirname catch { [.ngmenu.file.recent delete $filename] } .ngmenu.file.recent insert 0 command -label $filename \ -command "AddRecentFile {$filename}; Ng_LoadGeometry {$filename}; Ng_ParseGeometry; set selectvisual geometry; Ng_SetVisParameters; redraw; wm title . [concat \" $progname - $filename \"]; set dirname {[file dirname $filename]}; set basefilename {[file tail [file rootname $filename]]}; rebuildoccdialog;" if { [.ngmenu.file.recent index last] >= 6 } { .ngmenu.file.recent delete last } saveinifile; } loadinifile; .ngmenu.file add separator .ngmenu.file add command -label "Load Mesh..." -accelerator "" \ -command { set types { {"Mesh file" {.vol .vol.gz} } } set file [tk_getOpenFile -filetypes $types -defaultextension ".vol"] if {$file != ""} { AddRecentMeshFile $file; Ng_LoadMesh $file; set selectvisual mesh Ng_SetVisParameters redraw Ng_ReadStatus; # Ng_MeshSizeFromSurfaceMesh wm title . [concat "$progname - " $file] set dirname [file dirname $file] set basefilename [file tail [file rootname $file]] } } # astrid .ngmenu.file add cascade -label "Recent Meshes" -menu .ngmenu.file.recentmesh menu .ngmenu.file.recentmesh proc AddRecentMeshFile { filename } { global progname global dirname catch { [.ngmenu.file.recentmesh delete $filename] } .ngmenu.file.recentmesh insert 0 command -label $filename \ -command "AddRecentMeshFile {$filename}; Ng_LoadMesh {$filename}; set selectvisual mesh; Ng_SetVisParameters; redraw; wm title . [concat \" $progname - $filename \"]; set dirname {[file dirname $filename]}; set basefilename {[file tail [file rootname $filename]]}; rebuildoccdialog;" if { [.ngmenu.file.recentmesh index last] >= 6 } { .ngmenu.file.recentmesh delete last } savemeshinifile; } loadmeshinifile; # astrid end .ngmenu.file add command -label "Save Mesh..." -accelerator "" \ -command { set types { {"Mesh file" {.vol .vol.gz} } } set file [tk_getSaveFile -filetypes $types -defaultextension ".vol.gz" -initialfile $basefilename -initialdir $dirname ] if {$file != ""} { Ng_SaveMesh $file } AddRecentMeshFile $file; } .ngmenu.file add command -label "Merge Mesh..." \ -command { set types { {"Mesh file" {.vol} } } set file [tk_getOpenFile -filetypes $types -defaultextension ".vol"] if {$file != ""} { Ng_MergeMesh $file; set selectvisual mesh Ng_SetVisParameters redraw Ng_ReadStatus; } } set meshimportformats [Ng_GetImportFormats] .ngmenu.file add command -label "Import Mesh..." \ -command { foreach importformat $meshimportformats { if { [lindex $importformat 0] == $importfiletype } { set extension [lindex $importformat 1] } } set types { {"Neutral format" {.mesh .emt} } {"Surface mesh format" {.surf} } {"Universal format" {.unv} } {"Olaf format" {.emt} } {"TET format" {.tet} } {"STL format" {.stl .stlb} } {"Pro/ENGINEER neutral format" {.fnf} } {"CFD General Notation System" {.cgns} } } set file [tk_getOpenFile -filetypes $meshimportformats -typevariable importfiletype] if {$file != ""} { Ng_ImportMesh $file $importfiletype set selectvisual mesh Ng_SetVisParameters redraw Ng_ReadStatus; } } set meshexportformats [Ng_GetExportFormats] .ngmenu.file add command -label "Export Mesh..." \ -command { # global meshexportformats foreach exportformat $meshexportformats { if { [lindex $exportformat 0] == $exportfiletype } { set extension [lindex $exportformat 1] } } if { $exportfiletype == "Elmer Format"} { set file [file nativename [tk_chooseDirectory -title "Elmer Mesh Export - Select Directory"]] } elseif { $exportfiletype == "OpenFOAM 1.5+ Format"} { set file [file nativename [tk_chooseDirectory -title "OpenFOAM 1.5+ Mesh Export - Select Case Directory"]] } elseif { $exportfiletype == "OpenFOAM 1.5+ Compressed"} { set file [file nativename [tk_chooseDirectory -title "OpenFOAM 1.5+ Mesh Export - Select Case Directory"]] } else { # set file [tk_getSaveFile -filetypes "{ \"$exportfiletype\" {$extension} }" ] # set file [tk_getSaveFile -filetypes "{ \"$exportfiletype\" {*}}" ] set file [tk_getSaveFile -filetypes $meshexportformats -typevariable exportfiletype] puts "type = $exportfiletype" puts "filename = $file" } if {$file != ""} { Ng_ExportMesh $file $exportfiletype } } .ngmenu.file add cascade -label "Export Filetype" -menu .ngmenu.file.filetype menu .ngmenu.file.filetype foreach exportformat $meshexportformats { .ngmenu.file.filetype add radio -label [lindex $exportformat 0] -variable exportfiletype -command { .ngmenu.file invoke "Export Mesh..." } } .ngmenu.file add separator .ngmenu.file add command -label "Save Solution..." \ -command { set types { {"Solution File" {.sol} } {"VTK File" {.vtk} } } set file [tk_getSaveFile -filetypes $types ] if {$file != ""} { Ng_SaveSolution $file } } #-defaultextension ".sol" ] .ngmenu.file add command -label "Import Solution..." \ -command { set types { {"Solution File" {.sol} } } set file [tk_getOpenFile -filetypes $types -defaultextension ".sol" ] if {$file != ""} { Ng_ImportSolution $file set selectvisual solution Ng_SetVisParameters redraw } } set demostarttime [clock clicks -millisecond] set stopdemo 0 proc demoredraw { } { global demostarttime global stopdemo set curtime [clock clicks -millisecond] set result [ Ng_DemoSetTime [expr $curtime - $demostarttime] ] redraw global videoactive if { $videoactive == 1 } { puts "addframe" Ng_VideoClip .ndraw addframe } if { $result == 0 && $stopdemo == 0 } { after 1 { demoredraw } } } .ngmenu.file add command -label "Show Demo..." \ -command { set types { {"Demo File" {.dem} } } set file [tk_getOpenFile -filetypes $types -defaultextension ".dem" ] if {$file != ""} { Ng_ShowDemo $file set demostarttime [clock clicks -millisecond] set stopdemo 0 demoredraw } } .ngmenu.file add separator .ngmenu.file add command -label "Snapshot..." \ -command { set types { {"JPG file" {.jpg} } {"GIF file" {.gif} } {"PPM file" {.ppm} } } set file [tk_getSaveFile -filetypes $types] # -defaultextension ".ppm"] if {$file != ""} { Ng_SnapShot .ndraw $file } } .ngmenu.file add cascade -label "Video clip" -menu .ngmenu.file.video menu .ngmenu.file.video set videoactive 0 .ngmenu.file.video add command -label "start..." \ -command { set types { {"MPG file" {.mpg} } } set file [tk_getSaveFile -filetypes $types] if {$file != ""} { Ng_VideoClip .ndraw init $file global videoactive set videoactive 1 } } .ngmenu.file.video add command -label "add frame..." \ -command {Ng_VideoClip .ndraw addframe } .ngmenu.file.video add command -label "one cycle" \ -command { set visoptions.redrawperiodic 1 for { set j 0 } { $j < 100 } { incr j } { puts "j = $j" Ng_Vis_Set time [expr (1000 * $j / 100)] redraw Ng_VideoClip .ndraw addframe after 200 } } .ngmenu.file.video add command -label "finalize..." \ -command { Ng_VideoClip .ndraw finalize global videoactive set videoactive 0 } .ngmenu.file add command -label "Save Options" \ -command { saveoptions } .ngmenu.file add separator ## herbert tcl load menu # .ngmenu.file add command -label "Run tests ..." \ \# -command { runtestdialog } ## # .ngmenu.file add separator .ngmenu.file add command -label "Quit" -accelerator "" \ -command { puts "Thank you for using $progname"; if { [catch { unload libngsolve[info sharedlibextension] ngsolve } result ] } { # puts "cannot unload ngsolve" # puts "error: $result" } after cancel { timer2 } Ng_Exit; destroy . } # exit ##################################################### # # # Menu Mesh # # # ##################################################### menu .ngmenu.mesh .ngmenu.mesh add command -label "Generate Mesh" -accelerator "" \ -command { set selectvisual mesh Ng_SetVisParameters Ng_GenerateMesh ${meshoptions.firststep} ${meshoptions.laststep} Ng_ReadStatus redraw } .ngmenu.mesh add command -label "Stop Meshing" \ -command { Ng_StopMeshing } .ngmenu.mesh add command -label "Meshing Options..." \ -command meshingoptionsdialog .ngmenu.mesh add separator .ngmenu.mesh add command -label "Delete Mesh" \ -command { Ng_New mesh; Ng_ReadStatus; redraw } .ngmenu.mesh add command -label "Delete Vol Mesh" \ -command { Ng_DeleteVolMesh; Ng_ReadStatus; redraw } .ngmenu.mesh add command -label "Mesh Info" \ -command { set dim [Ng_MeshInfo dim] set np [Ng_MeshInfo np] set ne [Ng_MeshInfo ne] set nse [Ng_MeshInfo nse] set nseg [Ng_MeshInfo nseg] set bbox [Ng_MeshInfo bbox] tk_messageBox -message "Dimension: $dim\nPoints: $np\nElements: $ne\nSurface Els: $nse\nSegments: $nseg\nxmin [lindex $bbox 0] xmax [lindex $bbox 1]\nymin [lindex $bbox 2] ymax [lindex $bbox 3]\nzmin [lindex $bbox 4] zmax [lindex $bbox 5]" } .ngmenu.mesh add command -label "Mesh Quality" \ -command { set inplanemin 0 set inplanemax 0 set betplanemin 0 set betplanemax 0 Ng_MeshQuality inplanemin inplanemax betplanemin betplanemax puts "Triangle angles : $inplanemin - $inplanemax" puts "Tet angles : $betplanemin - $betplanemax" tk_messageBox -message "Triangle angles : $inplanemin - $inplanemax \n Tet angles : $betplanemin - $betplanemax" } # .ngmenu.mesh add command -label "Quality Plot" \ # -command { qualityviewdialog 1 } .ngmenu.mesh add command -label "Check Surface Mesh" \ -command { Ng_CheckSurfaceMesh } .ngmenu.mesh add command -label "Check Volume Mesh" \ -command { Ng_CheckVolumeMesh } .ngmenu.mesh add command -label "Edit Boundary Conditions..." \ -command { bcpropdialog } if { $userlevel == 3 } { .ngmenu.mesh add command -label "Mesh Doctor..." \ -command { meshdoctordialog } } .ngmenu.mesh add command -label "METIS Mesh Partitioning..." \ -command { METISdialog } .ngmenu.mesh add separator .ngmenu.mesh add command -label "Analyze Geometry" \ -command { Ng_GenerateMesh ag ag; Ng_ReadStatus; redraw } .ngmenu.mesh add command -label "Mesh Edges" \ -command { Ng_GenerateMesh me me; Ng_ReadStatus; redraw } .ngmenu.mesh add command -label "Mesh Surface" \ -command { set selectvisual mesh; Ng_SetVisParameters; \ Ng_GenerateMesh ms ms; Ng_ReadStatus; redraw } .ngmenu.mesh add command -label "Optimize Surface" \ -command { Ng_GenerateMesh os os cmsmSm; redraw } .ngmenu.mesh add cascade -label "Surface Optim. Step" -menu .ngmenu.mesh.surfoptstep menu .ngmenu.mesh.surfoptstep .ngmenu.mesh.surfoptstep add command -label "Mesh Smoothing" \ -command { Ng_GenerateMesh os os m; redraw} .ngmenu.mesh.surfoptstep add command -label "Edge swapping (topologic)" \ -command { Ng_GenerateMesh os os s; redraw} .ngmenu.mesh.surfoptstep add command -label "Edge swapping (metric)" \ -command { Ng_GenerateMesh os os S; redraw} .ngmenu.mesh.surfoptstep add command -label "Combine points" \ -command { Ng_GenerateMesh os os c; redraw} .ngmenu.mesh add separator .ngmenu.mesh add command -label "Mesh Volume" \ -command { Ng_GenerateMesh mv mv; Ng_ReadStatus } .ngmenu.mesh add command -label "Optimize Volume" \ -command { Ng_GenerateMesh ov ov; Ng_ReadStatus } .ngmenu.mesh add command -label "Smooth Opt Volume" \ -command { Ng_GenerateMesh ov ov m; Ng_ReadStatus } .ngmenu.mesh add command -label "Smooth Opt Volume Jacobian" \ -command { Ng_GenerateMesh ov ov j; Ng_ReadStatus } ##################################################### # # # Menu Geometry # # # ##################################################### menu .ngmenu.geometry ##################################################### # # # Menu View # # # ##################################################### menu .ngmenu.view .ngmenu.view add command -label "Zoom all" \ -command { Ng_ZoomAll; redraw } .ngmenu.view add command -label "Center" \ -command { Ng_Center; redraw } .ngmenu.view add command -label "x-y plane" \ -command { Ng_StandardRotation xy; redraw } .ngmenu.view add command -label "y-x plane" \ -command { Ng_StandardRotation yx; redraw } .ngmenu.view add command -label "x-z plane" \ -command { Ng_StandardRotation xz; redraw } .ngmenu.view add command -label "z-x plane" \ -command { Ng_StandardRotation zx; redraw } .ngmenu.view add command -label "y-z plane" \ -command { Ng_StandardRotation yz; redraw } .ngmenu.view add command -label "z-y plane" \ -command { Ng_StandardRotation zy; redraw } .ngmenu.view add command -label "Viewing Options..." \ -command { viewingoptionsdialog; redraw } .ngmenu.view add command -label "Clipping Plane..." \ -command { clippingdialog; redraw } .ngmenu.view add command -label "Solution Data..." \ -command { visual_dialog; redraw } .ngmenu.view add checkbutton -variable viewqualityplot \ -label "Quality Plot" \ -command { qualityviewdialog $viewqualityplot } .ngmenu.view add checkbutton -variable memuseplot \ -label "Memory Usage" \ -command { memusedialog $memuseplot } ##################################################### # # # Menu Refinement # # # ##################################################### # # Mesh size menu # menu .ngmenu.meshsize .ngmenu.meshsize add command -label "Refine uniform" \ -command { Ng_Refine; Ng_HighOrder ${options.elementorder}; Ng_ReadStatus; redraw } .ngmenu.meshsize add command -label "Second Order" \ -command { Ng_SecondOrder; Ng_ReadStatus; redraw } .ngmenu.meshsize add command -label "Validate Second Order" \ -command { Ng_ValidateSecondOrder; Ng_ReadStatus; redraw } .ngmenu.meshsize add command -label "High Order" \ -command { Ng_HighOrder ${options.elementorder}; Ng_ReadStatus; redraw } .ngmenu.meshsize add separator .ngmenu.meshsize add command -label "Refinement Dialog..." \ -command { refinementdialog } .ngmenu.meshsize add command -label "Load Meshsize..." \ -command { set types { {"Meshsize file" {.msz} } } set file [tk_getOpenFile -filetypes $types] if {$file != ""} { Ng_LoadMeshSize $file; } } .ngmenu.meshsize add command -label "MS from Surf Mesh" \ -command { Ng_MeshSizeFromSurfaceMesh } if { $userlevel == 3 } { .ngmenu.meshsize add command -label "Singular point ms" \ -command { Ng_SingularPointMS; } .ngmenu.meshsize add command -label "Singular edge ms" \ -command { Ng_SingularEdgeMS; } .ngmenu.meshsize add separator set bisectfilename ""; .ngmenu.meshsize add command -label "Bisection" \ -command { Ng_ReadStatus; set oldnp 0; set newnp $status_np; # Ng_BisectCopyMesh; # Ng_Split2Tets; Ng_ReadStatus; while { $oldnp < $newnp } { # if { $level == 0 } { # Ng_ExportMesh feppmesh.vol fepp; # } { # Ng_ExportMesh feppmesh$level feppml # } set level [expr $level+1] if { $bisectfilename == ""} { Ng_Bisect; } else { Ng_Bisect $bisectfilename; } # Ng_HighOrder ${options.elementorder} "noparallel" # Ng_Split2Tets; Ng_ReadStatus; redraw; if { $bisectfilename == ""} { set oldnp $newnp; set newnp $status_np; puts "oldnp $oldnp newnp $newnp"; } else { set oldnp $newnp; } } } # -command { Ng_Bisect; Ng_ReadStatus; redraw } # -command { exec netgen abc >outfile 2>errfile; Ng_ReadStatus; redraw } } .ngmenu.meshsize add command -label "Load Refinement Info..." \ -command { set types { {"Refinement info" {.refine} }} set bisectfilename [tk_getOpenFile -filetypes $types] } .ngmenu.meshsize add command -label "Z-Refinement" \ -command { Ng_ZRefinement 2; Ng_ReadStatus; redraw } # .ngmenu.meshsize add command -label "hp-Refinement" \ \# -command { Ng_HPRefinement 4; Ng_ReadStatus; redraw } .ngmenu.meshsize add cascade -label "hp-Refinement" -menu .ngmenu.meshsize.hpref menu .ngmenu.meshsize.hpref .ngmenu.meshsize.hpref add command -label "1 Level" \ -command { Ng_HPRefinement 1; Ng_ReadStatus; redraw } .ngmenu.meshsize.hpref add command -label "2 Levels" \ -command { Ng_HPRefinement 2; Ng_ReadStatus; redraw } .ngmenu.meshsize.hpref add command -label "3 Levels" \ -command { Ng_HPRefinement 3; Ng_ReadStatus; redraw } .ngmenu.meshsize.hpref add command -label "4 Levels" \ -command { Ng_HPRefinement 4; Ng_ReadStatus; redraw } .ngmenu.meshsize.hpref add command -label "5 Levels" \ -command { Ng_HPRefinement 5; Ng_ReadStatus; redraw } .ngmenu.meshsize.hpref add command -label "6 Levels" \ -command { Ng_HPRefinement 6; Ng_ReadStatus; redraw } .ngmenu.meshsize.hpref add command -label "7 Levels" \ -command { Ng_HPRefinement 7; Ng_ReadStatus; redraw } .ngmenu.meshsize.hpref add command -label "8 Levels" \ -command { Ng_HPRefinement 8; Ng_ReadStatus; redraw } .ngmenu.meshsize.hpref add command -label "9 Levels" \ -command { Ng_HPRefinement 9; Ng_ReadStatus; redraw } .ngmenu.meshsize.hpref add command -label "10 Levels" \ -command { Ng_HPRefinement 10; Ng_ReadStatus; redraw } .ngmenu.meshsize add command -label "Split to Tets" \ -command { Ng_Split2Tets; Ng_ReadStatus; redraw } ##################################################### # # # Menu Special # # # ##################################################### menu .ngmenu.special .ngmenu.special add command -label "Prismatic Boundary Layer" \ -command { Ng_GenerateBoundaryLayer; redraw } .ngmenu.special add command -label "Insert virtual boundary layer" \ -command { Ng_InsertVirtualBL; redraw } .ngmenu.special add command -label "Cut off and combine with other" \ -command { set types { {"Mesh file" {.vol} } } set file [tk_getOpenFile -filetypes $types] if {$file != ""} { Ng_CutOffAndCombine $file; } redraw } .ngmenu.special add command -label "Helmholtz Mesh grading" \ -command { Ng_HelmholtzMesh; } .ngmenu.special add cascade -label "Colour-based boundary conditions" -menu .ngmenu.special.colbndcond menu .ngmenu.special.colbndcond .ngmenu.special.colbndcond add command -label "Inspect Colours in mesh" \ -command { currmeshcoloursdialog } .ngmenu.special.colbndcond add separator .ngmenu.special.colbndcond add command -label "Automatic Assignment" \ -command { Ng_AutoColourBcProps auto; redraw } .ngmenu.special.colbndcond add separator set ocffile [file join ${ngdir} netgen.ocf]; .ngmenu.special.colbndcond add command -label "Select Colour Profile file" \ -command { set types { {"Colour Profile file" {.ocf} } } set ocffile [tk_getOpenFile -filetypes $types] if {$ocffile == ""} { set ocffile [file join ${ngdir} netgen.ocf]; } } .ngmenu.special.colbndcond add command -label "Profile based Assignment" \ -command { Ng_AutoColourBcProps profile ${ocffile}; redraw } # menu .mbar.stl.menu # .mbar.stl.menu add command -label "STL options" \ # -command { stloptionsdialog; } #.mbar.stl.menu add command -label "STL Doctor" \ # -command { stldoctordialog; } ##################################################### # # # Menu Help # # # ##################################################### menu .ngmenu.help # .ngmenu.help add command -label "Ng Help..." \ \# -command { help_main } # .ngmenu.view add checkbutton -variable showsensitivehelp \ # -label "Sensitive Help" \ # -command { sensitivehelpdialog $showsensitivehelp } .ngmenu.view add checkbutton -label "Help Line" -variable showhelpline \ -command { if { $showhelpline == 1} { pack .helpline -before .statbar -side bottom -fill x -padx 3p } { pack forget .helpline } } .ngmenu.help add command -label "About..." \ -command { tk_messageBox -message "This is NETGEN \nmainly written by \nJoachim Schoeberl \nthanks to \nRobert Gaisbauer, Johannes Gerstmayr, Philippose Rajan" } # tk_menuBar .mbar .mbar.file .mbar.mesh .mbar.test .mbar.help # focus .mbar ##################################################### # # # Button bar # # # ##################################################### ttk::frame .bubar # -relief raised #-relief raised -bd 2 pack .bubar -side top -fill x ttk::button .bubar.testb -text "Test" -command { Ng_SaveGeometry } ttk::button .bubar.surfm -text "Generate Mesh" -command \ { .ngmenu.mesh invoke "Generate Mesh"; # set selectvisual mesh; # Ng_SetVisParameters; # Ng_GenerateMesh ${meshoptions.firststep} ${meshoptions.laststep} # redraw } ttk::button .bubar.stopm -text "Stop" -command \ { # Ng_StopMeshing; set multithread_terminate 1; set stopdemo 1; } ttk::button .bubar.exitb -text "Quit" \ -command { set ans [tk_messageBox -title "Quit Netgen?" -message "Do you really want to quit Netgen?" -type yesno -default "no" -icon question] if { $ans == "yes" } { .ngmenu.file invoke "Quit"; } } pack .bubar.exitb .bubar.surfm .bubar.stopm -side left #button .bubar.scan -text "Scan" \ # -command { Ng_ParseGeometry; set selectvisual geometry; Ng_SetVisParameters; redraw } ttk::button .bubar.zoomall -text "Zoom All" \ -command { Ng_ZoomAll; redraw } ttk::button .bubar.center -text "Center" \ -command { Ng_Center; redraw } # tk_optionMenu .bubar.modesel drawmode "rotate" "move " "zoom " # tixOptionMenu .bubar.modesel \ # -options { # label.width 0 # label.anchor e # menubutton.width 6 # } \ # -variable drawmode # .bubar.modesel add command rotate -label Rotate # .bubar.modesel add command move -label Move # .bubar.modesel add command zoom -label Zoom ttk::menubutton .bubar.modesel -menu .bubar.modesel.menu -text "" -width 6 menu .bubar.modesel.menu -tearoff 0 .bubar.modesel.menu add command -label "Rotate" -command "set drawmode \"rotate\" ;.bubar.modesel configure -text \"Rotate\"" .bubar.modesel.menu add command -label "Move" -command "set drawmode \"move\" ;.bubar.modesel configure -text \"Move\"" .bubar.modesel.menu add command -label "Zoom" -command "set drawmode \"zoom\" ;.bubar.modesel configure -text \"Zoom\"" .bubar.modesel.menu invoke "Rotate" set viewvals { geometry specpoints mesh solution} if { $userlevel == 3} { set viewvals { geometry mesh specpoints surfmeshing modelview solution} } set viewvallabs(cross) "Cross" set viewvallabs(geometry) "Geometry" set viewvallabs(mesh) "Mesh" set viewvallabs(specpoints) "Edges" set viewvallabs(surfmeshing) "Mesh Gen" set viewvallabs(modelview) "Modeller" set viewvallabs(solution) "Solution" # tixOptionMenu .bubar.selview \ # -options { # label.width 0 # label.anchor e # menubutton.width 10 # } \ # foreach viewv $viewvals { # .bubar.selview add command $viewv -label $viewvallabs($viewv) # } # .bubar.selview config -variable selectvisual # .bubar.selview config -command { Ng_SetVisParameters; redraw } # pack .bubar.modesel -side right # pack forget .bubar.modesel pack .bubar.center .bubar.zoomall -side right # pack .bubar.selview -side right .ngmenu.view add checkbutton -variable viewrotatebutton \ -label "Enable LeftButton Selection" \ -command { if { $viewrotatebutton } { pack .bubar.modesel -side right } { pack forget .bubar.modesel } } menu .bubar.selviewmenu ttk::menubutton .bubar.selview1 -menu .bubar.selviewmenu -text "Geometry" foreach viewv $viewvals { .bubar.selviewmenu add command -label $viewvallabs($viewv) -command \ ".bubar.selview1 configure -text \"$viewvallabs($viewv)\" ; set selectvisual $viewv ; Ng_SetVisParameters; redraw" } pack .bubar.selview1 -side right # .bubar.selviewmenu invoke $viewvallabs($selectvisual) trace add variable selectvisual write selvis_monitor proc selvis_monitor { name args } { global selectvisual viewvallabs .bubar.selviewmenu invoke $viewvallabs($selectvisual) } # set selectvisual solution ##################################################### # # # Status bar # # # ##################################################### ttk::label .helpline -text "None" pack forget .helpline -side bottom -fill x ttk::frame .statbar -relief flat # -bd 2 pack .statbar -side bottom -fill x ttk::label .statbar.ptslabel -text " Points: " ttk::label .statbar.ptsval -textvariable status_np ttk::label .statbar.elslabel -text " Elements: " ttk::label .statbar.elsval -textvariable status_ne ttk::label .statbar.selslabel -text " Surf Elements: " ttk::label .statbar.selsval -textvariable status_nse # label .statbar.memlabel -text " Mem: " # label .statbar.memval -textvariable mem_moveable ttk::label .statbar.task -textvariable status_task pack .statbar.ptslabel .statbar.ptsval -side left -ipady 3p pack .statbar.elslabel .statbar.elsval -side left -ipady 3p pack .statbar.selslabel .statbar.selsval -side left -ipady 3p # if { $userlevel == 3 } { # pack .statbar.memlabel .statbar.memval -side left -ipady 3p # } #tixMeter .statbar.per -value 0 -text 0% ttk::progressbar .statbar.per -value 0 -maximum 1 #.statbar.per configure -fillcolor blue pack .statbar.per -side right pack .statbar.task -side right -ipady 4 set qualbaraxis(0) 0 set qualbar(0) 0 set qualbarnull(0) 0 proc timer2 { } { global status_np global status_ne global status_nse global multithread_running global multithread_redraw global status_working global status_task global status_percent global status_tetqualclasses Ng_ReadStatus if { $multithread_redraw == 1 } { # non-blocking redraw set multithread_redraw 0; redraw; global videoactive if { $videoactive == 1 } { puts "addframe" Ng_VideoClip .ndraw addframe } } if { $multithread_redraw == 2 } { # blocking redraw redraw; set multithread_redraw 0; global videoactive if { $videoactive == 1 } { puts "addframe" Ng_VideoClip .ndraw addframe } after 1 { timer2 } return } # global mem_moveable # set mem_moveable [Ng_MemInfo moveable] .statbar.per configure -value [expr $status_percent/100] # -text [format %2.1f [expr 0.1*int(10*$status_percent)]]% if { $multithread_running } { pack .statbar.per -side right -before .statbar.task -padx 6 } { pack forget .statbar.per } # tet quality if {[winfo exists .qualityview_dlg] == 1} { global qualbar global qualbarnull global qualbaraxis set maxval 0 for {set i 0} {$i < 20} {incr i} { if {[lindex $status_tetqualclasses $i] > $maxval} { set maxval [lindex $status_tetqualclasses $i] } } set ubound 1 while { $ubound < $maxval } { set ubound [expr {10 * $ubound}] } if { $ubound/5 > $maxval } { set ubound [expr $ubound/5] } if { $ubound/2 > $maxval } { set ubound [expr $ubound/2] } for {set i 1} {$i <= 5} {incr i} { # global qualbaraxis($i) set value [expr { $i * $ubound / 5 }] .qualityview_dlg.c dchars $qualbaraxis($i) 0 end .qualityview_dlg.c insert $qualbaraxis($i) end $value } for {set i 0} {$i < 20} {incr i} { set x1 [expr {100 + ($i*15) + 2}] set x2 [expr {$x1+10}] set nbrs [lindex $status_tetqualclasses $i] set y [expr (249 - (200 * $nbrs / $ubound ) )] # global qualbar($i) .qualityview_dlg.c coords $qualbar($i) $x1 250 $x2 $y # global qualbarnull($i) if { $nbrs == 0 } { .qualityview_dlg.c itemconfigure $qualbarnull($i) -text 0 } { .qualityview_dlg.c itemconfigure $qualbarnull($i) -text "" } } } if {[winfo exists .memuse_dlg] == 1} { global memmark set usemb [Ng_MemInfo usedmb] for {set i 0} {$i < [string length $usemb] } {incr i} { if { [string index $usemb $i] == 0 } { .memuse_dlg.c coords $memmark($i) [expr 50+$i] 68 [expr 50+$i] 70 } { .memuse_dlg.c coords $memmark($i) [expr 50+$i] 50 [expr 50+$i] 70 } } } after 40 { timer2 } } # after 1000 { timer2 } timer2 proc bgerror { error } { global errorInfo userlevel if { $userlevel == 3} { puts "ERROR: $error" puts "errinfo: $errorInfo" } tk_messageBox -title "Error Message" -message $error -type ok } proc smh2 { menuitem } { if {[catch {$menuitem entrycget active -label} name]} { set name " " } show_menu_help $name update idletasks } bind .ngmenu <> { smh2 %W } bind .ngmenu.file <> { smh2 %W } bind .ngmenu.geometry <> { smh2 %W } bind .ngmenu.mesh <> { smh2 %W } bind .ngmenu.view <> { smh2 %W } bind .ngmenu.meshsize <> { smh2 %W } bind .ngmenu.special <> { smh2 %W } bind .ngmenu.help <> { smh2 %W } # command bindings bind . { .ngmenu.file invoke "Quit" } bind . { .ngmenu.file invoke "Load Geometry..." } ; bind . { .ngmenu.file invoke "Load Mesh..." } ; bind . { .ngmenu.file invoke "Save Mesh..." } ; bind . { .ngmenu.file activate "Recent Files" } ; bind .

{ newprimitivedialog } ; # bind .

{ editprimitivedialog } bind . { newsoliddialog } bind . { .ngmenu.mesh invoke "Generate Mesh" } ; ================================================ FILE: ng/netgen.ocf ================================================ # Netgen Mesher # Boundary Condition Colour Profile # # Name: netgen.ocf # # Description: Netgen default colour # profile file for colour based automatic # assignment of boundary condition numbers # # Format: # [boundary_colours] (mandatory keyword) # # # # .... # .... # NOTE: # * Currently, the default Boundary # Condition number assigned to faces without # any colour defined is "1" # * Boundary Condition number "0" is invalid, # and should not be used boundary_colours 7 2 0.0000 0.0000 0.0000 3 1.0000 0.0000 0.0000 4 0.0000 0.0000 1.0000 5 1.0000 1.0000 0.0000 6 0.0000 1.0000 1.0000 7 1.0000 0.0000 1.0000 8 1.0000 1.0000 1.0000 ================================================ FILE: ng/netgenpy.cpp ================================================ // a wrapper to load netgen-dll into python #include #include <../general/ngpython.hpp> #include void NGCORE_API_IMPORT ExportNetgenMeshing(py::module &m); void NGCORE_API_IMPORT ExportCSG(py::module &m); void NGCORE_API_IMPORT ExportGeom2d(py::module &m); void NGCORE_API_IMPORT ExportSTL(py::module &m); #ifdef OCCGEOMETRY void NGCORE_API_IMPORT ExportNgOCC(py::module &m); #endif // OCCGEOMETRY PYBIND11_MODULE(libngpy, ngpy) { py::module::import("pyngcore"); py::module meshing = ngpy.def_submodule("_meshing", "pybind meshing module"); ExportNetgenMeshing(meshing); py::module csg = ngpy.def_submodule("_csg", "pybind csg module"); ExportCSG(csg); py::module geom2d = ngpy.def_submodule("_geom2d", "pybind geom2d module"); ExportGeom2d(geom2d); py::module stl = ngpy.def_submodule("_stl", "pybind stl module"); ExportSTL(stl); #ifdef OCCGEOMETRY py::module NgOCC = ngpy.def_submodule("_NgOCC", "pybind NgOCC module"); ExportNgOCC(NgOCC); #endif // OCCGEOMETRY } ================================================ FILE: ng/ng.tcl ================================================ catch {lappend auto_path $env(NETGENDIR) } catch {lappend auto_path $env(NETGENDIR)/../lib } if {[catch {Ng_GetCommandLineParameter batchmode} result ]} { load libnggui[info sharedlibextension] gui } set batchmode [Ng_GetCommandLineParameter batchmode] if {$batchmode=="undefined"} { # if {[catch {package require Tix } result ]} { # puts "cannot load package Tix" # puts "error : $result" # } if {[catch {package require tkdnd } result ]} { # puts "cannot load package tkdnd" # puts "error : $result" } } # if {[catch {package require Togl 2.0 } result ]} { # puts "cannot load package Togl 2.0" # puts "error : $result" # } # load [file dirname [info script]]/gears[info sharedlibextension] # puts "load togl lib" # load /Users/joachim/tcl_native3/Togl2.1/libTogl2.1.dylib # puts "have togl lib" # if {[catch {package require Togl 2.0 } result ]} { # puts "cannot load package Togl 2.0" # puts "error : $result" # } # userlevel 1..standard user 2..power-user 3..developer set userlevel 3 if { [Ng_GetCommandLineParameter expert]=="defined" } { set userlevel 3 } set progname "NETGEN" set ngdir "" if { [lsearch [array names env] NETGENDIR] != -1 } { set ngdir $env(NETGENDIR) } if { [string length $ngdir] == 0 } { set ngdir "." } set nguserdir "" if { [lsearch [array names env] NETGEN_USER_DIR] != -1 } { set nguserdir $env(NETGEN_USER_DIR) } if { [string length $nguserdir] == 0 } { set nguserdir "." } set batchmode [Ng_GetCommandLineParameter batchmode] set solvemode 0 if { [Ng_GetCommandLineParameter solve] != "undefined" || \ [Ng_GetCommandLineParameter recent] == "defined" } { set solvemode defined } set shellmode [Ng_GetCommandLineParameter shellmode] if { $shellmode == "defined" } { set batchmode "defined" } if { $batchmode != "defined" } { catch { wm withdraw . wm title . $progname wm geometry . =850x600 wm minsize . 400 300 } } source ${ngdir}/variables.tcl source ${ngdir}/parameters.tcl if { $batchmode != "defined" } { catch { source ${ngdir}/menustat.tcl } } catch { source ${ngdir}/dialog.tcl } catch { source ${ngdir}/drawing.tcl } # if { [catch { load libgeom2dvis[info sharedlibextension] Ng_Geom2d } result ] } { # puts "cannot load 2d meshing module" # puts "error: $result" # } catch { source ${ngdir}/csgeom.tcl } catch { source ${ngdir}/stlgeom.tcl } set hasocc no catch { source ${ngdir}/occgeom.tcl } source ${ngdir}/acisgeom.tcl catch { source ${ngdir}/nghelp.tcl } catch { source ${ngdir}/ngvisual.tcl } catch { source ${ngdir}/sockets.tcl } catch { source ${ngdir}/acis.tcl } set zugstange 0 catch { source ${ngdir}/trafo/menu.tcl } setgranularity ${meshoptions.fineness} Ng_SetMeshingParameters Ng_SetVisParameters Ng_SetDebugParameters Ng_STLDoctor Ng_GeometryOptions set if { $hasocc == "yes" } { Ng_SetOCCVisParameters } if { $batchmode != "defined" } { catch { wm protocol . WM_DELETE_WINDOW { .ngmenu.file invoke "Quit" } wm deiconify . } } set trafoapp 0 catch { source ${ngdir}/trafoapp/trafoapp.tcl } set geofilename [Ng_GetCommandLineParameter geofile] if { $geofilename != "undefined" && [info exists trafo] == 0 && $zugstange == 0} { if { [ catch { Ng_LoadGeometry $geofilename } errstring] == 0 } { if { $batchmode != "defined" } { AddRecentFile $geofilename } Ng_ParseGeometry if { $batchmode != "defined" } { set selectvisual geometry Ng_SetVisParameters redraw wm title . [concat "$progname - " $geofilename] } set dirname [file dirname $geofilename] set basefilename [file tail [file rootname $geofilename]] } { puts "Problem with input file:" puts "$errstring" } } set cnt 0 foreach { gran } { verycoarse coarse moderate fine veryfine } { set cnt [expr $cnt + 1] if { [Ng_GetCommandLineParameter $gran] == "defined" } { set meshoptions.fineness $cnt setgranularity ${meshoptions.fineness} } } set meshfilename [Ng_GetCommandLineParameter meshfile] if { $meshfilename == "undefined" } { set meshfilename out.mesh } set meshfiletype [Ng_GetCommandLineParameter meshfiletype] if { $meshfiletype == "undefined" } { set meshfiletype netgen } set inputmeshfilename [Ng_GetCommandLineParameter inputmeshfile] set mergemeshfilename [Ng_GetCommandLineParameter mergefile] set meshsizefilename [Ng_GetCommandLineParameter meshsizefile] if { $meshsizefilename != "undefined" } { set options.meshsizefilename $meshsizefilename } set refinementfilename [Ng_GetCommandLineParameter refinementfile] if { $batchmode == "defined" && $solvemode != "defined"} { set options.parthread 0 if { $shellmode == "undefined" } { # old batchmode: only processes commandline arguments set selectvisual mesh Ng_SetVisParameters set meshsize [Ng_GetCommandLineParameter meshsize] if {$meshsize != "undefined"} { set options.meshsize $meshsize } if { $inputmeshfilename == "undefined" } { Ng_GenerateMesh ${meshoptions.firststep} ${meshoptions.laststep} } else { Ng_LoadMesh $inputmeshfilename if { $mergemeshfilename != "undefined" } { Ng_MergeMesh $mergemeshfilename } } if { $refinementfilename != "undefined" } { Ng_Bisect $refinementfilename } if { $meshfiletype == "netgen" } { Ng_SaveMesh $meshfilename } else { if { [catch { Ng_ExportMesh $meshfilename $meshfiletype } ] == 1 } { puts "Unknown file format $meshfiletype" } } Ng_Exit; exit } else { set code [catch { source ${ngdir}/ngshell.tcl } errcode] if {$code} { puts "error: $errcode" } set code [ catch {Ng_RunShell} errcode] if {$code} { puts "error: $errcode" } Ng_Exit; exit } } set stereo [Ng_GetCommandLineParameter stereo] if { $stereo == "defined" } { set viewoptions.stereo 1 puts "use stereo mode" Ng_SetVisParameters; redraw } set ngsolve_loaded 0 catch { source ${ngdir}/ngsolve.tcl; set ngsolve_loaded 1 } # try to find ngsolve.tcl in PATH set pathlist [split $::env(PATH) \ [expr {$::tcl_platform(platform) == "windows" ? ";" : ":"}]] foreach dir $pathlist { if { $ngsolve_loaded != 1 } { catch { source ${dir}/ngsolve.tcl set ngsolve_loaded 1 } } } set scriptfilename [Ng_GetCommandLineParameter script] if { $scriptfilename != "undefined" } { if { [catch { source $scriptfilename } errstring] == 1 } { puts "Error in input: $errstring" } } if { [Ng_GetCommandLineParameter help]=="defined" } { if { $zugstange == 1 } { print_zug_commandline_help exit; } { if { $trafoapp == 1 } { print_trafo_commandline_help; } { print_commandline_help; Ng_Exit; exit } } } if { [file exists startup.tcl] } { source startup.tcl } catch { source ${ngdir}/demoapp.tcl } catch { source ${ngdir}/dropsexp.tcl } ================================================ FILE: ng/ng_acis.hpp ================================================ #include #ifdef ACIS_R17 extern void unlock_spatial_products_661(); #endif namespace netgen { ACISGeometry * acisgeometry = NULL; static VisualSceneACISGeometry vsacisgeom; extern int ACISGenerateMesh (ACISGeometry & geometry, Mesh*& mesh, int perfstepsstart, int perfstepsend, char* optstring); int Ng_ACISCommand (ClientData /* clientData */, Tcl_Interp * interp, int argc, tcl_const char *argv[]) { if (argc >= 2) { if (strcmp (argv[1], "isACISavailable") == 0) { Tcl_SetResult (interp, (char*)"yes", TCL_STATIC); return TCL_OK; } } if (!acisgeometry) { Tcl_SetResult (interp, (char*)"This operation needs an ACIS geometry", TCL_STATIC); return TCL_ERROR; } if (argc >= 2 && strcmp (argv[1], "getentities") == 0) { stringstream str; const ENTITY_LIST & entlist = acisgeometry -> entlist; ENTITY_LIST cellList; api_ct_get_all_cells( entlist, cellList ); for(int j=0; jattrib(); int k = 0; while (ap) { ATTRIB_GEN_INTEGER * aip = dynamic_cast(ap); if (aip) str << "cell" << j << "/attrib" << k << " { name = " << aip->name() << " val = " << aip->value() << "} \n"; else str << "cell" << j << "/attrib" << k << " { typename = " << ap->type_name() << "} \n"; ap = ap->next(); k++; } } for (int i = 0; i < entlist.count(); i++) { str << "entity" << i << " {Entity " << i << "} \n"; ENTITY_LIST faceList; ENTITY_LIST edgeList; api_get_faces_from_all_entities(entlist[i], faceList); for(int j=0; jattrib(); int k = 0; while (ap) { ATTRIB_GEN_INTEGER * aip = dynamic_cast(ap); if (aip) str << "entity" << i << "/face" << j << "/attrib" << k << " { name = " << aip->name() << " val = " << aip->value() << "} \n"; else str << "entity" << i << "/face" << j << "/attrib" << k << " { typename = " << ap->type_name() << "} \n"; ap = ap->next(); k++; } SPAbox * box = face->bound(); str << "entity" << i << "/face" << j << "/bbox" << " { BBox (" << box->low().x() << ", " << box->low().y() << ", " << box->low().z() << ";" << box->high().x() << ", " << box->high().y() << ", " << box->high().z() << ")" << " }\n"; } api_get_edges_from_all_entities(entlist[i], edgeList); for(int j=0; j= 2 && strcmp (argv[1], "selectentity") == 0) { int ientry = -1, iface = -1; string select = argv[2]; cout << "ACIS selectentity: " << select << endl; int pos_ent1 = select.find("entity", 0); int pos_ent2 = select.find("/", pos_ent1); if (pos_ent1 != -1 && pos_ent2 == -1) pos_ent2 = select.length(); if (pos_ent1 != -1) ientry = atoi (select.substr(pos_ent1+6, pos_ent2).c_str()); int pos_face1 = select.find("face", 0); int pos_face2 = select.find("/", pos_face1); if (pos_face1 != -1 && pos_face2 == -1) pos_face2 = select.length(); if (pos_face1 != -1) iface = atoi (select.substr(pos_face1+4, pos_face2).c_str()); cout << "entry = " << ientry << ", face = " << iface << endl; const ENTITY_LIST & entlist = acisgeometry -> entlist; if (ientry != -1 && iface == -1) vsacisgeom.SelectEntity (entlist[ientry]); if (iface != -1) { ENTITY_LIST faceList; api_get_faces_from_all_entities(entlist[ientry], faceList); vsacisgeom.SelectEntity (faceList[iface]); } } if (argc >= 2 && strcmp (argv[1], "createct") == 0) { acisgeometry -> CreateCT(); } if (argc >= 2 && strcmp (argv[1], "combineall") == 0) { cout << "combineall " << endl; acisgeometry -> Combine(); } if (argc >= 4) { if (strcmp (argv[1], "subtract") == 0) { cout << "subtract " << argv[2] << " minus " << argv[3] << endl; acisgeometry -> Subtract (atoi (argv[2])-1, atoi (argv[3])-1); } } return TCL_OK; } } ================================================ FILE: ng/ngappinit.cpp ================================================ /* The main function of netgen. This file is a modification of tkAppInit.c from the Tcl/Tk package */ #undef USE_TCL_STUBS #undef USE_TK_STUBS #include #include #include #include #include "../libsrc/interface/writeuser.hpp" #ifdef NETGEN_PYTHON #include #endif namespace netgen { DLL_HEADER extern Flags parameters; DLL_HEADER extern bool netgen_executable_started; } DLL_HEADER extern bool nodisplay; using netgen::parameters; using netgen::ngdir; using netgen::verbose; using netgen::NgArray; using netgen::RegisterUserFormats; using std::string; using std::endl; using std::cout; using std::cerr; using std::ofstream; /* * The following variable is a special hack that is needed in order for * Sun shared libraries to be used for Tcl. */ // extern "C" int matherr(); // int *tclDummyMathPtr = (int *) matherr; extern "C" int Ng_ServerSocketManagerInit (int port); extern "C" int Ng_ServerSocketManagerRun (void); bool shellmode = false; /* * * The Netgen main function * */ int main(int argc, char ** argv) { netgen::netgen_executable_started = true; if ( netgen::id == 0 ) { cout << "NETGEN-" << netgen::netgen_version << endl; cout << "Developed by Joachim Schoeberl at" << endl << "2010-xxxx Vienna University of Technology" << endl << "2006-2010 RWTH Aachen University" << endl << "1996-2006 Johannes Kepler University Linz" << endl; #ifdef OCCGEOMETRY cout << "Including OpenCascade geometry kernel" << endl; #endif #ifdef ACIS cout << "Including ACIS geometry kernel" << endl; #endif #ifdef LINUX //feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW); //feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW); //cout << "Handle Floating Point Exceptions: " << fegetexcept() << endl; #endif #ifdef DEBUG cout << "You are running the debug version !" << endl; #endif } netgen::h_argc = argc; netgen::h_argv = argv; // command line arguments: for (int i = 1; i < argc; i++) { if (argv[i][0] == '-') parameters.SetCommandLineFlag (argv[i]); else { if (strstr(argv[i], ".py")) parameters.SetFlag ("py", argv[i]); else parameters.SetFlag ("geofile", argv[i]); } } if (getenv ("NETGENDIR") && strlen (getenv ("NETGENDIR"))) ngdir = getenv ("NETGENDIR"); else ngdir = "."; verbose = parameters.GetDefineFlag ("V"); if (verbose) cout << "NETGENDIR = " << ngdir << endl; if ( netgen::id == 0 ) { if (parameters.StringFlagDefined ("testout")) { delete ngcore::testout; ngcore::testout = new ofstream (parameters.GetStringFlag ("testout", "test.out")); } #ifdef SOCKETS Ng_ServerSocketManagerInit(static_cast(parameters.GetNumFlag("serversocket",-1))); if(parameters.GetNumFlag("serversocket",-1) > 0 && !parameters.GetDefineFlag("display")) nodisplay = true; #endif if(parameters.GetDefineFlag("batchmode")) nodisplay = true; if(parameters.GetDefineFlag("shellmode")) { nodisplay = true; shellmode = true; } Tcl_FindExecutable(NULL); // initialize application Tcl_Interp * myinterp = Tcl_CreateInterp (); if (Tcl_AppInit (myinterp) == TCL_ERROR) { cerr << "Exit Netgen due to initialization problem" << endl; exit (1); } // parse tcl-script int errcode; bool internaltcl = INTERNAL_TCL_DEFAULT; if (shellmode) internaltcl = false; if (verbose) { cout << "Tcl header version = " << TCL_PATCH_LEVEL << endl; Tcl_Eval (myinterp, "puts \"Tcl runtime version = [info patchlevel] \";"); } if (parameters.GetDefineFlag ("internaltcl")) internaltcl=true; if (parameters.GetDefineFlag ("externaltcl")) internaltcl=false; if (internaltcl) { if (verbose) cout << "using internal Tcl-script" << endl; // connect to one string DLL_HEADER extern const char * ngscript[]; const char ** hcp = ngscript; int len = 0; while (*hcp) len += strlen (*hcp++); char * tr1 = new char[len+1]; *tr1 = 0; hcp = ngscript; char * tt1 = tr1; while (*hcp) { strcat (tt1, *hcp); tt1 += strlen (*hcp++); } errcode = Tcl_Eval (myinterp, tr1); delete [] tr1; } else { string startfile = ngdir + "/ng.tcl"; if (verbose) cout << "Load Tcl-script from " << startfile << endl; errcode = Tcl_EvalFile (myinterp, (char*)startfile.c_str()); } if (errcode) { cout << "Error in Tcl-Script:" << endl; // cout << "result = " << myinterp->result << endl; cout << "result = " << Tcl_GetStringResult (myinterp) << endl; // cout << "in line " << myinterp->errorLine << endl; cout << "\nMake sure to set environment variable NETGENDIR to directory containing ng.tcl" << endl; exit (1); } /* // lookup user file formats and insert into format list: NgArray userformats; NgArray extensions; RegisterUserFormats (userformats, extensions); ostringstream fstr; tcl_const char * exportft = Tcl_GetVar (myinterp, "exportfiletype", 0); for (int i = 1; i <= userformats.Size(); i++) { fstr << ".ngmenu.file.filetype add radio -label \"" << userformats.Get(i) << "\" -variable exportfiletype -command { .ngmenu.file invoke \"Export Mesh...\" } \n"; fstr << "lappend meshexportformats { {" << userformats.Get(i) << "} {" << extensions.Get(i) << "} }\n"; } Tcl_Eval (myinterp, (char*)fstr.str().c_str()); Tcl_SetVar (myinterp, "exportfiletype", exportft, 0); */ #ifdef SOCKETS Ng_ServerSocketManagerRun(); #endif // start event-loop Tk_MainLoop(); Tcl_DeleteInterp (myinterp); #ifdef NETGEN_PYTHON py::gil_scoped_acquire ensure_gil; #endif Tcl_Exit(0); } return 0; } /* extern "C" int Tix_Init (Tcl_Interp * interp); extern "C" int Itcl_Init (Tcl_Interp * interp); extern "C" int Itk_Init (Tcl_Interp * interp); */ extern "C" int Ng_Init (Tcl_Interp * interp); extern "C" int Ng_Vis_Init (Tcl_Interp * interp); // extern Tcl_PackageInitProc * Tk_SafeInit; /* * * Initialize packages * */ // extern "C" int NGSolve_Init (Tcl_Interp * interp); int Tcl_AppInit(Tcl_Interp * interp) { if (Tcl_Init(interp) == TCL_ERROR) { cerr << "Problem in Tcl_Init: " << endl; cout << "result = " << Tcl_GetStringResult (interp) << endl; // cerr << interp->result << endl; // return TCL_ERROR; } if (!nodisplay && Tk_Init(interp) == TCL_ERROR) { cerr << "Problem in Tk_Init: " << endl; cout << "result = " << Tcl_GetStringResult (interp) << endl; // cerr << interp->result << endl; // return TCL_ERROR; } #ifdef TRAFO // extern int Trafo_Init (Tcl_Interp * interp); // if (Trafo_Init(interp) == TCL_ERROR) // { // cerr << "Problem in Trafo_Init: " << endl; // cerr << interp->result << endl; // return TCL_ERROR; // } #endif #ifdef EBGELAST extern int EBGElast_Init (Tcl_Interp * interp); if(EBGElast_Init(interp) == TCL_ERROR) { cerr << "Problem in EBGElast_Init: " << endl; cerr << interp->result << endl; return TCL_ERROR; } #endif #ifdef SMALLTRAFO extern int SmallModels_Init (Tcl_Interp * interp); if(SmallModels_Init(interp) == TCL_ERROR) { cerr << "Problem in SmallModel_Init: " << endl; cerr << interp->result << endl; return TCL_ERROR; } #endif #ifdef SOCKETS extern int Ng_Socket_Init (Tcl_Interp * interp); if ( Ng_Socket_Init(interp) == TCL_ERROR) { cerr << "Problem in Ng_Socket_Init: " << endl; cerr << interp->result << endl; return TCL_ERROR; } #endif #ifdef ZUGSTANGE extern int Zugstange_Init (Tcl_Interp * interp); if (Zugstange_Init(interp) == TCL_ERROR) { cerr << "Problem in Zugstange_Init: " << endl; cerr << interp->result << endl; return TCL_ERROR; } #endif Tcl_StaticPackage(interp, "Tk", Tk_Init, 0); return TCL_OK; } ================================================ FILE: ng/ngguipy.cpp ================================================ #include #include <../general/ngpython.hpp> #include void NGCORE_API_IMPORT ExportMeshVis(py::module &m); void NGCORE_API_IMPORT ExportCSGVis(py::module &m); void NGCORE_API_IMPORT ExportSTLVis(py::module &m); namespace netgen { std::vector NGCORE_API_IMPORT Snapshot( int w, int h ); } PYBIND11_MODULE(libngguipy, ngpy) { py::module::import("pyngcore"); py::module meshvis = ngpy.def_submodule("meshvis", "pybind meshvis module"); ExportMeshVis(meshvis); py::module csgvis = ngpy.def_submodule("csgvis", "pybind csgvis module"); ExportCSGVis(csgvis); py::module stlvis = ngpy.def_submodule("stlvis", "pybind stlvis module"); ExportSTLVis(stlvis); ngpy.def("Snapshot", netgen::Snapshot); } ================================================ FILE: ng/nghelp.tcl ================================================ proc print_commandline_help { } { puts "Usage: ng { options }" puts "-geofile=filename Input geometry file (alternative: ng filename)" puts "-meshfile=filename Output mesh file" puts "-verycoarse, -coarse, -moderate, -fine, -veryfine" puts " Automatic mesh-size selection" puts "-meshsizefile=filename Load mesh-size file with local mesh sizes" puts "-meshfiletype={\"Neutral Format\", ...}" puts " Filetype of output file, default is netgen file" puts "-batchmode Run Netgen in batchmode" puts "-inputmeshfile=filename" puts " Input mesh file (batchmode only)" puts "-mergefile=filename Merge with mesh file (batchmode only)" puts "-refinementfile=filename" puts " Use refinementinfo from file (batchmode only)" puts "-serversocket=\#num Start a Netgen server with port \#num" puts "-V Print additional information" puts "-testout=filename file for test output" if { [catch { NGS_GetData } ] == 0 } { puts "\nNGSolve parameters:" puts "-pdefile=filename Load pde input file" puts "-solve Solve pde once" puts "-solve=n Solve pde by n adaptive refinement steps" puts "-recent Load and solve most recently loaded pde" } } proc set_menu_help { entry helpmsg } { global menuhelps set menuhelps($entry) $helpmsg } proc show_menu_help { entry } { global menuhelps if {[catch {set helptext $menuhelps($entry)}]} { set helptext "no help available " } .helpline configure -text $helptext if {[winfo exists .senshelp_dlg]==1} { .senshelp_dlg.text delete 1.0 end .senshelp_dlg.text insert end "Menu item: $entry\n\n" .senshelp_dlg.text insert end $helptext } } #tixBalloon .balloon -statusbar .helpline proc set_control_help { control helpmsg } { bind $control "show_control_help {$helpmsg}" bind $control "show_control_help {None}" .balloon bind $control -balloonmsg $helpmsg -statusmsg $helpmsg # puts "Add Help to $control" } proc show_control_help { helpmsg } { .helpline configure -text $helpmsg if {[winfo exists .senshelp_dlg]==1} { .senshelp_dlg.text delete 1.0 end .senshelp_dlg.text insert end $helpmsg } } proc sensitivehelpdialog { show } { set w .senshelp_dlg if {[winfo exists .senshelp_dlg] == 1} { if { $show == 1 } { wm withdraw .senshelp_dlg wm deiconify $w focus $w } { wm withdraw $w } } { toplevel $w # wm minsize $w 200 150 global senshelptext text $w.text -yscrollcommand "$w.scroll set" -setgrid true \ -width 40 -height 10 -wrap word scrollbar $w.scroll -command "$w.text yview" pack $w.scroll -side right -fill y pack $w.text -expand yes -fill both ttk::frame $w.bu pack $w.bu # -fill x ttk::button $w.close -text "Close" \ -command { wm withdraw .senshelp_dlg set showsensitivehelp 0 } pack $w.close if { $show == 1 } { wm withdraw $w wm geom $w +100+100 wm deiconify $w wm title $w "Help" focus $w } } } set_menu_help "File" "In File menu you can load and store geometries, meshes etc." set_menu_help "New Geometry" "Deletes current geometry" set_menu_help "Load Geometry" "Loads Geometry file in one of the formats STL (ASCII or binary), Constructive Solid Geometry (.geo) or 2D geometry. Please have a look into Netgen User's manuel for more details." set_menu_help "Save Geometry" "Saves STL Geometry in in either ASCII or binary STL format." set_menu_help "Load Mesh" "Loads surface and volume mesh in Netgen internal format." set_menu_help "Save Mesh" "Saves surface and volume mesh in Netgen internal format." set_menu_help "Write EPS File" "Dumps OpenGL rendering to EPS File." set_menu_help "Save Options" "Saves current options in file \"ng.opt\". These options will be loaded again when starting ng in the same directory." set_menu_help "Export Mesh" "Exports mesh in format defined by Export Filetype." set_menu_help "Export Filetype" "Selects file format for exporting mesh. Please have a look into the Netgen User's manual for more information." set_menu_help "Import Mesh" "Imports surface or volume mesh in exchange format." set_menu_help "Quit" "Quits Netgen" set_menu_help "Geometry" "Preparing geometries, visualiztion of geometries." set_menu_help "Scan CSG Geometry" "Generates surface triangulation for rendering" set_menu_help "CSG Options" "Sets Options for CSG visualization (bounding box, detail size, number of facets)." set_menu_help "CSG Properties" "Defines appearance of current CSG geometry (color, visibility, transparency)" set_menu_help "STL Doctor" "Calls STL Doctor for preprocessing STL geometry files." set_menu_help "STL Info" "Retrieves information about current STL geometry." set_menu_help "Mesh" "Menu for mesh generation" set_menu_help "Generate Mesh" "Generates mesh from geometry, same as Button \"Generate Mesh\"" set_menu_help "Stop Meshing" "Terminates meshgeneration. It may take a while until meshing terminates, please be patient." set_menu_help "Meshing Options" "Set options for mesh generation." set_menu_help "Delete Mesh" "Deletes mesh. Not necessary before generation of new mesh." set_menu_help "Delete Vol Mesh" "Deletes only volume mesh." set_menu_help "Mesh Quality" "Computs element shape measures. Triangle angles are inner angles of all triangles (faces of tetrahedra). Tet angles are angles between faces of tetrahedra." set_menu_help "Check Surface Mesh" "Checks consistency and overlap of surface mesh. Marks overlapping elements as bad elements, please enable visualization of bad elements in View->Mesh." set_menu_help "Check Volume Mesh" "Checks conformity of volume mesh." set_menu_help "Edit Boundary Conditions" "Open dialog for setting boundary condition numbers for individual faces." set_menu_help "Analyze Geometry" "Perform only first step in mesh generation. Action depends on geometry type, e.g. generates charts for STL mesh, find vertices in CSG geometries." set_menu_help "Mesh Edges" "Meshes edges" set_menu_help "Mesh Surface" "Generates surface mesh. Includes already surface optimization for some geometry types." set_menu_help "Optimize Surface" "Optimizes surface mesh." set_menu_help "Surface Optim. Step" "Performs a specific surface optimiztion step. Mesh smoothing moves nodes. edge swapping swaps the diagonal of a quadrilateral built by two triangles, criterion either by number of nodes, or anlges. Combine points eliminates triangles by combining points (in the center of gravity)." set_menu_help "Mesh Volume" "Performs volume meshing. Algorithm is a combination of Delaunay and Rule-based Advancing Front" set_menu_help "Optimize Volume" "Performs additional volume optimization steps" set_menu_help "Smooth Opt Volume" "Performs optimization steps by smoothing iterations" set_menu_help "Smooth Opt Volume Jacobian" "Volume optimization by smoothing iterations. Criterion is optimization of Jacobi determinants. This optimization step is also available for 10-node tetrahedra." set_menu_help "View" "Sets viewing options" set_menu_help "Zoom all" "Zooms scene to show whole object" set_menu_help "Center" "Defines center of rotation" set_menu_help "Viewing Options" "Sets viewing options for geometry, mesh, lighting" set_menu_help "Clipping Plane" "Introduces clipping plane. The clipping plane is defined by the normal vector, and a scaled offset. Clipping of performed by OpenGl rendering" set_menu_help "Quality Plot" "Shows the element quality distribution histogram. Measure is volume scaled by edge-length to the third. Optimal elements have measure 1." set_menu_help "Sensitive Help" "Shows this help window" set_menu_help "Mesh-size" "Manipulations of existing mesh" set_menu_help "Refine uniform" "Refines mesh by splitting elements into eight childs (algorithm of J. Bey)" set_menu_help "Second Order" "Converts 4 node elements to 10 node elements. Edge-midpoitns are projected to the geometry." set_menu_help "Refinement Dialog" "Controls local mesh refinement" set_menu_help "Load Meshsize" "Loads mesh-size file for local mesh refinement." set_menu_help "MS from Surf Mesh" "Defines mesh-size by the surface mesh." set f .options_dlg.nb.nbframe.general # set_control_help $f "General meshing page" set_control_help $f.fine "Controls relative mesh size.\nThis control affects other mesh-size controls in common" set_control_help $f.first "First step in mesh generation. Usually, meshing starts from \"analyze geometry\". If the surface mesh is already available \"First step\" should be set to \"mesh volume\"" set_control_help $f.last "Last step in mesh generation. If only the surface mesh is required, please set \"Last Step\" to \"Optimize Surface\"" set_control_help .bubar.surfm "Start mesh generation" set_control_help .bubar.stopm "Stop mesh generation" proc help_item { helptext } {p puts $helptext } proc show_help { } { set w .help if {[winfo exists .help] == 1} { wm withdraw $w wm deiconif $w focus $w } { toplevel $w frame $w.buttons pack $w.buttons -side bottom -fill x -pady 2m button $w.buttons.done -text Done -command "destroy $w" pack $w.buttons.done -side left -expand 1 text $w.text -yscrollcommand "$w.scroll set" -setgrid true \ -width 60 -height 24 -wrap word scrollbar $w.scroll -command "$w.text yview" pack $w.scroll -side right -fill y pack $w.text -expand yes -fill both } $w.text configure -state normal $w.text delete 1.0 end } set bold "-background #43ce80 -relief raised -borderwidth 1" set normal "-background {} -relief flat" proc help_main { } { show_help; set w .help global bold global normal $w.text insert 0.0 \ {NETGEN Help} $w.text insert end \n\n $w.text insert end \ {1. General} d1 $w.text insert end \n\n $w.text insert end \ {2. Menu items } d2 $w.text insert end \n\n foreach tag {d1 d2} { $w.text tag bind $tag "$w.text tag configure $tag $bold" $w.text tag bind $tag "$w.text tag configure $tag $normal" } $w.text tag bind d1 <1> { puts "general"; help_general } $w.text tag bind d2 <1> { help_menus } $w.text configure -state disabled } proc help_general { } { show_help; set w .help global bold global normal puts "general called" $w.text insert 0.0 \ {NETGEN is an automatic three dimensional tetrahedral mesh generation system. It accepts input from constructive solid geometry (CSG) or boundary representation (BRep) from STEP or STL file format. NETGEN contains modules for mesh optimization and hierarchical mesh refinement.} $w.text configure -state disabled } proc help_menus { } { show_help; set w .help global bold global normal $w.text insert 0.0 \ {The NETGEN Menu items are} $w.text insert end \n\n $w.text insert end \ {1. File} d1 $w.text insert end \n\n $w.text insert end \ {2. Geometry } d2 $w.text insert end \n\n $w.text insert end \ {3. Mesh } d3 $w.text insert end \n\n $w.text insert end \ {4. View } d4 $w.text insert end \n\n $w.text insert end \ {5. Mesh-size } d5 $w.text insert end \n\n $w.text insert end \ {6. STL } d6 foreach tag {d1 d2 d3 d4 d5 d6} { $w.text tag bind $tag "$w.text tag configure $tag $bold" $w.text tag bind $tag "$w.text tag configure $tag $normal" } $w.text tag bind d1 <1> {puts "File menu"} $w.text tag bind d2 <1> {puts "Geometry menu"} $w.text tag bind d3 <1> {puts "Mesh menu"} $w.text tag bind d4 <1> {puts "View menu"} $w.text tag bind d5 <1> {puts "Mesh-size menu"} $w.text tag bind d6 <1> {puts "STL menu"} $w.text configure -state disabled } ================================================ FILE: ng/ngicon.tcl ================================================ set icon_data { /* XPM */ static char *icon2[] = { /* width height num_colors chars_per_pixel */ " 60 60 6 1", /* colors */ ". c #000000", "# c #008000", "a c #00b700", "b c #00c700", "c c #00ff00", "d s c None c None", /* pixels */ "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", "dddddddddddddddd..........dddddddddddddddddddddddddddddddddd", "ddddddddddddddd.c..cc#####................dddddddddddddddddd", "ddddddddddddd..cccc..ccccccccccccccccc...#...............ddd", "dddddddddddd.cccccccc..cccccccccccc...ccc..cccccccccc###..dd", "ddddddddddd.ccccccccccc..ccccccccc.cccccccc.ccccccccccc...dd", "dddddddddd.cccccccccccccc.cccccc..cccccccccc.ccccccccc.b..dd", "ddddddddd.cccccccccccccccc..ccc.ccccccccccccc..cccccc.bb..dd", "ddddddd........................cccccccccccccccc.cccc.bbb..dd", "dddddd.ccc.ccccccccccccccccc..#..............ccc.c..bbbb..dd", "dddd..ccccc..cccccccccccccc.#..##############.....bbbbb.b.dd", "ddd.ccccccccc..ccccccccccc.##.#.#################.bbbbb.b.dd", "dd.cccccccccccc..cccccccc.###.##.################.bbbbb.b.dd", "d..cccccccccccccc..ccccc.####.###.###############.bbbbb.b.dd", "d.a..............cc..cc.#####.####.##############.bbbb.bb.dd", "d..aaaaaaaaaaaaaa......######.#####.#############.bbbb.bb.dd", "d.a.aaaaaaaaaaaaaaaaa...#####.######..###########.bbbb.bb.dd", "d.aa.aaaaaaaaaaaaaaaa...#####.########.##########.bbbb.bb.dd", "d.aaa.aaaaaaaaaaaaaaa..#.####.#########.##########..b.bbb.dd", "d.aaaa.aaaaaaaaaaaaaa..#.####.##########.#########..b.bbb.dd", "d.aaaaa..aaaaaaaaaaaa..##.###.###########.########..b.bbb.dd", "d.aaaaaaa.aaaaaaaaaaa..###.###.###########.#######..b.bbb.dd", "d.aaaaaaaa.aaaaaaaaaa..###.###.############.######..b.bbb#.d", "d.aaaaaaaaa.aaaaaaaaa..####.##.#############.#####...bbbb#.d", "d.aaaaaaaaaa.aaaaaaaa..#####.#.##############.####...bbbb#.d", "d.aaaaaaaaaaa.aaaaaaa..#####.#.###############.###...bbbb#.d", "d.aaaaaaaaaaaa.aaaaaa..######..################.##...bbbb#.d", "d.aaaaaaaaaaaaa.aaaaaaa.#####..#################.#..bbbbb#.d", "d.aaaaaaaaaaaaaa.aaaaaa.#####.............#######...bbbbb#.d", "d.aaaaaaaaaaaaaaa.aaaaa.####.###.#########..........bbbbbb.d", "dd.aaaaaaaaaaaaaaa.aaaa.###.#####..##############...bbbbbb.d", "dd.aaaaaaaaaaaaaaaa.aaa.##.########.############.b...bbbbb.d", "dd.aaaaaaaaaaaaaaaaa.aa.#.##########...########.b.bbb.bbbb.d", "dd.aaaaaaaaaaaaaaaaaa....##############.######.bb.bbb.bbbb.d", "dd.aaaaaaaaaaaaaaaaaaaa...##############..###.bbb.bbbb.bbb.d", "dd.aaaaaaaaaaaaaaaaaa..a.a..............##.#.bbbb.bbbb.bbb.d", "dd.aaaaaaaaaaaaaaaaa.aaaa.aaaaaaaaaaaaaa....bbbb.bbbbbb.bb.d", "dd.aaaaaaaaaaaaaaaa.aaaaa.aaaaaaaaaaaaaaaaa.bbbb.bbbbbbb.b.d", "dd.aaaaaaaaaaaaaaa.aaaaaaa.aaaaaaaaaaaaaaaa.bbbb.bbbbbbb.b.d", "dd.aaaaaaaaaaaaaa.aaaaaaaaa.aaaaaaaaaaaaaaa.bbbb.bbbbbbbb..d", "dd.aaaaaaaaaaaaa.aaaaaaaaaaa.aaaaaaaaaaaaaa.bbb.bbbbbbbbb..d", "dd.aaaaaaaaaaaa.aaaaaaaaaaaaa.aaaaaaaaaaaaa.bbb.bbbbbbbbbb.d", "dd.aaaaaaaaaaa.aaaaaaaaaaaaaaa.aaaaaaaaaaaa.bbb.bbbbbbbbbb.d", "dd.aaaaaaaaaa.aaaaaaaaaaaaaaaaa.aaaaaaaaaaaa.bb.bbbbbbbbb.dd", "dd.aaaaaaaaa.aaaaaaaaaaaaaaaaaaa.aaaaaaaaaaa.bb.bbbbbbbb.ddd", "dd.aaaaaaaa.aaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaa.b.bbbbbbbb.dddd", "dd.aaaaaaa.aaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaa.b.bbbbbbb.ddddd", "dd.aaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaa.b.bbbbbb.dddddd", "dd.aaaa..aaaaaaaaaaaaaaaaaaaaaaaaaaa..aaaaaa.b.bbbbb.ddddddd", "ddd.aa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaa..bbbb..dddddddd", "ddd.a.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaa..bbb.dddddddddd", "ddd..aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaa..bb.ddddddddddd", "ddd........aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aa..b.dddddddddddd", "ddddddddddd.............aaaaaaaaaaaaaaaaaa.a...ddddddddddddd", "dddddddddddddddddddddddd............aaaaaaa...dddddddddddddd", "dddddddddddddddddddddddddddddddddddd.........ddddddddddddddd", "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd" }; } ================================================ FILE: ng/ngpkg.cpp ================================================ /* The interface between the GUI and the netgen library */ #include #include #include #include #include "../libsrc/meshing/boundarylayer.hpp" #include #include #include #ifdef SOCKETS #include "../libsrc/sockets/sockets.hpp" #include "../libsrc/sockets/socketmanager.hpp" #endif #include "../libsrc/general/gzstream.h" // to be sure to include the 'right' togl-version #include "Togl2.1/togl.h" // EXTERN int Togl_PixelScale (const Togl * togl); #include "fonts.hpp" extern bool nodisplay; #include #include "../libsrc/interface/writeuser.hpp" namespace netgen { DLL_HEADER extern MeshingParameters mparam; DLL_HEADER extern void ImportSolution2(const char * filename); #include "demoview.hpp" } #ifdef ACIS #include "ng_acis.hpp" #endif #ifdef JPEGLIB #include #endif #ifdef FFMPEG #include "encoding.hpp" #endif #ifdef NGSOLVE extern "C" void NGSolve_Exit(); #endif // extern void * ngsolve_handle; namespace netgen { extern Flags parameters; /* NetgenOutStream operator<< ( ostream & ost, Imp imp ) { return ( NetgenOutStream ( &ost, imp ) ); } NetgenOutStream operator<< ( ostream & ost, Proc proc ) { return ( NetgenOutStream ( &ost, proc ) ); } NetgenOutStream operator<< ( ostream & ost, Procs & procs ) { return ( NetgenOutStream ( &ost, procs ) ); } */ DLL_HEADER extern std::shared_ptr ng_geometry; DLL_HEADER extern std::shared_ptr mesh; Tcl_Interp * tcl_interp; #ifdef SOCKETS AutoPtr clientsocket; ServerSocketManager serversocketmanager; //NgArray< AutoPtr < ServerInfo > > servers; NgArray< ServerInfo* > servers; AutoPtr serversocketusernetgen; #endif // visualization scenes, pointer vs selects which one is drawn: DLL_HEADER extern VisualSceneSurfaceMeshing vssurfacemeshing; DLL_HEADER extern VisualSceneMeshDoctor vsmeshdoc; static VisualSceneSpecPoints vsspecpoints; DLL_HEADER extern VisualScene *visual_scene; DLL_HEADER extern VisualScene visual_scene_cross; extern char * err_needsmesh;// = (char*) "This operation needs a mesh"; extern char * err_jobrunning;// = (char*) "Meshing Job already running"; static clock_t starttimea; void ResetTime2 () { starttimea = clock(); } #ifndef SMALLLIB double GetTime2 () { return double(clock() - starttimea) / CLOCKS_PER_SEC; } #endif // file handling .. int Ng_New (ClientData clientData, Tcl_Interp * interp, int argc, tcl_const char *argv[]) { if (strcmp (argv[1], "mesh") == 0) mesh.reset(); if (strcmp (argv[1], "geom") == 0) { /* delete ng_geometry; ng_geometry = new NetgenGeometry; */ ng_geometry = make_shared(); } return TCL_OK; } int Ng_ImportMesh (ClientData clientData, Tcl_Interp * interp, int argc, tcl_const char *argv[]); int Ng_LoadMesh (ClientData clientData, Tcl_Interp * interp, int argc, tcl_const char *argv[]) { auto filename = filesystem::u8path(argv[1]); if (filename.string().find(".vol") == string::npos) { return Ng_ImportMesh(clientData,interp,argc,argv); } PrintMessage (1, "load mesh from file ", filename); mesh = make_shared(); try { mesh -> Load(filename); SetGlobalMesh (mesh); #ifdef PARALLEL_NETGEN MyMPI_SendCmd ("mesh"); mesh -> Distribute(); #endif if(mesh->GetGeometry()) ng_geometry = mesh->GetGeometry(); } catch (const NgException & e) { PrintMessage (3, e.What()); return TCL_ERROR; } PrintMessage (2, mesh->GetNP(), " Points, ", mesh->GetNE(), " Elements."); return TCL_OK; } int Ng_SaveMesh (ClientData clientData, Tcl_Interp * interp, int argc, tcl_const char *argv[]) { if (!mesh) { Tcl_SetResult (interp, err_needsmesh, TCL_STATIC); return TCL_ERROR; } string filename (argv[1]); PrintMessage (1, "Save mesh to file ", filename, ".... Please Wait!"); ostream * outfile; if (filename.substr (filename.length()-3, 3) == ".gz") outfile = new ogzstream (filename.c_str()); else outfile = new ofstream (filename.c_str()); mesh -> Save (*outfile); // *outfile << endl << endl << "endmesh" << endl << endl; if (ng_geometry && !mesh->GetGeometry()) ng_geometry -> SaveToMeshFile (*outfile); delete outfile; PrintMessage (1, "Save mesh to file .... DONE!"); return TCL_OK; } int Ng_MergeMesh (ClientData clientData, Tcl_Interp * interp, int argc, tcl_const char *argv[]) { string filename (argv[1]); PrintMessage (1, "merge with mesh from file ", filename); try { CSGeometry * geometry = dynamic_cast (ng_geometry.get()); //mesh -> Merge (filename); ifstream infile(filename.c_str()); const int offset = (geometry) ? geometry->GetNSurf() : 0; mesh -> Merge(infile,offset); string auxstring; if(infile.good()) { infile >> auxstring; if(geometry && auxstring == "csgsurfaces") geometry -> LoadSurfaces(infile); } } catch (const NgException & e) { PrintMessage (3, e.What()); return TCL_ERROR; } PrintMessage (2, mesh->GetNP(), " Points, ", mesh->GetNSE(), " Surface Elements."); return TCL_OK; } int Ng_GetImportFormats (ClientData clientData, Tcl_Interp * interp, int argc, tcl_const char *argv[]) { ostringstream fstr; UserFormatRegister::IterateFormats([&](auto & entry) { fstr << "{ {" << entry.format << "} {" << entry.extensions[0]; for(auto ext : entry.extensions.Range(1, entry.extensions.Size())) fstr << ' ' << ext; fstr << "} }\n"; }, true, false); Tcl_SetResult (interp, const_cast(fstr.str().c_str()), TCL_VOLATILE); return TCL_OK; } int Ng_GetExportFormats (ClientData clientData, Tcl_Interp * interp, int argc, tcl_const char *argv[]) { ostringstream fstr; UserFormatRegister::IterateFormats([&](auto & entry) { fstr << "{ {" << entry.format << "} {" << entry.extensions[0]; for(auto ext : entry.extensions.Range(1, entry.extensions.Size())) fstr << ' ' << ext; fstr << "} }\n"; }, false, true); Tcl_SetResult (interp, const_cast(fstr.str().c_str()), TCL_VOLATILE); return TCL_OK; } int Ng_ExportMesh (ClientData clientData, Tcl_Interp * interp, int argc, tcl_const char *argv[]) { if (!mesh) { Tcl_SetResult (interp, err_needsmesh, TCL_STATIC); return TCL_ERROR; } string filename (argv[1]); string filetype (argv[2]); PrintMessage (1, "Export mesh to file ", filename, ".... Please Wait!"); // CSGeometry * geometry = dynamic_cast (ng_geometry); if (WriteUserFormat (filetype, *mesh, /* *ng_geometry, */ filename)) { ostringstream ost; ost << "Sorry, nothing known about file format " << filetype << endl; Tcl_SetResult (interp, (char*)ost.str().c_str(), TCL_VOLATILE); return TCL_ERROR; } PrintMessage (1, "Export mesh to file .... DONE!"); return TCL_OK; } int Ng_ImportMesh (ClientData clientData, Tcl_Interp * interp, int argc, tcl_const char *argv[]) { const string filename (argv[1]); const string format (argv[2]); PrintMessage (1, "import mesh from ", filename); mesh = make_shared(); ReadUserFormat (*mesh, filename, format); PrintMessage (2, mesh->GetNP(), " Points, ", mesh->GetNE(), " Elements."); SetGlobalMesh (mesh); mesh->SetGlobalH (mparam.maxh); mesh->CalcLocalH(mparam.grading); return TCL_OK; } int Ng_ImportSolution (ClientData clientData, Tcl_Interp * interp, int argc, tcl_const char *argv[]) { if (!mesh) { Tcl_SetResult (interp, err_needsmesh, TCL_STATIC); return TCL_ERROR; } const char * filename = argv[1]; PrintMessage (1, "Import solution from file ", filename); ImportSolution2 (filename); return TCL_OK; } static DemoView * demoview = 0; int Ng_ShowDemo (ClientData clientData, Tcl_Interp * interp, int argc, tcl_const char *argv[]) { const char * filename = argv[1]; PrintMessage (1, "Show demo ", filename); demoview = new DemoView (filename); return TCL_OK; } int Ng_DemoSetTime (ClientData clientData, Tcl_Interp * interp, int argc, tcl_const char *argv[]) { cout << "demosettime, time = " << argv[1] << endl; int result = -1; static char strminusone[] = "-1"; static char str0[] = "0"; if (demoview) result = demoview->SetTime (atof (argv[1])); if (result == -1) Tcl_SetResult (interp, strminusone, TCL_STATIC); else Tcl_SetResult (interp, str0, TCL_STATIC); return TCL_OK; } int Ng_SaveSolution (ClientData clientData, Tcl_Interp * interp, int argc, tcl_const char *argv[]) { if (!mesh) { Tcl_SetResult (interp, err_needsmesh, TCL_STATIC); return TCL_ERROR; } const char * filename = argv[1]; PrintMessage (1, "Save solution to file ", filename); netgen::GetVSSolution().SaveSolutionData (filename); return TCL_OK; } int Ng_SetNextTimeStamp (ClientData clientData, Tcl_Interp * interp, int argqc, tcl_const char *argv[]) { if (mesh) mesh -> SetNextTimeStamp(); return TCL_OK; } int Ng_LoadGeometry (ClientData clientData, Tcl_Interp * interp, int argc, tcl_const char *argv[]) { if (multithread.running) { Tcl_SetResult (interp, err_jobrunning, TCL_STATIC); return TCL_ERROR; } tcl_const char * lgfilename = argv[1]; #ifdef LOG_STREAM (*logout) << "Load geometry file: " << lgfilename << endl; #endif #ifdef STAT_STREAM (*statout) << lgfilename << " & " << endl; #endif try { for (auto loader : GeometryRegister()) { NetgenGeometry * hgeom = loader->Load (lgfilename); if (hgeom) { // delete ng_geometry; // ng_geometry = hgeom; ng_geometry = shared_ptr (hgeom); loader->SetParameters(interp); mesh.reset(); return TCL_OK; } } ifstream infile(lgfilename); if (strlen(lgfilename) < 4) { cout << "ERROR: cannot recognise file format!" << endl; } else { 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)) { Tcl_SetResult (interp, (char*)"IGES import requires the OpenCascade geometry kernel. " "Please install OpenCascade as described in the Netgen-website", TCL_STATIC); return TCL_ERROR; } else if (strcmp (&lgfilename[strlen(lgfilename)-3], "sat") == 0) { #ifdef ACIS PrintMessage (1, "Load ACIS geometry file ", lgfilename); acisgeometry = netgen::LoadACIS_SAT (lgfilename); #endif } 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)) { #ifdef ACISxxx PrintMessage (1, "Load STEP geometry file ", lgfilename); acisgeometry = netgen::LoadACIS_STEP (lgfilename); #else Tcl_SetResult (interp, (char*)"IGES import requires the OpenCascade geometry kernel. " "Please install OpenCascade as described in the Netgen-website", TCL_STATIC); return TCL_ERROR; #endif } else if ((strcmp (&lgfilename[strlen(lgfilename)-4], "brep") == 0) || (strcmp (&lgfilename[strlen(lgfilename)-4], "Brep") == 0) || (strcmp (&lgfilename[strlen(lgfilename)-4], "BREP") == 0)) { Tcl_SetResult (interp, (char*)"BREP import requires the OpenCascade geometry kernel. " "Please install OpenCascade as described in the Netgen-website", TCL_STATIC); return TCL_ERROR; } } } catch (const NgException & e) { Tcl_SetResult (interp, const_cast (e.What().c_str()), TCL_VOLATILE); return TCL_ERROR; } mesh.reset(); return TCL_OK; } int Ng_SaveGeometry (ClientData clientData, Tcl_Interp * interp, int argc, tcl_const char *argv[]) { if (argc == 2) { const char * cfilename = argv[1]; try { ng_geometry -> Save (string (cfilename)); } catch (const NgException & e) { Tcl_SetResult (interp, const_cast (e.What().c_str()), TCL_VOLATILE); return TCL_ERROR; } PrintMessage (1, "Save geometry to file ", cfilename); if (strlen(cfilename) < 4) {cout << "ERROR: can not recognise file format!!!" << endl;} else { #ifdef ACIS if (acisgeometry) { char * filename = const_cast (argv[1]); if (strcmp (&filename[strlen(filename)-3], "sat") == 0) { acisgeometry -> SaveSATFile (filename); } } #endif /* if (strcmp (&cfilename[strlen(cfilename)-3], "ngg") == 0) { CSGeometry * geometry = dynamic_cast (ng_geometry); if (geometry) { ofstream of(cfilename); geometry->Save (of); } } */ } } return TCL_OK; } int Ng_ReadStatus (ClientData clientData, Tcl_Interp * interp, int argc, tcl_const char *argv[]) { char buf[20], lstring[200]; static int prev_np = -1; static int prev_ne = -1; static int prev_nse = -1; if (mesh) { if (prev_np != mesh->GetNP()) { snprintf (buf, size(buf), "%u", unsigned(mesh->GetNP())); Tcl_SetVar (interp, "::status_np", buf, 0); prev_np = mesh->GetNP(); } if (prev_ne != mesh->GetNE()) { snprintf (buf, size(buf), "%u", unsigned(mesh->GetNE())); Tcl_SetVar (interp, "::status_ne", buf, 0); prev_ne = mesh->GetNE(); } if (prev_nse != mesh->GetNSE()) { snprintf (buf, size(buf), "%u", unsigned(mesh->GetNSE())); Tcl_SetVar (interp, "::status_nse", buf, 0); prev_nse = mesh->GetNSE(); } auto tets_in_qualclass = mesh->GetQualityHistogram(); lstring[0] = 0; for (int i = 0; i < tets_in_qualclass.Size(); i++) { snprintf (buf, size(buf), " %d", tets_in_qualclass[i]); strcat (lstring, buf); } for (int i = tets_in_qualclass.Size(); i < 20; i++) strcat (lstring, " 0"); Tcl_SetVar (interp, "::status_tetqualclasses", lstring, 0); } else { if (prev_np != 0) { Tcl_SetVar (interp, "::status_np", "0", 0); prev_np = 0; } if (prev_ne != 0) { Tcl_SetVar (interp, "::status_ne", "0", 0); prev_ne = 0; } if (prev_nse != 0) { Tcl_SetVar (interp, "::status_nse", "0", 0); prev_nse = 0; } Tcl_SetVar (interp, "::status_tetqualclasses", "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0", 0); } static string prev_working; string working = multithread.running ? "working" : " "; if (working != prev_working) { Tcl_SetVar (interp, "::status_working", working.c_str(), 0); prev_working = working; } /* if (multithread.running) Tcl_SetVar (interp, "::status_working", "working", 0); else Tcl_SetVar (interp, "::status_working", " ", 0); */ static string prev_task; if (prev_task != string(multithread.task)) { prev_task = multithread.task; Tcl_SetVar (interp, "::status_task", prev_task.c_str(), 0); } static double prev_percent = -1; if (prev_percent != multithread.percent) { prev_percent = multithread.percent; snprintf (buf, size(buf), "%lf", prev_percent); Tcl_SetVar (interp, "::status_percent", buf, 0); } { lock_guard guard(tcl_todo_mutex); if (multithread.tcl_todo->length()) { Tcl_Eval (interp, multithread.tcl_todo->c_str()); *multithread.tcl_todo = ""; } } return TCL_OK; } int Ng_MemInfo (ClientData clientData, Tcl_Interp * interp, int argc, tcl_const char *argv[]) {/* if (argc < 2) return TCL_ERROR; if (strcmp (argv[1], "usedmb") == 0) { // returns string of 512 '0' or '1' static char usedmb[513]; for (int i = 0; i < 512; i++) usedmb[i] = (i % 7 == 0) ? '1' : '0'; usedmb[512] = 0; BaseDynamicMem::GetUsed (512, usedmb); Tcl_SetResult (interp, usedmb, TCL_STATIC); return TCL_OK; } */ return TCL_ERROR; } int Ng_BCProp (ClientData clientData, Tcl_Interp * interp, int argc, tcl_const char *argv[]) { static char buf[100]; if (argc < 2) { Tcl_SetResult (interp, (char*)"Ng_BCProp needs arguments", TCL_STATIC); return TCL_ERROR; } if (strcmp (argv[1], "setbc") == 0) { int facenr = atoi (argv[2]); int bcnr = atoi (argv[3]); if (mesh && facenr >= 1 && facenr <= mesh->GetNFD()) mesh->GetFaceDescriptor (facenr).SetBCProperty (bcnr); } if (strcmp (argv[1], "setall") == 0) { int bcnr = atoi (argv[2]); if (mesh) { int nfd = mesh->GetNFD(); for (int i = 1; i <= nfd; i++) mesh->GetFaceDescriptor (i).SetBCProperty (bcnr); } } if (strcmp (argv[1], "getbc") == 0) { int facenr = atoi (argv[2]); if (mesh && facenr >= 1 && facenr <= mesh->GetNFD()) { snprintf (buf, size(buf), "%d", mesh->GetFaceDescriptor(facenr).BCProperty()); } else { strcpy (buf, "0"); } Tcl_SetResult (interp, buf, TCL_STATIC); } if (strcmp (argv[1], "getbcname") == 0) { int facenr = atoi (argv[2]); if (mesh && facenr >= 1 && facenr <= mesh->GetNFD()) { snprintf (buf, size(buf), "%s", mesh->GetFaceDescriptor(facenr).GetBCName().c_str()); } else { strcpy (buf, "-"); } Tcl_SetResult (interp, buf, TCL_STATIC); } if (strcmp (argv[1], "getactive") == 0) { snprintf (buf, size(buf), "%d", vsmesh.SelectedFace()); Tcl_SetResult (interp, buf, TCL_STATIC); } if (strcmp (argv[1], "setactive") == 0) { int facenr = atoi (argv[2]); if (mesh && facenr >= 1 && facenr <= mesh->GetNFD()) { vsmesh.SetSelectedFace (facenr); } } if (strcmp (argv[1], "getnfd") == 0) { if (mesh) snprintf (buf, size(buf), "%d", mesh->GetNFD()); else snprintf (buf, size(buf), "0"); Tcl_SetResult (interp, buf, TCL_STATIC); } return TCL_OK; } int Ng_Refine (ClientData clientData, Tcl_Interp * interp, int argc, tcl_const char *argv[]) { if (!mesh) { Tcl_SetResult (interp, err_needsmesh, TCL_STATIC); return TCL_ERROR; } if (multithread.running) { Tcl_SetResult (interp, err_jobrunning, TCL_STATIC); return TCL_ERROR; } #ifdef ACIS if (acisgeometry) { ACISRefinementSurfaces ref (*acisgeometry); ACISMeshOptimize2dSurfaces opt(*acisgeometry); ref.Set2dOptimizer(&opt); ref.Refine (*mesh); } else #endif { // ng_geometry -> GetRefinement().Refine(*mesh); mesh->GetGeometry()->GetRefinement().Refine(*mesh); } //redo second order refinement if desired if (mparam.secondorder) const_cast (mesh->GetGeometry()->GetRefinement()).MakeSecondOrder(*mesh); return TCL_OK; } int Ng_SecondOrder (ClientData clientData, Tcl_Interp * interp, int argc, tcl_const char *argv[]) { if (!mesh) { Tcl_SetResult (interp, err_needsmesh, TCL_STATIC); return TCL_ERROR; } if (multithread.running) { Tcl_SetResult (interp, err_jobrunning, TCL_STATIC); return TCL_ERROR; } const_cast (mesh->GetGeometry()->GetRefinement()).MakeSecondOrder (*mesh); return TCL_OK; } void * HighOrderDummy (void *) { // mparam.elementorder = atoi (Tcl_GetVar (interp, "options.elementorder", 0)); const char * savetask = multithread.task; Refinement & ref = const_cast (mesh->GetGeometry()->GetRefinement()); mesh -> GetCurvedElements().BuildCurvedElements (&ref, mparam.elementorder); multithread.task = savetask; multithread.running = 0; multithread.terminate = 1; mesh -> SetNextMajorTimeStamp(); return 0; } int Ng_HighOrder (ClientData clientData, Tcl_Interp * interp, int argc, tcl_const char *argv[]) { if (!mesh) { Tcl_SetResult (interp, err_needsmesh, TCL_STATIC); return TCL_ERROR; } if (multithread.running) { Tcl_SetResult (interp, err_jobrunning, TCL_STATIC); return TCL_ERROR; } multithread.running = 1; multithread.terminate = 0; mparam.elementorder = atoi(argv[1]); HighOrderDummy(NULL); return TCL_OK; } void * ValidateDummy (void *) { Refinement & ref = const_cast (mesh->GetGeometry()->GetRefinement()); ref.ValidateSecondOrder (*mesh); multithread.running = 0; return NULL; } int Ng_ValidateSecondOrder (ClientData clientData, Tcl_Interp * interp, int argc, tcl_const char *argv[]) { if (!mesh) { Tcl_SetResult (interp, err_needsmesh, TCL_STATIC); return TCL_ERROR; } if (multithread.running) { Tcl_SetResult (interp, err_jobrunning, TCL_STATIC); return TCL_ERROR; } multithread.running = 1; RunParallel (ValidateDummy, NULL); return TCL_OK; } int Ng_ZRefinement (ClientData clientData, Tcl_Interp * interp, int argc, tcl_const char *argv[]) { if (!mesh) { Tcl_SetResult (interp, err_needsmesh, TCL_STATIC); return TCL_ERROR; } if (multithread.running) { Tcl_SetResult (interp, err_jobrunning, TCL_STATIC); return TCL_ERROR; } ZRefinementOptions opt; opt.minref = 5; if (argc >= 2) opt.minref = atoi (argv[1]); ZRefinement (*mesh, ng_geometry.get(), opt); return TCL_OK; } int Ng_HPRefinement (ClientData clientData, Tcl_Interp * interp, int argc, tcl_const char *argv[]) { if (!mesh) { Tcl_SetResult (interp, err_needsmesh, TCL_STATIC); return TCL_ERROR; } if (multithread.running) { Tcl_SetResult (interp, err_jobrunning, TCL_STATIC); return TCL_ERROR; } int levels = atoi (argv[1]); Refinement & ref = const_cast (mesh->GetGeometry()->GetRefinement()); HPRefinement (*mesh, &ref, levels); return TCL_OK; } int Ng_LoadMeshSize (ClientData clientData, Tcl_Interp * interp, int argc, tcl_const char *argv[]) { if (!mesh) { Tcl_SetResult (interp, err_needsmesh, TCL_STATIC); return TCL_ERROR; } if (multithread.running) { Tcl_SetResult (interp, err_jobrunning, TCL_STATIC); return TCL_ERROR; } mesh->LoadLocalMeshSize(argv[1]); return TCL_OK; } int Ng_MeshSizeFromSurfaceMesh (ClientData clientData, Tcl_Interp * interp, int argc, tcl_const char *argv[]) { if (!mesh) { Tcl_SetResult (interp, err_needsmesh, TCL_STATIC); return TCL_ERROR; } if (multithread.running) { Tcl_SetResult (interp, err_jobrunning, TCL_STATIC); return TCL_ERROR; } mesh->SetGlobalH (mparam.maxh); mesh->CalcLocalH(mparam.grading); return TCL_OK; } // Philippose Rajan - 13 June 2009 // Added a new TCL function call for the generation // of prismatic boundary layers int Ng_GenerateBoundaryLayer (ClientData clientData, Tcl_Interp * interp, int argc, tcl_const char *argv[]) { if (!mesh) { Tcl_SetResult (interp, err_needsmesh, TCL_STATIC); return TCL_ERROR; } if(multithread.running) { Tcl_SetResult(interp, err_jobrunning, TCL_STATIC); return TCL_ERROR; } cout << "Generate Prismatic Boundary Layers (Experimental)...." << endl; // Use an array to support creation of boundary // layers for multiple surfaces in the future... std::vector surfid; int surfinp = 0; int prismlayers = 1; double hfirst = 0.01; double growthfactor = 1.0; while(surfinp >= 0) { cout << "Enter Surface ID (-1 to end list): "; cin >> surfinp; if(surfinp >= 0) surfid.push_back(surfinp); } cout << "Number of surfaces entered = " << surfid.size() << endl; cout << "Selected surfaces are:" << endl; for(auto i : Range(surfid.size())) cout << "Surface " << i << ": " << surfid[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; BoundaryLayerParameters blp; blp.boundary = surfid; std::vector thickness; for(auto i : Range(prismlayers)) { auto layer = i+1; if(growthfactor == 1) thickness.push_back(layer * hfirst); else thickness.push_back(hfirst * (pow(growthfactor, (layer+1))-1)/(growthfactor-1)); } blp.thickness = thickness; GenerateBoundaryLayer (*mesh, blp); return TCL_OK; } int Ng_InsertVirtualBL (ClientData clientData, Tcl_Interp * interp, int argc, tcl_const char *argv[]) { if (!mesh) { Tcl_SetResult (interp, err_needsmesh, TCL_STATIC); return TCL_ERROR; } if (multithread.running) { Tcl_SetResult (interp, err_jobrunning, TCL_STATIC); return TCL_ERROR; } InsertVirtualBoundaryLayer (*mesh); return TCL_OK; } int Ng_CutOffAndCombine (ClientData clientData, Tcl_Interp * interp, int argc, tcl_const char *argv[]) { Mesh othermesh; othermesh.Load (argv[1]); othermesh.SetGlobalH (mparam.maxh); othermesh.CalcLocalH(mparam.grading); CutOffAndCombine (*mesh, othermesh); return TCL_OK; } int Ng_HelmholtzMesh (ClientData clientData, Tcl_Interp * interp, int argc, tcl_const char *argv[]) { HelmholtzMesh (*mesh); return TCL_OK; } int Ng_SetMeshingParameters (ClientData clientData, Tcl_Interp * interp, int argc, tcl_const char *argv[]) { mparam.maxh = atof (Tcl_GetVar (interp, "::options.meshsize", 0)); mparam.minh = atof (Tcl_GetVar (interp, "::options.minmeshsize", 0)); mparam.meshsizefilename = Tcl_GetVar (interp, "::options.meshsizefilename", 0); // if (!strlen (mparam.meshsizefilename)) mparam.meshsizefilename = NULL; mparam.curvaturesafety = atof (Tcl_GetVar (interp, "::options.curvaturesafety", 0)); mparam.segmentsperedge = atof (Tcl_GetVar (interp, "::options.segmentsperedge", 0)); mparam.badellimit = atof (Tcl_GetVar (interp, "::options.badellimit", 0)); mparam.secondorder = atoi (Tcl_GetVar (interp, "::options.secondorder", 0)); mparam.elementorder = atoi (Tcl_GetVar (interp, "::options.elementorder", 0)); mparam.quad = atoi (Tcl_GetVar (interp, "::options.quad", 0)); mparam.try_hexes = atoi (Tcl_GetVar (interp, "::options.try_hexes", 0)); mparam.inverttets = atoi (Tcl_GetVar (interp, "::options.inverttets", 0)); mparam.inverttrigs = atoi (Tcl_GetVar (interp, "::options.inverttrigs", 0)); mparam.uselocalh = atoi (Tcl_GetVar (interp, "::options.localh", 0)); mparam.grading = atof (Tcl_GetVar (interp, "::options.grading", 0)); mparam.delaunay = atoi (Tcl_GetVar (interp, "::options.delaunay", 0)); mparam.checkoverlap = atoi (Tcl_GetVar (interp, "::options.checkoverlap", 0)); mparam.checkoverlappingboundary = atoi (Tcl_GetVar (interp, "::options.checkoverlappingboundary", 0)); mparam.checkchartboundary = atoi (Tcl_GetVar (interp, "::options.checkchartboundary", 0)); mparam.optsteps3d = atoi (Tcl_GetVar (interp, "::options.optsteps3d", 0)); mparam.optsteps2d = atoi (Tcl_GetVar (interp, "::options.optsteps2d", 0)); mparam.opterrpow = atof (Tcl_GetVar (interp, "::options.opterrpow", 0)); mparam.parthread = atoi (Tcl_GetVar (interp, "::options.parthread", 0)); mparam.elsizeweight = atof (Tcl_GetVar (interp, "::options.elsizeweight", 0)); mparam.autozrefine = atoi (Tcl_GetVar (interp, "::options.autozrefine", 0)); // extern int printmessage_importance; extern int printdots; printmessage_importance = atoi (Tcl_GetVar (interp, "::options.printmsg", 0)); printdots = (printmessage_importance >= 4); mparam.parallel_meshing = atoi (Tcl_GetVar (interp, "::options.parallel_meshing", 0)); mparam.nthreads = atoi (Tcl_GetVar (interp, "::options.nthreads", 0)); if(atoi(Tcl_GetVar (interp, "::stloptions.resthcloseedgeenable", 0))) mparam.closeedgefac = atof(Tcl_GetVar (interp, "::stloptions.resthcloseedgefac", 0)); else mparam.closeedgefac = {}; //BaseMoveableMem::totalsize = 0; // 1048576 * atoi (Tcl_GetVar (interp, "::options.memory", 0)); if (mesh) { mesh->SetGlobalH (mparam.maxh); mesh->SetMinimalH (mparam.minh); } #ifdef PARALLELGL MyMPI_SendCmd ("bcastparthread"); MyMPI_Bcast (mparam.parthread, MPI_COMM_WORLD); #endif return TCL_OK; } int Ng_SetDebugParameters (ClientData clientData, Tcl_Interp * interp, int argc, tcl_const char *argv[]) { debugparam.slowchecks = atoi (Tcl_GetVar (interp, "::debug.slowchecks", 0)); debugparam.debugoutput = atoi (Tcl_GetVar (interp, "::debug.debugoutput", 0)); debugparam.haltexistingline = atoi (Tcl_GetVar (interp, "::debug.haltexistingline", 0)); debugparam.haltoverlap = atoi (Tcl_GetVar (interp, "::debug.haltoverlap", 0)); debugparam.haltsuccess = atoi (Tcl_GetVar (interp, "::debug.haltsuccess", 0)); debugparam.haltnosuccess = atoi (Tcl_GetVar (interp, "::debug.haltnosuccess", 0)); debugparam.haltlargequalclass = atoi (Tcl_GetVar (interp, "::debug.haltlargequalclass", 0)); debugparam.haltsegment = atoi (Tcl_GetVar (interp, "::debug.haltsegment", 0)); debugparam.haltnode = atoi (Tcl_GetVar (interp, "::debug.haltnode", 0)); debugparam.haltface = atoi (Tcl_GetVar (interp, "::debug.haltface", 0)); debugparam.haltsegmentp1 = atoi (Tcl_GetVar (interp, "::debug.haltsegmentp1", 0)); debugparam.haltsegmentp2 = atoi (Tcl_GetVar (interp, "::debug.haltsegmentp2", 0)); debugparam.haltfacenr = atoi (Tcl_GetVar (interp, "::debug.haltfacenr", 0)); return TCL_OK; } int Ng_SetCommandLineParameter (ClientData clientData, Tcl_Interp * interp, int argc, tcl_const char *argv[]) { if (argc != 2) { Tcl_SetResult (interp, (char*)"Ng_SetCommandLineParameter needs 1 parameter", TCL_STATIC); return TCL_ERROR; } if (argv[1][0] == '-') parameters.SetCommandLineFlag (argv[1]); else { if (strstr(argv[1], ".py")) parameters.SetFlag ("py", argv[1]); else parameters.SetFlag ("geofile", argv[1]); } return TCL_OK; } int Ng_GetCommandLineParameter (ClientData clientData, Tcl_Interp * interp, int argc, tcl_const char *argv[]) { if (argc != 2) { Tcl_SetResult (interp, (char*)"Ng_GetCommandLineParameter needs 1 parameter", TCL_STATIC); return TCL_ERROR; } static char buf[10]; if (parameters.StringFlagDefined (argv[1])) Tcl_SetResult (interp, const_cast(parameters.GetStringFlag (argv[1], NULL).c_str()), TCL_VOLATILE); else if (parameters.NumFlagDefined (argv[1])) { snprintf (buf, size(buf), "%lf", parameters.GetNumFlag (argv[1], 0)); Tcl_SetResult (interp, buf, TCL_STATIC); } else if (parameters.GetDefineFlag (argv[1])) Tcl_SetResult (interp, (char*)"defined", TCL_STATIC); else Tcl_SetResult (interp, (char*)"undefined", TCL_STATIC); return TCL_OK; } static int perfstepsstart; static int perfstepsend; static char* optstring = NULL; static char* optstringcsg = NULL; void * MeshingDummy (void *) { const char * savetask = multithread.task; multithread.task = "Generate Mesh"; ResetTime(); try { #ifdef LOG_STREAM (*logout) << "Start meshing" << endl; (*logout) << "Meshing parameters:" << endl; mparam.Print (*logout); #endif #ifdef ACIS if (acisgeometry) { ACISGenerateMesh(*acisgeometry, mesh.Ptr(), perfstepsstart, perfstepsend, optstring); } else #endif if (ng_geometry) { if (perfstepsstart == 1) { mesh = make_shared (); // vsmesh.SetMesh (mesh); SetGlobalMesh (mesh); mesh -> SetGeometry(ng_geometry); } if(!mesh) throw Exception("Need existing global mesh"); mparam.perfstepsstart = perfstepsstart; mparam.perfstepsend = perfstepsend; if(optstring) mparam.optimize3d = *optstring; int res = ng_geometry -> GenerateMesh (mesh, mparam); if (res != MESHING3_OK) { multithread.task = savetask; multithread.running = 0; return 0; } } else if (mesh) { if(perfstepsstart > 1 && perfstepsstart < 5) throw Exception("Need geometry for surface mesh operations!"); MeshVolume(mparam, *mesh); OptimizeVolume(mparam, *mesh); return 0; } else // no ng_geometry { multithread.task = savetask; multithread.running = 0; return 0; } if (mparam.autozrefine) { ZRefinementOptions opt; opt.minref = 5; ZRefinement (*mesh, ng_geometry.get(), opt); mesh -> SetNextMajorTimeStamp(); } if (mparam.secondorder) { const_cast (mesh->GetGeometry()->GetRefinement()).MakeSecondOrder (*mesh); mesh -> SetNextMajorTimeStamp(); } if (mparam.elementorder > 1) { mesh -> GetCurvedElements().BuildCurvedElements (&const_cast (mesh->GetGeometry()->GetRefinement()), mparam.elementorder); mesh -> SetNextMajorTimeStamp(); } PrintMessage (1, "Meshing done, time = ", GetTime(), " sec"); } catch (const NgException & e) { cout << e.What() << endl; } multithread.task = savetask; multithread.running = 0; #ifdef OCCGEOMETRYorig // currently not active OCCGeometry * occgeometry = dynamic_cast (ng_geometry); if (occgeometry && occgeometry->ErrorInSurfaceMeshing()) { char script[] = "rebuildoccdialog"; Tcl_GlobalEval (tcl_interp, script); } #endif return NULL; } int MeshingVal(tcl_const char* str) { if (strcmp(str, "ag") == 0) {return MESHCONST_ANALYSE;} if (strcmp(str, "me") == 0) {return MESHCONST_MESHEDGES;} if (strcmp(str, "ms") == 0) {return MESHCONST_MESHSURFACE;} if (strcmp(str, "os") == 0) {return MESHCONST_OPTSURFACE;} if (strcmp(str, "mv") == 0) {return MESHCONST_MESHVOLUME;} if (strcmp(str, "ov") == 0) {return MESHCONST_OPTVOLUME;} cout << "TCL TK ERROR, wrong meshing value, return='" << str << "'" << endl; return 0; } int Ng_GenerateMesh (ClientData clientData, Tcl_Interp * interp, int argc, tcl_const char *argv[]) { if (multithread.running) { Tcl_SetResult (interp, err_jobrunning, TCL_STATIC); return TCL_ERROR; } multithread.running = 1; multithread.terminate = 0; extern void Render(bool blocking); mparam.render_function = &Render; for (auto loader : GeometryRegister()) loader -> SetParameters (interp); Ng_SetMeshingParameters (clientData, interp, 0, argv); perfstepsstart = 1; perfstepsend = 6; if (optstringcsg) delete optstringcsg; optstringcsg = NULL; if (optstring) delete optstring; optstring = NULL; if (argc == 2) { perfstepsstart = 1; perfstepsend = MeshingVal(argv[1]); } else if (argc == 3) { perfstepsstart = MeshingVal(argv[1]); perfstepsend = MeshingVal(argv[2]); } else if (argc == 4) { perfstepsstart = MeshingVal(argv[1]); perfstepsend = MeshingVal(argv[2]); optstring = new char[strlen(argv[3])+1]; strcpy(optstring, argv[3]); optstringcsg = new char[strlen(argv[3])+1]; strcpy(optstringcsg, argv[3]); } RunParallel (MeshingDummy, NULL); return TCL_OK; } int Ng_StopMeshing (ClientData clientData, Tcl_Interp * interp, int argc, tcl_const char *argv[]) { multithread.terminate = 1; return TCL_OK; } int Ng_MeshInfo (ClientData clientData, Tcl_Interp * interp, int argc, tcl_const char *argv[]) { if (!mesh) { Tcl_SetResult (interp, err_needsmesh, TCL_STATIC); return TCL_ERROR; } ostringstream str; if (argc >= 2 && strcmp (argv[1], "dim") == 0) str << mesh->GetDimension(); else if (argc >= 2 && strcmp (argv[1], "np") == 0) str << mesh->GetNP(); else if (argc >= 2 && strcmp (argv[1], "ne") == 0) str << mesh->GetNE(); else if (argc >= 2 && strcmp (argv[1], "nse") == 0) str << mesh->GetNSE(); else if (argc >= 2 && strcmp (argv[1], "nseg") == 0) str << mesh->GetNSeg(); else if (argc >= 2 && strcmp (argv[1], "bbox") == 0) { Point3d pmin, pmax; mesh->GetBox (pmin, pmax); str << pmin.X() << " " << pmax.X() << " " << pmin.Y() << " " << pmax.Y() << " " << pmin.Z() << " " << pmax.Z() << endl; } else { cout << "argv[1] = " << argv[1] << endl; Tcl_SetResult (interp, (char*)"Ng_MeshInfo requires an argument out of \n dim np ne", TCL_STATIC); return TCL_ERROR; } Tcl_SetResult (interp, (char*)str.str().c_str(), TCL_VOLATILE); return TCL_OK; } int Ng_MeshQuality (ClientData clientData, Tcl_Interp * interp, int argc, tcl_const char *argv[]) { if (!mesh) { Tcl_SetResult (interp, err_needsmesh, TCL_STATIC); return TCL_ERROR; } if (multithread.running) { Tcl_SetResult (interp, err_jobrunning, TCL_STATIC); return TCL_ERROR; } double angles[4]; char buf[10]; if (mesh) mesh->CalcMinMaxAngle(mparam.badellimit, angles); else { angles[0] = angles[1] = angles[2] = angles[3] = 0; } snprintf (buf, size(buf), "%5.1lf", angles[0]); Tcl_SetVar (interp, argv[1], buf, 0); snprintf (buf, size(buf), "%5.1lf", angles[1]); Tcl_SetVar (interp, argv[2], buf, 0); snprintf (buf, size(buf), "%5.1lf", angles[2]); Tcl_SetVar (interp, argv[3], buf, 0); snprintf (buf, size(buf), "%5.1lf", angles[3]); Tcl_SetVar (interp, argv[4], buf, 0); return TCL_OK; } int Ng_CheckSurfaceMesh (ClientData clientData, Tcl_Interp * interp, int argc, tcl_const char *argv[]) { if (!mesh) { Tcl_SetResult (interp, err_needsmesh, TCL_STATIC); return TCL_ERROR; } if (multithread.running) { Tcl_SetResult (interp, err_jobrunning, TCL_STATIC); return TCL_ERROR; } mesh->FindOpenElements(); if (mesh->CheckConsistentBoundary()) { PrintMessage (1, "surface mesh not consistent, trying orientation"); mesh->SurfaceMeshOrientation(); } else { PrintMessage (1, "surface mesh consistent"); } mesh->CheckOverlappingBoundary(); return TCL_OK; } int Ng_CheckVolumeMesh (ClientData clientData, Tcl_Interp * interp, int argc, tcl_const char *argv[]) { if (!mesh) { Tcl_SetResult (interp, err_needsmesh, TCL_STATIC); return TCL_ERROR; } if (multithread.running) { Tcl_SetResult (interp, err_jobrunning, TCL_STATIC); return TCL_ERROR; } mesh->CheckVolumeMesh(); return TCL_OK; } int Ng_DeleteVolMesh (ClientData clientData, Tcl_Interp * interp, int argc, tcl_const char *argv[]) { if (mesh) mesh->ClearVolumeElements(); return TCL_OK; } int Ng_SplitSeparatedFaces (ClientData clientData, Tcl_Interp * interp, int argc, tcl_const char *argv[]) { if (mesh) mesh->SplitSeparatedFaces (); return TCL_OK; } int Ng_RestrictH (ClientData clientData, Tcl_Interp * interp, int argc, tcl_const char *argv[]) { if (!mesh) { Tcl_SetResult (interp, err_needsmesh, TCL_STATIC); return TCL_ERROR; } if (multithread.running) { Tcl_SetResult (interp, err_jobrunning, TCL_STATIC); return TCL_ERROR; } if (argc != 3) return TCL_OK; if (!mesh) return TCL_OK; double loch = atof (argv[2]); if (strcmp (argv[1], "face") == 0) { cout << "Restrict h at face to " << loch << endl; mesh -> RestrictLocalH (RESTRICTH_FACE, vsmesh.SelectedFace(), loch); } if (strcmp (argv[1], "edge") == 0) { cout << "Restrict h at edge to " << loch << endl; mesh -> RestrictLocalH (RESTRICTH_EDGE, vsmesh.SelectedEdge(), loch); } if (strcmp (argv[1], "point") == 0) { cout << "Restrict h at point to " << loch << endl; mesh -> RestrictLocalH (RESTRICTH_POINT, vsmesh.SelectedPoint(), loch); } return TCL_OK; } int Ng_Anisotropy (ClientData clientData, Tcl_Interp * interp, int argc, tcl_const char *argv[]) { if (!mesh) { Tcl_SetResult (interp, err_needsmesh, TCL_STATIC); return TCL_ERROR; } if (multithread.running) { Tcl_SetResult (interp, err_jobrunning, TCL_STATIC); return TCL_ERROR; } if (argc != 2) return TCL_OK; if (!mesh) return TCL_OK; if (strcmp (argv[1], "edge") == 0) { int edgenr = vsmesh.SelectedEdge(); for (int i = 1; i <= mesh->GetNSeg(); i++) { Segment & seg = mesh->LineSegment(i); if (seg.edgenr == edgenr) { seg.singedge_left = 1 - seg.singedge_left; seg.singedge_right = 1 - seg.singedge_right; } } } return TCL_OK; } BisectionOptions biopt; void * BisectDummy (void *) { const Refinement & ref = mesh->GetGeometry()->GetRefinement(); MeshOptimize2d * opt = NULL; /* #ifdef ACIS 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); } */ if(!mesh->LocalHFunctionGenerated()) mesh->CalcLocalH(mparam.grading); mesh->LocalHFunction().SetGrading (mparam.grading); ref . Bisect (*mesh, biopt); mesh -> UpdateTopology(); mesh -> GetCurvedElements().BuildCurvedElements (&ref, mparam.elementorder); multithread.running = 0; delete opt; return NULL; } int Ng_Bisect (ClientData clientData, Tcl_Interp * interp, int argc, tcl_const char *argv[]) { if (!mesh) { Tcl_SetResult (interp, err_needsmesh, TCL_STATIC); return TCL_ERROR; } if (multithread.running) { Tcl_SetResult (interp, err_jobrunning, TCL_STATIC); return TCL_ERROR; } if (multithread.running) { cout << "Thread alrad running" << endl; return TCL_OK; } multithread.running = 1; biopt.outfilename = NULL; // "ngfepp.vol"; biopt.femcode = "fepp"; biopt.refinementfilename = NULL; if (argc >= 2) biopt.refinementfilename = argv[1]; BisectDummy (0); /* extern void BisectTets (Mesh &, const CSGeometry *); BisectTets (*mesh, geometry); */ return TCL_OK; } // int Ng_BisectCopyMesh (ClientData clientData, // Tcl_Interp * interp, // int argc, tcl_const char *argv[]) // { // if (!mesh) // { // Tcl_SetResult (interp, err_needsmesh, TCL_STATIC); // return TCL_ERROR; // } // if (multithread.running) // { // Tcl_SetResult (interp, err_jobrunning, TCL_STATIC); // return TCL_ERROR; // } // BisectTetsCopyMesh (*mesh, geometry.Ptr(), biopt); // return TCL_OK; // } int Ng_Split2Tets (ClientData clientData, Tcl_Interp * interp, int argc, tcl_const char *argv[]) { if (!mesh) { Tcl_SetResult (interp, err_needsmesh, TCL_STATIC); return TCL_ERROR; } if (multithread.running) { Tcl_SetResult (interp, err_jobrunning, TCL_STATIC); return TCL_ERROR; } mesh->Split2Tets (); return TCL_OK; } extern int Ng_MeshDoctor (ClientData clientData, Tcl_Interp * interp, int argc, tcl_const char *argv[]); SymbolTable & GetVisualizationScenes () { static SymbolTable vss; return vss; } void AddVisualizationScene (const string & name, VisualScene * avs) { GetVisualizationScenes().Set (name.c_str(), avs); } void SetVisualScene (Tcl_Interp * interp) { const char * vismode = vispar.selectvisual; // Tcl_GetVar (interp, "selectvisual", 0); VisualScene *& vs = visual_scene; vs = &visual_scene_cross; if (GetVisualizationScenes().Used(vismode)) { vs = GetVisualizationScenes()[vismode]; } else if (vismode) { if (strcmp (vismode, "geometry") == 0) { for (auto loader : GeometryRegister()) { VisualScene * hvs = loader->GetVisualScene (ng_geometry.get()); if (hvs) { vs = hvs; return; } } #ifdef ACIS else if (acisgeometry) vs = &vsacisgeom; #endif // ACIS } if (strcmp (vismode, "mesh") == 0) { if (!meshdoctor.active) vs = &vsmesh; else vs = &vsmeshdoc; } if (strcmp (vismode, "surfmeshing") == 0) vs = &vssurfacemeshing; if (strcmp (vismode, "specpoints") == 0) vs = &vsspecpoints; if (strcmp (vismode, "solution") == 0) vs = &netgen::GetVSSolution(); } } Font * font = nullptr; Togl * togl = NULL; void MyOpenGLText_GUI (const char * text) { glListBase (font->getDisplayListsBase()); glCallLists (GLsizei(strlen(text)), GL_UNSIGNED_BYTE, text); } static int Ng_ToglVersion(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { Tcl_SetResult (interp, (char*)"2", TCL_STATIC); return TCL_OK; } static int init(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { // cout << "call init" << endl; if (Togl_GetToglFromObj(interp, objv[1], &togl) != TCL_OK) return TCL_ERROR; // possible values: 12,14,16,18,20,22,24,28,32 font = selectFont(18); LoadOpenGLFunctionPointers(); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); SetVisualScene (Togl_Interp(togl)); visual_scene->DrawScene(); Set_OpenGLText_Callback (&MyOpenGLText_GUI, font->Width()); return TCL_OK; } static int zap(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { return TCL_OK; } static int draw(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { SetVisualScene (interp); glPushMatrix(); glLoadIdentity(); visual_scene->DrawScene(); Togl_SwapBuffers(togl); glPopMatrix(); return TCL_OK; } static int reshape(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { int w = Togl_Width (togl); int h = Togl_Height (togl); // glViewport(0, 0, w, h); int res[4]; glGetIntegerv(GL_VIEWPORT, res); // cout << "w = " << w << " h = " << h << endl; w = res[2]; h = res[3]; /* cout << "viewport: " << res[0] << " " << res[1] << " " << res[2] << " " << res[3] << endl; */ // change font size according to window width font = selectFont(w/80); glMatrixMode(GL_PROJECTION); glLoadIdentity(); // OpenGL near and far clipping planes double pnear = 0.1; double pfar = 10; gluPerspective(20.0f, double(w) / h, pnear, pfar); glMatrixMode(GL_MODELVIEW); return TCL_OK; } static int Ng_SnapShot(ClientData clientData, Tcl_Interp *interp, int argc, Tcl_Obj *const *argv) { struct Togl *togl; if (Togl_GetToglFromObj(interp, argv[1], &togl) != TCL_OK) return TCL_ERROR; const char * filename = Tcl_GetString(argv[2]); int w = Togl_PixelScale(togl)*Togl_Width (togl); int h = Togl_PixelScale(togl)*Togl_Height (togl); NgArray buffer(w*h*3); glPixelStorei(GL_UNPACK_ALIGNMENT,1); glPixelStorei(GL_PACK_ALIGNMENT,1); glReadPixels (0, 0, w, h, GL_RGB, GL_UNSIGNED_BYTE, &buffer[0]); #ifdef JPEGLIB int len = strlen(filename); if (strcmp ("jpg", filename+len-3) == 0) { cout << "Snapshot to file '" << filename << "'" << endl; struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; FILE *outfile = fopen(filename,"wb"); JSAMPROW row_pointer[1]; int row_stride, quality = 100; // 1...100 cinfo.err = jpeg_std_error( &jerr ); jpeg_create_compress( &cinfo ); jpeg_stdio_dest( &cinfo, outfile ); cinfo.image_width = w; cinfo.image_height = h; cinfo.input_components = 3; cinfo.in_color_space = JCS_RGB; jpeg_set_defaults( &cinfo ); jpeg_set_quality( &cinfo, quality, FALSE ); // TRUE jpeg_start_compress( &cinfo, TRUE ); row_stride = 3*w; while( cinfo.next_scanline < cinfo.image_height ) { row_pointer[0] = &buffer[ (h-1-cinfo.next_scanline) * row_stride ]; (void)jpeg_write_scanlines( &cinfo, row_pointer, 1 ); } jpeg_finish_compress( &cinfo ); fclose( outfile ); jpeg_destroy_compress( &cinfo ); fprintf( stdout, "done [ok]\n" ); fflush( stdout ); return TCL_OK; } #endif // JPEGLIB { string command; std::filesystem::path filepath(filename); bool need_conversion = filepath.extension() != ".ppm"; if (need_conversion) filepath += ".ppm"; cout << IM(3) << "Snapshot to file '" << filepath.string() << endl; ofstream outfile(filepath); outfile << "P6" << endl << "# CREATOR: Netgen" << endl << w << " " << h << endl << "255" << endl; for (int i = 0; i < h; i++) for (int j = 0; j < w; j++) for (int k = 0; k < 3; k++) outfile.put (buffer[k+3*j+3*w*(h-i-1)]); outfile << flush; if (need_conversion) { // convert image file (Unix/Linux only): command = string("convert -quality 100 ") + filepath.string() + " " + filename; int err = system(command.c_str()); if (err != 0) { Tcl_SetResult (Togl_Interp(togl), (char*)"Cannot convert image file, stored as .ppm", TCL_VOLATILE); return TCL_ERROR; } std::filesystem::remove(filepath); } return TCL_OK; } } #ifdef FFMPEG static int Ng_VideoClip(ClientData clientData, Tcl_Interp *interp, int argc, Tcl_Obj *const *argv) { static Mpeg mpeg; struct Togl *togl; if (Togl_GetToglFromObj(interp, argv[1], &togl) != TCL_OK) return TCL_ERROR; if (strcmp (Tcl_GetString(argv[2]), "init") == 0) { // Can't initialize when running: //------------------------------- if( mpeg.IsStarted() ) { cout << "cannot initialize: already running" << endl; return TCL_ERROR; } const char * filename = Tcl_GetString(argv[3]); mpeg.Start(filename); return TCL_OK; } else if (strcmp (Tcl_GetString(argv[2]), "addframe") == 0) { if(mpeg.AddFrame()) return TCL_ERROR; } else if (strcmp (Tcl_GetString(argv[2]), "finalize") == 0) { mpeg.Stop(); } return TCL_OK; } #else // FFMPEG static int Ng_VideoClip(ClientData clientData, Tcl_Interp *interp, int argc, Tcl_Obj *const *argv) { Tcl_SetResult (Togl_Interp(togl), (char*)"Video not available, Netgen was not compiled with FFMPEG library", TCL_STATIC); return TCL_ERROR; } #endif // FFMPEG int Ng_MouseMove (ClientData clientData, Tcl_Interp * interp, int argc, tcl_const char *argv[]) { int oldx, oldy; int newx, newy; oldx = atoi (argv[1]); oldy = atoi (argv[2]); newx = atoi (argv[3]); newy = atoi (argv[4]); SetVisualScene(interp); visual_scene->MouseMove (oldx, oldy, newx, newy, argv[5][0]); return TCL_OK; } int Ng_MouseDblClick (ClientData clientData, Tcl_Interp * interp, int argc, tcl_const char *argv[]) { int px = Togl_PixelScale(togl)*atoi (argv[1]); int py = Togl_PixelScale(togl)*atoi (argv[2]); SetVisualScene(interp); visual_scene->MouseDblClick (px, py); return TCL_OK; } int Ng_ZoomAll (ClientData clientData, Tcl_Interp * interp, int argc, tcl_const char *argv[]) { SetVisualScene(interp); visual_scene->BuildScene (1); return TCL_OK; } int Ng_Center (ClientData clientData, Tcl_Interp * interp, int argc, tcl_const char *argv[]) { SetVisualScene(interp); visual_scene->BuildScene (2); return TCL_OK; } int Ng_StandardRotation (ClientData clientData, Tcl_Interp * interp, int argc, tcl_const char *argv[]) { SetVisualScene(interp); visual_scene->StandardRotation (argv[1]); return TCL_OK; } int Ng_ArbitraryRotation (ClientData clientData, Tcl_Interp * interp, int argc, tcl_const char *argv[]) { SetVisualScene(interp); NgArray alpha; NgArray vec; for(int i=1; iArbitraryRotation (alpha,vec); return TCL_OK; } int Ng_Metis (ClientData clientData, Tcl_Interp * interp, int argc, tcl_const char *argv[]) { #ifdef PARALLEL if (!mesh) { Tcl_SetResult (interp, err_needsmesh, TCL_STATIC); return TCL_ERROR; } int nparts = atoi (argv[1]); ntasks = nparts+1; cout << "calling metis ... " << flush; mesh->ParallelMetis(ntasks); cout << "done" << endl; ntasks = 1; // for (ElementIndex ei = 0; ei < mesh->GetNE(); ei++) // (*mesh)[ei].SetIndex ( (*mesh)[ei].GetPartition() ); return TCL_OK; #else Tcl_SetResult (interp, (char*)"metis not available", TCL_STATIC); return TCL_ERROR; #endif #ifdef OLDOLD // METIS Partitioning if (mesh->GetDimension() == 3) { using namespace metis; int ne = mesh->GetNE(); if (ne < 3) { Tcl_SetResult (interp, "This operation needs a volume mesh", TCL_STATIC); return TCL_ERROR; } int nn = mesh->GetNP(); ELEMENT_TYPE elementtype = mesh->VolumeElement(1).GetType(); int npe = mesh->VolumeElement(1).GetNP(); for (int i = 2; i<=ne; i++) if (mesh->VolumeElement(i).GetType() != elementtype) { Tcl_SetResult (interp, "Works in 3D only uniformal tet or hex meshes", TCL_STATIC); return TCL_ERROR; } idxtype *elmnts; elmnts = new idxtype[ne*npe]; int etype; if (elementtype == TET) etype = 2; else if (elementtype == HEX) etype = 3; else { Tcl_SetResult (interp, "Works in 3D only uniformal tet or hex meshes", TCL_STATIC); return TCL_ERROR; } for (int i=1; i<=ne; i++) for (int j=1; j<=npe; j++) elmnts[(i-1)*npe+(j-1)] = mesh->VolumeElement(i).PNum(j)-1; int numflag = 0; int nparts = atoi (argv[1]); int edgecut; idxtype *epart, *npart; epart = new idxtype[ne]; npart = new idxtype[nn]; cout << "Starting Metis (" << ne << " Elements, " << nn << " Nodes, " << nparts << " Partitions) ... " << flush; METIS_PartMeshNodal (&ne, &nn, elmnts, &etype, &numflag, &nparts, &edgecut, epart, npart); cout << "done" << endl; cout << "edge-cut: " << edgecut << ", balance: " << ComputeElementBalance(ne, nparts, epart) << endl; for (int i=1; i<=ne; i++) mesh->VolumeElement(i).SetPartition(epart[i-1]); mesh->SetNextTimeStamp(); } #endif return TCL_OK; } void SelectFaceInOCCDialogTree (int facenr) { char script[50]; snprintf (script, size(script), "selectentity {Face %i}", facenr); Tcl_GlobalEval (tcl_interp, script); } #ifndef ACIS int Ng_ACISCommand (ClientData clientData, Tcl_Interp * interp, int argc, tcl_const char *argv[]) { if (argc >= 2) { if (strcmp (argv[1], "isACISavailable") == 0) { Tcl_SetResult (interp, (char*)"no", TCL_STATIC); return TCL_OK; } } Tcl_SetResult (interp, (char*)"undefined ACiS command", TCL_STATIC); return TCL_ERROR; } #endif // from ng_interface void Ng_SetVisualizationParameter (const char * name, const char * value) { // #ifdef OPENGL // #ifndef NOTCL char buf[100]; snprintf (buf, size(buf), "visoptions.%s", name); if (printmessage_importance>0) { cout << "name = " << name << ", value = " << value << endl; cout << "set tcl-variable " << buf << " to " << value << endl; } Tcl_SetVar (tcl_interp, buf, const_cast (value), 0); Tcl_Eval (tcl_interp, "Ng_Vis_Set parameters;"); // #endif // #endif } } using namespace netgen; void Ng_SetMouseEventHandler (netgen::MouseEventHandler * handler) { vsmesh.SetMouseEventHandler (handler); } void Ng_SetUserVisualizationObject (netgen::UserVisualizationObject * vis) { netgen::GetVSSolution().AddUserVisualizationObject (vis); } namespace netgen { int firsttime = 1; int animcnt = 0; void PlayAnimFile(const char* name, int speed, int maxcnt) { //extern Mesh * mesh; /* if (mesh) mesh->DeleteMesh(); if (!mesh) mesh = new Mesh(); */ mesh = make_shared(); int ne, np, i; char str[80]; char str2[80]; //int tend = 5000; // for (ti = 1; ti <= tend; ti++) //{ int rti = (animcnt%(maxcnt-1)) + 1; animcnt+=speed; snprintf(str2, sizeof(str2), "%05i.sol",rti); strcpy(str,"mbssol/"); strcat(str,name); strcat(str,str2); if (printmessage_importance>0) cout << "read file '" << str << "'" << endl; ifstream infile(str); infile >> ne; for (i = 1; i <= ne; i++) { int j; Element2d tri(TRIG); tri.SetIndex(1); //faceind for (j = 1; j <= 3; j++) infile >> tri.PNum(j); infile >> np; for (i = 1; i <= np; i++) { Point3d p; infile >> p.X() >> p.Y() >> p.Z(); if (firsttime) mesh->AddPoint (p); else mesh->Point(i) = Point<3> (p); } //firsttime = 0; Ng_Redraw(); } } int Ng_SetVisParameters (ClientData clientData, Tcl_Interp * interp, int argc, tcl_const char *argv[]) { if (!Tcl_GetVar (interp, "::viewoptions.light.amb", TCL_GLOBAL_ONLY)) return TCL_ERROR; vispar.lightamb = atof (Tcl_GetVar (interp, "::viewoptions.light.amb", TCL_GLOBAL_ONLY)); vispar.lightdiff = atof (Tcl_GetVar (interp, "::viewoptions.light.diff", TCL_GLOBAL_ONLY)); vispar.lightspec = atof (Tcl_GetVar (interp, "::viewoptions.light.spec", TCL_GLOBAL_ONLY)); vispar.shininess = atof (Tcl_GetVar (interp, "::viewoptions.mat.shininess", TCL_GLOBAL_ONLY)); vispar.locviewer = atoi (Tcl_GetVar (interp, "::viewoptions.light.locviewer", TCL_GLOBAL_ONLY)); vispar.transp = atof (Tcl_GetVar (interp, "::viewoptions.mat.transp", TCL_GLOBAL_ONLY)); VisualizationParameters::Clipping hclip; hclip.normal.X() = atof (Tcl_GetVar (interp, "::viewoptions.clipping.nx", TCL_GLOBAL_ONLY)); hclip.normal.Y() = atof (Tcl_GetVar (interp, "::viewoptions.clipping.ny", TCL_GLOBAL_ONLY)); hclip.normal.Z() = atof (Tcl_GetVar (interp, "::viewoptions.clipping.nz", TCL_GLOBAL_ONLY)); hclip.dist = atof (Tcl_GetVar (interp, "::viewoptions.clipping.dist", TCL_GLOBAL_ONLY)); hclip.dist2 = atof (Tcl_GetVar (interp, "::viewoptions.clipping.dist2", TCL_GLOBAL_ONLY)); hclip.enable = atoi (Tcl_GetVar (interp, "::viewoptions.clipping.enable", TCL_GLOBAL_ONLY)); vispar.clipdomain = atoi (Tcl_GetVar (interp, "::viewoptions.clipping.onlydomain", TCL_GLOBAL_ONLY)); vispar.donotclipdomain = atoi (Tcl_GetVar (interp, "::viewoptions.clipping.notdomain", TCL_GLOBAL_ONLY)); if ( ! (hclip == vispar.clipping) ) { vispar.clipping = hclip; vispar.clipping.timestamp = NextTimeStamp(); } vispar.whitebackground = atoi (Tcl_GetVar (interp, "::viewoptions.whitebackground", TCL_GLOBAL_ONLY)); vispar.drawcoordinatecross = atoi (Tcl_GetVar (interp, "::viewoptions.drawcoordinatecross", TCL_GLOBAL_ONLY)); vispar.drawcolorbar = atoi (Tcl_GetVar (interp, "::viewoptions.drawcolorbar", TCL_GLOBAL_ONLY)); vispar.drawnetgenlogo = atoi (Tcl_GetVar (interp, "::viewoptions.drawnetgenlogo", TCL_GLOBAL_ONLY)); vispar.stereo = atoi (Tcl_GetVar (interp, "::viewoptions.stereo", TCL_GLOBAL_ONLY)); vispar.colormeshsize = atoi (Tcl_GetVar (interp, "::viewoptions.colormeshsize", TCL_GLOBAL_ONLY)); VisualScene :: SetBackGroundColor (vispar.whitebackground ? 1 : 0); strcpy (vispar.selectvisual, Tcl_GetVar (interp, "::selectvisual", TCL_GLOBAL_ONLY)); // vispar.showstltrias = atoi (Tcl_GetVar (interp, "::viewoptions.stl.showtrias", TCL_GLOBAL_ONLY)); vispar.stlshowtrias = atoi (Tcl_GetVar (interp, "::stloptions.showtrias", TCL_GLOBAL_ONLY)); vispar.stlshowfilledtrias = atoi (Tcl_GetVar (interp, "::stloptions.showfilledtrias", TCL_GLOBAL_ONLY)); vispar.stlshowedges = atoi (Tcl_GetVar (interp, "::stloptions.showedges", TCL_GLOBAL_ONLY)); vispar.stlshowmarktrias = atoi (Tcl_GetVar (interp, "::stloptions.showmarktrias", TCL_GLOBAL_ONLY)); vispar.stlshowactivechart = atoi (Tcl_GetVar (interp, "::stloptions.showactivechart", TCL_GLOBAL_ONLY)); vispar.stlchartnumber = atoi (Tcl_GetVar (interp, "::stloptions.chartnumber", TCL_GLOBAL_ONLY)); vispar.stlchartnumberoffset = atoi (Tcl_GetVar (interp, "::stloptions.chartnumberoffset", TCL_GLOBAL_ONLY)); vispar.occshowsurfaces = atoi (Tcl_GetVar (interp, "::occoptions.showsurfaces", TCL_GLOBAL_ONLY)); vispar.occshowedges = atoi (Tcl_GetVar (interp, "::occoptions.showedges", TCL_GLOBAL_ONLY)); vispar.drawoutline = atoi (Tcl_GetVar (interp, "::viewoptions.drawoutline", TCL_GLOBAL_ONLY)); vispar.drawfilledtrigs = atoi (Tcl_GetVar (interp, "::viewoptions.drawfilledtrigs", TCL_GLOBAL_ONLY)); vispar.subdivisions = atoi (Tcl_GetVar (interp, "::visoptions.subdivisions", TCL_GLOBAL_ONLY)); vispar.drawbadels = atoi (Tcl_GetVar (interp, "::viewoptions.drawbadels", TCL_GLOBAL_ONLY)); vispar.drawedges = atoi (Tcl_GetVar (interp, "::viewoptions.drawedges", TCL_GLOBAL_ONLY)); vispar.drawtetsdomain = atoi (Tcl_GetVar (interp, "::viewoptions.drawtetsdomain", TCL_GLOBAL_ONLY)); vispar.drawtets = atoi (Tcl_GetVar (interp, "::viewoptions.drawtets", TCL_GLOBAL_ONLY)); vispar.drawprisms = atoi (Tcl_GetVar (interp, "::viewoptions.drawprisms", TCL_GLOBAL_ONLY)); vispar.drawpyramids = atoi (Tcl_GetVar (interp, "::viewoptions.drawpyramids", TCL_GLOBAL_ONLY)); vispar.drawhexes = atoi (Tcl_GetVar (interp, "::viewoptions.drawhexes", TCL_GLOBAL_ONLY)); /* vispar.shrink = atof (Tcl_GetVar (interp, "::viewoptions.shrink", TCL_GLOBAL_ONLY)); */ double hshrink = atof (Tcl_GetVar (interp, "::viewoptions.shrink", TCL_GLOBAL_ONLY)); if (hshrink != vispar.shrink) { vispar.shrink = hshrink; vispar.clipping.timestamp = NextTimeStamp();} vispar.drawidentified = atoi (Tcl_GetVar (interp, "::viewoptions.drawidentified", TCL_GLOBAL_ONLY)); vispar.drawpointnumbers = atoi (Tcl_GetVar (interp, "::viewoptions.drawpointnumbers", TCL_GLOBAL_ONLY)); vispar.drawedgenumbers = atoi (Tcl_GetVar (interp, "::viewoptions.drawedgenumbers", TCL_GLOBAL_ONLY)); vispar.drawfacenumbers = atoi (Tcl_GetVar (interp, "::viewoptions.drawfacenumbers", TCL_GLOBAL_ONLY)); vispar.drawelementnumbers = atoi (Tcl_GetVar (interp, "::viewoptions.drawelementnumbers", TCL_GLOBAL_ONLY)); vispar.drawsurfaceelementnumbers = atoi (Tcl_GetVar (interp, "::viewoptions.drawsurfaceelementnumbers", TCL_GLOBAL_ONLY)); vispar.drawsegmentnumbers = atoi (Tcl_GetVar (interp, "::viewoptions.drawsegmentnumbers", TCL_GLOBAL_ONLY)); vispar.drawdomainsurf = atoi (Tcl_GetVar (interp, "::viewoptions.drawdomainsurf", TCL_GLOBAL_ONLY)); vispar.drawededges = atoi (Tcl_GetVar (interp, "::viewoptions.drawededges", TCL_GLOBAL_ONLY)); vispar.drawedpoints = atoi (Tcl_GetVar (interp, "::viewoptions.drawedpoints", TCL_GLOBAL_ONLY)); vispar.drawedpointnrs = atoi (Tcl_GetVar (interp, "::viewoptions.drawedpointnrs", TCL_GLOBAL_ONLY)); vispar.drawedtangents = atoi (Tcl_GetVar (interp, "::viewoptions.drawedtangents", TCL_GLOBAL_ONLY)); vispar.drawededgenrs = atoi (Tcl_GetVar (interp, "::viewoptions.drawededgenrs", TCL_GLOBAL_ONLY)); vispar.drawcurveproj = atoi (Tcl_GetVar (interp, "::viewoptions.drawcurveproj", TCL_GLOBAL_ONLY)); vispar.drawcurveprojedge = atoi (Tcl_GetVar (interp, "::viewoptions.drawcurveprojedge", TCL_GLOBAL_ONLY)); vispar.centerpoint = atoi (Tcl_GetVar (interp, "::viewoptions.centerpoint", TCL_GLOBAL_ONLY)); vispar.use_center_coords = atoi (Tcl_GetVar (interp, "::viewoptions.usecentercoords", TCL_GLOBAL_ONLY)) > 0; vispar.centerx = atof (Tcl_GetVar (interp, "::viewoptions.centerx", TCL_GLOBAL_ONLY)); vispar.centery = atof (Tcl_GetVar (interp, "::viewoptions.centery", TCL_GLOBAL_ONLY)); vispar.centerz = atof (Tcl_GetVar (interp, "::viewoptions.centerz", TCL_GLOBAL_ONLY)); vispar.drawelement = atoi (Tcl_GetVar (interp, "::viewoptions.drawelement", TCL_GLOBAL_ONLY)); vispar.drawmetispartition = atoi (Tcl_GetVar (interp, "::viewoptions.drawmetispartition", TCL_GLOBAL_ONLY)); vispar.drawspecpoint = atoi (Tcl_GetVar (interp, "::viewoptions.drawspecpoint", TCL_GLOBAL_ONLY)); vispar.specpointx = atof (Tcl_GetVar (interp, "::viewoptions.specpointx", TCL_GLOBAL_ONLY)); vispar.specpointy = atof (Tcl_GetVar (interp, "::viewoptions.specpointy", TCL_GLOBAL_ONLY)); vispar.specpointz = atof (Tcl_GetVar (interp, "::viewoptions.specpointz", TCL_GLOBAL_ONLY)); vsspecpoints.len = atof (Tcl_GetVar (interp, "::viewoptions.specpointvlen", TCL_GLOBAL_ONLY)); vispar.occdeflection = pow(10.0,-1-atof (Tcl_GetVar (interp, "::occoptions.deflection", TCL_GLOBAL_ONLY))); #ifdef PARALLELGL vsmesh.Broadcast (); #endif return TCL_OK; } int Ng_BuildFieldLines (ClientData clientData, Tcl_Interp * interp, int argc, tcl_const char *argv[]) { netgen::GetVSSolution().BuildFieldLinesPlot(); return TCL_OK; } int Ng_Exit (ClientData clientData, Tcl_Interp * interp, int argc, tcl_const char *argv[]) { /* #ifdef PARALLEL int id, rc, ntasks; MPI_Comm_size(MPI_COMM_WORLD, &ntasks); MPI_Comm_rank(MPI_COMM_WORLD, &id); if ( id != 0 ) return TCL_OK; #endif */ /* if (ngsolve_handle) { void (*ngs_exit)(); ngs_exit = ( void (*)() ) dlsym (ngsolve_handle, "NGSolve_Exit"); if (ngs_exit) (*ngs_exit)(); } */ #ifdef NGSOLVE NGSolve_Exit (); #endif #ifdef ACIS outcome res; res = api_terminate_faceter(); if(!res.ok()) cerr << "problem with terminating acis faceter" << endl; res = api_terminate_constructors(); if(!res.ok()) cerr << "problem with terminating acis constructors" << endl; res = api_terminate_kernel(); if(!res.ok()) cerr << "problem with terminating acis kernel" << endl; res = api_stop_modeller(); if(!res.ok()) cerr << "problem with terminating acis modeller" << endl; //cout << "stopped acis, outcome = " << res.ok() << endl; #endif #ifdef PARALLELGL if (id == 0) MyMPI_SendCmd ("end"); MPI_Finalize(); #endif mesh.reset(); ng_geometry.reset(); if (testout != &cout) delete testout; return TCL_OK; } #ifdef SOCKETS void * ServerSocketManagerRunDummy ( void * nix ) { serversocketmanager.Run(); return NULL; } extern "C" int Ng_ServerSocketManagerRun( void ); int Ng_ServerSocketManagerRun( void ) { if(mparam.parthread) RunParallel(ServerSocketManagerRunDummy,NULL); else serversocketmanager.Run(); return TCL_OK; } extern "C" int Ng_ServerSocketManagerInit(int port); int Ng_ServerSocketManagerInit(int port) { serversocketmanager.Init(port); return TCL_OK; } #endif //SOCKETS extern "C" int Ng_Init (Tcl_Interp * interp); extern "C" int Ng_CSG_Init (Tcl_Interp * interp); extern "C" int Ng_stl_Init (Tcl_Interp * interp); extern "C" int Ng_geom2d_Init (Tcl_Interp * interp); #ifdef OCCGEOMETRY extern "C" int Ng_occ_Init (Tcl_Interp * interp); #endif // extern "C" int Ng_Geom2d_Init (Tcl_Interp * interp); // int main_Eero (ClientData clientData, // Tcl_Interp * interp, // int argc, tcl_const char *argv[]); int Ng_Init (Tcl_Interp * interp) { #ifdef SOCKETS if(serversocketmanager.Good()) serversocketusernetgen.Reset(new ServerSocketUserNetgen (serversocketmanager, mesh, geometry)); #endif Ng_CSG_Init(interp); Ng_stl_Init(interp); Ng_geom2d_Init (interp); #ifdef OCCGEOMETRY Ng_occ_Init (interp); #endif // Ng_Geom2d_Init(interp); tcl_interp = interp; // Tcl_CreateCommand (interp, "Ng_Eero", main_Eero, // (ClientData)NULL, // (Tcl_CmdDeleteProc*) NULL); Tcl_CreateCommand (interp, "Ng_New", Ng_New, (ClientData)NULL, (Tcl_CmdDeleteProc*) NULL); // Tcl_CreateCommand (interp, "Ng_Lock", Ng_Lock, // (ClientData)NULL, // (Tcl_CmdDeleteProc*) NULL); Tcl_CreateCommand (interp, "Ng_LoadGeometry", Ng_LoadGeometry, (ClientData)NULL, (Tcl_CmdDeleteProc*) NULL); Tcl_CreateCommand (interp, "Ng_SaveGeometry", Ng_SaveGeometry, (ClientData)NULL, (Tcl_CmdDeleteProc*) NULL); Tcl_CreateCommand (interp, "Ng_LoadMesh", Ng_LoadMesh, (ClientData)NULL, (Tcl_CmdDeleteProc*) NULL); Tcl_CreateCommand (interp, "Ng_SaveMesh", Ng_SaveMesh, (ClientData)NULL, (Tcl_CmdDeleteProc*) NULL); Tcl_CreateCommand (interp, "Ng_MergeMesh", Ng_MergeMesh, (ClientData)NULL, (Tcl_CmdDeleteProc*) NULL); Tcl_CreateCommand (interp, "Ng_GetImportFormats", Ng_GetImportFormats, (ClientData)NULL, (Tcl_CmdDeleteProc*) NULL); Tcl_CreateCommand (interp, "Ng_GetExportFormats", Ng_GetExportFormats, (ClientData)NULL, (Tcl_CmdDeleteProc*) NULL); Tcl_CreateCommand (interp, "Ng_ExportMesh", Ng_ExportMesh, (ClientData)NULL, (Tcl_CmdDeleteProc*) NULL); Tcl_CreateCommand (interp, "Ng_ImportMesh", Ng_ImportMesh, (ClientData)NULL, (Tcl_CmdDeleteProc*) NULL); Tcl_CreateCommand (interp, "Ng_ImportSolution", Ng_ImportSolution, (ClientData)NULL, (Tcl_CmdDeleteProc*) NULL); Tcl_CreateCommand (interp, "Ng_ShowDemo", Ng_ShowDemo, (ClientData)NULL, (Tcl_CmdDeleteProc*) NULL); Tcl_CreateCommand (interp, "Ng_DemoSetTime", Ng_DemoSetTime, (ClientData)NULL, (Tcl_CmdDeleteProc*) NULL); Tcl_CreateCommand (interp, "Ng_SaveSolution", Ng_SaveSolution, (ClientData)NULL, (Tcl_CmdDeleteProc*) NULL); // meshing Tcl_CreateCommand (interp, "Ng_GenerateMesh", Ng_GenerateMesh, (ClientData)NULL, (Tcl_CmdDeleteProc*) NULL); Tcl_CreateCommand (interp, "Ng_StopMeshing", Ng_StopMeshing, (ClientData)NULL, (Tcl_CmdDeleteProc*) NULL); Tcl_CreateCommand (interp, "Ng_MeshInfo", Ng_MeshInfo, (ClientData)NULL, (Tcl_CmdDeleteProc*) NULL); Tcl_CreateCommand (interp, "Ng_MeshQuality", Ng_MeshQuality, (ClientData)NULL, (Tcl_CmdDeleteProc*) NULL); Tcl_CreateCommand (interp, "Ng_CheckSurfaceMesh", Ng_CheckSurfaceMesh, (ClientData)NULL, (Tcl_CmdDeleteProc*) NULL); Tcl_CreateCommand (interp, "Ng_CheckVolumeMesh", Ng_CheckVolumeMesh, (ClientData)NULL, (Tcl_CmdDeleteProc*) NULL); Tcl_CreateCommand (interp, "Ng_DeleteVolMesh", Ng_DeleteVolMesh, (ClientData)NULL, (Tcl_CmdDeleteProc*) NULL); Tcl_CreateCommand (interp, "Ng_SplitSeparatedFaces", Ng_SplitSeparatedFaces, (ClientData)NULL, (Tcl_CmdDeleteProc*) NULL); Tcl_CreateCommand (interp, "Ng_SetNextTimeStamp", Ng_SetNextTimeStamp, (ClientData)NULL, (Tcl_CmdDeleteProc*) NULL); Tcl_CreateCommand (interp, "Ng_Refine", Ng_Refine, (ClientData)NULL, (Tcl_CmdDeleteProc*) NULL); Tcl_CreateCommand (interp, "Ng_SecondOrder", Ng_SecondOrder, (ClientData)NULL, (Tcl_CmdDeleteProc*) NULL); Tcl_CreateCommand (interp, "Ng_HighOrder", Ng_HighOrder, (ClientData)NULL, (Tcl_CmdDeleteProc*) NULL); Tcl_CreateCommand (interp, "Ng_ValidateSecondOrder", Ng_ValidateSecondOrder, (ClientData)NULL, (Tcl_CmdDeleteProc*) NULL); Tcl_CreateCommand (interp, "Ng_RestrictH", Ng_RestrictH, (ClientData)NULL, (Tcl_CmdDeleteProc*) NULL); Tcl_CreateCommand (interp, "Ng_Anisotropy", Ng_Anisotropy, (ClientData)NULL, (Tcl_CmdDeleteProc*) NULL); Tcl_CreateCommand (interp, "Ng_Bisect", Ng_Bisect, (ClientData)NULL, (Tcl_CmdDeleteProc*) NULL); // Tcl_CreateCommand (interp, "Ng_BisectCopyMesh", Ng_BisectCopyMesh, // (ClientData)NULL, // (Tcl_CmdDeleteProc*) NULL); Tcl_CreateCommand (interp, "Ng_Split2Tets", Ng_Split2Tets, (ClientData)NULL, (Tcl_CmdDeleteProc*) NULL); Tcl_CreateCommand (interp, "Ng_ZRefinement", Ng_ZRefinement, (ClientData)NULL, (Tcl_CmdDeleteProc*) NULL); Tcl_CreateCommand (interp, "Ng_HPRefinement", Ng_HPRefinement, (ClientData)NULL, (Tcl_CmdDeleteProc*) NULL); Tcl_CreateCommand (interp, "Ng_LoadMeshSize", Ng_LoadMeshSize, (ClientData)NULL, (Tcl_CmdDeleteProc*) NULL); Tcl_CreateCommand (interp, "Ng_MeshSizeFromSurfaceMesh", Ng_MeshSizeFromSurfaceMesh, (ClientData)NULL, (Tcl_CmdDeleteProc*) NULL); Tcl_CreateCommand (interp, "Ng_GenerateBoundaryLayer", Ng_GenerateBoundaryLayer, (ClientData)NULL, (Tcl_CmdDeleteProc*) NULL); Tcl_CreateCommand (interp, "Ng_InsertVirtualBL", Ng_InsertVirtualBL, (ClientData)NULL, (Tcl_CmdDeleteProc*) NULL); Tcl_CreateCommand (interp, "Ng_CutOffAndCombine", Ng_CutOffAndCombine, (ClientData)NULL, (Tcl_CmdDeleteProc*) NULL); Tcl_CreateCommand (interp, "Ng_HelmholtzMesh", Ng_HelmholtzMesh, (ClientData)NULL, (Tcl_CmdDeleteProc*) NULL); Tcl_CreateCommand (interp, "Ng_ReadStatus", Ng_ReadStatus, (ClientData)NULL, (Tcl_CmdDeleteProc*) NULL); Tcl_CreateCommand (interp, "Ng_MemInfo", Ng_MemInfo, (ClientData)NULL, (Tcl_CmdDeleteProc*) NULL); Tcl_CreateCommand (interp, "Ng_MeshDoctor", Ng_MeshDoctor, (ClientData)NULL, (Tcl_CmdDeleteProc*) NULL); Tcl_CreateCommand (interp, "Ng_BCProp", Ng_BCProp, (ClientData)NULL, (Tcl_CmdDeleteProc*) NULL); Tcl_CreateCommand (interp, "Ng_ACISCommand", Ng_ACISCommand, (ClientData)NULL, (Tcl_CmdDeleteProc*) NULL); Tcl_CreateCommand (interp, "Ng_MouseMove", Ng_MouseMove, (ClientData)NULL, (Tcl_CmdDeleteProc*) NULL); Tcl_CreateCommand (interp, "Ng_MouseDblClick", Ng_MouseDblClick, (ClientData)NULL, (Tcl_CmdDeleteProc*) NULL); Tcl_CreateCommand (interp, "Ng_ZoomAll", Ng_ZoomAll, (ClientData)NULL, (Tcl_CmdDeleteProc*) NULL); Tcl_CreateCommand (interp, "Ng_Center", Ng_Center, (ClientData)NULL, (Tcl_CmdDeleteProc*) NULL); Tcl_CreateCommand (interp, "Ng_StandardRotation", Ng_StandardRotation, (ClientData)NULL, (Tcl_CmdDeleteProc*) NULL); Tcl_CreateCommand (interp, "Ng_ArbitraryRotation", Ng_ArbitraryRotation, (ClientData)NULL, (Tcl_CmdDeleteProc*) NULL); Tcl_CreateCommand (interp, "Ng_SetVisParameters", Ng_SetVisParameters, (ClientData)NULL, (Tcl_CmdDeleteProc*) NULL); Tcl_CreateCommand (interp, "Ng_SetMeshingParameters", Ng_SetMeshingParameters, (ClientData)NULL, (Tcl_CmdDeleteProc*) NULL); Tcl_CreateCommand (interp, "Ng_SetDebugParameters", Ng_SetDebugParameters, (ClientData)NULL, (Tcl_CmdDeleteProc*) NULL); Tcl_CreateCommand (interp, "Ng_SetCommandLineParameter", Ng_SetCommandLineParameter, (ClientData)NULL, (Tcl_CmdDeleteProc*) NULL); Tcl_CreateCommand (interp, "Ng_GetCommandLineParameter", Ng_GetCommandLineParameter, (ClientData)NULL, (Tcl_CmdDeleteProc*) NULL); Tcl_CreateCommand (interp, "Ng_Exit", Ng_Exit, (ClientData)NULL, (Tcl_CmdDeleteProc*) NULL); Tcl_CreateCommand (interp, "Ng_Metis", Ng_Metis, (ClientData)NULL, (Tcl_CmdDeleteProc*) NULL); Tcl_CreateCommand (interp, "Ng_BuildFieldLines", Ng_BuildFieldLines, (ClientData)NULL, (Tcl_CmdDeleteProc*) NULL); /* * Specify the C callback functions for widget creation, display, * and reshape. */ Tcl_CreateObjCommand(interp, "Ng_GetToglVersion", Ng_ToglVersion, NULL, NULL); if (!nodisplay) { if (Togl_Init(interp) == TCL_ERROR) return TCL_ERROR; Tcl_CreateObjCommand(interp, "init", init, NULL, NULL); Tcl_CreateObjCommand(interp, "zap", zap, NULL, NULL); Tcl_CreateObjCommand(interp, "draw", draw, NULL, NULL); Tcl_CreateObjCommand(interp, "reshape", reshape, NULL, NULL); // Togl_TimerFunc( idle ); Tcl_CreateObjCommand(interp, "Ng_SnapShot", Ng_SnapShot, NULL, NULL); Tcl_CreateObjCommand(interp, "Ng_VideoClip", Ng_VideoClip, NULL, NULL); } multithread.pause = 0; multithread.testmode = 0; multithread.redraw = 0; multithread.drawing = 1; multithread.terminate = 0; multithread.running = 0; multithread.task = ""; multithread.percent = 20; Tcl_LinkVar (interp, "multithread_pause", (char*)&multithread.pause, TCL_LINK_INT); Tcl_LinkVar (interp, "multithread_testmode", (char*)&multithread.testmode, TCL_LINK_INT); Tcl_LinkVar (interp, "multithread_redraw", (char*)&multithread.redraw, TCL_LINK_INT); Tcl_LinkVar (interp, "multithread_drawing", (char*)&multithread.drawing, TCL_LINK_INT); Tcl_LinkVar (interp, "multithread_terminate", (char*)&multithread.terminate, TCL_LINK_INT); Tcl_LinkVar (interp, "multithread_running", (char*)&multithread.running, TCL_LINK_INT); //testout->setstate(ios_base::badbit); myerr = &cerr; extern ostream * mycout; mycout = &cout; testmode = 0; #ifdef ACIS outcome res; res = api_start_modeller (0); if(!res.ok()) cerr << "problem with starting acis modeller" << endl; #ifdef ACIS_R17 unlock_spatial_products_661(); #endif res = api_initialize_kernel(); if(!res.ok()) cerr << "problem with starting acis kernel" << endl; res = api_initialize_constructors(); if(!res.ok()) cerr << "problem with starting acis constructors" << endl; res = api_initialize_faceter(); if(!res.ok()) cerr << "problem with starting acis faceter" << endl; #endif return TCL_OK; } } ================================================ FILE: ng/ngshell.tcl ================================================ ## the shell loop proc dotest {} { source ngtest.tcl } proc Ng_RunShell {} { puts "Wellcome to NG Shell mode" set line 1 while { 1 } { puts -nonewline "$line: " flush stdout set cmdline [gets stdin] if { [catch $cmdline errcode] } { # puts "error in command: '$cmdline'" puts "$errcode" } incr line 1 } } ## global list for help index # ---> global var in variables.tcl # set cmdindex {} # set hlpindex {} # set secindex {} # print comd list proc Ng_PrintCmdIndex { } { global cmdindex foreach { lst } $cmdindex { puts $lst } } # print formatted help index proc Ng_PrintHlpIndex { } { global hlpindex global secindex foreach {sec} $secindex { puts "\n * $sec:" foreach {lst} $hlpindex { if {$sec == [lindex $lst 1]} { puts " * [lindex $lst 2]: [lindex $lst 3]" } } } } # register a cmd to the help index proc Ng_RegisterCmd { cmd section syntax {help ""} } { global hlpindex global cmdindex global secindex puts "register command $cmd" if { [lsearch $cmdindex cmd] != -1 } { puts "command '$cmd' already defined" } else { lappend cmdindex $cmd lappend hlpindex [list $cmd $section $syntax $help] if {[lsearch $secindex $section]==-1} { lappend secindex $section } # puts "registered command $cmd" } } # general purpose commands Ng_RegisterCmd "exit" "general" "exit" "exit Netgen shell mode" #Ng_RegisterCmd "Ng_LoadGeometry" "netgen" "Ng_LoadGeometry " "load geometry file" #Ng_RegisterCmd "Ng_ParseGeometry" "netgen" "Ng_ParseGeometry" "parse geometry" #Ng_RegisterCmd "Ng_GenerateMesh" "netgen" "Ng_GenerateMesh" "generate mesh" #Ng_RegisterCmd "Ng_SaveMesh" "netgen" "Ng_SaveMesh " "save mesh to file" ## public domain shell functions # print hel information proc nghelp { {sec ""} } { global secindex global hlpindex global cmdindex if { $sec == "" } { Ng_PrintHlpIndex puts "\n type help 'section'\n" return } if { [lsearch $secindex $sec] != -1} { foreach {lst} $hlpindex { if {[lindex $lst 1] == $sec } { puts " * [lindex $lst 2]: [lindex $lst 3]" } } return } set ind [lsearch $cmdindex $sec] if {$ind != -1} { set lst [lindex $hlpindex $ind] puts " * [lindex $lst 2]: [lindex $lst 3]" return } puts " unknown section or command $sec" } set ngtimer 0 proc nggettimer {} { return [clock clicks -milliseconds] } proc ngtic {} { set ::ngtimer [nggettimer] } proc ngtoc { {logfile stdout} } { set end [nggettimer] set tim [expr ($end - $::ngtimer)/1000.0] puts $logfile "$tim s" } # load geometry file proc ngloadgeometry { fname } { if { ![file exists $fname] } { puts "error: file $fname does not exist" } else { set err [catch {Ng_LoadGeometry $fname}] if {$err != 0} { puts "error: loading geometry failed" } } } Ng_RegisterCmd "ngloadgeometry" "netgen" "ngloadgeometry " "load geometry file" # parse geometry proc ngparsegeometry {} { set err [catch {Ng_ParseGeometry}] if {$err} { puts "error: parsing geometry failed" } } Ng_RegisterCmd "ngparsegeometry" "netgen" "ngparsegeometry" "parse geometry" # generate mesh proc nggeneratemesh {} { set err [catch {Ng_GenerateMesh}] if {$err} { puts "error: mesh generation failed" } } Ng_RegisterCmd "nggeneratemesh" "netgen" "nggeneratemesh" "generate mesh" # save mesh proc ngsavemesh { fname } { if { [file exists $fname]} { puts "warning: existing file $fname overwritten" } else { set err [catch {Ng_SaveMesh $fname}] if {$err != 0} { puts "error: saving mesh failed" } } } Ng_RegisterCmd "ngsavemesh" "netgen" "ngsavemesh " "save mesh to file" #set option proc ngset { opt {val 0} } { if {$opt == "meshsize"} { set ::options.meshsize $val Ng_SetMeshingParameters } elseif {$opt == "printmsg"} { set ::options.printmsg $val Ng_SetMeshingParameters } else { puts "error: unknown option $opt"; } } Ng_RegisterCmd "ngset" "netgen" "ngset

{ newprimitivedialog } ; \n" ,"bind .

{ editprimitivedialog }\n" ,"bind . { newsoliddialog }\n" ,"bind . { .ngmenu.mesh invoke \"Generate Mesh\" } ;\n" ,"}\n" ,"}\n" ,"catch {\n" ,"proc meshingoptionsdialog { } {\n" ,"set w .options_dlg\n" ,"if {[winfo exists .options_dlg] == 1} {\n" ,"wm withdraw $w\n" ,"wm deiconify $w\n" ,"focus $w\n" ,"} {\n" ,"toplevel $w\n" ,"pack [ttk::notebook $w.nb] -fill both -side top\n" ,"$w.nb add [ttk::frame $w.nb.general] -text \"General\" -underline 0\n" ,"$w.nb add [ttk::frame $w.nb.meshsize] -text \"Mesh Size\" -underline 0\n" ,"$w.nb add [ttk::frame $w.nb.chartopt] -text \"STL Charts\" -underline 0\n" ,"$w.nb add [ttk::frame $w.nb.optimizer] -text \"Optimizer\" -underline 0\n" ,"$w.nb add [ttk::frame $w.nb.debug] -text \"Debug\" -underline 0\n" ,"set f $w.nb.general\n" ,"ttk::frame $f.background\n" ,"pack $f.background -fill both\n" ,"set f $f.background\n" ,"ttk::labelframe $f.f2 -relief groove -borderwidth 3 -text \"General meshing options\"\n" ,"pack $f.f2 -pady 15 -fill x\n" ,"set f $f.f2\n" ,"set finevals { 1 2 3 4 5 6 }\n" ,"set finelabs(1) \"very coarse\"\n" ,"set finelabs(2) \"coarse\"\n" ,"set finelabs(3) \"moderate\"\n" ,"set finelabs(4) \"fine\"\n" ,"set finelabs(5) \"very fine\"\n" ,"set finelabs(6) \"user defined\"\n" ,"global meshoptions.fineness\n" ,"ttk::label $f.fine2l -text \"Mesh granularity: \"\n" ,"ttk::menubutton $f.fine2c -menu $f.fine2m -text \"coarse\" -width 16\n" ,"menu $f.fine2m -tearoff 0\n" ,"foreach finev { 1 2 3 4 5 6 } {\n" ,"$f.fine2m add command -label $finelabs($finev) \\\n" ,"-command \"set meshoptions.fineness $finev ; setgranularity $finev; $f.fine2c configure -text \\\"$finelabs($finev)\\\"\"\n" ,"}\n" ,"$f.fine2m invoke $finelabs(${meshoptions.fineness})\n" ,"grid $f.fine2l $f.fine2c -sticky nw\n" ,"set mgsteps { ag me ms os mv ov }\n" ,"set mgsteplabel(ag) \"Analyze Geometry\"\n" ,"set mgsteplabel(me) \"Mesh Edges\"\n" ,"set mgsteplabel(ms) \"Mesh Surface\"\n" ,"set mgsteplabel(os) \"Optimize Surface\"\n" ,"set mgsteplabel(mv) \"Mesh Volume\"\n" ,"set mgsteplabel(ov) \"Optimize Volume\"\n" ,"global meshoptions.firststep\n" ,"ttk::label $f.first2l -text \"First Step: \"\n" ,"ttk::menubutton $f.first2c -menu $f.first2m -width 16\n" ,"menu $f.first2m -tearoff 0\n" ,"foreach i $mgsteps {\n" ,"$f.first2m add command -label $mgsteplabel($i) -command \"set meshoptions.firststep $i ; $f.first2c configure -text \\\"$mgsteplabel($i)\\\"\"\n" ,"}\n" ,"$f.first2m invoke $mgsteplabel(${meshoptions.firststep})\n" ,"grid $f.first2l $f.first2c -sticky nw\n" ,"global meshoptions.laststep\n" ,"ttk::label $f.last2l -text \"Last Step: \"\n" ,"ttk::menubutton $f.last2c -menu $f.last2m -width 16\n" ,"menu $f.last2m -tearoff 0\n" ,"foreach i $mgsteps {\n" ,"$f.last2m add command -label $mgsteplabel($i) -command \"set meshoptions.laststep $i ; $f.last2c configure -text \\\"$mgsteplabel($i)\\\"\"\n" ,"}\n" ,"$f.last2m invoke $mgsteplabel(${meshoptions.laststep})\n" ,"grid $f.last2l $f.last2c -sticky nw\n" ,"grid anchor $f center\n" ,"set msg(0) \"None\"\n" ,"set msg(1) \"Least\"\n" ,"set msg(2) \"Little\"\n" ,"set msg(3) \"Moderate\"\n" ,"set msg(4) \"Much\"\n" ,"set msg(5) \"Most\"\n" ,"global options.printmsg\n" ,"ttk::label $f.msg2l -text \"Print Messages: \"\n" ,"menu $f.msg2m -tearoff 0\n" ,"ttk::menubutton $f.msg2c -menu $f.msg2m -width 16\n" ,"foreach step {0 1 2 3 4 5 } {\n" ,"$f.msg2m add command -label $msg($step) -command \"set options.printmsg $step ; $f.msg2c configure -text $msg($step)\"\n" ,"}\n" ,"$f.msg2m invoke ${options.printmsg}\n" ,"grid $f.msg2l $f.msg2c -sticky nw\n" ,"set f $w.nb.general\n" ,"ttk::labelframe $f.bts -borderwidth 3 -relief groove -text \"Additional meshing options\"\n" ,"pack $f.bts -fill x -pady 15\n" ,"ttk::frame $f.bts.btnframe\n" ,"ttk::checkbutton $f.bts.btnframe.parthread -text \"Separate meshing thread\" \\\n" ,"-variable options.parthread\n" ,"ttk::checkbutton $f.bts.btnframe.second -text \"Second order elements\" \\\n" ,"-variable options.secondorder\n" ,"ttk::checkbutton $f.bts.btnframe.quad -text \"Quad dominated\" \\\n" ,"-variable options.quad -command {\n" ,"if { ${options.quad} } {\n" ,"set meshoptions.laststep os\n" ,"}\n" ,"}\n" ,"ttk::checkbutton $f.bts.btnframe.invtets -text \"Invert volume elements\" \\\n" ,"-variable options.inverttets\n" ,"ttk::checkbutton $f.bts.btnframe.invtrigs -text \"Invert surface elements\" \\\n" ,"-variable options.inverttrigs\n" ,"ttk::checkbutton $f.bts.btnframe.azref -text \"Automatic Z-refinement\" \\\n" ,"-variable options.autozrefine\n" ,"pack $f.bts.btnframe -anchor center\n" ,"pack $f.bts.btnframe.parthread $f.bts.btnframe.second $f.bts.btnframe.quad $f.bts.btnframe.invtets $f.bts.btnframe.invtrigs $f.bts.btnframe.azref -anchor w\n" ,"ttk::frame $f.bts.btnframe.elorder\n" ,"ttk::label $f.bts.btnframe.elorder.l -text \"Element order\"\n" ,"ttk::spinbox $f.bts.btnframe.elorder.elementorder2 -from 1 -to 20 -textvariable options.elementorder -width 2\n" ,"pack $f.bts.btnframe.elorder -fill x\n" ,"pack $f.bts.btnframe.elorder.elementorder2 $f.bts.btnframe.elorder.l -anchor w -side left\n" ,"ttk::frame $f.bts.btnframe.pm\n" ,"ttk::checkbutton $f.bts.btnframe.pm.parallel_meshing -text \"Parallel meshing\" \\\n" ,"-variable options.parallel_meshing\n" ,"pack $f.bts.btnframe.pm -fill x -pady 5\n" ,"pack $f.bts.btnframe.pm.parallel_meshing -anchor w\n" ,"ttk::label $f.bts.btnframe.pm.lnthreads -text \"Number of meshing threads\"\n" ,"ttk::spinbox $f.bts.btnframe.pm.nthreads -from 1 -to 128 -textvariable options.nthreads -width 2\n" ,"pack $f.bts.btnframe.pm.nthreads $f.bts.btnframe.pm.lnthreads -anchor w -side left\n" ,"set f $w.nb.meshsize\n" ,"ttk::frame $f.f2\n" ,"pack $f.f2 -pady 10\n" ,"set f $f.f2\n" ,"ttk::frame $f.meshsize\n" ,"ttk::label $f.meshsize.l -text \"max mesh-size\"\n" ,"ttk::spinbox $f.meshsize.s -from 1e-9 -to 1e9 -textvariable options.meshsize -width 5 -validate focus -validatecommand \"my_validatespinbox %W %P 10\" \\\n" ,"-invalidcommand \"my_invalidspinbox %W\"\n" ,"pack $f.meshsize -fill x\n" ,"pack $f.meshsize.s $f.meshsize.l -side right\n" ,"ttk::frame $f.minmeshsize\n" ,"ttk::label $f.minmeshsize.l -text \"min mesh-size\"\n" ,"ttk::spinbox $f.minmeshsize.s -from 0 -to 1e9 -textvariable options.minmeshsize -width 5 -validate focus -validatecommand \"my_validatespinbox %W %P 10\" \\\n" ,"-invalidcommand \"my_invalidspinbox %W\"\n" ,"pack $f.minmeshsize -fill x\n" ,"pack $f.minmeshsize.s $f.minmeshsize.l -side right\n" ,"ttk::frame $f.grading\n" ,"ttk::label $f.grading.l -text \"mesh-size grading\"\n" ,"ttk::spinbox $f.grading.s -from 0.1 -to 1.0 -textvariable options.grading -width 5 -increment 0.1 -validate focus -validatecommand \"my_validatespinbox %W %P 3\" \\\n" ,"-invalidcommand \"my_invalidspinbox %W\"\n" ,"pack $f.grading -fill x\n" ,"pack $f.grading.s $f.grading.l -side right\n" ,"set f $w.nb.meshsize\n" ,"ttk::labelframe $f.msf -text \"mesh-size file:\" -relief groove -borderwidth 3\n" ,"pack $f.msf\n" ,"ttk::entry $f.msf.ent -textvariable options.meshsizefilename -width 30\n" ,"ttk::button $f.msf.btn -text \"Browse\" -command {\n" ,"global options.meshsizefilename\n" ,"set types {\n" ,"{\"Meshsize file\" {.msz} } }\n" ,"set options.meshsizefilename [tk_getOpenFile -filetypes $types -initialfile ${options.meshsizefilename}]\n" ,"}\n" ,"pack $f.msf.ent -side left -expand yes -fill x -anchor s -padx 4 -pady 4\n" ,"pack $f.msf.btn -side left -anchor s -padx 4 -pady 4\n" ,"ttk::label $f.lab -text \"Additional mesh size restrictions:\"\n" ,"ttk::labelframe $f.csg -relief groove -borderwidth 3 -text \"CSG mesh-size\"\n" ,"pack $f.csg -fill x\n" ,"proc test {a} {puts $a}\n" ,"ttk::scale $f.csg.curvsc -orient horizontal -length 150 -from 0.2 -to 5 \\\n" ,"-variable options.curvaturesafety -takefocus 0 -command \"roundscale $f.csg.curvsc 1\"\n" ,"ttk::entry $f.csg.curve -textvariable options.curvaturesafety -width 3 \\\n" ,"-validatecommand \"my_validate %W [$f.csg.curvsc cget -from] [$f.csg.curvsc cget -to] %P 1\" \\\n" ,"-invalidcommand \"my_invalid %W\" -validate focus\n" ,"ttk::label $f.csg.curvla -text \"Elements per curvature radius\"\n" ,"grid $f.csg.curvsc $f.csg.curve $f.csg.curvla -sticky nw -padx 4\n" ,"ttk::scale $f.csg.elensc -orient horizontal -length 150 -from 0.2 -to 5 \\\n" ,"-variable options.segmentsperedge -takefocus 0 -command \"roundscale $f.csg.elensc 1\"\n" ,"ttk::entry $f.csg.elene -textvariable options.segmentsperedge -width 3 \\\n" ,"-validatecommand \"my_validate %W [$f.csg.elensc cget -from] [$f.csg.elensc cget -to] %P 1\" \\\n" ,"-invalidcommand \"my_invalid %W\" -validate focus\n" ,"ttk::label $f.csg.elenla -text \"Elements per edge\"\n" ,"grid $f.csg.elensc $f.csg.elene $f.csg.elenla -sticky nw -padx 4\n" ,"grid anchor $f.csg center\n" ,"ttk::labelframe $f.stl -relief groove -borderwidth 3 -text \"STL mesh-size\"\n" ,"pack $f.stl -fill x\n" ,"ttk::scale $f.stl.r2sc -orient horizontal -length 150 -from 0.2 -to 5 \\\n" ,"-variable stloptions.resthchartdistfac -takefocus 0 -command \"roundscale $f.stl.r2sc 1\"\n" ,"ttk::entry $f.stl.r2e -textvariable stloptions.resthchartdistfac -width 3 \\\n" ,"-validatecommand \"my_validate %W [$f.stl.r2sc cget -from] [$f.stl.r2sc cget -to] %P 1\" \\\n" ,"-invalidcommand \"my_invalid %W\" -validate focus\n" ,"ttk::checkbutton $f.stl.r2bu -text \"STL - chart distance\" \\\n" ,"-variable stloptions.resthchartdistenable\n" ,"grid $f.stl.r2sc $f.stl.r2e $f.stl.r2bu -sticky nw -padx 4\n" ,"ttk::scale $f.stl.r6sc -orient horizontal -length 150 -from 0.2 -to 5 \\\n" ,"-variable stloptions.resthlinelengthfac -takefocus 0 -command \"roundscale $f.stl.r6sc 1\"\n" ,"ttk::entry $f.stl.r6e -textvariable stloptions.resthlinelengthfac -width 3 \\\n" ,"-validatecommand \"my_validate %W [$f.stl.r6sc cget -from] [$f.stl.r6sc cget -to] %P 1\" \\\n" ,"-invalidcommand \"my_invalid %W\" -validate focus\n" ,"ttk::checkbutton $f.stl.r6bu -text \"STL - line length\" \\\n" ,"-variable stloptions.resthlinelengthenable\n" ,"grid $f.stl.r6sc $f.stl.r6e $f.stl.r6bu -sticky nw -padx 4\n" ,"ttk::scale $f.stl.r3sc -orient horizontal -length 150 -from 0.2 -to 8 \\\n" ,"-variable stloptions.resthcloseedgefac -takefocus 0 -command \"roundscale $f.stl.r3sc 1\"\n" ,"ttk::entry $f.stl.r3e -textvariable stloptions.resthcloseedgefac -width 3 \\\n" ,"-validatecommand \"my_validate %W [$f.stl.r3sc cget -from] [$f.stl.r3sc cget -to] %P 1\" \\\n" ,"-invalidcommand \"my_invalid %W\" -validate focus\n" ,"ttk::checkbutton $f.stl.r3bu -text \"STL/IGES/STEP - close edges\" \\\n" ,"-variable stloptions.resthcloseedgeenable\n" ,"grid $f.stl.r3sc $f.stl.r3e $f.stl.r3bu -sticky nw -padx 4\n" ,"ttk::scale $f.stl.r1sc -orient horizontal -length 150 -from 0.2 -to 5 \\\n" ,"-variable stloptions.resthsurfcurvfac -takefocus 0 -command \"roundscale $f.stl.r1sc 1\"\n" ,"ttk::entry $f.stl.r1e -textvariable stloptions.resthsurfcurvfac -width 3 \\\n" ,"-validatecommand \"my_validate %W [$f.stl.r1sc cget -from] [$f.stl.r1sc cget -to] %P 1\" \\\n" ,"-invalidcommand \"my_invalid %W\" -validate focus\n" ,"ttk::checkbutton $f.stl.r1bu -text \"STL - surface curvature\" \\\n" ,"-variable stloptions.resthsurfcurvenable\n" ,"grid $f.stl.r1sc $f.stl.r1e $f.stl.r1bu -sticky nw -padx 4\n" ,"ttk::scale $f.stl.r3bsc -orient horizontal -length 150 -from 0.2 -to 5 \\\n" ,"-variable stloptions.resthedgeanglefac -takefocus 0 -command \"roundscale $f.stl.r3bsc 1\"\n" ,"ttk::entry $f.stl.r3be -textvariable stloptions.resthedgeanglefac -width 3 \\\n" ,"-validatecommand \"my_validate %W [$f.stl.r3bsc cget -from] [$f.stl.r3bsc cget -to] %P 1\" \\\n" ,"-invalidcommand \"my_invalid %W\" -validate focus\n" ,"ttk::checkbutton $f.stl.r3bbu -text \"STL - edge angle\" \\\n" ,"-variable stloptions.resthedgeangleenable\n" ,"grid $f.stl.r3bsc $f.stl.r3be $f.stl.r3bbu -sticky nw -padx 4\n" ,"ttk::scale $f.stl.r5sc -orient horizontal -length 150 -from 0.2 -to 5 \\\n" ,"-variable stloptions.resthsurfmeshcurvfac -takefocus 0 -command \"roundscale $f.stl.r5sc 1\"\n" ,"ttk::entry $f.stl.r5e -textvariable stloptions.resthsurfmeshcurvfac -width 3 \\\n" ,"-validatecommand \"my_validate %W [$f.stl.r5sc cget -from] [$f.stl.r5sc cget -to] %P 1\" \\\n" ,"-invalidcommand \"my_invalid %W\" -validate focus\n" ,"ttk::checkbutton $f.stl.r5bu -text \"STL - surface mesh curv\" \\\n" ,"-variable stloptions.resthsurfmeshcurvenable\n" ,"grid $f.stl.r5sc $f.stl.r5e $f.stl.r5bu -sticky nw -padx 4\n" ,"ttk::checkbutton $f.stl.recalch -text \"STL - Recalc mesh size for surface optimization\" \\\n" ,"-variable stloptions.recalchopt\n" ,"grid $f.stl.recalch -sticky n -columnspan 3 -column 0\n" ,"ttk::button $f.stl.calch -text \"Calc New H\" -command { redraw; Ng_STLCalcLocalH }\n" ,"grid $f.stl.calch -columnspan 3 -column 0\n" ,"grid anchor $f.stl center\n" ,"proc roundscale {w n_digits args} {\n" ,"set val [$w get]\n" ,"global [$w cget -variable]\n" ,"if {$n_digits == 0 } {\n" ,"set [$w cget -variable] [tcl::mathfunc::round $val]\n" ,"} else {\n" ,"set [$w cget -variable] [format \"%.[append n_digits \"f\"]\" $val]\n" ,"}\n" ,"}\n" ,"global last_accepted_sc\n" ,"proc my_validate {w mini maxi val n_digits} {\n" ,"global last_accepted_sc [$w cget -textvariable]\n" ,"if {[string length $val] == 0} {return 0}\n" ,"if {[string is double $val] == 1} {\n" ,"if { $n_digits == 0 } {\n" ,"set val [tcl::mathfunc::max $mini [tcl::mathfunc::min $maxi [tcl::mathfunc::round $val]]]\n" ,"} else {\n" ,"if { $n_digits < 9 } {\n" ,"set val [tcl::mathfunc::max $mini [tcl::mathfunc::min $maxi [format \"%.[append n_digits \"f\"]\" $val]]]\n" ,"}\n" ,"}\n" ,"set last_accepted_sc $val\n" ,"set [$w cget -textvariable] $val\n" ,"return 1\n" ,"} else {\n" ,"return 0\n" ,"}\n" ,"}\n" ,"proc my_invalid {w} {\n" ,"global last_accepted_sc [$w cget -textvariable]\n" ,"set [$w cget -textvariable] $last_accepted_sc\n" ,"}\n" ,"set f $w.nb.chartopt\n" ,"ttk::labelframe $f.mainframe -text \"STL angles\" -relief groove -borderwidth 3\n" ,"pack $f.mainframe -fill x -pady 15\n" ,"set f $f.mainframe\n" ,"ttk::label $f.labYangles -text \"Yellow Edges Angle ()\"\n" ,"ttk::scale $f.scale1 -orient horizontal -length 150 -from 0 -to 90 -variable stloptions.yangle -takefocus 0 -command \"roundscale $f.scale1 1\"\n" ,"ttk::entry $f.entry1 -textvariable stloptions.yangle -width 5 -validate focus -takefocus 0 -validatecommand \"my_validate %W [$f.scale1 cget -from] [$f.scale1 cget -to] %P 1\" \\\n" ,"-invalidcommand \"my_invalid %W\"\n" ,"grid $f.scale1 $f.entry1 $f.labYangles -sticky nw -padx 4 -pady 6\n" ,"ttk::label $f.labEangles -text \"Edge Corner Angle ()\"\n" ,"ttk::scale $f.scale2 -orient horizontal -length 150 -from 0 -to 180 -variable stloptions.edgecornerangle -takefocus 0 -command \"roundscale $f.scale2 1\"\n" ,"ttk::entry $f.entry2 -textvariable stloptions.edgecornerangle -width 5 -validate focus -takefocus 0 -validatecommand \"my_validate %W [$f.scale2 cget -from] [$f.scale2 cget -to] %P 1\" \\\n" ,"-invalidcommand \"my_invalid %W\"\n" ,"grid $f.scale2 $f.entry2 $f.labEangles -sticky nw -padx 4 -pady 6\n" ,"ttk::label $f.lab31 -text \"Chart Angle ()\"\n" ,"ttk::scale $f.scale3 -orient horizontal -length 150 -from 0 -to 180 -variable stloptions.chartangle -takefocus 0 -command \"roundscale $f.scale3 1\"\n" ,"ttk::entry $f.entry3 -textvariable stloptions.chartangle -width 5 -validate focus -takefocus 0 -validatecommand \"my_validate %W [$f.scale3 cget -from] [$f.scale3 cget -to] %P 1\" \\\n" ,"-invalidcommand \"my_invalid %W\"\n" ,"grid $f.scale3 $f.entry3 $f.lab31 -sticky nw -padx 4 -pady 6\n" ,"ttk::label $f.lab41 -text \"Outer Chart Angle ()\"\n" ,"ttk::scale $f.scale4 -orient horizontal -length 150 -from 0 -to 180 -variable stloptions.outerchartangle -takefocus 0 -command \"roundscale $f.scale4 1\"\n" ,"ttk::entry $f.entry4 -textvariable stloptions.outerchartangle -width 5 -validate focus -takefocus 0 -validatecommand \"my_validate %W [$f.scale4 cget -from] [$f.scale4 cget -to] %P 1\" \\\n" ,"-invalidcommand \"my_invalid %W\"\n" ,"grid $f.scale4 $f.entry4 $f.lab41 -sticky nw -padx 4 -pady 6\n" ,"grid anchor $f center\n" ,"global last_accepted_sp\n" ,"proc my_validatespinbox {w val n_digits} {\n" ,"global last_accepted_sp\n" ,"if {[string length $val] == 0} {return 0}\n" ,"if {[string is double $val] == 1} {\n" ,"if { $n_digits == 0 } {\n" ,"if { $n_digits < 9 } {\n" ,"set val [tcl::mathfunc::round $val] } else { set val [format \"%.[append n_digits \"f\"]\" $val]\n" ,"}\n" ,"}\n" ,"$w set [tcl::mathfunc::max [$w cget -from] [tcl::mathfunc::min [$w cget -to] $val]]\n" ,"set last_accepted_sp $val\n" ,"return 1\n" ,"} else {\n" ,"return 0\n" ,"}\n" ,"}\n" ,"proc my_invalidspinbox {w} {\n" ,"global last_accepted_sp\n" ,"$w set $last_accepted_sp\n" ,"}\n" ,"set f $w.nb.optimizer\n" ,"ttk::labelframe $f.optframe -text \"Optimization settings\" -relief groove -borderwidth 3\n" ,"pack $f.optframe -fill x -pady 15\n" ,"ttk::label $f.optframe.sosl -text \"Surface opt steps\"\n" ,"ttk::spinbox $f.optframe.soss -from 0 -to 99 -textvariable options.optsteps2d -width 5 -increment 1 -validate focus -validatecommand \"my_validatespinbox %W %P 0\" \\\n" ,"-invalidcommand \"my_invalidspinbox %W\"\n" ,"grid $f.optframe.sosl $f.optframe.soss -sticky nw;\n" ,"ttk::label $f.optframe.vosl -text \"Volume opt steps\"\n" ,"ttk::spinbox $f.optframe.voss -from 0 -to 99 -textvariable options.optsteps3d -width 5 -increment 1 -validate focus -validatecommand \"my_validatespinbox %W %P 0\" \\\n" ,"-invalidcommand \"my_invalidspinbox %W\"\n" ,"grid $f.optframe.vosl $f.optframe.voss -sticky nw;\n" ,"ttk::label $f.optframe.eswl -text \"Element size weight\"\n" ,"ttk::spinbox $f.optframe.esws -from 0 -to 1 -textvariable options.elsizeweight -width 5 -increment 0.1 -validate focus -validatecommand \"my_validatespinbox %W %P 1\" \\\n" ,"-invalidcommand \"my_invalidspinbox %W\"\n" ,"grid $f.optframe.eswl $f.optframe.esws -sticky nw;\n" ,"ttk::label $f.optframe.weml -text \"Worst element measure\"\n" ,"ttk::spinbox $f.optframe.wems -from 1 -to 10 -textvariable options.opterrpow -width 5 -increment 1 -validate focus -validatecommand \"my_validatespinbox %W %P 0\" \\\n" ,"-invalidcommand \"my_invalidspinbox %W\"\n" ,"grid $f.optframe.weml $f.optframe.wems -sticky nw;\n" ,"grid anchor $f.optframe center\n" ,"proc roundscale_helper_osx {w val} {\n" ,"global [$w cget -variable] options.badellimit\n" ,"set [$w cget -variable] [tcl::mathfunc::round $val]\n" ,"set options.badellimit [expr [tcl::mathfunc::round $val]+160]\n" ,"}\n" ,"proc my_validate_helper_osx {w val} {\n" ,"if {[string length $val] == 0} {return 0}\n" ,"if {[string is double $val] == 1} {\n" ,"set scale_loc [lindex [winfo children [winfo parent $w]] [lsearch [winfo children [winfo parent $w]] *scale]]\n" ,"global [$scale_loc cget -variable] options.badellimit\n" ,"set [$scale_loc cget -variable] [tcl::mathfunc::max [$scale_loc cget -from] [tcl::mathfunc::min [$scale_loc cget -to] [expr [tcl::mathfunc::round $val]-160]]]\n" ,"set options.badellimit [tcl::mathfunc::max [expr [$scale_loc cget -from]+160] [tcl::mathfunc::min [expr [$scale_loc cget -to]+160] [tcl::mathfunc::round $val]]]\n" ,"return 1\n" ,"} else {\n" ,"return 0\n" ,"}\n" ,"}\n" ,"proc my_invalid_helper_osx {w} {\n" ,"global options.badellimit\n" ,"set scale_loc [lindex [winfo children [winfo parent $w]] [lsearch [winfo children [winfo parent $w]] *scale]]\n" ,"global [$scale_loc cget -variable]\n" ,"set [$scale_loc cget -variable] [tcl::mathfunc::round [$scale_loc get]]\n" ,"set options.badellimit [expr [tcl::mathfunc::round [$scale_loc get]]+160]\n" ,"}\n" ,"global dummy_badellimit\n" ,"set dummy_badellimit 15\n" ,"ttk::labelframe $f.optframe2 -text \"Bad elements\" -relief groove -borderwidth 3\n" ,"pack $f.optframe2 -fill x -pady 15 -ipady 5\n" ,"ttk::frame $f.optframe2.badellimit\n" ,"ttk::label $f.optframe2.lab -text \"bad element criterion\";\n" ,"ttk::scale $f.optframe2.scale -orient horizontal -length 100 -from 00 -to 20 -variable dummy_badellimit -takefocus 0 -command \"roundscale_helper_osx $f.optframe2.scale\"\n" ,"ttk::entry $f.optframe2.entry -textvariable options.badellimit -width 3 -validate focusout -takefocus 0 -validatecommand \"my_validate_helper_osx %W %P\" \\\n" ,"-invalidcommand \"my_invalid_helper_osx %W\"\n" ,"grid $f.optframe2.scale $f.optframe2.entry $f.optframe2.lab -padx 4 -sticky nw\n" ,"grid anchor $f.optframe2 center\n" ,"set f $w.nb.debug\n" ,"ttk::labelframe $f.f2 -text \"Advanced options\" -borderwidth 3 -relief groove\n" ,"pack $f.f2 -fill x -pady 15\n" ,"set f $f.f2\n" ,"ttk::checkbutton $f.localh -text \"Use Local Meshsize\" \\\n" ,"-variable options.localh\n" ,"ttk::checkbutton $f.delauney -text \"Use Delaunay\" \\\n" ,"-variable options.delaunay\n" ,"ttk::checkbutton $f.checkoverlap -text \"Check Overlapping\" \\\n" ,"-variable options.checkoverlap\n" ,"ttk::checkbutton $f.checkcb -text \"Check Chart Boundary\" \\\n" ,"-variable options.checkchartboundary\n" ,"ttk::checkbutton $f.blockfill -text \"Do Blockfilling\" \\\n" ,"-variable options.blockfill\n" ,"grid $f.localh $f.delauney -sticky nw\n" ,"grid $f.checkoverlap $f.blockfill -sticky nw\n" ,"grid $f.checkcb -sticky nw\n" ,"grid anchor $f center\n" ,"set f $w.nb.debug\n" ,"proc enable_cb {w1 w2 w3} {\n" ,"Ng_SetDebugParameters\n" ,"if {[string match *selected* [$w1 state]] == 1 } {\n" ,"$w2 configure -state normal\n" ,"$w3 configure -state normal\n" ,"} else {\n" ,"$w2 configure -state disabled\n" ,"$w3 configure -state disabled\n" ,"}\n" ,"}\n" ,"ttk::labelframe $f.cb1 -text \"Debugging options\" -borderwidth 3 -relief groove\n" ,"pack $f.cb1 -fill x -pady 15\n" ,"ttk::checkbutton $f.cb1.slowchecks -text \"Slow checks\" \\\n" ,"-variable debug.slowchecks -command { Ng_SetDebugParameters }\n" ,"ttk::checkbutton $f.cb1.debugoutput -text \"Debugging output\" \\\n" ,"-variable debug.debugoutput -command { Ng_SetDebugParameters }\n" ,"ttk::checkbutton $f.cb1.haltexline -text \"Halt on existing line\" \\\n" ,"-variable debug.haltexistingline -command { Ng_SetDebugParameters }\n" ,"ttk::checkbutton $f.cb1.haltoverlap -text \"Halt on Overlap\" \\\n" ,"-variable debug.haltoverlap -command { Ng_SetDebugParameters }\n" ,"ttk::checkbutton $f.cb1.haltsuc -text \"Halt on success\" \\\n" ,"-variable debug.haltsuccess -command { Ng_SetDebugParameters }\n" ,"ttk::checkbutton $f.cb1.haltnosuc -text \"Halt on no success\" \\\n" ,"-variable debug.haltnosuccess -command { Ng_SetDebugParameters }\n" ,"ttk::checkbutton $f.cb1.haltlargequal -text \"Halt on large quality class\" \\\n" ,"-variable debug.haltlargequalclass -command { Ng_SetDebugParameters }\n" ,"ttk::checkbutton $f.cb1.haltseg -text \"Halt on Segment:\" \\\n" ,"-variable debug.haltsegment -command { Ng_SetDebugParameters }\n" ,"ttk::checkbutton $f.cb1.haltnode -text \"Halt on Node:\" \\\n" ,"-variable debug.haltnode -command { Ng_SetDebugParameters }\n" ,"ttk::frame $f.cb1.fr\n" ,"ttk::checkbutton $f.cb1.fr.cb -text \"Halt on Face:\" \\\n" ,"-variable debug.haltface -command { Ng_SetDebugParameters }\n" ,"ttk::entry $f.cb1.fr.ent -textvariable debug.haltfacenr -width 3\n" ,"pack $f.cb1.fr.cb $f.cb1.fr.ent -side left\n" ,"ttk::frame $f.cb1.segs\n" ,"ttk::label $f.cb1.segs.lab1 -text \"P1:\"\n" ,"ttk::entry $f.cb1.segs.ent1 -width 6 \\\n" ,"-textvariable debug.haltsegmentp1\n" ,"ttk::label $f.cb1.segs.lab2 -text \"P2:\"\n" ,"ttk::entry $f.cb1.segs.ent2 -width 6 \\\n" ,"-textvariable debug.haltsegmentp2\n" ,"pack $f.cb1.segs.lab1 $f.cb1.segs.ent1 $f.cb1.segs.lab2 $f.cb1.segs.ent2 -side left\n" ,"grid $f.cb1.slowchecks $f.cb1.debugoutput -sticky nw\n" ,"grid $f.cb1.haltexline $f.cb1.haltoverlap -sticky nw\n" ,"grid $f.cb1.haltsuc $f.cb1.haltnosuc -sticky nw\n" ,"grid $f.cb1.haltlargequal $f.cb1.fr -sticky nw\n" ,"grid $f.cb1.haltnode -sticky nw\n" ,"grid $f.cb1.haltseg -stick nw\n" ,"grid $f.cb1.segs -stick w -row 4 -rowspan 2 -column 1\n" ,"grid rowconfigure $f.cb1 3 -pad 8\n" ,"grid anchor $f.cb1 center\n" ,"ttk::checkbutton $f.cb1.showactivechart -text \"Show Active Meshing-Chart\" -variable stloptions.showactivechart -command { Ng_SetVisParameters; redraw }\n" ,"grid $f.cb1.showactivechart\n" ,"grid rowconfigure $f.cb1 3 -pad 8\n" ,"grid rowconfigure $f.cb1 5 -pad 8\n" ,"set f $w.nb.debug\n" ,"ttk::labelframe $f.cont -relief groove -borderwidth 3 -text \"Debugging visualization\"\n" ,"pack $f.cont -fill x -pady 15\n" ,"ttk::checkbutton $f.cont.multidrawing -text \"Draw Meshing\" -variable multithread_drawing\n" ,"ttk::checkbutton $f.cont.multitestmode -text \"Meshing Testmode\" -variable multithread_testmode\n" ,"ttk::button $f.cont.goon -text \"Go On\" -command { set multithread_pause 0 }\n" ,"grid $f.cont.multidrawing -sticky nw\n" ,"grid $f.cont.multitestmode -sticky nw\n" ,"grid $f.cont.goon -row 0 -rowspan 2 -column 1 -sticky w\n" ,"grid columnconfigure $f.cont 0 -pad 30\n" ,"grid columnconfigure $f.cont 1 -pad 20\n" ,"grid anchor $f.cont center\n" ,"global userlevel\n" ,"if { $userlevel < 3} {\n" ,"$w.nb delete insider\n" ,"$w.nb delete debug\n" ,"}\n" ,"ttk::frame $w.bu\n" ,"pack $w.bu -fill x -ipady 3\n" ,"ttk::button $w.bu.apl -text \"Apply\" -command {\n" ,"Ng_SetMeshingParameters\n" ,"Ng_SetDebugParameters\n" ,"}\n" ,"ttk::button $w.bu.ok -text \"Done\" -command {\n" ,"Ng_SetMeshingParameters\n" ,"Ng_SetDebugParameters\n" ,"wm withdraw .options_dlg\n" ,"}\n" ,"pack $w.bu.apl $w.bu.ok -side left -expand yes\n" ,"wm withdraw $w\n" ,"wm geom $w +100+100\n" ,"wm deiconify $w\n" ,"wm title $w \"Meshing Options\"\n" ,"focus .options_dlg\n" ,"}\n" ,"}\n" ,"meshingoptionsdialog\n" ,"wm withdraw .options_dlg\n" ,"proc viewingoptionsdialog { } {\n" ,"global userlevel\n" ,"set w .viewopts_dlg\n" ,"if {[winfo exists .viewopts_dlg] == 1} {\n" ,"wm withdraw $w\n" ,"wm deiconify $w\n" ,"focus $w\n" ,"} {\n" ,"toplevel $w\n" ,"pack [ttk::notebook $w.nb] -fill both -fill both -side top\n" ,"$w.nb add [ttk::frame $w.nb.general] -text \"General\" -underline 0\n" ,"$w.nb add [ttk::frame $w.nb.stl] -text \"STL\" -underline 0\n" ,"$w.nb add [ttk::frame $w.nb.occ] -text \"IGES/STEP\" -underline 0\n" ,"$w.nb add [ttk::frame $w.nb.mesh] -text \"Mesh\" -underline 0\n" ,"$w.nb add [ttk::frame $w.nb.light] -text \"Light\" -underline 0\n" ,"$w.nb add [ttk::frame $w.nb.edges] -text \"Edges\" -underline 0\n" ,"$w.nb add [ttk::frame $w.nb.misc] -text \"Misc.\" -underline 3\n" ,"set f $w.nb.general\n" ,"ttk::labelframe $f.gvop -text \"General viewing options\" -relief groove -borderwidth 3\n" ,"pack $f.gvop -fill x -pady 15\n" ,"set f $f.gvop\n" ,"ttk::checkbutton $f.backcol -text \"White Background\" \\\n" ,"-variable viewoptions.whitebackground \\\n" ,"-command { Ng_SetVisParameters; redraw }\n" ,"ttk::checkbutton $f.cross -text \"Draw Coordinate Cross\" \\\n" ,"-variable viewoptions.drawcoordinatecross \\\n" ,"-command { Ng_SetVisParameters; redraw }\n" ,"ttk::checkbutton $f.color -text \"Draw Color-bar\" \\\n" ,"-variable viewoptions.drawcolorbar \\\n" ,"-command { Ng_SetVisParameters; redraw }\n" ,"ttk::checkbutton $f.netgen -text \"Draw Netgen-logo\" \\\n" ,"-variable viewoptions.drawnetgenlogo \\\n" ,"-command { Ng_SetVisParameters; redraw }\n" ,"grid $f.backcol -sticky nw\n" ,"grid $f.cross -stick nw\n" ,"grid $f.color -sticky nw\n" ,"grid $f.netgen -sticky nw\n" ,"menu $f.stylemenu\n" ,"ttk::menubutton $f.style -menu $f.stylemenu -width 10 -text [ttk::style theme use]\n" ,"grid $f.style -sticky nw\n" ,"grid anchor $f center\n" ,"foreach theme [ttk::themes] {\n" ,"$f.stylemenu add command -label $theme \\\n" ,"-command \" $f.style configure -text $theme; puts $theme ; ttk::setTheme $theme\"\n" ,"}\n" ,"set f $w.nb.stl\n" ,"ttk::labelframe $f.show -relief groove -borderwidth 3 -text \"STL viewing options\"\n" ,"pack $f.show -fill x -pady 15\n" ,"ttk::checkbutton $f.show.showtrias -text \"Show STL-Triangles\" \\\n" ,"-variable stloptions.showtrias -command { Ng_SetVisParameters; redraw }\n" ,"ttk::checkbutton $f.show.showfilledtrias -text \"Show Filled Triangles\" \\\n" ,"-variable stloptions.showfilledtrias -command { Ng_SetVisParameters; redraw }\n" ,"grid $f.show.showtrias $f.show.showfilledtrias -sticky nw\n" ,"ttk::checkbutton $f.show.showactivechart -text \"Show Active Meshing-Chart\" \\\n" ,"-variable stloptions.showactivechart -command { Ng_SetVisParameters; redraw }\n" ,"ttk::checkbutton $f.show.showedges -text \"Show Edges\" \\\n" ,"-variable stloptions.showedges -command { Ng_SetVisParameters; redraw }\n" ,"grid $f.show.showactivechart $f.show.showedges -sticky nw\n" ,"grid anchor $f.show center\n" ,"ttk::checkbutton $f.show.showmarktrias -text \"Show Chart Triangles\" \\\n" ,"-variable stloptions.showmarktrias \\\n" ,"-command {set stldoctor.showfaces 0; Ng_STLDoctor; Ng_SetVisParameters; redraw }\n" ,"ttk::checkbutton $f.show.showfaces -text \"Show Faces\" \\\n" ,"-variable stldoctor.showfaces \\\n" ,"-command {set stloptions.showmarktrias 0; Ng_STLDoctor; Ng_SetVisParameters; redraw}\n" ,"grid $f.show.showmarktrias $f.show.showfaces -sticky nw\n" ,"ttk::labelframe $f.fn -relief groove -borderwidth 3 -text \"Chart/Face number\"\n" ,"pack $f.fn -fill x\n" ,"ttk::label $f.fn.lab3 -text \"Chart/Face number\"\n" ,"ttk::scale $f.fn.scale3 -orient horizontal -length 150 -from 0 -to 200 \\\n" ,"-variable stloptions.chartnumber -command \"Ng_SetVisParameters; redraw;roundscale $f.fn.scale3 0\"\n" ,"ttk::entry $f.fn.ent3 -textvariable stloptions.chartnumber -width 3 -validate focus -takefocus 0 \\\n" ,"-validatecommand \"Ng_SetVisParameters; redraw;my_validate %W [$f.fn.scale3 cget -from] [$f.fn.scale3 cget -to] %P 0\" \\\n" ,"-invalidcommand \"my_invalid %W;Ng_SetVisParameters; redraw;\"\n" ,"grid $f.fn.scale3 $f.fn.ent3 $f.fn.lab3 -sticky nw -padx 4\n" ,"tk::label $f.fn.lab -text \"Chart/Face Offset:\";\n" ,"ttk::entry $f.fn.ent -width 3 \\\n" ,"-textvariable stloptions.chartnumberoffset -validate focus -takefocus 0 \\\n" ,"-validatecommand \"my_validate %W 0 1e9 %P 0\" \\\n" ,"-invalidcommand \"my_invalid %W\"\n" ,"ttk::button $f.fn.btn_write_chart -text \"Write selected chart to chart.stlb\" -command {\n" ,"Ng_STLDoctor writechart\n" ,"}\n" ,"grid $f.fn.lab -sticky ne -padx 4\n" ,"grid $f.fn.ent -sticky nw -padx 4 -row 1 -column 1\n" ,"grid $f.fn.btn_write_chart -padx 4 -row 2 -column 1\n" ,"grid anchor $f.fn center\n" ,"ttk::labelframe $f.advstl -text \"Advanced STL options\" -relief groove -borderwidth 3\n" ,"pack $f.advstl -fill x -pady 15\n" ,"ttk::checkbutton $f.advstl.bu1 -text \"Show Marked (Dirty) Triangles\" \\\n" ,"-variable stldoctor.showmarkedtrigs \\\n" ,"-command {Ng_STLDoctor; redraw}\n" ,"ttk::checkbutton $f.advstl.bu2 -text \"show edge corner points\" \\\n" ,"-variable stldoctor.showedgecornerpoints \\\n" ,"-command {Ng_STLDoctor; redraw}\n" ,"ttk::checkbutton $f.advstl.bu3 -text \"show touched triangle chart\" \\\n" ,"-variable stldoctor.showtouchedtrigchart \\\n" ,"-command {set stldoctor.showfaces 0; set stloptions.showmarktrias 1; \\\n" ,"Ng_STLDoctor; Ng_SetVisParameters; redraw}\n" ,"ttk::checkbutton $f.advstl.bu4 -text \"draw meshed edges\" \\\n" ,"-variable stldoctor.drawmeshededges \\\n" ,"-command {Ng_STLDoctor;}\n" ,"ttk::checkbutton $f.advstl.bu5 -text \"select with mouse\" \\\n" ,"-variable stldoctor.selectwithmouse\n" ,"grid $f.advstl.bu1 -stick nw\n" ,"grid $f.advstl.bu2 -sticky nw\n" ,"grid $f.advstl.bu3 -stick nw\n" ,"grid $f.advstl.bu4 -stick nw\n" ,"grid $f.advstl.bu5 -stick nw\n" ,"grid anchor $f.advstl center\n" ,"ttk::frame $f.advstl.tbn\n" ,"ttk::label $f.advstl.tbn.lab -text \"Select triangle by number\";\n" ,"ttk::entry $f.advstl.tbn.ent -width 5 \\\n" ,"-textvariable stldoctor.selecttrig\n" ,"pack $f.advstl.tbn.lab $f.advstl.tbn.ent -padx 4 -side left\n" ,"grid $f.advstl.tbn -sticky nw\n" ,"grid anchor $f.advstl center\n" ,"grid rowconfigure $f.advstl 4 -pad 8\n" ,"ttk::labelframe $f.vc -relief groove -borderwidth 3 -text \"Vicinity options\"\n" ,"pack $f.vc -fill x -pady 15\n" ,"ttk::checkbutton $f.vc.bu -text \"show vicinity\" \\\n" ,"-variable stldoctor.showvicinity \\\n" ,"-command {Ng_STLDoctor vicinity; redraw}\n" ,"ttk::label $f.vc.lab -text \"vicinity size\";\n" ,"ttk::scale $f.vc.scale -orient horizontal -length 150 -from 0 -to 200 \\\n" ,"-variable stldoctor.vicinity \\\n" ,"-takefocus 0 \\\n" ,"-command \"roundscale $f.vc.scale 0; Ng_STLDoctor vicinity; redraw\"\n" ,"ttk::entry $f.vc.ent -width 4 -textvariable stldoctor.vicinity -validate focus \\\n" ,"-takefocus 0 -validatecommand \"Ng_STLDoctor vicinity; redraw;my_validate %W [$f.vc.scale cget -from] [$f.vc.scale cget -to] %P 0\" \\\n" ,"-invalidcommand \"my_invalid %W;Ng_STLDoctor vicinity; redraw\"\n" ,"grid $f.vc.bu -stick nw -columnspan 3 -column 0\n" ,"grid $f.vc.scale $f.vc.ent $f.vc.lab -sticky nw -padx 4\n" ,"grid anchor $f.vc center\n" ,"set f $w.nb.occ\n" ,"ttk::labelframe $f.occframe -text \"IGES/STEP options\" -relief groove -borderwidth 3\n" ,"pack $f.occframe -fill x -pady 15 -ipady 8\n" ,"ttk::checkbutton $f.occframe.occshowsurfaces -text \"Show surfaces \" \\\n" ,"-variable occoptions.showsurfaces \\\n" ,"-command { Ng_SetOCCVisParameters; redraw }\n" ,"ttk::checkbutton $f.occframe.occshowedges -text \"Show edges \" \\\n" ,"-variable occoptions.showedges \\\n" ,"-command { Ng_SetOCCVisParameters; redraw }\n" ,"grid $f.occframe.occshowsurfaces $f.occframe.occshowedges -sticky nw -padx 4\n" ,"grid anchor $f.occframe center\n" ,"ttk::button $f.occframe.btn -text \"Rebuild visualization data\" \\\n" ,"-command {\n" ,"Ng_SetOCCVisParameters\n" ,"Ng_OCCCommand buildvisualizationmesh\n" ,"redraw\n" ,"}\n" ,"ttk::frame $f.occframe.vssm\n" ,"ttk::label $f.occframe.vssm.lab -text \"Visulization smoothness\"\n" ,"ttk::spinbox $f.occframe.vssm.sp -textvariable occoptions.deflection \\\n" ,"-from 0.1 -to 3 -increment 0.1 -width 4 -command { catch Ng_SetOCCVisParameters } \\\n" ,"-validate focus -validatecommand \"my_validatespinbox %W %P 0\" \\\n" ,"-invalidcommand \"my_invalidspinbox %W\"\n" ,"pack $f.occframe.vssm.lab $f.occframe.vssm.sp -side left -padx 4\n" ,"grid $f.occframe.vssm -sticky nw -columnspan 2 -column 0 -pady 8\n" ,"grid $f.occframe.btn -columnspan 2 -column 0 -sticky n\n" ,"ttk::labelframe $f.occframe1 -relief groove -borderwidth 3 -text \"ACIS visulization / construction\"\n" ,"pack $f.occframe1 -fill x -pady 15 -ipady 8\n" ,"ttk::label $f.occframe1.lab1 -text \"Show solid (0 for all)\"\n" ,"ttk::spinbox $f.occframe1.sp1 -textvariable occoptions.showsolidnr \\\n" ,"-from 0 -to 999 -increment 1 -width 4 -command { catch Ng_SetOCCVisParameters;redraw } \\\n" ,"-validate focus -validatecommand \"my_validatespinbox %W %P 0\" \\\n" ,"-invalidcommand \"my_invalidspinbox %W\"\n" ,"ttk::label $f.occframe1.lab2 -text \"Show solid 2\"\n" ,"ttk::spinbox $f.occframe1.sp2 -textvariable occoptions.showsolidnr2 \\\n" ,"-from 0 -to 999 -increment 1 -width 4 -command { catch Ng_SetOCCVisParameters;redraw } \\\n" ,"-validate focus -validatecommand \"my_validatespinbox %W %P 0\" \\\n" ,"-invalidcommand \"my_invalidspinbox %W\"\n" ,"ttk::button $f.occframe1.subtract -text \"Subtract (2 minus 1)\" \\\n" ,"-command {\n" ,"Ng_ACISCommand subtract ${occoptions.showsolidnr} ${occoptions.showsolidnr2}\n" ,"redraw\n" ,"}\n" ,"ttk::button $f.occframe1.combine -text \"Combine all\" \\\n" ,"-command {\n" ,"Ng_ACISCommand combineall\n" ,"redraw\n" ,"}\n" ,"grid $f.occframe1.lab1 -row 0 -column 0 -sticky ne\n" ,"grid $f.occframe1.sp1 -row 0 -column 1 -sticky nw\n" ,"grid $f.occframe1.lab2 -row 1 -column 0 -sticky ne\n" ,"grid $f.occframe1.sp2 -row 1 -column 1 -sticky nw\n" ,"grid $f.occframe1.combine -columnspan 2 -column 0 -sticky n\n" ,"grid anchor $f.occframe1 center\n" ,"set f $w.nb.mesh\n" ,"ttk::labelframe $f.center -relief groove -borderwidth 3 -text \"how shall i name you?\"\n" ,"pack $f.center -fill x -pady 15\n" ,"ttk::button $f.center.lab1 -text \"Set Center Point\" \\\n" ,"-command { Ng_SetVisParameters; Ng_Center; redraw }\n" ,"ttk::entry $f.center.ent1 -width 5 \\\n" ,"-textvariable viewoptions.centerpoint -validate focus \\\n" ,"-validatecommand \"my_validate %W 0 1e9 %P 0\" \\\n" ,"-invalidcommand \"my_invalid %W\"\n" ,"grid $f.center.ent1 $f.center.lab1 -padx 4 -pady 4 -sticky nw\n" ,"ttk::button $f.center.lab2 -text \"Draw Element\" \\\n" ,"-command { Ng_SetVisParameters; Ng_ZoomAll; redraw }\n" ,"ttk::entry $f.center.ent2 -width 5 \\\n" ,"-textvariable viewoptions.drawelement -validate focus \\\n" ,"-validatecommand \"my_validate %W 0 1e9 %P 0\" \\\n" ,"-invalidcommand \"my_invalid %W\"\n" ,"grid $f.center.ent2 $f.center.lab2 -padx 4 -pady 4 -sticky nw\n" ,"grid anchor $f.center center\n" ,"ttk::labelframe $f.meshframe -text \"Mesh visualization options\" -relief groove -borderwidth 3\n" ,"pack $f.meshframe -fill x -pady 15\n" ,"set f $f.meshframe\n" ,"ttk::checkbutton $f.showcolor -text \"Meshsize Visualization\" \\\n" ,"-variable viewoptions.colormeshsize \\\n" ,"-command { Ng_SetVisParameters;redraw; }\n" ,"ttk::checkbutton $f.showfilledtrigs -text \"Show filled triangles\" \\\n" ,"-variable viewoptions.drawfilledtrigs \\\n" ,"-command { Ng_SetVisParameters; redraw }\n" ,"ttk::checkbutton $f.showedges -text \"Show edges\" \\\n" ,"-variable viewoptions.drawedges \\\n" ,"-command { Ng_SetVisParameters; redraw }\n" ,"ttk::checkbutton $f.showoutline -text \"Show Triangle Outline\" \\\n" ,"-variable viewoptions.drawoutline \\\n" ,"-command { Ng_SetVisParameters; redraw }\n" ,"ttk::checkbutton $f.showbadels -text \"Show bad elements\" \\\n" ,"-variable viewoptions.drawbadels \\\n" ,"-command { Ng_SetVisParameters; redraw }\n" ,"ttk::checkbutton $f.showprisms -text \"Show prisms\" \\\n" ,"-variable viewoptions.drawprisms \\\n" ,"-command { Ng_SetVisParameters; redraw }\n" ,"ttk::checkbutton $f.showpyramids -text \"Show pyramids\" \\\n" ,"-variable viewoptions.drawpyramids \\\n" ,"-command { Ng_SetVisParameters; redraw }\n" ,"ttk::checkbutton $f.showhexes -text \"Show hexes\" \\\n" ,"-variable viewoptions.drawhexes \\\n" ,"-command { Ng_SetVisParameters; redraw }\n" ,"ttk::checkbutton $f.showidentified -text \"Show identified points\" \\\n" ,"-variable viewoptions.drawidentified \\\n" ,"-command { Ng_SetVisParameters; redraw }\n" ,"ttk::checkbutton $f.showmetispartition -text \"Show METIS Partition\" \\\n" ,"-variable viewoptions.drawmetispartition \\\n" ,"-command { Ng_SetVisParameters; redraw }\n" ,"ttk::checkbutton $f.showpointnumbers -text \"Show Point-numbers\" \\\n" ,"-variable viewoptions.drawpointnumbers \\\n" ,"-command { Ng_SetVisParameters; redraw }\n" ,"ttk::checkbutton $f.showedgenumbers -text \"Show Edge-numbers\" \\\n" ,"-variable viewoptions.drawedgenumbers \\\n" ,"-command { Ng_SetVisParameters; redraw }\n" ,"ttk::checkbutton $f.showfacenumbers -text \"Show Face-numbers\" \\\n" ,"-variable viewoptions.drawfacenumbers \\\n" ,"-command { Ng_SetVisParameters; redraw }\n" ,"ttk::checkbutton $f.showelementnumbers -text \"Show Element-numbers\" \\\n" ,"-variable viewoptions.drawelementnumbers \\\n" ,"-command { Ng_SetVisParameters; redraw }\n" ,"ttk::checkbutton $f.showsegmentnumbers -text \"Show Segment-numbers\" \\\n" ,"-variable viewoptions.drawsegmentnumbers \\\n" ,"-command { Ng_SetVisParameters; redraw }\n" ,"ttk::checkbutton $f.showsurfaceelementnumbers -text \"Show Surfaceelement-numbers\" \\\n" ,"-variable viewoptions.drawsurfaceelementnumbers \\\n" ,"-command { Ng_SetVisParameters; redraw }\n" ,"ttk::frame $f.frametets\n" ,"ttk::checkbutton $f.frametets.showtets -text \"\" \\\n" ,"-variable viewoptions.drawtets \\\n" ,"-command { Ng_SetVisParameters; redraw }\n" ,"ttk::label $f.frametets.label -text \"\\Show Tets\\rin domain\"\n" ,"ttk::spinbox $f.frametets.showtetsdomain -from 0 -to 500 -increment 1 -width 3 \\\n" ,"-textvariable viewoptions.drawtetsdomain -validate focus \\\n" ,"-command \"Ng_SetVisParameters; redraw;\" \\\n" ,"-validatecommand \"my_validatespinbox %W %P 0\" \\\n" ,"-invalidcommand \"my_invalidspinbox %W\"\n" ,"ttk::label $f.frametets.label1 -text \"Subdivision\"\n" ,"ttk::spinbox $f.frametets.subdiv -from 0 -to 8 -increment 1 -width 3 \\\n" ,"-textvariable visoptions.subdivisions -validate focus \\\n" ,"-command { Ng_SetVisParameters; Ng_Vis_Set parameters; Ng_SetNextTimeStamp; redraw } \\\n" ,"-validatecommand \"my_validatespinbox %W %P 0\" \\\n" ,"-invalidcommand \"my_invalidspinbox %W\"\n" ,"ttk::label $f.frametets.label2 -text \"Show surface\\rof domain\"\n" ,"ttk::spinbox $f.frametets.showdomain -from 0 -to 50 -increment 1 -width 3 \\\n" ,"-textvariable viewoptions.drawdomainsurf -validate focus \\\n" ,"-command { Ng_SetVisParameters; Ng_Vis_Set parameters; redraw } \\\n" ,"-validatecommand \"my_validatespinbox %W %P 0\" \\\n" ,"-invalidcommand \"my_invalidspinbox %W\"\n" ,"grid $f.frametets.showtets $f.frametets.label $f.frametets.showtetsdomain -sticky w\n" ,"grid x $f.frametets.label2 $f.frametets.showdomain -stick w\n" ,"grid x $f.frametets.label1 $f.frametets.subdiv -sticky w\n" ,"grid $f.showfilledtrigs $f.showoutline -sticky nw\n" ,"grid $f.showedges $f.showbadels -sticky nw\n" ,"grid $f.showpointnumbers $f.showedgenumbers -sticky nw\n" ,"grid $f.showfacenumbers $f.showelementnumbers -sticky nw\n" ,"grid $f.showsurfaceelementnumbers $f.showsegmentnumbers -sticky nw\n" ,"grid $f.showmetispartition $f.showidentified -sticky nw\n" ,"grid $f.showcolor $f.showpyramids -sticky nw\n" ,"grid $f.showprisms $f.showhexes -sticky nw\n" ,"grid $f.frametets -sticky n -columnspan 2 -column 0 -pady 8\n" ,"grid anchor $f center\n" ,"set f $w.nb.mesh\n" ,"ttk::labelframe $f.fshrink -text \"Element visualization\" -relief groove -borderwidth 3\n" ,"ttk::label $f.fshrink.lab -text \"Shrink elements\"\n" ,"ttk::scale $f.fshrink.scale -orient horizontal -length 200 -from 0 -to 1.0001 \\\n" ,"-command \"roundscale $f.fshrink.scale 2;Ng_SetVisParameters; after idle redraw\" \\\n" ,"-variable viewoptions.shrink\n" ,"ttk::entry $f.fshrink.entry -textvariable viewoptions.shrink -width 4 -validate focus \\\n" ,"-takefocus 0 -validatecommand \"Ng_SetVisParameters; after idle redraw;my_validate %W [$f.fshrink.scale cget -from] [$f.fshrink.scale cget -to] %P 2\" \\\n" ,"-invalidcommand \"my_invalid %W;Ng_SetVisParameters; after idle redraw;\"\n" ,"pack $f.fshrink -fill x -ipady 8\n" ,"grid $f.fshrink.scale $f.fshrink.entry $f.fshrink.lab -padx 4\n" ,"grid anchor $f.fshrink center\n" ,"set f $w.nb.light\n" ,"ttk::labelframe $f.main -text \"Lighting options\" -relief groove -borderwidth 3\n" ,"pack $f.main -fill x -pady 15\n" ,"set f $f.main\n" ,"ttk::label $f.lab1 -text \"Ambient Light\"\n" ,"ttk::scale $f.scale1 -orient horizontal -length 200 -from 0 -to 1 \\\n" ,"-command \"roundscale $f.scale1 2; Ng_SetVisParameters; redraw\" \\\n" ,"-variable viewoptions.light.amb\n" ,"ttk::entry $f.ent1 -textvariable viewoptions.light.amb -validate focus -width 4 \\\n" ,"-validatecommand \" Ng_SetVisParameters; redraw;my_validate %W [$f.scale1 cget -from] [$f.scale1 cget -to] %P 2\" \\\n" ,"-invalidcommand \"my_invalid %W;Ng_SetVisParameters; redraw;\"\n" ,"ttk::label $f.lab2 -text \"Diffuse Light\"\n" ,"ttk::scale $f.scale2 -orient horizontal -length 200 -from 0 -to 1 \\\n" ,"-command \"roundscale $f.scale2 2; Ng_SetVisParameters; redraw \" \\\n" ,"-variable viewoptions.light.diff\n" ,"ttk::entry $f.ent2 -textvariable viewoptions.light.diff -validate focus -width 4 \\\n" ,"-validatecommand \" Ng_SetVisParameters; redraw;my_validate %W [$f.scale2 cget -from] [$f.scale2 cget -to] %P 2\" \\\n" ,"-invalidcommand \"my_invalid %W;Ng_SetVisParameters; redraw;\"\n" ,"ttk::label $f.lab3 -text \"Specular Light\"\n" ,"ttk::scale $f.scale3 -orient horizontal -length 200 -from 0 -to 1 \\\n" ,"-command \"roundscale $f.scale3 2; Ng_SetVisParameters; redraw \" \\\n" ,"-variable viewoptions.light.spec\n" ,"ttk::entry $f.ent3 -textvariable viewoptions.light.spec -validate focus -width 4 \\\n" ,"-validatecommand \" Ng_SetVisParameters; redraw;my_validate %W [$f.scale3 cget -from] [$f.scale3 cget -to] %P 2\" \\\n" ,"-invalidcommand \"my_invalid %W;Ng_SetVisParameters; redraw;\"\n" ,"grid $f.scale1 $f.ent1 $f.lab1 -sticky nw -padx 4 -pady 8\n" ,"grid $f.scale2 $f.ent2 $f.lab2 -sticky nw -padx 4 -pady 8\n" ,"grid $f.scale3 $f.ent3 $f.lab3 -sticky nw -padx 4 -pady 8\n" ,"grid anchor $f center\n" ,"set f $w.nb.light\n" ,"ttk::labelframe $f.main1 -text \"Material options\" -relief groove -borderwidth 3\n" ,"pack $f.main1 -fill x -pady 15\n" ,"set f $f.main1\n" ,"ttk::label $f.lab4 -text \"Material Shininess\"\n" ,"ttk::scale $f.scale4 -orient horizontal -length 200 -from 0 -to 128 \\\n" ,"-command \"roundscale $f.scale4 0; Ng_SetVisParameters; redraw \" \\\n" ,"-variable viewoptions.mat.shininess\n" ,"ttk::entry $f.ent4 -textvariable viewoptions.mat.shininess -validate focus -width 4 \\\n" ,"-validatecommand \" Ng_SetVisParameters; redraw;my_validate %W [$f.scale4 cget -from] [$f.scale4 cget -to] %P 0\" \\\n" ,"-invalidcommand \"my_invalid %W;Ng_SetVisParameters; redraw;\"\n" ,"ttk::label $f.lab5 -text \"Material Transparency\"\n" ,"ttk::scale $f.scale5 -orient horizontal -length 200 -from 0 -to 1 \\\n" ,"-command \"roundscale $f.scale5 2; Ng_SetVisParameters; redraw \" \\\n" ,"-variable viewoptions.mat.transp\n" ,"ttk::entry $f.ent5 -textvariable viewoptions.mat.transp -validate focus -width 4 \\\n" ,"-validatecommand \" Ng_SetVisParameters; redraw;my_validate %W [$f.scale5 cget -from] [$f.scale5 cget -to] %P 2\" \\\n" ,"-invalidcommand \"my_invalid %W;Ng_SetVisParameters; redraw;\"\n" ,"grid $f.scale4 $f.ent4 $f.lab4 -sticky nw -padx 4 -pady 8\n" ,"grid $f.scale5 $f.ent5 $f.lab5 -sticky nw -padx 4 -pady 8\n" ,"grid anchor $f center\n" ,"set f $w.nb.edges\n" ,"ttk::labelframe $f.main -text \"Edge viewing options\" -relief groove -borderwidth 3\n" ,"pack $f.main -fill x -pady 15\n" ,"set f $f.main\n" ,"ttk::frame $f.helper\n" ,"pack $f.helper -anchor center\n" ,"set f $f.helper\n" ,"ttk::checkbutton $f.showedges -text \"Show Edges\" \\\n" ,"-variable viewoptions.drawededges \\\n" ,"-command { Ng_SetVisParameters; redraw }\n" ,"ttk::checkbutton $f.showpoints -text \"Show Points\" \\\n" ,"-variable viewoptions.drawedpoints \\\n" ,"-command { Ng_SetVisParameters; redraw }\n" ,"ttk::checkbutton $f.showpointnrs -text \"Show Points Nrs\" \\\n" ,"-variable viewoptions.drawedpointnrs \\\n" ,"-command { Ng_SetVisParameters; redraw }\n" ,"ttk::checkbutton $f.showtang -text \"Show CP Tangents\" \\\n" ,"-variable viewoptions.drawedtangents \\\n" ,"-command { Ng_SetVisParameters; redraw }\n" ,"ttk::checkbutton $f.drawedgenrs -text \"Show Edge Nrs\" \\\n" ,"-variable viewoptions.drawededgenrs \\\n" ,"-command { Ng_SetVisParameters; redraw }\n" ,"pack $f.showedges $f.showpoints $f.showpointnrs $f.showtang $f.drawedgenrs -anchor w\n" ,"set f $w.nb.edges\n" ,"ttk::labelframe $f.main1 -text \"Center point\" -relief groove -borderwidth 3\n" ,"pack $f.main1 -fill x -pady 15\n" ,"set f $f.main1\n" ,"ttk::frame $f.center\n" ,"pack $f.center -anchor center\n" ,"ttk::button $f.center.btn -text \"Set Center Point\" \\\n" ,"-command { Ng_SetVisParameters; Ng_Center; redraw }\n" ,"ttk::entry $f.center.ent -width 5 -textvariable viewoptions.centerpoint -validate focus \\\n" ,"-validatecommand \"my_validate %W 0 1e9 %P 0\" \\\n" ,"-invalidcommand \"my_invalid %W\"\n" ,"grid $f.center.ent $f.center.btn -sticky nw -padx 4\n" ,"ttk::label $f.center.lab1 -text \"SpecPoint Veclen\"\n" ,"ttk::entry $f.center.ent1 -width 5 -textvariable viewoptions.specpointvlen -validate focus \\\n" ,"-validatecommand \"my_validate %W 0 1e9 %P 4\" \\\n" ,"-invalidcommand \"my_invalid %W\"\n" ,"grid $f.center.ent1 $f.center.lab1 -sticky nw -padx 4\n" ,"set f $w.nb.misc\n" ,"ttk::labelframe $f.point -relief groove -borderwidth 3 -text \"Special point\"\n" ,"ttk::frame $f.point.dp\n" ,"ttk::checkbutton $f.point.dp.drawpoint -text \"Draw Point\" \\\n" ,"-variable viewoptions.drawspecpoint \\\n" ,"-command { Ng_SetVisParameters; redraw }\n" ,"ttk::entry $f.point.dp.px -width 8 -textvariable viewoptions.specpointx -validate focus \\\n" ,"-validatecommand \"my_validate %W -1e9 1e9 %P 10\" \\\n" ,"-invalidcommand \"my_invalid %W\"\n" ,"ttk::entry $f.point.dp.py -width 8 -textvariable viewoptions.specpointy -validate focus \\\n" ,"-validatecommand \"my_validate %W -1e9 1e9 %P 10\" \\\n" ,"-invalidcommand \"my_invalid %W\"\n" ,"ttk::entry $f.point.dp.pz -width 8 -textvariable viewoptions.specpointz -validate focus \\\n" ,"-validatecommand \"my_validate %W -1e9 1e9 %P 10\" \\\n" ,"-invalidcommand \"my_invalid %W\"\n" ,"grid $f.point.dp.drawpoint $f.point.dp.px $f.point.dp.py $f.point.dp.pz -sticky nw -padx 4;\n" ,"ttk::checkbutton $f.point.dp.center -text \"Use as Center\" \\\n" ,"-variable viewoptions.usecentercoords \\\n" ,"-command {\n" ,"if { ${viewoptions.usecentercoords} } {\n" ,"set viewoptions.centerx ${viewoptions.specpointx}\n" ,"set viewoptions.centery ${viewoptions.specpointy}\n" ,"set viewoptions.centerz ${viewoptions.specpointz}\n" ,"Ng_SetVisParameters; Ng_Center\n" ,"redraw\n" ,"} {\n" ,"Ng_SetVisParameters\n" ,"}\n" ,"}\n" ,"grid $f.point.dp.center -sticky nw -padx 4\n" ,"pack $f.point.dp\n" ,"pack $f.point -fill x -ipady 3 -pady 15\n" ,"ttk::frame $w.bu\n" ,"pack $w.bu -fill x -ipady 3\n" ,"ttk::button $w.bu.done -text \"Done\" -command {\n" ,"Ng_SetVisParameters;\n" ,"redraw\n" ,"destroy .viewopts_dlg\n" ,"}\n" ,"ttk::button $w.bu.apply -text \"Apply\" -command {\n" ,"Ng_SetVisParameters;\n" ,"redraw\n" ,"}\n" ,"pack $w.bu.apply $w.bu.done -expand yes -side left\n" ,"wm withdraw $w\n" ,"wm geom $w +100+100\n" ,"wm deiconify $w\n" ,"wm title $w \"Viewing options\"\n" ,"focus $w\n" ,"}\n" ,"}\n" ,"proc clipplanecommand { { optionalvar 0 } } {\n" ,"Ng_SetVisParameters\n" ,"after idle redraw\n" ,"}\n" ,"set clippingdialog_pop1 0\n" ,"set clippingdialog_pop2 0\n" ,"set clippingdialog_pop3 0\n" ,"set clippingdialog_pop4 0\n" ,"proc clippingdialog { } {\n" ,"global clippingdialog_pop1\n" ,"global clippingdialog_pop2\n" ,"global clippingdialog_pop3\n" ,"global clippingdialog_pop4\n" ,"set clippingdialog_pop1 1\n" ,"set clippingdialog_pop2 1\n" ,"set clippingdialog_pop3 1\n" ,"set clippingdialog_pop4 1\n" ,"set w .clipping_dlg\n" ,"if {[winfo exists .clipping_dlg] == 1} {\n" ,"wm withdraw $w\n" ,"wm deiconify $w\n" ,"focus $w\n" ,"} {\n" ,"toplevel $w\n" ,"ttk::frame $w.background\n" ,"pack $w.background -fill x -fill y\n" ,"set w $w.background\n" ,"ttk::labelframe $w.main -text \"Visual clipping\" -relief groove -borderwidth 3\n" ,"pack $w.main -fill x -pady 15\n" ,"set w $w.main\n" ,"ttk::label $w.lab1 -text \"Normal x\"\n" ,"ttk::scale $w.scale1 -orient horizontal -length 300 -from -1 -to 1 \\\n" ,"-variable viewoptions.clipping.nx \\\n" ,"-command \"roundscale $w.scale1 2; clipplanecommand \"\n" ,"ttk::entry $w.entry1 -width 5 -textvariable viewoptions.clipping.nx \\\n" ,"-validate focus -validatecommand \" clipplanecommand;my_validate %W [$w.scale1 cget -from] [$w.scale1 cget -to] %P 2\" \\\n" ,"-invalidcommand \"my_invalid %W; clipplanecommand\"\n" ,"ttk::label $w.lab2 -text \"Normal y\"\n" ,"ttk::scale $w.scale2 -orient horizontal -length 300 -from -1 -to 1 \\\n" ,"-variable viewoptions.clipping.ny \\\n" ,"-command \"roundscale $w.scale2 2; clipplanecommand \"\n" ,"ttk::entry $w.entry2 -width 5 -textvariable viewoptions.clipping.ny \\\n" ,"-validate focus -validatecommand \" clipplanecommand;my_validate %W [$w.scale2 cget -from] [$w.scale2 cget -to] %P 2\" \\\n" ,"-invalidcommand \"my_invalid $w.entry2;clipplanecommand\"\n" ,"ttk::label $w.lab3 -text \"Normal z\"\n" ,"ttk::scale $w.scale3 -orient horizontal -length 300 -from -1 -to 1 \\\n" ,"-variable viewoptions.clipping.nz \\\n" ,"-command \"roundscale $w.scale3 2; clipplanecommand \"\n" ,"ttk::entry $w.entry3 -width 5 -textvariable viewoptions.clipping.nz \\\n" ,"-validate focus -validatecommand \" clipplanecommand;my_validate %W [$w.scale3 cget -from] [$w.scale3 cget -to] %P 2\" \\\n" ,"-invalidcommand \"my_invalid %W;clipplanecommand\"\n" ,"ttk::label $w.lab4 -text \"Distance\"\n" ,"ttk::scale $w.scale4 -orient horizontal -length 300 -from -1 -to 1.001 \\\n" ,"-variable viewoptions.clipping.dist \\\n" ,"-command \"roundscale $w.scale4 3; clipplanecommand \"\n" ,"ttk::entry $w.entry4 -width 5 -textvariable viewoptions.clipping.dist \\\n" ,"-validate focus -validatecommand \" clipplanecommand;my_validate %W [$w.scale4 cget -from] [$w.scale4 cget -to] %P 3\" \\\n" ,"-invalidcommand \"my_invalid %W;clipplanecommand\"\n" ,"proc my_Press {w x y} {\n" ,"set inc [expr {([$w get $x $y] <= [$w get]) ? -1 : 1}]\n" ,"ttk::Repeatedly ttk::scale::Increment $w [expr 0.001*$inc]\n" ,"}\n" ,"bind $w.scale4 { if { [string match *slider [%W identify %x %y]] == 0 } { my_Press %W %x %y;break } }\n" ,"bind $w.scale4 {ttk::scale::Release %W %x %y}\n" ,"ttk::label $w.lab5 -text \"Additional\\rDistance\"\n" ,"ttk::scale $w.scale5 -orient horizontal -length 300 -from -1 -to 1.001 \\\n" ,"-variable viewoptions.clipping.dist2 \\\n" ,"-command \"roundscale $w.scale5 3; clipplanecommand \"\n" ,"ttk::entry $w.entry5 -width 5 -textvariable viewoptions.clipping.dist2 \\\n" ,"-validate focus -validatecommand \" clipplanecommand;my_validate %W [$w.scale5 cget -from] [$w.scale5 cget -to] %P 3\" \\\n" ,"-invalidcommand \"my_invalid %W;clipplanecommand\"\n" ,"bind $w.scale5 { if { [string match *slider [%W identify %x %y]] == 0 } { my_Press %W %x %y;break } }\n" ,"bind $w.scale5 {ttk::scale::Release %W %x %y}\n" ,"ttk::label $w.clipdomainlabel -text \"Clip only domain\"\n" ,"ttk::spinbox $w.clipdomainspinb -from 0 -to 500 -increment 1 -width 3 \\\n" ,"-textvariable viewoptions.clipping.onlydomain -validate focus \\\n" ,"-command {clipplanecommand;} \\\n" ,"-validatecommand \"my_validatespinbox %W %P 0\" \\\n" ,"-invalidcommand \"my_invalidspinbox %W\"\n" ,"ttk::label $w.donotclipdomainlabel -text \"Do not clip domain\"\n" ,"ttk::spinbox $w.donotclipdomainspinb -from 0 -to 500 -increment 1 -width 3 \\\n" ,"-textvariable viewoptions.clipping.notdomain -validate focus \\\n" ,"-command \"clipplanecommand\" \\\n" ,"-validatecommand \"my_validatespinbox %W %P 0\" \\\n" ,"-invalidcommand \"my_invalidspinbox %W\"\n" ,"grid $w.scale1 $w.entry1 $w.lab1 -sticky nw -padx 4 -pady 14\n" ,"grid $w.scale2 $w.entry2 $w.lab2 -sticky nw -padx 4 -pady 14\n" ,"grid $w.scale3 $w.entry3 $w.lab3 -sticky nw -padx 4 -pady 14\n" ,"grid $w.scale4 $w.entry4 $w.lab4 -sticky nw -padx 4 -pady 14\n" ,"grid $w.scale5 $w.entry5 $w.lab5 -sticky w -padx 4 -pady 14\n" ,"grid $w.clipdomainlabel -sticky ne -padx 4 -pady 14\n" ,"grid $w.clipdomainspinb -sticky nw -padx 4 -pady 14 -column 1 -row 5\n" ,"grid $w.donotclipdomainlabel -sticky ne -padx 4 -pady 14\n" ,"grid $w.donotclipdomainspinb -sticky nw -padx 4 -pady 14 -column 1 -row 6\n" ,"grid anchor $w center\n" ,"set w .clipping_dlg.background.main\n" ,"ttk::checkbutton $w.cb1 -text \"Enable clipping\" \\\n" ,"-variable viewoptions.clipping.enable \\\n" ,"-command { Ng_SetVisParameters; redraw }\n" ,"grid $w.cb1 -columnspan 2 -sticky ne\n" ,"ttk::frame $w.bu\n" ,"grid $w.bu;\n" ,"ttk::button $w.cancle -text \"Done\" -command \"destroy .clipping_dlg\"\n" ,"grid $w.cancle -columnspan 3 -pady 16\n" ,"set w .clipping_dlg\n" ,"wm withdraw $w\n" ,"wm geom $w +100+100\n" ,"wm deiconify $w\n" ,"wm title $w \"Clipping Plane\"\n" ,"focus $w\n" ,"clipplanecommand\n" ,"}\n" ,"}\n" ,"proc refinementdialog { } {\n" ,"set w .refinement_dlg\n" ,"if {[winfo exists .refinement_dlg] == 1} {\n" ,"wm withdraw $w\n" ,"wm deiconify $w\n" ,"focus $w\n" ,"} {\n" ,"toplevel $w\n" ,"global localh\n" ,"set localh 1\n" ,"ttk::frame $w.meshsize\n" ,"ttk::label $w.meshsize.l1 -text \"max mesh-size: \"\n" ,"ttk::spinbox $w.meshsize.sp1 -from 1e-6 -to 1e6 -textvariable options.meshsize -validate focus -validatecommand \"my_validatespinbox %W %P 4\" \\\n" ,"-invalidcommand \"my_invalidspinbox %W\" -width 6 -increment 0.1\n" ,"ttk::frame $w.meshsizeloc\n" ,"ttk::label $w.meshsizeloc.l1 -text \"local mesh-size: \"\n" ,"ttk::spinbox $w.meshsizeloc.sp1 -from 1e-6 -to 1e6 -textvariable localh -validate focus -validatecommand \"my_validatespinbox %W %P 4\" \\\n" ,"-invalidcommand \"my_invalidspinbox %W\" -width 6 -increment 0.1\n" ,"pack $w.meshsize\n" ,"pack $w.meshsizeloc\n" ,"grid $w.meshsize.l1 $w.meshsize.sp1\n" ,"grid $w.meshsizeloc.l1 $w.meshsizeloc.sp1\n" ,"ttk::button $w.restface -text \"Restrict H at face\" \\\n" ,"-command {\n" ,".refinement_dlg.meshsize invoke\n" ,".refinement_dlg.loch invoke\n" ,"Ng_RestrictH face $localh\n" ,"}\n" ,"ttk::button $w.restedge -text \"Restrict H at edge\" \\\n" ,"-command {\n" ,".refinement_dlg.meshsize invoke\n" ,".refinement_dlg.loch invoke\n" ,"Ng_RestrictH edge $localh\n" ,"}\n" ,"ttk::button $w.restelement -text \"Restrict H at element\" \\\n" ,"-command {\n" ,".refinement_dlg.meshsize invoke\n" ,".refinement_dlg.loch invoke\n" ,"Ng_RestrictH element $localh\n" ,"}\n" ,"ttk::button $w.restpoint -text \"Restrict H at point\" \\\n" ,"-command {\n" ,".refinement_dlg.meshsize invoke\n" ,".refinement_dlg.loch invoke\n" ,"Ng_RestrictH point $localh\n" ,"}\n" ,"pack $w.restface $w.restedge $w.restelement $w.restpoint\n" ,"ttk::button $w.anisoedge -text \"Declare Anisotropic edge\" \\\n" ,"-command {\n" ,"Ng_Anisotropy edge\n" ,"}\n" ,"pack $w.anisoedge\n" ,"frame $w.bu\n" ,"pack $w.bu -fill x -ipady 3\n" ,"ttk::button $w.bu.cancle -text \"Done\" -command \"destroy .refinement_dlg\"\n" ,"ttk::button $w.bu.refine -text \"Refine\" \\\n" ,"-command {\n" ,"set oldnp 0; set newnp $status_np;\n" ,"while { $oldnp < $newnp } {\n" ,"set level [expr $level+1]\n" ,"Ng_Bisect;\n" ,"Ng_HighOrder ${options.elementorder}\n" ,"Ng_ReadStatus;\n" ,"redraw;\n" ,"set oldnp $newnp\n" ,"set newnp $status_np\n" ,"puts \"oldnp $oldnp newnp $newnp\"\n" ,"}\n" ,"}\n" ,"ttk::button $w.bu.zrefine -text \"Z-Refine\" \\\n" ,"-command { Ng_ZRefinement; Ng_ReadStatus; redraw; }\n" ,"pack $w.bu.zrefine $w.bu.refine $w.bu.cancle -expand yes -side left\n" ,"wm withdraw $w\n" ,"wm geom $w +100+100\n" ,"wm deiconify $w\n" ,"wm title $w \"Select Refinement\"\n" ,"focus $w\n" ,"}\n" ,"}\n" ,"proc bcpropdialog { } {\n" ,"set w .bcprop_dlg\n" ,"if {[winfo exists .bcprop_dlg] == 1} {\n" ,"wm withdraw $w\n" ,"wm deiconify $w\n" ,"} {\n" ,"toplevel $w\n" ,"ttk::frame $w.face -borderwidth 3\n" ,"pack $w.face -fill x\n" ,"ttk::label $w.face.lab -text \"face index:\"\n" ,"ttk::label $w.face.ent -text 1\n" ,"ttk::button $w.face.next -text \"next\" -command {\n" ,"set w .bcprop_dlg;\n" ,"set facenr [$w.face.ent cget -text]\n" ,"if {$facenr == [Ng_BCProp getnfd]} {\n" ,"set facenr 1\n" ,"} {\n" ,"set facenr [expr $facenr + 1]\n" ,"}\n" ,"$w.face.ent configure -text $facenr\n" ,"Ng_BCProp setactive $facenr\n" ,"set bcnr [Ng_BCProp getbc $facenr]\n" ,"$w.bc.ent delete 0 end\n" ,"$w.bc.ent insert 0 $bcnr\n" ,"redraw\n" ,"}\n" ,"ttk::button $w.face.prev -text \"prev\" -command {\n" ,"set w .bcprop_dlg;\n" ,"set facenr [$w.face.ent cget -text]\n" ,"if {$facenr == 1} {\n" ,"set facenr [Ng_BCProp getnfd]\n" ,"} {\n" ,"set facenr [expr $facenr - 1]\n" ,"}\n" ,"$w.face.ent configure -text $facenr\n" ,"Ng_BCProp setactive $facenr\n" ,"set bcnr [Ng_BCProp getbc $facenr]\n" ,"$w.bc.ent delete 0 end\n" ,"$w.bc.ent insert 0 $bcnr\n" ,"redraw\n" ,"}\n" ,"pack $w.face.lab $w.face.ent $w.face.prev $w.face.next -side left\n" ,"ttk::frame $w.bc -borderwidth 3\n" ,"pack $w.bc -fill x\n" ,"ttk::label $w.bc.lab -text \"bc property:\"\n" ,"entry $w.bc.ent -width 5 -relief sunken\n" ,"ttk::button $w.bc.but -text \"change\" -command {\n" ,"set w .bcprop_dlg;\n" ,"Ng_BCProp setbc [$w.face.ent cget -text] [$w.bc.ent get];\n" ,"}\n" ,"ttk::button $w.bc.but2 -text \"all\" -command {\n" ,"set w .bcprop_dlg;\n" ,"Ng_BCProp setall [$w.bc.ent get];\n" ,"}\n" ,"pack $w.bc.lab $w.bc.ent $w.bc.but $w.bc.but2 -side left -expand yes\n" ,"ttk::frame $w.bcname -borderwidth 3\n" ,"pack $w.bcname -fill x\n" ,"ttk::label $w.bcname.lab -text \"bc name:\"\n" ,"ttk::label $w.bcname.ent -text \"-\"\n" ,"pack $w.bcname.lab $w.bcname.ent -side left -expand yes\n" ,"ttk::frame $w.bu\n" ,"pack $w.bu -fill x -ipady 3\n" ,"ttk::button $w.bu.close -text \"Close\" -command { destroy .bcprop_dlg }\n" ,"pack $w.bu.close -expand yes -side left\n" ,"wm withdraw $w\n" ,"wm geom $w +100+100\n" ,"wm deiconify $w\n" ,"wm title $w \"Boundary Conditions\"\n" ,"}\n" ,"focus $w\n" ,"set facenr [Ng_BCProp getactive]\n" ,"$w.face.ent configure -text $facenr\n" ,"set bcnr [Ng_BCProp getbc $facenr]\n" ,"$w.bc.ent delete 0 end\n" ,"$w.bc.ent insert 0 $bcnr\n" ,"set bcname [Ng_BCProp getbcname $facenr]\n" ,"$w.bcname.ent configure -text $bcname\n" ,"}\n" ,"proc currmeshcoloursdialog { } {\n" ,"set w .currmeshcolours_dlg\n" ,"if {[winfo exists .currmeshcolours_dlg] == 1} {\n" ,"wm withdraw $w\n" ,"wm deiconify $w\n" ,"focus $w\n" ,"} {\n" ,"toplevel $w\n" ,"global facecolslist\n" ,"frame $w.facecols -borderwidth 3\n" ,"listbox $w.facecols.list -yscroll \"$w.facecols.scroll set\" -selectmode single -setgrid 1 -width 32 -height 12\n" ,"scrollbar $w.facecols.scroll -command \"$w.facecols.list yview\"\n" ,"pack $w.facecols.scroll -side right -fill y\n" ,"pack $w.facecols.list -side left -expand yes -fill both\n" ,"Ng_CurrentFaceColours getcolours facecolslist\n" ,"set i 1\n" ,"foreach el $facecolslist {\n" ,"set hel [format \"%d: (%.4f %.4f %.4f)\" $i [ lindex $el 0 ] [ lindex $el 1 ] [ lindex $el 2 ]]\n" ,"incr i\n" ,"$w.facecols.list insert end $hel }\n" ,"frame $w.bu1 -borderwidth 3\n" ,"ttk::button $w.bu1.showonly -text \"show only\" -command {\n" ,"Ng_CurrentFaceColours showonly [.currmeshcolours_dlg.facecols.list curselection]\n" ,"redraw\n" ,"}\n" ,"ttk::button $w.bu1.hideonly -text \"hide only\" -command {\n" ,"Ng_CurrentFaceColours hideonly [.currmeshcolours_dlg.facecols.list curselection]\n" ,"redraw\n" ,"}\n" ,"ttk::button $w.bu1.showalso -text \"show\" -command {\n" ,"Ng_CurrentFaceColours showalso [.currmeshcolours_dlg.facecols.list curselection]\n" ,"redraw\n" ,"}\n" ,"ttk::button $w.bu1.hidealso -text \"hide\" -command {\n" ,"Ng_CurrentFaceColours hidealso [.currmeshcolours_dlg.facecols.list curselection]\n" ,"redraw\n" ,"}\n" ,"pack $w.bu1.showonly $w.bu1.hideonly $w.bu1.showalso $w.bu1.hidealso -expand yes -fill x -padx 2 -pady 2 -side left\n" ,"frame $w.bu2\n" ,"ttk::button $w.bu2.showall -text \"show all\" -command {\n" ,"Ng_CurrentFaceColours showall\n" ,"redraw\n" ,"}\n" ,"ttk::button $w.bu2.hideall -text \"hide all\" -command {\n" ,"Ng_CurrentFaceColours hideall\n" ,"redraw\n" ,"}\n" ,"pack $w.bu2.showall $w.bu2.hideall -expand yes -fill x -padx 2 -pady 2 -side left\n" ,"frame $w.bu3\n" ,"ttk::button $w.bu3.close -text \"close\" -command {\n" ,"destroy .currmeshcolours_dlg\n" ,"}\n" ,"pack $w.bu3.close -expand yes -fill x -pady 3 -side right\n" ,"pack $w.facecols -side top -expand yes -fill x -fill y\n" ,"pack $w.bu3 -side bottom\n" ,"pack $w.bu2 -side bottom\n" ,"pack $w.bu1 -expand yes -fill x -side left\n" ,"wm withdraw $w\n" ,"wm geom $w +100+100\n" ,"wm deiconify $w\n" ,"wm title $w \"Inspect Mesh Colours\"\n" ,"focus $w\n" ,"}\n" ,"}\n" ,"proc surfacemeshsizedialog { } {\n" ,"set w .surfacemeshsize_dlg\n" ,"if {[winfo exists .surfacemeshsize_dlg] == 1} {\n" ,"wm withdraw $w\n" ,"wm deiconify $w\n" ,"} {\n" ,"toplevel $w\n" ,"frame $w.face -borderwidth 3\n" ,"pack $w.face -fill x -padx 5\n" ,"ttk::label $w.face.lab -text \"face index:\"\n" ,"ttk::label $w.face.ent -text 1\n" ,"ttk::button $w.face.next -text \"next\" -command {\n" ,"set w .surfacemeshsize_dlg;\n" ,"set facenr [$w.face.ent cget -text]\n" ,"if {$facenr == [Ng_SurfaceMeshSize getnfd]} {\n" ,"set facenr 1\n" ,"} {\n" ,"set facenr [expr $facenr + 1]\n" ,"}\n" ,"$w.face.ent configure -text $facenr\n" ,"Ng_SurfaceMeshSize setactive $facenr\n" ,"set surfms [Ng_SurfaceMeshSize getsurfms $facenr]\n" ,"$w.sms.ent delete 0 end\n" ,"$w.sms.ent insert 0 $surfms\n" ,"redraw\n" ,"}\n" ,"ttk::button $w.face.prev -text \"prev\" -command {\n" ,"set w .surfacemeshsize_dlg;\n" ,"set facenr [$w.face.ent cget -text]\n" ,"if {$facenr == 1} {\n" ,"set facenr [Ng_SurfaceMeshSize getnfd]\n" ,"} {\n" ,"set facenr [expr $facenr - 1]\n" ,"}\n" ,"$w.face.ent configure -text $facenr\n" ,"Ng_SurfaceMeshSize setactive $facenr\n" ,"set surfms [Ng_SurfaceMeshSize getsurfms $facenr]\n" ,"$w.sms.ent delete 0 end\n" ,"$w.sms.ent insert 0 $surfms\n" ,"redraw\n" ,"}\n" ,"pack $w.face.lab $w.face.ent $w.face.prev $w.face.next -side left\n" ,"frame $w.sms -borderwidth 3\n" ,"pack $w.sms -fill x\n" ,"ttk::label $w.sms.lab -text \"max mesh size:\"\n" ,"entry $w.sms.ent -width 8 -relief sunken\n" ,"ttk::button $w.sms.but -text \"change\" -command {\n" ,"set w .surfacemeshsize_dlg;\n" ,"Ng_SurfaceMeshSize setsurfms [$w.face.ent cget -text] [$w.sms.ent get];\n" ,"}\n" ,"ttk::button $w.sms.but2 -text \"all\" -command {\n" ,"set w .surfacemeshsize_dlg;\n" ,"Ng_SurfaceMeshSize setall [$w.sms.ent get];\n" ,"}\n" ,"pack $w.sms.lab $w.sms.ent $w.sms.but $w.sms.but2 -side left -padx 5 -expand yes\n" ,"frame $w.bu\n" ,"pack $w.bu -fill x -ipady 3\n" ,"ttk::button $w.bu.close -text \"Close\" -command { destroy .surfacemeshsize_dlg }\n" ,"pack $w.bu.close -expand yes -side left\n" ,"wm withdraw $w\n" ,"wm geom $w +100+100\n" ,"wm deiconify $w\n" ,"wm title $w \"Edit Surface Mesh Size\"\n" ,"}\n" ,"focus $w\n" ,"set facenr [Ng_SurfaceMeshSize getactive]\n" ,"$w.face.ent configure -text $facenr\n" ,"set surfms [Ng_SurfaceMeshSize getsurfms $facenr]\n" ,"$w.sms.ent delete 0 end\n" ,"$w.sms.ent insert 0 $surfms\n" ,"}\n" ,"proc METISdialog { } {\n" ,"set w .metis_dlg\n" ,"set w.parts 64\n" ,"if {[winfo exists .metis_dlg] == 1} {\n" ,"wm withdraw $w\n" ,"wm deiconify $w\n" ,"} {\n" ,"toplevel $w\n" ,"frame $w.a -borderwidth 0\n" ,"frame $w.b -borderwidth 0\n" ,"pack $w.a $w.b\n" ,"ttk::label $w.a.lab -text \"Number of partitions:\"\n" ,"entry $w.a.ent -textvariable w.parts -width 4 -relief sunken\n" ,"ttk::button $w.b.start -text \"Start METIS\" -command {\n" ,"Ng_Metis ${w.parts}\n" ,"redraw\n" ,"}\n" ,"ttk::button $w.b.cancel -text \"Cancel\" -command { destroy .metis_dlg }\n" ,"pack $w.a.lab $w.a.ent -side left -expand yes\n" ,"pack $w.b.start $w.b.cancel -side left\n" ,"wm withdraw $w\n" ,"wm geom $w +100+100\n" ,"wm deiconify $w\n" ,"wm title $w \"METIS Partitioning\"\n" ,"focus $w\n" ,"}\n" ,"}\n" ,"proc stloptionsdialog { } {\n" ,"set w .stlopts_dlg\n" ,"if {[winfo exists .stlopts_dlg] == 1} {\n" ,"wm withdraw $w\n" ,"wm deiconify $w\n" ,"focus $w\n" ,"} {\n" ,"toplevel $w\n" ,"pack [ttk::notebook $w.nb] -fill both -fill both -side top\n" ,"frame $w.bu\n" ,"pack $w.bu -fill x -ipady 3\n" ,"ttk::button $w.bu.apply -text \"Apply\" -command { redraw; Ng_GenerateMesh 1 2}\n" ,"ttk::button $w.bu.cancle -text \"Done\" -command { destroy .stlopts_dlg }\n" ,"pack $w.bu.cancle $w.bu.apply -side left -expand yes\n" ,"wm withdraw $w\n" ,"wm geom $w +100+100\n" ,"wm deiconify $w\n" ,"wm title $w \"STL Options\"\n" ,"focus $w\n" ,"}\n" ,"}\n" ,"proc stldoctordialog { } {\n" ,"Ng_STLDoctor\n" ,"set wd .stldoctor_dlg\n" ,"if {[winfo exists .stldoctor_dlg] == 1} {\n" ,"wm withdraw $wd\n" ,"wm deiconify $wd\n" ,"focus $wd\n" ,"} {\n" ,"toplevel $wd\n" ,"pack [ttk::notebook $wd.nb] -fill both -fill both -side top\n" ,"$wd.nb add [ttk::frame $wd.nb.general] -text \"General\" -underline 0\n" ,"$wd.nb add [ttk::frame $wd.nb.topology] -text \"Edit Topology\" -underline 5\n" ,"$wd.nb add [ttk::frame $wd.nb.edges] -text \"Edit Edges\" -underline 5\n" ,"$wd.nb add [ttk::frame $wd.nb.normals] -text \"Edit Normals\" -underline 5\n" ,"$wd.nb add [ttk::frame $wd.nb.advanced] -text \"Advanced\" -underline 0\n" ,"set f $wd.nb.general\n" ,"ttk::frame $f.selectframe -borderwidth 0\n" ,"ttk::checkbutton $f.selectframe.showtrias -text \"Show STL-Triangles\" \\\n" ,"-variable stloptions.showtrias -command { Ng_SetVisParameters; redraw }\n" ,"ttk::checkbutton $f.selectframe.showfilledtrias -text \"Show Filled Triangles\" \\\n" ,"-variable stloptions.showfilledtrias -command { Ng_SetVisParameters; redraw }\n" ,"set selmodevals { 0 1 2 3 4 }\n" ,"set selmodelabs(0) \"triangle\"\n" ,"set selmodelabs(1) \"edge\"\n" ,"set selmodelabs(2) \"point\"\n" ,"set selmodelabs(3) \"line\"\n" ,"set selmodelabs(4) \"line cluster\"\n" ,"global stldoctor.selectmode\n" ,"ttk::label $f.selectframe.dblcsellab -text \"Double Click selects : \"\n" ,"ttk::menubutton $f.selectframe.dblcselbut -menu $f.selectframe.dblcselmen -text \"triangle\" -width 16\n" ,"menu $f.selectframe.dblcselmen -tearoff 0\n" ,"foreach selmode { 0 1 2 3 4 } {\n" ,"$f.selectframe.dblcselmen add command -label $selmodelabs($selmode) \\\n" ,"-command \"set stldoctor.selectmode $selmode ; Ng_STLDoctor ; $f.selectframe.dblcselbut configure -text \\\"$selmodelabs($selmode)\\\"\"\n" ,"}\n" ,"$f.selectframe.dblcselmen invoke $selmodelabs(${stldoctor.selectmode})\n" ,"pack $f.selectframe\n" ,"grid $f.selectframe.showtrias -sticky nw\n" ,"grid $f.selectframe.showfilledtrias -sticky nw\n" ,"grid $f.selectframe.dblcsellab $f.selectframe.dblcselbut -sticky nw\n" ,"ttk::frame $f.sm\n" ,"pack $f.sm -fill x\n" ,"ttk::checkbutton $f.sm.bu -text \"select with mouse\" \\\n" ,"-variable stldoctor.selectwithmouse\n" ,"pack $f.sm.bu\n" ,"ttk::frame $f.st -relief groove -borderwidth 3\n" ,"pack $f.st -fill x\n" ,"ttk::label $f.st.lab -text \"Select triangle by number\";\n" ,"ttk::entry $f.st.ent -width 5 \\\n" ,"-textvariable stldoctor.selecttrig\n" ,"pack $f.st.ent $f.st.lab -side left -expand yes\n" ,"ttk::frame $f.vc -relief groove -borderwidth 3\n" ,"pack $f.vc -fill x\n" ,"ttk::checkbutton $f.vc.bu -text \"show vicinity\" \\\n" ,"-variable stldoctor.showvicinity \\\n" ,"-command {Ng_STLDoctor vicinity; redraw}\n" ,"ttk::label $f.vc.lab -text \"vicinity size\";\n" ,"ttk::frame $f.vc.sc\n" ,"ttk::scale $f.vc.sc.scale -orient horizontal -length 200 -from 0 -to 200 \\\n" ,"-variable stldoctor.vicinity -takefocus 0 -command \"Ng_STLDoctor vicinity; redraw; roundscale $f.vc.sc.scale 0\"\n" ,"ttk::entry $f.vc.sc.entry -textvariable stldoctor.vicinity -width 3 \\\n" ,"-validatecommand \"Ng_STLDoctor vicinity; redraw; my_validate %W [$f.vc.sc.scale cget -from] [$f.vc.sc.scale cget -to] %P 0\" \\\n" ,"-invalidcommand \"my_invalid %W;Ng_STLDoctor vicinity; redraw;\" -validate focus\n" ,"ttk::label $f.vc.sc.lab -text \"vicinity size\"\n" ,"grid $f.vc.sc.scale $f.vc.sc.entry $f.vc.sc.lab -sticky nw -padx 4\n" ,"pack $f.vc.bu $f.vc.lab $f.vc.sc -expand yes\n" ,"ttk::frame $f.ge -relief groove -borderwidth 0\n" ,"pack $f.ge -expand yes\n" ,"ttk::button $f.ge.neighbourangles -text \"calc neighbourangles\" -command {Ng_STLDoctor neighbourangles}\n" ,"ttk::button $f.ge.showcoords -text \"show coords of touched triangle\" -command {Ng_STLDoctor showcoords}\n" ,"ttk::button $f.ge.moveptm -text \"move point to middle of trianglepoints\" -command {Ng_STLDoctor movepointtomiddle; redraw}\n" ,"ttk::button $f.ge.destroy0trigs -text \"destroy 0-volume triangles\" -command {Ng_STLDoctor destroy0trigs}\n" ,"grid $f.ge.neighbourangles -sticky nw -padx 4 -pady 4\n" ,"grid $f.ge.showcoords -sticky nw -padx 4 -pady 4\n" ,"grid $f.ge.moveptm -sticky nw -padx 4 -pady 4\n" ,"grid $f.ge.destroy0trigs -sticky nw -padx 4 -pady 4\n" ,"ttk::button $f.ge.cancle -text \"Done\" -command {destroy .stldoctor_dlg }\n" ,"grid $f.ge.cancle -sticky nw\n" ,"set f $wd.nb.topology\n" ,"ttk::frame $f.oc -relief groove -borderwidth 3\n" ,"pack $f.oc -pady 3 -ipady 3 -fill y -fill x\n" ,"ttk::frame $f.oc.oc1 -borderwidth 0\n" ,"pack $f.oc.oc1\n" ,"ttk::button $f.oc.oc1.bu -text \"invert orientation \\n of selected trig\" -command {Ng_STLDoctor invertselectedtrig; redraw }\n" ,"ttk::button $f.oc.oc1.bu2 -text \"orient after \\n selected trig\" -command {Ng_STLDoctor orientafterselectedtrig; redraw }\n" ,"ttk::button $f.oc.oc1.toperr -text \"mark inconsistent triangles\" -command {Ng_STLDoctor marktoperrortrigs; redraw }\n" ,"ttk::button $f.oc.oc1.deltrig -text \"delete selected triangle\" -command {Ng_STLDoctor deleteselectedtrig; redraw }\n" ,"ttk::button $f.oc.oc1.geosmooth -text \"geometric smoothing\" -command {Ng_STLDoctor smoothgeometry; redraw }\n" ,"grid $f.oc.oc1.bu x $f.oc.oc1.bu2 -sticky nw -padx 4 -pady 4\n" ,"grid $f.oc.oc1.toperr - x -sticky nw -padx 4 -pady 4\n" ,"grid $f.oc.oc1.deltrig - x -sticky nw -padx 4 -pady 4\n" ,"grid $f.oc.oc1.geosmooth - x -sticky nw -padx 4 -pady 4\n" ,"set f $wd.nb.edges\n" ,"ttk::frame $f.be -relief groove -borderwidth 3\n" ,"pack $f.be -fill x\n" ,"ttk::frame $f.be.frame\n" ,"pack $f.be.frame -ipady 4 -pady 4\n" ,"ttk::label $f.be.frame.lab -text \"build edges with yellow angle:\";\n" ,"ttk::scale $f.be.frame.scale -orient horizontal -length 200 -from 0 -to 200 \\\n" ,"-variable stloptions.yangle -takefocus 0 -command \"roundscale $f.be.frame.scale 1; Ng_SetSTLParameters; Ng_STLDoctor buildedges; redraw\"\n" ,"ttk::entry $f.be.frame.entry -textvariable stloptions.yangle -width 5 \\\n" ,"-validatecommand \"Ng_SetSTLParameters; Ng_STLDoctor buildedges; redraw;my_validate %W [$f.be.frame.scale cget -from] [$f.be.frame.scale cget -to] %P 1\" \\\n" ,"-invalidcommand \"my_invalid %W;Ng_SetSTLParameters; Ng_STLDoctor buildedges; redraw\" -validate focus\n" ,"grid $f.be.frame.lab - -sticky nw -padx 4\n" ,"grid $f.be.frame.scale $f.be.frame.entry -sticky nw -padx 4\n" ,"ttk::label $f.be.frame.lab2 -text \"continue edges with yellow angle:\";\n" ,"ttk::scale $f.be.frame.scale2 -orient horizontal -length 200 -from 0 -to 100 \\\n" ,"-variable stloptions.contyangle -takefocus 0 -command \"roundscale $f.be.frame.scale2 1; Ng_SetSTLParameters; Ng_STLDoctor buildedges; redraw\"\n" ,"ttk::entry $f.be.frame.entry2 -textvariable stloptions.contyangle -width 5 \\\n" ,"-validatecommand \"Ng_SetSTLParameters; Ng_STLDoctor buildedges; redraw;my_validate %W [$f.be.frame.scale2 cget -from] [$f.be.frame.scale2 cget -to] %P 1\" \\\n" ,"-invalidcommand \"my_invalid %W;Ng_SetSTLParameters; Ng_STLDoctor buildedges; redraw\" -validate focus\n" ,"grid $f.be.frame.lab2 - -sticky nw -padx 4\n" ,"grid $f.be.frame.scale2 $f.be.frame.entry2 -sticky nw -padx 4\n" ,"ttk::button $f.be.frame.buildedges -text \"Build Edges\" -command {Ng_STLDoctor buildedges; redraw}\n" ,"grid $f.be.frame.buildedges - -sticky n -padx 4 -pady 4\n" ,"ttk::frame $f.se -relief groove -borderwidth 3\n" ,"pack $f.se -fill x\n" ,"ttk::checkbutton $f.se.bu -text \"show excluded\" \\\n" ,"-variable stldoctor.showexcluded \\\n" ,"-command {Ng_STLDoctor; redraw}\n" ,"pack $f.se.bu\n" ,"set edgeselmodevals { 0 1 2 3 4 }\n" ,"set edgeselmodelabs(0) \"no change\"\n" ,"set edgeselmodelabs(1) \"undefined\"\n" ,"set edgeselmodelabs(2) \"confirmed\"\n" ,"set edgeselmodelabs(3) \"candidate\"\n" ,"set edgeselmodelabs(4) \"excluded\"\n" ,"global stldoctor.edgeselectmode\n" ,"ttk::frame $f.scaleframe -relief groove -borderwidth 0\n" ,"pack $f.scaleframe -ipadx 4 -pady 4 -expand yes\n" ,"ttk::label $f.scaleframe.dblcedgelab -text \"Double Click sets edge :\"\n" ,"ttk::menubutton $f.scaleframe.dblcledgebut -menu $f.scaleframe.dblcledgem -text \"coarse\" -width 16\n" ,"menu $f.scaleframe.dblcledgem -tearoff 0\n" ,"foreach selectmode { 0 1 2 3 4 } {\n" ,"$f.scaleframe.dblcledgem add command -label $edgeselmodelabs($selectmode) \\\n" ,"-command \"set stldoctor.edgeselectmode $selectmode ; $f.scaleframe.dblcledgebut configure -text \\\"$edgeselmodelabs($selectmode)\\\"\"\n" ,"}\n" ,"$f.scaleframe.dblcledgem invoke $edgeselmodelabs(${stldoctor.edgeselectmode})\n" ,"grid $f.scaleframe.dblcedgelab $f.scaleframe.dblcledgebut -sticky n -ipadx 4\n" ,"ttk::frame $f.edg -relief groove -borderwidth 3\n" ,"pack $f.edg -fill x -ipadx 4 -ipady 4\n" ,"ttk::frame $f.edg.f0\n" ,"pack $f.edg.f0\n" ,"ttk::button $f.edg.f0.confirmedge -text \"confirm\" -command {Ng_STLDoctor confirmedge; redraw}\n" ,"ttk::button $f.edg.f0.candidateedge -text \"candidate\" -command {Ng_STLDoctor candidateedge; redraw}\n" ,"ttk::button $f.edg.f0.excludeedge -text \"exclude\" -command {Ng_STLDoctor excludeedge; redraw}\n" ,"ttk::button $f.edg.f0.undefinededge -text \"undefined\" -command {Ng_STLDoctor undefinededge; redraw}\n" ,"pack $f.edg.f0.confirmedge $f.edg.f0.candidateedge $f.edg.f0.excludeedge $f.edg.f0.undefinededge -side left\n" ,"ttk::frame $f.edg.fa\n" ,"pack $f.edg.fa\n" ,"ttk::button $f.edg.fa.setallundefined -text \"all undefined\" -command {Ng_STLDoctor setallundefinededges; redraw}\n" ,"ttk::button $f.edg.fa.erasecandidates -text \"candidates to undefined\" -command {Ng_STLDoctor erasecandidateedges; redraw}\n" ,"pack $f.edg.fa.setallundefined $f.edg.fa.erasecandidates -side left\n" ,"ttk::frame $f.edg.fb\n" ,"pack $f.edg.fb\n" ,"ttk::button $f.edg.fb.confirmcandidates -text \"candidates to confirmed\" -command {Ng_STLDoctor confirmcandidateedges; redraw}\n" ,"ttk::button $f.edg.fb.confirmedtocandidates -text \"confirmed to candidates\" -command {Ng_STLDoctor confirmedtocandidateedges; redraw}\n" ,"pack $f.edg.fb.confirmcandidates $f.edg.fb.confirmedtocandidates -side left\n" ,"ttk::frame $f.edg.f1\n" ,"ttk::frame $f.edg.f2\n" ,"ttk::frame $f.edg.f3\n" ,"ttk::frame $f.edg.f4\n" ,"pack $f.edg.f1 $f.edg.f2 $f.edg.f3 $f.edg.f4\n" ,"ttk::button $f.edg.f1.exportedges -text \"export edges\" -command {Ng_STLDoctor exportedges}\n" ,"ttk::button $f.edg.f1.importedges -text \"import edges\" -command {Ng_STLDoctor importedges; redraw}\n" ,"ttk::button $f.edg.f1.saveedgedata -text \"save edgedata\" \\\n" ,"-command {\n" ,"set types {\n" ,"{\"Netgen Edgedata\" {.ned} }\n" ,"}\n" ,"set file [tk_getSaveFile -filetypes $types -defaultextension \".ned\"]\n" ,"if {$file != \"\"} {\n" ,"Ng_STLDoctor saveedgedata $file\n" ,"}\n" ,"}\n" ,"ttk::button $f.edg.f1.loadedgedata -text \"load edgedata\" \\\n" ,"-command {\n" ,"set types {\n" ,"{\"Netgen Edgedata\" {.ned} }\n" ,"}\n" ,"set file [tk_getOpenFile -filetypes $types -defaultextension \".ned\"]\n" ,"if {$file != \"\"} {\n" ,"Ng_STLDoctor loadedgedata $file\n" ,"puts \"loading done\"\n" ,"redraw\n" ,"}\n" ,"}\n" ,"ttk::button $f.edg.f1.importAVLedges -text \"import AVL edges\" \\\n" ,"-command {\n" ,"set types {{\"Edge file\" {.edg }}}\n" ,"set file [tk_getOpenFile -filetypes $types -defaultextension \".edg\"]\n" ,"if {$file != \"\"} {\n" ,"Ng_STLDoctor importexternaledges $file;\n" ,"}\n" ,"}\n" ,"pack $f.edg.f1.importAVLedges $f.edg.f1.loadedgedata $f.edg.f1.saveedgedata -side left\n" ,"ttk::frame $f.edg2 -relief groove -borderwidth 3\n" ,"pack $f.edg2 -fill x\n" ,"ttk::label $f.edg2.lab -text \"length (%):\"\n" ,"scale $f.edg2.sc -orient horizontal -length 200 -from 0 -to 100 \\\n" ,"-resolution 0.5 \\\n" ,"-variable stldoctor.longlinefact\n" ,"ttk::button $f.edg2.undoedge -text \"undo last edge change\" -command {Ng_STLDoctor undoedgechange; redraw}\n" ,"pack $f.edg2.undoedge -expand yes\n" ,"set f $wd.nb.normals\n" ,"ttk::frame $f.dt -relief groove -borderwidth 3\n" ,"pack $f.dt -fill x\n" ,"ttk::label $f.dt.lab -text \"dirty triangle factor\";\n" ,"ttk::entry $f.dt.ent -width 5 \\\n" ,"-textvariable stldoctor.dirtytrigfact -validatecommand \"Ng_SetSTLParameters;my_validate %W -1e9 1e9 %P 3\" \\\n" ,"-invalidcommand \"my_invalid %W;Ng_SetSTLParameters\" -validate focus\n" ,"pack $f.dt.ent $f.dt.lab -side left -expand yes -pady 8\n" ,"ttk::frame $f.srt -relief groove -borderwidth 3\n" ,"pack $f.srt -fill x\n" ,"ttk::button $f.srt.bu -text \"smooth reverted triangles geometric\" -command {Ng_STLDoctor smoothrevertedtrigs; redraw }\n" ,"ttk::entry $f.srt.ent -width 5 \\\n" ,"-textvariable stldoctor.smoothangle -validatecommand \"Ng_SetSTLParameters;my_validate %W -1e9 1e9 %P 2\" \\\n" ,"-invalidcommand \"my_invalid %W;Ng_SetSTLParameters\" -validate focus\n" ,"pack $f.srt.ent $f.srt.bu -side left -expand yes -pady 8\n" ,"ttk::frame $f.bdt -relief groove -borderwidth 3\n" ,"pack $f.bdt -fill x\n" ,"ttk::button $f.bdt.bu -text \"mark dirty triangles\" -command {Ng_STLDoctor markdirtytrigs; redraw }\n" ,"ttk::button $f.bdt.bu2 -text \"smooth dirty triangles normal\" -command {Ng_STLDoctor smoothdirtytrigs; redraw }\n" ,"pack $f.bdt.bu $f.bdt.bu2 -side left -expand yes -pady 8\n" ,"ttk::frame $f.sno -relief groove -borderwidth 3\n" ,"pack $f.sno -fill x\n" ,"ttk::frame $f.sno.snoframe -borderwidth 0\n" ,"ttk::button $f.sno.smoothnormals -text \"smooth normals\" -command { Ng_STLDoctor smoothnormals; redraw}\n" ,"ttk::scale $f.sno.snoframe.scale -orient horizontal -length 100 -from 0.0 -to 0.8 \\\n" ,"-variable stldoctor.smoothnormalsweight -takefocus 0 -command \"roundscale $f.sno.snoframe.scale 2;Ng_SetSTLParameters\"\n" ,"ttk::entry $f.sno.snoframe.entry -textvariable stldoctor.smoothnormalsweight -width 4 \\\n" ,"-validatecommand \"Ng_SetSTLParameters;my_validate %W [$f.sno.snoframe.scale cget -from] [$f.sno.snoframe.scale cget -to] %P 2\" \\\n" ,"-invalidcommand \"my_invalid %W;Ng_SetSTLParameters\" -validate focus\n" ,"ttk::label $f.sno.snoframe.labrough -text \"rough\"\n" ,"ttk::label $f.sno.snoframe.labsmooth -text \"smooth\"\n" ,"grid $f.sno.snoframe.labrough $f.sno.snoframe.scale $f.sno.snoframe.labsmooth $f.sno.snoframe.entry -sticky nw -padx 4\n" ,"pack $f.sno.snoframe $f.sno.smoothnormals -side left -padx 5 -pady 8\n" ,"ttk::frame $f.no -relief groove -borderwidth 3\n" ,"pack $f.no -fill x\n" ,"ttk::button $f.no.marknonsmoothnormals -text \"mark non-smooth triangles\" -command {Ng_STLDoctor marknonsmoothnormals; redraw}\n" ,"ttk::button $f.no.calcnormals -text \"calculate normals from geometry\" -command {Ng_STLDoctor calcnormals; redraw}\n" ,"pack $f.no.marknonsmoothnormals $f.no.calcnormals -expand yes -pady 8\n" ,"set f $wd.nb.advanced\n" ,"ttk::frame $f.sc\n" ,"pack $f.sc -fill x\n" ,"ttk::checkbutton $f.sc.bu -text \"spiral check\" \\\n" ,"-variable stldoctor.spiralcheck \\\n" ,"-command {Ng_STLDoctor;}\n" ,"ttk::checkbutton $f.sc.bu2 -text \"cone check\" \\\n" ,"-variable stldoctor.conecheck \\\n" ,"-command {Ng_STLDoctor;}\n" ,"pack $f.sc.bu $f.sc.bu2\n" ,"ttk::label $f.gtol_lbl -text \"LoadSTL tolerance factor\"\n" ,"ttk::spinbox $f.gtol -from 1e-15 -to 0.001 -textvariable stldoctor.geom_tol_fact -width 8\n" ,"pack $f.gtol_lbl $f.gtol\n" ,"ttk::button $f.adap -text \"Apply\" -command {\n" ,"Ng_STLDoctor;\n" ,"}\n" ,"pack $f.adap -expand yes\n" ,"wm withdraw $wd\n" ,"wm geom $wd +100+100\n" ,"wm deiconify $wd\n" ,"wm title $wd \"STL Doctor\"\n" ,"focus $wd\n" ,"}\n" ,"}\n" ,"proc meshdoctordialog { } {\n" ,"set w .meshdoc_dlg\n" ,"global meshdoctor.active\n" ,"if {[winfo exists .meshdoc_dlg] == 1} {\n" ,"wm withdraw $w\n" ,"wm deiconify $w\n" ,"focus $w\n" ,"} {\n" ,"toplevel $w\n" ,"set meshdoctor.active 1\n" ,"Ng_MeshDoctor;\n" ,"ttk::frame $w.vis -relief groove -borderwidth 3\n" ,"pack $w.vis\n" ,"ttk::checkbutton $w.vis.showfilledtrigs -text \"Show filled triangles\" \\\n" ,"-variable viewoptions.drawfilledtrigs \\\n" ,"-command { Ng_SetVisParameters; redraw }\n" ,"ttk::checkbutton $w.vis.showedges -text \"Show edges\" \\\n" ,"-variable viewoptions.drawedges \\\n" ,"-command { Ng_SetVisParameters; redraw }\n" ,"ttk::checkbutton $w.vis.showoutline -text \"Show Triangle Outline\" \\\n" ,"-variable viewoptions.drawoutline \\\n" ,"-command { Ng_SetVisParameters; redraw }\n" ,"pack $w.vis.showfilledtrigs $w.vis.showoutline $w.vis.showedges\n" ,"ttk::frame $w.markedgedist\n" ,"ttk::label $w.markedgedist.l -text \"Mark edge dist: \"\n" ,"ttk::spinbox $w.markedgedist.s -from 0 -to 999 -width 5 -increment 1 -validate focus -validatecommand \"my_validatespinbox %W %P 0\" \\\n" ,"-invalidcommand \"my_invalidspinbox %W\" -command {Ng_MeshDoctor markedgedist ${meshdoc.markedgedist};redraw} -textvariable meshdoc.markedgedist\n" ,"pack $w.markedgedist.l $w.markedgedist.s -side left\n" ,"pack $w.markedgedist\n" ,"ttk::button $w.deledge -text \"Delete marked segments\" -command {\n" ,"Ng_MeshDoctor deletemarkedsegments\n" ,"redraw\n" ,"}\n" ,"pack $w.deledge\n" ,"ttk::button $w.close -text \"Close\" -command {\n" ,"set meshdoctor.active 0;\n" ,"Ng_MeshDoctor;\n" ,"destroy .meshdoc_dlg\n" ,"}\n" ,"pack $w.close -expand yes\n" ,"wm withdraw $w\n" ,"wm geom $w +100+100\n" ,"wm deiconify $w\n" ,"wm title $w \"Mesh Doctor\"\n" ,"}\n" ,"}\n" ,"proc qualityviewdialog { show } {\n" ,"set w .qualityview_dlg\n" ,"if {[winfo exists .qualityview_dlg] == 1} {\n" ,"if { $show == 1 } {\n" ,"wm withdraw .qualityview_dlg\n" ,"wm deiconify $w\n" ,"focus $w\n" ,"} {\n" ,"wm withdraw $w\n" ,"}\n" ,"} {\n" ,"toplevel $w\n" ,"set c $w.c\n" ,"canvas $c -relief raised -width 450 -height 300\n" ,"pack $w.c -side top -fill x\n" ,"set plotFont {Helvetica 12}\n" ,"set smallFont {Helvetica 12}\n" ,"$c create line 100 250 400 250 -width 2\n" ,"$c create line 100 250 100 50 -width 2\n" ,"for {set i 0} {$i <= 10} {incr i} {\n" ,"set x [expr {100 + ($i*30)}]\n" ,"$c create line $x 250 $x 245 -width 2\n" ,"if { [expr {$i % 2}] == 0 } {\n" ,"$c create text $x 254 -text [format %1.1f [expr 0.1*$i]] -anchor n -font $plotFont\n" ,"}\n" ,"}\n" ,"global qualbar\n" ,"global qualbarnull\n" ,"global qualbaraxis\n" ,"for {set i 0} {$i <= 5} {incr i} {\n" ,"set y [expr {250 - ($i*40)}]\n" ,"$c create line 100 $y 105 $y -width 2\n" ,"set qualbaraxis($i) \\\n" ,"[$c create text 96 $y -text [expr $i*50].0 -anchor e -font $plotFont]\n" ,"}\n" ,"for {set i 0} {$i < 20} {incr i} {\n" ,"set x1 [expr {100 + ($i*15) + 2}]\n" ,"set x2 [expr {$x1+10}]\n" ,"set y [expr {250 - 10 * $i}]\n" ,"set qualbar($i) [$c create rectangle $x1 250 $x2 245 -fill blue]\n" ,"set qualbarnull($i) [$c create text [expr {($x1+$x2)/2}] 245 -text 0 -anchor s -font $smallFont -fill blue]\n" ,"}\n" ,"frame $w.bu\n" ,"pack $w.bu\n" ,"ttk::button $w.close -text \"Close\" \\\n" ,"-command {\n" ,"wm withdraw .qualityview_dlg\n" ,"set viewqualityplot 0\n" ,"}\n" ,"pack $w.close\n" ,"if { $show == 1 } {\n" ,"wm withdraw $w\n" ,"wm geom $w +100+100\n" ,"wm deiconify $w\n" ,"wm title $w \"Mesh Quality\"\n" ,"focus $w\n" ,"}\n" ,"}\n" ,"}\n" ,"proc memusedialog { show } {\n" ,"set w .memuse_dlg\n" ,"if {[winfo exists .memuse_dlg] == 1} {\n" ,"if { $show == 1 } {\n" ,"wm withdraw .memuse_dlg\n" ,"wm deiconify $w\n" ,"focus $w\n" ,"} {\n" ,"wm withdraw $w\n" ,"}\n" ,"} {\n" ,"toplevel $w\n" ,"set c $w.c\n" ,"canvas $c -relief raised -width 600 -height 300\n" ,"pack $w.c -side top -fill x\n" ,"set plotFont {Helvetica 18}\n" ,"set smallFont {Helvetica 12}\n" ,"global memmark\n" ,"for {set i 0} {$i < 512} { incr i } {\n" ,"set memmark($i) [$c create line [expr 50+$i] 50 [expr 50+$i] 70 -fill blue]\n" ,"}\n" ,"set plotFont {Helvetica 18}\n" ,"set smallFont {Helvetica 12}\n" ,"$c create text 50 90 -text \"0 GB\" -anchor n -font $plotFont\n" ,"$c create text 178 90 -text \"1 GB\" -anchor n -font $plotFont\n" ,"$c create text 306 90 -text \"2 GB\" -anchor n -font $plotFont\n" ,"$c create text 434 90 -text \"3 GB\" -anchor n -font $plotFont\n" ,"$c create text 562 90 -text \"4 GB\" -anchor n -font $plotFont\n" ,"ttk::frame $w.bu\n" ,"pack $w.bu\n" ,"ttk::button $w.close -text \"Close\" \\\n" ,"-command {\n" ,"wm withdraw .memuse_dlg\n" ,"set memuseplot 0\n" ,"}\n" ,"pack $w.close\n" ,"if { $show == 1 } {\n" ,"wm withdraw $w\n" ,"wm geom $w +100+100\n" ,"wm deiconify $w\n" ,"wm title $w \"Memory Usage\"\n" ,"focus $w\n" ,"}\n" ,"}\n" ,"}\n" ,"proc STLinfodialog { show } {\n" ,"set w .STLinfo_dlg\n" ,"if {[winfo exists .STLinfo_dlg] == 1} {\n" ,"if { $show == 1 } {\n" ,"wm withdraw .STLinfo_dlg\n" ,"wm deiconify $w\n" ,"focus $w\n" ,"} {\n" ,"wm withdraw $w\n" ,"}\n" ,"} {\n" ,"toplevel $w\n" ,"set c $w.c\n" ,"canvas $c -relief raised -width 450 -height 300\n" ,"pack $w.c -side top -fill x\n" ,"set plotFont {Helvetica 18}\n" ,"set smallFont {Helvetica 12}\n" ,"$c create line 100 250 400 250 -width 2\n" ,"$c create line 100 250 100 50 -width 2\n" ,"ttk::frame $w.bu\n" ,"pack $w.bu\n" ,"ttk::button $w.close -text \"Close\" \\\n" ,"-command {\n" ,"wm withdraw .STLinfo_dlg\n" ,"}\n" ,"pack $w.close\n" ,"if { $show == 1 } {\n" ,"wm withdraw $w\n" ,"wm geom $w +100+100\n" ,"wm deiconify $w\n" ,"wm title $w \"STL Geometry Info\"\n" ,"focus $w\n" ,"}\n" ,"}\n" ,"}\n" ,"proc logwindow { } {\n" ,"set w .logwindow\n" ,"if {[winfo exists .logwindow] == 1} {\n" ,"wm withdraw $w\n" ,"wm deiconify $w\n" ,"focus $w\n" ,"} {\n" ,"toplevel $w\n" ,"text $w.edit -yscroll \"$w.scrolly set\" -setgrid 1 -height 12\n" ,"scrollbar $w.scrolly -command \"$w.edit yview\"\n" ,"pack $w.edit -side left -fill both -expand 1\n" ,"pack $w.scrolly -side left -fill both -expand 0\n" ,".logwindow.edit insert end \"Netgen Log Window\\n\"\n" ,"wm withdraw $w\n" ,"wm geom $w +100+100\n" ,"wm deiconify $w\n" ,"wm title $w \"Netgen Log\"\n" ,"focus $w\n" ,"}\n" ,"}\n" ,"proc printtable { tablevar } {\n" ,"set w newtcltable\n" ,"while {[winfo exists .$w] == 1} {set w 1$w}\n" ,"set w .$w\n" ,"toplevel $w\n" ,"for {set i 0} {$i < [lindex $tablevar 2]} { incr i } {\n" ,"frame $w.col$i\n" ,"for {set j 0} {$j < [lindex $tablevar 1]} { incr j } {\n" ,"frame $w.col$i.row$j\n" ,"message $w.col$i.row$j.txt -aspect 10000000 -text [lindex $tablevar [expr 3+[lindex $tablevar 2]*$j+$i]]\n" ,"pack $w.col$i.row$j.txt\n" ,"pack $w.col$i.row$j -side top\n" ,"}\n" ,"pack $w.col$i -side left\n" ,"}\n" ,"wm withdraw $w\n" ,"wm geom $w +200+100; wm deiconify $w\n" ,"wm title $w [lindex $tablevar 0]\n" ,"focus $w\n" ,"}\n" ,"set latestwarning 0\n" ,"proc printwarning { textvar } {\n" ,"global latestwarning\n" ,"set latestwarning $textvar\n" ,"set w warning\n" ,"while {[winfo exists .$w] == 1} {set w 1$w}\n" ,"set w .$w\n" ,"toplevel $w\n" ,"message $w.mes -aspect 2000 -text \"WARNING:\\n$textvar\"\n" ,"ttk::button $w.done -text \"Done\" -command \"destroy $w\"\n" ,"pack $w.mes\n" ,"pack $w.done\n" ,"wm withdraw $w\n" ,"wm deiconify $w\n" ,"wm title $w \"Warning\"\n" ,"focus $w\n" ,"}\n" ,"proc printlatestwarning { } {\n" ,"global latestwarning\n" ,"if {$latestwarning != 0} {printwarning $latestwarning}\n" ,"}\n" ,"}\n" ,"catch {\n" ,"set oldmousex 0\n" ,"set oldmousey 0\n" ,"set toglversion [Ng_GetToglVersion]\n" ,"puts \"togl-version : $toglversion\"\n" ,"set toglok 0\n" ,"if { [Ng_GetToglVersion] == 2 } {\n" ,"if {[catch {togl .ndraw -width 400 -height 300 -rgba true -double true -depth true -privatecmap false -stereo false -indirect false -create init -display draw -reshape reshape }] } {\n" ,"puts \"no OpenGL\"\n" ,"} {\n" ,"set toglok 1\n" ,"}\n" ,"} {\n" ,"if {[catch {togl .ndraw -width 400 -height 300 -rgba true -double true -depth true -privatecmap false -stereo false -indirect false }] } {\n" ,"puts \"no OpenGL\"\n" ,"} {\n" ,"set toglok 1\n" ,"}\n" ,"}\n" ,"if { $toglok == 1} {\n" ,"pack .ndraw -expand true -fill both -padx 0 -pady 0\n" ,"catch { tkdnd::drop_target register .ndraw DND_Files }\n" ,"bind .ndraw {\n" ,"set oldmousex %x; set oldmousey %y;\n" ,"}\n" ,"bind .ndraw {\n" ,"set oldmousex %x; set oldmousey %y;\n" ,"}\n" ,"bind .ndraw {\n" ,"set oldmousex %x; set oldmousey %y;\n" ,"}\n" ,"bind .ndraw {\n" ,"Ng_MouseMove $oldmousex $oldmousey %x %y $drawmode\n" ,".ndraw render\n" ,"set oldmousex %x; set oldmousey %y;\n" ,"}\n" ,"bind .ndraw {\n" ,"Ng_MouseDblClick %x %y\n" ,".ndraw render\n" ,"if { [winfo exists .bcprop_dlg] } { bcpropdialog }\n" ,"if { [winfo exists .surfacemeshsize_dlg] } { surfacemeshsizedialog }\n" ,"if { [winfo exists .fieldlines_dlg] } { fieldlinesdialog }\n" ,"}\n" ,"bind .ndraw {\n" ,"Ng_MouseMove $oldmousex $oldmousey %x %y move\n" ,".ndraw render\n" ,"set oldmousex %x; set oldmousey %y;\n" ,"}\n" ,"bind .ndraw {\n" ,"if { $tcl_platform(os) == \"Darwin\" } {\n" ,"Ng_MouseMove $oldmousex $oldmousey %x %y move\n" ,"} {\n" ,"Ng_MouseMove $oldmousex $oldmousey %x %y zoom\n" ,"}\n" ,".ndraw render\n" ,"set oldmousex %x; set oldmousey %y;\n" ,"}\n" ,"bind .ndraw {\n" ,"Ng_MouseMove $oldmousex $oldmousey %x %y Move2d\n" ,".ndraw render\n" ,"set oldmousex %x; set oldmousey %y;\n" ,"}\n" ,"bind .ndraw {\n" ,"Ng_MouseMove $oldmousex $oldmousey %x %y Zoom2d\n" ,".ndraw render\n" ,"set oldmousex %x; set oldmousey %y;\n" ,"}\n" ,"}\n" ,"proc popupcheckredraw { vari { x 0 } } {\n" ,"upvar $vari varname\n" ,"if { $varname == 1 } {\n" ,"set varname 0\n" ,"} {\n" ,"Ng_Vis_Set parameters\n" ,"redraw\n" ,"}\n" ,"}\n" ,"proc popupcheckredraw2 { vari boolvar { x 0 } } {\n" ,"upvar $vari varname\n" ,"if { $varname == 1 } {\n" ,"set varname 0\n" ,"} {\n" ,"Ng_SetVisParameters\n" ,"Ng_Vis_Set parameters\n" ,"if { $boolvar == 1 } { redraw }\n" ,"Ng_SetVisParameters\n" ,"}\n" ,"}\n" ,"proc popupcheckredraw3 { vari { x 0 } } {\n" ,"upvar $vari varname\n" ,"if { $varname == 1 } {\n" ,"set varname 0\n" ,"} {\n" ,"Ng_Vis_Set parameters\n" ,"}\n" ,"}\n" ,"proc redraw { {x 0} } {\n" ,"if {[winfo exists .ndraw]} { .ndraw render }\n" ,"}\n" ,"bind . { Ng_MouseMove 0 0 -10 0 rotate; redraw }\n" ,"bind . { Ng_MouseMove 0 0 10 0 rotate; redraw }\n" ,"bind . { Ng_MouseMove 0 0 0 -10 rotate; redraw }\n" ,"bind . { Ng_MouseMove 0 0 0 10 rotate; redraw }\n" ,"bind . { Ng_MouseMove 0 0 -10 0 move; redraw }\n" ,"bind . { Ng_MouseMove 0 0 10 0 move; redraw }\n" ,"bind . { Ng_MouseMove 0 0 0 -10 move; redraw }\n" ,"bind . { Ng_MouseMove 0 0 0 10 move; redraw }\n" ,"bind . { Ng_MouseMove 0 0 0 -10 zoom; redraw }\n" ,"bind . { Ng_MouseMove 0 0 0 10 zoom; redraw }\n" ,"bind . \\\n" ,"{event generate [focus -displayof %W] -delta 120}\n" ,"bind . \\\n" ,"{event generate [focus -displayof %W] -delta -120}\n" ,"bind . { Ng_MouseMove 0 0 0 [expr {%D/-5}] zoom; redraw }\n" ,"bind .ndraw <> {\n" ,"set filename [join %D \" \"]\n" ,"set index [string last . $filename]\n" ,"set type [string range $filename $index+1 end]\n" ,"set ispde [string match -nocase $type \"pde\"]\n" ,"set isgeo [expr max([string match -nocase $type \"geo\"],[string match -nocase $type \"in2d\"])]\n" ,"set ismesh [expr max([string match -nocase $type \"vol\"],[string match -nocase $type \"vol.gz\"])]\n" ,"set ispy [string match -nocase $type \"py\"]\n" ,"if {$ispde == 1} {\n" ,"AddRecentNGSFile $filename;\n" ,"NGS_LoadPDE $filename;\n" ,"SetNumProcHelpMenu\n" ,"set selectvisual mesh;\n" ,"Ng_SetVisParameters\n" ,"}\n" ,"if {$ispy == 1} {\n" ,"AddRecentPYNGSFile $filename;\n" ,"NGS_LoadPy $filename;\n" ,"}\n" ,"if {$isgeo == 1} {\n" ,"AddRecentFile $filename;\n" ,"Ng_LoadGeometry $filename;\n" ,"Ng_ParseGeometry\n" ,"set selectvisual geometry\n" ,"Ng_SetVisParameters\n" ,"redraw\n" ,"wm title . [concat \"$progname - \" $filename]\n" ,"set dirname [file dirname $filename]\n" ,"set basefilename [file tail [file rootname $filename]]\n" ,"}\n" ,"if {$ismesh == 1} {\n" ,"AddRecentMeshFile $filename;\n" ,"Ng_LoadMesh $filename;\n" ,"set selectvisual mesh\n" ,"Ng_SetVisParameters\n" ,"redraw\n" ,"Ng_ReadStatus;\n" ,"wm title . [concat \"$progname - \" %D]\n" ,"set dirname [file dirname %D]\n" ,"set basefilename [file tail [file rootname %D]]\n" ,"}\n" ,"return %A\n" ,"}\n" ,"}\n" ,"catch { .ngmenu.geometry add command -label \"Scan CSG Geometry\" -command { Ng_ParseGeometry }\n" ,".ngmenu.geometry add command -label \"CSG Options...\" -command geometryoptionsdialog\n" ,".ngmenu.geometry add command -label \"CSG Properties...\" \\\n" ,"-command topleveldialog2\n" ,"proc geometryoptionsdialog { } {\n" ,"set w .geometry_dlg\n" ,"if {[winfo exists .geometry_dlg] == 1} {\n" ,"wm withdraw $w\n" ,"wm deiconify $w\n" ,"focus $w\n" ,"} {\n" ,"toplevel $w\n" ,"global geooptions\n" ,"Ng_GeometryOptions get\n" ,"checkbutton $w.drawcsg -text \"Draw Geometry\" \\\n" ,"-variable geooptions.drawcsg\n" ,"pack $w.drawcsg\n" ,"frame $w.fac\n" ,"pack $w.fac -pady 5\n" ,"ttk::label $w.fac.lab -text \"Facets:\";\n" ,"entry $w.fac.ent -width 8 -relief sunken \\\n" ,"-textvariable geooptions.facets\n" ,"pack $w.fac.lab $w.fac.ent -side left\n" ,"frame $w.det\n" ,"pack $w.det -pady 5\n" ,"ttk::label $w.det.lab -text \"Detail:\";\n" ,"entry $w.det.ent -width 8 -relief sunken \\\n" ,"-textvariable geooptions.detail\n" ,"pack $w.det.lab $w.det.ent -side left\n" ,"frame $w.cox\n" ,"pack $w.cox -pady 5\n" ,"ttk::label $w.cox.lab -text \"min/max x:\";\n" ,"entry $w.cox.ent1 -width 8 -relief sunken \\\n" ,"-textvariable geooptions.minx\n" ,"entry $w.cox.ent2 -width 8 -relief sunken \\\n" ,"-textvariable geooptions.maxx\n" ,"pack $w.cox.lab $w.cox.ent1 \\\n" ,"$w.cox.ent2 -side left\n" ,"frame $w.coy\n" ,"pack $w.coy -pady 5\n" ,"ttk::label $w.coy.lab -text \"min/max y:\";\n" ,"entry $w.coy.ent1 -width 8 -relief sunken \\\n" ,"-textvariable geooptions.miny\n" ,"entry $w.coy.ent2 -width 8 -relief sunken \\\n" ,"-textvariable geooptions.maxy\n" ,"pack $w.coy.lab $w.coy.ent1 \\\n" ,"$w.coy.ent2 -side left\n" ,"frame $w.coz\n" ,"pack $w.coz -pady 5\n" ,"ttk::label $w.coz.lab -text \"min/max z:\";\n" ,"entry $w.coz.ent1 -width 8 -relief sunken \\\n" ,"-textvariable geooptions.minz\n" ,"entry $w.coz.ent2 -width 8 -relief sunken \\\n" ,"-textvariable geooptions.maxz\n" ,"pack $w.coz.lab $w.coz.ent1 \\\n" ,"$w.coz.ent2 -side left\n" ,"frame $w.bu\n" ,"pack $w.bu -fill x -ipady 3\n" ,"ttk::button $w.bu.app -text \"Apply\" -command {\n" ,"Ng_GeometryOptions set\n" ,"}\n" ,"ttk::button $w.bu.ok -text \"Done\" -command {\n" ,"Ng_GeometryOptions set\n" ,"destroy .geometry_dlg\n" ,"}\n" ,"pack $w.bu.app $w.bu.ok -side left -expand yes\n" ,"wm withdraw $w\n" ,"wm geom $w +100+100\n" ,"wm deiconify $w\n" ,"wm title $w \"Geometry options\"\n" ,"focus $w\n" ,"}\n" ,"}\n" ,"proc editprimitivedialog2 { name } {\n" ,"global w classname\n" ,"set w .ep_dlg\n" ,"toplevel .$w\n" ,"Ng_GetPrimitiveData $name classname valuelist\n" ,"ttk::label $w.lab1 -text \"Primitive Name: $name\";\n" ,"ttk::label $w.lab2 -text \"Primitive Class: $classname\";\n" ,"pack $w.lab1 $w.lab2 -fill x -pady 1m -padx 5m\n" ,"frame $w.specific -relief groove\n" ,"global spec\n" ,"set spec(sphere) { cx cy cz rad }\n" ,"set spec(cylinder) { ax ay az bx by bz rad }\n" ,"set spec(plane) { px py pz nx ny nz }\n" ,"set spec(cone) { ax ay az bx by bz ra rb }\n" ,"set spec(brick) { p1x p1y p1z p2x p2y p2z p3x p3y p3z p4x p4y p4z }\n" ,"set cnt 0\n" ,"foreach field $spec($classname) {\n" ,"frame $w.specific.f$cnt\n" ,"pack $w.specific.f$cnt -side top -anchor ne\n" ,"ttk::label $w.specific.f$cnt.lab -text \"$field\"\n" ,"entry $w.specific.f$cnt.ent -textvariable dataval($cnt) \\\n" ,"-width 6 -relief sunken\n" ,"pack $w.specific.f$cnt.ent $w.specific.f$cnt.lab -side right\n" ,"$w.specific.f$cnt.ent delete 0 end\n" ,"$w.specific.f$cnt.ent insert 0 [lindex $valuelist $cnt]\n" ,"set cnt [expr $cnt + 1]\n" ,"}\n" ,"pack $w.specific\n" ,"ttk::button $w.cancel -text \"cancel\" -command {\n" ,"destroy $w\n" ,"}\n" ,"ttk::button $w.ok -text \"ok\" -command {\n" ,"set valuelist \"\"\n" ,"set cnt 0\n" ,"foreach field $spec($classname) {\n" ,"lappend valuelist $dataval($cnt)\n" ,"set cnt [expr $cnt + 1]\n" ,"}\n" ,"Ng_SetPrimitiveData $name $valuelist\n" ,"destroy $w\n" ,"}\n" ,"pack $w.cancel $w.ok -side left -expand yes\n" ,"bind $w { $w.ok invoke}\n" ,"bind $w { $w.cancel invoke}\n" ,"wm withdraw $w\n" ,"wm geom $w +100+100\n" ,"wm deiconify $w\n" ,"focus $w.specific.f0.ent\n" ,"}\n" ,"proc editprimitivedialog { } {\n" ,"global w\n" ,"set w .ep_dlg\n" ,"toplevel $w\n" ,"frame $w.frame -borderwidth 5m\n" ,"pack $w.frame -side top -expand yes -fill y\n" ,"listbox $w.frame.list -yscroll \"$w.frame.scroll set\" -setgrid 1 -height 12\n" ,"scrollbar $w.frame.scroll -command \"$w.frame.list yview\"\n" ,"pack $w.frame.scroll -side right -fill y\n" ,"pack $w.frame.list -side left -expand 1 -fill both\n" ,"Ng_GetPrimitiveList primlist\n" ,"foreach el $primlist {\n" ,"$w.frame.list insert end $el }\n" ,"ttk::button $w.cancel -text \"cancel\" -command { destroy $w }\n" ,"ttk::button $w.ok -text \"ok\" -command {\n" ,"set name [.ep_dlg.frame.list get active]\n" ,"puts \"name=($name)\"\n" ,"destroy $w\n" ,"if { $name != \"\" } { editprimitivedialog2 $name }\n" ,"}\n" ,"bind $w { $w.cancel invoke }\n" ,"bind $w { $w.ok invoke }\n" ,"pack $w.cancel $w.ok -side left -expand yes\n" ,"wm withdraw $w\n" ,"wm geom $w +100+100\n" ,"wm deiconify $w\n" ,"focus $w.frame.list\n" ,"}\n" ,"proc newprimitivedialog { } {\n" ,"global w name\n" ,"set w .ap_dlg\n" ,"toplevel $w\n" ,"set name \"\"\n" ,"frame $w.f1\n" ,"pack $w.f1 -pady 2m\n" ,"ttk::label $w.f1.lab -text \"Primitive Name: \";\n" ,"entry $w.f1.ent -width 5 -relief sunken \\\n" ,"-textvariable name\n" ,"pack $w.f1.lab $w.f1.ent -side left\n" ,"frame $w.frame -borderwidth .5c\n" ,"pack $w.frame -side top -expand yes -fill y\n" ,"listbox $w.frame.list -yscroll \"$w.frame.scroll set\" -setgrid 1 -height 8\n" ,"scrollbar $w.frame.scroll -command \"$w.frame.list yview\"\n" ,"pack $w.frame.scroll -side right -fill y\n" ,"pack $w.frame.list -side left -expand 1 -fill both\n" ,"$w.frame.list insert 0 sphere cylinder plane cone brick\n" ,"$w.frame.list activate 0\n" ,"ttk::button $w.ok -text \"ok\" -command {\n" ,"Ng_CreatePrimitive [$w.frame.list get active] $name\n" ,"destroy $w\n" ,"editprimitivedialog2 $name\n" ,"}\n" ,"ttk::button $w.cancel -text \"cancel\" -command {\n" ,"destroy $w\n" ,"}\n" ,"pack $w.cancel $w.ok -side left -expand yes -pady 2m\n" ,"bind $w { $w.cancel invoke }\n" ,"bind $w { $w.ok invoke }\n" ,"wm withdraw $w\n" ,"wm geom $w +100+100\n" ,"wm deiconify $w\n" ,"focus $w.f1.ent\n" ,"}\n" ,"proc newsoliddialog { } {\n" ,"global w name val sollist\n" ,"set w .ns_dlg\n" ,"toplevel $w\n" ,"set name \"\"\n" ,"frame $w.f1\n" ,"ttk::label $w.f1.lab -text \"Solid Name: \";\n" ,"entry $w.f1.ent -width 5 -relief sunken \\\n" ,"-textvariable name\n" ,"$w.f1.ent delete 0 end\n" ,"ttk::button $w.f1.getsel -text \"Get Selected\" -command {\n" ,"$w.f1.ent delete 0 end\n" ,"$w.f1.ent insert 0 [$w.f3.list get active]\n" ,"$w.bu.get invoke\n" ,"}\n" ,"pack $w.f1.getsel -side bottom\n" ,"pack $w.f1.ent $w.f1.lab -side right\n" ,"frame $w.f3 -borderwidth .5c\n" ,"listbox $w.f3.list -yscroll \"$w.f3.scroll set\" -setgrid 1 -height 12\n" ,"scrollbar $w.f3.scroll -command \"$w.f3.list yview\"\n" ,"pack $w.f3.scroll -side right -fill y\n" ,"pack $w.f3.list -side left -expand 1 -fill both\n" ,"Ng_GetSolidList sollist\n" ,"foreach el $sollist {\n" ,"$w.f3.list insert end $el }\n" ,"frame $w.f2\n" ,"ttk::label $w.f2.lab -text \"Solid Description: \";\n" ,"pack $w.f2.lab\n" ,"entry $w.f2.ent -width 100 -relief sunken \\\n" ,"-textvariable val -xscrollcommand \"$w.f2.scr set\"\n" ,"scrollbar $w.f2.scr -relief sunken -orient horiz -command \\\n" ,"\"$w.f2.ent xview\"\n" ,"$w.f2.ent delete 0 end\n" ,"pack $w.f2.ent $w.f2.scr -fill x\n" ,"frame $w.bu\n" ,"ttk::button $w.bu.close -text \"close\" -command {\n" ,"destroy $w\n" ,"}\n" ,"ttk::button $w.bu.get -text \"get data\" -command {\n" ,"Ng_GetSolidData $name val\n" ,"}\n" ,"ttk::button $w.bu.set -text \"set data\" -command {\n" ,"Ng_SetSolidData $name $val\n" ,"}\n" ,"pack $w.bu.get $w.bu.set $w.bu.close -side left\n" ,"pack $w.bu -pady 5 -side bottom ;\n" ,"pack $w.f2 -pady 5 -side bottom ;\n" ,"pack $w.f1 -pady 5 -side left ;\n" ,"pack $w.f3 -side left -expand yes -fill y ;\n" ,"bind $w { $w.bu.close invoke }\n" ,"wm withdraw $w\n" ,"wm geom $w +100+100\n" ,"wm deiconify $w\n" ,"focus $w\n" ,"}\n" ,"proc toplevelproperties { w solname surfname } {\n" ,"global properties\n" ,"Ng_TopLevel getprop $solname $surfname properties\n" ,"set w .tlprop_dlg\n" ,"if {[winfo exists $w] == 1} {\n" ,"wm withdraw $w\n" ,"wm deiconify $w\n" ,"focus $w\n" ,"} {\n" ,"toplevel $w\n" ,"ttk::label $w.lab1 -text \"Red\"\n" ,"scale $w.scale1 -orient horizontal -length 300 -from 0 -to 1 \\\n" ,"-resolution 0.01 -tickinterval 0.2 \\\n" ,"-command { Ng_TopLevel setprop $solname $surfname properties; redraw } -variable properties(red)\n" ,"ttk::label $w.lab2 -text \"Green\"\n" ,"scale $w.scale2 -orient horizontal -length 300 -from 0 -to 1 \\\n" ,"-resolution 0.01 -tickinterval 0.2 \\\n" ,"-command { Ng_TopLevel setprop $solname $surfname properties; redraw } -variable properties(green)\n" ,"ttk::label $w.lab3 -text \"Blue\"\n" ,"scale $w.scale3 -orient horizontal -length 300 -from 0 -to 1 \\\n" ,"-resolution 0.01 -tickinterval 0.2 \\\n" ,"-command { Ng_TopLevel setprop $solname $surfname properties; redraw } -variable properties(blue)\n" ,"pack $w.lab1 $w.scale1 $w.lab2 $w.scale2 $w.lab3 $w.scale3\n" ,"checkbutton $w.cb4 -text \"Visible\" \\\n" ,"-command { Ng_TopLevel setprop $solname $surfname properties; redraw } \\\n" ,"-variable properties(visible)\n" ,"checkbutton $w.cb5 -text \"Transparent\" \\\n" ,"-command { Ng_TopLevel setprop $solname $surfname properties; redraw } \\\n" ,"-variable properties(transp)\n" ,"pack $w.cb4 $w.cb5\n" ,"frame $w.bu\n" ,"pack $w.bu -fill x\n" ,"ttk::button $w.bu.ok -text \"Ok\" -command \"destroy .tlprop_dlg\"\n" ,"pack $w.bu.ok -expand yes\n" ,"wm withdraw $w\n" ,"wm geom $w +100+100\n" ,"wm deiconify $w\n" ,"focus $w\n" ,"}\n" ,"wm title $w \"Properties $solname $surfname\"\n" ,"}\n" ,"proc topleveldialog { } {\n" ,"global w name val sollist\n" ,"set w .tl_dlg\n" ,"toplevel $w\n" ,"frame $w.sol -borderwidth .5c\n" ,"listbox $w.sol.list -yscroll \"$w.sol.scroll set\" -setgrid 1 -height 12\n" ,"scrollbar $w.sol.scroll -command \"$w.sol.list yview\"\n" ,"pack $w.sol.scroll -side right -fill y\n" ,"pack $w.sol.list -side left -expand 1 -fill both\n" ,"Ng_GetSolidList sollist\n" ,"foreach el $sollist {\n" ,"$w.sol.list insert end $el }\n" ,"Ng_GetPrimitiveList sollist\n" ,"foreach el $sollist {\n" ,"$w.sol.list insert end $el }\n" ,"frame $w.sul -borderwidth .5c\n" ,"listbox $w.sul.list -yscroll \"$w.sul.scroll set\" -setgrid 1 -height 12\n" ,"scrollbar $w.sul.scroll -command \"$w.sul.list yview\"\n" ,"pack $w.sul.scroll -side right -fill y\n" ,"pack $w.sul.list -side left -expand 1 -fill both\n" ,"Ng_GetSurfaceList sollist\n" ,"foreach el $sollist {\n" ,"$w.sul.list insert end $el }\n" ,"frame $w.topl -borderwidth .5c\n" ,"listbox $w.topl.list -yscroll \"$w.topl.scroll set\" -setgrid 1 -height 12 \\\n" ,"-command { puts hi }\n" ,"scrollbar $w.topl.scroll -command \"$w.topl.list yview\"\n" ,"pack $w.topl.scroll -side right -fill y\n" ,"pack $w.topl.list -side left -expand 1 -fill both\n" ,"Ng_TopLevel getlist sollist\n" ,"puts $sollist\n" ,"foreach el $sollist {\n" ,"set hel \"[ lindex $el 0 ]\"\n" ,"if { [ llength $el ] == 2 } {\n" ,"set hel \"[ lindex $el 1 ] on [ lindex $el 0 ]\"\n" ,"}\n" ,"$w.topl.list insert end $hel\n" ,"}\n" ,"frame $w.bu\n" ,"ttk::button $w.bu.close -text \"close\" -command {\n" ,"destroy $w\n" ,"}\n" ,"ttk::button $w.bu.addsol -text \"Add Solid\" -command {\n" ,"set solname [$w.sol.list get active]\n" ,"Ng_TopLevel set $solname \"\"\n" ,"Ng_ParseGeometry\n" ,"$w.topl.list insert end $solname\n" ,"}\n" ,"ttk::button $w.bu.addsurf -text \"Add Surface\" -command {\n" ,"set solname [$w.sol.list get active]\n" ,"set surfname [$w.sul.list get active]\n" ,"Ng_TopLevel set $solname $surfname\n" ,"Ng_ParseGeometry\n" ,"puts \"$solname on $surfname\"\n" ,"$w.topl.list insert end \"$surfname on $solname\"\n" ,"}\n" ,"ttk::button $w.bu.remsol -text \"Remove\" -command {\n" ,"set solname [$w.topl.list get active]\n" ,"set surfname \"\"\n" ,"if { [llength $solname] == 3 } {\n" ,"set surfname [lindex $solname 0]\n" ,"set solname [lindex $solname 2]\n" ,"}\n" ,"Ng_TopLevel remove $solname $surfname\n" ,"Ng_ParseGeometry\n" ,"$w.topl.list delete active\n" ,"}\n" ,"ttk::button $w.bu.prop -text \"Properties\" -command {\n" ,"set solname [$w.topl.list get active]\n" ,"set surfname \"\"\n" ,"if { [llength $solname] == 3 } {\n" ,"set surfname [lindex $solname 0]\n" ,"set solname [lindex $solname 2]\n" ,"}\n" ,"toplevelproperties tlp $solname $surfname\n" ,"}\n" ,"pack $w.bu.close $w.bu.addsol $w.bu.addsurf $w.bu.remsol $w.bu.prop -side left\n" ,"pack $w.bu -side bottom\n" ,"pack $w.sol -side left -expand yes -fill y ;\n" ,"pack $w.sul -side left -expand yes -fill y ;\n" ,"pack $w.topl -side left -expand yes -fill y ;\n" ,"bind $w { $w.bu.close invoke }\n" ,"wm withdraw $w\n" ,"wm geom $w +100+100\n" ,"wm deiconify $w\n" ,"focus $w\n" ,"}\n" ,"proc topleveldialog2 { } {\n" ,"set w .tl2_dlg\n" ,"if {[winfo exists .tl2_dlg] == 1} {\n" ,"wm withdraw $w\n" ,"wm deiconify $w\n" ,"focus $w\n" ,"} {\n" ,"toplevel $w\n" ,"global name val sollist\n" ,"frame $w.topl -borderwidth .5c\n" ,"listbox $w.topl.list -yscroll \"$w.topl.scroll set\" -setgrid 1 -height 12\n" ,"scrollbar $w.topl.scroll -command \"$w.topl.list yview\"\n" ,"pack $w.topl.scroll -side right -fill y\n" ,"pack $w.topl.list -side left -expand 1 -fill both\n" ,"Ng_TopLevel getlist sollist\n" ,"puts $sollist\n" ,"set i 1\n" ,"foreach el $sollist {\n" ,"set hel \"$i: [ lindex $el 0 ]\"\n" ,"if { [ llength $el ] == 2 } {\n" ,"set hel \"$i: [ lindex $el 1 ] on [ lindex $el 0 ]\"\n" ,"}\n" ,"incr i\n" ,"$w.topl.list insert end $hel }\n" ,"frame $w.bu\n" ,"ttk::button $w.bu.close -text \"close\" -command {\n" ,"destroy .tl2_dlg\n" ,"}\n" ,"ttk::button $w.bu.prop -text \"Properties\" -command {\n" ,"set solname [.tl2_dlg.topl.list get active]\n" ,"set surfname \"\"\n" ,"if { [llength $solname] == 2 } {\n" ,"set solname [lindex $solname 1]\n" ,"}\n" ,"if { [llength $solname] == 4 } {\n" ,"set surfname [lindex $solname 1]\n" ,"set solname [lindex $solname 3]\n" ,"}\n" ,"toplevelproperties tlp $solname $surfname\n" ,"}\n" ,"pack $w.bu.close $w.bu.prop -side left\n" ,"pack $w.bu -side bottom\n" ,"pack $w.topl -side left -expand yes -fill y ;\n" ,"bind .tl2_dlg.topl.list {\n" ,"set solname [.tl2_dlg.topl.list get @%x,%y]\n" ,"set surfname \"\"\n" ,"if { [llength $solname] == 2 } {\n" ,"set solname [lindex $solname 1]\n" ,"}\n" ,"if { [llength $solname] == 4 } {\n" ,"set surfname [lindex $solname 1]\n" ,"set solname [lindex $solname 3]\n" ,"}\n" ,"toplevelproperties tlp $solname $surfname\n" ,"}\n" ,"bind .tl2_dlg { .tl2_dlg.bu.close invoke }\n" ,"wm withdraw $w\n" ,"wm geom $w +100+100\n" ,"wm deiconify $w\n" ,"wm title $w \"Top-Level Options\"\n" ,"focus $w\n" ,"}\n" ,"}\n" ,"}\n" ,"catch { \n" ,".ngmenu.geometry add separator\n" ,".ngmenu.geometry add command -label \"STL Doctor...\" \\\n" ,"-command { stldoctordialog; }\n" ,".ngmenu.geometry add command -label \"STL Info\" \\\n" ,"-command {\n" ,"set notriangles 0\n" ,"set minx 0\n" ,"set maxx 0\n" ,"set miny 0\n" ,"set maxy 0\n" ,"set minz 0\n" ,"set maxz 0\n" ,"set trigscons 0\n" ,"Ng_STLInfo notriangles minx maxx miny maxy minz maxz trigscons\n" ,"set msgtext \"NO STL-Triangles : $notriangles\\nGeometry:\\nX = $minx - $maxx\\nY = $miny - $maxy\\nZ = $minz - $maxz\\nConsistency Check = $trigscons\\n\"\n" ,"set msgtext \"$msgtext Status: [Ng_STLInfo status]\"\n" ,"tk_messageBox -title \"STL Info\" -message $msgtext -type ok\n" ,"}\n" ,"}\n" ,"set hasocc no\n" ,"catch { if { [catch { load liboccvis[info sharedlibextension] Ng_OCC } result ] } {\n" ,"}\n" ,"if { [catch { Ng_OCCCommand isoccgeometryloaded }] } {\n" ,"proc rebuildoccdialog { } { }\n" ,"} {\n" ,"puts \"OCC module loaded\"\n" ,"set hasocc yes\n" ,".ngmenu.geometry add separator\n" ,".ngmenu.geometry add command -label \"IGES/STEP Topology Explorer/Doctor...\" \\\n" ,"-command { occdialog; }\n" ,".ngmenu.geometry add command -label \"Edit Face Mesh Size...\" \\\n" ,"-command { surfacemeshsizedialog }\n" ,"set entities [ ]\n" ,"proc occdialogbuildtree {} {\n" ,"global entities\n" ,"set w .occ_dlg\n" ,"set entities [Ng_GetOCCData getentities]\n" ,"set nrentities [expr [llength $entities]]\n" ,"if {$nrentities != 0} {\n" ,"$w.tree insert {Topology} end -id \"CompSolids\" -text \"Composite Solids\"\n" ,"$w.tree insert {Topology} end -id \"FreeSolids\" -text \"Free Solids\"\n" ,"$w.tree insert {Topology} end -id \"FreeShells\" -text \"Free Shells\"\n" ,"$w.tree insert {Topology} end -id \"FreeFaces\" -text \"Free Faces\"\n" ,"$w.tree insert {Topology} end -id \"FreeWires\" -text \"Free Wires\"\n" ,"$w.tree insert {Topology} end -id \"FreeEdges\" -text \"Free Edges\"\n" ,"$w.tree insert {Topology} end -id \"FreeVertices\" -text \"Free Vertices\"\n" ,"$w.tree item \"Topology\" -open true\n" ,"set i [expr 0]\n" ,"while {$i < $nrentities} {\n" ,"set entity [lindex $entities [expr $i]]\n" ,"incr i 1\n" ,"set entityname [lindex $entities [expr $i]]\n" ,"set myroot [string range $entity 0 [string last / $entity]-1]\n" ,"$w.tree insert $myroot end -id $entity -text $entityname -value 1\n" ,"incr i 1\n" ,"}\n" ,"set i [expr 0]\n" ,"while {$i < $nrentities} {\n" ,"set entity [lindex $entities [expr $i]]\n" ,"$w.tree item $entity -open false\n" ,"incr i 2\n" ,"}\n" ,"set faces [Ng_OCCCommand getunmeshedfaceinfo]\n" ,"set nrfaces [expr [llength $faces]]\n" ,"if {$nrfaces >= 2} {\n" ,"$w.tree insert {} end -id \"ErrorFaces\" -text \"Faces with surface meshing error\"\n" ,"$w.tree item ErrorFaces -open true\n" ,"set i [expr 0]\n" ,"while {$i < $nrfaces} {\n" ,"set entity [lindex $faces [expr $i]]\n" ,"set myroot [string range $entity 0 [string last / $entity]-1]\n" ,"if { [string length $myroot] == 0 } {\n" ,"set myroot \"ErrorFaces\"\n" ,"}\n" ,"incr i 1\n" ,"set entityname [lindex $faces [expr $i]]\n" ,"$w.tree insert $myroot end -id $entity -text $entityname -value 0\n" ,"incr i 1\n" ,"}\n" ,"}\n" ,"set faces [Ng_OCCCommand getnotdrawablefaces]\n" ,"set nrfaces [expr [llength $faces]]\n" ,"if {$nrfaces >= 2} {\n" ,"$w.tree insert {} -id NotDrawableFaces -text \"Faces impossible to visualize\"\n" ,"$w.tree item NotDrawableFaces -open true\n" ,"set i [expr 0]\n" ,"while {$i < $nrfaces} {\n" ,"set entity [lindex $faces [expr $i]]\n" ,"set myroot [string range $entity 0 [string last / $entity]-1]\n" ,"if { [string length $myroot ] == 0 } {\n" ,"set myroot NotDrawableFaces\n" ,"}\n" ,"incr i 1\n" ,"set entityname [lindex $faces [expr $i]]\n" ,"$w.tree insert $myroot end -id $entity -text $entityname -value 0\n" ,"incr i 1\n" ,"}\n" ,"}\n" ,"puts \"done\"\n" ,"}\n" ,"}\n" ,"proc rebuildoccdialog {} {\n" ,"if {[winfo exists .occ_dlg] == 1} {\n" ,".occ_dlg.tree delete [.occ_dlg.tree children Topology]\n" ,"occdialogbuildtree\n" ,"}\n" ,"}\n" ,"proc checkoccloaded { } {\n" ,"set isoccgeometryloaded [Ng_OCCCommand isoccgeometryloaded]\n" ,"if {$isoccgeometryloaded == 0} {\n" ,"puts \"no IGES/STEP geometry loaded\"\n" ,"destroy .occ_dlg\n" ,"}\n" ,"}\n" ,"proc selectentity { entityname } {\n" ,"global entities\n" ,"set nrentities [expr [llength $entities]]\n" ,"set i [expr 0]\n" ,"while {$i < $nrentities} {\n" ,"set entitylength []\n" ,"set entity2 [lindex $entities [expr $i]]\n" ,"incr i 1\n" ,"set entityname2 [lindex $entities [expr $i]]\n" ,"incr i 1\n" ,"set entityname2 [string range $entityname2 0 [expr [string length $entityname]-1]]\n" ,"if {$entityname == $entityname2} {\n" ,".occ_dlg.tree see $entity2\n" ,".occ_dlg.tree selection set $entity2\n" ,"}\n" ,"}\n" ,"}\n" ,"proc occdialog { } {\n" ,"uplevel 1 {\n" ,"global entities\n" ,"set selectvisual geometry\n" ,"Ng_SetVisParameters\n" ,"redraw\n" ,"set w .occ_dlg\n" ,"if {[winfo exists .occ_dlg] == 1} {\n" ,"wm withdraw $w\n" ,"wm deiconify $w\n" ,"focus $w\n" ,"} {\n" ,"toplevel $w\n" ,"ttk::treeview $w.tree\n" ,"$w.tree insert {} end -id \"Topology\" -text \"Topology\"\n" ,"pack $w.tree -fill both -expand yes\n" ,"occdialogbuildtree\n" ,"bind $w.tree {\n" ,"set entityname [.occ_dlg.tree item [.occ_dlg.tree selection] -text ]\n" ,"set rootname \"\"\n" ,"if {[.occ_dlg.tree item [.occ_dlg.tree selection] -value] == 1 } {\n" ,"set rootname \"Topology\"\n" ,"}\n" ,"set spacepos [string first \" \" $entityname]\n" ,"set entitytype [string range $entityname 0 [expr $spacepos-1]]\n" ,"set helpstring [string range $entityname [expr $spacepos+1] [expr [string length $entityname]-1]]\n" ,"set spacepos2 [string first \" \" $helpstring]\n" ,"set entitynumber [string range $helpstring 0 [expr $spacepos2-1]]\n" ,"if {$rootname == \"Topology\"} {\n" ,"Ng_OCCCommand highlightentity $entitytype $entitynumber\n" ,"set selectvisual geometry\n" ,"redraw\n" ,"} {\n" ,"set brackpos [string first \" (\" $entityname]\n" ,"if {$brackpos != -1} {\n" ,"set entityname [string range $entityname 0 $brackpos]\n" ,"}\n" ,"selectentity $entityname\n" ,"}\n" ,"}\n" ,"ttk::button $w.cl -text \"Close\" -command {\n" ,"destroy .occ_dlg\n" ,"}\n" ,"ttk::button $w.show -text \"Show\" -command {\n" ,"set entityname [.occ_dlg.tree item [.occ_dlg.tree selection] -text ]\n" ,"set spacepos [string first \" \" $entityname]\n" ,"set entitytype [string range $entityname 0 [expr $spacepos-1]]\n" ,"set helpstring [string range $entityname [expr $spacepos+1] [expr [string length $entityname]-1]]\n" ,"set spacepos2 [string first \" \" $helpstring]\n" ,"set entitynumber [string range $helpstring 0 [expr $spacepos2-1]]\n" ,"Ng_OCCCommand show $entitytype $entitynumber\n" ,"set selectvisual geometry\n" ,"redraw\n" ,"}\n" ,"ttk::button $w.hide -text \"Hide\" -command {\n" ,"set entityname [.occ_dlg.tree item [.occ_dlg.tree selection] -text ]\n" ,"set spacepos [string first \" \" $entityname]\n" ,"set entitytype [string range $entityname 0 [expr $spacepos-1]]\n" ,"set helpstring [string range $entityname [expr $spacepos+1] [expr [string length $entityname]-1]]\n" ,"set spacepos2 [string first \" \" $helpstring]\n" ,"set entitynumber [string range $helpstring 0 [expr $spacepos2-1]]\n" ,"Ng_OCCCommand hide $entitytype $entitynumber\n" ,"set selectvisual geometry\n" ,"redraw\n" ,"}\n" ,"ttk::button $w.swaporientation -text \"Swap orientation\" -command {\n" ,"set entityname [.occ_dlg.tree item [.occ_dlg.tree selection] -text ]\n" ,"set spacepos [string first \" \" $entityname]\n" ,"set entitytype [string range $entityname 0 [expr $spacepos-1]]\n" ,"set helpstring [string range $entityname [expr $spacepos+1] [expr [string length $entityname]-1]]\n" ,"set spacepos2 [string first \" \" $helpstring]\n" ,"set entitynumber [string range $helpstring 0 [expr $spacepos2-1]]\n" ,"Ng_OCCCommand swaporientation $entitytype $entitynumber\n" ,"set selectvisual geometry\n" ,"redraw\n" ,".occ_dlg.tree delete [.occ_dlg.tree children Topology]\n" ,"occdialogbuildtree\n" ,"}\n" ,"ttk::button $w.marksingular -text \"Mark/Unmark as singular\" -command {\n" ,"set entityname [.occ_dlg.tree item [.occ_dlg.tree selection] -text ]\n" ,"set spacepos [string first \" \" $entityname]\n" ,"if { $spacepos != 0 } {\n" ,"set entitytype [string range $entityname 0 [expr $spacepos-1]]\n" ,"set helpstring [string range $entityname [expr $spacepos+1] [expr [string length $entityname]-1]]\n" ,"set spacepos2 [string first \" \" $helpstring]\n" ,"if { $spacepos2 != 0 } {\n" ,"set entitynumber [string range $helpstring 0 [expr $spacepos2-1]]\n" ,"puts $entitytype\n" ,"puts $entitynumber\n" ,"global ismarkedsingular\n" ,"Ng_OCCCommand marksingular $entitytype $entitynumber\n" ,"if { $ismarkedsingular == 0 } {\n" ,".occ_dlg.tree tag remove \"Color\" [.occ_dlg.tree selection]\n" ,"} {\n" ,".occ_dlg.tree tag add \"Color\" [.occ_dlg.tree selection]\n" ,".occ_dlg.tree tag configure \"Color\" -foreground \"red\"\n" ,".occ_dlg.tree tag configure \"Color\" -background \"blue\"\n" ,"}\n" ,"}\n" ,"}\n" ,"}\n" ,"ttk::checkbutton $w.zoomtohighlightedentity -text \"Zoom to highlighted entity\" \\\n" ,"-variable occoptions.zoomtohighlightedentity \\\n" ,"-command {\n" ,"Ng_SetOCCVisParameters\n" ,"if { ${occoptions.zoomtohighlightedentity} == 1} {\n" ,"set selectvisual geometry\n" ,"Ng_OCCCommand redrawstatus 1\n" ,"redraw\n" ,"} {\n" ,"Ng_OCCCommand redrawstatus 0\n" ,"}\n" ,"}\n" ,"ttk::frame $w.healing -relief groove -borderwidth 3\n" ,"ttk::button $w.healing.checkentities -text \"Analyze geometry\" -command {\n" ,"set irregent [Ng_OCCCommand findsmallentities]\n" ,"set w .occ_dlg\n" ,"set nritems [expr [llength $irregent]]\n" ,"set i [expr 0]\n" ,"if {$nritems > 0 } {\n" ,"if { [.occ_dlg.tree exists ProblematicEntities] == 1 } {\n" ,"$w.tree delete ProblematicEntities\n" ,"}\n" ,"$w.tree insert {} end -id ProblematicEntities -text \"Problematic Entities\"\n" ,"}\n" ,"while {$i < $nritems} {\n" ,"set entity [lindex $irregent [expr $i]]\n" ,"incr i 1\n" ,"set entityname [lindex $irregent [expr $i]]\n" ,"set myroot [string range $entity 0 [string last / $entity]-1]\n" ,"if { [string length $myroot] == 0 } {\n" ,"set myroot ProblematicEntities\n" ,"}\n" ,"$w.tree insert $myroot end -id $entity -text $entityname\n" ,"incr i 1\n" ,"}\n" ,"$w.tree item ProblematicEntities -open true\n" ,"}\n" ,"ttk::frame $w.healing.tolerance\n" ,"ttk::label $w.healing.tolerance.label -text \"Healing tolerance: \"\n" ,"ttk::spinbox $w.healing.tolerance.sp -textvariable occoptions.tolerance -width 6 -increment 0.01 -validate focus -validatecommand \"my_validatespinbox %W %P 12\" \\\n" ,"-invalidcommand \"my_invalidspinbox %W\" -from -1e-9 -to 1e6\n" ,"grid $w.healing.tolerance.label $w.healing.tolerance.sp\n" ,"ttk::checkbutton $w.healing.fixsmalledges -text \"Fix small edges\" \\\n" ,"-variable occoptions.fixsmalledges\n" ,"ttk::checkbutton $w.healing.fixspotstripfaces -text \"Fix spot/strip faces\" \\\n" ,"-variable occoptions.fixspotstripfaces\n" ,"ttk::checkbutton $w.healing.sewfaces -text \"Sew faces\" \\\n" ,"-variable occoptions.sewfaces\n" ,"ttk::checkbutton $w.healing.makesolids -text \"Make solids\" \\\n" ,"-variable occoptions.makesolids\n" ,"ttk::checkbutton $w.healing.splitpartitions -text \"Split partitions\" \\\n" ,"-variable occoptions.splitpartitions\n" ,"ttk::button $w.healing.heal -text \"Heal geometry\" -command {\n" ,"Ng_OCCCommand shapehealing\n" ,"redraw\n" ,".occ_dlg.tree delete [.occ_dlg.tree children Topology]\n" ,"occdialogbuildtree\n" ,"}\n" ,"pack $w.healing.checkentities\n" ,"pack $w.healing.tolerance $w.healing.fixsmalledges \\\n" ,"$w.healing.fixspotstripfaces $w.healing.sewfaces \\\n" ,"$w.healing.makesolids $w.healing.splitpartitions -anchor w\n" ,"pack $w.healing.heal\n" ,"pack $w.show $w.hide\n" ,"pack $w.zoomtohighlightedentity -anchor w\n" ,"pack $w.swaporientation\n" ,"pack $w.marksingular\n" ,"pack $w.healing -fill x\n" ,"pack $w.cl\n" ,"wm withdraw $w\n" ,"wm geom $w +100+100\n" ,"wm deiconify $w\n" ,"wm title $w \"IGES/STEP Topology Explorer/Doctor\"\n" ,"focus .occ_dlg\n" ,"}\n" ,"}\n" ,"}\n" ,"} }\n" ,"if { [Ng_ACISCommand isACISavailable] == \"yes\" } {\n" ,".ngmenu.geometry add command -label \"ACIS Topology Explorer...\" \\\n" ,"-command { acisdialog; }\n" ,".ngmenu.geometry add command -label \"ACIS combine all\" \\\n" ,"-command { Ng_ACISCommand combineall }\n" ,".ngmenu.geometry add command -label \"ACIS Create CT\" \\\n" ,"-command { Ng_ACISCommand createct }\n" ,"}\n" ,"catch { proc print_commandline_help { } {\n" ,"puts \"Usage: ng { options }\"\n" ,"puts \"-geofile=filename Input geometry file (alternative: ng filename)\"\n" ,"puts \"-meshfile=filename Output mesh file\"\n" ,"puts \"-verycoarse, -coarse, -moderate, -fine, -veryfine\"\n" ,"puts \" Automatic mesh-size selection\"\n" ,"puts \"-meshsizefile=filename Load mesh-size file with local mesh sizes\"\n" ,"puts \"-meshfiletype={\\\"Neutral Format\\\", ...}\"\n" ,"puts \" Filetype of output file, default is netgen file\"\n" ,"puts \"-batchmode Run Netgen in batchmode\"\n" ,"puts \"-inputmeshfile=filename\"\n" ,"puts \" Input mesh file (batchmode only)\"\n" ,"puts \"-mergefile=filename Merge with mesh file (batchmode only)\"\n" ,"puts \"-refinementfile=filename\"\n" ,"puts \" Use refinementinfo from file (batchmode only)\"\n" ,"puts \"-serversocket=\\\n" ,"puts \"-V Print additional information\"\n" ,"puts \"-testout=filename file for test output\"\n" ,"if { [catch { NGS_GetData } ] == 0 } {\n" ,"puts \"\\nNGSolve parameters:\"\n" ,"puts \"-pdefile=filename Load pde input file\"\n" ,"puts \"-solve Solve pde once\"\n" ,"puts \"-solve=n Solve pde by n adaptive refinement steps\"\n" ,"puts \"-recent Load and solve most recently loaded pde\"\n" ,"}\n" ,"}\n" ,"proc set_menu_help { entry helpmsg } {\n" ,"global menuhelps\n" ,"set menuhelps($entry) $helpmsg\n" ,"}\n" ,"proc show_menu_help { entry } {\n" ,"global menuhelps\n" ,"if {[catch {set helptext $menuhelps($entry)}]} {\n" ,"set helptext \"no help available \"\n" ,"}\n" ,".helpline configure -text $helptext\n" ,"if {[winfo exists .senshelp_dlg]==1} {\n" ,".senshelp_dlg.text delete 1.0 end\n" ,".senshelp_dlg.text insert end \"Menu item: $entry\\n\\n\"\n" ,".senshelp_dlg.text insert end $helptext\n" ,"}\n" ,"}\n" ,"proc set_control_help { control helpmsg } {\n" ,"bind $control \"show_control_help {$helpmsg}\"\n" ,"bind $control \"show_control_help {None}\"\n" ,".balloon bind $control -balloonmsg $helpmsg -statusmsg $helpmsg\n" ,"}\n" ,"proc show_control_help { helpmsg } {\n" ,".helpline configure -text $helpmsg\n" ,"if {[winfo exists .senshelp_dlg]==1} {\n" ,".senshelp_dlg.text delete 1.0 end\n" ,".senshelp_dlg.text insert end $helpmsg\n" ,"}\n" ,"}\n" ,"proc sensitivehelpdialog { show } {\n" ,"set w .senshelp_dlg\n" ,"if {[winfo exists .senshelp_dlg] == 1} {\n" ,"if { $show == 1 } {\n" ,"wm withdraw .senshelp_dlg\n" ,"wm deiconify $w\n" ,"focus $w\n" ,"} {\n" ,"wm withdraw $w\n" ,"}\n" ,"} {\n" ,"toplevel $w\n" ,"global senshelptext\n" ,"text $w.text -yscrollcommand \"$w.scroll set\" -setgrid true \\\n" ,"-width 40 -height 10 -wrap word\n" ,"scrollbar $w.scroll -command \"$w.text yview\"\n" ,"pack $w.scroll -side right -fill y\n" ,"pack $w.text -expand yes -fill both\n" ,"ttk::frame $w.bu\n" ,"pack $w.bu\n" ,"ttk::button $w.close -text \"Close\" \\\n" ,"-command {\n" ,"wm withdraw .senshelp_dlg\n" ,"set showsensitivehelp 0\n" ,"}\n" ,"pack $w.close\n" ,"if { $show == 1 } {\n" ,"wm withdraw $w\n" ,"wm geom $w +100+100\n" ,"wm deiconify $w\n" ,"wm title $w \"Help\"\n" ,"focus $w\n" ,"}\n" ,"}\n" ,"}\n" ,"set_menu_help \"File\" \"In File menu you can load and store geometries, meshes etc.\"\n" ,"set_menu_help \"New Geometry\" \"Deletes current geometry\"\n" ,"set_menu_help \"Load Geometry\" \"Loads Geometry file in one of the formats STL (ASCII or binary), Constructive Solid Geometry (.geo) or 2D geometry. Please have a look into Netgen User's manuel for more details.\"\n" ,"set_menu_help \"Save Geometry\" \"Saves STL Geometry in in either ASCII or binary STL format.\"\n" ,"set_menu_help \"Load Mesh\" \"Loads surface and volume mesh in Netgen internal format.\"\n" ,"set_menu_help \"Save Mesh\" \"Saves surface and volume mesh in Netgen internal format.\"\n" ,"set_menu_help \"Write EPS File\" \"Dumps OpenGL rendering to EPS File.\"\n" ,"set_menu_help \"Save Options\" \"Saves current options in file \\\"ng.opt\\\". These options will be loaded again when starting ng in the same directory.\"\n" ,"set_menu_help \"Export Mesh\" \"Exports mesh in format defined by Export Filetype.\"\n" ,"set_menu_help \"Export Filetype\" \"Selects file format for exporting mesh. Please have a look into the Netgen User's manual for more information.\"\n" ,"set_menu_help \"Import Mesh\" \"Imports surface or volume mesh in exchange format.\"\n" ,"set_menu_help \"Quit\" \"Quits Netgen\"\n" ,"set_menu_help \"Geometry\" \"Preparing geometries, visualiztion of geometries.\"\n" ,"set_menu_help \"Scan CSG Geometry\" \"Generates surface triangulation for rendering\"\n" ,"set_menu_help \"CSG Options\" \"Sets Options for CSG visualization (bounding box, detail size, number of facets).\"\n" ,"set_menu_help \"CSG Properties\" \"Defines appearance of current CSG geometry (color, visibility, transparency)\"\n" ,"set_menu_help \"STL Doctor\" \"Calls STL Doctor for preprocessing STL geometry files.\"\n" ,"set_menu_help \"STL Info\" \"Retrieves information about current STL geometry.\"\n" ,"set_menu_help \"Mesh\" \"Menu for mesh generation\"\n" ,"set_menu_help \"Generate Mesh\" \"Generates mesh from geometry, same as Button \\\"Generate Mesh\\\"\"\n" ,"set_menu_help \"Stop Meshing\" \"Terminates meshgeneration. It may take a while until meshing terminates, please be patient.\"\n" ,"set_menu_help \"Meshing Options\" \"Set options for mesh generation.\"\n" ,"set_menu_help \"Delete Mesh\" \"Deletes mesh. Not necessary before generation of new mesh.\"\n" ,"set_menu_help \"Delete Vol Mesh\" \"Deletes only volume mesh.\"\n" ,"set_menu_help \"Mesh Quality\" \"Computs element shape measures. Triangle angles are inner angles of all triangles (faces of tetrahedra). Tet angles are angles between faces of tetrahedra.\"\n" ,"set_menu_help \"Check Surface Mesh\" \"Checks consistency and overlap of surface mesh. Marks overlapping elements as bad elements, please enable visualization of bad elements in View->Mesh.\"\n" ,"set_menu_help \"Check Volume Mesh\" \"Checks conformity of volume mesh.\"\n" ,"set_menu_help \"Edit Boundary Conditions\" \"Open dialog for setting boundary condition numbers for individual faces.\"\n" ,"set_menu_help \"Analyze Geometry\" \"Perform only first step in mesh generation. Action depends on geometry type, e.g. generates charts for STL mesh, find vertices in CSG geometries.\"\n" ,"set_menu_help \"Mesh Edges\" \"Meshes edges\"\n" ,"set_menu_help \"Mesh Surface\" \"Generates surface mesh. Includes already surface optimization for some geometry types.\"\n" ,"set_menu_help \"Optimize Surface\" \"Optimizes surface mesh.\"\n" ,"set_menu_help \"Surface Optim. Step\" \"Performs a specific surface optimiztion step. Mesh smoothing moves nodes. edge swapping swaps the diagonal of a quadrilateral built by two triangles, criterion either by number of nodes, or anlges. Combine points eliminates triangles by combining points (in the center of gravity).\"\n" ,"set_menu_help \"Mesh Volume\" \"Performs volume meshing. Algorithm is a combination of Delaunay and Rule-based Advancing Front\"\n" ,"set_menu_help \"Optimize Volume\" \"Performs additional volume optimization steps\"\n" ,"set_menu_help \"Smooth Opt Volume\" \"Performs optimization steps by smoothing iterations\"\n" ,"set_menu_help \"Smooth Opt Volume Jacobian\" \"Volume optimization by smoothing iterations. Criterion is optimization of Jacobi determinants. This optimization step is also available for 10-node tetrahedra.\"\n" ,"set_menu_help \"View\" \"Sets viewing options\"\n" ,"set_menu_help \"Zoom all\" \"Zooms scene to show whole object\"\n" ,"set_menu_help \"Center\" \"Defines center of rotation\"\n" ,"set_menu_help \"Viewing Options\" \"Sets viewing options for geometry, mesh, lighting\"\n" ,"set_menu_help \"Clipping Plane\" \"Introduces clipping plane. The clipping plane is defined by the normal vector, and a scaled offset. Clipping of performed by OpenGl rendering\"\n" ,"set_menu_help \"Quality Plot\" \"Shows the element quality distribution histogram. Measure is volume scaled by edge-length to the third. Optimal elements have measure 1.\"\n" ,"set_menu_help \"Sensitive Help\" \"Shows this help window\"\n" ,"set_menu_help \"Mesh-size\" \"Manipulations of existing mesh\"\n" ,"set_menu_help \"Refine uniform\" \"Refines mesh by splitting elements into eight childs (algorithm of J. Bey)\"\n" ,"set_menu_help \"Second Order\" \"Converts 4 node elements to 10 node elements. Edge-midpoitns are projected to the geometry.\"\n" ,"set_menu_help \"Refinement Dialog\" \"Controls local mesh refinement\"\n" ,"set_menu_help \"Load Meshsize\" \"Loads mesh-size file for local mesh refinement.\"\n" ,"set_menu_help \"MS from Surf Mesh\" \"Defines mesh-size by the surface mesh.\"\n" ,"set f .options_dlg.nb.nbframe.general\n" ,"set_control_help $f.fine \"Controls relative mesh size.\\nThis control affects other mesh-size controls in common\"\n" ,"set_control_help $f.first \"First step in mesh generation. Usually, meshing starts from \\\"analyze geometry\\\". If the surface mesh is already available \\\"First step\\\" should be set to \\\"mesh volume\\\"\"\n" ,"set_control_help $f.last \"Last step in mesh generation. If only the surface mesh is required, please set \\\"Last Step\\\" to \\\"Optimize Surface\\\"\"\n" ,"set_control_help .bubar.surfm \"Start mesh generation\"\n" ,"set_control_help .bubar.stopm \"Stop mesh generation\"\n" ,"proc help_item { helptext } {p\n" ,"puts $helptext\n" ,"}\n" ,"proc show_help { } {\n" ,"set w .help\n" ,"if {[winfo exists .help] == 1} {\n" ,"wm withdraw $w\n" ,"wm deiconif $w\n" ,"focus $w\n" ,"} {\n" ,"toplevel $w\n" ,"frame $w.buttons\n" ,"pack $w.buttons -side bottom -fill x -pady 2m\n" ,"button $w.buttons.done -text Done -command \"destroy $w\"\n" ,"pack $w.buttons.done -side left -expand 1\n" ,"text $w.text -yscrollcommand \"$w.scroll set\" -setgrid true \\\n" ,"-width 60 -height 24 -wrap word\n" ,"scrollbar $w.scroll -command \"$w.text yview\"\n" ,"pack $w.scroll -side right -fill y\n" ,"pack $w.text -expand yes -fill both\n" ,"}\n" ,"$w.text configure -state normal\n" ,"$w.text delete 1.0 end\n" ,"}\n" ,"set bold \"-background \n" ,"set normal \"-background {} -relief flat\"\n" ,"proc help_main { } {\n" ,"show_help;\n" ,"set w .help\n" ,"global bold\n" ,"global normal\n" ,"$w.text insert 0.0 \\\n" ,"{NETGEN Help}\n" ,"$w.text insert end \\n\\n\n" ,"$w.text insert end \\\n" ,"{1. General} d1\n" ,"$w.text insert end \\n\\n\n" ,"$w.text insert end \\\n" ,"{2. Menu items } d2\n" ,"$w.text insert end \\n\\n\n" ,"foreach tag {d1 d2} {\n" ,"$w.text tag bind $tag \"$w.text tag configure $tag $bold\"\n" ,"$w.text tag bind $tag \"$w.text tag configure $tag $normal\"\n" ,"}\n" ,"$w.text tag bind d1 <1> { puts \"general\"; help_general }\n" ,"$w.text tag bind d2 <1> { help_menus }\n" ,"$w.text configure -state disabled\n" ,"}\n" ,"proc help_general { } {\n" ,"show_help;\n" ,"set w .help\n" ,"global bold\n" ,"global normal\n" ,"puts \"general called\"\n" ,"$w.text insert 0.0 \\\n" ,"{NETGEN is an automatic three dimensional tetrahedral mesh generation system. It accepts input from constructive solid geometry (CSG) or boundary representation (BRep) from STEP or STL file format. NETGEN contains modules for mesh optimization and hierarchical mesh refinement.}\n" ,"$w.text configure -state disabled\n" ,"}\n" ,"proc help_menus { } {\n" ,"show_help;\n" ,"set w .help\n" ,"global bold\n" ,"global normal\n" ,"$w.text insert 0.0 \\\n" ,"{The NETGEN Menu items are}\n" ,"$w.text insert end \\n\\n\n" ,"$w.text insert end \\\n" ,"{1. File} d1\n" ,"$w.text insert end \\n\\n\n" ,"$w.text insert end \\\n" ,"{2. Geometry } d2\n" ,"$w.text insert end \\n\\n\n" ,"$w.text insert end \\\n" ,"{3. Mesh } d3\n" ,"$w.text insert end \\n\\n\n" ,"$w.text insert end \\\n" ,"{4. View } d4\n" ,"$w.text insert end \\n\\n\n" ,"$w.text insert end \\\n" ,"{5. Mesh-size } d5\n" ,"$w.text insert end \\n\\n\n" ,"$w.text insert end \\\n" ,"{6. STL } d6\n" ,"foreach tag {d1 d2 d3 d4 d5 d6} {\n" ,"$w.text tag bind $tag \"$w.text tag configure $tag $bold\"\n" ,"$w.text tag bind $tag \"$w.text tag configure $tag $normal\"\n" ,"}\n" ,"$w.text tag bind d1 <1> {puts \"File menu\"}\n" ,"$w.text tag bind d2 <1> {puts \"Geometry menu\"}\n" ,"$w.text tag bind d3 <1> {puts \"Mesh menu\"}\n" ,"$w.text tag bind d4 <1> {puts \"View menu\"}\n" ,"$w.text tag bind d5 <1> {puts \"Mesh-size menu\"}\n" ,"$w.text tag bind d6 <1> {puts \"STL menu\"}\n" ,"$w.text configure -state disabled\n" ,"}\n" ,"}\n" ,"catch { Ng_Vis_Set parameters\n" ,"set viscnt 0\n" ,"proc snapshottimer { } {\n" ,"after 2000 { snapshottimer }\n" ,"global viscnt\n" ,"set viscnt [expr $viscnt+1]\n" ,"set s1 0000$viscnt\n" ,"set cnt [string range $s1 [expr [string length $s1]-4] end]\n" ,"set filename \"p$cnt.jpg\"\n" ,"}\n" ,"snapshottimer\n" ,"proc redrawtimer { } {\n" ,"global visoptions.autoredraw\n" ,"global visoptions.autoredrawtime\n" ,"set delay [expr int(${visoptions.autoredrawtime}*1000)]\n" ,"if { ${visoptions.autoredraw} == 1 } { redraw; }\n" ,"after $delay { redrawtimer }\n" ,"}\n" ,"redrawtimer\n" ,"set perstarttime [clock clicks -millisecond]\n" ,"proc redrawperiodic { } {\n" ,"global visoptions.redrawperiodic\n" ,"global perstarttime\n" ,"set curtime [clock clicks -millisecond]\n" ,"Ng_Vis_Set time [expr ($curtime - $perstarttime) / 5]\n" ,"redraw\n" ,"if { ${visoptions.redrawperiodic} == 1 } { after 30 { redrawperiodic } };\n" ,"}\n" ,"proc addplotline { identifier datax datay plotinfo {color black}} {\n" ,"set c $identifier.c\n" ,"set xstart [lindex $plotinfo 0]\n" ,"set ystart [lindex $plotinfo 1]\n" ,"set xmin [lindex $plotinfo 2]\n" ,"set ymin [lindex $plotinfo 3]\n" ,"set unitx [lindex $plotinfo 4]\n" ,"set unity [lindex $plotinfo 5]\n" ,"set latestx [expr ([lindex $datax 0]-$xmin)*$unitx + $xstart]\n" ,"set latesty [expr ([lindex $datay 0]-$ymin)*$unity + $ystart]\n" ,"for {set i 1} {$i < [llength $datax]} {incr i} {\n" ,"set xpos [expr ([lindex $datax $i]-$xmin)*$unitx + $xstart]\n" ,"set ypos [expr ([lindex $datay $i]-$ymin)*$unity + $ystart]\n" ,"$c create line $latestx $latesty $xpos $ypos -width 1 -fill $color\n" ,"set latestx $xpos\n" ,"set latesty $ypos\n" ,"}\n" ,"}\n" ,"proc createlineplot { width height identifier title xmin xmax ymin ymax plotinfo} {\n" ,"set thiswidth $width\n" ,"set thisheight $height\n" ,"if { $thiswidth < 275 } { set thiswidth 275 }\n" ,"if { $thisheight < 225 } { seth thisheight 225 }\n" ,"set w $identifier\n" ,"if {[winfo exists $w] == 1} {\n" ,"wm withdraw $w\n" ,"wm deiconify $w\n" ,"focus $w\n" ,"} {\n" ,"toplevel $w\n" ,"set c $w.c\n" ,"canvas $c -relief raised -width $thiswidth -height $thisheight\n" ,"pack $w.c -side top -fill x\n" ,"set titleFont {Helvetica 18}\n" ,"set smallFont {Helvetica 12}\n" ,"set xstart 100\n" ,"set xend [expr $thiswidth-75]\n" ,"set ystart [expr $thisheight-75]\n" ,"set yend 75\n" ,"$c create line $xstart $ystart $xstart $yend -width 2\n" ,"$c create line $xstart $ystart $xend $ystart -width 2\n" ,"set unitx [expr double($xend-$xstart)/($xmax-$xmin)]\n" ,"set unity [expr double($yend-$ystart)/($ymax-$ymin)]\n" ,"for {set i 0} {$i <= 1} {set i [expr $i+0.2]} {\n" ,"$c create line [expr $xstart+$i*($xend-$xstart)] [expr $ystart] [expr $xstart+$i*($xend-$xstart)] [expr $ystart+5] -width 2\n" ,"$c create text [expr $xstart+$i*($xend-$xstart)] [expr $ystart+7] -anchor n -font $smallFont \\\n" ,"-text [format \"%.3g\" [expr $xmin+$i*($xmax-$xmin)]]\n" ,"$c create line [expr $xstart] [expr $ystart+$i*($yend-$ystart)] [expr $xstart-7] [expr $ystart+$i*($yend-$ystart)] -width 2\n" ,"$c create text [expr $xstart-9] [expr $ystart+$i*($yend-$ystart)] -anchor e -font $smallFont \\\n" ,"-text [format \"%.3g\" [expr $ymin+$i*($ymax-$ymin)]]\n" ,"}\n" ,"upvar $plotinfo ploti\n" ,"set ploti \"$xstart $ystart $xmin $ymin $unitx $unity\"\n" ,"button $w.close -text \"Close\" -command \"destroy $w\"\n" ,"pack $w.close\n" ,"wm withdraw $w\n" ,"wm geom $w +100+100\n" ,"wm deiconify $w\n" ,"wm title $w $title\n" ,"focus $w\n" ,"}\n" ,"}\n" ,"proc getlineplotdata { datax datay xmini xmaxi ymini ymaxi} {\n" ,"upvar $datax datx\n" ,"upvar $datay daty\n" ,"upvar $xmini xmin\n" ,"upvar $xmaxi xmax\n" ,"upvar $ymini ymin\n" ,"upvar $ymaxi ymax\n" ,"global visoptions.lineplotusingx\n" ,"global visoptions.lineplotusingy\n" ,"global visoptions.lineplotsource\n" ,"global visoptions.lineplotfile\n" ,"set datx \"\"\n" ,"set daty \"\"\n" ,"set xmin 1e20\n" ,"set xmax -1e20\n" ,"set ymin 1e20\n" ,"set ymax -1e20\n" ,"if {${visoptions.lineplotsource} == \"file\"} {\n" ,"set fileId [open ${visoptions.lineplotfile} r]\n" ,"set line \"\"\n" ,"while {[gets $fileId line] >= 0} {\n" ,"if { [string index [lindex $line 0] 0] != \"\\\n" ,"if { ${visoptions.lineplotusingx} < [llength $line] } {\n" ,"lappend datx [lindex $line ${visoptions.lineplotusingx}]\n" ,"if { [lindex $datx end] < $xmin } {set xmin [lindex $datx end]}\n" ,"if { [lindex $datx end] > $xmax } {set xmax [lindex $datx end]}\n" ,"} {\n" ,"lappend datx 0\n" ,"}\n" ,"if { ${visoptions.lineplotusingy} < [llength $line] } {\n" ,"lappend daty [lindex $line ${visoptions.lineplotusingy}]\n" ,"if { [lindex $daty end] < $ymin } {set ymin [lindex $daty end]}\n" ,"if { [lindex $daty end] > $ymax } {set ymax [lindex $daty end]}\n" ,"} {\n" ,"lappend daty 0\n" ,"}\n" ,"}\n" ,"}\n" ,"close $fileId\n" ,"}\n" ,"}\n" ,"proc lineplotdialog { } {\n" ,"set w .lineplot_dlg\n" ,"if {[winfo exists .lineplot_dlg] == 1} {\n" ,"wm withdraw $w\n" ,"wm deiconify $w\n" ,"focus $w\n" ,"} {\n" ,"toplevel $w\n" ,"ttk::frame $w.filesettings -relief groove -borderwidth 3\n" ,"ttk::frame $w.filesettings.title\n" ,"ttk::radiobutton $w.filesettings.title.choose -variable visoptions.lineplotsource \\\n" ,"-value file -text \"Data from File\"\n" ,"pack $w.filesettings.title.choose -side left\n" ,"pack $w.filesettings.title\n" ,"global visoptions.lineplotselectedeval\n" ,"global visoptions.lineplotfile\n" ,"global visoptions.evaluatefilenames\n" ,"global visoptions.evaluatefiledescriptions\n" ,"set evdata [NGS_GetData evaluatefiles]\n" ,"set visoptions.evaluatefilenames none\n" ,"set visoptions.evaluatefiledescriptions none\n" ,"for {set i 0} {[expr $i+1] < [llength $evdata]} {incr i 2} {\n" ,"lappend visoptions.evaluatefilenames [lindex $evdata $i]\n" ,"lappend visoptions.evaluatefiledescriptions [lindex $evdata [expr $i+1]]\n" ,"}\n" ,"ttk::frame $w.filesettings.latestevals\n" ,"ttk::label $w.filesettings.latestevals.lab -text \"Use Evaluate Results: \"\n" ,"ttk::menubutton $w.filesettings.latestevals.but -menu $w.filesettings.latestevals.menu -text \"coarse\" -width 40\n" ,"menu $w.filesettings.latestevals.menu -tearoff 0\n" ,"for {set i 0} {$i < [llength ${visoptions.evaluatefilenames}]} {incr i} {\n" ,"$w.filesettings.latestevals.menu add command -label $i\\\n" ,"-command \"set visoptions.lineplotselectedeval $i ; $w.filesettings.latestevals.but configure -text \\\"[lindex ${visoptions.evaluatefiledescriptions} $i] ([lindex ${visoptions.evaluatefilenames} $i])\\\"\"\n" ,"}\n" ,"$w.filesettings.latestevals.menu invoke ${visoptions.lineplotselectedeval}\n" ,"grid $w.filesettings.latestevals.lab $w.filesettings.latestevals.but -sticky nw\n" ,"pack $w.filesettings.latestevals\n" ,"ttk::frame $w.filesettings.sfn\n" ,"ttk::button $w.filesettings.sfn.bb -text \"Browse\" \\\n" ,"-command { set visoptions.lineplotfile [tk_getOpenFile] }\n" ,"ttk::entry $w.filesettings.sfn.fn -width 50 \\\n" ,"-textvariable visoptions.lineplotfile\n" ,"pack $w.filesettings.sfn.bb $w.filesettings.sfn.fn -side left\n" ,"pack $w.filesettings.sfn\n" ,"ttk::button $w.filesettings.refresh -text \"Refresh\" -command {\n" ,"if { ${visoptions.lineplotselectedeval} != 0} {\n" ,"set visoptions.lineplotfile [lindex ${visoptions.evaluatefilenames} ${visoptions.lineplotselectedeval}]\n" ,"}\n" ,"set saveusingx ${visoptions.lineplotusingx}\n" ,"set saveusingy ${visoptions.lineplotusingy}\n" ,"for { set i 0 } { $i < [llength ${visoptions.lineplotdatadescr}] } { incr i } {\n" ,"${visoptions.lineplotxcoordselector} delete $i\n" ,"}\n" ,"for { set i 0 } { $i < [llength ${visoptions.lineplotdatadescr}] } { incr i } {\n" ,"${visoptions.lineplotycoordselector} delete $i\n" ,"}\n" ,"set fileId [open ${visoptions.lineplotfile} r]\n" ,"set line \"\"\n" ,"gets $fileId line\n" ,"close $fileId\n" ,"if { [lindex $line 0] == \"\\\n" ,"set visoptions.lineplotdatadescr [lrange $line 1 end]\n" ,"} {\n" ,"set visoptions.lineplotdatadescr \"\"\n" ,"for { set i 0 } { $i < [llength $line] } { incr i } {\n" ,"lappend visoptions.lineplotdatadescr \"data[expr $i+1]\"\n" ,"}\n" ,"}\n" ,"for { set i 0 } { $i < [llength ${visoptions.lineplotdatadescr}] } { incr i } {\n" ,"${visoptions.lineplotxcoordselector} add command $i -label [lindex ${visoptions.lineplotdatadescr} $i]\n" ,"}\n" ,"for { set i 0 } { $i < [llength ${visoptions.lineplotdatadescr}] } { incr i } {\n" ,"${visoptions.lineplotycoordselector} add command $i -label [lindex ${visoptions.lineplotdatadescr} $i]\n" ,"}\n" ,"if { $saveusingx < [llength ${visoptions.lineplotdatadescr}] } {\n" ,"set visoptions.lineplotusingx $saveusingx\n" ,"} {\n" ,"set visoptions.lineplotusingx 0\n" ,"}\n" ,"if { $saveusingy < [llength ${visoptions.lineplotdatadescr}] } {\n" ,"set visoptions.lineplotusingy $saveusingy\n" ,"} {\n" ,"set visoptions.lineplotusingy 1\n" ,"}\n" ,"}\n" ,"pack $w.filesettings.refresh\n" ,"ttk::frame $w.filesettings.using\n" ,"global visoptions.lineplotdatadescr\n" ,"ttk::frame $w.filesettings.using.xco\n" ,"ttk::label $w.filesettings.using.xco.lab -text \"X-Coord:\"\n" ,"ttk::menubutton $w.filesettings.using.xco.but -menu $w.filesettings.using.xco.menu -text \"\" -width 15\n" ,"menu $w.filesettings.using.xco.menu -tearoff 0\n" ,"for {set i 0} {$i < [llength ${visoptions.lineplotdatadescr}]} {incr i} {\n" ,"$w.filesettings.using.xco.menu add command -label [lindex ${visoptions.lineplotdatadescr} $i]\\\n" ,"-command \"set visoptions.lineplotusingx $i ; $w.filesettings.using.xco.but configure -text \\\"[lindex ${visoptions.lineplotdatadescr} $i]\\\"\"\n" ,"}\n" ,"$w.filesettings.using.xco.menu invoke [lindex ${visoptions.lineplotdatadescr} 0]\n" ,"grid $w.filesettings.using.xco.lab $w.filesettings.using.xco.but -sticky nw\n" ,"ttk::frame $w.filesettings.using.yco\n" ,"ttk::label $w.filesettings.using.yco.lab -text \"Y-Coord:\"\n" ,"ttk::menubutton $w.filesettings.using.yco.but -menu $w.filesettings.using.yco.menu -text \"\" -width 15\n" ,"menu $w.filesettings.using.yco.menu -tearoff 0\n" ,"for {set i 0} {$i < [llength ${visoptions.lineplotdatadescr}]} {incr i} {\n" ,"$w.filesettings.using.yco.menu add command -label [lindex ${visoptions.lineplotdatadescr} $i]\\\n" ,"-command \"set visoptions.lineplotusingy $i ; $w.filesettings.using.yco.but configure -text \\\"[lindex ${visoptions.lineplotdatadescr} $i]\\\"\"\n" ,"}\n" ,"$w.filesettings.using.yco.menu invoke [lindex ${visoptions.lineplotdatadescr} 0]\n" ,"grid $w.filesettings.using.yco.lab $w.filesettings.using.yco.but -sticky nw\n" ,"global visoptions.lineplotxcoordselector\n" ,"global visoptions.lineplotycoordselector\n" ,"set visoptions.lineplotxcoordselector $w.filesettings.using.xco\n" ,"set visoptions.lineplotycoordselector $w.filesettings.using.yco\n" ,"pack $w.filesettings.using.xco $w.filesettings.using.yco -side left\n" ,"pack $w.filesettings.using\n" ,"pack $w.filesettings -fill x -ipady 3\n" ,"ttk::frame $w.settings -relief groove -borderwidth 3\n" ,"ttk::label $w.settings.title -text \"\\nSettings\\n\"\n" ,"pack $w.settings.title\n" ,"ttk::frame $w.settings.minmax\n" ,"ttk::checkbutton $w.settings.minmax.autoscale -text \"Autoscale\" -variable visoptions.lineplotautoscale\n" ,"ttk::frame $w.settings.minmax.xmin\n" ,"ttk::label $w.settings.minmax.xmin.label -text \"Min. x: \"\n" ,"ttk::spinbox $w.settings.minmax.xmin.sp -textvariable visoptions.lineplotxmin -width 6 -increment 0.1 -validate focus -validatecommand \"my_validatespinbox %W %P 3\" \\\n" ,"-invalidcommand \"my_invalidspinbox %W\" -from -1e9 -to 1e9\n" ,"ttk::frame $w.settings.minmax.xmax\n" ,"ttk::label $w.settings.minmax.xmax.label -text \"Max. x: \"\n" ,"ttk::spinbox $w.settings.minmax.xmax.sp -textvariable visoptions.lineplotxmax -width 6 -increment 0.1 -validate focus -validatecommand \"my_validatespinbox %W %P 3\" \\\n" ,"-invalidcommand \"my_invalidspinbox %W\" -from -1e9 -to 1e9\n" ,"ttk::frame $w.settings.minmax.ymin\n" ,"ttk::label $w.settings.minmax.ymin.label -text \"Min. y: \"\n" ,"ttk::spinbox $w.settings.minmax.ymin.sp -textvariable visoptions.lineplotymin -width 6 -increment 0.1 -validate focus -validatecommand \"my_validatespinbox %W %P 3\" \\\n" ,"-invalidcommand \"my_invalidspinbox %W\" -from -1e9 -to 1e9\n" ,"ttk::frame $w.settings.minmax.ymax\n" ,"ttk::label $w.settings.minmax.ymax.label -text \"Max. y: \"\n" ,"ttk::spinbox $w.settings.minmax.ymax.sp -textvariable visoptions.lineplotymax -width 6 -increment 0.1 -validate focus -validatecommand \"my_validatespinbox %W %P 3\" \\\n" ,"-invalidcommand \"my_invalidspinbox %W\" -from -1e9 -to 1e9\n" ,"pack $w.settings.minmax.xmin.label $w.settings.minmax.xmin.sp\n" ,"pack $w.settings.minmax.xmax.label $w.settings.minmax.xmax.sp\n" ,"pack $w.settings.minmax.ymin.label $w.settings.minmax.ymin.sp\n" ,"pack $w.settings.minmax.ymax.label $w.settings.minmax.ymax.sp\n" ,"pack $w.settings.minmax.autoscale $w.settings.minmax.xmin $w.settings.minmax.xmax \\\n" ,"$w.settings.minmax.ymin $w.settings.minmax.ymax -side left\n" ,"pack $w.settings.minmax\n" ,"ttk::label $w.settings.empty1 -text \"\"\n" ,"pack $w.settings.empty1\n" ,"ttk::frame $w.settings.plotsize\n" ,"ttk::frame $w.settings.plotsize.xsize\n" ,"ttk::label $w.settings.plotsize.xsize.label -text \"Plotsize x: \"\n" ,"ttk::spinbox $w.settings.plotsize.xsize.sp -textvariable visoptions.lineplotsizex -width 6 -increment 1 -validate focus -validatecommand \"my_validatespinbox %W %P 0\" \\\n" ,"-invalidcommand \"my_invalidspinbox %W\" -from -1e9 -to 1e9\n" ,"pack $w.settings.plotsize.xsize.label $w.settings.plotsize.xsize.sp\n" ,"ttk::frame $w.settings.plotsize.ysize\n" ,"ttk::label $w.settings.plotsize.ysize.label -text \"Plotsize y: \"\n" ,"ttk::spinbox $w.settings.plotsize.ysize.sp -textvariable visoptions.lineplotsizey -width 6 -increment 1 -validate focus -validatecommand \"my_validatespinbox %W %P 0\" \\\n" ,"-invalidcommand \"my_invalidspinbox %W\" -from -1e9 -to 1e9\n" ,"pack $w.settings.plotsize.ysize.label $w.settings.plotsize.ysize.sp\n" ,"pack $w.settings.plotsize.xsize $w.settings.plotsize.ysize -side left\n" ,"pack $w.settings.plotsize\n" ,"ttk::label $w.settings.empty2 -text \"\"\n" ,"pack $w.settings.empty2\n" ,"ttk::frame $w.settings.color\n" ,"ttk::label $w.settings.color.lab -text \"Linecolor: \"\n" ,"ttk::menubutton $w.settings.color.but -menu $w.settings.color.menu -text \"\" -width 15\n" ,"menu $w.settings.color.menu -tearoff 0\n" ,"foreach step { red black blue green yellow } {\n" ,"$w.settings.color.menu add command -label $step -command \"set visoptions.lineplotcolor $step; $w.settings.color.but configure -text \\\"$step\\\"\"\n" ,"}\n" ,"$w.settings.color.menu invoke \"red\"\n" ,"grid $w.settings.color.lab $w.settings.color.but -sticky nw\n" ,"pack $w.settings.color\n" ,"pack $w.settings -fill x\n" ,"set datax \"\"\n" ,"set datay \"\"\n" ,"set xmin 0\n" ,"set xmax 0\n" ,"set ymin 0\n" ,"set ymax 0\n" ,"ttk::frame $w.plots -relief groove -borderwidth 3\n" ,"ttk::frame $w.plots.selplot\n" ,"ttk::label $w.plots.selplot.lab -text \"Linecolor: \"\n" ,"ttk::menubutton $w.plots.selplot.but -menu $w.plots.selplot.menu -text \"\" -width 15\n" ,"menu $w.plots.selplot.menu -tearoff 0\n" ,"$w.plots.selplot.menu add command -label \"None\" -command \"set visoptions.lineplotselected \\\"None\\\"; $w.plots.selplot.but configure -text \\\"None\\\"\"\n" ,"grid $w.plots.selplot.lab $w.plots.selplot.but -sticky nw\n" ,"$w.plots.selplot.menu invoke \"None\"\n" ,"global visoptions.lineplotselector\n" ,"set visoptions.lineplotselector $w.plots.selplot.menu\n" ,"ttk::button $w.plots.new -text \"Generate New Plot\" -command {\n" ,"if { ${visoptions.lineplotselectedeval} != 0} {\n" ,"set visoptions.lineplotfile [lindex ${visoptions.evaluatefilenames} ${visoptions.lineplotselectedeval}]\n" ,"}\n" ,"getlineplotdata datax datay xmin xmax ymin ymax\n" ,"puts stdout \"xmin $xmin xmax $xmax ymin $ymin ymax $ymax\"\n" ,"global visoptions.lineplotautoscale\n" ,"if {! ${visoptions.lineplotautoscale}} {\n" ,"puts \"using set min/max values\"\n" ,"set xmin ${visoptions.lineplotxmin}\n" ,"set xmax ${visoptions.lineplotxmax}\n" ,"set ymin ${visoptions.lineplotymin}\n" ,"set ymax ${visoptions.lineplotymax}\n" ,"}\n" ,"incr visoptions.lineplotcurrentnum\n" ,"set ident .newplot${visoptions.lineplotcurrentnum}\n" ,"set plotinfo \"\"\n" ,"createlineplot ${visoptions.lineplotsizex} ${visoptions.lineplotsizey} \\\n" ,"$ident \"Lineplot ${visoptions.lineplotcurrentnum}\" \\\n" ,"$xmin $xmax $ymin $ymax plotinfo\n" ,"lappend visoptions.lineplotinfos $plotinfo\n" ,"${visoptions.lineplotselector} add command ${visoptions.lineplotcurrentnum} -label \"Lineplot ${visoptions.lineplotcurrentnum}\"\n" ,"addplotline $ident $datax $datay $plotinfo ${visoptions.lineplotcolor}\n" ,"}\n" ,"ttk::button $w.plots.addto -text \"Add to Selected Plot\" -command {\n" ,"if { ${visoptions.lineplotselectedeval} != 0} {\n" ,"set visoptions.lineplotfile [lindex ${visoptions.evaluatefilenames} ${visoptions.lineplotselectedeval}]\n" ,"}\n" ,"if { ${visoptions.lineplotselected} != \"none\" } {\n" ,"getlineplotdata datax datay xmin xmax ymin ymax\n" ,"set ident .newplot${visoptions.lineplotselected}\n" ,"set plotinfo [lindex ${visoptions.lineplotinfos} ${visoptions.lineplotselected}]\n" ,"addplotline $ident $datax $datay $plotinfo ${visoptions.lineplotcolor}\n" ,"}\n" ,"}\n" ,"pack $w.plots.new $w.plots.addto $w.plots.selplot\n" ,"pack $w.plots -fill x -ipady 3\n" ,"ttk::button $w.close -text \"Close\" -command \"destroy $w\"\n" ,"pack $w.close\n" ,"wm withdraw $w\n" ,"wm geom $w +200+100\n" ,"wm deiconify $w\n" ,"wm title $w \"2D Lineplots\"\n" ,"focus $w\n" ,"}\n" ,"}\n" ,"set fieldlinesdialog_pop1 0\n" ,"proc fieldlinesdialog { } {\n" ,"set w .fieldlines_dlg\n" ,"global fieldlinesdialog_pop1\n" ,"set fieldlinesdialog_pop1 1\n" ,"if {[winfo exists .fieldlines_dlg] == 1} {\n" ,"wm withdraw $w\n" ,"wm deiconify $w\n" ,"focus $w\n" ,"} {\n" ,"toplevel $w\n" ,"pack [ttk::notebook $w.nb] -fill both -side top -ipadx 6 -ipady 6\n" ,"$w.nb add [ttk::frame $w.nb.draw] -text \"Draw\" -underline 0\n" ,"$w.nb add [ttk::frame $w.nb.settings] -text \"Settings\" -underline 0\n" ,"set f $w.nb.draw\n" ,"ttk::labelframe $f.general -text \"General settings\" -relief groove -borderwidth 3\n" ,"ttk::checkbutton $f.general.enable -text \"Enable Fieldlines\" \\\n" ,"-variable visoptions.drawfieldlines \\\n" ,"-command {\n" ,"Ng_Vis_Set parameters;\n" ,"redraw\n" ,"}\n" ,"ttk::label $f.general.numl -text \"num:\"\n" ,"ttk::spinbox $f.general.num -from 0 -to 100 -increment 1 \\\n" ,"-textvariable visoptions.numfieldlines -width 4\n" ,"grid $f.general.enable -sticky nw -padx 4 -pady 2\n" ,"grid x $f.general.numl $f.general.num -rowspan 3 -sticky w -padx 4 -row 0 -pady 2\n" ,"grid anchor $f.general center\n" ,"pack $f.general -pady 15 -fill x -ipady 3\n" ,"ttk::label $f.labe0 -text \" \"\n" ,"pack $f.labe0\n" ,"ttk::checkbutton $f.general.randomstart -text \"Field dependent density \" \\\n" ,"-variable visoptions.fieldlinesrandomstart \\\n" ,"-command { Ng_Vis_Set parameters; redraw}\n" ,"ttk::checkbutton $f.general.redrawperiodic -text \"Animate periodic\" \\\n" ,"-variable visoptions.redrawperiodic \\\n" ,"-command {\n" ,"redrawperiodic\n" ,"Ng_Vis_Set parameters;\n" ,"redraw\n" ,"}\n" ,"grid $f.general.randomstart -sticky nw -padx 4 -row 1\n" ,"grid $f.general.redrawperiodic -sticky nw -padx 4 -row 2\n" ,"ttk::label $f.lab0 -text \" \"\n" ,"pack $f.lab0\n" ,"ttk::frame $f.vecfun\n" ,"ttk::label $f.vecfun.lab -text \"Vector Function: \"\n" ,"ttk::menubutton $f.vecfun.but -menu $f.vecfun.menu -text \"\" -width 12\n" ,"menu $f.vecfun.menu -tearoff 0\n" ,"for { set i 1 } { $i <= [Ng_Vis_Field getnfieldnames] } { incr i } {\n" ,"set fname [Ng_Vis_Field getfieldname $i]\n" ,"set fcomp [Ng_Vis_Field getfieldcomponents $i]\n" ,"set iscomplex [Ng_Vis_Field iscomplex $i]\n" ,"set sdim [Ng_Vis_Field getdimension]\n" ,"if { $iscomplex == 1 } { set fcomp [expr $fcomp / 2] }\n" ,"if { ($fcomp == $sdim) || ($fcomp == 3) } {\n" ,"$f.vecfun.menu add command -label $fname -command \"set visoptions.fieldlinesvecfunction $fname;Ng_Vis_Set parameters; redraw;$f.vecfun.but configure -text \\\"$fname\\\" \" }\n" ,"}\n" ,"grid $f.vecfun.lab $f.vecfun.but -sticky nw\n" ,"pack $f.vecfun\n" ,"ttk::label $f.lab00 -text \" \"\n" ,"pack $f.lab00\n" ,"ttk::frame $f.phasesettings\n" ,"ttk::checkbutton $f.phasesettings.onephase -text \"Fix Phase\" -variable visoptions.fieldlinesonlyonephase\n" ,"ttk::frame $f.phasesettings.phase\n" ,"ttk::label $f.phasesettings.phase.lab -text \"phi\"\n" ,"ttk::scale $f.phasesettings.phase.sc -orient horizontal -length 100 -from 0 -to 360 -variable visoptions.fieldlinesphase \\\n" ,"-command \"roundscale $f.phasesettings.phase.sc 0; popupcheckredraw3 fieldlinesdialog_pop1\"\n" ,"ttk::entry $f.phasesettings.phase.ent -width 4 -textvariable visoptions.fieldlinesphase -validate focus -takefocus 0 \\\n" ,"-validatecommand \"popupcheckredraw3 fieldlinesdialog_pop1;my_validate %W 0 1 %P 0\" \\\n" ,"-invalidcommand \"my_invalid %W;popupcheckredraw3 fieldlinesdialog_pop1\"\n" ,"grid $f.phasesettings.phase.lab $f.phasesettings.phase.sc $f.phasesettings.phase.ent -sticky nw -ipadx 4\n" ,"pack $f.phasesettings.onephase $f.phasesettings.phase -side left\n" ,"pack $f.phasesettings\n" ,"ttk::label $f.lab1 -text \" \"\n" ,"pack $f.lab1\n" ,"ttk::frame $f.boxsettings -relief groove -borderwidth 3\n" ,"ttk::frame $f.boxsettings.title\n" ,"ttk::radiobutton $f.boxsettings.title.choose -variable visoptions.fieldlinesstartarea \\\n" ,"-value box -text \"Startpoints in Box\"\n" ,"pack $f.boxsettings.title.choose -side left\n" ,"pack $f.boxsettings.title\n" ,"ttk::frame $f.boxsettings.points\n" ,"ttk::label $f.boxsettings.points.lab2 -text \"Pmin\";\n" ,"ttk::entry $f.boxsettings.points.ent1x -width 8 \\\n" ,"-textvariable visoptions.fieldlinesstartareap1x\n" ,"ttk::entry $f.boxsettings.points.ent1y -width 8 \\\n" ,"-textvariable visoptions.fieldlinesstartareap1y\n" ,"ttk::entry $f.boxsettings.points.ent1z -width 8 \\\n" ,"-textvariable visoptions.fieldlinesstartareap1z\n" ,"ttk::label $f.boxsettings.points.lab3 -text \" Pmax\";\n" ,"ttk::entry $f.boxsettings.points.ent2x -width 8 \\\n" ,"-textvariable visoptions.fieldlinesstartareap2x\n" ,"ttk::entry $f.boxsettings.points.ent2y -width 8 \\\n" ,"-textvariable visoptions.fieldlinesstartareap2y\n" ,"ttk::entry $f.boxsettings.points.ent2z -width 8 \\\n" ,"-textvariable visoptions.fieldlinesstartareap2z\n" ,"pack $f.boxsettings.points\n" ,"pack $f.boxsettings.points.lab2 $f.boxsettings.points.ent1x $f.boxsettings.points.ent1y $f.boxsettings.points.ent1z -side left\n" ,"pack $f.boxsettings.points.lab3 $f.boxsettings.points.ent2x $f.boxsettings.points.ent2y $f.boxsettings.points.ent2z -side left\n" ,"ttk::button $f.boxsettings.settobb -text \"Bounding Box\" -command {\n" ,"set bbox [Ng_MeshInfo bbox]\n" ,"set visoptions.fieldlinesstartareap1x [lindex $bbox 0]\n" ,"set visoptions.fieldlinesstartareap2x [lindex $bbox 1]\n" ,"set visoptions.fieldlinesstartareap1y [lindex $bbox 2]\n" ,"set visoptions.fieldlinesstartareap2y [lindex $bbox 3]\n" ,"set visoptions.fieldlinesstartareap1z [lindex $bbox 4]\n" ,"set visoptions.fieldlinesstartareap2z [lindex $bbox 5]\n" ,"}\n" ,"pack $f.boxsettings.settobb\n" ,"pack $f.boxsettings -fill x -ipady 3\n" ,"ttk::frame $f.facesettings -relief groove -borderwidth 3\n" ,"ttk::frame $f.facesettings.title\n" ,"ttk::radiobutton $f.facesettings.title.choose -variable visoptions.fieldlinesstartarea \\\n" ,"-value face -text \"Startpoints on Face\"\n" ,"pack $f.facesettings.title.choose -side left\n" ,"pack $f.facesettings.title\n" ,"ttk::frame $f.facesettings.index\n" ,"ttk::label $f.facesettings.index.lab -text \"face index:\"\n" ,"ttk::label $f.facesettings.index.ent -text 1;\n" ,"pack $f.facesettings.index.lab $f.facesettings.index.ent -side left\n" ,"pack $f.facesettings.index\n" ,"pack $f.facesettings -fill x -ipady 3\n" ,"global visoptions.fieldlinesfilename\n" ,"ttk::frame $f.filesettings -relief groove -borderwidth 3\n" ,"ttk::frame $f.filesettings.title\n" ,"ttk::radiobutton $f.filesettings.title.choose -variable visoptions.fieldlinesstartarea \\\n" ,"-value file -text \"Startpoints from File\"\n" ,"pack $f.filesettings.title.choose -side left\n" ,"pack $f.filesettings.title\n" ,"ttk::frame $f.filesettings.sfn\n" ,"ttk::button $f.filesettings.sfn.bb -text \"Browse\" \\\n" ,"-command {\n" ,"set types {\n" ,"{ \"Netgen Fieldlines\" {.nef} }\n" ,"}\n" ,"set visoptions.fieldlinesfilename [tk_getOpenFile -filetypes $types -defaultextension \".nef\"]\n" ,"}\n" ,"ttk::entry $f.filesettings.sfn.fn -width 50 \\\n" ,"-textvariable visoptions.fieldlinesfilename\n" ,"pack $f.filesettings.sfn.bb $f.filesettings.sfn.fn -side left\n" ,"pack $f.filesettings.sfn\n" ,"pack $f.filesettings -fill x -ipady 3\n" ,"set g $w.nb.settings\n" ,"ttk::frame $g.linesettings -relief groove -borderwidth 3\n" ,"ttk::label $g.linesettings.title -text \"\\nLine Settings\\n\"\n" ,"ttk::frame $g.linesettings.length\n" ,"ttk::label $g.linesettings.length.lab -text \"rel. Length: \"\n" ,"ttk::spinbox $g.linesettings.length.sp -textvariable visoptions.fieldlineslength -width 6 -increment 0.1 -validate focus -validatecommand \"my_validatespinbox %W %P 5\" \\\n" ,"-invalidcommand \"my_invalidspinbox %W\" -from 0.00001 -to 10000\n" ,"grid $g.linesettings.length.lab $g.linesettings.length.sp -sticky nw\n" ,"ttk::frame $g.linesettings.maxpoints\n" ,"ttk::label $g.linesettings.maxpoints.lab -text \"max. Points: \"\n" ,"ttk::spinbox $g.linesettings.maxpoints.sp -textvariable visoptions.fieldlinesmaxpoints -width 6 -increment 1 -validate focus -validatecommand \"my_validatespinbox %W %P 0\" \\\n" ,"-invalidcommand \"my_invalidspinbox %W\" -from 0 -to 10000\n" ,"grid $g.linesettings.maxpoints.lab $g.linesettings.maxpoints.sp -sticky nw\n" ,"ttk::frame $g.linesettings.thick\n" ,"ttk::label $g.linesettings.thick.lab -text \"rel. Thickness: \"\n" ,"ttk::spinbox $g.linesettings.thick.sp -textvariable visoptions.fieldlinesthickness -width 6 -increment 0.001 -validate focus -validatecommand \"my_validatespinbox %W %P 6\" \\\n" ,"-invalidcommand \"my_invalidspinbox %W\" -from 1e-10 -to 0.5\n" ,"grid $g.linesettings.thick.lab $g.linesettings.thick.sp -stick nw\n" ,"pack $g.linesettings.title $g.linesettings.length $g.linesettings.maxpoints $g.linesettings.thick\n" ,"pack $g.linesettings -fill x -ipady 3\n" ,"global visoptions.fieldlinestolerance\n" ,"ttk::frame $g.odesettings -relief groove -borderwidth 3\n" ,"ttk::label $g.odesettings.title -text \"\\nODE Settings\\n\"\n" ,"ttk::frame $g.odesettings.tol\n" ,"ttk::label $g.odesettings.tol.lab -text \"rel. Thickness: \"\n" ,"ttk::spinbox $g.odesettings.tol.sp -textvariable visoptions.fieldlinestolerance -width 6 -increment 0.01 -validate focus -validatecommand \"my_validatespinbox %W %P 5\" \\\n" ,"-invalidcommand \"my_invalidspinbox %W\" -from 0.00001 -to 1\n" ,"grid $g.odesettings.tol.lab $g.odesettings.tol.sp -stick nw\n" ,"ttk::frame $g.odesettings.rktype\n" ,"ttk::label $g.odesettings.rktype.lab -text \"RK-Type \"\n" ,"ttk::menubutton $g.odesettings.rktype.but -menu $g.odesettings.rktype.menu -text \"\" -width 25\n" ,"menu $g.odesettings.rktype.menu -tearoff 0\n" ,"$g.odesettings.rktype.menu add command -label \"Euler, order 1\" -command \"set visoptions.fieldlinesrktype \\\"euler\\\" ;Ng_Vis_Set parameters; redraw;$g.odesettings.rktype.but configure -text \\\"Euler,order 1\\\" \"\n" ,"$g.odesettings.rktype.menu add command -label \"Euler-Cauchy, order 2\" -command \"set visoptions.fieldlinesrktype \\\"eulercauchy\\\" ;Ng_Vis_Set parameters; redraw;$g.odesettings.rktype.but configure -text \\\"Euler-Cauchy,order 2\\\" \"\n" ,"$g.odesettings.rktype.menu add command -label \"Simpson, order 3\" -command \"set visoptions.fieldlinesrktype \\\"simpson\\\" ;Ng_Vis_Set parameters; redraw;$g.odesettings.rktype.but configure -text \\\"Simpson,order 3\\\"\"\n" ,"$g.odesettings.rktype.menu add command -label \"classical Runge-Kutta, order 4\" -command \"set visoptions.fieldlinesrktype \\\"crungekutta\\\" ;Ng_Vis_Set parameters; redraw; $g.odesettings.rktype.but configure -text \\\"classical Runge-Kutta,order 4\\\"\"\n" ,"$g.odesettings.rktype.menu invoke \"classical Runge-Kutta, order 4\"\n" ,"grid $g.odesettings.rktype.lab $g.odesettings.rktype.but -sticky nw\n" ,"pack $g.odesettings.title $g.odesettings.tol $g.odesettings.rktype\n" ,"pack $g.odesettings -fill x -ipady 3\n" ,"ttk::frame $w.bu\n" ,"pack $w.bu -fill x -ipady 3\n" ,"ttk::button $w.bu.calc -text \"Build Fieldlines\" -command {\n" ,"if { ${visoptions.fieldlinesvecfunction} == \"none\" } {\n" ,"bgerror \"Please select the vector function first!\"\n" ,"} {\n" ,"set visoptions.drawfieldlines 1\n" ,"Ng_Vis_Set parameters\n" ,"Ng_BuildFieldLines\n" ,"redraw\n" ,"}\n" ,"}\n" ,"ttk::button $w.bu.help -text \"Help\" -command {\n" ,"if {[winfo exists .fieldlines_help] == 1} {\n" ,"wm withdraw .fieldlines_help\n" ,"wm deiconify .fieldlines_help\n" ,"focus .fieldlines_help\n" ,"} {\n" ,"toplevel .fieldlines_help\n" ,"set f [frame .fieldlines_help.ht]\n" ,"ttk::scrollbar $f.vsb -orient vertical -command [list $f.t yview]\n" ,"text $f.t -yscrollcommand [list $f.vsb set]\n" ,"grid $f.t -row 0 -column 0 -sticky nsew\n" ,"grid $f.vsb -row 0 -column 1 -sticky nsew\n" ,"grid columnconfigure $f 0 -weight 1\n" ,"grid rowconfigure $f 0 -weight 1\n" ,"set text $f.t\n" ,"$text configure -setgrid true -wrap word\n" ,"$text tag configure bold -font *-*-bold-*-*-*-*\n" ,"$text insert end \\\n" ,"\"Draw menu\\n \\n\" bold\n" ,"$text insert end \\\n" ,"\"Enable Fieldlines\\n To turn on and off the calculated fieldlines. (Has to be turned on to start the calculation)\\n\"\n" ,"$text insert end \\\n" ,"\"Num\\n Number of fieldlines to calculate. (May not be used exactly.)\"\n" ,"$text insert end \\\n" ,"\"Field dependent density\\n There will be more fieldline startpoints where the field is stronger\\n\\n\"\n" ,"$text insert end \\\n" ,"\"Animate periodic\\n (for quasistationary fields) The fieldlines of the different phase angles are animated.\\n ATTENTION: \\\"Fix Phase\\\" has to be turned off\\n\\n\"\n" ,"$text insert end \\\n" ,"\"Vector Function\\n The function fixing the direction of the lines\\n\\n\"\n" ,"$text insert end \\\n" ,"\"Fix Phase\\n (for quasistationary fields) Only calculate and draw fieldlines for one special phase angle.\\n\\n\"\n" ,"$text insert end \\\n" ,"\"Startpoints in Box\\n Set the startpoints inside the box \\[Pmin1,Pmax1\\] x \\[Pmin2,Pmax2\\] x \\[Pmin3,Pmax3\\]\\n\"\n" ,"$text insert end \\\n" ,"\" With the button \\\"Bounding Box\\\" the whole bounding box of the geometry is selected.\\n\\n\"\n" ,"$text insert end \\\n" ,"\"Startpoints on Face\\n All startpoints will be set on one face. This face is selected by double-clicking with the mouse.\\n\\n\"\n" ,"$text insert end \\\n" ,"\"Startpoints from File\\n The startpoint information will be read from the selected file.\\n The entries in the file can be as follows:\\n\"\n" ,"$text insert end \\\n" ,"\" point \\n set a (potential) startpoint\\n\"\n" ,"$text insert end \\\n" ,"\" line \\n set n (potential) startpoints on the line from (x1,y1,z1) to (x2,y2,z2)\\n\"\n" ,"$text insert end \\\n" ,"\" box \\n set n (potential) startpoints inside the box \\[x1,x2\\] x \\[y1,y2\\] x \\[z1,z2\\]\\n\"\n" ,"$text insert end \\\n" ,"\" ATTENTION: These are potential startpoints.\\n The total number of startpoints will be bounded by the \\\"Num\\\"-parameter.\\n \\n \\n \\n\"\n" ,"$text insert end \\\n" ,"\"Settings Menu\\n \\n\" bold\n" ,"$text insert end \\\n" ,"\"rel. Length\\n The maximal length of a fieldline relative to the diameter of the geometry.\\n\\n\"\n" ,"$text insert end \\\n" ,"\"max. Points\\n The maximum number of Runge-Kutta steps.\\n\\n\"\n" ,"$text insert end \\\n" ,"\"rel. Thickness\\n The thickness of the fieldlines relative to the diameter of the geometry.\\n\\n\"\n" ,"$text insert end \\\n" ,"\"rel. Tolerance\\n The tolerance for the step-length control of the Runge-Kutta method.\\n\\n\"\n" ,"$text insert end \\\n" ,"\"RK-Type\\n Which Runge-Kutta scheme to use\\n \\n \\n \\n\"\n" ,"$text insert end \\\n" ,"\"Button \\\"Build Fieldlines\\\"\\n\" bold\n" ,"$text insert end \\\n" ,"\" Build the fieldlines.\"\n" ,"$text configure -state disabled\n" ,"pack .fieldlines_help.ht -expand yes -fill both\n" ,"wm withdraw .fieldlines_help\n" ,"wm geom .fieldlines_help +300+200\n" ,"wm deiconify .fieldlines_help\n" ,"wm title .fieldlines_help \"Fieldlines Help\"\n" ,"focus .fieldlines_help\n" ,"}\n" ,"}\n" ,"ttk::button $w.bu.cancel -text \"Done\" -command \"destroy $w\"\n" ,"grid $w.bu.calc $w.bu.help $w.bu.cancel -sticky nw -padx 4\n" ,"grid anchor $w.bu center\n" ,"wm withdraw $w\n" ,"wm geom $w +200+100\n" ,"wm deiconify $w\n" ,"wm title $w \"Fieldlines\"\n" ,"focus $w\n" ,"}\n" ,"global visoptions.fieldlinesstartface\n" ,"set f $w.nb.draw\n" ,"set visoptions.fieldlinesstartface [Ng_BCProp getactive]\n" ,"$f.facesettings.index.ent configure -text ${visoptions.fieldlinesstartface}\n" ,"}\n" ,"set visual_dialog_pop1 0\n" ,"set visual_dialog_pop2 0\n" ,"set visual_dialog_pop3 0\n" ,"set visual_dialog_pop4 0\n" ,"set visual_dialog_pop5 0\n" ,"set visual_dialog_pop6 0\n" ,"set visual_dialog_pop7 0\n" ,"proc visual_dialog { } {\n" ,"set w .visoptions_dlg\n" ,"global visual_dialog_pop1\n" ,"global visual_dialog_pop2\n" ,"global visual_dialog_pop3\n" ,"global visual_dialog_pop4\n" ,"global visual_dialog_pop5\n" ,"global visual_dialog_pop6\n" ,"global visual_dialog_pop7\n" ,"set visual_dialog_pop1 1\n" ,"set visual_dialog_pop2 1\n" ,"set visual_dialog_pop3 1\n" ,"set visual_dialog_pop4 1\n" ,"set visual_dialog_pop5 1\n" ,"set visual_dialog_pop6 1\n" ,"set visual_dialog_pop7 1\n" ,"if {[winfo exists .visoptions_dlg] == 1} {\n" ,"wm withdraw $w\n" ,"wm deiconify $w\n" ,"focus $w\n" ,"} {\n" ,"toplevel $w\n" ,"ttk::frame $w.main\n" ,"pack $w.main -fill x\n" ,"set w $w.main\n" ,"ttk::frame $w.upperfr ;\n" ,"pack $w.upperfr -fill x;\n" ,"ttk::labelframe $w.upperfr.size -text \"Grid\" -relief groove -borderwidth 3\n" ,"ttk::entry $w.upperfr.size.ent -width 3 -textvariable visoptions.gridsize -validate focus -takefocus 0 -validatecommand \"popupcheckredraw visual_dialog_pop2;my_validate %W 0 200 %P 0\" \\\n" ,"-invalidcommand \"my_invalid %W;popupcheckredraw visual_dialog_pop2\"\n" ,"ttk::scale $w.upperfr.size.sc -orient horizontal -length 100 -from 1 -to 200 -variable visoptions.gridsize\\\n" ,"-command \"roundscale $w.upperfr.size.sc 0;popupcheckredraw visual_dialog_pop2\"\n" ,"ttk::labelframe $w.upperfr.offsets -text \"x / y offsets\" -relief groove -borderwidth 3\n" ,"ttk::label $w.upperfr.offsets.xlab -text \"x\"\n" ,"ttk::label $w.upperfr.offsets.ylab -text \"y\"\n" ,"ttk::scale $w.upperfr.offsets.xoffset -orient horizontal -length 100 -from 0 -to 1 -variable visoptions.xoffset \\\n" ,"-command \"roundscale $w.upperfr.offsets.xoffset 2; popupcheckredraw visual_dialog_pop3\"\n" ,"ttk::scale $w.upperfr.offsets.yoffset -orient horizontal -length 100 -from 0 -to 1 -variable visoptions.yoffset \\\n" ,"-command \"roundscale $w.upperfr.offsets.yoffset 2; popupcheckredraw visual_dialog_pop4\"\n" ,"ttk::entry $w.upperfr.offsets.entx -width 4 -textvariable visoptions.xoffset -validate focus -takefocus 0 \\\n" ,"-validatecommand \"popupcheckredraw visual_dialog_pop3;my_validate %W 0 1 %P 2\" \\\n" ,"-invalidcommand \"my_invalid %W;popupcheckredraw visual_dialog_pop3\"\n" ,"ttk::entry $w.upperfr.offsets.enty -width 4 -textvariable visoptions.yoffset -validate focus -takefocus 0 \\\n" ,"-validatecommand \"popupcheckredraw visual_dialog_pop4;my_validate %W 0 1 %P 2\" \\\n" ,"-invalidcommand \"my_invalid %W;popupcheckredraw visual_dialog_pop4\"\n" ,"pack $w.upperfr.size.sc $w.upperfr.size.ent -padx 4 -pady 12 -side left\n" ,"grid $w.upperfr.offsets.xoffset $w.upperfr.offsets.entx $w.upperfr.offsets.xlab -sticky nw -padx 4\n" ,"grid $w.upperfr.offsets.yoffset $w.upperfr.offsets.enty $w.upperfr.offsets.ylab -sticky nw -padx 4\n" ,"grid $w.upperfr.size $w.upperfr.offsets -sticky nw -pady 7 -padx 10\n" ,"grid anchor $w.upperfr center\n" ,"ttk::labelframe $w.deform -relief groove -borderwidth 3 -text \"Deformation settings\"\n" ,"ttk::checkbutton $w.deform.cb -text \"Deformation\" \\\n" ,"-variable visoptions.deformation \\\n" ,"-command { Ng_Vis_Set parameters; redraw }\n" ,"ttk::label $w.deform.l -text \"Scale: \"\n" ,"ttk::spinbox $w.deform.sc1 -from 0 -to 1e99 -textvariable visoptions.scaledeform1 -width 5 \\\n" ,"-command { Ng_Vis_Set parameters; redraw } \\\n" ,"-validate focusout -validatecommand { Ng_Vis_Set parameters; redraw; string is double %P } \\\n" ,"-invalidcommand { puts \"invalid value, %P %s\"; set visoptions.scaledeform1 1; }\n" ,"ttk::scale $w.deform.sc2 -orient horizontal -length 100 -from 0 -to 1 \\\n" ,"-variable visoptions.scaledeform2 \\\n" ,"-command { popupcheckredraw visual_dialog_pop5 }\n" ,"pack $w.deform -fill x -ipady 2 -pady 4 -ipady 3\n" ,"grid $w.deform.cb $w.deform.l $w.deform.sc1 $w.deform.sc2 -sticky nw -padx 4;\n" ,"grid anchor $w.deform center\n" ,"grid columnconfigure $w.deform 0 -pad 20\n" ,"grid columnconfigure $w.deform 2 -pad 20\n" ,"ttk::labelframe $w.as -relief groove -borderwidth 3 -text \"Scaling options\"\n" ,"ttk::checkbutton $w.as.autoscale -text \"Autoscale\" \\\n" ,"-variable visoptions.autoscale \\\n" ,"-command { Ng_Vis_Set parameters; redraw }\n" ,"ttk::label $w.as.lmin -text \"Min-value\"\n" ,"ttk::spinbox $w.as.smin -textvariable visoptions.mminval -width 5 -validate focus \\\n" ,"-validatecommand \"my_validatespinbox %W %P 10\" \\\n" ,"-command \"Ng_Vis_Set parameters; redraw;\" \\\n" ,"-invalidcommand \"my_invalidspinbox %W\" -from -1e10 -to 1e10 -increment 0.001\n" ,"ttk::label $w.as.lmax -text \"Max-value\"\n" ,"ttk::spinbox $w.as.smax -textvariable visoptions.mmaxval -width 5 -validate focus \\\n" ,"-validatecommand \"Ng_Vis_Set parameters; redraw;my_validatespinbox %W %P 10\" \\\n" ,"-command \"Ng_Vis_Set parameters; redraw;\" \\\n" ,"-invalidcommand \"my_invalidspinbox %W;Ng_Vis_Set parameters; redraw\" -from -1e10 -to 1e10 -increment 0.001\n" ,"ttk::label $w.as.lncols -text \"N Colors\"\n" ,"ttk::spinbox $w.as.snumcols -textvariable visoptions.numtexturecols -width 5 -validate focus \\\n" ,"-command \"Ng_Vis_Set parameters; redraw;\" \\\n" ,"-from 2 -to 31 -increment 1\n" ,"pack $w.as -fill x -pady 5 -ipady 3\n" ,"grid $w.as.autoscale $w.as.lmin $w.as.smin $w.as.lmax $w.as.smax $w.as.lncols $w.as.snumcols -sticky nw -padx 4\n" ,"grid columnconfigure $w.as 0 -pad 20\n" ,"grid columnconfigure $w.as 2 -pad 20\n" ,"grid anchor $w.as center\n" ,"ttk::frame $w.iso; \n" ,"pack $w.iso -anchor center;\n" ,"ttk::labelframe $w.iso.cb -relief groove -borderwidth 3 -text \"Iso lines / surfaces\"\n" ,"pack $w.iso.cb -side left -pady 7 -fill y\n" ,"ttk::checkbutton $w.iso.cb.isolines -text \"Iso-lines\" \\\n" ,"-variable visoptions.isolines \\\n" ,"-command { Ng_Vis_Set parameters; redraw }\n" ,"ttk::checkbutton $w.iso.cb.isosurf -text \"Iso-Surface\" \\\n" ,"-variable visoptions.isosurf \\\n" ,"-command { Ng_Vis_Set parameters; redraw }\n" ,"ttk::label $w.iso.cb.numisol -text \"amount\"\n" ,"ttk::scale $w.iso.cb.numiso -orient horizontal -length 100 -from 2 -to 50 \\\n" ,"-variable visoptions.numiso \\\n" ,"-command \"roundscale $w.iso.cb.numiso 0;popupcheckredraw visual_dialog_pop6\"\n" ,"ttk::entry $w.iso.cb.entry -textvariable visoptions.numiso -width 3 \\\n" ,"-validate focus -validatecommand \"popupcheckredraw visual_dialog_pop6;\\\n" ,"my_validate %W [$w.iso.cb.numiso cget -from] [$w.iso.cb.numiso cget -to] %P 0\" \\\n" ,"-invalidcommand \"my_invalid %W;popupcheckredraw visual_dialog_pop6\"\n" ,"grid $w.iso.cb.isolines $w.iso.cb.numisol $w.iso.cb.entry -sticky nw -padx 4\n" ,"grid $w.iso.cb.isosurf -sticky nw -padx 4\n" ,"grid $w.iso.cb.numiso -sticky nw -padx 4 -columnspan 2 -column 1 -row 1\n" ,"ttk::labelframe $w.iso.subdiv -text \"Subdivision\" -relief groove -borderwidth 3\n" ,"ttk::radiobutton $w.iso.subdiv.zero -text \"0\" -variable visoptions.subdivisions -value 0 \\\n" ,"-command {\n" ,"Ng_Vis_Set parameters; redraw;\n" ,"}\n" ,"ttk::radiobutton $w.iso.subdiv.one -text \"1\" -variable visoptions.subdivisions -value 1 \\\n" ,"-command {\n" ,"Ng_Vis_Set parameters; redraw;\n" ,"}\n" ,"ttk::radiobutton $w.iso.subdiv.two -text \"2\" -variable visoptions.subdivisions -value 2 \\\n" ,"-command {\n" ,"Ng_Vis_Set parameters; redraw;\n" ,"}\n" ,"ttk::radiobutton $w.iso.subdiv.three -text \"3\" -variable visoptions.subdivisions -value 3 \\\n" ,"-command {\n" ,"Ng_Vis_Set parameters; redraw;\n" ,"}\n" ,"ttk::radiobutton $w.iso.subdiv.four -text \"4\" -variable visoptions.subdivisions -value 4 \\\n" ,"-command {\n" ,"Ng_Vis_Set parameters; redraw;\n" ,"}\n" ,"ttk::radiobutton $w.iso.subdiv.five -text \"5\" -variable visoptions.subdivisions -value 5 \\\n" ,"-command {\n" ,"Ng_Vis_Set parameters; redraw;\n" ,"}\n" ,"ttk::label $w.iso.subdiv.text -text \"subdivision\"\n" ,"pack $w.iso.subdiv -side right -fill y -padx 4 -pady 7\n" ,"grid $w.iso.subdiv.zero $w.iso.subdiv.one $w.iso.subdiv.two $w.iso.subdiv.three $w.iso.subdiv.four $w.iso.subdiv.five\n" ,"grid anchor $w.iso.subdiv center\n" ,"ttk::labelframe $w.redraw -relief groove -borderwidth 3 -text \"Auto-redraw\"\n" ,"ttk::checkbutton $w.redraw.auto -text \"Auto-redraw after (sec)\" \\\n" ,"-variable visoptions.autoredraw\n" ,"ttk::spinbox $w.redraw.val -textvariable visoptions.autoredrawtime -from 0 -to 100 -width 3\n" ,"pack $w.redraw -fill x -ipady 3 -pady 7\n" ,"grid $w.redraw.auto $w.redraw.val -sticky nw\n" ,"grid anchor $w.redraw center\n" ,"ttk::labelframe $w.lowerframe -text \"Additional viewing options\" -relief groove -borderwidth 3\n" ,"pack $w.lowerframe -fill x\n" ,"set w $w.lowerframe\n" ,"ttk::frame $w.f1\n" ,"set f [ttk::frame $w.f1.clipsol]\n" ,"pack $f -anchor e\n" ,"menu $f.m\n" ,"ttk::menubutton $f.b -menu $f.m -width 12\n" ,"ttk::label $f.l -text \"Clipping Plane Sol: \"\n" ,"global visoptions.clipsolution\n" ,"set clipsollabs(none) \"None\"\n" ,"set clipsollabs(scal) \"Scalar Function\"\n" ,"set clipsollabs(vec) \"Vector Function\"\n" ,"foreach i { none scal vec } {\n" ,"set textval $clipsollabs($i)\n" ,"$f.m add command -label \"$textval\" -command \\\n" ,"\"$f.b configure -text \\\"$textval\\\" ; set visoptions.clipsolution $i ; Ng_Vis_Set parameters ; redraw \"\n" ,"}\n" ,"pack $f.b $f.l -side right\n" ,"$f.m invoke $clipsollabs(${visoptions.clipsolution})\n" ,"set f [ttk::frame $w.f1.scalfun]\n" ,"pack $f -anchor e\n" ,"menu $f.m\n" ,"ttk::menubutton $f.b -menu $f.m -width 12\n" ,"ttk::label $f.l -text \"Scalar Function: \"\n" ,"set scalentries [list none None]\n" ,"for { set i 1 } { $i <= [Ng_Vis_Field getnfieldnames] } { incr i } {\n" ,"set fname [Ng_Vis_Field getfieldname $i]\n" ,"set fcomp [Ng_Vis_Field getfieldcomponents $i]\n" ,"if { $fcomp == 1 } {\n" ,"lappend scalentries $fname:1 $fname\n" ,"} {\n" ,"for { set j 1 } { $j <= $fcomp } { incr j } {\n" ,"lappend scalentries $fname:$j \"$fname ($j)\"\n" ,"}\n" ,"lappend scalentries $fname:0 \"func ($fname)\"\n" ,"}\n" ,"}\n" ,"global visoptions.scalfunction\n" ,"foreach { name textval } $scalentries {\n" ,"$f.m add command -label \"$textval\" -command \\\n" ,"\"$f.b configure -text \\\"$textval\\\" ; set visoptions.scalfunction \\\"$name\\\" ; Ng_Vis_Set parameters ; redraw ; \"\n" ,"}\n" ,"pack $f.b $f.l -side right\n" ,"foreach { name textval } $scalentries {\n" ,"if { ${visoptions.scalfunction} == $name } {\n" ,"$f.m invoke $textval\n" ,"}\n" ,"}\n" ,"set f [ttk::frame $w.f1.vecfun]\n" ,"pack $f -anchor e\n" ,"menu $f.m\n" ,"ttk::menubutton $f.b -menu $f.m -width 12\n" ,"ttk::label $f.l -text \"Vector Function: \"\n" ,"set vecentries [list none None]\n" ,"for { set i 1 } { $i <= [Ng_Vis_Field getnfieldnames] } { incr i } {\n" ,"set fname [Ng_Vis_Field getfieldname $i]\n" ,"set fcomp [Ng_Vis_Field getfieldcomponents $i]\n" ,"set iscomplex [Ng_Vis_Field iscomplex $i]\n" ,"set sdim [Ng_Vis_Field getdimension]\n" ,"if { $iscomplex == 1 } { set fcomp [expr $fcomp / 2] }\n" ,"if { ($fcomp == $sdim) || ($fcomp == 3) } {\n" ,"lappend vecentries $fname $fname\n" ,"}\n" ,"}\n" ,"global visoptions.vecfunction\n" ,"foreach { name textval } $vecentries {\n" ,"$f.m add command -label \"$textval\" -command \\\n" ,"\"$f.b configure -text \\\"$textval\\\" ; set visoptions.vecfunction $name ; Ng_Vis_Set parameters ; redraw ; \"\n" ,"}\n" ,"pack $f.b $f.l -side right\n" ,"foreach { name textval } $vecentries {\n" ,"if { ${visoptions.vecfunction} == $name } {\n" ,"$f.m invoke $textval\n" ,"}\n" ,"}\n" ,"set f [ttk::frame $w.f1.evaluate]\n" ,"pack $f -anchor e\n" ,"menu $f.m\n" ,"ttk::menubutton $f.b -menu $f.m -width 12\n" ,"ttk::label $f.l -text \"Evaluate: \"\n" ,"global visoptions.evaluate\n" ,"set evallabs(abs) \"| |\"\n" ,"set evallabs(abstens) \"|tensor|\"\n" ,"set evallabs(mises) \"Mises\"\n" ,"set evallabs(main) \"Main\"\n" ,"foreach i { abs abstens mises main } {\n" ,"set textval $evallabs($i)\n" ,"$f.m add command -label \"$textval\" -command \\\n" ,"\"$f.b configure -text \\\"$textval\\\" ; set visoptions.evaluate $i ; \"\n" ,"}\n" ,"pack $f.b $f.l -side right\n" ,"$f.m invoke $evallabs(${visoptions.evaluate})\n" ,"pack [ttk::frame $w.f1.multidim] -fill x\n" ,"set f [ttk::frame $w.f1.multidim.f]\n" ,"pack $f -anchor e\n" ,"ttk::label $f.l1 -text \"multidim-component: \"\n" ,"ttk::spinbox $f.sb1 -from 0 -to 1e99 -textvariable visoptions.multidimcomponent -width 3 \\\n" ,"-command { Ng_Vis_Set parameters; redraw }\n" ,"pack $f.l1 $f.sb1 -side left\n" ,"ttk::frame $w.fcb\n" ,"grid $w.f1 $w.fcb -sticky nw -padx 7 -ipady 3\n" ,"grid anchor $w center\n" ,"ttk::frame $w.fcb.cb\n" ,"pack $w.fcb.cb\n" ,"ttk::checkbutton $w.fcb.cb.showsurfsolution -text \"Draw Surface Vectors\" \\\n" ,"-variable visoptions.showsurfacesolution \\\n" ,"-command { Ng_Vis_Set parameters; redraw }\n" ,"ttk::checkbutton $w.fcb.cb.showcurves -text \"Show Curves\" \\\n" ,"-variable visoptions.drawpointcurves \\\n" ,"-command { Ng_Vis_Set parameters; redraw }\n" ,"ttk::checkbutton $w.fcb.cb.imaginary -text \"Imaginary Part\" \\\n" ,"-variable visoptions.imaginary \\\n" ,"-command { Ng_Vis_Set parameters; redraw }\n" ,"ttk::checkbutton $w.fcb.cb.logscale -text \"Log Scale\" \\\n" ,"-variable visoptions.logscale \\\n" ,"-command { Ng_Vis_Set parameters; redraw }\n" ,"ttk::checkbutton $w.fcb.cb.invcolor -text \"Inverse Color\" \\\n" ,"-variable visoptions.invcolor \\\n" ,"-command { Ng_Vis_Set parametersrange; redraw }\n" ,"ttk::frame $w.fcb.cb.texframe\n" ,"ttk::checkbutton $w.fcb.cb.texframe.usetexture -text \"Use Textures (\" \\\n" ,"-variable visoptions.usetexture \\\n" ,"-command { Ng_Vis_Set parameters; redraw }\n" ,"ttk::checkbutton $w.fcb.cb.texframe.lintexture -text \"Linear )\" \\\n" ,"-variable visoptions.lineartexture \\\n" ,"-command { Ng_Vis_Set parametersrange; redraw }\n" ,"ttk::checkbutton $w.fcb.cb.lineartexture -text \"Use Linear Texture\" \\\n" ,"-variable visoptions.lineartexture \\\n" ,"-command { Ng_Vis_Set parameters; redraw }\n" ,"ttk::checkbutton $w.fcb.cb.showclipsolution -text \"Draw Clipping Plane Solution\" \\\n" ,"-variable visoptions.showclipsolution \\\n" ,"-command { Ng_Vis_Set parameters; redraw }\n" ,"ttk::checkbutton $w.fcb.cb.redrawperiodic -text \"Animate periodic\" \\\n" ,"-variable visoptions.redrawperiodic \\\n" ,"-command {\n" ,"redrawperiodic\n" ,"Ng_Vis_Set parameters;\n" ,"redraw\n" ,"}\n" ,"grid $w.fcb.cb.showsurfsolution -sticky nw\n" ,"grid $w.fcb.cb.showcurves -sticky nw\n" ,"grid $w.fcb.cb.imaginary -sticky nw\n" ,"grid $w.fcb.cb.logscale -sticky nw\n" ,"grid $w.fcb.cb.texframe -sticky nw\n" ,"grid $w.fcb.cb.invcolor -sticky nw\n" ,"grid $w.fcb.cb.redrawperiodic -sticky nw\n" ,"pack $w.fcb.cb.texframe.usetexture $w.fcb.cb.texframe.lintexture -side left -expand yes\n" ,"set w .visoptions_dlg.main\n" ,"ttk::frame $w.bu;\n" ,"pack $w.bu -pady 5 -padx 4\n" ,"ttk::button $w.bu.showsol -text \"Show Solution\" -command {\n" ,"set selectvisual solution\n" ,"Ng_SetVisParameters\n" ,"redraw\n" ,"}\n" ,"ttk::button $w.bu.clipping -text \"Clipping\" -command {\n" ,"clippingdialog;\n" ,"}\n" ,"ttk::button $w.bu.fieldlines -text \"Fieldlines\" -command {\n" ,"fieldlinesdialog;\n" ,"}\n" ,"ttk::button $w.bu.lineplot -text \"2D Lineplot\" -command {\n" ,"lineplotdialog;\n" ,"}\n" ,"ttk::button $w.bu.done -text \"Close\" -command {\n" ,"destroy .visoptions_dlg\n" ,"}\n" ,"pack $w.bu.showsol $w.bu.clipping $w.bu.fieldlines $w.bu.lineplot $w.bu.done -side left -expand yes\n" ,"set w .visoptions_dlg\n" ,"wm withdraw $w\n" ,"wm geom $w +100+100\n" ,"wm deiconify $w\n" ,"wm title $w \"Visualization\"\n" ,"}\n" ,"}\n" ,"}\n" ,"catch { set sockets.serverport 0\n" ,"set sockets.serverhost \"localhost\"\n" ,"set sockets.serverlistbox 0\n" ,"set sockets.queuelistbox 0\n" ,"set sockets.currentjoblistbox 0\n" ,"set sockets.answerlistbox 0\n" ,"set sockets.myidlabel -1\n" ,"proc updateserverlist { } {\n" ,"global sockets.serverlistbox\n" ,"set retval [Ng_Socket getserverlist]\n" ,"${sockets.serverlistbox} delete 0 end\n" ,"for {set i 0} {$i < [llength $retval]} {incr i 3} {\n" ,"${sockets.serverlistbox} insert end \\\n" ,"[format \"%-16s %6i %6i\" [lindex $retval $i] [lindex $retval [expr $i+1]] [lindex $retval [expr $i+2]]]\n" ,"}\n" ,"}\n" ,"proc clientsocketdialog { } {\n" ,"set w .clientsock_dlg\n" ,"if {[winfo exists .clientsock_dlg] == 1} {\n" ,"wm withdraw $w\n" ,"wm deiconify $w\n" ,"focus $w\n" ,"} {\n" ,"toplevel $w\n" ,"global sockets.serverhost\n" ,"global sockets.serverport\n" ,"ttk::frame $w.general\n" ,"ttk::frame $w.host\n" ,"ttk::label $w.host.lab -text \"Serverhost: \"\n" ,"ttk::entry $w.host.name -width 30 -textvariable sockets.serverhost\n" ,"pack $w.host.lab $w.host.name -side left\n" ,"pack $w.host\n" ,"ttk::frame $w.ports\n" ,"ttk::label $w.ports.lab1 -text \"Serverport: \"\n" ,"ttk::entry $w.ports.statport -width 6 -textvariable sockets.serverport\n" ,"pack $w.ports.lab1 $w.ports.statport -side left\n" ,"pack $w.ports\n" ,"ttk::frame $w.listboxes\n" ,"ttk::frame $w.listboxes.choosesocketframe\n" ,"tixScrolledListBox $w.listboxes.choosesocketframe.choosesocket -scrollbar auto\n" ,"global sockets.serverlistbox\n" ,"set sockets.serverlistbox [$w.listboxes.choosesocketframe.choosesocket subwidget listbox]\n" ,"${sockets.serverlistbox} configure -width 35\n" ,"${sockets.serverlistbox} configure -selectmode browse\n" ,"${sockets.serverlistbox} configure -exportselection false\n" ,"ttk::button $w.addserver -text \"Add ServerSocket\" -command {\n" ,"Ng_Socket addserver ${sockets.serverport} ${sockets.serverhost}\n" ,"updateserverlist\n" ,"}\n" ,"pack $w.addserver\n" ,"ttk::label $w.linefeed -text \"\\n\"\n" ,"pack $w.linefeed\n" ,"ttk::frame $w.clientidframe\n" ,"ttk::label $w.clientidframe.lab -text \"Client ID: \";\n" ,"global sockets.myidlabel\n" ,"ttk::entry $w.clientidframe.val -width 5 -textvariable sockets.myidlabel\n" ,"ttk::button $w.clientidframe.but -text \"Set\" -command {\n" ,"set opsel [${sockets.serverlistbox} curselection]\n" ,"if {[llength $opsel] > 0} {\n" ,"set opserver [lindex $opsel 0]\n" ,"Ng_Socket setid $opserver ${sockets.myidlabel}\n" ,"updateserverlist\n" ,"}\n" ,"}\n" ,"pack $w.clientidframe.lab $w.clientidframe.val $w.clientidframe.but -side left\n" ,"pack $w.clientidframe\n" ,"ttk::label $w.listboxes.choosesocketframe.chooselab -text [format \"\\n\\n%-16s %6s %6s \" Host Socket MyID ]\n" ,"pack $w.listboxes.choosesocketframe.chooselab\n" ,"pack $w.listboxes.choosesocketframe.choosesocket\n" ,"ttk::frame $w.listboxes.choosesocketframe.serverbuttons\n" ,"ttk::button $w.listboxes.choosesocketframe.serverbuttons.save -text \"Save\" -command {\n" ,"Ng_Socket saveserverlist\n" ,"}\n" ,"global sockets.serverlist\n" ,"Ng_Socket loadserverlist\n" ,"updateserverlist\n" ,"ttk::button $w.listboxes.choosesocketframe.serverbuttons.delete -text \"Delete\" -command {\n" ,"set opsel [${sockets.serverlistbox} curselection]\n" ,"if {[llength $opsel] > 0} {\n" ,"Ng_Socket deletesocket [lindex $opsel 0]\n" ,"updateserverlist\n" ,"}\n" ,"}\n" ,"pack $w.listboxes.choosesocketframe.serverbuttons.save $w.listboxes.choosesocketframe.serverbuttons.delete -side left\n" ,"pack $w.listboxes.choosesocketframe.serverbuttons\n" ,"ttk::frame $w.listboxes.statusframe\n" ,"ttk::label $w.listboxes.statusframe.statuslabel1 -text \"\\n\\njobqueue\"\n" ,"tixScrolledListBox $w.listboxes.statusframe.queuestatus -scrollbar auto\n" ,"ttk::label $w.listboxes.statusframe.statuslabel2 -text \"\\ncurrent job\"\n" ,"tixScrolledListBox $w.listboxes.statusframe.currentjobstatus -scrollbar auto\n" ,"ttk::label $w.listboxes.statusframe.statuslabel3 -text \"\\nanswers\"\n" ,"tixScrolledListBox $w.listboxes.statusframe.answers -scrollbar auto\n" ,"global sockets.queuelistbox\n" ,"global sockets.currentjoblistbox\n" ,"global sockets.answerlistbox\n" ,"set sockets.queuelistbox [$w.listboxes.statusframe.queuestatus subwidget listbox]\n" ,"set sockets.currentjoblistbox [$w.listboxes.statusframe.currentjobstatus subwidget listbox]\n" ,"set sockets.answerlistbox [$w.listboxes.statusframe.answers subwidget listbox]\n" ,"${sockets.queuelistbox} configure -width 50\n" ,"${sockets.queuelistbox} configure -height 5\n" ,"${sockets.queuelistbox} configure -selectmode browse\n" ,"${sockets.queuelistbox} configure -exportselection false\n" ,"${sockets.currentjoblistbox} configure -width 50\n" ,"${sockets.currentjoblistbox} configure -height 1\n" ,"${sockets.currentjoblistbox} configure -selectmode browse\n" ,"${sockets.currentjoblistbox} configure -exportselection false\n" ,"${sockets.answerlistbox} configure -width 50\n" ,"${sockets.answerlistbox} configure -height 5\n" ,"${sockets.answerlistbox} configure -selectmode browse\n" ,"${sockets.answerlistbox} configure -exportselection false\n" ,"ttk::button $w.listboxes.statusframe.updatebutton -text \"Update\" -command {\n" ,"set opsel [${sockets.serverlistbox} curselection]\n" ,"if {[llength $opsel] > 0} {\n" ,"set opserver [lindex $opsel 0]\n" ,"set retval [Ng_Socket sendqueuestatus $opserver]\n" ,"${sockets.queuelistbox} delete 0 end\n" ,"if {[lindex $retval 0] > 0} {\n" ,"${sockets.queuelistbox} insert end [format \"Blocked for user %i\" [lindex $retval 0]]\n" ,"} {\n" ,"${sockets.queuelistbox} insert end \"Not blocked\"\n" ,"}\n" ,"for {set i 2} {$i < [expr 2*[lindex $retval 1]+2]} {incr i 2} {\n" ,"${sockets.queuelistbox} insert end [format \"client %i, command %s\" [lindex $retval $i] [lindex $retval [expr $i+1]]]\n" ,"}\n" ,"${sockets.answerlistbox} delete 0 end\n" ,"for {set i [expr 2*[lindex $retval 1]+3]} {$i < [llength $retval]} {incr i 2} {\n" ,"${sockets.answerlistbox} insert end [format \"client %i, command %s\" [lindex $retval $i] [lindex $retval [expr $i+1]]]\n" ,"}\n" ,"${sockets.currentjoblistbox} delete 0 end\n" ,"set retval [Ng_Socket sendjobstatus $opserver]\n" ,"if {[lindex $retval 0] != 0} {\n" ,"${sockets.currentjoblistbox} insert end [format \"client %i, command %s: %s\" [lindex $retval 0] [lindex $retval 1] [lrange $retval 2 end]]\n" ,"}\n" ,"}\n" ,"}\n" ,"pack $w.listboxes.statusframe.statuslabel1 $w.listboxes.statusframe.queuestatus \\\n" ,"$w.listboxes.statusframe.statuslabel2 $w.listboxes.statusframe.currentjobstatus \\\n" ,"$w.listboxes.statusframe.statuslabel3 $w.listboxes.statusframe.answers \\\n" ,"$w.listboxes.statusframe.updatebutton\n" ,"pack $w.listboxes.choosesocketframe $w.listboxes.statusframe -side left\n" ,"pack $w.listboxes\n" ,"ttk::label $w.lab1 -text \"\\n\"\n" ,"pack $w.lab1\n" ,"ttk::frame $w.buttons1\n" ,"ttk::frame $w.buttons2\n" ,"ttk::button $w.buttons1.getid -text \"Get ID\" -command {\n" ,"set opsel [${sockets.serverlistbox} curselection]\n" ,"if {[llength $opsel] > 0} {\n" ,"set opserver [lindex $opsel 0]\n" ,"set retval [Ng_Socket getid $opserver]\n" ,"updateserverlist\n" ,"set sockets.myidlabel $retval\n" ,"}\n" ,"}\n" ,"ttk::button $w.buttons1.killjob -text \"Kill Cur. Job\" -command {\n" ,"set opsel [${sockets.serverlistbox} curselection]\n" ,"if {[llength $opsel] > 0} {\n" ,"set opserver [lindex $opsel 0]\n" ,"Ng_Socket killcurrentjob $opserver\n" ,"}\n" ,"}\n" ,"ttk::button $w.buttons2.sendmesh -text \"Send Mesh\" -command {\n" ,"set opsel [${sockets.serverlistbox} curselection]\n" ,"if {[llength $opsel] > 0} {\n" ,"set opserver [lindex $opsel 0]\n" ,"set retval [Ng_Socket sendmesh $opserver]\n" ,"set sockets.meshsent 1\n" ,"}\n" ,"}\n" ,"ttk::button $w.buttons2.sendpde -text \"Send PDE\" -command {\n" ,"set opsel [${sockets.serverlistbox} curselection]\n" ,"if {[llength $opsel] > 0} {\n" ,"set opserver [lindex $opsel 0]\n" ,"set retval [NGS_Socket sendpdefile $opserver]\n" ,"}\n" ,"}\n" ,"ttk::button $w.buttons2.solvepde -text \"Solve PDE\" -command {\n" ,"set opsel [${sockets.serverlistbox} curselection]\n" ,"if {[llength $opsel] > 0} {\n" ,"set opserver [lindex $opsel 0]\n" ,"set retval [NGS_Socket solvepde $opserver]\n" ,"}\n" ,"}\n" ,"ttk::button $w.buttons2.writesol -text \"Write Solution\" -command {\n" ,"set opsel [${sockets.serverlistbox} curselection]\n" ,"if {[llength $opsel] > 0} {\n" ,"set opserver [lindex $opsel 0]\n" ,"set retval [NGS_Socket writesolution $opserver]\n" ,"}\n" ,"}\n" ,"ttk::button $w.buttons2.sendsol -text \"Receive Solution\" -command {\n" ,"set opsel [${sockets.serverlistbox} curselection]\n" ,"if {[llength $opsel] > 0} {\n" ,"set opserver [lindex $opsel 0]\n" ,"set retval [NGS_Socket sendsolution $opserver]\n" ,"}\n" ,"}\n" ,"ttk::button $w.buttons1.blockserver -text \"Block Server\" -command {\n" ,"set opsel [${sockets.serverlistbox} curselection]\n" ,"if {[llength $opsel] > 0} {\n" ,"set opserver [lindex $opsel 0]\n" ,"set retval [Ng_Socket blockserver $opserver]\n" ,"}\n" ,"}\n" ,"ttk::button $w.buttons1.unblockserver -text \"UnBlock Server\" -command {\n" ,"set opsel [${sockets.serverlistbox} curselection]\n" ,"if {[llength $opsel] > 0} {\n" ,"set opserver [lindex $opsel 0]\n" ,"set retval [Ng_Socket unblockserver $opserver]\n" ,"}\n" ,"}\n" ,"pack $w.buttons1.getid $w.buttons1.blockserver $w.buttons1.unblockserver $w.buttons1.killjob -side left\n" ,"pack $w.buttons2.sendmesh $w.buttons2.sendpde $w.buttons2.solvepde $w.buttons2.writesol $w.buttons2.sendsol -side left\n" ,"pack $w.buttons1 $w.buttons2\n" ,"wm withdraw $w\n" ,"wm geom $w +200+200\n" ,"wm deiconify $w\n" ,"wm title $w \"Client Socket\"\n" ,"focus .options_dlg\n" ,"}\n" ,"}\n" ,"}\n" ,"catch { source ${ngdir}/acis.tcl }\n" ,"set zugstange 0\n" ,"catch { source ${ngdir}/trafo/menu.tcl }\n" ,"setgranularity ${meshoptions.fineness}\n" ,"Ng_SetMeshingParameters\n" ,"Ng_SetVisParameters\n" ,"Ng_SetDebugParameters\n" ,"Ng_STLDoctor\n" ,"Ng_GeometryOptions set\n" ,"if { $hasocc == \"yes\" } {\n" ,"Ng_SetOCCVisParameters\n" ,"}\n" ,"if { $batchmode != \"defined\" } {\n" ,"catch {\n" ,"wm protocol . WM_DELETE_WINDOW { .ngmenu.file invoke \"Quit\" }\n" ,"wm deiconify .\n" ,"}\n" ,"}\n" ,"set trafoapp 0\n" ,"catch { source ${ngdir}/trafoapp/trafoapp.tcl }\n" ,"set geofilename [Ng_GetCommandLineParameter geofile]\n" ,"if { $geofilename != \"undefined\" &&\n" ,"[info exists trafo] == 0 && $zugstange == 0} {\n" ,"if { [ catch { Ng_LoadGeometry $geofilename } errstring] == 0 } {\n" ,"if { $batchmode != \"defined\" } {\n" ,"AddRecentFile $geofilename\n" ,"}\n" ,"Ng_ParseGeometry\n" ,"if { $batchmode != \"defined\" } {\n" ,"set selectvisual geometry\n" ,"Ng_SetVisParameters\n" ,"redraw\n" ,"wm title . [concat \"$progname - \" $geofilename]\n" ,"}\n" ,"set dirname [file dirname $geofilename]\n" ,"set basefilename [file tail [file rootname $geofilename]]\n" ,"} {\n" ,"puts \"Problem with input file:\"\n" ,"puts \"$errstring\"\n" ,"}\n" ,"}\n" ,"set cnt 0\n" ,"foreach { gran } { verycoarse coarse moderate fine veryfine } {\n" ,"set cnt [expr $cnt + 1]\n" ,"if { [Ng_GetCommandLineParameter $gran] == \"defined\" } {\n" ,"set meshoptions.fineness $cnt\n" ,"setgranularity ${meshoptions.fineness}\n" ,"}\n" ,"}\n" ,"set meshfilename [Ng_GetCommandLineParameter meshfile]\n" ,"if { $meshfilename == \"undefined\" } {\n" ,"set meshfilename out.mesh\n" ,"}\n" ,"set meshfiletype [Ng_GetCommandLineParameter meshfiletype]\n" ,"if { $meshfiletype == \"undefined\" } {\n" ,"set meshfiletype netgen\n" ,"}\n" ,"set inputmeshfilename [Ng_GetCommandLineParameter inputmeshfile]\n" ,"set mergemeshfilename [Ng_GetCommandLineParameter mergefile]\n" ,"set meshsizefilename [Ng_GetCommandLineParameter meshsizefile]\n" ,"if { $meshsizefilename != \"undefined\" } {\n" ,"set options.meshsizefilename $meshsizefilename\n" ,"}\n" ,"set refinementfilename [Ng_GetCommandLineParameter refinementfile]\n" ,"if { $batchmode == \"defined\" && $solvemode != \"defined\"} {\n" ,"set options.parthread 0\n" ,"if { $shellmode == \"undefined\" } {\n" ,"set selectvisual mesh\n" ,"Ng_SetVisParameters\n" ,"set meshsize [Ng_GetCommandLineParameter meshsize]\n" ,"if {$meshsize != \"undefined\"} { set options.meshsize $meshsize }\n" ,"if { $inputmeshfilename == \"undefined\" } {\n" ,"Ng_GenerateMesh ${meshoptions.firststep} ${meshoptions.laststep}\n" ,"} else {\n" ,"Ng_LoadMesh $inputmeshfilename\n" ,"if { $mergemeshfilename != \"undefined\" } {\n" ,"Ng_MergeMesh $mergemeshfilename\n" ,"}\n" ,"}\n" ,"if { $refinementfilename != \"undefined\" } {\n" ,"Ng_Bisect $refinementfilename\n" ,"}\n" ,"if { $meshfiletype == \"netgen\" } {\n" ,"Ng_SaveMesh $meshfilename\n" ,"} else {\n" ,"if { [catch { Ng_ExportMesh $meshfilename $meshfiletype } ] == 1 } {\n" ,"puts \"Unknown file format $meshfiletype\"\n" ,"}\n" ,"}\n" ,"Ng_Exit;\n" ,"exit\n" ,"} else {\n" ,"set code [catch { \n" ,"proc dotest {} {\n" ,"source ngtest.tcl\n" ,"}\n" ,"proc Ng_RunShell {} {\n" ,"puts \"Wellcome to NG Shell mode\"\n" ,"set line 1\n" ,"while { 1 } {\n" ,"puts -nonewline \"$line: \"\n" ,"flush stdout\n" ,"set cmdline [gets stdin]\n" ,"if { [catch $cmdline errcode] } {\n" ,"puts \"$errcode\"\n" ,"}\n" ,"incr line 1\n" ,"}\n" ,"}\n" ,"proc Ng_PrintCmdIndex { } {\n" ,"global cmdindex\n" ,"foreach { lst } $cmdindex {\n" ,"puts $lst\n" ,"}\n" ,"}\n" ,"proc Ng_PrintHlpIndex { } {\n" ,"global hlpindex\n" ,"global secindex\n" ,"foreach {sec} $secindex {\n" ,"puts \"\\n * $sec:\"\n" ,"foreach {lst} $hlpindex {\n" ,"if {$sec == [lindex $lst 1]} {\n" ,"puts \" * [lindex $lst 2]: [lindex $lst 3]\"\n" ,"}\n" ,"}\n" ,"}\n" ,"}\n" ,"proc Ng_RegisterCmd { cmd section syntax {help \"\"} } {\n" ,"global hlpindex\n" ,"global cmdindex\n" ,"global secindex\n" ,"puts \"register command $cmd\"\n" ,"if { [lsearch $cmdindex cmd] != -1 } {\n" ,"puts \"command '$cmd' already defined\"\n" ,"} else {\n" ,"lappend cmdindex $cmd\n" ,"lappend hlpindex [list $cmd $section $syntax $help]\n" ,"if {[lsearch $secindex $section]==-1} {\n" ,"lappend secindex $section\n" ,"}\n" ,"}\n" ,"}\n" ,"Ng_RegisterCmd \"exit\" \"general\" \"exit\" \"exit Netgen shell mode\"\n" ,"proc nghelp { {sec \"\"} } {\n" ,"global secindex\n" ,"global hlpindex\n" ,"global cmdindex\n" ,"if { $sec == \"\" } {\n" ,"Ng_PrintHlpIndex\n" ,"puts \"\\n type help 'section'\\n\"\n" ,"return\n" ,"}\n" ,"if { [lsearch $secindex $sec] != -1} {\n" ,"foreach {lst} $hlpindex {\n" ,"if {[lindex $lst 1] == $sec } {\n" ,"puts \" * [lindex $lst 2]: [lindex $lst 3]\"\n" ,"}\n" ,"}\n" ,"return\n" ,"}\n" ,"set ind [lsearch $cmdindex $sec]\n" ,"if {$ind != -1} {\n" ,"set lst [lindex $hlpindex $ind]\n" ,"puts \" * [lindex $lst 2]: [lindex $lst 3]\"\n" ,"return\n" ,"}\n" ,"puts \" unknown section or command $sec\"\n" ,"}\n" ,"set ngtimer 0\n" ,"proc nggettimer {} {\n" ,"return [clock clicks -milliseconds]\n" ,"}\n" ,"proc ngtic {} {\n" ,"set ::ngtimer [nggettimer]\n" ,"}\n" ,"proc ngtoc { {logfile stdout} } {\n" ,"set end [nggettimer]\n" ,"set tim [expr ($end - $::ngtimer)/1000.0]\n" ,"puts $logfile \"$tim s\"\n" ,"}\n" ,"proc ngloadgeometry { fname } {\n" ,"if { ![file exists $fname] } {\n" ,"puts \"error: file $fname does not exist\"\n" ,"} else {\n" ,"set err [catch {Ng_LoadGeometry $fname}]\n" ,"if {$err != 0} {\n" ,"puts \"error: loading geometry failed\"\n" ,"}\n" ,"}\n" ,"}\n" ,"Ng_RegisterCmd \"ngloadgeometry\" \"netgen\" \"ngloadgeometry \" \"load geometry file\"\n" ,"proc ngparsegeometry {} {\n" ,"set err [catch {Ng_ParseGeometry}]\n" ,"if {$err} {\n" ,"puts \"error: parsing geometry failed\"\n" ,"}\n" ,"}\n" ,"Ng_RegisterCmd \"ngparsegeometry\" \"netgen\" \"ngparsegeometry\" \"parse geometry\"\n" ,"proc nggeneratemesh {} {\n" ,"set err [catch {Ng_GenerateMesh}]\n" ,"if {$err} {\n" ,"puts \"error: mesh generation failed\"\n" ,"}\n" ,"}\n" ,"Ng_RegisterCmd \"nggeneratemesh\" \"netgen\" \"nggeneratemesh\" \"generate mesh\"\n" ,"proc ngsavemesh { fname } {\n" ,"if { [file exists $fname]} {\n" ,"puts \"warning: existing file $fname overwritten\"\n" ,"} else {\n" ,"set err [catch {Ng_SaveMesh $fname}]\n" ,"if {$err != 0} {\n" ,"puts \"error: saving mesh failed\"\n" ,"}\n" ,"}\n" ,"}\n" ,"Ng_RegisterCmd \"ngsavemesh\" \"netgen\" \"ngsavemesh \" \"save mesh to file\"\n" ,"proc ngset { opt {val 0} } {\n" ,"if {$opt == \"meshsize\"} {\n" ,"set ::options.meshsize $val\n" ,"Ng_SetMeshingParameters\n" ,"} elseif {$opt == \"printmsg\"} {\n" ,"set ::options.printmsg $val\n" ,"Ng_SetMeshingParameters\n" ,"} else {\n" ,"puts \"error: unknown option $opt\";\n" ,"}\n" ,"}\n" ,"Ng_RegisterCmd \"ngset\" \"netgen\" \"ngset